选择显示字体大小

perl cgi编程安全点滴


 cgi在现在的互联网应用越来越广泛,cgi编程的安全问题也得到越来越多的重视。perl作为cgi编程的主要语言之一,其安全性也受到很大的关注。在 w3c组织的 "www security faq" 之 "cgi scripts"一章中,perl安全编程就整整占了一节。由此可见 perl cgi 安全编程的重要性。 
  这里我不会重复 "www security faq" 的内容,而是根据一直以来对 perl免费/商业程序包的源代码的研究,得出一些较易被忽略的编程漏洞,在此将几个最常见的(主要是变量字符过滤方面)写出来,供广大程序员作为参考。 
  如果你对本文的内容有不同意见或任何建议,请告诉我。如果你发现了其它perl cgi 编程漏洞,也请告诉我。如果你也发表了关于这方面的文章,当然也请告诉我。:-) 

--------------------- 
1、“有毒”的null字符 
--------------------- 

  如果我说:"root"=="root",相信没有什么人反对。但同时我也这样说:"root"!="root"!还有多少人会认为我是个“正常人”?:) 
  但在各种不同的编程语言中,确实存在着这种情况。 
  对于每一个希望发现cgi漏洞的安全专家或黑客来说,最常用的方法之一是通过传递特殊字符(串),绕过cgi限制以执行系统级调用或程序。如果你仔细留意的话,或许也会发现null字符确实有它的“妙用”。:) 
  阅读以下例子: 

# parse $user_input 
$database="$user_input.db"; 
open(file "<$database"); 

这个例子用于打开客户端指定的数据库文件。例如客户端输入"backend",则系统将打开"backend.db"文件考只读方式)。(注:在这里我们暂且不讨论"../" 的安全问题。)这种处理方式在互联网中是很常见的。 
  现在,让我们在客户端输入"backend%00",在该perl程序中$database="backend.db",然后调用open函数打开该文件。但结果是什么呢?系统会打开"backend"文件(,如果该文件存在)! 
  出现这种情况的原因是由于perl允许在字符串变量中使用null空字符,而在c语言中字符串则不允许包含空字符。因此,也就有了"root"!="root"(在perl中)和"root"="root"(在c语言中)。由于系统内核/调用等都是使用c语言编写,因此当perl将"backend.db"字符串传递到(c语言的)链接库/程序时,空字符以后的字符将被忽略?(或许还有利用价值?我还没发现。:)) 
  这种编程缺陷的影响可大可小。试想一下,如果利用以上编程原理编写一个给系统其他管理员修改除了root外的其他用户口令的perl程序: 

$user=$argv[1] # user the jr admin wants to change 
if ($user ne "root"){ 
# do whatever needs to be done for this user } 

那么,聪明的你应该知道如何绕过这个限制修改root用户口令了吧?对了,只要使 $user="root",则perl会执行上面程序中花括号内的语句。除非所有处理过程均使用perl,否则一旦该变量传递给系统,则会造成安全问题。如修改root用户口令等。 
  也许你认为很难遇到这种会造成严重安全问题的情况,那么我们能否将它作为一种寻找网站源程序漏洞的间接手段呢?;-) 
  不知你有没有经常遇到这种类型的cgi程序,该程序用于打开客户端(提交的表单中)要求的页面?如: 

page.cgi?page=1 

然后网站是否返回页面"1.html"呢?;-) 好,现在将其改为: 

page.cgi?page=page.cgi%00 (%00 == '' escaped) 

这样,我们就可以得到我们感兴趣的文件内容了!这种方法连perl的"-e"参数也可绕过: 

$file="/etc/passwd.txt.whatever.we.want"; 
die("hahaha! caught you!) if($file eq "/etc/passwd"); 
if (-e $file){ 
open (file, ">$file");} 

绕过这段程序的后果你应该想像得到吧?:) 
  解决方法?最简单地,过滤null空字符。在perl程序中, 

$insecure_data=~s///g; 

------------------------ 
2、漏网之鱼--反斜杠() 
------------------------ 

  对于每一个关心cgi安全的人,也许都看过 w3c 的 www.security faq 中关于cgi安全编程一节。其中列出了建议过滤的字符: 

&;`'"*?~<>^()[]{}$nr 

但我在很多时候发现反斜杠()往往被遗忘了。以下是正确的过滤表达式: 

s/([&;`'\"*?~<>^()[]{}$nr])/\$1/g; 

但在很多商业的cgi程序中反斜杠却没有被包含进去,这可能是程序员们写程序时被这些过滤用的匹配表达式搞迷糊了? 
  那么,没有过滤反斜杠会造成安全问题吗?试想一下,如果向你的程序中发送如下一行内容: 

user data `rm -rf /` 

大多数情况下,程序员编写的程序会将以上内容过滤为: 

user data `rm -rf /` 

从而保护了系统。但如果perl程序中忘记过滤了反斜杠,当客户端向该程序提交如下内容时: 

user data `rm -rf / ` 

经过匹配表达式后为: 

user data \`rm -rf / \` 

怎么样,看出危险了吗?由于两个反斜杠经系统解释后为一个字符"",但`字符却因此没有被过滤掉,`rm -rf / `将被系统执行!不过,由于其中还含有一个反斜杠字符,执行时系统会出错。你自己想办法绕过这个限制吧?;-) 
  利用反斜杠的另一个应用--绕过系统目录进入限制。请看以下表达式: 

