Just Another Geek!/ notes/ Debian Hardened

Debian Hardened, ou Debian Version X interdite aux moins de 81 ans

Le paquet harderning-wrapper est un wrapper à gcc et à ld, le script Perl caché derrière permet d'ajouter des options de compilation de manière transparente.

Parmi ces options, on retrouvera bien sûr le support de Stack Guard (l'équivalent de ProPolice d'OpenBSD), la prévention des vulnérabilités de type Format string mais surtout la mise en Read-Only de certaines sections ELF comme la GOT.

Enfin, pour boucler la boucle, l'activation du mode PIE (Position Independent Executable) qui permet de profiter pleinement du support de l'ASLR.

Avec toutes vos applications compilées ainsi et tournant sur un noyau patché avec PaX, tous les vecteurs d'attaque connus touchant à la corruption de mémoire sont rendus "impossible".

Le soucis, c'est qu'il faut tout recompiler et déjà, c'est moins drôle.

Mais sous Debian, on peut essayer de faire les choses un peu proprement en créant son propre repository. Il ne reste plus qu'à jouer avec les outils disponibles dans devscripts.

Première étape : Récupération des paquets à recompiler

L'étape la plus facile :)

server% dpkg -l > pkglist

Deuxième étape : Création de l'environnement de compilation

On a pas envie de salir notre station de travail avec plein de paquets de développement et revenir en Debian Etch juste pour la compilation donc utilisons un environnement chrooté :

dev% sudo debootstrap etch /tmp/debian-etch
dev% sudo chroot /tmp/debian-etch bash
chroot# apt-get install build-essential ...
chroot# wget http://ftp.fr.debian.org/debian/pool/main/h/hardening-wrapper/hardening-wrapper_1.1_i386.deb
chroot# dpkg -i hardening-wrapper_1.1_i386.deb

Par chance, il n'y aucune dépendance qui nous empêche d'utiliser le paquet Unstable pour Etch.

Deuxième étape : Compilation

On pourrait se contenter de faire un apt-get source suivi d'un dpkg-buildpackage mais le numéro de version ne serait pas modifié car aucune entrée dans le changelog serait ajouté. En plus, la signature GnuPG du paquet ne sera pas la votre, heureusement debchange (aka dch) vient à notre secours permet de calculer un nouveau numéro de version et d'ajouter un item dans le changelog à notre nom.

#! /bin/bash


export DEBFULLNAME="Nicolas Bareil"
export DEBEMAIL="nico@chdir.org"

### Le fichier pkglist contient juste la liste des paquets
### disponibles sur le serveur via un "dpkg -l > pkglist"
packages=$(awk '/^ii/ {print $2}' pkglist)

[ -d done ]    || mkdir done 
[ -d notdone ] || mkdir notdone

for pkg in $packages; do
    pkgsrc=$(apt-cache show "$pkg" | perl -ne 'print $1 if /Source: (.+)/')
    pkgsrc="${pkgsrc:-$pkg}"

    [[ -f done/$pkgsrc ]] && continue
    apt-get -yyy --force-yes --quiet build-dep $pkg

    srcdir=$(apt-get source $pkg | perl -lne '/dpkg-source: extracting [^ ]+ in (.*)/ && print $1')
    if (cd $srcdir &&
            dch  --local hardened -D stable  "Rebuilt with compiler's security features enabled" &&
            debuild --no-tgz-check -us -uc); then
            touch done/$pkgsrc
    else
            touch notdone/$pkgsrc
    fi
done

Quelques heures plus tard... ZZZzzzzZZZZZzzzzZZZZZZzzzzz

Bien sûr, fallait pas rêver, il y a quelques paquets qui ne compileront pas aussi facilement, certains sont juste des problèmes de dépendances qui se régleront rapidement, et d'autres demandront un peu plus de doigté comme bash, mais on finit par s'en sortir. Donc il ne vous reste plus qu'à compiler à la main tous les paquets signalés dans le répertoire notdone/.

Signature des paquets

