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 Tuesday, April 23, 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! Tuesday, April 23, 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 and she says “test it for security issues, please”... Tuesday, April 23, 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) Tuesday, April 23, 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) Tuesday, April 23, 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 Tuesday, April 23, 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 Tuesday, April 23, 13
How do I break this? 26 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 Tuesday, April 23, 13
How do I break this? 27 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 Tuesday, April 23, 13
Look for Cross Site Scripting 33 • 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 Tuesday, April 23, 13
Look for Cross Site Scripting 34 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 Tuesday, April 23, 13
Look for Cross Site Scripting 35 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 = "alert('cross canary');" 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 Tuesday, April 23, 13
What we learnt 38 • 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 Tuesday, April 23, 13
Some links before we leave 39 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 Tuesday, April 23, 13