s/..//g; 

这个匹配表达式的作用非常简单,就是过滤字符串中的".."。当输入为: 

/usr/tmp/../../etc/passwd 

将被过滤为: 

/usr/tmp///etc/passwd 

这样,你将无法访问/etc/passwd文件。(注:*nix系统允许///,试一下'ls -l/etc////passwd'命令就知道了。) 
  现在,让我们的“好伙伴”反斜杠来帮忙。将输入改为: 

/usr/tmp/../../etc/passwd 

则由于反斜杠的存在而不符合过滤表达式。当perl中存在如下程序段时, 

$file="/usr/tmp/.\./.\./etc/passwd"; 
$file=s/..//g; 
system("ls -l $file"); 

当运行到执行系统调用时,执行的命令会是"ls -l /usr/tmp/../../etc/passwd"。想知道会得到什么输出吗?自己在机器上试试吧。;-) 
  然而,以上方法只适用于系统调用或``命令中。无法绕过perl中的'-e'命令和open函数(非管道)。如下程序: 

$file="/usr/tmp/.\./.\./etc/passwd"; 
open(file, "<$file") or die("no such file"); 

执行时将显示"no such file"并退出。我还没有找出绕过这个限制的方法。:( 

  解决方法:只要别忘了过滤反斜杠字符(),就已足够了。 

-------------------------------- 
3、畅通无阻的“管道”--字符"" 
-------------------------------- 

  在perl的open函数中,如果在文件名后加上"",则perl将会执行这个文件,而不是打开它。即: 

open(file, "/bin/ls") 

将打开并得到/bin/ls的二进制代码,但 

open(file, "/bin/ls") 

将执行/bin/ls命令! 
  以下过滤表达式 

s/()/\$1/g 

可以限制这个方法。perl会提示"unexpected end of file"。如果你找到绕过这个限制的方法,请告诉我。:-) 

综合应用 

  现在让我们综合以上几种编程安全漏洞加以利用。先举个例子,$form是客户端需要提交给cgi程序的变量。而在cgi程序中有如下语句: 

open(file, "$form") 

那我们可以将"ls"传递给$form变量来获得当前目录列表。现在让我们考虑如下程序段: 

$filename="/safe/dir/to/read/$form" 
open(file, $filename) 

如何再执行"ls"命令呢?只要能使$form="../../../../bin/ls"即可。如果系统对目录操作加入了".."过滤,则可利用反斜杠的漏洞绕过它。 
  在这段程序中,我们还可以在命令中加入参数。如"touch /backend",将建立/backend文件。(但我不会使用这个文件名,因为它是我的名字。:-)) 
  现在,让我们在程序段中加入更多的安全限制: 

$filename="safe/dir/to/read/$form" 
if(!(-e $filename)) die("i don't think so!") 
open(file, $filename) 

这样我们还需要绕过"-e"的限制。由于我们在$form变量中使用了""字符,当"-e"运算符检查"ls"文件时,因为不存在此文件而退出程序。如何当"-e"检查时去掉管道符,而调用open函数时又含有管道符呢?回忆一下在前面谈到的null字符的利用,我们就知道应该如何做了。只要使$form="ls"(注:在客户端提交的表单中为"ls%00")即可。其中的原理复习一下前面提到的内容就会明白了。 
  需要说明的是,以上程序段中,我们无法象再上一段程序那样执行带参数的命令,这是因为"-e"运算符的限制所致。举例如下: 

$filename="/bin/ls /etc" 
open(file, $filename) 

将显示/etc目录下文件列表。 

$filename="/bin/ls /etc" 
if(!(-e $filename)) exit; 
open(file, $filename) 

将导致因不存在文件而退出。 

$filename="/bin/ls /etc" 
if(!(-e $filename)) exit; 
open(file, $filename) 

将只显示当前目录下文件列表。

  


 


关键字 本文所属关键字

相关 与本文相关文章

分类 所有文章关键字导航

源码编程相关

Java   Asp   PHP   .Net   XML   C/C++   CGI   VB   Jsp   J2ee   J2se   J2me   EJB   Servlet   Tomcat   Resin   Struts   Weblogic   Eclipse   ANT   GUI   JMS   Web servise   IDEA   Webphere   Hibernate   Spring   Jboss   Applet   Swing   Socket   Javamail   Perl   Ajax   P2P   安全   模式   框架   测试   开源   游戏

SQL数据库相关

My-SQL   Ms-SQL   Access   DB2   Oracle   Sybase   SQLserver   索引   存储过程   加密   数据库   分页   视图  

手机无线相关

3G   Wap   CDMA   GRPS   GSM   IVR   彩信   短信   无线   增值业务

网页设计制作相关

HTML   CSS   网页配色   网页特效   Javascript   VBscript   Dreamweaver   Frontpage   JS   Web   网站设计

网站建设推广相关

建站经验   网站优化   网站排名   推广   Alexa

操作系统/服务器相关

Windows XP   Windows 2000   Windows 2003   Windows Me   Windows 9.x   Linux   UNIX   注册表   操作系统   服务器   应用服务器

图形图像多媒体相关

Photoshop   Fireworks   Flash   Coreldraw   Illustrator   Freehand   Photoimpact   多媒体   图形图像

标准 网站致力的规范

Valid CSS!

无不良内容,无不良广告,无恶意代码

Valid XHTML 1.0 Transitional

creativecommons