Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Zákeřný eval()

Petr Viktorin
September 27, 2012

Zákeřný eval()

Zrádnosti funkce eval(), a co použít místo ní. Přednáška pro zářijové PyVo 2012.

Petr Viktorin

September 27, 2012
Tweet

More Decks by Petr Viktorin

Other Decks in Programming

Transcript

  1. $ 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().
  2. import os import math f = raw_input ( " Zadej

    funkci : " ) for x in range ( 5 ) : print " x = %s , y = %s " % ( x , eval ( f ) )
  3. Zadej funkci: x * 5 x = 0, y =

    0 x = 1, y = 5 x = 2, y = 10 x = 3, y = 15 x = 4, y = 20
  4. 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
  5. 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
  6. 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
  7. 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')
  8. $ 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.
  9. >>> import math >>> eval ( "math . sin (

    3 . 1 4 1 ) " ) 0.0005926535550994539
  10. >>> 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
  11. >>> import math >>> import os >>> eval ( "math

    . sin ( 3 . 1 4 1 ) " , dict ( math=math) ) 0.0005926535550994539
  12. >>> 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
  13. >>> import math >>> import os >>> eval ( "

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

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

    ' abs ' , ' a l l ' , ' any ' , ' apply ' , ' basestring ' , ' bin ' , ' bool ' , ' buffer ' , ' bytearray ' , ' bytes ' , ' callable ' , ' chr ' , 'cmp ' , . . . , ' vars ' , ' xrange ' , ' zip ' ]
  16. >>> 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 ...
  17. >>> eval ( "open ( ' / etc / passwd

    ' ) . read ( ) " , dict ( __builtins__ = { } ) ) Traceback ( most recent c a l l l a s t ) : . . . NameError : name 'open' is not defined
  18. >>> 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
  19. Co není výraz? def f ( x ) : return

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

    3 + x for x in range (10) : print x x = 3
  21. 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
  22. def f ( x ) : return 3 + x

    f = ( lambda x : 3 + x ) !
  23. x = 3 * 8 foobar ( x ) (

    lambda x=3 ** 8: foobar ( x ) ) ( )
  24. for x in range (10) : print x [ sys

    . stdout . write ( '%s \ n ' % x ) for x in range (10) ]
  25. def f ( x ) : return 3 + x

    for i in range (10) : print f ( i )
  26. 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) ] ) ( ) !
  27. 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) } )
  28. import os os . system ( " echo pwned" )

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

    ( lambda os=__import__ ( ' os ' ) : os . system ( " echo pwned" ) ) ( )
  30. 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__...
  31. >>> (42) . bit_length ( ) 6 >>> dir (42)

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

    [ . . . , '__add__ ' , ' __class__ ' , '__doc__ ' , ' __hash__ ' , ' __str__ ' , ' bit_length ' , . . . ] >>> (42) . __class__ <type ' int ' >
  33. >>> (42) . __class__ . mro ( ) [ <

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

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

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

    <type 'object'> >>> ( ( 4 2 ) . __class__ . mro ( ) [ −1]. __subclasses__ ( ) ) [<type 'type'>, <type 'weakref'>, ..., <type 'int'>, <type 'basestring'>, ..., <type 'super'>, <type 'xrange'>, ..., <type 'function'>, <type 'classobj'>, ..., <type 'sys.version_info'>, ..., <class 'warnings.catch_warnings'>, ..., <class 'codecs.IncrementalEncoder'>, ...]
  37. >>> [ c for c in ( ( 4 2

    ) . __class__ . mro ( ) [ −1]. __subclasses__ ( ) ) i f c . __name__ == ' f i l e ' ] [ 0 ] <type 'file'>
  38. >>> [ 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 . . .
  39. ( 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 , " " ) , { } ) ( ) ) ( )
  40. 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?
  41. 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á!!!!
  42. 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
  43. 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()
  44. Pozor na to, že eval se zákeřně schovává ve funkci

    input! input(x) ⇔ eval(raw_input(x))
  45. ? Petr Viktorin @encukou [email protected] Slajdy jsou pod licencí Creative

    Commons Attribution-ShareAlike 3.0 http://creativecommons.org/licenses/by-sa/3.0/