Discord Stealer样本分析
基本信息
样本名称为RockPaperScissors.exe,MD5:7b6e1adf588ce77419920593970292fb,由C#编写。

Discord Stealer分析
Main
没有混淆,首先获取黑名单数组,检测当前用户是否在黑名单中,如果不在黑名单中,则异步任务调用Program.<>c.<>9.<Main>.<b__6_0>()方法Program.<>c.<>9.<Main>.<b__6_1>()方法,然后获取本地应用程序数据文件夹路径(即C:\Users\用户名\AppData\Local)并启动异步任务调用Program.<>c.<>9.<Main>.<b__6_2>()方法、Program.<>c.<>9.<Main>.<b__6_3>()**方法,最后调用 Program.RPS()方法,如果在黑名单内,则调用Program.RPS() 方法,Program.RPS()方法是石头剪刀布(Rock, Paper, Scissors)游戏。

blacklistUsers如下:
1 | WDAGUtilityAccount、3W1GJT、QZSBJVWM、5ISYH9SH、Abby、hmarc、patex、RDhJ0CNFevzX、kEecfMwgj、Frank、8Nl0ColNQ5bq、Lisa、John、george、PxmdUOpVyx、8VizSM、w0fjuOVmCcP5A、lmVwjj9b、PqONjHVwexsS、3u2v9m8、Julia、HEUeRzl、fred、server、BvJChRPnsxn、Harry Johnson、SqgFOf3G、Lucas、mike、PateX、h7dk1xPr、Louise、User01、test、RGzcBUyrznReg、05h00Gi0、43By4、4tgiizsLimS、6O4KyHhJXBiR、7wjlGX7PjlW4、Amy、AppOnFlySupport、ASPNET、azure、BUiA1hkm、cM0uEGN4do、cMkNdS6、DefaultAccount、dOuyo8RV71、DVrzi、e60UW、ecVtZ5wE、EGG0p、G2DbYLDgzz8Y、GjBsjb、Guest、ICQja5iT、IVwoKUF、j6SHA37KA、j7pNjWM、jude、kFu0lQwgX5P、KUv3bT4、lK3zMR、l3cnbB8Ar5b8、lmVwjj9b、Louise、Lucas、mike、Mr.None、noK4zG7ZhOf、o6jdigq、o8yTi52T、OgJb6GqgK0O、PgfV1X、pWOuqdTDQ、PxmdUOpVyx、QfofoG、QmIS5df7u、QORxJKNk、qZo9A、S7Wjuf、sal.rosenburg、Steve、TVM、txWas1m2t、umyUJ、Uox1tzaMO、vzY4jmH0Jw02、XMiMmcKziitD、xPLyvzr8sgC、ykj0egq7fze、DdQrgc、ryjIJKIrOMs、nZAp7UBVaS1、zOEsT、xUnUy、fNBDSlDTXY、gu17B、UiQcX、21zLucUnfI85、OZFUCOD6、8LnfAai9QdJR、5sIBK、rB5BnfuR2、GexwjQdjXG、IZZuXj、ymONofg、dxd8DJ7c、JAW4Dz0、GJAm1NxXVm、UspG1y1C、equZE3J、BXw7q、lubi53aN14cU、5Y3y73、9yjCPsEYIMH、GGw8NR、JcOtj17dZx、05KvAUQKPQ、64F2tKIqO5、7DBgdxu、uHUQIuwoEFU、gL50ksOp、Of20XqH4VL、tHiF2T、dx、jz、WALKER |
通过这个用户名黑名单列表,在github发现了名为Creal-Stealer和Ethical-Stealer的项目,这两个项目由python编写,Ethical-Stealer参考了Creal-Stealer的很多逻辑和代码,可以窃取密码、Token、Cookie、加密货币等等等,同时找到VirusTotal博客2023年6月份的一篇文章:Inside of the WASP's nest: deep dive into PyPI-hosted malware,也提到了Creal-Stealer,可以推测这个样本的主要功能也与Stealer相关,这个用户名黑名单列表的作用是检查当前程序是否在 VirusTotal 沙箱中运行。除此之外,亦发现了另一个项目virustotal-vm-blacklist,blacklistUsers参考了里面的pc_username_list.txt,顺便对比了下两个黑名单列表,blacklistUsers比pc_username_list.txt多了三个,分别是:dx、jz、WALKER。
类<>c
私有密封类<>c,匿名委托方法<FRFRFRFRFRF>b__14_0(Process p),检索名为"discord"的进程、匿名方法<Main>b__6_0()调用Program.GetScreenshot()方法来获取屏幕截图发送至指定的Discord Webhook URL、匿名方法<Main>b__6_1()调用了Program.addstartupnonadmin()方法,通过方法命名推测其功能为非在管理员账户下实现自启动、匿名方法 <Main>b__6_2()发送密码至指定的Discord Webhook URL、匿名方法 <Main>b__6_2()调用了一个Program.GreenToast()方法,可能与通知相关。

