samedi 20 août 2011

Kippo - Honeypot SSH

Présentation

Kippo <http://code.google.com/p/kippo/> est un honeypot SSH. Il permet de simuler un serveur SSH qui, suivant l'objectif, peut être facilement accessible lors d'une tentative d'attaque sur le serveur hôte. Il permet, entres autres, de récupérer certaines informations de l'attaquant :

  • les couples logins / mots de passe utilisés pour s'authentifier ;
  • une fois authentifié, les commandes utilisées ;
  • les fichiers envoyés par l'attaquant ;
  • et bien d'autres...
Il est codé en python et nécessite quelques librairies pour fonctionner (en plus du moteur Python bien évidemment) :
  • Twisted 8.0+ (paquet : python-twisted-bin)
  • PyCrypto (paquet : python-crypto)
  • Zope Interface (paquet : python-zope.interface)

Installation

L'installation est vraiment simpliste :

$ wget http://kippo.googlecode.com/files/kippo-0.5.tar.gz
$ tar xzf kippo-0.5.tar.gz && rm kippo-0.5.tar.gz && cd kippo-0.5
$ ./start.sh

et voilà :)

Par défaut, le serveur SSH sera lancé sur le port 2222. Ce port peut être modifié dans le fichier de configuration kippo.cfg:

15|    ssh_port = 2222

Attention néanmoins, Kippo refusera de se lancer avec des droits root, ce qui est très compréhensible, donc il ne sera pas possible de désigner un port inférieur à 1024 (il faudra alors privilégier le port-forwarding afin que le service soit à l'écoute sur le port 22).

Informations et modifications

Plusieurs dossiers sont intéressants

  • honeyfs : il contient l'arborescence des fichiers du serveur SSH. Il est ainsi possible de configurer un /proc/meminfo comme désirer par exemple ;
  • txtcmds : il contient le retour de plusieurs commandes, encore une fois pour personnaliser l'environnement de l'attaquant ;
  • log : il contient le fichier de log du serveur, qui enregistre en particulier les couples logins/passwords et les commandes tapées ;
  • dl : il va contenir tous les fichiers envoyés par l'attaquant.

Récupération des logins et mots de passe

Notre objectif maintenant serait de récupérer dynamiquement, et séparément les logins et mots de passe utilisés (par exemple pour pouvoir se confectionner un petit dictionnaire).
Plusieurs solutions sont possibles :

1 - L'extraction à partir du fichier de logs

Ca ne sera pas du tout dynamique ni probant, mais voici un petit script rapidement écrit pour extraire les IP, les logins et les mots de passe :

#!/bin/bash
#
for ll in $(egrep -o "([[:digit:]]{1,3})(.)([[:digit:]]{1,3})(.)([[:digit:]]{1,3})(.)([[:digit:]]{1,3})(.)(\])( login attempt )(\[)([[:print:]]+)(/)([[:print:]]+)(\])" kippo.log | cut -d' ' -f1,4 -s --output-delimiter=)
do
        IP=$(echo $ll | cut -s -d']' -f1)
        LOGIN_PASS=$(echo $ll | cut -s -d'[' -f2 | cut -s -d']' -f1)
        LOGIN=$(echo $LOGIN_PASS | cut -s -d'/' -f1)
        PASS=$(echo $LOGIN_PASS | cut -s -d'/' -f2)

        ## Logs
        echo $IP >> tempIPs
        echo $LOGIN >> tempLOGINs
        echo $PASS >> tempPASSWORDs

        echo "IP: $IP -- Login: $LOGIN -- Password: $PASS"
done

## Logs globaux
for name in IPs LOGINs PASSWORDs
do
        uniq "temp$name" >> $name
        rm "temp$name"
done


2 - L'enregistrement automatique

Autre solution un peu plus propre est de modifier directement le code source de Kippo afin que, à chaque tentative de connexion, le couple login/mot de passe soit enregistré dans un fichier :

Modification du fichier kippo/core/honeypot.py

## Ouverture du flux vers les deux fichiers
19 > logsLogins = open('log/logins.log', 'a');
19 > logsPasswd = open('log/passwd.log', 'a');

## Ne pas vérifier le login à l'authentification
## Sinon, le fichier log/logins.log ne contiendrait que 'root' :s
## Je laisse quand même la vérification pas mot de passe, ce dernier, modifié, étant très complexe, afin de me laisser une porte au besoin
440 < if username == 'root' and password == cfg.get('honeypot', 'password'):
440 > if password == cfg.get('honeypot', 'password'):

442 < elif username == 'root' and password in passdb:
442 > elif password in passdb:

445 > logsLogins.write(username)

445 > logsPasswd.write(password)
445 > logsLogins.flush()
445 > logsLogins.flush()


(fichier d'exemple joint à ce billet)

Le résultat après une tentative / attaque :
  • Concernant les commandes

$ cat log/kippo.log
[...]
2011-08-19 23:05:43+0200 ... ,89.158.96.199] channel open
2011-08-19 23:05:43+0200 ... ,89.158.96.199] pty request: xterm (24, 80, 0, 0)
2011-08-19 23:05:43+0200 ... ,89.158.96.199] Terminal size: 24 80
2011-08-19 23:05:43+0200 ... ,89.158.96.199] getting shell
2011-08-19 23:05:43+0200 ... ,89.158.96.199] Opening TTY log: log/tty/20110819-230543-4519.log
2011-08-19 23:06:19+0200 ... ,89.158.96.199] CMD: cat /proc/cpuinfo
2011-08-19 23:06:19+0200 ... ,89.158.96.199] Command found: cat /proc/cpuinfo
2011-08-19 23:06:19+0200 ... ,89.158.96.199] Updating realfile to honeyfs//proc/cpuinfo
2011-08-19 23:09:06+0200 ... ,89.158.96.199] CMD: ifcondif
2011-08-19 23:09:06+0200 ... ,89.158.96.199] Command not found: ifcondif
2011-08-19 23:09:10+0200 ... ,89.158.96.199] CMD: ifconfig
2011-08-19 23:09:10+0200 ... ,89.158.96.199] Command found: ifconfig
2011-08-19 23:09:10+0200 ... ,89.158.96.199] Reading txtcmd from "/tmp/kippo-0.5/txtcmds/sbin/ifconfig"
2011-08-19 23:10:26+0200 ... ,89.158.96.199] CMD: cat /proc/meminfo
2011-08-19 23:10:26+0200 ... ,89.158.96.199] Command found: cat /proc/meminfo
2011-08-19 23:11:19+0200 ... ,89.158.96.199] CMD: ifconfig
2011-08-19 23:11:19+0200 ... ,89.158.96.199] Command found: ifconfig
2011-08-19 23:11:19+0200 ... ,89.158.96.199] Reading txtcmd from "/tmp/kippo-0.5/txtcmds/sbin/ifconfig"
2011-08-19 23:11:32+0200 ... ,89.158.96.199] CMD: ifconfig
[...]

$ cat log/passwd.log
[...]
00ad82
00AL09
00al74
00B430
00bd
00beaba
00beca
00bn23
00bob
00C737
00chr2
[...]