이제 F.T.Z.도 거의 막바지네요.

Level19hint를 한번 보도록 하겠습니다.

살짝 당황스럽네요매우 짧은 코드가 나왔습니다.

BOF버그가 있는 gets함수를 이용해서 어떻게 하라는거 같은데 이전의 코드와는 달리 setreuidsystem(“/bin/bash”)가 보이지 않습니다.

즉 이부분이 필요할테니.. level20setreuid가 설정 되어 있는 쉘코드를 작성해야겠네요.

이번 문제는 이러한 쉘코드를 작성할 수 있느냐가 핵심입니다.

 

우선 level20의 계정 정보를 확인해 보도록 하겠습니다.

level20의 계정 번호는 3100이네요.

 

다음과 같은 코드를 쉘코드로 만들어야 합니다.

쉘코드를 만드는 방법은 Level11에 첨부해놓은 pdf를 보시면 알 수 있습니다.

 

간단하게 설명해 드리자면, 위의 코드를 static으로 컴파일한후 gccexecvesetreuid의 어셈블리어를 확인해 핵심만 추출하면 다음과 같이 됩니다.

이제 이 코드를 컴파일 해서 objdump로 어셈블리 명령어를 추출하면 다음과 같이 나옵니다.

여기서 필요한 부분은 0x08048304부터 0x084832d입니다. 이부분의 기계어만 추출하면 다음과 같은 쉘코드를 얻을 수 있습니다.

 

"\x31\xd2\x66\xb8\x1c\x0c\x66\xb9\x1c\x0c\x89\xc3\x89\xd0\xb0\x46\xcd\x80\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\x31\xd2\x89\xd0\xb0\x0b\xcd\x80"

 

이제 이 쉘코드를 에그쉘에 올리고 그 주소를 ./attackmeret에 덮어 씌우면 됩니다.

에그쉘과 에그쉘의 주소를 얻는 파일은 아래에 있습니다.

(출처 : http://pwnbit.kr/7)

EGG Shell.c

getegg.c

egshell을 통해 등록한 쉘코드의 주소는 0xbffff2bc네요.

 

Gdbattackme를 확인해 보도록 하겠습니다.

확인한 결과 덮어 씌워야 할 ret의 위치는 입력 포인터로부터 44만큼 떨어져 있네요.

 

44만큼 채우고 쉘코드의 주소를 넣으면 될듯 합니다.

다행히도 생각한 대로 Level20의 쉘이 획득 되었습니다.


Level20의 패스워드는 we are just regular guys입니다.


작성하고 나서 보니 폴더 경로에 좋지 않은 문자가 들어가 있네요.... 쉘코드 만들다가 빡쳐서 그만... 죄송합니다. ㅎㅎ;

Level18로 접속하고 늘 그렇듯이 hint를 확인해봅니다.

힌트 코드가 굉장히 길어졌네요.

우선 코드에 대한 설명부터 하겠습니다.

 

코드 내에 있는 낯설은 함수들의 설명은 다음과 같습니다.

FD_ZERO(fd_set *fdset) : *fdset의 모든 비트를 지운다.

FD_SET(int fd, fd_set *fdset) : *fdset 중 첫번째 인자 fd에 해당하는 비트를 1로 한다.

FD_CLR(int fd, fd_set *fdset) : *fdset 중 첫번째 인자 fd에 해당하는 비트를 0으로 한다.

FD_ISSET(int fd, fd_set *fdset) : *fdset 중 첫번째 인자 fd에 해당하는 비트가 세트되어 있으면 양수값인 fd를 리턴한다.

 

select()FD_SET으로 설정된 fd만을 확인한다. 그리고 확인 결과 read또는 write준비가 된 fdfdset내에서 세트시킨다. 따라서 select() 함수 직후에 FD_ISSET으로 특정 fd‘SET’되었는지 확인할 수 있다. 데이터가 변경된 파일의 개수 즉 fd_set에서 비트값이 1인 필드의 개수를 반환

(출처 : http://jsnim.blogspot.kr/2010/02/select-fdzero-fdset-fdclr-fdisset.html)

 

터미널에서 man select라고 입력하시거나, 구글에 select 함수에 대해서 검색하시면 관련 정보를 얻으실 수 있습니다.

 

코드의 내용을 간단하게 말하면 표준 입력으로부터 한글자씩 입력을 받아 string[count]에 넣는 코드 입니다.

입력이 ‘\r, \n’이면 에러음을 내구요.

입력이 ‘\b’이면 입력값을 지우기 위해서 count1감소합니다.

 

코드의 조건을 다음과 같이 정리할 수 있습니다.

1.    입력은 100자 이내

2.    check0xdeadbeef여야함 : clear

3.    사용자로부터 표준입력을 받음

 

gdb를 통해 어셈을 따라가다 보면 알수 있는 스택구조는 다음과 같습니다.

어셈코드가 상당히 길기때문에 첨부하진 않겠습니다.

string(100byte)

check(4byte)

x(4byte)

count(4byte)

fds

이 문제를 해결하기 위한 핵심은 count--string[count] = x입니다.

코드에서 보다시피 ‘\b’를 입력받으면 내용을 지우기 위해 count1감소시키게 됩니다.

그러나 코드 어디에서도 count가 음수일때를 체크하는 내용은 볼 수 없습니다.

즉 우리는 check에 값을 넣어야 하는데 count가 음수가 되면 string[count]로 인해 스택상 string밑에 있는 check에 값을 입력 할 수 있게 되는 것이죠.

 

이로인해 우리가 필요한 정보는 전부 획득했습니다.

‘\b’4번 입력하고 0xdeadbeef를 입력하면 문제를 해결 할수 있을 것으로 보입니다.

획득한 정보에 맞춰 커맨드를 입력했더니 예상이 맞았네요. Level19권한의 쉘을 획득하였습니다.

 

Level19의 패스워드는 swimming in pink입니다.

 

이번 문제는 낯설은 함수가 많아 전부다 분석하는데 시간이 걸렸을 뿐이지 취약한 원인이 되는 코드는 상당히 간단했네요.

Level17로 접속하여 hint를 확인해 줍니다.


Level16의 코드와 비슷한데 shell 함수가 없네요.

그렇다면 쉘을 띄워주는 함수를 어딘가에 넣어주고, call 변수에 쉘을 띄워주는 함수의 주소값을 넣어주면 될 것 같습니다.

코드 구조가 비슷하니 call 변수에 쉘을 띄워주는 함수의 주소값을 넣어주는 것은 Level16과 동일한 방법을 사용하면 될 듯 하구요.

쉘을 띄워주는 함수는 Level11에서 환경변수에 Shell 코드를 삽입했던 것을 떠올리면 될 듯 합니다.


그럼 우선 환경변수에 shell을 넣도록 하겠습니다.


정상적으로 환경변수에 쉘 코드가 등록이 되었네요.


그럼 환경변수에 등록된 쉘코드의 시작 주소를 가져오도록 하겠습니다.


0xbffffc8a에 등록이 되어 있군요. 이제 call 포인터 변수에 0xbffffc8a를 넣어주면 됩니다.

어렵지 않게 Level18의 쉘이 획득 되었습니다.

 


Level18의 패스워드는 why did you do it 이네요.

+ Recent posts