linux社区爱心援助Linux认证系列教程业界动态站务新闻公司招聘网络学院网址大全LPI专题CISCO专题
设为首页
加入收藏
管理团队
JSP  
JAVA  
PERL  
 您的位置:首页 > 开发语言 > perl >
栏目导栏
  php
  JSP
  ASP
  asp.net
  JAVA
  c/c++/c#
  perl
  JavaScript
  Basic
  Delphi
资料搜索
热门文章
·perl入门学习指南
·perl入门教程:Perl 的变量
·perl入门教程:Perl的语法与C语
·Perl文件及目录操作
·perl入门教程:Perl概述
·perl入门教程:正则表达式
·perl 学习笔记
·Perl常用系统函数
·perl中传递和存储文件句柄
·Perl连接Oracle数据库的方法
·curl+perl的自动MAIL报警程序
·使用 perldoc 找文档
·perl入门教程:Perl 程序的属性
·Perl新手的误区和新手必读
·Perl命令行应用介绍
最新文章
·perl 学习笔记
·Perl 特殊变量
·perl Base64码的获取
·perl 父子进程的数据库连接继承
·工作中的实用 perl 脚本
·perl中传递和存储文件句柄
·curl+perl的自动MAIL报警程序
·Perl类包的动态调用
·使用open创建的管道进行父子进
·perl 执行一个系统命令(svn in
·windows平台下根据可执行文件名
·关联数组(hash)
·Perl语言在风险评估的系统基础
·在Perl/CGI中使用模板
·PERL CGI 常见问题
Google
 
Perl CGI编程安全点滴
[ 作者:  加入时间:2007-10-11 17:31:59  来自:Linux联盟收集整理 ]

CGI在现在的互联网应用越来越广泛,CGI编程的安全问题也得到越来越多的重视。Perl作为CGI编程的主要语言之一,其安全性也受到很大的关注。

这里根据一直以来对 Perl免费/商业程序包的源代码的研究,得出一些较易被忽略的编程漏洞,在此将几个最常见的(主要是变量字符过滤方面)写出来,供广大程序员作为参考。  6scLinux联盟
1、“有毒”的NULL字符  6scLinux联盟
如果我说:"root"=="root",相信没有什么人反对。但同时我也这样说:"root"!="root"!还有多少人会认为我是个“正常人”?:)  6scLinux联盟
但在各种不同的编程语言中,确实存在着这种情况。  6scLinux联盟
对于每一个希望发现CGI漏洞的安全专家或黑客来说,最常用的方法之一是通过传递特殊字符(串),绕过CGI限制以执行系统级调用或程序。如果你仔细留意的话,或许也会发现NULL字符确实有它的“妙用”。:)  6scLinux联盟
阅读以下例子:  6scLinux联盟
# parse $user_input  6scLinux联盟
$database="$user_input.db";  6scLinux联盟
open(FILE "<$database");  6scLinux联盟
这个例子用于打开客户端指定的数据库文件。例如客户端输入"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程序:  6scLinux联盟
$user=$ARGV[1] # user the jr admin wants to change  6scLinux联盟
if ($user ne "root"){  6scLinux联盟
# do whatever needs to be done for this user }  6scLinux联盟
那么,聪明的你应该知道如何绕过这个限制修改root用户口令了吧?对了,只要使 $user="root",则PERL会执行上面程序中花括号内的语句。除非所有处理过程均使用PERL,否则一旦该变量传递给系统,则会造成安全问题。如修改root用户口令等。 

也许你认为很难遇到这种会造成严重安全问题的情况,那么我们能否将它作为一种寻找网站源程序漏洞的间接手段呢?不知你有没有经常遇到这种类型的CGI程序,该程序用于打开客户端(提交的表单中)要求的页面?如:  6scLinux联盟
page.cgi?page=1  6scLinux联盟
然后网站是否返回页面"1.html"呢?;-) 好,现在将其改为:  6scLinux联盟
page.cgi?page=page.cgi%00 (%00 == '' escaped)  6scLinux联盟
这样,我们就可以得到我们感兴趣的文件内容了!这种方法连PERL的"-e"参数也可绕过:  6scLinux联盟
$file="/etc/passwd.txt.whatever.we.want";  6scLinux联盟
die("hahaha! Caught you!) if($file eq "/etc/passwd");  6scLinux联盟
if (-e $file){  6scLinux联盟
open (FILE, ">$file");}  6scLinux联盟
绕过这段程序的后果你应该想像得到吧?:)  6scLinux联盟
解决方法?最简单地,过滤NULL空字符。在PERL程序中,  6scLinux联盟
$insecure_data=~s///g;  6scLinux联盟
2、漏网之鱼--反斜杠()  6scLinux联盟
对于每一个关心CGI安全的人,也许都看过 W3C 的 www.Security FAQ 中关于CGI安全编程一节。其中列出了建议过滤的字符:  6scLinux联盟
&;`'"|*?~<>^()[]{}$nr  6scLinux联盟
但我在很多时候发现反斜杠()往往被遗忘了。以下是正确的过滤表达式:  6scLinux联盟
s/([&;`'\|"*?~<>^()[]{}$nr])/\$1/g;  6scLinux联盟
但在很多商业的CGI程序中反斜杠却没有被包含进去,这可能是程序员们写程序时被这些过滤用的匹配表达式搞迷糊了? 那么,没有过滤反斜杠会造成安全问题吗?试想一下,如果向你的程序中发送如下一行内容:  6scLinux联盟
user data `rm -rf /`  6scLinux联盟
大多数情况下,程序员编写的程序会将以上内容过滤为:  6scLinux联盟
user data `rm -rf /`  6scLinux联盟
从而保护了系统。但如果PERL程序中忘记过滤了反斜杠,当客户端向该程序提交如下内容时:  6scLinux联盟
user data `rm -rf / `  6scLinux联盟
经过匹配表达式后为:  6scLinux联盟
user data \`rm -rf / \`  6scLinux联盟
怎么样,看出危险了吗?由于两个反斜杠经系统解释后为一个字符"",但`字符却因此没有被过滤掉,`rm -rf / `将被系统执行!不过,由于其中还含有一个反斜杠字符,执行时系统会出错。你自己想办法绕过这个限制吧?

