1 of 130

Reverse me challenge

1

Disconnect3d

AlligatorCon 2k18 ~world

2 of 130

https://python-challenges.com/

3 of 130

4 of 130

5 of 130

6 of 130

7 of 130

nc 51.38.138.161 31337

8 of 130

import os�import sys��print('~~ May the Witchers be with you. Always.')��started = False�filtered = False�

9 of 130

import os�import sys��print('~~ May the Witchers be with you. Always.')��started = False�filtered = False��with open(__file__) as f:� print('~'*30)� for line in f:� if 'import os' in line:� started = True� elif not started:� continue�� if line == '#end-of-filter\n':� filtered = False�� elif filtered:� continue�� print(line, end='')� if 'class Challenge:\n' in line:� filtered = True� print('# [ filtered ]')� print('~'*30)�

10 of 130

def disconnect_code():� print(� 'I am closin\' the', __file__, 'file so it aint too eazy; you know, for your own fun.\n'� )� os.close(100)��

11 of 130

def disconnect_code():� print(� 'I am closin\' the', __file__, 'file so it aint too eazy; you know, for your own fun.\n'� )� os.close(100)���LOL_NO = "I won't give you flag like this"�LOL_MEH = "Meh, you need a bit more here"�

12 of 130

def disconnect_code():� print(� 'I am closin\' the', __file__, 'file so it aint too eazy; you know, for your own fun.\n'� )� os.close(100)���LOL_NO = "I won't give you flag like this"�LOL_MEH = "Meh, you need a bit more here"��print("Flags have a format of FLAG{[A-Za-z0-9_]+}")�

13 of 130

def disconnect_code():� print(� 'I am closin\' the', __file__, 'file so it aint too eazy; you know, for your own fun.\n'� )� os.close(100)���LOL_NO = "I won't give you flag like this"�LOL_MEH = "Meh, you need a bit more here"��print("Flags have a format of FLAG{[A-Za-z0-9_]+}")��class Challenge:�# [ filtered ]�#end-of-filter�

14 of 130

def run():� assert __file__ == '/proc/self/fd/100' # Disconnect3d's magic�� disconnect_code()�� print('\n\n\nOkay. Now you can show off your skills. gl hf')�� while True:� msg = input('msg: ')[:300] # you don't need that many, but feel free...�� print(eval(msg)) # YOLO. gl hf�

15 of 130

def run():� assert __file__ == '/proc/self/fd/100' # Disconnect3d's magic�� disconnect_code()�� print('\n\n\nOkay. Now you can show off your skills. gl hf')�� while True:� msg = input('msg: ')[:300] # you don't need that many, but feel free...�� print(eval(msg)) # YOLO. gl hf���if __name__ == '__main__':� run()�

16 of 130

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~�Flags have a format of FLAG{[A-Za-z0-9_]+}�I am closin' the /proc/self/fd/100 file so it aint too eazy; you know, for your own fun.�����Okay. Now you can show off your skills. gl hf�msg:

17 of 130

eval is evil

17

18 of 130

'__import__("os").system("...")'

18

19 of 130

eval(input, {'__builtins__':{}})

19

20 of 130

"{}.__class__.__base__.__subclasses__()[59]()._module�.__builtins__['__import__']('os').system('echo sick')"

20

21 of 130

"{}.__class__.__base__.__subclasses__()[59]()._module�.__builtins__['__import__']('os').system('echo sick')"

21

22 of 130

"{}.__class__.__base__.__subclasses__()[59]()._module�.__builtins__['__import__']('os').system('echo sick')"

22

23 of 130

"{}.__class__.__base__.__subclasses__()[59]()._module�.__builtins__['__import__']('os').system('echo sick')"

23

24 of 130

"{}.__class__.__base__.__subclasses__()[59]()._module�.__builtins__['__import__']('os').system('echo sick')"

24

25 of 130

"{}.__class__.__base__.__subclasses__()[59]()._module�.__builtins__['__import__']('os').system('echo sick')"

25

26 of 130

The challenge

26

27 of 130

class Challenge:�# [ filtered ]�#end-of-filter

27

28 of 130

First level

28

29 of 130

Reverse me challenge

class Challenge:� def first_level(self):� return 'That was just a begining. First flag: FLAG{easy_peasy_lemon_squeezy}'�

29

30 of 130

class Challenge:�# [ filtered ]�#end-of-filter

30

31 of 130

Reverse me challenge

class Challenge:� def first_level(self):� return 'That was just a begining. First flag: FLAG{easy_peasy_lemon_squeezy}'

msg: dir(Challenge)

['first_level', 'second_level', 'third_level', ...]

