|
Se refiere a una política en los permisos de las secciones de un programa en OpenBSD. Una sección ejecutable no puede ser escribible, y una sección escribible no puede ser ejecutable. Esto descarta programas que intentan automodificarse y programas que pretendan ejecutar instrucciones entre los datos. A continuación se presentan 2 programas que ponen a prueba esta política. Programa que intenta modificarse
.intel_syntax noprefix
.section ".note.openbsd.ident", "a"
.p2align 2
.long 8,4,1
.ascii "OpenBSD\0"
.long 0
.global _start
.global puts
.global exit
.text
_start:
# Lo siguiente usaría libc
lea rdi, [rip + hola]
mov rsi, rdi
call puts@plt
# Modificamos cadena por imprimir e imprimimos
mov rdi,rsi
movb [rdi], 65
call puts@plt
# Mostramos algunos bytes del programa (usando gdb determinamos el 28 del inicio al call
lea rdi, [rip - 33]
call puts@plt
# Intentamos modificar primer byte del programa y mostrar
lea rdi, [rip - 45]
movb [rdi], 66 # En esta instrucción se produce un SIGSEGV
call puts@plt
# Terminar
xor rdi, rdi
call exit@plt
.data
hola:
.asciz "Hola mundo!\n\0"
Si llamamos automod.s a este programa, podemos compilarlo con: export N=automod; as -gstabs+ $N.s -o $N.o; ld --dynamic-linker=/usr/libexec/ld.so -pie -L/usr/lib -lc $N.o -o $N; y su ejecución detallando llamados al sistema puede verse con: ktrace ./$N; kdump Que generará:
Hola Mundo!
Aola Mundo!
H=!
zsh: segmentation fault (core dumped)
...
19739 automod CALL fcntl(1,F_ISATTY)
19739 automod RET fcntl 1
19739 automod CALL write(1,0x942be953000,0xc)
19739 automod GIO fd 1 wrote 12 bytes
"Hola mundo!
"
19739 automod RET write 12/0xc
19739 automod CALL write(1,0x942be953000,0x1)
19739 automod GIO fd 1 wrote 1 bytes
"
"
19739 automod RET write 1
19739 automod CALL write(1,0x942be953000,0xc)
19739 automod GIO fd 1 wrote 12 bytes
"Aola mundo!
19739 automod RET write 12/0xc
19739 automod CALL write(1,0x942be953000,0x1)
19739 automod GIO fd 1 wrote 1 bytes
"
"
19739 automod RET write 1
19739 automod CALL write(1,0x942be953000,0x6)
19739 automod GIO fd 1 wrote 6 bytes
"H\M^M=\M-9!
"
19739 automod RET write 6
19739 automod PSIG SIGSEGV SIG_DFL code=SEGV_ACCERR addr=0x940ab6bf398 trapno=6
19739 automod NAMI "automod.core"
Programa que pretende ejecutar código entre sus datos
.intel_syntax noprefix
.section ".note.openbsd.ident", "a"
.p2align 2
.long 8,4,1
.ascii "OpenBSD\0"
.long 0
.global _start
.global puts
.global exit
.text
_start:
# Lo siguiente usaría libc para mostrar prop
lea rdi, [rip + prop]
push rdi
mov rsi, rdi
call puts@plt
# Copiamos de _start a prop
pop rdi
push rdi
lea rsi, [rip - 25] # 25 calculado experimentado con egdb
mov rcx, 10
rep
movsb
# Imprimimos tras copiar
pop rdi
push rdi
call puts@plt
pop rdi
jmp [rdi] # Producirá un SIGSEGV
# Terminar
xor rdi, rdi
call exit@plt
.data
prop:
.asciz "Por sobreescribir con código binario que imprime\n\0"
hola:
.asciz "Hola mundo!\n\0"
Si llamamos export N=xdat; as -gstabs+ $N.s -o $N.o; ld --dynamic-linker=/usr/libexec/ld.so -pie -L/usr/lib -lc $N.o -o $N; y ejecutarlo con ktrace con: ktrace ./xdat; kdump que produce
Por sobreescribir con código binario que imprime
H=!
zsh: segmentation fault (core dumped) ktrace ./xdat
...
9755 xdat CALL fcntl(1,F_ISATTY)
9755 xdat RET fcntl 1
9755 xdat CALL write(1,0x3e9ef3d4000,0x32)
9755 xdat GIO fd 1 wrote 50 bytes
"Por sobreescribir con c\M-C\M-3digo binario que imprime
"
9755 xdat RET write 50/0x32
9755 xdat CALL write(1,0x3e9ef3d4000,0x1)
9755 xdat GIO fd 1 wrote 1 bytes
"
"
9755 xdat RET write 1
9755 xdat CALL write(1,0x3e9ef3d4000,0x6)
9755 xdat GIO fd 1 wrote 6 bytes
"H\M^M=\M-)!
"
9755 xdat RET write 6
9755 xdat PSIG SIGSEGV SIG_DFL code=SEGV_MAPERR addr=0x3e705a153c2 trapno=4
9755 xdat NAMI "xdat.core"
Al ejecutar readelf -t xdat Vemos que la sección
...
[ 8] .text
PROGBITS 0000000000001398 0000000000000398 0
0000000000000034 0000000000000000 0 4
[0000000000000006]: ALLOC, EXEC
...
[12] .data
PROGBITS 0000000000003548 0000000000000548 0
0000000000000042 0000000000000000 0 4
[0000000000000003]: WRITE, ALLOC
ConclusiónLos binarios ELF producidos en OpenBSD con sus herramientas estándar (experimentado con 7.4 sobre amd64) implementan la política W^X en sus secciones. |