과유불급 (Hawkis_CTF) write-up

2023. 5. 29. 14:51Hawkis_CTF

 

CTF 문제

 

 

 

bof.zip 폴더 다운로드

 

* bof.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 read_me(){
        system("/bin/sh");
}

void food() {
        puts("do you like fastfood?");
        puts("choose!");
        puts("[h]amberger");
        puts("[p]izza");
        puts("[c]hiken");
        printf("> ");
}

int main(int argc, char *argv[])
{
        char name[0x50] = {};
        char choose[2] = {};
        initialize();
        while(1) {
                food();
                read(0, choose, 2);
                switch(choose[0]){
                        case 'h':
                                printf("i like hamberger!");
                                break;
                        case 'p':
                                printf("what do you want?");
                                read(0,name,79);
                                break;
                        case 'c':
                                printf("i don't like chiken.\n");
                                printf("pick another one: ");
                                read(0,name,0x100);
                                return 0;
                        default:
                                break;
                }
        }
}

 

read_me 함수를 이용해 /bin/sh 쉘을 실행할 수 있음

 

buffer 대상 함수 = name [0x50]

 

 

 

 

 

 

스택 버퍼 오버 플로우

 

■ 버퍼 (Buffer)

 

데이터가 목적지로 이동되기 전에 보관되는 임시 저장소

   (사용자의 입력값)

 

 

■  버퍼 오버 플로우 (Buffer overflow)

 

:  메모리에 할당된 공간인 buffer를 넘어서 SFP와 RET영역까지 사용자가 원하는 값을 채워넣을 수 있는 취약점

 

 

 

 

 

gdb로 bof파일 실행

 

 

* gdb란?

: GNU DeBugger의 약자로 GNU 소프트웨어를 위한 기본 디버거

 

* gdb가 지원하는 언어

: Ada, Assembly, C, C++, D, Fortran, Go, Objective-C, OpenCL, Modula-2, Pascal, Rust

 

 

 

 

gdb bof 명령으로 bof파일을 디버깅 

-> No debugging symbols found in bof 라는 오류 뜸 (디버깅 안된다는 뜻)

 

-> info file 명령어를 통해 파일의 .text 영역의 주소값을 알아냄

 

-> disas (.text 주소 값) 명령 입력시 어셈블리 코드 출력 가능

 

 

 

* gdb 디스어셈블리는 기본적으로 AT&T문법을 따른다

하지만 우리가 흔히 접한 어셈블 코드는 Intel 문법이기에 

 

$ set disassembly-flavor intel 명령을 통해  설정을 Intel 문법으로 변환하였다

 

AT&T 문법 Intel 문법

 

