Insecure CAPTCHA(不安全的验证码)
CAPTCHA是Completely Automated Public Turing Test to Tell Computers and Humans Apart (全自动区分计算机和人类的图灵测试)的简称。
审计代码
可以看到分为两个阶段 1.验证身份 2.检查两次密码是否一致 然后更改密码
<?php
if( isset( $_POST[ 'Change' ] ) ) {
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
// Hide the CAPTCHA form
$hide_form = true;
// Get input
$pass_new = $_POST[ 'password_new' ];
$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 );
$pass_conf = $_POST[ 'password_conf' ];
$pass_conf = stripslashes( $pass_conf );
$pass_conf = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_conf ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
$pass_conf = md5( $pass_conf );
$pass_curr = $_POST[ 'password_current' ];
$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 CAPTCHA from 3rd party
$resp = recaptcha_check_answer(
$_DVWA[ 'recaptcha_private_key' ],
$_POST['g-recaptcha-response']
);
// Did the CAPTCHA fail?
if( !$resp ) {
// What happens when the CAPTCHA was entered incorrectly
echo "<pre><br />The CAPTCHA was incorrect. Please try again.</pre>";
$hide_form = false;
return;
}
else {
// Check that the current password is correct
$data = $db->prepare( 'SELECT password FROM users WHERE user = (:user) AND password = (:password) LIMIT 1;' );
$data->bindParam( ':user', dvwaCurrentUser(), PDO::PARAM_STR );
$data->bindParam( ':password', $pass_curr, PDO::PARAM_STR );
$data->execute();
// Do both new password match and was the current password correct?
if( ( $pass_new == $pass_conf) && ( $data->rowCount() == 1 ) ) {
// Update the database
$data = $db->prepare( 'UPDATE users SET password = (:password) WHERE user = (:user);' );
$data->bindParam( ':password', $pass_new, PDO::PARAM_STR );
$data->bindParam( ':user', dvwaCurrentUser(), PDO::PARAM_STR );
$data->execute();
// Feedback for the end user - success!
echo "<pre>Password Changed.</pre>";
}
else {
// Feedback for the end user - failed!
echo "<pre>Either your current password is incorrect or the new passwords did not match.<br />Please try again.</pre>";
$hide_form = false;
}
}
}
// Generate Anti-CSRF token
generateSessionToken();
?>
burp对其抓包

将step改为2即可,如下图看到密码修改成功。

SQL注入(SQL Injection)<low>
原理:通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令
本质:用户输入的数据当作代码执行
SQL注入常规思路:
1、寻找注入点
2、通过注入点,尝试获取数据库相关基本信息
3、猜解数据库及其重要字段以及内容
4、通过用户信息,寻找后台登录
5、利用后台或连接的进一步信息,上传webshell或向数据库写入一句话木马,以进一步提权,直到拿到服务器权限

先输入 1 ,查看回显 (URL中ID=1,说明php页面通过get方法传递参数):
SQL查询代码为:$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
通过控制参数Id的值来返回我们需要的信息。
输入框中输入 1' order by 1#
输入 1' order by 1#和 1' order by 2#时都返回正常:

输入 1' order by 3#时,返回错误
由此可知,users表中只有两个字段,数据为两列。
接下来我们使用 union select联合查询继续获取信息。
union 运算符可以将两个或两个以上 select 语句的查询结果集合合并成一个结果集合显示,即执行联合查询。需要注意在使用 union 查询的时候需要和主查询的列数相同,而我们之前已经知道了主查询列数为 2,接下来就好办了。
输入1' union select database(),user()#进行查询 :
database()将会返回当前网站所使用的数据库名字.
user()将会返回执行当前查询的用户名.

sql手工盲注
盲注分为时间注入与布尔注入
<?php
if( 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 '<pre>User ID exists in the database.</pre>';
}
else {
// User wasn't found, so the page wasn't!
header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' );
// Feedback for end user
echo '<pre>User ID is MISSING from the database.</pre>';
}
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
?>
审计代码,发现符合布尔注入
猜测数据库长度:id=1' and (length(database()))>数字#
输入数字4时

输入3时回显时正确的,说明数据库长度为4
猜测用户名admin():
id=1' and (ascii(substr((select 列名 from 表名 limit 0,1),1,1)))=ASCII#
Weak Session IDs弱会话<low>
用户访问服务器的时候,一般服务器都会分配一个身份证 session id 给用户,用于标识。 用户拿到 session id 后就会保存到 cookies 上,之后只要拿着 cookies 再访问服务器,服务器就知道你是谁了。 但是 session id 过于简单就会容易被人伪造。
审计代码
<?php
$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);
}
直接用burp抓包,可以清楚的看到dvwaSesion的cookie,每重放一次,dvwaSesion增加一


点击执行,即可看到自己直接登录进入到页面
xss(dom型漏洞)<low>
DOM又称DOM树,全称为文档对象模型(Document Objeet Mode),是Web前端开发中使用到的一种模型。在前端开发中会使用到很多元素,如< title>、< h1>等,而为了方便使用这些已经定义的元素,将这些元素作为结点排成树状后,通过遍历这棵树,就可以很方便的调用这些元素。而这颗树就称为DOM树。
当js脚本从url获得数据并将其传递到支持动态代码执行的接收器时,就会产生基于DOM的XSS漏洞。也就是说不规范的使用接收器时就会产生基于DOM的XSS漏洞。因此基于DOM的XSS漏洞一般产生于用户能够进行参数输入查询的地方。
因此这题的关键是通过构造含有恶意代码的url获取受害者的私人信息。
观察url发现可以在此直接修改,因此我们可以添加一些恶意代码,如<script>alert('hack')</script>

xss(反射型漏洞)<low>
可以通过构造js恶意代码<script>alert(document.cookie)</script>获取cookie
<?php
header ("X-XSS-Protection: 0");
// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
// Feedback for end user
echo '<pre>Hello ' . $_GET[ 'name' ] . '</pre>';
}
?>

xss(存储型漏洞)<low>
该类型与之前不同点便是有了数据库的连接,若该网站有发布及浏览文章的类似功能,攻击者便可以通过xss存储型漏洞发布含恶意代码的文章,并被存储在数据库中,当受害者访问该文章时,浏览器便会执行此恶意代码,最终攻击者可以获得受害者的私人信息
因此这题的关键是想办法将自己的恶意代码存储进数据库中,首先我们审计代码,发现对name,message变量没有过滤,因此我们可以直接输入恶意代码执行。
<?php
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( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
//mysql_close();
}
?>
