第四章 做几个试验:第四节、一些脚本漏洞的应用
一、邮件脚本特殊字符应用:
我们来讨论下面这个例子:有一个著名的"邮件脚本,它的主要任务是把访问者填写的表单发送到webmaster的邮箱。下面看一下有关的代码:
— vuln1.html – The submission form —
Thankyou for visiting my site. Please submit your comments and suggestions here:
— EOF —
— vuln1.pl – The vulnerable perl script —
#!/usr/bin/perl
# Output will be an html page
print "Content-type: text/htmlnn";
# Get input from form into the @pairs array
@pairs = split(/&/, $ENV{‘QUERY_STRING’});
# For each name/value pair in the array foreach
$pair (@pairs) {
# Split the pair into their own variables
($name, $value) = split(/=/, $pair);
# Convert the form-encoding back
$name =~ tr/+/ /;
$name =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
# Store the destination email address and comments in variables
if ($name eq "address") {
# Store the destination email
address $address = $value; }
elsif ($name eq "comments") {
# Store the comments
$comments = $value; } }
# At this point $address holds the address specified on the form, and
# $comments holds the user’s comments.
# — "Active" part
# See discussion for details of this part
open(MAIL,"| /bin/mail $address");
print MAIL "$comments";
close(MAIL);
# — End of "active" part
# Print output for the user print Thanks for your comments
EOT– EOF —
以上这个例子包括两段程序。Html段负责提交用户的输入,并且也是易受攻击的。如果你不了解Perl那么你也没必要知道他的原理。你只要知道目的Email地址(就是在html页面被指明为hidden的元素)和你输入的内容(根据textarea的输入)被保存,然后在“active”部分向“邮件”程序提交就可以了。
在Perl程序中,open函数的用处打开文件,但是这里更重要的是管道符。在这句话中,指向命令“/bin/mail ”的管道被打开,你在Html页面填写的内容被发送到了指定的webmaster的邮箱中去了。
看看发生了什么? “/bin/mail ”命令是由你在html页面提交表单时激活的。如果一个恶意的用户在本地保存并改装了表单会发生什么事情呢?如果html页面没有驻留在服务器,你必须在“action”中填写完整的URL。现在提交的Email地址被改成了你自己的Email地址,你的提交内容也就发送到了自己的Email里去了。
如果你如下改装表单,试想会发生什么?
“value=" ”
在script程序中,这样的Email地址将被解析为:“/bin/mail ”(注意:这里我虽然用/etc/passwd,但是这仅仅是个说明原理的举例。现在大多数系统的passwd文件对于入侵者来说都不会包含有效的密码信息)
如果你发现script程序过滤“;”,你可以试“|”符号,或者用“n”来换行,这样做的目的是重新运行命令按你的意图执行。记住:使用“|”将使第一条命令的输出回传给第二命令,并且在web上发送换行符你需要用到的是“%0a”。于是地址部分现在变成了“value=" ”
二、SSI的危险应用:
SSI的意思是“Server Side Includes”。SSI是一些能放在html中的、被服务器解析的指令。这些页面通常都支持扩展的.shtml(或者更底的版本),不过这还是要看服务器的设置。有些服务器对所有的html都解析。如果你可以让服务器解析你自己写的SSI,那么你就能够执行命令和其他的一些动作了,事实上很多CGI程序都没有考虑这些东西,比如下面的例子:
— vuln2.shtml – A public comments page —
Thankyou for visiting my site. Please submit your comments and suggestions here:
Here’s what other people have had to say:
— EOF —
— vuln2.pl – The vulnerable perl script —
#!/usr/bin/perl
# Define the location of the page to be updated
# Change this to the location of vuln2.shtml if you’re trying this out
$pagename = "/home/web/html/vuln2.shtml";
# Print content-type header
print "Content-type: text/htmlnn";
# Get input from form into the @pairs array
@pairs = split(/&/, $ENV{‘QUERY_STRING’});
# For each name/value pair in the array foreach
$pair (@pairs) {
# Split the pair into their own variables
($name, $value) = split(/=/, $pair);
# Convert the form-encoding back
$name =~ tr/+/ /;
$name =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
# Store the comments in a variable
if ($name eq "comments") {
# Store the comments
$comments = $value; } }
# At this point $comments holds the user’s comments.
# Separate each comment in the output file
$comments .= "n n";
# — "Active" part # Open the file for read/write
open(FILE,"+;
# Search through the array and insert the comments just before the #
line $linenum = 1;
foreach $line (@list) { if ($line =~ /^/) { $linenum–;
splice(@list, $linenum, 0, $comments);
last; }
$linenum++; }
# Write the array back to the file
seek(FILE,0,0);
truncate(FILE,0);
foreach $line (@list) { print FILE $line; }
# Close the file
close(FILE);
# — End "active" part
# Print output for the user print Thanks for your comments. Click here to return to the comments page
EOT — EOF —
这里的两段代码其实是一个简单的留言板,你可以发现.shtml文件用SSI来显示页眉和页脚,当我们浏览网页的时候,SSI所指向的代码将会被执行。注意在.shtml文件中用标记的地方,其后的内容都将被认为是SSI指令而执行,然后等你回到页面上,你就可以看到你所需要的密码文件了。(注意:密码文件可能是很长的一行文字——这是因为html没有在该换行的时候插入换行符。你可以从浏览器的“查看源文件”来查看)。
这一切都是我们所希望的,但是很多服务器都屏蔽了exec指令来防止这类攻击。在以上的例子中,你最多能做到的就是用include指令来取得一个你所知道路径的文件内容。象密码文件对于你的当前权限来说可能不可访问。注意有的文件(比如CGI scripts)不会因为include调用而暴露它们的源码。从入侵者的角度来看,include指令的价值并不是很大,如果不能exec,那你能做的就更有限了。