Puisqu'on cherche à faire un truc propre, il faut maintenant signer les paquets mais vos poignets ne vous pardonneront jamais de ne pas avoir utilisé gpg-agent, ca évitera de retaper X fois votre passphrase (où X = 500).

dev% echo use-agent > ~/.gnupg/options
dev% eval "$(gpg-agent --daemon)"
dev% for i in  *changes; do  \
         debsign "$i"        \
     done

La séance d'autographe est terminée, passons en backstage, au niveau du serveur qui hébergera votre repository,

Préparation du serveur

Le paquet mini-dinstall fournit une implémentation light de gestion de repository, il se chargera de vérifier les signatures des paquets, que tout est carré et génera les fichiers nécessaire à apt-get pour accéder à votre repository.

Mais avant de pouvoir l'utiliser, il faut que votre clef PGP soit disponible dans votre keyring.

server$ sudo apt-get install mini-dinstall
server$ mkdir -p /.../debian-etch-rebuilt/htdocs/debian/mini-dinstall/incoming/
server$ cat > ~/.mini-dinstall.conf
[DEFAULT]
archivedir = /.../debian-etch-rebuilt/htdocs/debian/
archive_style = flat
verify_sigs = yes
keyrings = ~/.gnupg/pubring.gpg

[stable]
archivedir = /.../debian-etch-rebuilt/htdocs/debian/
archive_style = flat
verify_sigs = yes
keyrings = ~/.gnupg/pubring.gpg

server$ gpg --recv-key nico@chdir.org
### On vérifie la clef

Il est maintenant temps d'uploader les paquets !

Upload des paquets

Encore une fois, il suffit d'utiliser les bons outils pour ne pas se compliquer la vie, ici, l'upload est le rôle de dput qui fait toutes les vérifications d'usage avant de pourrir votre bande passante :

dev% cat ~/.dput.cf
[serva]             
fqdn = mamachine
login = monlogin
incoming = /.../debian-etch-rebuilt/htdocs/debian/mini-dinstall/incoming
method = rsync
run_dinstall = 0
#post_upload_command = ssh mamachine mini-dinstall -b

dev% for i in  *changes; do \
               dput serva "$i" \
     done

Mise à jour du repository

Dans un premier temps, on va traiter tous les paquets qui attendent dans incoming/ pour les placer là où cela est nécessaire, c'est le rôle de mini-dinstall.

Puis, comme cela est nécessaire depuis que Secure APT existe, il faut maintenant signer les fichiers additionnels pour garantir l'intégrité des paquets.

server$ mini-dinstall -b
server$ cd /.../debian-etch-rebuilt/htdocs/debian/stable
server$ cat > Release
Origin: <span class="selflink">DebianHardened</span>
Label: <span class="selflink">DebianHardened</span>
Suite: stable
Codename: etch
Date: Sun, 30 Dec 2007 16:12:36 UTC
Architectures: amd64 i386 all
Components: main
Description: Debian stable hardened
server$ apt-ftparchive release . >> Release
server$ gpg -abs -o Release.gpg Release

Mise à jour de vos serveurs

Une fois la clef ajoutée au keyring d'apt-get, vous avez gagné !

server$ gpg --export nico@chdir.org| sudo apt-key add -
server# echo "deb http://debian.chdir.org/debian/ stable/" >> /etc/apt/sources.list
server# apt-get update
server# apt-get upgrade

Enjoy :) Ce repository est public, vous pouvez l'utiliser librement.

Les paquets durçis ont une version "locale" ce qui signifie que si une mise à jour du paquet officiel (par exemple via un DSA) est publiée, il sera utilisé à la place du votre (en attendant que vous le recompiliez). Si vous souhaitez un comportement différent, je vous laisse jouer avec l' APT Pinning.

Maintenance du repository

C'est l'étape problématique : comment tenir à jour son repository de manière automatique ? C'est à dire qu'il détecte lorsqu'il y a une mise à jour et compile-lui même la version puis vous envoit un mail pour signer et uploader le paquet.

Parmi les pistes à envisager :

To be continued.