�

31

32 of 130

Reverse me challenge

class Challenge:� def first_level(self):� return 'That was just a begining. First flag: FLAG{easy_peasy_lemon_squeezy}'

msg: dir(Challenge)

['first_level', 'second_level', 'third_level', ...]

msg: Challenge().first_level()

That was just a begining. First flag: FLAG{easy_peasy_lemon_squeezy}

�

32

33 of 130

Second level

33

34 of 130

def second_level(self):� raise Exception(LOL_NO)�� def a():� """� Never gonna give you up� Never gonna let you down� Never gonna run around and desert you� Never gonna make you cry� Never gonna say goodbye� Never gonna tell a lie and hurt you� """� def b():� """� Never gonna give you up� Never gonna let you down� Never gonna run around and desert you� Never gonna make you cry� Never gonna say goodbye� Never gonna tell a lie and hurt you� """�

34

35 of 130

def c():� """� Never gonna give you up� Never gonna let you down� Never gonna run around and desert you� Never gonna make you cry� Never gonna say goodbye� Never gonna tell a lie and hurt you� """� def d():� """� Never gonna give you up� Never gonna let you down� Never gonna run around and desert you� Never gonna make you cry� Never gonna say goodbye� Never gonna tell a lie and hurt you� """� def e():� return 'Lets play moar =). Second flag: FLAG{this_was_also_easy}'� def f():� """� Never gonna give you up� Never gonna let you down� Never gonna run around and desert you� Never gonna make you cry� Never gonna say goodbye� Never gonna tell a lie and hurt you� """�� return LOL_MEH�� def third_level(self):� raise Exception(LOL_NO)� � key = [3, 1, 3, 3, 7]� ciphertext = '^DGMH[t@Or]CH]r^JZvEHYM'�� flag = ''.join(chr(ord(ciphertext[i]) ^ key[i%len(key)] ^ 42) for i in range(len(ciphertext)))�� return 'This could be deducted... MOOAAR. Third flag: FLAG{%s}' % flag�

35

36 of 130

msg: Challenge().second_level()

36

37 of 130

msg: Challenge().second_level()

Traceback (most recent call last):

File "/proc/self/fd/100", line 188, in <module>

File "/proc/self/fd/100", line 184, in run

File "<string>", line 1, in <module>

File "/proc/self/fd/100", line 109, in second_level

Exception: I won't give you flag like this

37

38 of 130

msg: Challenge.second_level.__code__

<code object second_level at 0x7f437b874d20, file

"/proc/self/fd/100", line 108>

38

39 of 130

msg: Challenge.second_level.__code__.co_consts

(

None,�

<code object a (...)>,

'Challenge.second_level.<locals>.a',

<code object b (...)>,

'Challenge.second_level.<locals>.b',

<code object c (...)>,

'Challenge.second_level.<locals>.c',

<code object d (...)>,

'Challenge.second_level.<locals>.d',

<code object f (...)>,

'Challenge.second_level.<locals>.f'

)

39

40 of 130

msg: Challenge.second_level.__code__.co_consts[7].co_consts

(

‘Never gonna give you up (...)',

<code object e (...)>,

'Challenge.second_level.<locals>.d.<locals>.e',

None

)

40

41 of 130

msg: Challenge.second_level.__code__.co_consts[7].co_consts[1].co_consts

(

None,

'Lets play moar =). Second flag: FLAG{this_was_also_easy}'�)

41

42 of 130

Third level

42

43 of 130

Third level

def third_level(self):� raise Exception(LOL_NO)� � key = [3, 1, 3, 3, 7]� ciphertext = '^DGMH[t@Or]CH]r^JZvEHYM'�� flag = ''.join(chr(ord(ciphertext[i]) ^ key[i%len(key)] ^ 42) for i in range(len(ciphertext)))�� return 'This could be deducted... MOOAAR. Third flag: FLAG{%s}' % flag�

43

44 of 130

Meet dis

44

45 of 130

45

46 of 130

46

47 of 130

47

48 of 130

48

49 of 130

__import__('dis').dis(Challenge.third_level)

49

50 of 130

msg: __import__('dis').dis(Challenge.third_level)

162 0 LOAD_GLOBAL 0 (Exception)

3 LOAD_GLOBAL 1 (LOL_NO)

6 CALL_FUNCTION 1 (1 positional, 0 keyword pair)

9 RAISE_VARARGS 1

164 12 LOAD_CONST 1 (3)

15 LOAD_CONST 2 (1)

18 LOAD_CONST 1 (3)

21 LOAD_CONST 1 (3)

24 LOAD_CONST 3 (7)

