Las DLL (Dynamic Link Libraries) son componentes fundamentales de Windows y de muchas aplicaciones. Permiten que diferentes programas utilicen funciones y código compartido sin tener que incluir toda esa funcionalidad dentro del ejecutable.
Esta característica también puede convertirse en un riesgo de seguridad cuando una aplicación carga una biblioteca desde una ubicación que un usuario puede modificar.
En esta práctica se construirá un pequeño laboratorio en C# utilizando exclusivamente el compilador incluido en .NET Framework 3.5:
C:\Windows\Microsoft.NET\Framework\v3.5\csc.exe
No es necesario instalar Visual Studio.
La demostración utilizará un ejecutable denominado Notepad2.exe. Al ejecutarlo, primero abrirá el Notepad de Windows y posteriormente cargará una DLL. Inicialmente se utilizará una DLL legítima. Después se sustituirá por otra DLL que abrirá Chrome.
El objetivo es observar cómo un programa puede mantener el mismo ejecutable mientras cambia el comportamiento de una biblioteca que carga.
1. Estructura del laboratorio
Se puede crear una carpeta:
C:\DLL-Hijacking-Lab
Dentro tendremos:
C:\DLL-Hijacking-Lab
│
├── Notepad2.cs
├── Biblioteca.cs
├── Notepad2.exe
└── Biblioteca.dll
El funcionamiento será:
Notepad2.exe
│
┌─────────┴─────────┐
│ │
▼ ▼
notepad.exe Biblioteca.dll
│
▼
código DLL
2. Crear Notepad2.exe
El primer programa será Notepad2.cs.
using System;
using System.Diagnostics;
using System.Reflection;
class Notepad2
{
static void Main()
{
// Abrimos el Notepad real
Process.Start("notepad.exe");
try
{
// Cargamos la biblioteca
Assembly dll = Assembly.LoadFrom("Biblioteca.dll");
Type tipo = dll.GetType("Biblioteca.Inicio");
if (tipo != null)
{
MethodInfo metodo = tipo.GetMethod("Ejecutar");
if (metodo != null)
{
metodo.Invoke(null, null);
}
}
}
catch (Exception)
{
// Ignoramos errores durante la demostración
}
}
}
Este código realiza dos operaciones:
Notepad2.exe
│
├── Process.Start()
│ │
│ └── notepad.exe
│
└── Assembly.LoadFrom()
│
└── Biblioteca.dll
La primera operación abre el Notepad real.
La segunda carga Biblioteca.dll.
3. Compilar Notepad2.exe
No es necesario utilizar Visual Studio.
Desde una consola de Windows se puede ejecutar:
C:\Windows\Microsoft.NET\Framework\v3.5\csc.exe /target:exe /out:Notepad2.exe Notepad2.cs
Si la compilación termina correctamente aparecerá:
Notepad2.exe
4. Crear la DLL legítima
Ahora se crea Biblioteca.cs:
using System;
namespace Biblioteca
{
public class Inicio
{
public static void Ejecutar()
{
Console.WriteLine("Biblioteca legítima cargada.");
}
}
}
Esta DLL no realiza ninguna acción especial.
Se compila con:
C:\Windows\Microsoft.NET\Framework\v3.5\csc.exe /target:library /out:Biblioteca.dll Biblioteca.cs
Ahora tenemos:
Notepad2.exe
Biblioteca.dll
5. Primera ejecución
Al ejecutar:
Notepad2.exe
se produce:
Notepad2.exe
│
├───────────────► notepad.exe
│
└───────────────► Biblioteca.dll
│
▼
"Biblioteca legítima cargada"
Para el alumno, aparentemente se ha ejecutado un programa denominado Notepad2.exe que abre el Notepad.
La DLL legítima no hace nada visible.
6. Sustituir la DLL
Ahora se modifica Biblioteca.cs.
La nueva versión será:
using System.Diagnostics;
namespace Biblioteca
{
public class Inicio
{
public static void Ejecutar()
{
Process.Start("chrome.exe");
}
}
}
Se vuelve a compilar:
C:\Windows\Microsoft.NET\Framework\v3.5\csc.exe /target:library /out:Biblioteca.dll Biblioteca.cs
La nueva Biblioteca.dll sustituye a la anterior.
Ahora el mismo:
Notepad2.exe
utiliza una DLL con un comportamiento diferente.
7. Segunda ejecución
Al volver a ejecutar:
Notepad2.exe
el flujo será:
Notepad2.exe
│
┌────────┴────────┐
│ │
▼ ▼
notepad.exe Biblioteca.dll
│
▼
Process.Start()
│
▼
chrome.exe
El resultado visual será:
- Se abre
notepad.exe. Notepad2.execargaBiblioteca.dll.- La DLL modificada ejecuta su código.
- Se abre Chrome.
La demostración permite observar que el ejecutable principal no ha cambiado:
Notepad2.exe
Lo que ha cambiado es la biblioteca que utiliza.
8. ¿Dónde está el riesgo?
El problema de seguridad aparece cuando una aplicación confía en una DLL que puede ser sustituida o cargada desde una ubicación controlable por un usuario no autorizado.
Conceptualmente:
Aplicación legítima
│
▼
busca/carga DLL
│
▼
DLL legítima ────────► comportamiento esperado
Pero si la biblioteca puede ser sustituida:
Aplicación legítima
│
▼
busca/carga DLL
│
▼
DLL modificada
│
▼
código no previsto
En determinados escenarios esto puede utilizarse para DLL Hijacking, una técnica asociada en MITRE ATT&CK con T1574.001 - DLL.
9. DLL Hijacking frente a esta demostración
Hay que diferenciar la práctica de laboratorio del mecanismo nativo completo.
En este ejemplo se utiliza:
Assembly.LoadFrom("Biblioteca.dll");
Por tanto, estamos trabajando con un assembly .NET.
Un DLL Hijacking nativo de Windows utiliza mecanismos como:
LoadLibrary()
y el sistema de búsqueda de DLL.
El concepto que se quiere visualizar es similar:
programa
│
▼
carga biblioteca
│
▼
biblioteca inesperada
│
▼
ejecución de código
Para una demostración más avanzada se puede sustituir este laboratorio .NET por una aplicación nativa en C/C++ que utilice LoadLibrary() y estudiar el orden de búsqueda de DLL de Windows.
10. Crear un acceso directo
Para hacer la demostración más visual se puede crear un acceso directo a:
Notepad2.exe
Por ejemplo:
Abrir Notepad
El alumno solamente verá:
Abrir Notepad
Al ejecutar el acceso directo:
Acceso directo
│
▼
Notepad2.exe
│
├────────► Notepad
│
└────────► Biblioteca.dll
│
▼
Chrome
La gracia de la práctica consiste precisamente en que el ejecutable principal permanece igual mientras se cambia la biblioteca que utiliza.
11. Una herramienta especialmente útil: Process Monitor
Para analizar la práctica se puede utilizar Process Monitor (Procmon) de Microsoft Sysinternals.
El objetivo no debería ser únicamente observar que Chrome aparece, sino comprobar qué ocurre durante la ejecución.
Se puede filtrar por:
Process Name is Notepad2.exe
y observar las operaciones relacionadas con:
Biblioteca.dll
De esta forma se puede relacionar:
ejecución del proceso
↓
búsqueda/carga de biblioteca
↓
carga de DLL
↓
ejecución de código
Esto permite convertir una demostración visual en una práctica de análisis de seguridad.
12. Medidas de protección
Para reducir el riesgo de DLL Hijacking se pueden aplicar diferentes medidas, entre ellas:
- Utilizar rutas explícitas cuando sea apropiado.
- Evitar cargar bibliotecas desde directorios que usuarios no autorizados puedan modificar.
- Revisar los permisos de las carpetas que contienen DLL.
- Utilizar mecanismos de carga seguros proporcionados por Windows.
- Mantener las aplicaciones y sus dependencias actualizadas.
- Supervisar cargas de DLL desde ubicaciones anómalas.
- Utilizar herramientas como Sysmon y Process Monitor para investigar comportamientos sospechosos.
- Verificar la integridad y procedencia de las bibliotecas utilizadas por una aplicación.