Slide 1

Slide 1 text

Zákeřný eval() Petr Viktorin encukou@gmail.com nebezpečné PyVo 2012-09-27

Slide 2

Slide 2 text

$ pydoc eval eval(source[, globals[, locals]]) Evaluate the source in the context of globals and locals. The source may be a string representing a Python expression or a code object as returned by compile().

Slide 3

Slide 3 text

import os import math f = raw_input ( " Zadej funkci : " ) for x in range ( 5 ) : print " x = %s , y = %s " % ( x , eval ( f ) )

Slide 4

Slide 4 text

Zadej funkci: x * 5 x = 0, y = 0 x = 1, y = 5 x = 2, y = 10 x = 3, y = 15 x = 4, y = 20

Slide 5

Slide 5 text

Zadej funkci: x * 5 x = 0, y = 0 x = 1, y = 5 x = 2, y = 10 x = 3, y = 15 x = 4, y = 20 Zadej funkci: math.sin(x) x = 0, y = 0.0 x = 1, y = 0.841470984808 x = 2, y = 0.909297426826 x = 3, y = 0.14112000806 x = 4, y = -0.756802495308

Slide 6

Slide 6 text

Zadej funkci: x * 5 x = 0, y = 0 x = 1, y = 5 x = 2, y = 10 x = 3, y = 15 x = 4, y = 20 Zadej funkci: math.sin(x) x = 0, y = 0.0 x = 1, y = 0.841470984808 x = 2, y = 0.909297426826 x = 3, y = 0.14112000806 x = 4, y = -0.756802495308 Zadej funkci: x ** 999999 x = 0, y = 0 x = 1, y = 1

Slide 7

Slide 7 text

Zadej funkci: x * 5 x = 0, y = 0 x = 1, y = 5 x = 2, y = 10 x = 3, y = 15 x = 4, y = 20 Zadej funkci: math.sin(x) x = 0, y = 0.0 x = 1, y = 0.841470984808 x = 2, y = 0.909297426826 x = 3, y = 0.14112000806 x = 4, y = -0.756802495308 Zadej funkci: x ** 999999 x = 0, y = 0 x = 1, y = 1 Zadej funkci: open('/etc/passwd').read() x = 0, y = root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin

Slide 8

Slide 8 text

Zadej funkci: x * 5 x = 0, y = 0 x = 1, y = 5 x = 2, y = 10 x = 3, y = 15 x = 4, y = 20 Zadej funkci: math.sin(x) x = 0, y = 0.0 x = 1, y = 0.841470984808 x = 2, y = 0.909297426826 x = 3, y = 0.14112000806 x = 4, y = -0.756802495308 Zadej funkci: x ** 999999 x = 0, y = 0 x = 1, y = 1 Zadej funkci: open('/etc/passwd').read() x = 0, y = root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin Zadej funkci: os.system('fire-mah-lazors --target=alderaan')

Slide 9

Slide 9 text

Jak se bránit?

Slide 10

Slide 10 text

$ pydoc eval eval(source[, globals[, locals]]) The globals must be a dictionary and locals can be any mapping, defaulting to the current globals and locals. If only globals is given, locals defaults to it.

Slide 11

Slide 11 text

>>> import math >>> eval ( "math . sin ( 3 . 1 4 1 ) " ) 0.0005926535550994539

Slide 12

Slide 12 text

>>> import math >>> eval ( "math . sin ( 3 . 1 4 1 ) " ) 0.0005926535550994539 >>> eval ( "math . sin ( 3 . 1 4 1 ) " , { } ) Traceback ( most recent c a l l l a s t ) : . . . NameError : name 'math' is not defined

Slide 13

Slide 13 text

>>> import math >>> import os >>> eval ( "math . sin ( 3 . 1 4 1 ) " , dict ( math=math) ) 0.0005926535550994539

Slide 14

Slide 14 text

>>> import math >>> import os >>> eval ( "math . sin ( 3 . 1 4 1 ) " , dict ( math=math) ) 0.0005926535550994539 >>> eval ( " os . system ( ' echo pwned ' ) " , dict (math=math) ) Traceback ( most recent c a l l l a s t ) : . . . NameError : name 'os' is not defined

Slide 15

Slide 15 text

Už je to bezpečné?

Slide 16

Slide 16 text

>>> import math >>> import os >>> eval ( " dir ( ) " ) [ ' __builtins__ ' , '__doc__ ' , '__name__ ' , ' __package__ ' , 'math ' , ' os ' ]

Slide 17

Slide 17 text

>>> import math >>> import os >>> eval ( " dir ( ) " ) [ ' __builtins__ ' , '__doc__ ' , '__name__ ' , ' __package__ ' , 'math ' , ' os ' ] >>> eval ( " dir ( ) " , dict (math=math) ) [ ' __builtins__ ' , 'math ' ]