* bof 어셈블 코드

   0x00000000004010b0 <_start+0>:	xor    ebp,ebp
   0x00000000004010b2 <_start+2>:	mov    r9,rdx
   0x00000000004010b5 <_start+5>:	pop    rsi
   0x00000000004010b6 <_start+6>:	mov    rdx,rsp
   0x00000000004010b9 <_start+9>:	and    rsp,0xfffffffffffffff0
   0x00000000004010bd <_start+13>:	push   rax
   0x00000000004010be <_start+14>:	push   rsp
   0x00000000004010bf <_start+15>:	xor    r8d,r8d
   0x00000000004010c2 <_start+18>:	xor    ecx,ecx
   0x00000000004010c4 <_start+20>:	mov    rdi,0x401290
   0x00000000004010cb <_start+27>:	call   QWORD PTR [rip+0x2f07]        # 0x403fd8
   0x00000000004010d1 <_start+33>:	hlt    
   0x00000000004010d2:	cs nop WORD PTR [rax+rax*1+0x0]
   0x00000000004010dc:	nop    DWORD PTR [rax+0x0]
   0x00000000004010e0 <_dl_relocate_static_pie+0>:	ret    
   0x00000000004010e1:	cs nop WORD PTR [rax+rax*1+0x0]
   0x00000000004010eb:	nop    DWORD PTR [rax+rax*1+0x0]
   0x00000000004010f0 <deregister_tm_clones+0>:	mov    eax,0x404050
   0x00000000004010f5 <deregister_tm_clones+5>:	cmp    rax,0x404050
   0x00000000004010fb <deregister_tm_clones+11>:	je     0x401110 <deregister_tm_clones+32>
   0x00000000004010fd <deregister_tm_clones+13>:	mov    eax,0x0
   0x0000000000401102 <deregister_tm_clones+18>:	test   rax,rax
   0x0000000000401105 <deregister_tm_clones+21>:	je     0x401110 <deregister_tm_clones+32>
   0x0000000000401107 <deregister_tm_clones+23>:	mov    edi,0x404050
   0x000000000040110c <deregister_tm_clones+28>:	jmp    rax
   0x000000000040110e <deregister_tm_clones+30>:	xchg   ax,ax
   0x0000000000401110 <deregister_tm_clones+32>:	ret    
   0x0000000000401111 <deregister_tm_clones+33>:	data16 cs nop WORD PTR [rax+rax*1+0x0]
   0x000000000040111c <deregister_tm_clones+44>:	nop    DWORD PTR [rax+0x0]
   0x0000000000401120 <register_tm_clones+0>:	mov    esi,0x404050
   0x0000000000401125 <register_tm_clones+5>:	sub    rsi,0x404050
   0x000000000040112c <register_tm_clones+12>:	mov    rax,rsi
   0x000000000040112f <register_tm_clones+15>:	shr    rsi,0x3f
   0x0000000000401133 <register_tm_clones+19>:	sar    rax,0x3
   0x0000000000401137 <register_tm_clones+23>:	add    rsi,rax
   0x000000000040113a <register_tm_clones+26>:	sar    rsi,1
   0x000000000040113d <register_tm_clones+29>:	je     0x401150 <register_tm_clones+48>
   0x000000000040113f <register_tm_clones+31>:	mov    eax,0x0
   0x0000000000401144 <register_tm_clones+36>:	test   rax,rax
   0x0000000000401147 <register_tm_clones+39>:	je     0x401150 <register_tm_clones+48>
   0x0000000000401149 <register_tm_clones+41>:	mov    edi,0x404050
   0x000000000040114e <register_tm_clones+46>:	jmp    rax
   0x0000000000401150 <register_tm_clones+48>:	ret    
   0x0000000000401151 <register_tm_clones+49>:	data16 cs nop WORD PTR [rax+rax*1+0x0]
   0x000000000040115c <register_tm_clones+60>:	nop    DWORD PTR [rax+0x0]
   0x0000000000401160 <__do_global_dtors_aux+0>:	endbr64 
   0x0000000000401164 <__do_global_dtors_aux+4>:	cmp    BYTE PTR [rip+0x2efd],0x0        # 0x404068 <completed.0>
   0x000000000040116b <__do_global_dtors_aux+11>:	jne    0x401180 <__do_global_dtors_aux+32>
   0x000000000040116d <__do_global_dtors_aux+13>:	push   rbp
   0x000000000040116e <__do_global_dtors_aux+14>:	mov    rbp,rsp
   0x0000000000401171 <__do_global_dtors_aux+17>:	call   0x4010f0 <deregister_tm_clones>
   0x0000000000401176 <__do_global_dtors_aux+22>:	mov    BYTE PTR [rip+0x2eeb],0x1        # 0x404068 <completed.0>
   0x000000000040117d <__do_global_dtors_aux+29>:	pop    rbp
   0x000000000040117e <__do_global_dtors_aux+30>:	ret    
   0x000000000040117f <__do_global_dtors_aux+31>:	nop
   0x0000000000401180 <__do_global_dtors_aux+32>:	ret    
   0x0000000000401181 <__do_global_dtors_aux+33>:	data16 cs nop WORD PTR [rax+rax*1+0x0]
   0x000000000040118c <__do_global_dtors_aux+44>:	nop    DWORD PTR [rax+0x0]
   0x0000000000401190 <frame_dummy+0>:	endbr64 
   0x0000000000401194 <frame_dummy+4>:	jmp    0x401120 <register_tm_clones>
   0x0000000000401196 <alarm_handler+0>:	push   rbp
   0x0000000000401197 <alarm_handler+1>:	mov    rbp,rsp
   0x000000000040119a <alarm_handler+4>:	lea    rax,[rip+0xe63]        # 0x402004
   0x00000000004011a1 <alarm_handler+11>:	mov    rdi,rax
   0x00000000004011a4 <alarm_handler+14>:	call   0x401030 <puts@plt>
   0x00000000004011a9 <alarm_handler+19>:	mov    edi,0xffffffff
   0x00000000004011ae <alarm_handler+24>:	call   0x4010a0 <exit@plt>
   0x00000000004011b3 <initialize+0>:	push   rbp
   0x00000000004011b4 <initialize+1>:	mov    rbp,rsp
   0x00000000004011b7 <initialize+4>:	mov    rax,QWORD PTR [rip+0x2ea2]        # 0x404060 <stdin@GLIBC_2.2.5>
   0x00000000004011be <initialize+11>:	mov    ecx,0x0
   0x00000000004011c3 <initialize+16>:	mov    edx,0x2
   0x00000000004011c8 <initialize+21>:	mov    esi,0x0
   0x00000000004011cd <initialize+26>:	mov    rdi,rax
   0x00000000004011d0 <initialize+29>:	call   0x401090 <setvbuf@plt>
   0x00000000004011d5 <initialize+34>:	mov    rax,QWORD PTR [rip+0x2e74]        # 0x404050 <stdout@GLIBC_2.2.5>
   0x00000000004011dc <initialize+41>:	mov    ecx,0x0
   0x00000000004011e1 <initialize+46>:	mov    edx,0x2
   0x00000000004011e6 <initialize+51>:	mov    esi,0x0
   0x00000000004011eb <initialize+56>:	mov    rdi,rax
   0x00000000004011ee <initialize+59>:	call   0x401090 <setvbuf@plt>
   0x00000000004011f3 <initialize+64>:	lea    rax,[rip+0xffffffffffffff9c]        # 0x401196 <alarm_handler>
   0x00000000004011fa <initialize+71>:	mov    rsi,rax
   0x00000000004011fd <initialize+74>:	mov    edi,0xe
   0x0000000000401202 <initialize+79>:	call   0x401080 <signal@plt>
   0x0000000000401207 <initialize+84>:	mov    edi,0x1e
   0x000000000040120c <initialize+89>:	call   0x401060 <alarm@plt>
   0x0000000000401211 <initialize+94>:	nop
   0x0000000000401212 <initialize+95>:	pop    rbp
   0x0000000000401213 <initialize+96>:	ret    
   0x0000000000401214 <read_me+0>:	push   rbp
   0x0000000000401215 <read_me+1>:	mov    rbp,rsp
   0x0000000000401218 <read_me+4>:	lea    rax,[rip+0xdee]        # 0x40200d
   0x000000000040121f <read_me+11>:	mov    rdi,rax
   0x0000000000401222 <read_me+14>:	call   0x401040 <system@plt>
   0x0000000000401227 <read_me+19>:	nop
   0x0000000000401228 <read_me+20>:	pop    rbp
   0x0000000000401229 <read_me+21>:	ret    
   0x000000000040122a <food+0>:	push   rbp
   0x000000000040122b <food+1>:	mov    rbp,rsp
   0x000000000040122e <food+4>:	lea    rax,[rip+0xde0]        # 0x402015
   0x0000000000401235 <food+11>:	mov    rdi,rax
   0x0000000000401238 <food+14>:	call   0x401030 <puts@plt>
   0x000000000040123d <food+19>:	lea    rax,[rip+0xde7]        # 0x40202b
   0x0000000000401244 <food+26>:	mov    rdi,rax
   0x0000000000401247 <food+29>:	call   0x401030 <puts@plt>
   0x000000000040124c <food+34>:	lea    rax,[rip+0xde0]        # 0x402033
   0x0000000000401253 <food+41>:	mov    rdi,rax
   0x0000000000401256 <food+44>:	call   0x401030 <puts@plt>
   0x000000000040125b <food+49>:	lea    rax,[rip+0xddd]        # 0x40203f
   0x0000000000401262 <food+56>:	mov    rdi,rax
   0x0000000000401265 <food+59>:	call   0x401030 <puts@plt>
   0x000000000040126a <food+64>:	lea    rax,[rip+0xdd6]        # 0x402047
   0x0000000000401271 <food+71>:	mov    rdi,rax
   0x0000000000401274 <food+74>:	call   0x401030 <puts@plt>
   0x0000000000401279 <food+79>:	lea    rax,[rip+0xdd0]        # 0x402050
   0x0000000000401280 <food+86>:	mov    rdi,rax
   0x0000000000401283 <food+89>:	mov    eax,0x0
   0x0000000000401288 <food+94>:	call   0x401050 <printf@plt>
   0x000000000040128d <food+99>:	nop
   0x000000000040128e <food+100>:	pop    rbp
   0x000000000040128f <food+101>:	ret    
   0x0000000000401290 <main+0>:	push   rbp
   0x0000000000401291 <main+1>:	mov    rbp,rsp
   0x0000000000401294 <main+4>:	sub    rsp,0x70
   0x0000000000401298 <main+8>:	mov    DWORD PTR [rbp-0x64],edi
   0x000000000040129b <main+11>:	mov    QWORD PTR [rbp-0x70],rsi
   0x000000000040129f <main+15>:	mov    QWORD PTR [rbp-0x50],0x0
   0x00000000004012a7 <main+23>:	mov    QWORD PTR [rbp-0x48],0x0
   0x00000000004012af <main+31>:	mov    QWORD PTR [rbp-0x40],0x0
   0x00000000004012b7 <main+39>:	mov    QWORD PTR [rbp-0x38],0x0
   0x00000000004012bf <main+47>:	mov    QWORD PTR [rbp-0x30],0x0
   0x00000000004012c7 <main+55>:	mov    QWORD PTR [rbp-0x28],0x0
   0x00000000004012cf <main+63>:	mov    QWORD PTR [rbp-0x20],0x0
   0x00000000004012d7 <main+71>:	mov    QWORD PTR [rbp-0x18],0x0
   0x00000000004012df <main+79>:	mov    QWORD PTR [rbp-0x10],0x0
   0x00000000004012e7 <main+87>:	mov    QWORD PTR [rbp-0x8],0x0
   0x00000000004012ef <main+95>:	mov    WORD PTR [rbp-0x52],0x0
   0x00000000004012f5 <main+101>:	mov    eax,0x0
   0x00000000004012fa <main+106>:	call   0x4011b3 <initialize>
   0x00000000004012ff <main+111>:	mov    eax,0x0
   0x0000000000401304 <main+116>:	call   0x40122a <food>
   0x0000000000401309 <main+121>:	lea    rax,[rbp-0x52]
   0x000000000040130d <main+125>:	mov    edx,0x2
   0x0000000000401312 <main+130>:	mov    rsi,rax
   0x0000000000401315 <main+133>:	mov    edi,0x0
   0x000000000040131a <main+138>:	call   0x401070 <read@plt>
   0x000000000040131f <main+143>:	movzx  eax,BYTE PTR [rbp-0x52]
   0x0000000000401323 <main+147>:	movsx  eax,al
   0x0000000000401326 <main+150>:	cmp    eax,0x70
   0x0000000000401329 <main+153>:	je     0x401358 <main+200>
   0x000000000040132b <main+155>:	cmp    eax,0x70
   0x000000000040132e <main+158>:	jg     0x4013c4 <main+308>
   0x0000000000401334 <main+164>:	cmp    eax,0x63
   0x0000000000401337 <main+167>:	je     0x401384 <main+244>
   0x0000000000401339 <main+169>:	cmp    eax,0x68
   0x000000000040133c <main+172>:	jne    0x4013c4 <main+308>
   0x0000000000401342 <main+178>:	lea    rax,[rip+0xd0a]        # 0x402053
   0x0000000000401349 <main+185>:	mov    rdi,rax
   0x000000000040134c <main+188>:	mov    eax,0x0
   0x0000000000401351 <main+193>:	call   0x401050 <printf@plt>
   0x0000000000401356 <main+198>:	jmp    0x4013c5 <main+309>
   0x0000000000401358 <main+200>:	lea    rax,[rip+0xd06]        # 0x402065
   0x000000000040135f <main+207>:	mov    rdi,rax
   0x0000000000401362 <main+210>:	mov    eax,0x0
   0x0000000000401367 <main+215>:	call   0x401050 <printf@plt>
   0x000000000040136c <main+220>:	lea    rax,[rbp-0x50]
   0x0000000000401370 <main+224>:	mov    edx,0x4f
   0x0000000000401375 <main+229>:	mov    rsi,rax
   0x0000000000401378 <main+232>:	mov    edi,0x0
   0x000000000040137d <main+237>:	call   0x401070 <read@plt>
   0x0000000000401382 <main+242>:	jmp    0x4013c5 <main+309>
   0x0000000000401384 <main+244>:	lea    rax,[rip+0xcec]        # 0x402077
   0x000000000040138b <main+251>:	mov    rdi,rax
   0x000000000040138e <main+254>:	call   0x401030 <puts@plt>
   0x0000000000401393 <main+259>:	lea    rax,[rip+0xcf2]        # 0x40208c
   0x000000000040139a <main+266>:	mov    rdi,rax
   0x000000000040139d <main+269>:	mov    eax,0x0
   0x00000000004013a2 <main+274>:	call   0x401050 <printf@plt>
   0x00000000004013a7 <main+279>:	lea    rax,[rbp-0x50]
   0x00000000004013ab <main+283>:	mov    edx,0x100
   0x00000000004013b0 <main+288>:	mov    rsi,rax
   0x00000000004013b3 <main+291>:	mov    edi,0x0
   0x00000000004013b8 <main+296>:	call   0x401070 <read@plt>
   0x00000000004013bd <main+301>:	mov    eax,0x0
   0x00000000004013c2 <main+306>:	jmp    0x4013ca <main+314>
   0x00000000004013c4 <main+308>:	nop
   0x00000000004013c5 <main+309>:	jmp    0x4012ff <main+111>
   0x00000000004013ca <main+314>:	leave  
   0x00000000004013cb <main+315>:	ret

 

 