27 BUILD_LIST 5

30 STORE_DEREF 1 (key)

165 33 LOAD_CONST 4 ('^DGMH[t@Or]CH]r^JZvEHYM')

36 STORE_DEREF 0 (ciphertext)

167 39 LOAD_CONST 5 ('')

42 LOAD_ATTR 2 (join)

45 LOAD_CLOSURE 0 (ciphertext)

48 LOAD_CLOSURE 1 (key)

51 BUILD_TUPLE 2

54 LOAD_CONST 6 (<code object <genexpr> (...))

57 LOAD_CONST 7 ('Challenge.third_level.<locals>.<genexpr>')

50

51 of 130

msg: __import__('dis').dis(Challenge.third_level)

162 0 LOAD_GLOBAL 0 (Exception)

3 LOAD_GLOBAL 1 (LOL_NO)

6 CALL_FUNCTION 1 (1 positional, 0 keyword pair)

9 RAISE_VARARGS 1

164 12 LOAD_CONST 1 (3)

15 LOAD_CONST 2 (1)

18 LOAD_CONST 1 (3)

21 LOAD_CONST 1 (3)

24 LOAD_CONST 3 (7)

27 BUILD_LIST 5

30 STORE_DEREF 1 (key)

165 33 LOAD_CONST 4 ('^DGMH[t@Or]CH]r^JZvEHYM')

36 STORE_DEREF 0 (ciphertext)

167 39 LOAD_CONST 5 ('')

42 LOAD_ATTR 2 (join)

45 LOAD_CLOSURE 0 (ciphertext)

48 LOAD_CLOSURE 1 (key)

51 BUILD_TUPLE 2

54 LOAD_CONST 6 (<code object <genexpr> (...))

57 LOAD_CONST 7 ('Challenge.third_level.<locals>.<genexpr>')

51

52 of 130

msg: __import__('dis').dis(Challenge.third_level)

162 0 LOAD_GLOBAL 0 (Exception)

3 LOAD_GLOBAL 1 (LOL_NO)

6 CALL_FUNCTION 1 (1 positional, 0 keyword pair)

9 RAISE_VARARGS 1

164 12 LOAD_CONST 1 (3)

15 LOAD_CONST 2 (1)

18 LOAD_CONST 1 (3)

21 LOAD_CONST 1 (3)

24 LOAD_CONST 3 (7)

27 BUILD_LIST 5

30 STORE_DEREF 1 (key)

165 33 LOAD_CONST 4 ('^DGMH[t@Or]CH]r^JZvEHYM')

36 STORE_DEREF 0 (ciphertext)

167 39 LOAD_CONST 5 ('')

42 LOAD_ATTR 2 (join)

45 LOAD_CLOSURE 0 (ciphertext)

48 LOAD_CLOSURE 1 (key)

51 BUILD_TUPLE 2

54 LOAD_CONST 6 (<code object <genexpr> (...))

57 LOAD_CONST 7 ('Challenge.third_level.<locals>.<genexpr>')

52

53 of 130

60 MAKE_CLOSURE 0

63 LOAD_GLOBAL 3 (range)

66 LOAD_GLOBAL 4 (len)

69 LOAD_DEREF 0 (ciphertext)

72 CALL_FUNCTION 1 (1 positional, 0 keyword pair)

75 CALL_FUNCTION 1 (1 positional, 0 keyword pair)

78 GET_ITER

79 CALL_FUNCTION 1 (1 positional, 0 keyword pair)

82 CALL_FUNCTION 1 (1 positional, 0 keyword pair)

85 STORE_FAST 1 (flag)

169 88 LOAD_CONST 8 ('This could be deducted... MOOAAR. Third flag: FLAG{%s}')

91 LOAD_FAST 1 (flag)

94 BINARY_MODULO

95 RETURN_VALUE

None

53

54 of 130

msg: __import__('dis').dis(Challenge.third_level.__code__.co_consts[6])

167 0 LOAD_FAST 0 (.0)

>> 3 FOR_ITER 49 (to 55)

6 STORE_FAST 1 (i)

9 LOAD_GLOBAL 0 (chr)

12 LOAD_GLOBAL 1 (ord)

15 LOAD_DEREF 0 (ciphertext)

18 LOAD_FAST 1 (i)

21 BINARY_SUBSCR

22 CALL_FUNCTION 1 (1 positional, 0 keyword pair)

25 LOAD_DEREF 1 (key)

28 LOAD_FAST 1 (i)

31 LOAD_GLOBAL 2 (len)

34 LOAD_DEREF 1 (key)

37 CALL_FUNCTION 1 (1 positional, 0 keyword pair)

