• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
festival ICT 2013: Solid as diamond: use ruby in an web application penetration test
 

festival ICT 2013: Solid as diamond: use ruby in an web application penetration test

on

  • 1,853 views

 

Statistics

Views

Total Views
1,853
Views on SlideShare
1,846
Embed Views
7

Actions

Likes
0
Downloads
10
Comments
0

2 Embeds 7

http://www.linkedin.com 5
https://twitter.com 2

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    festival ICT 2013: Solid as diamond: use ruby in an web application penetration test festival ICT 2013: Solid as diamond: use ruby in an web application penetration test Presentation Transcript

    • Solid as Diamond Using Ruby in a web application penetration test Wednesday, September 18, 13
    • self.inspect • I do stuff: husband, proud father && martial artist • I break other people code for living (only when authorized) • I blog at: http://armoredcode.com • I’m on github too: https:// github.com/thesp0nge • I love twitter: @thesp0nge, @armoredcode 2 Wednesday, September 18, 13
    • talk.inspect • Owasp Top 10 2013 • Ruby code to... • Leverage a web application attack surface • Bruteforce authentication mechanism • Look for Cross site scripting 3 Wednesday, September 18, 13
    • Disclaimer 4 Attack only sites you’re authorized to Wednesday, September 18, 13
    • Change your mindset. You’re an attacker now! 5 Your web application is a blackbox You’ve got only a URL as a starting point (optional) You may have a valid user, instead you have to register a user to the application Good luck! Wednesday, September 18, 13
    • It all starts with... 6 ... someone wants to publish a new web application on the Internet or on an Internal network, she gives me the url saying: “test it for security issues, please”... Wednesday, September 18, 13
    • Our target 7 Wednesday, September 18, 13
    • The Owasp Top 10 - 2013 8 • A1 – Injection • A2 – Broken Authentication and Session Management • A3 – Cross-Site Scripting (XSS) • A4 – Insecure Direct Object References • A5 – Security Misconfiguration • A6 – Sensitive Data Exposure • A7 – Missing Function Level Access Control • A8 – Cross-Site Request Forgery (CSRF) • A9 – Using Known Vulnerable Components • A10 – Unvalidated Redirects and Forwards https://www.owasp.org/index.php/Top_10_2013 Wednesday, September 18, 13
    • Leverage your attack surface 9 Wednesday, September 18, 13
    • Leverage your attack surface 10 Spot attack entrypoints: (robots.txt and url discovery with bruteforce) Fingerprint your target Check transport layer security Check for the service door (backup files) Wednesday, September 18, 13
    • Fingerprint your target 11 • Meta generator tag • Server HTTP response field • X-Powered-by HTTP response field • Popular pages with extension (login.do, index.jsp, main.asp, login.php, phpinfo.php...) • The HTTP response field order (soon it will be implemented in the gengiscan gem) Wednesday, September 18, 13
    • Fingerprint your target 12 def detect(url) uri = URI(url) begin res = Net::HTTP.get_response(uri) {:status=>:OK, :code=>res.code, :server=>res['Server'], :powered=>res['X-Powered-By'], :generator=>get_generator_signature(res)} rescue {:status=>:KO, :code=>nil, :server=>nil, :powered=>nil, :generator=>nil} end end def get_generator_signature(res) generator = "" doc=Nokogiri::HTML(res.body) doc.xpath("//meta[@name='generator']/@content").each do |value| generator = value.value end generator end $ gem install gengiscan $ gengiscan http://localhost:4567 {:status=>:OK, :code=>"404", :server=>"WEBrick/1.3.1 (Ruby/ 1.9.3/2012-04-20)", :powered=>nil, :generator=>""} Wednesday, September 18, 13
    • Spot attack entrypoints 13 robots.txt to discover to fingerprint Wednesday, September 18, 13
    • Spot attack entrypoints 14 # TESTING: SPIDERS, ROBOTS, AND CRAWLERS (OWASP-IG-001) def self.robots(site) site = 'http://'+site unless site.start_with? 'http://' or site.start_with? 'https://' allow_list = [] disallow_list = [] begin res=Net::HTTP.get_response(URI(site+'/robots.txt')) return {:status=>:KO, :allow_list=>[], :disallow_list=>[], :error=>"robots.txt response code was #{res.code}"} if (res.code != "200") res.body.split("n").each do |line| disallow_list << line.split(":")[1].strip.chomp if (line.downcase.start_with?('disallow')) allow_list << line.split(":")[1].strip.chomp if (line.downcase.start_with?('allow')) end rescue Exception => e return {:status=>:KO, :allow_list=>[], :disallow_list=>[], :error=>e.message} end {:status=>:OK, :allow_list=>allow_list, :disallow_list=>disallow_list, :error=>""} end $ gem install codesake_links $ links -r http://localhost:4567 Wednesday, September 18, 13
    • Spot attack entrypoints 15 • Use a dictionary to discover URLs with bruteforce • Very intrusive attack... you’ll be busted, be aware $ gem install codesake_links $ links -b test_case_dir_wordlist.txt http://localhost:4567 Wednesday, September 18, 13
    • Check transport layer security 16 $ gem install ciphersurfer $ ciphersurfer www.gmail.com Evaluating secure communication with www.gmail.com:443 Overall evaluation : B (76.5) Protocol support : ooooooooooooooooooooooooooooooooooooooooooooooooooooooo (55) Key exchange : oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo (80) Cipher strength : oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo (90) Evaluate an SSL connection for: • protocols the server supports • cipher length • certificate key length Wednesday, September 18, 13
    • Check transport layer security 17 def go context=OpenSSL::SSL::SSLContext.new(@proto) cipher_set = context.ciphers cipher_set.each do |cipher_name, cipher_version, bits, algorithm_bits| request = Net::HTTP.new(@host, @port) request.use_ssl = true request.verify_mode = OpenSSL::SSL::VERIFY_NONE request.ciphers= cipher_name begin response = request.get("/") @ok_bits << bits @ok_ciphers << cipher_name rescue OpenSSL::SSL::SSLError => e # Quietly discard SSLErrors, really I don't care if the cipher has # not been accepted rescue # Quietly discard all other errors... you must perform all error # chekcs in the calling program end end end protocol_version.each do |version| s = Ciphersurfer::Scanner.new({:host=>host, :port=>port, :proto=>version}) s.go if (s.ok_ciphers.size != 0) supported_protocols << version cipher_bits = cipher_bits | s.ok_bits ciphers = ciphers | s.ok_ciphers end end Wednesday, September 18, 13
    • Check for the service door 18 require 'anemone' require 'httpclient' h=HTTPClient.new() Anemone.crawl(ARGV[0]) do |anemone| anemone.on_every_page do |page| response = h.get(page.url) puts "Original: #{page.url}: #{response.code}" response = h.get(page.url.to_s.split(";")[0].concat(".bak")) puts "BAK: #{page.url.to_s.split(";")[0].concat(".bak")}: #{response.code}" response = h.get(page.url.to_s.split(";")[0].concat(".old")) puts "OLD: #{page.url.to_s.split(";")[0].concat(".old")}: #{response.code}" response = h.get(page.url.to_s.split(";")[0].concat("~")) puts "~: #{page.url.to_s.split(";")[0].concat("~")}: #{response.code}" end end Wednesday, September 18, 13
    • Demo 19 Wednesday, September 18, 13
    • Bruteforce authentication mechanism 20 Wednesday, September 18, 13
    • Am I vulnerable? 21 Wednesday, September 18, 13
    • Am I vulnerable? 22 Wednesday, September 18, 13
    • How do I break this? 23 1. Use an existing user to check the HTML <p> Wrong password for admin user </p> 2. Place a canary string to anonymize the output <p> Wrong password for canary_username user </p> 3. Submit the post and check if the response is the one expected with the canary substituted <p> Wrong password for tom user </p> Wednesday, September 18, 13
    • How do I break this? 24 def post(url, username, password) agent = Mechanize.new agent.user_agent_alias = 'Mac Safari' agent.agent.http.verify_mode = OpenSSL::SSL::VERIFY_NONE username_set = false password_set = false page = agent.get(url) page.forms.each do |form| form.fields.each do |field| if field.name.downcase == 'username' or field.name.downcase== 'login' username_set = true field.value = username end if field.name.downcase == 'password' or field.name.downcase== 'pass' or field.name.downcase== 'pwd' password_set = true field.value = password end end return agent.submit(form) if username_set and password_set end return nil end Wednesday, September 18, 13
    • How do I break this? 25 log("existing user #{username} used as canary") wrong_pwd = post(url, username, "caosintheground").body.gsub(username, 'canary_username') wrong_creds = post(url, "caostherapy", "caosintheground").body.gsub("caostherapy", "canary_username") if ! line.start_with?("#") sleep(@sleep_time) log("awake... probing with: #{line}") r= post(url, line, ".4nt4n1") found << line if r.body == wrong_pwd.gsub("canary_username", line) end Wednesday, September 18, 13
    • Demo 26 Wednesday, September 18, 13
    • Look for Cross Site Scripting (reflected) 27 Wednesday, September 18, 13
    • Look for Cross Site Scripting 28 Wednesday, September 18, 13
    • Look for Cross Site Scripting 29 Wednesday, September 18, 13
    • Look for Cross Site Scripting 30 • In GETs • Submit the attack payload as parameter in the query string • Parse HTML and check if payload is in the script nodes • In POSTs • Get the page • Find the form(s) • Fill the form input values with attack payload • Submit the form • Parse HTML and check if payload is in the script nodes Wednesday, September 18, 13
    • Look for Cross Site Scripting 31 attack_url = Cross::Url.new(url) Cross::Attack::XSS.each do |pattern| attack_url.params.each do |par| page = @agent.get(attack_url.fuzz(par[:name],pattern)) @agent.log.debug(page.body) if debug? scripts = page.search("//script") scripts.each do |sc| found = true if sc.children.text.include?("alert('cross canary')") @agent.log.debug(sc.children.text) if @options[:debug] end attack_url.reset end end Exploiting GETs... $ gem install cross $ cross -u http://localhost:4567/hello?name=paolo Wednesday, September 18, 13
    • Look for Cross Site Scripting 32 begin page = @agent.get(url) rescue Mechanize::UnauthorizedError puts 'Authentication failed. Giving up.' return false rescue Mechanize::ResponseCodeError puts 'Server gave back 404. Giving up.' return false end puts "#{page.forms.size} form(s) found" if debug? page.forms.each do |f| f.fields.each do |ff| ff.value = "<script>alert('cross canary');</script>" end pp = @agent.submit(f) puts "#{pp.body}" if debug? scripts = pp.search("//script") scripts.each do |sc| found = true if sc.children.text == "alert('cross canary');" end end Exploiting POSTs... $ gem install cross $ cross http://localhost:4567/login Wednesday, September 18, 13
    • Demo 33 Wednesday, September 18, 13
    • What we learnt 34 • Don’t trust your users • “Security through obscurity” is EVIL • Testing for security issues is a mandatory step before deploy • HTTPS won’t safe from XSS or SQL Injections Wednesday, September 18, 13
    • Some links before we leave 35 http://armoredcode.com/blog/categories/pentest-with-ruby/ https://github.com/codesake http://ronin-ruby.github.com/ https://github.com/rapid7/metasploit-framework http://www.owasp.org http://brakemanscanner.org/ Not mine, here because they’re cool http://www.youtube.com/user/armoredcodedotcom Wednesday, September 18, 13
    • Questions? 36 Wednesday, September 18, 13
    • Thank you! 37 Wednesday, September 18, 13