Shiny, Let's Be Bad Guys: Exploiting and Mitigating the Top 10 Web App Vulnerabilities -- OSCON 2016 edition

Shiny, Let's Be Bad Guys: Exploiting and Mitigating the Top 10 Web App Vulnerabilities -- OSCON 2016 edition

Slides from the OSCON 2016 presentation of our tutorial that walks through the OWASP Top 10 web application vulnerabilities.

E4c5e3c69566ff80db62a4ab521b6e5a?s=128

Mike Pirnat

May 16, 2016
Tweet

Transcript

  1. 1.

    Shiny Let’s Be Bad Guys! Exploiting and Mitigating the Top

    1 0 Web App Vulnerabilities Mike Pirnat - @mpirnat OSCON 2016 Setup: https://github.com/mpirnat/lets-be-bad-guys
  2. 2.

    Schedule • This session will run 1:30 PM – 5:00

    PM • 30-minute break 3:00 – 3:30 PM • Here on Level 4
  3. 3.

    Shiny Let’s Be Bad Guys! Exploiting and Mitigating the Top

    1 0 Web App Vulnerabilities Mike Pirnat - @mpirnat OSCON 2016
  4. 7.

    OWASP • http://www.owasp.org • Open Web Application Security Project •

    Non-profit focused on improving software security • Documentation and tools to help learn about security and protect your apps
  5. 8.

    OWASP Top Ten • Based on risk data from 8

    firms • Over 500,000 vulnerabilities, hundreds of orgs, thousands of apps • Selected & prioritized by prevalence data combined with estimates of exploitability, detectability, and impact • Updated in 2013
  6. 9.

    Today • Background on a type of vulnerability • Exploit

    it! • Discuss prevention • Django & Flask specific advice where possible • Light examples where we have time
  7. 13.

    Setup: 1 Make & activate a virtualenv: # Python 3...

    $ pyvenv badguys # Python 2... $ virtualenv badguys $ cd badguys $ source bin/activate
  8. 14.
  9. 18.
  10. 19.

    Injection Attacks • When an application sends untrusted data to

    an interpreter • Can result in data loss/corruption, lack of accountability, denial of access • Can lead to complete host takeover
  11. 22.

    Attack Vectors • GET parameters • POST parameters • PATH_INFO

    • Some HTTP headers: Cookie, Host • Uploaded Files
  12. 23.

    Possible Consequences • Creation of malicious SQL (or other queries)

    • Accessing private files on disk • Arbitrary code execution
  13. 24.

    Real-World Examples • Sony Playstation Network • Ruby on Rails

    • HBGary • MySQL • Many, many others…
  14. 25.

    SQL Injection • Unescaped user input causes the premature end

    of a SQL query and allows a malicious query to be executed... """ select * from users where username='%s'; """ • http://localhost:8000/injection/sql
  15. 26.

    Accessing Private Files • File system access + unvalidated user

    input allows attackers to navigate the file system • http://localhost:8000/injection/file- access
  16. 27.

    Arbitrary Code Execution • Unsafe input is dynamically evaluated or

    executed • http://localhost:8000/injection/code- execution
  17. 28.

    Prevention • Validate ALL user input • Sign cookies, don’t

    accept if signature is bogus/missing • Use ORMs or bind variables when talking to the database • Don’t use eval or exec, beware of pickle, user-supplied YAML, etc.
  18. 29.

    Django Advice • Make sure data types for your model

    are tight • Use Forms instead of ModelForms for stronger validation • Make new validators as needed for your application • Make sure your URL regexes for dynamic URLs are tight
  19. 30.

    Django Advice • Use the ORM when you can •

    When you can’t, use extreme caution! • Use bind variables/parameters • No string concatenation/formatting of anything that came from the client
  20. 31.

    Without the ORM # If it's a basic select: MyModel.objects.raw("SELECT

    ... WHERE foo = %s", params={'foo': ...}) # If it's more complicated: from django.db import connection cursor = connection.cursor() cursor.execute("UPDATE bar set bar = 1 WHERE foo < %s",  [foo]) row = cursor.fetchall()
  21. 32.

    Flask Advice • Use Flask-WTF to validate form input •

    Use SQLAlchemy • Bind variables if you don’t
  22. 34.

    Broken Auth & Session Management • Attacker uses leaks or

    flaws in authentication or session management to impersonate users • Roll-your-own solutions contribute to the difficulty of finding these flaws
  23. 36.

    Prevention • Hash or encrypt passwords • Don’t let credentials

    be easily overwritten • Don’t put session IDs in URLs • Allow session IDs to timeout/log out • Rotate session IDs after successful login • TLS connections for passwords, session IDs
  24. 37.

    Django Advice • Use django.contrib.auth • Consider https://github.com/yourlabs/ django-session-security middleware

    for timing out sessions • We’ll talk about transport layer security later on...
  25. 40.

    XSS Attacks • Cross-Site Scripting (XSS) • The most prevalent

    web app security flaw • App includes user-supplied data in content sent to the browser without properly validating or sanitizing it
  26. 41.

    XSS Attacks • Stored: injected code permanently stored in database,

    message forum, comment, etc. • Reflected: injected code in live request to server, reflected back in error message or search result • DOM: injected code in browser DOM environment that causes scripts to run in unexpected ways (eg, reading from URL)
  27. 42.

    Possible Consequences • Execute scripts in a victim’s browser •

    Hijack sessions • Deface sites • Insert hostile content • Redirect users • Hijack browser (install malware)
  28. 43.

    Most Often Seen... • Places where user-created text is displayed

    to other users (comments, messages) • Form inputs where value is populated with user-supplied data • Script tags where user-supplied data is populated into script variables
  29. 45.

    XSS in Dynamic URLs • Part of the URL path

    is variable, isn’t validated, and gets included into the page: http://example.com/stuff/{$CATEGORY} • http://localhost:8000/cross-site- scripting/path-matching/your-path- here
  30. 46.

    XSS in Query String Parameters • Unvalidated user input from

    a query string parameter is included in the page: http://example.com/?search={$TEXT} • http://localhost:8000/cross-site- scripting/query-params?qs=awesome
  31. 47.

    XSS in Form Fields • The value part of an

    input is prematurely terminated, allowing Javascript to be injected into or adjacent to the element: <input … value="{$TEXT}"> • http://localhost:8000/cross-site- scripting/form-field
  32. 49.

    Prevention • Escape all untrusted data based on the HTML

    context the data will be placed into • Whitelist input validation • Consider auto-sanitization libraries for rich content (eg, OWASP’s AntiSamy) • Update your parents’/in-laws’ browsers!
  33. 50.

    Django Advice • Be careful with the safe filter, django.utils.safestring,

    etc. • Use form.as_p, form.as_table, form.as_ul when displaying a form in a template • Be careful with your own template tags; django.utils.html.escape is your friend!
  34. 52.

    Flask Advice • Don’t disable autoescaping • Be very careful

    with anything you bless via Markup objects, the safe filter, or blocks where autoescape is disabled
  35. 54.

    Insecure Direct Object Reference • Expose a reference to an

    internal implementation object without verifying authorization • Attacker changes URL, GET/POST parameters, cookies
  36. 55.

    Possible Consequences • Compromise of all data that can be

    referenced by the vulnerable parameter • Unless the namespace is sparse, an attacker can easily access all available data of that type
  37. 56.

    Exercises • Manipulate parameters in the URL to access data

    that doesn’t belong to you • http://localhost:8000/direct-object- references
  38. 57.

    Prevention • Implement access controls on any direct references to

    restricted resources • Implement per-user or per-session indirect object references • This can be as much about URL design as about access control!
  39. 58.

    Django + Flask • Lock down views: • Use Django’s

    permissions architecture • Use Flask-Security or Flask-Login • Customize Django queryset for looking up objects that involve user ownership
  40. 59.

    Custom Queryset # In models.py... class ThingyManager(models.Manager): def for_user(self, user):

    return self.get_query_set().filter(user=user) class Thingy(models.Model): objects = ThingyManager() # In views.py... class ThingyUpdateView(UpdateView): def get_queryset(self): return Thingy.objects.for_user( self.request.user)
  41. 62.

    Possible Consequences • Unauthorized access to some system data or

    functionality • Potential complete system compromise
  42. 64.

    Text This Really Happens! • Patreon compromised via exposed Werkzeug

    Debugger • https://labs.detectify.com/2015/10/02/ how-patreon-got-hacked-publicly- exposed-werkzeug-debugger/
  43. 65.
  44. 66.
  45. 67.
  46. 68.

    Prevention • Have a repeatable hardening process • Have a

    process for keeping on top of updates and patches • Architecture that provides secure separation between components • Periodic scans and audits
  47. 69.

    Django Advice • Don’t run in debug mode in production

    • Keep your SECRET_KEY secret! • Keep Python code out of webserver’s root • Don’t run admin publicly • Don’t use the built-in admin for normal user admin tasks
  48. 73.

    Sensitive Data Exposure • Failure to properly protect credit cards,

    tax IDs, authentication credentials, etc. • Sensitive data deserves extra protection such as encryption at rest or in transit, special precautions when exchanged with the browser
  49. 74.

    Insecure Cryptographic Storage • Not encrypting worthy data • Unsafe

    key generation & storage, failure to rotate keys • Weak algorithms • Weak or unsalted hashes
  50. 75.

    Insufficient Transport Layer Protection • May not authenticate, encrypt, and

    protect the confidentiality and integrity of sensitive network traffic • May use weak algorithms • May use expired or invalid certificates • May use certificates incorrectly
  51. 76.

    Possible Consequences • Compromise of all data that should have

    been encrypted • This can be highly sensitive information: credentials, credit cards, personal data, health records, etc.
  52. 77.

    Possible Consequences • Expose individual users’ data • Account theft

    • Compromise an admin account?! • Poor SSL setup can facilitate phishing and man-in-the-middle attacks
  53. 78.

    Attack Vectors • Attacker monitors network traffic of your users

    • Maybe in public places (Starbucks, conference wi-fi, etc.) • Maybe back end connections • Maybe inside your network (!!!)
  54. 81.

    Prevention • Encrypt sensitive data at rest • Encrypt offsite

    backups; manage keys separately • Use strong standard algorithms, strong keys • Hash passwords with strong standard algorithm & use appropriate salt • Protect passwords & keys from unauthorized access
  55. 82.

    Prevention • Require SSL for all sensitive pages; redirect non-SSL

    requests to SSL • Set the “secure” flag on sensitive cookies • Use only strong SSL algorithms • Ensure your cert is valid, not expired, not revoked, and matches your domain • SSL/encryption on the back end too
  56. 83.

    Django Advice • Use django.contrib.auth for proper password salting and

    hashing • Use bcrypt; see https://docs.djangoproject.com/en/ 1.8/topics/auth/passwords/ • Require SSL in Apache or Nginx • Require SSL using middleware: • Configure Django SecurityMiddleware–new in Django 1.8! • http://django-secure.readthedocs.org/en/v0.1.2/ • https://github.com/rdegges/django-sslify
  57. 85.

    Flask Advice • Salt passwords using werkzeug.security: • http://flask.pocoo.org/snippets/54/ •

    Require SSL: • https://github.com/kennethreitz/flask-sslify • https://github.com/jacobian/wsgi-sslify • Use bcrypt: https://pythonhosted.org/ passlib/
  58. 87.

    Missing Function Level Access Control • Application doesn’t protect its

    functions properly • Misconfiguration • Forgot proper code checks
  59. 88.

    Attack Vectors • Authorized user changes a URL or parameter

    to a privileged function • Anonymous users could access private functions that aren’t protected
  60. 90.

    Exercises • Manipulate the URL to access privileged functionality •

    http://localhost:8000/missing-access- control
  61. 91.

    Prevention • Consider every page; public or private? • If

    authentication is required, make sure that checks are in place • If additional authorization is required, make sure that checks are in place • Deny all by default; explicitly grant access to users or roles
  62. 92.

    Django + Flask • Lock down views: • Use Django’s

    permissions architecture • Use Flask-Security or Flask-Login • Don’t use Django’s built-in admin for normal user admin tasks
  63. 94.

    CSRF Attacks • Cross-Site Request Forgery (CSRF) • Attacker tricks

    victim into submitting forged HTTP requests • Attack succeeds if user is authorized/ authenticated
  64. 95.

    Attack Vectors • Image tags • Cross-Site Scripting (XSS) •

    Fake buttons • Phishing forms • Other techniques
  65. 96.

    Possible Consequences • Cause victim to change any data the

    victim is allowed to change • Cause victim to perform any function the victim is authorized to use • Impact varies based on victim’s role • Think of some possibilities...
  66. 100.

    CSRF via Image • Craft an “image” link that triggers

    some site functionality • http://localhost:8000/csrf/image
  67. 101.

    CSRF via Form Post • Create an innocuous-looking form that

    POSTs to a vulnerable location • http://localhost:8000/csrf/third-party- site
  68. 102.

    Prevention • Don’t “do” things on a GET • Include

    a unique token in a hidden field (often used in concert with a cookie) • Validate token to make sure the request is from on-site • Avoid putting the token into a query string
  69. 103.

    Django Advice • Don’t change the built-in settings! • Do

    use the CSRF middleware and template tag in forms • Be VERY CAREFUL about deactivating it (csrf_exempt decorator) • Be careful about APIs (Tastypie, oauth); http://codrspace.com/vote539/csrf- protection-in-django-tastypie/
  70. 104.

    Flask Advice Various CSRF solutions... • DIY/naïve: http://flask.pocoo.org/snippets/3/ • Flask-WTF:

    http://flask-wtf.readthedocs.org/ en/latest/csrf.html • Flask-SeaSurf: https://flask- seasurf.readthedocs.org/en/latest/ • Flask-csrf: http://sjl.bitbucket.org/flask-csrf/
  71. 106.

    Components  with Known Vulnerabilities • Libraries, frameworks, and other

    modules almost always run with full privilege • Hard to stay up to date on everything • Do you even know all the components in use, let alone their versions? • Components with known problems can be identified & exploited with automated tools
  72. 107.

    Attack Vectors • Attacker identifies a weak component through scanning

    or manual analysis • Customize exploit as needed • More difficult the deeper the component is in the application
  73. 108.

    Possible Consequences • Full range of weaknesses are possible •

    Impact could be minimal, or... • Complete host takeover! • Data compromise!
  74. 109.
  75. 110.
  76. 111.
  77. 112.
  78. 113.
  79. 114.

    Prevention • Don’t use components you don’t write (unrealistic) •

    Keep components up to date • Identify all components and versions • Monitor security of these components
  80. 115.

    Python Advice • Use pip to find old packages: pip

    list --outdated • Use requires.io to monitor dependencies
  81. 116.

    Django + Flask • Keep an eye on the mailing

    lists: • https://groups.google.com/group/django- announce • http://flask.pocoo.org/mailinglist • Follow @djangoproject on Twitter
  82. 118.

    Redirection Abuse • Attacker tricks user into visiting a URL

    that redirects or forwards the request without validating the redirect location • Users prone to click because the link is to a legitimate site
  83. 120.

    External Redirection • Use a redirection URL to redirect to

    an external location • http://localhost:8000/redirects-and- forwards/redirects
  84. 121.

    Forwards • Manipulate a forward parameter to gain access to

    privileged functionality • http://localhost:8000/redirects-and- forwards/forwards
  85. 122.

    Prevention • Don’t use redirects or forwards • Don’t involve

    user-supplied data to build the redirect location • Ensure the supplied value is valid and authorized for the user
  86. 123.

    Django Advice • Use django.utils.http.is_safe_url to check redirect URLs •

    Used by django.contrib.auth internally • Consider wrapping is_safe_url if you have to allow other off-domain URLs
  87. 124.

    Checking Redirects from django.shortcuts import redirect from django.utils.http import is_safe_url

    def my_view(request): ... url = 'http://www.example.com/foo/bar' if is_safe_url(url, host='www.example.com'): return redirect(url) else: ...
  88. 125.

    Allowing Multiple Safe Hosts from django.utils.http import is_safe_url def is_whitelisted_url(url,

    hosts): for host in hosts: if is_safe_url(url, host=host): return True return False >>> url = 'http://us.pycon.org' >>> whitelist = ['us.pycon.org', 'pycon.org', ...] >>> is_whitelisted_url(url, whitelist) True
  89. 126.

    Flask Advice • Redirect back: http://flask.pocoo.org/ snippets/62/ • Redirect back,

    more selectively with whitelist, using cookies for previous URL: http://flask.pocoo.org/snippets/120/ • Can modify these approaches to suit, as with the Django example