[原]在apache中运行root权限的CGI脚本

    为了安全保护,apache默认的编译选项是不支持root作为其服务运行的用户的,而应使用apache用户来运行。但在某些情况下,我们确实有这样的需求,如:编写了某个CGI程序,其中需要调用/sbin下的命令,挂载某个设备文件、修改iptables参数等。下面我们利用suid权限来解决,提供两个方法。
(注意,一旦给脚本赋予suid权限,让apache可运行root权限的程序时,务必做好安全检查,特别是由客户端输入的信息。)

一、apache 默认状态
1、先来看看apache的配置文件

引用
# cat /etc/httpd/conf/httpd.conf
……
User apache
Group apache
……

可见,是使用apache用户和组来运行httpd服务的。
2、验证
写个CGI脚本:
# cat /var/www/cgi-bin/cgitest.pl

#!/usr/bin/perl -w
use strict;
use CGI qw(:all);
use CGI::Carp qw(fatalsToBrowser);
print header (-charset=>"gb2312");

my $HTML=qx(id);
print $HTML;
print "<br>End";

运行结果:
点击在新窗口中浏览此图片……
my $HTML=qx(id);
print $HTML,"<br>";
$HTML=qx(/sbin/iptables -L);
print $HTML;
print "<br>End";

命令行下,使用root用户运行该脚本:

引用
# ./cgitest.pl
Content-Type: text/html; charset=gb2312

uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel)
<br>Chain INPUT (policy ACCEPT)
target     prot opt source               destination
ACCEPT     tcp  —  anywhere             anywhere            tcp dpt:rfe

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

再来看看浏览器上运行的结果:
点击在新窗口中浏览此图片

引用
uid=48(apache) gid=48(apache) groups=48(apache)
<br><br>End

运行命令的结果没有显示出来,看看httpd服务器上的后台日志:

引用
10.8.1.10 – – [17/Mar/2009:11:29:06 +0800] "GET /cgi-bin/cgitest.pl HTTP/1.1" 200 59
[Tue Mar 17 11:34:04 2009] [error] [client 10.8.1.10] iptables v1.3.5:
[Tue Mar 17 11:34:04 2009] [error] [client 10.8.1.10] can't initialize iptables table `filter': Permission denied (you must be root)
[Tue Mar 17 11:34:04 2009] [error] [client 10.8.1.10]
10.8.1.10 – – [17/Mar/2009:11:34:04 +0800] "GET /cgi-bin/cgitest.pl HTTP/1.1" 200 59

信息非常清楚了,因为是使用apache用户来运行httpd上的CGI程序,所以权限不足。

二、解决问题
要解决这个问题,可以使用suid权限。
1、借用一个第三方代理
由于shell本身不能直接利用suid特性,所以,需要使用一个第三方的代理来完成。下面是一个用C写的程序:
(程序源码来自:这里)
# cat run_root.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
    uid_t uid ,euid;

    uid = getuid() ;
    euid = geteuid();

    //printf("my uid :%u\n",getuid());  //这里显示的是当前的uid 可以注释掉.
    //printf("my euid :%u\n",geteuid()); //这里显示的是当前的euid
    if(setreuid(euid, uid))  //交换这两个id
        perror("setreuid");
    //printf("after setreuid uid :%u\n",getuid());
    //printf("afer sertreuid euid :%u\n",geteuid());

    //system("/sbin/iptables -L"); //执行iptables -L命令
   system("/var/www/cgi-bin/test.sh"); //执行一个需root权限运行的脚本
    return 0;
}

关键在于,利用该程序交换执行用户的uid和程序的euid,以实现apache用户执行root权限的功能。因程序中没有提供参数,可以把需要root权限执行的命令写在某个脚本(test.sh)中一同运行。该脚本的内容:
# cat /var/www/cgi-bin/test.sh

#!/bin/bash
echo 'From test.sh:<br>'
/usr/bin/id
echo '<br>'
/sbin/iptables -L

编译生成run_root程序:

# gcc -o run_root -Wall run_root.c

修改CGI脚本,调用run_root插件:

……
print "From CGI scripts:<br>";
my $HTML=qx(id);
print $HTML,"<br>";
$HTML=qx(/var/www/cgi-bin/run_root);
print $HTML;
print "<br>End";

◎ 调用前,先来看看run_root的用户和权限:

引用
# ll run_root
-rwxr-xr-x 1 root root 5162 03-17 12:00 run_root

看看命令行的调用结果:
# ./cgitest.pl

引用
Content-Type: text/html; charset=gb2312

From CGI scripts:<br>uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel)
<br>From test.sh:<br>
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel)
<br>
Chain INPUT (policy ACCEPT)
target     prot opt source               destination
ACCEPT     tcp  —  anywhere             anywhere            tcp dpt:rfe

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

看看浏览器的显示:
点击在新窗口中浏览此图片

引用
# chmod u+s run_root
# ll run_root
-rwsr-xr-x 1 root root 5162 03-17 12:00 run_root

再看看浏览器的结果:
点击在新窗口中浏览此图片 [原]在apache中运行root权限的CGI脚本内文分页: [1] [2]

Apache 因SSL Library Certificate has expired 无法启动
Apache中虚拟主机设置泛域名解析
[转]Apache的Satisfy详解
Subversion 安全点滴
使用mod_dav_svn访问Subversion仓库

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/110925.html

(0)
上一篇 2021年8月26日
下一篇 2021年8月26日

相关推荐

发表回复

登录后才能评论