Mar 19

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

linuxing , 11:16 , 网络服务 » 常见服务 , 评论(1) , 引用(0) , 阅读(38578) , Via 本站原创 | |
    为了安全保护,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";

运行结果:
点击在新窗口中浏览此图片
可见,运行的用户确实是apache(48) 。
3、测试
修改一些CGI脚本,让其运行一个需要root权限的命令:

......
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

再来看看浏览器上运行的结果:
点击在新窗口中浏览此图片
HTML源码是:
引用
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

看看浏览器的显示:
点击在新窗口中浏览此图片
似乎还是不行哦。

◎ 给run_root赋予suid权限
引用
# chmod u+s run_root
# ll run_root
-rwsr-xr-x 1 root root 5162 03-17 12:00 run_root

再看看浏览器的结果:
点击在新窗口中浏览此图片
成功了。看看图中红色标记的地方,运行test.sh命令时,是作为root(0)用户执行的,权限正确。
内文分页: [1] [2]
Tags:
logicmd Email Homepage
2012/11/06 15:58
如果就my $HTML=qx(id);都permission deny怎么办?是apache配置错误么?
分页: 1/1 第一页 1 最后页
发表评论
表情
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
打开HTML
打开UBB
打开表情
隐藏
记住我
昵称   密码   游客无需密码
网址   电邮   [注册]