目录
核心函数解释:
-
strrpos() 函数查找字符串在另一字符串中最后一次出现的位置。此函数是区分大小写的,与strripos()函数相反,strripos()函数不区分大小写
-
sys_get_temp_dir() :返回临时文件路径
-
ini_get(): 获取一个配置选项的值,成功是返回配置选项值的字符串,null 的值则返回空字符串。如果配置选项不存在,将会返回 FALSE
-
uniqid() :基于以微秒计的当前时间,生成一个唯一的 ID
-
getimagesize():是PHP中用于获取图像的大小和格式的函数,底层利用文件头来判断文件类型。它可以返回一个包含图像的宽度、高度、类型和MIME类型的数组。可以从本地获取,也可以从远程获取。如果目标地址是图片,就会返回数组,否则返回FALSE并产生一条 E_WARNING 级的错误信息。
-
imagecreatefromjpeg() 函数用于从 JPEG 文件或 URL 创建一个新图象,将新图像放入内存中,后面需要通过imagedestroy()函数释放内存中的图像资源
-
imagejpeg():
-
1、imagejpeg()函数是php图像处理中的一个重要函数,用于将图像保存为jpeg格式文件。
-
2、imagejpeg()函数的语法如下:
-
bool imagejpeg ( resource $image [, string $filename [, int $quality ]] )
其中,image是图像资源,filename是保存的文件名,$quality是保存质量,取值范围从0-100,默认为75。
-
-
imagedestroy():释放内存中的图像资源
-
getcwd():获取当前目录
-
rename():函数用于重命名文件或目录,可以用于移动文件
-
bool rename ( string $source , string $target )
-
参数:
-
$source:必需,表示源文件或目录的名称。
-
$target:必需,表示目标文件或目录的名称。
-
-
返回值:
-
在成功时返回TRUE,失败时返回FALSE。
-
-
-
file_exists():检查文件或目录是否存在
-
unlink():删除文件
DVWA-xss_s-impossible
正式审计开始
-
判断是否正确提交参数btnSign,如果该参数存在才进行下面的代码
-
$_REQUEST['user_token']
:这是从请求(无论是GET、POST还是COOKIE等)中获取名为user_token
的值。这个值应该是由客户端(如浏览器)在发起请求时提供的。 -
mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $message)
这行代码的作用是对$message
字符串中的特殊字符进行转义,以防止 SQL 注入攻击,这里的转义操作是基于存储在$GLOBALS["___mysqli_ston"]
中的 MySQLi 连接对象进行的。 -
在 PHP 中,
htmlspecialchars()
函数是一个非常重要的安全函数,用于将特殊字符转换为 HTML 实体。这意味着它会将诸如&
、<
、>
、"
(双引号)和'
(单引号,如果设置了ENT_QUOTES
标志)这样的字符转换成它们的 HTML 实体形式,例如&
、<
、>
、"
和'
。
<?php if( isset( $_POST[ 'btnSign' ] ) ) { // Check Anti-CSRF token 利用 token 技术,防止CSRF跨站请求伪造攻击 // $_REQUEST['user_token']`:这是从请求(无论是GET、POST还是COOKIE等)中获取名为user_token的值。这个值应该是由客户端(如浏览器)在发起请求时提供的。checkToken函数会比较$_REQUEST['user_token']和$_SESSION['session_token']的值。如果这两个值相等,说明用户提交的令牌与服务器会话中存储的令牌相匹配,可能是一个有效的请求。如果不相等,则可能表示请求被篡改或来自不受信任的来源,函数可能会采取相应的安全措施,如拒绝请求、记录日志、重定向到错误页面等。 checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); // Get input //去除提交参数mtxMessage和txtName的值中左右两边的空格 $message = trim( $_POST[ 'mtxMessage' ] ); $name = trim( $_POST[ 'txtName' ] ); // Sanitize message input $message = stripslashes( $message ); // 先删除$message中的反斜杠 // 检查全局变量 $GLOBALS["___mysqli_ston"] 是否已设置(即存在),并且其值是一个对象。如果成立,则对 $message 字符串中的特殊字符进行转义,以防止 SQL 注入攻击,这里的转义操作是基于存储在 $GLOBALS["___mysqli_ston"] 中的 MySQLi 连接对象进行的。否则就抛出一个用户级别的错误,但我觉得更好的方式建议使用抛异常的方式。 $message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); $message = htmlspecialchars( $message ); // 确保了当你将 $message 变量的内容输出到 HTML 页面时,那些原本可能被浏览器解释为 HTML 或 JavaScript 代码的特殊字符现在只是普通的文本字符,即特殊字符实体转换,防止 XSS 跨站脚本攻击 // Sanitize name input // 作用和功能和上面是一样的 $name = stripslashes( $name ); // 去除变量 $name 中的反斜杠 $name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); $name = htmlspecialchars( $name ); // Update database 这部分防止SQL注入 // 使用 PDO(PHP Data Objects)扩展来准备并执行一个 SQL 插入语句,该语句将用户提交的评论($message)和名称($name)插入到名为 guestbook 的数据库表中。这是一种非常好的做法,因为它可以防止 SQL 注入攻击,因为 PDO 会自动处理特殊字符的转义。 $data = $db->prepare( 'INSERT INTO guestbook ( comment, name ) VALUES ( :message, :name );' ); $data->bindParam( ':message', $message, PDO::PARAM_STR ); $data->bindParam( ':name', $name, PDO::PARAM_STR ); $data->execute(); } // Generate Anti-CSRF token generateSessionToken(); // 生成session_token,用于与user_token进行比较 ?>
DVWA-file_upload-impossible
-
checkToken()
:这是一个自定义的函数,其目的是比较传入的两个token是否一致。如果_REQUEST['user_token']与_SESSION['session_token']相匹配,则说明这次请求来自一个合法的、已验证身份的用户;如果不匹配,则可能表示请求无效或已被篡改,此时服务器可能会拒绝该请求,或者重定向至指定的URL,这里是指向 'index.php' 页面。 -
uniqid()
:生成一个基于当前时间戳(精确到微秒)的唯一标识符。这个标识符通常用于创建临时文件名、会话ID或其他需要唯一性的场景 -
ini_get()
:函数在PHP中用于获取PHP配置选项当前的值 -
strtolower()
:用于将一个字符串中的所有字符转换为小写。 -
getimagesize()
:getimagesize() 函数在PHP中用于获取图像文件的尺寸、类型等信息。getimagesize()
函数也会检查文件是否真的是一个图像文件,如果文件不是图像或无法读取,它将返回FALSE
。因此,在尝试访问$width
和$height
变量之前,最好检查getimagesize()
的返回值是否有效。
<?php if( isset( $_POST[ 'Upload' ] ) ) { // Check Anti-CSRF token checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); // File information // 定义一堆变量名 $uploaded_name = $_FILES[ 'uploaded' ][ 'name' ]; // 上传的文件名 $uploaded_ext = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1); // 上传的文件名的后缀 $uploaded_size = $_FILES[ 'uploaded' ][ 'size' ]; // 上传的文件的大小,以字节为单位 $uploaded_type = $_FILES[ 'uploaded' ][ 'type' ]; // 上传的文件的类型 $uploaded_tmp = $_FILES[ 'uploaded' ][ 'tmp_name' ]; // 文件被上传后在服务器上存储的临时文件名。 // $uploaded_tmp 变量包含的是上传文件在服务器上的临时文件名。 // Where are we going to be writing to? $target_path = DVWA_WEB_PAGE_TO_ROOT . 'hackable/uploads/'; // 要上传的目标的部分目录路径 //$target_file = basename( $uploaded_name, '.' . $uploaded_ext ) . '-'; $target_file = md5( uniqid() . $uploaded_name ) . '.' . $uploaded_ext; // 修改上传的文件名,这里可以考虑一下使用md5散列值作为文件名的好处 $temp_file = ( ( ini_get( 'upload_tmp_dir' ) == '' ) ? ( sys_get_temp_dir() ) : ( ini_get( 'upload_tmp_dir' ) ) ); // $temp_file 变量包含的是 PHP 用于存储上传文件的临时目录的路径 $temp_file .= DIRECTORY_SEPARATOR . md5( uniqid() . $uploaded_name ) . '.' . $uploaded_ext; // DIRECTORY_SEPARATOR 目录分隔符 linux和mac等是 / ,windows是 \ // 最终构成了完整的临时路径$temp_file,并且其文件名使用的是md5散列值 // Is it an image? 其实就是进行了一次二次渲染 // 将后缀全部转换为小写之后与白名单比较判断,并且上传的文件必须是图片,其大小要小于100000字节,类型必须是image/jpeg或image/png if( ( strtolower( $uploaded_ext ) == 'jpg' || strtolower( $uploaded_ext ) == 'jpeg' || strtolower( $uploaded_ext ) == 'png' ) && ( $uploaded_size < 100000 ) && ( $uploaded_type == 'image/jpeg' || $uploaded_type == 'image/png' ) && getimagesize( $uploaded_tmp ) ) { // Strip any metadata, by re-encoding image (Note, using php-Imagick is recommended over php-GD) if( $uploaded_type == 'image/jpeg' ) { $img = imagecreatefromjpeg( $uploaded_tmp ); // 通过上传的文件,二次渲染出新的图片资源 imagejpeg( $img, $temp_file, 100); // 将渲染出来的图片资源保存为jpeg格式的文件 } else { $img = imagecreatefrompng( $uploaded_tmp ); // 通过上传的文件,二次渲染出新的图片资源 imagepng( $img, $temp_file, 9); // 将渲染出来的图片资源保存为jpeg格式的文件 } imagedestroy( $img ); // 保存了图片文件之后,释放图片文件资源 // Can we move the file to the web root from the temp folder? if( rename( $temp_file, ( getcwd() . DIRECTORY_SEPARATOR . $target_path . $target_file ) ) ) { // Yes! 表示已经成功移动文件 $html .= "<pre><a href='{$target_path}{$target_file}'>{$target_file}</a> succesfully uploaded!</pre>"; } else { // No $html .= '<pre>Your image was not uploaded.</pre>'; } // Delete any temp files if( file_exists( $temp_file ) ) // 如果临时文件还存在,那么就把他删掉,那么这里有是否会存在条件竞争呢 unlink( $temp_file ); } else { // Invalid file $html .= '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>'; } } // Generate Anti-CSRF token generateSessionToken(); ?>