标题:selinux中php以root身份sudo执行shell命令

发表于

环境:centos7 selinux开启,php文件/test/test.php,shell文件/test/test.sh的权限是root,php和nginx的用户不是root,是test,/test/test.php文件内容如下:

<?php
system("sudo /test/test.sh",$status);
if($status == 'true') { echo "成功!"; }
else { echo "失败!"; }
?>

问题:访问http://localhost/test/test.php,发现php无法执行test.sh

分析:

1、test用户执行root权限,需要做sudo授权,做如下操作,vi /etc/sudoers 添加

test ALL=(root) NOPASSWD: /test/test.sh

2、用test用户登录到centos系统中,执行sudo /test/test.sh,已经正常,但是http://localhost/test/test.php失败,如果关掉selinux,则php执行成功,说明是selinux的缘故。

执行setenforce 1打开selinux,又做如下调试:
a, 把test.php中执行的命令改成system("/bin/whoami",$status);这时php执行成功。
b, 把1中test.php中执行的命令改成system("sudo -V",$status);这时php执行成功。
c, 把1中test.php中执行的命令改成system("sudo /bin/whoami",$status);在/etc/sudoers 中添加whoami的sudo权限,这时php执行失败。
说明php和shell脚本都没有问题,php可以执行shell脚本。问题出在php执行了sudo,但没有获取到root权限。

3、google查找相关资料,执行getsebool -a | grep httpd_mod_auth_pam,发现为off状态,所以下边操作非常重要,执行:

# setsebool -P httpd_mod_auth_pam=1

4、经测试,至此php已经可以执行部分sudo命令如sudo whoami,但php依然无法正常执行这里的test.sh,继续google,做如下操作:

# setenforce 0
# echo "" > /var/log/audit/audit.log
# service auditd restart
<访问你的php页面http://localhost/test/test.php>
# setenforce 1
# grep denied /var/log/audit/audit.log
# grep avc /var/log/audit/audit.log

这时候发现日志有报错:

type=AVC msg=audit(1512616099.474:6279928): avc: denied { setrlimit } for pid=24197 comm="sudo" scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:system_r:httpd_t:s0 tclass=process
type=AVC msg=audit(1512616099.516:6279929): avc: denied { execmem } for pid=24213 comm="java" scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:system_r:httpd_t:s0 tclass=process

请注意红色部分,sudo和java,因为test.sh文件里我写的是java代码,所以有java报错,如果你日志有报其他的错误,比如php-fpm等,就根据报错进行模块安装,所以,下一步,做如下操作:

# cat /var/log/audit/audit.log | audit2allow -M sudo

提示

******************** IMPORTANT ***********************
To make this policy package active, execute:

semodule -i sudo.pp

根据提示继续执行:

# semodule -i sudo.pp

又提示:

libsemanage.semanage_direct_install_info: Overriding sudo module at lower priority 100 with module at priority 400.

至此,问题有点明了了,sudo模块的权限不够,这个操作用更高权限的sudo模块覆盖了原来低权限的sudo模块!

最后执行:
# cat /var/log/audit/audit.log | audit2allow -M java
# semodule -i java.pp

执行# getenforce确认是Enforcing状态,再去测试http://localhost/test/test.php,发现已经正常了,到这里就全部OK了!

PS:
1、如果是日志中提示php-fpm权限错误,就执行# cat /var/log/audit/audit.log | audit2allow -M php-fpm和# semodule -i php-fpm.pp
2、最初是简单的修改了文件权限# chcon -R -t usr_t /test/,发现其实是没用的。
3、参考资料中用到了semodule -i httpd_sudo,但是我发现这个安装和删除掉,都没什么影响,可能是系统中具体的配置有区别吧。
4、解决此类问题,查找资料必须用google,访问不了外网,那就没办法了,baidu就算了吧。

再附加调试中常用的几个命令:
# semodule -e sudo  //enable,注意是sudo,不是sudo.pp
# semodule -r sudo  //remove
# semodule -R  //Refresh
# setenforce 1  //打开selinux
# setenforce 0  //关闭selinux
# getenforce  //查看selinux状态
# yum install policycoreutils //如果没有selinux相关命令,要安装所属包

参考文档:https://stackoverflow.com/questions/24149071/php-shell-exec-and-sudo-commands-for-selinux-administration

网络摘录:php调用shell怎么调试?
不好调试,无log可查,只能看输出,nginx,php的log没有调用shell的相关信息,我有一些以经验,屡试不爽
1,检查php启动用户权限,文件本身能被执行,php启动用户也要能执行该文件的权限。以前遇到过一个情况是,php执行一个shell怎么都执行不了,后来才发面,没有chmod +x操作。
2,php是可以捕获取shell的输出的,但是要知道,不是所有命令执行都是有输出的,也就是说,成功,失败,或者没执行没办法区别,搞不清。这个时候,我们可以shell脚本中输出,用echo就可以。这样我们可以知道,执行到什么地方,可以知道,在什么地方出错了。
3,直接通过su切换到php的启动用户,然后在linux命令行下执行,有人问了,nologin用户无法su,那就直接useradd一个,改一下php的启动用户。如果用php的启动用户测试成功,通过php脚本去执行,基本也是能通过的。
4,在这里要注意一点,路径问题,相对路径和绝对路径,尽量用绝对路径。