40 BINARY_MODULO

41 BINARY_SUBSCR

42 BINARY_XOR

43 LOAD_CONST 0 (42)

46 BINARY_XOR

47 CALL_FUNCTION 1 (1 positional, 0 keyword pair)

50 YIELD_VALUE

51 POP_TOP

52 JUMP_ABSOLUTE 3

>> 55 LOAD_CONST 1 (None)

58 RETURN_VALUE

54

55 of 130

TIL

55

56 of 130

You can use exec and pdb�in eval

56

57 of 130

Lets see some cool solutions

57

58 of 130

exec("import pdb; pdb.run('Challenge().second_level()')")�from types import CodeType��def fix_function(func, payload):

fn_code = func.__code__

func.__code__ = CodeType(fn_code.co_argcount, fn_code.co_kwonlyargcount,fn_code.co_nlocals,fn_code.co_stacksize,fn_code.co_flags,payload,fn_code.co_consts,fn_code.co_names,fn_code.co_varnames,fn_code.co_filename,fn_code.co_name,fn_code.co_firstlineno,fn_code.co_lnotab,fn_code.co_freevars,fn_code.co_cellvars,)��payload = b't\x00\x00d\x01\x00d\x02\x00\x84\x00\x00}\x01\x00d\x03\x00d\x04\x00\x84\x00\x00}\x02\x00d\x05\x00d\x06\x00\x84\x00\x00}\x03\x00d\x07\x00d\x08\x00\x84\x00\x00}\x04\x00d\t\x00d\n\x00\x84\x00\x00}\x05\x00t\x02\x00S'�ch = Challenge.second_level

fix_function(ch, payload)

ch(Challenge())�

58

59 of 130

exec("import pdb; pdb.run('Challenge().second_level()')")�from types import CodeType��def fix_function(func, payload):

fn_code = func.__code__

func.__code__ = CodeType(fn_code.co_argcount, fn_code.co_kwonlyargcount,fn_code.co_nlocals,fn_code.co_stacksize,fn_code.co_flags,payload,fn_code.co_consts,fn_code.co_names,fn_code.co_varnames,fn_code.co_filename,fn_code.co_name,fn_code.co_firstlineno,fn_code.co_lnotab,fn_code.co_freevars,fn_code.co_cellvars,)��payload = b't\x00\x00d\x01\x00d\x02\x00\x84\x00\x00}\x01\x00d\x03\x00d\x04\x00\x84\x00\x00}\x02\x00d\x05\x00d\x06\x00\x84\x00\x00}\x03\x00d\x07\x00d\x08\x00\x84\x00\x00}\x04\x00d\t\x00d\n\x00\x84\x00\x00}\x05\x00t\x02\x00S'�ch = Challenge.second_level

fix_function(ch, payload)

ch(Challenge())�

59

60 of 130

exec("import pdb; pdb.run('Challenge().second_level()')")�from types import CodeType��def fix_function(func, payload):

fn_code = func.__code__

func.__code__ = CodeType(fn_code.co_argcount, fn_code.co_kwonlyargcount,fn_code.co_nlocals,fn_code.co_stacksize,fn_code.co_flags,payload,fn_code.co_consts,fn_code.co_names,fn_code.co_varnames,fn_code.co_filename,fn_code.co_name,fn_code.co_firstlineno,fn_code.co_lnotab,fn_code.co_freevars,fn_code.co_cellvars,)��payload = b't\x00\x00d\x01\x00d\x02\x00\x84\x00\x00}\x01\x00d\x03\x00d\x04\x00\x84\x00\x00}\x02\x00d\x05\x00d\x06\x00\x84\x00\x00}\x03\x00d\x07\x00d\x08\x00\x84\x00\x00}\x04\x00d\t\x00d\n\x00\x84\x00\x00}\x05\x00t\x02\x00S'�ch = Challenge.second_level

fix_function(ch, payload)

ch(Challenge())�

60

func.__code__.co_code

61 of 130

exec("import pdb; pdb.run('Challenge().second_level()')")�from types import CodeType��def fix_function(func, payload):

fn_code = func.__code__

func.__code__ = CodeType(fn_code.co_argcount, fn_code.co_kwonlyargcount,fn_code.co_nlocals,fn_code.co_stacksize,fn_code.co_flags,payload,fn_code.co_consts,fn_code.co_names,fn_code.co_varnames,fn_code.co_filename,fn_code.co_name,fn_code.co_firstlineno,fn_code.co_lnotab,fn_code.co_freevars,fn_code.co_cellvars,)��payload = b't\x00\x00d\x01\x00d\x02\x00\x84\x00\x00}\x01\x00d\x03\x00d\x04\x00\x84\x00\x00}\x02\x00d\x05\x00d\x06\x00\x84\x00\x00}\x03\x00d\x07\x00d\x08\x00\x84\x00\x00}\x04\x00d\t\x00d\n\x00\x84\x00\x00}\x05\x00t\x02\x00S'�ch = Challenge.second_level

