Sobre shellcodes.
Un SHELLCODE es un arreglo opaco de bytes que al ponerlos en memoria(ejecutable)
y pasarle el control ejecuta un shell(o cualquier otra cosa).
Eso debería hacer ago como:
1) Alocar memoria ejectutable
2) Leer el contenido de un archivo(shellcode)
3) Pasar el control
Listo. Ahora intentemos hacer un shellcode (cacho de mem que al pasarle el control imprime "YOU WIN!")
.section .data
-
message:
.ascii "YOU WIN!\n"
-
len = . - message
.section .text
-
.globl _start
_start:
#write mesaje to stdout
movl $len, %edx # LEN
-
movl $message, %ecx # BUFFER
movl $1, %ebx # FD
movl $4, %eax # WRITE
int $0x80 # SYSCALL
#exit
movl $0, %ebx # RETVALUE
movl $1, %eax # EXIT
int $0x80 # SYSCALL
Esto claramente tiene 2 "secciones" o cachos de memoria diferentes: .text y .data. El codigo vive en .text y message en .data.
Se ensambla asi:
$ as -32 01-holamundo.s -o 01-holamundo.o
Y podemos inspeccionar lo generado usando los comandos objdump, nm, readelf , od:
$ objdump -s 01-holamundo.o
01-holamundo.o: file format elf32-i386
Contents of section .text:
0000 ba0b0000 00b90000 0000bb01 000000b8 ................
0010 04000000 cd80bb00 000000b8 01000000 ................
0020 cd80 ..
Contents of section .data:
0000 486f6c61 204d756e 646f0a Hola Mundo.
Lo importante es que tiene "relocations" es decir que hay diferentes secciones que se referencian entre si. En este caso en el código hay una referencia a message que esta' en otra sección. Las relocations se pueden ver con el "-r":
$objdump -r 01-holamundo.o
01-holamundo.o: file format elf32-i386
RELOCATION RECORDS FOR [.text]:
OFFSET TYPE VALUE
00000006 R_386_32 .data
Normalmente el loader (man ld) se ocupa de poner las secciones en memoria, asignar los permisos y resolver esas "relocations":
ld combines a number of object and archive files, relocates their data and ties up symbol references.
Usually the last step in compiling a program is to run ld.
Para construir un shellcode usando las toolchains clásicas necesitamos código que no tenga relocations y que use una sola sección. (o bien implementar el loader a mano (si en assembler)). Ok, para esto podemos hacer:
1) Mezclar todas las secciones en una sola => .text.
Los datos aparecerán a continuación del código(se pueden inventar otros layouts).
2) Las referencias a variables deben ser calculadas en función de offsets estáticos y
de la posición actual del código en memoria (que se obtiene de la pila haciendo un call).
El assembler queda con esta pinta.
# BASIC SHELLCODE
.section .text #everything in one section
.globl _start
_start:
call dummy
dummy: #<--------------------------------\
popl %ecx #address of dummy in ecx
#write mesaje to stdout using int 80
movl $len, %edx # LEN
# add the distance from dummy tu message to get
# the absolute pointer to message
# no matter where this code is put in memory
addl $offset_dummy_to_message, %ecx # buffer
movl $1, %ebx # FD
movl $4, %eax # WRITE
int $0x80 # SYSCALL
#exit
movl $0, %ebx # RETVALUE
movl $1, %eax # EXIT
int $0x80 # SYSCALL
# The GNU Assembler knows the sizes of intructions
# and is able to calculate distances between labels
# statically at 'assembling' time
offset_dummy_to_message = message-dummy # This wont generate
# nothing in the binary
message:
# This is in the .text section and inmediatelly
# after the last instruction
.ascii "YOU WIN\n"
len = . - message
Se ensambla asi:
$as -32 02-holamundo-shellcode.s -o 02-holamundo-shellcode.o
Esto genera un archivo ELF con una sola sección y sin "relocations". Se puede investigar con :
$objdump -S 02-holamundo-shellcode.o
$objdump -r 02-holamundo-shellcode.o
Para sacar el binario correspondiente a la sección .text (también se puede ver con objdump -D) usamos este python...
from elftools.elf.elffile import ELFFile
import sys
-
-
if len(sys.argv) != 3:
print "Usage:\t%s file.o file.bin"%sys.argv[0]
sys.exit()
-
-
#read the ELF object file
elf = ELFFile(file(sys.argv[1]))
#read .text data (abort if not found)
text = elf.get_section_by_name('.text').data()
print "Section .text is %d bytes long"%len(text)
print "Dumping .text section to %s ..."%sys.argv[2]
file(sys.argv[2],"wb").write(text)
print "done."
Adjunto un tgz con todo esto.
Cualquier consulta .. mail.
Salut!
f/
===
Ha llegado a mi atención que las slides de _la_ clase estan medio escondidas, entonces adjunto.