当前位置:WooYun >> 漏洞信息

漏洞概要 关注数(24) 关注此漏洞

缺陷编号:wooyun-2013-037204

漏洞标题:代码审计系列2:Simple Down 简单下载系统 v5.4 各种SQLi、XSS

相关厂商:Simple Down

漏洞作者: LaiX

提交时间:2013-09-16 12:06

修复时间:2013-12-15 12:06

公开时间:2013-12-15 12:06

漏洞类型:SQL注射漏洞

危害等级:高

自评Rank:15

漏洞状态:未联系到厂商或者厂商积极忽略

漏洞来源: http://www.wooyun.org,如有疑问或需要帮助请联系 [email protected]

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2013-09-16: 积极联系厂商并且等待厂商认领中,细节不对外公开
2013-12-15: 厂商已经主动忽略漏洞,细节向公众公开

简要描述:

整个程序无任何过滤,满城尽是 SQLi 、 XSS。

详细说明:

1.拿到程序后,我们先来看看 登录页面。(login.php)
先来看看管理登录页面(admin/adminlogin.php)的核心代码

<?php
if(!isset($_POST['adminlogin'])){
echo "<script type='text/javascript'>";
echo "document.title = '·Ç·¨·ÃÎÊ'";
echo "</script>";
echo "·Ç·¨·ÃÎÊ¡£3Ãëºó½«·µ»ØµÇ½ҳÃ棬Èç¹ûÄãµÄä¯ÀÀÆ÷²»Ö§³Ö×Ô¶¯Ìøת£¬Çëµã»÷&nbsp;<a href='index.php' style='color:green;'>ÕâÀï</a>";
echo '<script type="text/javascript">';
echo 'GoIndex()';
echo '</script>';
exit();
}
$username = strval($_POST['t_UserName']);
$password = strval($_POST['t_UserPass']);
$password = MD5($password);
if($username != "admin")
{
echo "<script type='text/javascript'>";
echo "document.title = '¹ÜÀíÔ±Õ˺ŴíÎó'";
echo "</script>";
echo "¹ÜÀíÔ±Õ˺ŴíÎó¡£3Ãëºó½«·µ»ØµÇ½ҳÃ棬Èç¹ûÄãµÄä¯ÀÀÆ÷²»Ö§³Ö×Ô¶¯Ìøת£¬Çëµã»÷&nbsp;<a href='index.php' style='color:green;'>ÕâÀï</a>";
echo '<script type="text/javascript">';
echo 'GoIndex()';
echo '</script>';
exit();
}
$check_query = mysql_query("SELECT ID FROM HBDX_USERS WHERE USER_NAME = '$username' AND USER_PASS = '$password' LIMIT 1");
if($row = mysql_fetch_array($check_query))
{
$_SESSION['username'] = $username;
$_SESSION['userid'] = $row['ID'];
echo '<script type="text/javascript">';
echo "AutoOpenURL('admin.php')";
echo '</script>';
exit();
}
else
{
echo "<script type='text/javascript'>";
echo "document.title = '¹ÜÀíÔ±µÇ½ʧ°Ü'";
echo "</script>";
echo "¹ÜÀíÔ±µÇ½ʧ°Ü£¬Çë¼ì²éÕ˺źÍÃÜÂëÊÇ·ñÕýÈ·¡£3Ãëºó½«·µ»ØµÇ½ҳÃ棬Èç¹ûÄãµÄä¯ÀÀÆ÷²»Ö§³Ö×Ô¶¯Ìøת£¬Çëµã»÷&nbsp;<a href='index.php' style='color:green;'>ÕâÀï</a>";
echo '<script type="text/javascript">';
echo 'GoIndex()';
echo '</script>';
exit();
}
mysql_free_result($result);
mysql_close($conn);
?>


if($username != "admin")

$password = MD5($password);

这两句发现,似乎用户名只允许使用admin 并且密码被md5加密。
现在似乎还无法绕过登录
我们再来看看用户登录页面(login.php)的核心代码