fix_function(ch, payload)

ch(Challenge())�

61

func.__code__.co_code

62 of 130

Next

62

63 of 130

exec("import dis")�exec("ch = Challenge()")�exec("from types import CodeType as CT")�exec("fnc = Challenge.second_level.__code__")�print(fnc.co_code)�exec("payload = fnc.co_code[-4:] + b't\x05\x00S'")�print("hello")�print(fnc.co_code)�exec("AAAA = [fnc.co_argcount, fnc.co_kwonlyargcount, fnc.co_nlocals, fnc.co_stacksize, fnc.co_flags, payload, fnc.co_consts, fnc.co_names, fnc.co_varnames, fnc.co_filename, fnc.co_name, fnc.co_firstlineno, fnc.co_lnotab, fnc.co_freevars, fnc.co_cellvars]")�exec("Challenge.second_level.__code__ = CT(*AAAA)")�dis.dis(ch.second_level)�ch.second_level()�

63

64 of 130

exec("import dis")�exec("ch = Challenge()")�exec("from types import CodeType as CT")�exec("fnc = Challenge.second_level.__code__")�print(fnc.co_code)�exec("payload = fnc.co_code[-4:] + b't\x05\x00S'")�print("hello")�print(fnc.co_code)�exec("AAAA = [fnc.co_argcount, fnc.co_kwonlyargcount, fnc.co_nlocals, fnc.co_stacksize, fnc.co_flags, payload, fnc.co_consts, fnc.co_names, fnc.co_varnames, fnc.co_filename, fnc.co_name, fnc.co_firstlineno, fnc.co_lnotab, fnc.co_freevars, fnc.co_cellvars]")�exec("Challenge.second_level.__code__ = CT(*AAAA)")�dis.dis(ch.second_level)�ch.second_level()�

64

65 of 130

65

66 of 130

Next

66

67 of 130

Jumping in pdb

67

68 of 130

with Telnet('51.38.138.161', 31337) as tn:� # tn.write(b"Challenge().second_level.__func__.__code__" + b'\n')� tn.write(b"__import__('dis').dis(Challenge().third_level)" + b'\n')� tn.write(b"__import__('pdb').run('Challenge().third_level()')" + b'\n')� tn.write(b"step" + b'\n')� tn.write(b"step" + b'\n')� tn.write(b"j 164" + b'\n')

# tn.write(b"__import__('pdb').runcall(d)" + b'\n')�

68

69 of 130

Next

69

70 of 130

You can read /proc/self/mem

70

71 of 130

import re�p = "/proc/self/"�

ma = open(p+"maps",'r')�me = open(p+"mem",'rb',0)

�for l in ma.readlines():� m = re.match(r'([0-9A-Fa-f]+)-([0-9A-Fa-f]+) ([-r])', l)� if m.group(3) == 'r':� s = int(m.group(1),16)� me.seek(s)� chunk = me.read(int(m.group(2),16)-s)� print(chunk,)

71

72 of 130

msg: exec('import re\np="/proc/self/"\nma=open(p+"maps",\'r\')\nme=open(p+"mem",\'rb\',0)\nfor l in ma.readlines():\n m=re.match(r\'([0-9A-Fa-f]+)-([0-9A-Fa-f]+) ([-r])\', l)\n if m.group(3) == \'r\':\n s=int(m.group(1),16)\n me.seek(s)\n chunk=me.read(int(m.group(2),16)-s)\n print(chunk,)\n')�

72

73 of 130

73

74 of 130

74

75 of 130

75

*this is only the part that fit on the screen

76 of 130