Program.addstartupnonadmin()方法
Program.addstartupnonadmin()方法,在注册表键SOFTWARE\Microsoft\Windows\CurrentVersion\Run下添加一个注册表值,值的内容为 $77 + 当前程序文件的名称,该值的数据部分是当前程序的位置,实现开机自启动。

Program.GreenToast()方法
Program.GreenToast()方法,再次检测用户名是否在用户名黑名单中,如果在用户名黑名单中,则调用Program.Yellowtoast()方法,然后终止当前程序的执行;如果不在用户名黑名单中,首先调用 TheFrrMonster.TheFRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR() 方法,返回一个字符串列表,然后遍历字符串列表,将每个字符串添加到 Program.father 变量中,接着调用 Program.SendWEBBY() 方法,解析处理并发送Program.father 到指定的 Discord Webhook URL,最后调用 Program.FRFRFRFRFRF() 方法。

Program.Yellowtoast()方法
Program.Yellowtoast()方法,调用RtlAdjustPrivilege提权,19(0x13)对应特权常量SeShutdownPrivilege,即关机权限,一旦提权成功,接着调用NtRaiseHardError设置错误码为0xC0000022,可引发蓝屏(BSOD )。

Program.TheFR{49}() 方法
Program.TheFRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR() 方法,创建了一个空的字符串列表list,循环遍历字符串数组,将字符串解码后拼接成文件路径,检查指定文件是否存在,如果存在则调用TheFrrMonster.GrabTokens方法,并将结果添加到"list"中。