<?php
require_once "header.php";
if(!isset($_POST['login'])){
echo "<script type='text/javascript'>";
echo "document.title = '非法访问'";
echo "</script>";
echo "非法访问。3秒后将返回登陆页面,如果你的浏览器不支持自动跳转,请点击&nbsp;<a href='login.html' style='color:green;'>这里</a>&nbsp;如果您还没有账号可从&nbsp;<a href='reg.html' style='color:green;'>这里</a>&nbsp;前往注册。";
echo '<script type="text/javascript">';
echo 'GoLogin()';
echo '</script>';
exit();
}
$username = strval($_POST['t_UserName']);
$password = strval($_POST['t_UserPass']);
$password = MD5($password);

$check_query = mysql_query("SELECT ID FROM HBDX_USERS WHERE USER_NAME = '$username' AND USER_PASS = '$password' LIMIT 1");
if( $row = mysql_fetch_array( $check_query ) ){ //登录成功
$_SESSION['username'] = $username;
$_SESSION['userid'] = $row['ID'];
echo "<script type='text/javascript'>";
echo "document.title = '登陆成功'";
echo "</script>";
echo "用户登陆成功。3秒后将跳转到网站主首页,如果你的浏览器不支持自动跳转,请点击&nbsp;<a href='index.php' style='color:green;'>这里</a>&nbsp;返回首页。如果您还没有账号可从&nbsp;<a href='reg.html' style='color:green;'>这里</a>&nbsp;前往注册。";
echo '<script type="text/javascript">';
echo 'GoIndex()';
echo '</script>';
}
else
{
echo "<script type='text/javascript'>";
echo "document.title = '登陆失败'";
echo "</script>";
echo "用户登陆失败。3秒后将返回登陆页面,如果你的浏览器不支持自动跳转,请点击&nbsp;<a href='login.html' style='color:green;'>这里</a>&nbsp;如果您还没有账号可从&nbsp;<a href='reg.html' style='color:green;'>这里</a>&nbsp;前往注册。";
echo '<script type="text/javascript">';
echo 'GoLogin()';
echo '</script>';
}
?>


这个页面出现了一个比较经典的语句