메모리 구조

 

buf SFP RET

 

- 버퍼 (buf) : 사용자의 입력값 

- SFP : Stack Frame Pointer

- RET : 다음에 실행시킬 주소값 

 

해당 메모리는 버퍼 (buf) = name 의 메모리가 사용된 뒤에 SFP, RET 영역이 실행 된다 

 

하지만 name 함수에 할당된 메모리 영역 + SFP영역 까지 임의의 문자를 넣고, 쉘 획득 코드를 뒤에 붙이면

 

RET 영역에서 쉘 코드가 실행이 되고 쉘 권한을 획득할 수 있는것이다.

 

 

Buffer + SFP 크기

 

(*참고)

rbp : 스택의 시작점

rsp : 스택의 꼭대기

 

 

 

bof.c 코드에서 변수총 2개가 선언

 

buffer = name의 크기는 0x50 byte (50 byte)

choose의 크기는 2byte 

 

SFP와 RET의 크기는

 

운영체제가 32bit이며 4byte, 64bit이면 8byte이다

 

운영체제 확인시 64bit이므로 각각 8byte의 크기를 가지고있다

 

 

 

따라서, 프로그램을 실행 시켰을때 실행 구조는 다음과 같다

 

즉, RET 전 = 버퍼 + SFT 의 크기는  0x50 + 0x2 + 0x8 = 0x60으로

 

총 0x60크기의 문자열을 입력하면 RET 직전까지 입력하게 되는것이다!

 

 

결론적으로, 0x60크기의 문자열 +  쉘 실행 코드 입력시 쉘을 획득 가능하다 !!

 

 

 

 

Shell 권한 획득

 

'Hawkis_CTF' 카테고리의 다른 글

Babysheets 문제  (0) 2023.07.05
Babyforms 문제  (0) 2023.07.04
하위 문제  (0) 2023.07.04
Plz Recovery 문제  (0) 2023.07.03
Hacker Wannabe (Hawkis_CTF) write-up  (0) 2023.05.21