Activar ASLR, PIE, RELRO, NX-Stack y hardening en FreeBSD

FreeBSD a día de hoy (9.0-RELEASE) no tiene ASLR de serie, en este artículo vamos a enseñar a aplicar un parche con soporte de ASLR, recompilar el kernel, instalarlo y la nueva sysctl para configurar el espacio aleatorio de ASLR.

Para empezar necesitamos tener las fuentes del sistema (kernel) que se instalan en: /usr/src/sys
Si no tenemos las fuentes deberemos descargarlas, el sistema más cómodo es mediante cvsup (o csup, un clon en C)

Para ello, lo primero es instalar cvsup en caso de no disponer de él:

[root@reki ~]# cd /usr/ports/net/cvsup
[root@reki /usr/ports/net/cvsup]# make install clean

Una vez instalado, debemos configurarlo:

cat > /root/RELENG_9-supfile
*default host=cvsup11.FreeBSD.org
*default base=/var/db
*default prefix=/usr
*default release=cvs tag=RELENG_9
*default delete use-rel-suffix
*default compress

ports-all
src-all
^D

En la configuración expuesta, se está utilizando el mirror cvsup11, recomiendo verificar el mejor en vuestra conexión.
Por otro lado, el tag es RELENG_9 que es el utilizado para FreeBSD 9. Si queréis probar lo último de lo último (Ahora mismo 10.0-CURRENT) con poner un "." como tag es suficiente.

Este supfile actualizará todo el árbol de ports de FreeBSD y todos los sources del userspace.
Si solo queréis los sources del kernel, comentar las dos lineas y añadir la siguiente: src-sys

Una vez tenemos nuestro fichero es el momento de ejecutar cvsup:

[root@reki ~]# cvsup -g -L2 /root/RELENG_9-supfile

Este proceso es bastante lento, así que recomiendo armarse de paciencia y ponerse a otra cosa :-)
Una vez finalizado deberemos de parchear nuestro kernel.

[root@reki ~]# fetch http://lists.freebsd.org/pipermail/freebsd-current/attachments/20111116/...
[root@reki ~]# cd /usr/src
[root@reki /usr/src]# patch -p1 < /root/randomize-stack-and-mmap.bin
Hmm... Looks like a unified diff to me...
The text leading up to this was:
--------------------------
|commit 779a962519e7ead63dda24348b98f6cde8156752
|Author: Oliver Pinter
|Date: Tue Oct 4 00:24:01 2011 +0200
|
| forwardport mmap-randomization patch from 7-STABLE-op
|
| Signed-off-by: Oliver Pinter
|
|diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c
|index fe01142..dc66db6 100644
|--- a/sys/kern/kern_exec.c
|+++ b/sys/kern/kern_exec.c
--------------------------
Patching file sys/kern/kern_exec.c using Plan A...
Hunk #1 succeeded at 107 (offset 1 line).
Hunk #2 succeeded at 122 (offset 1 line).
Hunk #3 succeeded at 182 (offset 1 line).
Hunk #4 succeeded at 1274 (offset -2 lines).
Hunk #5 succeeded at 1295 (offset 1 line).
Hmm... The next patch looks like a unified diff to me...
The text leading up to this was:
--------------------------
|diff --git a/sys/vm/vm_mmap.c b/sys/vm/vm_mmap.c
|index e85b681..991a37d 100644
|--- a/sys/vm/vm_mmap.c
|+++ b/sys/vm/vm_mmap.c
--------------------------
Patching file sys/vm/vm_mmap.c using Plan A...
Hunk #1 succeeded at 68.
Hunk #2 succeeded at 101 (offset 1 line).
Hunk #3 succeeded at 260 (offset -1 lines).
Hunk #4 succeeded at 272 (offset 1 line).
done
[root@reki /usr/src]#

Este es un paso opcional, pero recomiendo añadir el flag "-fstack-protector", "-fomit-frame-pointer" y "-fPIE" en el /etc/make.conf
También es recomendable instalar clang y sustituir gcc por clang.

[root@reki ~]# cat /etc/make.conf
CPUTYPE?=               core2