Slide 18

Slide 18 text

>>> dir ( __builtins__ ) [ . . . , ' abs ' , ' a l l ' , ' any ' , ' apply ' , ' basestring ' , ' bin ' , ' bool ' , ' buffer ' , ' bytearray ' , ' bytes ' , ' callable ' , ' chr ' , 'cmp ' , . . . , ' vars ' , ' xrange ' , ' zip ' ]

Slide 19

Slide 19 text

>>> dir ( __builtins__ ) [ . . . , ' abs ' , ' a l l ' , ' any ' , ' apply ' , ' basestring ' , ' bin ' , ' bool ' , ' buffer ' , ' bytearray ' , ' bytes ' , ' callable ' , ' chr ' , 'cmp ' , . . . , ' vars ' , ' xrange ' , ' zip ' ] >>> eval ( ' ' ' open ( ' / etc / passwd ' ) . read ( ) ' ' ' , { } ) 'root:x:0:0:root:/root:/bin/bash\n ...

Slide 20

Slide 20 text

>>> eval ( "open ( ' / etc / passwd ' ) . read ( ) " , dict ( __builtins__ = { } ) ) Traceback ( most recent c a l l l a s t ) : . . . NameError : name 'open' is not defined

Slide 21

Slide 21 text

>>> eval ( "open ( ' / etc / passwd ' ) . read ( ) " , dict ( __builtins__ = { } ) ) Traceback ( most recent c a l l l a s t ) : . . . NameError : name 'open' is not defined >>> eval ( " abs(−5) " , dict ( __builtins__ = { } , abs=abs ) ) 5

Slide 22

Slide 22 text

Už je to bezpečné!?

Slide 23

Slide 23 text

eval() vyhodnotí jakýkoli výraz

Slide 24

Slide 24 text

Co není výraz? def f ( x ) : return 3 + x

Slide 25

Slide 25 text

Co není výraz? def f ( x ) : return 3 + x for x in range (10) : print x

Slide 26

Slide 26 text

Co není výraz? def f ( x ) : return 3 + x for x in range (10) : print x x = 3

Slide 27

Slide 27 text

Co není výraz? def f ( x ) : return 3 + x for x in range (10) : print x x = 3 import os a další příkazy: http://docs.python.org/reference/index.html

Slide 28

Slide 28 text

Jak to obejít?

Slide 29

Slide 29 text

def f ( x ) : return 3 + x

Slide 30

Slide 30 text

def f ( x ) : return 3 + x f = ( lambda x : 3 + x ) !

Slide 31

Slide 31 text

x = 3 * 8 foobar ( x )

Slide 32

Slide 32 text

x = 3 * 8 foobar ( x ) ( lambda x=3 ** 8: foobar ( x ) ) ( )

Slide 33

Slide 33 text

for x in range (10) : print x

Slide 34

Slide 34 text

for x in range (10) : print x [ sys . stdout . write ( '%s \ n ' % x ) for x in range (10) ]

Slide 35

Slide 35 text

def f ( x ) : return 3 + x for i in range (10) : print f ( i )

Slide 36

Slide 36 text

def f ( x ) : return 3 + x for i in range (10) : print f ( i ) ( lambda f =( lambda x : 3 + x ) , out=sys . stdout . write : [ out ( '%s \ n ' % f ( x ) ) for x in range (10) ] ) ( ) !

Slide 37

Slide 37 text

class T( object ) : def __init__ ( self , p) : s e l f . p = p

Slide 38

Slide 38 text

class T( object ) : def __init__ ( self , p) : s e l f . p = p T = type ( "T" , ( object , ) , { ' __init__ ' : lambda self , p : setattr ( self , 'p ' , p) } )

Slide 39

Slide 39 text

import os os . system ( " echo pwned" )

Slide 40

Slide 40 text

import os os . system ( " echo pwned" ) __import__ ( ' os ' ) . system ( " echo pwned" ) !

Slide 41

Slide 41 text

import os os . system ( " echo pwned" ) ( lambda os=__import__ ( ' os ' ) : os . system ( " echo pwned" ) ) ( )

Slide 42

Slide 42 text

Téměř jakýkoli program se dá převést na jediný výraz

Slide 43

Slide 43 text

Téměř jakýkoli program se dá převést na jediný výraz eval() vyhodnotí jakýkoli výraz

Slide 44

Slide 44 text

Téměř jakýkoli program se dá převést na jediný výraz eval() vyhodnotí jakýkoli výraz Ještě tak mít ten __import__...

Slide 45

Slide 45 text

>>> (42) . bit_length ( ) 6

Slide 46

Slide 46 text