\x00\x00\x00\x00\x00\x00 you\n """\n def e():\n \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 =). Second flag: FLAG{this_was_also_easy}\'\n def\x00\x01\x00\x00\x00\x00\x00\x00\x00 Never gonna give you up\n Never gonna\xe0\xf6=\x1d\xcf\x7f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 Never gonna run around and desert you\n Neve\xf0\x19,\x1d\xcf\x7f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17\x00\x00\x00\x00\x00\x00\x00 Never gonna say goodbye\n Never gonna\xe0\xf6=\x1d\xcf\x7f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\n """\n\n return LOL_MEH\n\n def third_\xe0\xbc2\x1d\xcf\x7f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00se Exception(LOL_NO)\n \n key = [3, 1, 3, 3,\xe0\xf6=\x1d\xcf\x7f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \'^DGMH[t@Or]CH]r^JZvEHYM\'\n\n flag = \'\'.join(chr(o\xb06+\x1d\xcf\x7f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00a\x00\x00\x00\x00\x00\x00\x00i%len(key)] ^ 42) for i in range(len(ciphertext)))\n\n \xe0\xf6=\x1d\xcf\x7f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00e deducted... MOOAAR. Third flag: FLAG{%s}\' % flag\n\n#endP\xb53\x1d\xcf\x7f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00 assert __file__ == \'/proc/self/fd/100\' # Disconnect\xe0\xf6=\x1d\xcf\x7f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00ct_code()\n\n print(\'\\n\\n\\nOkay. Now you can show off y(\x1a,\x1d\xcf\x7f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00 while True:\n msg = input(\'msg: \')[:300] # you d\xe0\xf6=\x1d\xcf\x7f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 feel free...\n\n print(eval(msg)) # YOL\xd8\xb43\x1d\xcf\x7f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00= \'__main__\':\n run()\n \x16\x00\x00\x00\x00\x00\x000\x16\x0

76

77 of 130

\x00\x00\x00\x00\x00\x00 you\n """\n def e():\n \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 =). Second flag: FLAG{this_was_also_easy}\'\n def\x00\x01\x00\x00\x00\x00\x00\x00\x00 Never gonna give you up\n Never gonna\xe0\xf6=\x1d\xcf\x7f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 Never gonna run around and desert you\n Neve\xf0\x19,\x1d\xcf\x7f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17\x00\x00\x00\x00\x00\x00\x00 Never gonna say goodbye\n Never gonna\xe0\xf6=\x1d\xcf\x7f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\n """\n\n return LOL_MEH\n\n def third_\xe0\xbc2\x1d\xcf\x7f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00se Exception(LOL_NO)\n \n key = [3, 1, 3, 3,\xe0\xf6=\x1d\xcf\x7f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \'^DGMH[t@Or]CH]r^JZvEHYM\'\n\n flag = \'\'.join(chr(o\xb06+\x1d\xcf\x7f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00a\x00\x00\x00\x00\x00\x00\x00i%len(key)] ^ 42) for i in range(len(ciphertext)))\n\n \xe0\xf6=\x1d\xcf\x7f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00e deducted... MOOAAR. Third flag: FLAG{%s}\' % flag\n\n#endP\xb53\x1d\xcf\x7f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00 assert __file__ == \'/proc/self/fd/100\' # Disconnect\xe0\xf6=\x1d\xcf\x7f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00ct_code()\n\n print(\'\\n\\n\\nOkay. Now you can show off y(\x1a,\x1d\xcf\x7f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00 while True:\n msg = input(\'msg: \')[:300] # you d\xe0\xf6=\x1d\xcf\x7f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 feel free...\n\n print(eval(msg)) # YOL\xd8\xb43\x1d\xcf\x7f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00= \'__main__\':\n run()\n \x16\x00\x00\x00\x00\x00\x000\x16\x0

77

78 of 130

key = [3, 1, 3, 3, 7]

ciphertext = '^DGMH[t@Or]CH]r^JZvEHYM'

flag = \'\'.join(chr(ord(ciphertext[i])len(key)] ^ 42) for i in range(len(ciphertext)))

ord(ciphertext[i])%

key[i%len(key)]

flag = \'\'.join(chr(oXX"\xab\x7f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00a\x00\x00\x00\x00\x00\x00\x00i%len(key)] ^ 42) for i in range(len(ciphertext)))

flag = \'\'.join(chr(o\xb06+\x1d\xcf\x7fXXXXXXXXXXaXXXXXXXi%len(key)] ^ 42) for i in range(len(ciphertext)))\n\n

flag = ''.join(chr(oX6+XXXXXXXXXXXXXaXXXXXXXi%len(key)] ^ 42) for i in range(len(ciphertext)))

flag = ''.join(chr(ord(ciphertext[i]) ^ key[i%len(key)] ^ 42) for i in range(len(ciphertext)))

78

Some of the notes :P

79 of 130

Lets try to get all the source code!

Input: open(__file__).read()

79

80 of 130

Lets try to get all the source code!

Input: open(__file__).read()

Traceback (most recent call last):

File "/proc/self/fd/100", line 188, in <module>

File "/proc/self/fd/100", line 184, in run

File "<string>", line 1, in <module>

FileNotFoundError: [Errno 2] No such file or directory: '/proc/self/fd/100'

80

81 of 130

Wait what?

'/proc/self/fd/100'

$ mount

proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)

