Chinaunix首页 | 论坛 | 博客
  • 博客访问: 23254
  • 博文数量: 12
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 95
  • 用 户 组: 普通用户
  • 注册时间: 2014-10-28 14:12
文章分类
文章存档

2015年(6)

2014年(6)

我的朋友

分类: Web开发

2015-01-08 15:55:14

为了安全保护,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 "
End";

运行结果:

可见,运行的用户确实是apache(48) 。
3、测试
修改一些CGI脚本,让其运行一个需要root权限的命令:

......
my $HTML=qx(id);
print $HTML,"
";
$HTML=qx(/sbin/iptables -L);
print $HTML;
print "
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)

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)


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
#include
#include
#include

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:
'
/usr/bin/id
echo '
'
/sbin/iptables -L

编译生成run_root程序:

# gcc -o run_root -Wall run_root.c

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

......
print "From CGI scripts:
";
my $HTML=qx(id);
print $HTML,"
";
$HTML=qx(/var/www/cgi-bin/run_root);
print $HTML;
print "
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:
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel)

From test.sh:

uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel)


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)用户执行的,权限正确。
阅读(2584) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~