解码字符串如下,获取特定的所在的Local Storage\leveldb、 User Data、User Data\Default、\Local State等目录信息。浏览器列表:Amigo、Torch、Kometa、Google Chrome、Orbitum、CentBrowser、7Star、Sputnik、Vivaldi、Google Chrome SxS、Epic Privacy Browser、Uran、Microsoft Edge、Yandex、Opera Neon、Brave-Browser
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | \AppData\Local Storage\leveldb \Roaming v+ discord\Roaming v+ discordptb\Roaming v+ discordcanary\Roaming v+ discorddevelopment\Roaming v+ Opera Software Opera Stable\Roaming v+ Opera Software Opera GX Stable\Local\Amigo\User Data\Local\Torch\User Data\Local\Kometa\User Data\Local\Google\Chrome\User Data\Default\Local\Orbitum\User Data\Local\CentBrowser\User Data\Local\7Star\7Star\User Data\Local\Sputnik\Sputnik\User Data\Local\Vivaldi\User Data\Default\Local\Google\Chrome SxS\User Data\Local\Epic Privacy Browser\User Data\Local\uCozMedia\Uran\User Data\Default\Local\Microsoft\Edge\User Data\Default\Local\Yandex\YandexBrowser\User Data\Default\Local\Opera Software\Opera Neon\User Data\Default\Local\BraveSoftware\Brave-Browser\User Data\Default |
TheFrrMonster.GrabTokens方法
TheFrrMonster.GrabTokens方法,用于获取浏览器保存的Discord toke,三个正则: [\\w-]{24}\.[\\w-]{6}\.[\\w-]{27}、mfa\.[\\w-]{84}、(dQw4w9WgXcQ:)([\^.*\\['(.*)'\\].*$][^\"]*),前两个正则用于直接匹配Discord token,第三个正则匹配到成功则会调用DecryptToken方法解密dQw4w9WgXcQ:后的部分,解密算法为AES-GCM。关于具体密钥获取和解密逻辑,可参阅github项目Browser-password-stealer

获取Discord toke成功后调用Distinct去重,通过token和WebClient 获取用户数据

Program.SendWEBBY() 方法,从Discord API返回的JSON数据中解析详细的用户信息,然后将用户名(username)、鉴别器(discriminator,通常是一个四位数),用户ID(user ID)添加到一个列表(list)中, 接着将 Discord Token 以YAML格式添加到一个list中,同时创建一个包含 Discord Token 复制链接的项,再把用户的2FA和验证状态、将.gif或.png格式的链接形式的用户头像的信息添加到 list 中,最后,相关信息经格式化处理之后,将Discord用户相关信息发送至指定的Discord Webhook URL。

在Program.SendWEBBY() 方法中,包含一个frfrfrfrfrfrfrfrfrfr()方法,向 Discord API 发送请求,获取与已认证用户相关的结算/支付信息。

发送Discord Webhook URL的消息标题被设置为 Anthemia logger <:TrackerPFP:1089051195722706964>

Program.FRFRFRFRFRF() 方法
将获取的token和用户相关信息发送至指定Discord Webhook URL后,会调用FRFRFRFRFRF() 方法。关闭所有与 Discord 相关的进程,并检查特定的Discord目录是否存在,并在discord 客户端注入名为index.js的脚本文件,修改discord 客户端以实现一些定制化的功能。

被注入的js文件较长,通过 JavaScript文件的配置信息可以窥见其主要功能如下,其详细功能见https://www.trendmicro.com/ja_jp/research/23/h/info-stealer-abusing-codespaces-puts-discord-users--data-at-risk.html ,
1.webhook: Discord Webhook 的 URL,用于将信息发送到指定的 Discord 服务器或频道。
2.webhook_protector_key: Webhook 保护密钥。
3.auto_buy_nitro: 一个布尔值,表示是否启用自动购买 Nitro 的功能。
4.ping_on_run: 一个布尔值,表示是否在运行时通过 ping_val 提及(ping)所有人。
5.ping_val: 在运行时提及(ping)的消息内容,通常是 @everyone。
6.embed_name: 发送到 Discord 的消息中嵌入的名称。
7.embed_icon: 发送到 Discord 的消息中嵌入的图标的 URL。
8.embed_color: 发送到 Discord 的消息中嵌入的颜色。
9.injection_url: Discord 注入脚本的 URL。
10.api: Discord 用户信息 API 的 URL。
11.nitro: 包含 Nitro 订阅计划的对象。
12.boost: 包含 Nitro Boost 订阅计划。
13.year: 年订阅计划的详细信息。
14.month: 月订阅计划的详细信息。
15.classic: 包含经典 Nitro 订阅计划。
16.filter: 包含需要过滤的 URL 列表,用于监听 Discord API 请求。
17.filter2: 包含需要过滤的第二个 URL 列表,用于监听其他 Discord 相关请求。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | const config = { webhook: 'hxxps://discord[.]com/api/webhooks/1095580593544237088/P6vEnIM_dngrti7YjsQG7J5vsRaMY6EFlxxj-kMLNU-6Hnb1d4PHjrHUDlAsLXtBJHew', webhook_protector_key: '%WEBHOOK_KEY%', auto_buy_nitro: false, ping_on_run: false, ping_val: '@everyone', embed_name: 'Fr injection', embed_icon: 'hxxps://cdn.discordapp[.]com/attachments/1077267633365340172/1094133346788970556/582387.png', embed_color: 0, injection_url: 'hxxps://raw.githubusercontent[.]com/Anthemiaa/fr/main/clean.js', api: 'https://discord.com/api/v9/users/@me', nitro: { boost: { year: { id: '521847234246082599', sku: '511651885459963904', price: '9999', }, month: { id: '521847234246082599', sku: '511651880837840896', price: '999', }, }, classic: { month: { id: '521846918637420545', sku: '511651871736201216', price: '499', }, }, }, filter: { urls: [ 'https://discord.com/api/v*/users/@me', 'https://discordapp.com/api/v*/users/@me', 'https://*.discord.com/api/v*/users/@me', 'https://discordapp.com/api/v*/auth/login', 'https://discord.com/api/v*/auth/login', 'https://*.discord.com/api/v*/auth/login', 'https://api.braintreegateway.com/merchants/49pp2rp4phym7387/client_api/v*/payment_methods/paypal_accounts', 'https://api.stripe.com/v*/tokens', 'https://api.stripe.com/v*/setup_intents/*/confirm', 'https://api.stripe.com/v*/payment_intents/*/confirm', ], }, filter2: { urls: [ 'https://status.discord.com/api/v*/scheduled-maintenances/upcoming.json', 'https://*.discord.com/api/v*/applications/detectable', 'https://discord.com/api/v*/applications/detectable', 'https://*.discord.com/api/v*/users/@me/library', 'https://discord.com/api/v*/users/@me/library', 'wss://remote-auth-gateway.discord.gg/*', ], },}; |
LoadDll
该样本还会下载名为PasswordStealer.dll的恶意dll文件并加载执行类PasswordStealer.Stealer 中的Run方法。该恶意dll托管在github,hxxps://raw.githubusercontent[.]com/Anthemiaa/fr/master/PasswordStealer.dll

github用户名为 Anthemiaa

PasswordStealer.dll同目录下还有一个名为clean.js的文件,功能与index.js几乎一致。

PasswordStealer.dll
基本信息
MD5:ef4265e61daa8c0c8db8d40744196b11

PasswordStealer分析
Stealer.run()方法
通过Chromium.Grab()方法窃取基于 chromium 的浏览器相关浏览器中保存的url、账户和密码信息,如:Hostname (账户相关的网站 URL,origin_url)、
Username(用户名,username_value)、Password(密码,password_value),其逻辑与Browser-password-stealer类似,针对基于 chromium 的浏览器。

通过FirefoxPassReader方法,窃取Firefox浏览器中保存的url、账户和密码信息,其获取逻辑与https://github.com/unode/firefox_decrypt/blob/main/firefox_decrypt.py 基本一致。

窃取FileZilla 应用程序的密码等信息。FileZilla是一个FTP客户端软件,其历史记录以纯文本形式存储在文件“%APPDATA%\filezilla\recentservers.xml”中,并将其登录数据存储在文件“%APPDATA%\filezilla\sitemanager.xml”中。

窃取NordVPN的密码等信息。

窃取Outlook密码等信息。遍历注册表中与 Outlook 配置文件相关的子键,并尝试获取 IMAP、POP3、HTTP 和 SMTP 密码。

IOCs
7b6e1adf588ce77419920593970292fb
ef4265e61daa8c0c8db8d40744196b11
hxxps://raw.githubusercontent[.]com/Anthemiaa/fr/master