(...)

81

82 of 130

Wait what?

'/proc/self/fd/100'

$ mount

proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)

(...)

82

83 of 130

Wait what?

'/proc/self/fd/100'

$ mount

proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)

(...)

83

84 of 130

So...

The file was read by [C]Python… but it is not there anymore.

def disconnect_code():� print(� 'I am closin\' the',� __file__,

'file so it aint too eazy;',� 'you know, for your own fun.\n'� )� os.close(100)�

84

85 of 130

So...

The file was read by [C]Python… but it is not there anymore.

def disconnect_code():� print(� 'I am closin\' the',� __file__,

'file so it aint too eazy;',� 'you know, for your own fun.\n'� )� os.close(100)�

85

86 of 130

So...

The file was read by [C]Python… but it is not there anymore.

def disconnect_code():� print(� 'I am closin\' the',� __file__,

'file so it aint too eazy;',� 'you know, for your own fun.\n'� )� os.close(100)�

86

87 of 130

Here comes the fun part!

87

88 of 130

Can we break or hack the server?

I don’t know.

If you ask for permission:�Yes, you can try.

88

89 of 130

Can we break or hack the server?

I don’t know.

If you ask for permission:�Yes, you can try.

89

90 of 130

Can we break or hack the server?

I don’t know.

If you ask for permission:�Yes, you can try.

90

91 of 130

But… good luck!

91

92 of 130

Lets see some examples!

92

93 of 130

Lets see some examples!

Input: msg: __import__('os').fork()

Traceback (most recent call last):

File "/proc/self/fd/100", line 188, in <module>

File "/proc/self/fd/100", line 184, in run

File "<string>", line 1, in <module>

BlockingIOError: [Errno 11] Resource temporarily unavailable

93

94 of 130

Lets see some examples!

Input: msg: __import__('os').fork()

Traceback (most recent call last):

File "/proc/self/fd/100", line 188, in <module>

File "/proc/self/fd/100", line 184, in run

File "<string>", line 1, in <module>

BlockingIOError: [Errno 11] Resource temporarily unavailable

94

95 of 130

Lets see some examples!

Input: msg: os.system('cat /etc/passwd')

-1

95

96 of 130

So maybe DOS?

96

97 of 130

DOS?

Input: list(range(2**32))

Traceback (most recent call last):

File "/proc/self/fd/100", line 188, in <module>

File "/proc/self/fd/100", line 184, in run

File "<string>", line 1, in <module>

MemoryError

97

98 of 130

DOS?

Input: list(range(2**32))

Traceback (most recent call last):

File "/proc/self/fd/100", line 188, in <module>

File "/proc/self/fd/100", line 184, in run

File "<string>", line 1, in <module>

MemoryError

98

99 of 130

Behind the scenes

99

100 of 130

nsjail

100

101 of 130

How is it done?

101

102 of 130

How is it done?

Tool created by Jagger from Dragon Sector CTF team

102

103 of 130

How is it done?

Tool created by Jagger from Dragon Sector CTF team

Funfact: he was supposed to be my manager in Google

103

104 of 130

How is it done?

Tool created by Jagger from Dragon Sector CTF team

Funfact: he was supposed to be my manager in Google but apparently I rejected them

104

105 of 130

How its build

105

106 of 130

Build

docker build -t test .

docker run -d -v /sys/fs/cgroup:/sys/fs/cgroup:rw -p 31337:31337 --privileged --rm test

106

107 of 130

Build

docker build -t test .

docker run -d -v /sys/fs/cgroup:/sys/fs/cgroup:rw -p 31337:31337 --privileged --rm test

107

Wait whaaaat? Rooot?

108 of 130

Build

FROM nsjail

RUN apt-get update && apt-get install -y python3

ADD . /task

RUN groupadd nobody

CMD /task/launch.sh

108

109 of 130

launch.sh

#!/bin/bash

mkdir -p /sys/fs/cgroup/{cpu,memory,pids}/NSJAIL

nsjail --config /task/nsjail.cfg 100<>/task/chall.py

109

110 of 130

nsjail.cfg

name: "Python challenges task"

description: "yolo"

mode: LISTEN

hostname: "OhYouHaxx0rThereIsNothingHere"

bindhost: "0.0.0.0"

port: 31337

110

111 of 130

nsjail.cfg

pass_fd: 0

pass_fd: 1

pass_fd: 2

pass_fd: 100

111

112 of 130

nsjail.cfg

pass_fd: 0

pass_fd: 1

pass_fd: 2

pass_fd: 100

