posix_setuid

(PHP 4, PHP 5, PHP 7, PHP 8)

posix_setuid设置当前进程的 UID

说明

posix_setuid(int $user_id): bool

设置当前进程的真实用户 ID。这是一个特权函数,需要系统上适当的权限(通常是 root)才能执行此函数。

参数

user_id

用户 ID。

返回值

成功时返回 true,失败时返回 false

示例

示例 #1 posix_setuid() 示例

此示例将显示当前用户 ID,然后将其设置为不同的值。

<?php
echo posix_getuid()."\n"; //10001
echo posix_geteuid()."\n"; //10001
posix_setuid(10000);
echo
posix_getuid()."\n"; //10000
echo posix_geteuid()."\n"; //10000
?>

参见

添加备注

用户贡献的备注 7 个备注

3
Leigh
10 年前
请注意,在 unix 上,如果您的目标用户没有有效的 shell,一些 php 函数(例如:tempnam)将无法正常工作。

$ grep www-data /etc/passwd
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin

$ cat test.php
#!/usr/bin/php -q
<?php
$info
=posix_getpwnam("www-data");
$id=$info["uid"];

$file=tempnam("/tmp","something");
print
"PRE SetUID: $file\n";

$SETUID=posix_setuid($id);

$file=tempnam("/tmp","something");
print
"POST SetUID: $file\n";
?>

$ sudo ./test.php
PRE SetUID: /tmp/somethingrsb1qZ
POST SetUID
1
TheWanderer
17 年前
在许多 UNIX 系统(在 Debian GNU/Linux 上测试)上,SUID 对脚本是禁用的,只对二进制文件有效。如果您需要 setuid,则必须使用运行 setuid() php 脚本的包装二进制文件。这是一个例子

$ nano suexec.cpp
#include <stdlib>
using namespace std;
int main()
{
system("php /home/php/php_user.php");
return 0;
}

$ g++ -o suexec suexec.cpp
$ sudo chown root:root suexec
$ sudo chmod 4755 root

然后我们创建一个简短的 PHP 脚本以设置进程 uid(您应该已经知道如何执行此操作)。不要尝试在 php.ini 中尝试 auto_prepend_file,它不会像预期的那样工作。
1
reuben @ nospam me
17 年前
作为对上面建议在用 C 编写的 setuid 程序中使用 system() 的备注的回应,这通常对安全来说是个坏主意。

您应该使用标准库调用(如 execl())来代替,因为 system() 可以通过 SHELL、IFS 和可能的其他变量进行操作以执行错误的事情。
0
fm at farhad.ca
16 年前
当您从 root 到其他用户执行 posix_setuid 时,您将无法根据其权限访问 root 拥有的文件。例如,如果您更改进程的所有者,并且仍然需要以 600 权限打开 root 拥有的文件进行读写,您将收到权限被拒绝的错误。
有一些方法可以做到这一点(例如,unix 套接字或 tcp 守护进程等),但可能最简单的方法是

在更改进程所有权之前打开文件,将文件指针保存在全局变量中,并在更改所有权后使用它。

例如,假设 /root/test_file 是一个由 root:root 拥有的文件,具有 600 权限,并且您在 root 下运行此脚本。此代码将无法工作

<?php
// 将进程所有权更改为 nobody
posix_setgid(99);
posix_setuid(99);

$fd = fopen('/root/test_file','a');
fwrite($fd,"some test strings");
fclose();

?>

但这个代码将可以工作

<?php
$fd
= fopen('/root/test_file','a');

// 将进程所有权更改为 nobody
posix_setgid(99);
posix_setuid(99);

fwrite($fd,"some test strings");
fclose();

?>

希望这对某些人有帮助。

[在 CentOS 5 - Linux 2.6.x - PHP 5.2.x 上测试]
0
hpaul/at/abo/dot/fi
18 年前
似乎,如果您尝试将 uid 更改为当前活动用户(即使您不是 root),此函数也会返回 true。

在某些情况下,可以为您节省一个 if 语句。
0
simon at dont-spam-me-pleease dot simonster dot com
22 年前
以下是一些 Perl 代码,用于运行 setuid 的 PHP 脚本。只需将其放入 CGI 中,使该 CGI 成为 setuid 且可执行的,然后在您通常调用 PHP 脚本的地方调用该 CGI。

#!/usr/local/bin/perl

# Perl 包装器,用于执行 setuid 的 PHP 脚本
# ?2002 Simon Kornblith
# 需要 PHP CGI

# 使 UID = EUID(以便 PHP 可以运行 setuid 的 system() 和 exec())
$< = $>;
# 将此设置为路径,以便我们无法被污染
$ENV{'PATH'} = "/home/httpd/cgi-bin/ssl/admin";
# 打开 PHP 脚本(必须以 !#/usr/local/bin/php 或类似形式开头,并且
# 可执行)
open(STDOUT, "| /home/httpd/cgi-bin/ssl/admin/new.php");
# 将 STDIN 写入 PHP 脚本
print while <STDIN>;
-2
rjmooney at syr dot edu
20 年前
对于简单的操作,您可以轻松创建一种权限分离机制来执行需要提升权限的命令。

例如,在创建文档存储库时,我需要根据用户的登录名提供对某些目录和文件操作的访问权限。将 Web 服务器提供对用户可能需要访问的所有目录的访问权限既不现实也不安全,因此我创建了一个 setuid() 脚本,为我执行所需的操作。

代码摘录演示了这一点

<?

//
// main.php
//

// 执行特权 stat()
function privsep_stat($path)
{
// 调用权限分离程序,请求指定路径的 stat
$serialized_result = exec("/path/to/privsep.php stat " . $path, $oa, $return_code);
if ($return_code != 0)
{
return false;
}

// 返回反序列化的对象
return unserialize($serialized_result);
}

// 获取我们作为 Web 服务器用户无法访问的文件的统计信息
$st = privsep_stat("/private_directory/private_file");
print_r($st);

?>

privsep.php 如下所示

#!/usr/local/bin/php
<?

//
// privsep.php
//

// 不允许从 Web 运行此脚本
if (isset($_SERVER['REQUEST_METHOD']))
{
print "<br>此程序不打算直接从 WWW 运行。\n";
return 1;
}

// TODO:在此添加您的参数验证

// 请求了 stat
if ($argv[1] == "stat")
{
// 重置 stat() 缓存
clearstatcache();

// 原始用户 ID
$original_uid = posix_get_uid();

// 将我们的实际用户 ID 设置为 root
$success = posix_setuid(0);
if (!$success)
{
print "错误:无法 setuid()。\n";
return 1;
}

// 存储文件统计信息
$st = stat($argv[2]);

// 将实际 UID 恢复到调用用户 ID
$success = posix_setuid($original_uid);
if (!$success)
{
print "错误:无法 setuid()。\n";
return 1;
}

// 也删除有效 UID
$success = posix_seteuid($original_uid);
if (!$success)
{
print "错误:无法 seteuid()。\n";
return 1;
}

// 序列化结果并打印
$result = serialize($st);
print $result;

// 成功!
return 0;
}
?>

最后,privsep.php 的权限配置如下

# chown root:wheel privsep.php
# chmod 4755 privsep.php

并且如下所示

-rwsr-xr-x 1 root wheel 1000 Nov 1 00:00 privsep.php

将 privsep.php 保持在您的文档根目录之外可能很明智,以帮助减轻任何成功的攻击。

此方法可以扩展到其他功能。自行承担风险使用。
To Top