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. |