利用反斜杠的另一个应用--绕过系统目录进入限制。请看以下表达式:  6scLinux联盟
s/..//g;  6scLinux联盟
这个匹配表达式的作用非常简单,就是过滤字符串中的".."。当输入为:  6scLinux联盟
/usr/tmp/../../etc/passwd  6scLinux联盟
将被过滤为:  6scLinux联盟
/usr/tmp///etc/passwd  6scLinux联盟
这样,你将无法访问/etc/passwd文件。(注:*nix系统允许///,试一下'ls -l/etc////passwd'命令就知道了。)  6scLinux联盟
现在,让我们的“好伙伴”反斜杠来帮忙。将输入改为:  6scLinux联盟
/usr/tmp/../../etc/passwd  6scLinux联盟
则由于反斜杠的存在而不符合过滤表达式。当PERL中存在如下程序段时,  6scLinux联盟
$file="/usr/tmp/.\./.\./etc/passwd";  6scLinux联盟
$file=s/..//g;  6scLinux联盟
system("ls -l $file");  6scLinux联盟
当运行到执行系统调用时,执行的命令会是"ls -l /usr/tmp/../../etc/passwd"。想知道会得到什么输出吗?自己在机器上试试吧。然而,以上方法只适用于系统调用或``命令中。无法绕过PERL中的'-e'命令和open函数(非管道)。如下程序:  6scLinux联盟
$file="/usr/tmp/.\./.\./etc/passwd";  6scLinux联盟
open(FILE, "<$file") or die("No such file");  6scLinux联盟
执行时将显示"No such file"并退出。我还没有找出绕过这个限制的方法。:(  6scLinux联盟
解决方法:只要别忘了过滤反斜杠字符(),就已足够了。  6scLinux联盟
3、畅通无阻的“管道”--字符"|"  6scLinux联盟
在PERL的open函数中,如果在文件名后加上"|",则PERL将会执行这个文件,而不是打开它。即:  6scLinux联盟
open(FILE, "/bin/ls")  6scLinux联盟
将打开并得到/bin/ls的二进制代码,但  6scLinux联盟
open(FILE, "/bin/ls|")  6scLinux联盟
将执行/bin/ls命令!

以下过滤表达式  6scLinux联盟
s/(|)/\$1/g  6scLinux联盟
可以限制这个方法。PERL会提示"unexpected end of file"。如果你找到绕过这个限制的方法,请告诉我。:-)  6scLinux联盟
综合应用  6scLinux联盟
6scLinux联盟
现在让我们综合以上几种编程安全漏洞加以利用。先举个例子,$FORM是客户端需要提交给CGI程序的变量。而在CGI程序中有如下语句:  6scLinux联盟
open(FILE, "$FORM")  6scLinux联盟
那我们可以将"ls|"传递给$FORM变量来获得当前目录列表。现在让我们考虑如下程序段:  6scLinux联盟
$filename="/safe/dir/to/read/$FORM"  6scLinux联盟
open(FILE, $filename)  6scLinux联盟
如何再执行"ls"命令呢?只要能使$FORM="../../../../bin/ls|"即可。如果系统对目录操作加入了".."过滤,则可利用反斜杠的漏洞绕过它。在这段程序中,我们还可以在命令中加入参数。如"touch /backend|",将建立/backend文件。(但我不会使用这个文件名,因为它是我的名字。现在,让我们在程序段中加入更多的安全限制:  6scLinux联盟
$filename="safe/dir/to/read/$FORM"  6scLinux联盟
if(!(-e $filename)) die("I don't think so!")  6scLinux联盟
open(FILE, $filename)  6scLinux联盟
这样我们还需要绕过"-e"的限制。由于我们在$FORM变量中使用了"|"字符,当"-e"运算符检查"ls|"文件时,因为不存在此文件而退出程序。如何当"-e"检查时去掉管道符,而调用open函数时又含有管道符呢?回忆一下在前面谈到的NULL字符的利用,我们就知道应该如何做了。只要使$FORM="ls|"(注:在客户端提交的表单中为"ls%00|")即可。其中的原理复习一下前面提到的内容就会明白了。需要说明的是,以上程序段中,我们无法象再上一段程序那样执行带参数的命令,这是因为"-e"运算符的限制所致。举例如下:  6scLinux联盟
$filename="/bin/ls /etc|"  6scLinux联盟
open(FILE, $filename)  6scLinux联盟
将显示/etc目录下文件列表。  6scLinux联盟
$filename="/bin/ls /etc|"  6scLinux联盟
if(!(-e $filename)) exit;  6scLinux联盟
open(FILE, $filename)  6scLinux联盟
将导致因不存在文件而退出。  6scLinux联盟
$filename="/bin/ls /etc|"  6scLinux联盟
if(!(-e $filename)) exit;  6scLinux联盟
open(FILE, $filename)  6scLinux联盟
将只显示当前目录下文件列表。

Linux联盟收集整理 ,转贴请标明原始链接,如有任何疑问欢迎来本站Linux论坛讨论
评论】【加入收藏夹】【 】【打印】【关闭
※ 相关链接
无相关信息