>>> (42) . bit_length ( ) 6 >>> dir (42) [ . . . , '__add__ ' , ' __class__ ' , '__doc__ ' , ' __hash__ ' , ' __str__ ' , ' bit_length ' , . . . ]

Slide 47

Slide 47 text

>>> (42) . bit_length ( ) 6 >>> dir (42) [ . . . , '__add__ ' , ' __class__ ' , '__doc__ ' , ' __hash__ ' , ' __str__ ' , ' bit_length ' , . . . ] >>> (42) . __class__

Slide 48

Slide 48 text

>>> (42) . __class__ . mro ( ) [ < type ' int ' > , ]

Slide 49

Slide 49 text

>>> (42) . __class__ . mro ( ) [ < type ' int ' > , ] >>> ' 42 ' . __class__ . mro ( ) [ < type ' str ' > , , ]

Slide 50

Slide 50 text

>>> (42) . __class__ . mro ( ) [ < type ' int ' > , ] >>> ' 42 ' . __class__ . mro ( ) [ < type ' str ' > , , ] >>> (42) . __class__ . mro ( ) [ −1]

Slide 51

Slide 51 text

>>> (42) . __class__ . mro ( ) [ −1]

Slide 52

Slide 52 text

>>> (42) . __class__ . mro ( ) [ −1] >>> ( ( 4 2 ) . __class__ . mro ( ) [ −1]. __subclasses__ ( ) ) [, , ..., , , ..., , , ..., , , ..., , ..., , ..., , ...]

Slide 53

Slide 53 text

>>> [ c for c in ( ( 4 2 ) . __class__ . mro ( ) [ −1]. __subclasses__ ( ) ) i f c . __name__ == ' f i l e ' ] [ 0 ]

Slide 54

Slide 54 text

>>> [ c for c in (42) . __class__ . mro ( ) [ −1]. __subclasses__ ( ) i f c . __name__ == ' f i l e ' ] [ 0 ] ( ' / etc / passwd ' ) . read ( ) 'root:x:0:0:root:/root:/bin/bash\n . . .

Slide 55

Slide 55 text

( lambda fc =( lambda n : [ c for c in ( ) . __class__ . __bases__ [ 0 ] . __subclasses__ ( ) i f c . __name__ == n ] [ 0 ] ) : fc ( " function " ) ( fc ( " code " ) ( 0 ,0 ,0 ,0 , "KABOOM" , ( ) , ( ) , ( ) , " " , " " ,0 , " " ) , { } ) ( ) ) ( )

Slide 56

Slide 56 text

Ale eval()ovaný kód se dá předem vyčistit!!!!

Slide 57

Slide 57 text

Ale eval()ovaný kód se dá předem vyčistit!!!! Znáte problémy s os.system? SQL injection? XSS?

Slide 58

Slide 58 text

Ale eval()ovaný kód se dá předem vyčistit!!!! Znáte problémy s os.system? SQL injection? XSS? Znáte moduly rexec a bastion?

Slide 59

Slide 59 text

Ale eval()ovaný kód se dá předem vyčistit!!!! Znáte problémy s os.system? SQL injection? XSS? Znáte moduly rexec a bastion? ... nedá!!!!

Slide 60

Slide 60 text

Co místo evalu?

Slide 61

Slide 61 text

Věřím svým uživatelům! Opravdový modul

Slide 62

Slide 62 text

Věřím svým uživatelům! Opravdový modul Dělám kalkulačku! pyparsing, PLY

Slide 63

Slide 63 text

Věřím svým uživatelům! Opravdový modul Dělám kalkulačku! pyparsing, PLY Chci načíst dict/list! ast.literal_eval

Slide 64

Slide 64 text

Věřím svým uživatelům! Opravdový modul Dělám kalkulačku! pyparsing, PLY Chci načíst dict/list! ast.literal_eval Čtu/píšu data/koniguraci! YAML, JSON, ConfigParser

Slide 65

Slide 65 text

Věřím svým uživatelům! Opravdový modul Dělám kalkulačku! pyparsing, PLY Chci načíst dict/list! ast.literal_eval Čtu/píšu data/koniguraci! YAML, JSON, ConfigParser Dělám překladač/REPL! compile & exec()

Slide 66

Slide 66 text

Pozor na to, že eval se zákeřně schovává ve funkci input! input(x) ⇔ eval(raw_input(x))

Slide 67

Slide 67 text

? Petr Viktorin @encukou encukou@gmail.com Slajdy jsou pod licencí Creative Commons Attribution-ShareAlike 3.0 http://creativecommons.org/licenses/by-sa/3.0/

Slide 68

Slide 68 text

Zdroje (pozor, většinou zastaralé) http://nedbatchelder.com/blog/201206/eval_really_is_ dangerous.html http://lybniz2.sourceforge.net/safeeval.html http://effbot.org/zone/librarybook-core-eval.htm