# Comment from -fomit-frame-pointer to kernel compiling
CFLAGS=                 -O3 -pipe -fno-strict-aliasing -fstack-protector -fomit-frame-pointer # -Wl,-z,relro -Wl,-z,now -D_FORTIFY_SOURCE=2 -fPIE -pie
COPTFLAGS=              -O3 -pipe -fno-strict-aliasing -fstack-protector -fomit-frame-pointer -funroll-loops -ffast-math # -Wl,-z,relro -Wl,-z,now -D_FORTIFY_SOURCE=2 -fPIE -pie
CXXFLAGS+=              -O3 -pipe -fno-strict-aliasing -fstack-protector -fomit-frame-pointer -funroll-loops -ffast-math # -Wl,-z,relro -Wl,-z,now -D_FORTIFY_SOURCE=2 -fPIE -pie

FORCE_MAKE_JOBS=        yes
MAKE_JOBS_NUMBER=       3
KERNCONF=               BSD GENERIC

OPTIMIZED_CFLAGS=       YES
WITHOUT_X11=            YES
BUILD_OPTIMIZED=        YES
WITH_CPUFLAGS=          YES
WITH_OPTIMIZED_CFLAGS=  YES
WITHOUT_DEBUG=          YES
BUILD_STATIC=           YES
NO_PROFILE=             YES

CC=                     clang
CXX=                    clang++
CPP=                    clang-cpp

NO_WERROR=
WERROR=
NO_FSCHG=

# added by use.perl 2012-06-08 14:22:50
PERL_VERSION=5.10.1

Una vez parcheado pasamos a configurar el kernel. Si no entiendes este paso, puedes ignorarlo, es opcional.

[root@reki /usr/src]# vi sys/amd64/conf/GENERIC

Una vez configurado (o si se ha dejado por defecto) hay que compilarlo:

[root@reki /usr/src]# make -j4 buildkernel KERNCONF=GENERIC

Una vez compilado, si todo ha ido bien, es hora de instalarlo (también descomentar las opciones de make.conf):

[root@reki /usr/src]# make installkernel

Ahora activaremos el soporte de NX en Stack:

cat >> /etc/sysctl.conf
kern.elf64.nxstack=1
kern.elf32.nxstack=1
^D

El siguiente paso sería compilar e instalar el userland.

[root@reki /usr/src]# make -j4 buildworld
[root@reki /usr/src]# make installworld

Ahora reiniciamos y si todo ha ido bien, deberíamos volver a tener nuestra shell :-)

[root@reki ~]# uname -a
FreeBSD reki 8.2-STABLE FreeBSD 9.0-STABLE #1: Thu Jul 19 19:01:37 CEST 2012 root@reki:/usr/obj/usr/src/sys/GENERIC amd64

Para comprobar si tenemos ASLR, se puede hacer algo como lo siguiente:

[capi_x@reki ~]$ cat > kk.c
#include <stdio.h>

int main() {
float pp;
char kk[256];

printf("%p\n", &pp);
printf("%p\n", kk);

return(0);
}
^D
[capi_x@reki ~]$ clang -fstack-protector -fPIE -pie kk.c -o kk
[capi_x@reki ~]$ ./kk
0x7fffffff70b0
0x7fffffff7040
[capi_x@reki ~]$ ./kk
0x7fffffff9bf0
0x7fffffff9b80
[capi_x@reki ~]$

Como se puede observar, las direcciones cambian, eso es por que tenemos una implementación de ASLR.
Si queremos aumentar el tamaño de aletorización puede realizarse mediante la sysctl: kern.stackgap_random

Por defecto su valor es 65536 (16 bits) no recomiendo aumentar su valor, ya que he visto que algunos software pueden dar problemas.

Bueno, una vez terminado el artículo recomiendo leer la siguiente presentación donde se expone una arquitectura basada en FreeBSD y su securización al completo: Deploying web servers
De verdad y no es peloteo, os recomiendo leer la presentación, es una auténtica delicia con sello FreeBSD ;-)

Disclaimer: Esto es un parche no oficial, ya sabéis si todo casca, pues rollback y pasando de esto.
Update: El make.conf expuesto y el patch de ASLR funcionan perfectamente en 10.0-CURRENT a día de hoy.

P.D: Saludos a bryn1u si lees esto :)

Hasta la próxima!