$check_query = mysql_query("SELECT ID FROM HBDX_USERS WHERE USER_NAME = '$username' AND USER_PASS = '$password' LIMIT 1");
if( $row = mysql_fetch_array( $check_query ) ){ //登录成功


这句SQL语句的意思是查询是否存在管理员,如果存在就提升权限。
看了一下周围的代码,没有发现任何过滤。
根据此SQL语句结构,我们构造一个"万能密码":

1.png


进入服务器后就会变成:

"SELECT ID FROM HBDX_USERS WHERE USER_NAME = 'admin' # AND USER_PASS = '123456' LIMIT 1"


意为:查询目标表中是否存在admin用户名,而查询密码的语句已经被 # 所注释。
登录一下果然进入了:

2.png


3.png


2.再来看看注册页面。

<?php
require_once 'header.php';
if(!isset($_POST['reg'])){
echo "<script type='text/javascript'>";
echo "document.title = '非法访问'";
echo "</script>";
echo "非法访问1。3秒后将返回注册页面,如果你的浏览器不支持自动跳转,请点击&nbsp;<a href='reg.html' style='color:green;'>这里</a>&nbsp;如果您已经有账号可从&nbsp;<a href='login.html' style='color:green;'>这里</a>&nbsp;前往登陆。";
echo '<script type="text/javascript">';
echo 'GoReg()';
echo '</script>';
exit();
}
$username = strval($_POST['t_UserName']);
$disname = strval($_POST['iptNickName']);
$userqq = strval($_POST['iptCard']);
$password = strval($_POST['t_UserPass']);
$password = MD5($password);
$repass = strval($_POST['t_RePass']);
$email = strval($_POST['t_Email']);
$datetime = date("Y-m-d H:i:s");


$reg = mysql_query("SELECT ID FROM HBDX_USERS WHERE USER_NAME = '".$username."'");
$regnum = mysql_num_rows($reg);
if($regnum > 0){
echo "用户名&nbsp;<b style='color:green;'>".$username."</b>&nbsp;已经被使用<br/>";
echo "<script type='text/javascript'>";
echo "document.title = '注册失败'";
echo "</script>";
echo "用户注册失败。3秒后将返回注册页面,如果你的浏览器不支持自动跳转,请点击&nbsp;<a href='reg.html' style='color:green;'>这里</a>&nbsp;如果您已经有账号可从&nbsp;<a href='login.html' style='color:green;'>这里</a>&nbsp;前往登陆。";
echo '<script type="text/javascript">';
echo 'GoReg()';
echo '</script>';
exit();
}
$reg = mysql_query("SELECT ID FROM HBDX_USERS WHERE USER_DISPLAYNAME = '".$disname."'");
$regnum = mysql_num_rows($reg);
if($regnum > 0){
echo "昵称&nbsp;<b style='color:green;'>".$disname."</b>&nbsp;已经被使用<br/>";
echo "<script type='text/javascript'>";
echo "document.title = '注册失败'";
echo "</script>";
echo "用户注册失败。3秒后将返回注册页面,如果你的浏览器不支持自动跳转,请点击&nbsp;<a href='reg.html' style='color:green;'>这里</a>&nbsp;如果您已经有账号可从&nbsp;<a href='login.html' style='color:green;'>这里</a>&nbsp;前往登陆。";
echo '<script type="text/javascript">';
echo 'GoReg()';
echo '</script>';
exit();
}
$reg = mysql_query("SELECT ID FROM HBDX_USERS WHERE USER_QQ = '".$userqq."'");
$regnum = mysql_num_rows($reg);
if($regnum > 0){
echo "QQ号码&nbsp;<b style='color:green;'>".$userqq."</b>&nbsp;已经被使用<br/>";
echo "<script type='text/javascript'>";
echo "document.title = '注册失败'";
echo "</script>";
echo "用户注册失败。3秒后将返回注册页面,如果你的浏览器不支持自动跳转,请点击&nbsp;<a href='reg.html' style='color:green;'>这里</a>&nbsp;如果您已经有账号可从&nbsp;<a href='login.html' style='color:green;'>这里</a>&nbsp;前往登陆。";
echo '<script type="text/javascript">';
echo 'GoReg()';
echo '</script>';
exit();
}

$reg = mysql_query("SELECT ID FROM HBDX_USERS WHERE USER_MAIL = '".$email."'");
$regnum = mysql_num_rows($reg);
if($regnum > 0){
echo "邮箱&nbsp;<b style='color:green;'>".$email."</b>&nbsp;已经被使用<br/>";
echo "<script type='text/javascript'>";
echo "document.title = '注册失败'";
echo "</script>";
echo "用户注册失败。3秒后将返回注册页面,如果你的浏览器不支持自动跳转,请点击&nbsp;<a href='reg.html' style='color:green;'>这里</a>&nbsp;如果您已经有账号可从&nbsp;<a href='login.html' style='color:green;'>这里</a>&nbsp;前往登陆。";
echo '<script type="text/javascript">';
echo 'GoReg()';
echo '</script>';
exit();
}

if(mysql_query("INSERT INTO HBDX_USERS (USER_NAME,USER_DISPLAYNAME,USER_QQ,USER_PASS,USER_MAIL,REGISTERDATE,LOGINDATE) VALUES ('$username','$disname','$userqq','$password','$email','$datetime','$datetime')"))
{
echo "<script type='text/javascript'>";
echo "document.title = '用户注册成功'";
echo "</script>";
echo "用户注册成功。3秒后将跳转到登录页面,如果你的浏览器不支持自动跳转,请点击&nbsp;<a href='login.html' style='color:green;'>登录</a>&nbsp;或者返回&nbsp;<a href='index.php' style='color:green;'>主页</a>";
echo '<script type="text/javascript">';
echo 'GoLogin()';
echo '</script>';
}
else
{
echo "<script type='text/javascript'>";
echo "document.title = '注册失败'";
echo "</script>";
echo "用户注册失败。3秒后将返回注册页面,如果你的浏览器不支持自动跳转,请点击&nbsp;<a href='reg.html' style='color:green;'>这里</a>&nbsp;如果您已经有账号可从&nbsp;<a href='login.html' style='color:green;'>这里</a>&nbsp;前往登陆。";
echo '<script type="text/javascript">';
echo 'GoReg()';
echo '</script>';
}
?>


同样无任何过滤,根据最后一层验证的SQL语句

if(mysql_query("INSERT INTO HBDX_USERS (USER_NAME,USER_DISPLAYNAME,USER_QQ,USER_PASS,USER_MAIL,REGISTERDATE,LOGINDATE) VALUES ('$username','$disname','$userqq','$password','$email','$datetime','$datetime')"))


我们可以构造一个form来绕过前端验证

<form action="http://127.0.0.1:8080/d.hbdx.cc/reg.php" method="post" >
<input name="reg" value="免费注册">
<input name="t_UserName" value="admin2">
<input name="iptNickName" value="的的">
<input name="t_UserPass" value="123456">
<input name="t_RePass" value="123456">
<input name="iptCard" value="123456">
<input name="t_Email" value="[email protected]'">
<input type="submit" value="ok">
</form>


4.png


可以看见提交之后出现报错,我们可以使用子查询构造除了HBDX_USERS表以外的 读取任意表数据的 SQL语句
因为这个站的表除了HBDX_USERS,其他的表并没有什么敏感数据故不再演示。
3.再来看看(catalogue.php)

@$type      = strval($_GET['type']);  //得到type的值
@$page = intval($_GET['page']); //得到page的值
@$hot = strval($_GET['hot']); //得到type的值
$page = isset($_GET['page'])?intval($_GET['page']):1; //当前页数
$result = mysql_query("SELECT CODE FROM HBDX_BASEINFO WHERE TAGSECOND = 'FILESHOW'");
$filerow = mysql_fetch_array($result);
$result = mysql_query("SELECT CODE FROM HBDX_BASEINFO WHERE TAGSECOND = 'PAGENUM'");
$pagerow = mysql_fetch_array($result);
$perNumber = $filerow['CODE']; //每页显示的最大记录数
$limit_page = $pagerow['CODE'];
$startCount = ($page-1)*$perNumber;
if (empty($type))
{
echo '<script type="text/javascript">';
echo 'AutoOpenURL("index.php")';
echo '</script>';
}
else
{
echo "<script type='text/javascript'>";
echo "document.title = '$type'";
echo "</script>";
}
if (empty($hot))
{
$hot = ",ID DESC";
}
else
{
$hot = ",FILENUM DESC";
}
$result = mysql_query("SELECT * FROM HBDX_BLUE WHERE FILETYPE = '".$type."'");
$num_max = mysql_num_rows($result);
$result = mysql_query("SELECT * FROM HBDX_BLUE WHERE FILETYPE = '".$type."' ORDER BY TOP ".$hot." LIMIT $startCount,$perNumber");
echo '<table class="table"><tr>';
echo "<th>操作</th><th>名称</th><th>大小</th><th><a href='catalogue.php?type=".$type."&hot=hot' style='color:green;'>下载量</a></th><th>发布者/联盟</th><th>标签</th><th>发布时间</th>";
echo '</tr>';
while($row = mysql_fetch_array($result))
{
$fileuser = $row['FILEUSER'];
$usersinfo = mysql_query("SELECT USER_DISPLAYNAME FROM HBDX_USERS WHERE ID = '".$fileuser."'");
$usersrows = mysql_fetch_array($usersinfo);
echo "<td><a href='pages.php?id=".$row['ID']."'>详情&nbsp;&nbsp;</a>";
if( $row['FILEEXT'] == 'net' )
{
$fileid = $row['ID'];
echo "<a href='".$row['FILEURL']."' target='_blank' onClick=\"javascript:ClickNumber('$fileid');\">下载&nbsp;&nbsp;</a></td>";
}
else
{
echo "<a href='download.php?id=".$row['ID']."'>下载&nbsp;&nbsp;</a></td>";
}
echo "<td>";
if( $row['FILEEXT'] == 'torrent' )
{
echo '<a style="background:#1369A4;color:#fff;">&nbsp;&nbsp;种子&nbsp;&nbsp;</a>';
}
$pos = strpos( $row['FILEURL'], 'ed2k://|file|');
if ($pos !== false)
{
echo '<a style="background:#467500;color:#fff;">&nbsp;&nbsp;电驴&nbsp;&nbsp;</a>';
}
$baidu = strpos( $row['FILEURL'], 'pan.baidu.com/share/link?');
if ($baidu !== false)
{
echo '<a style="background:#BB3D00;color:#fff;">&nbsp;&nbsp;百度&nbsp;&nbsp;</a>';
}
$kuai = strpos( $row['FILEURL'], 'kuai.xunlei.com/d/');
if ($kuai !== false)
{
echo '<a style="background:#7E3D76;color:#fff;">&nbsp;&nbsp;快传&nbsp;&nbsp;</a>';
}

echo "<a href='pages.php?id=".$row['ID']."'><b>".$row['FILETITLE']."</b></a>";
if ($row['TOP'] == 0) {
echo "<img src='images/top.gif'></img>";
}
$datetoday = date("Y-m-d");
$d1 = strtotime($datetoday);
$d2 = strtotime($row['LOADDATE']);
$days = round(($d1-$d2)/3600/24);
if( $days < 10 )
{
echo "<img src='images/new.gif'></img>";
}
if( $row['FILENUM'] > 99 )
{
echo "<img src='images/hot.gif'></img>";
}
echo "</td>";
echo "<td>".$row['FILESIZE']."</td>";
echo "<td>".$row['FILENUM']."</td>";
echo "<td>".$usersrows['USER_DISPLAYNAME']."</td>";
$tags = strtok( $row['FILETAG'],',');
echo "<td>";
while( $tags ) {
echo "<a href=\"javascript:void(0)\" onClick=\"javascript:send_request('tools.php?seacher=".$tags."');\">".$tags."&nbsp;&nbsp;</a>";
$tags = strtok (",");
}
echo "</td>";
echo "<td>".$row['LOADDATE']."</td>";
echo '</tr>';
}
echo "</table>";
$pagecount = ceil($num_max/$perNumber); //总页数
if ($page == 1) {
echo "<a href='catalogue.php?type=".$type."'><strong>首页&nbsp;&nbsp;</strong></a>";
}
if ($page != 1)
{
echo "<a href='catalogue.php?type=".$type."'><strong>首页&nbsp;&nbsp;</strong></a>";
echo "<a href='catalogue.php?type=".$type."&page=".($page-1)."'><strong>上一页&nbsp;&nbsp;</strong></a>";
}
for ($i=1;$i<=$pagecount;$i++)
{
if($i <= $limit_page)
{
echo "<a href='catalogue.php?type=".$type."&page=".$i."'>$i&nbsp;&nbsp;</a>";
}
}
if ($page<$pagecount)
{
echo "<a href='catalogue.php?type=".$type."&page=".($page+1)."'><strong>下一页&nbsp;&nbsp;</strong></a>";
echo "<a href='catalogue.php?type=".$type."&page=".$pagecount."'><strong>尾页&nbsp;&nbsp;</strong></a>";
}
if ($page==$pagecount)
{
echo "<a href='catalogue.php?type=".$type."&page=".$pagecount."'><strong>尾页&nbsp;&nbsp;</strong></a>";
}
echo "第<b>".$page."</b>页 ";
echo " 共<b>".$pagecount."</b>页 ";


这个页面可控参数太多
@$type = strval($_GET['type']); //得到type的值
@$page = intval($_GET['page']); //得到page的值
@$hot = strval($_GET['hot']); //得到type的值
$page = isset($_GET['page'])?intval($_GET['page']):1; //当前页数
这个页面也同样无任何过滤。我们尝试type参数,除了出现注入以外,还出现了输出在<script>中的情况

5.png


我们闭合之后:

6.png


漏洞证明:

以上详细说明附带证明过程。

修复方案:

幸好你的后台很简单。

版权声明:转载请注明来源 LaiX@乌云


漏洞回应

厂商回应:

未能联系到厂商或者厂商积极拒绝