keep_env: true

112

113 of 130

nsjail.cfg

time_limit: 60

max_cpus: 1

cgroup_pids_max: 1

rlimit_as: 64

rlimit_core: 0

rlimit_cpu: 10

rlimit_fsize: 0

rlimit_nofile: 32

rlimit_stack_type: SOFT

rlimit_nproc_type: SOFT

113

114 of 130

nsjail.cfg

uidmap {

inside_id: "1"

outside_id: "nobody"

}

gidmap {

inside_id: "1"

outside_id: "nobody"

}

114

115 of 130

nsjail.cfg

mount_proc: true

mount {

src: "/usr"

dst: "/usr"

is_bind: true

rw: false

}

mount {

src: "/lib"

dst: "/lib"

is_bind: true

rw: false

}

mount {

src: "/lib64"

dst: "/lib64"

is_bind: true

rw: false

}

mount {

src: "/bin"

dst: "/bin"

is_bind: true

rw: false

}

115

116 of 130

nsjail.cfg

mount {

src: "/task/fake_passwd"

dst: "/etc/passwd"

is_bind: true

rw: false

mandatory: true

is_dir: false

}

mount {

dst: "/tmp"

fstype: "tmpfs"

rw: true

}

116

117 of 130

nsjail.cfg

exec_bin {

path: "/usr/bin/python3"

arg0: "python3"

arg: "/proc/self/fd/100"

}

117

118 of 130

nsjail.cfg

seccomp_string: "POLICY example { "

seccomp_string: " ERRNO(1337) { getuid, getgid, geteuid, getegid }, "

seccomp_string: " ERRNO(0) { ptrace }, "

seccomp_string: " ALLOW { execve } "

seccomp_string: "} "

seccomp_string: "USE example DEFAULT ALLOW "

seccomp_log: true

118

119 of 130

nsjail.cfg

seccomp_string: "POLICY example { "

seccomp_string: " ERRNO(1337) { getuid, getgid, geteuid, getegid }, "

seccomp_string: " ERRNO(0) { ptrace }, "

seccomp_string: " ALLOW { execve } "

seccomp_string: "} "

seccomp_string: "USE example DEFAULT ALLOW "

seccomp_log: true

119

120 of 130

nsjail.cfg

seccomp_string: "POLICY example { "

seccomp_string: " ERRNO(1337) { getuid, getgid, geteuid, getegid }, "

seccomp_string: " ERRNO(0) { ptrace }, "

seccomp_string: " ALLOW { execve } "

seccomp_string: "} "

seccomp_string: "USE example DEFAULT ALLOW "

seccomp_log: true

120

121 of 130

nsjail.cfg

seccomp_string: "POLICY example { "

seccomp_string: " ERRNO(1337) { getuid, getgid, geteuid, getegid }, "

seccomp_string: " ERRNO(0) { ptrace }, "

seccomp_string: " ALLOW { execve } "

seccomp_string: "} "

seccomp_string: "USE example DEFAULT ALLOW "

seccomp_log: true

121

122 of 130

nsjail.cfg

seccomp_string: "POLICY example { "

seccomp_string: " ERRNO(1337) { getuid, getgid, geteuid, getegid }, "

seccomp_string: " ERRNO(0) { ptrace }, "

seccomp_string: " ALLOW { execve } "

seccomp_string: "} "

seccomp_string: "USE example DEFAULT ALLOW "

seccomp_log: true

122

123 of 130

nsjail.cfg

seccomp_string: "POLICY example { "

seccomp_string: " ERRNO(1337) { getuid, getgid, geteuid, getegid }, "

seccomp_string: " ERRNO(0) { ptrace }, "

seccomp_string: " ALLOW { execve } "

seccomp_string: "} "

seccomp_string: "USE example DEFAULT ALLOW "

seccomp_log: true

123

DEFAULT ALLOW

124 of 130

nsjail.cfg

seccomp_string: "POLICY example { "

seccomp_string: " ERRNO(1337) { getuid, getgid, geteuid, getegid }, "

seccomp_string: " ERRNO(0) { ptrace }, "

seccomp_string: " ALLOW { execve } "

seccomp_string: "} "

seccomp_string: "USE example DEFAULT ALLOW "

seccomp_log: true

124

DEFAULT ALLOW

LOL WUT?

125 of 130

And that’s all :)

125

126 of 130

Hope you enjoyed!

126

127 of 130

Thanks

127

128 of 130

PS

128

129 of 130

Make a lightning talk! :)

129

130 of 130

The end

Hope you enjoyed o/

https://disconnect3d.pl/

disconnect3d # irc.freenode.net