festival ict 2013: solid as diamond: use ruby in an web application penetration test

Post on 07-Nov-2014

2.103 Views

Category:

Technology

0 Downloads

Preview:

Click to see full reader

DESCRIPTION

 

TRANSCRIPT

Solid as DiamondUsing 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

2Wednesday, 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

3Wednesday, 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 blackboxYou’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

7Wednesday, 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

9Wednesday, 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.valueendgenerator

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'))

endrescue 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.comEvaluating 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 endend

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}" endend

Wednesday, September 18, 13

Demo

19Wednesday, September 18, 13

Bruteforce authentication mechanism

20Wednesday, September 18, 13

Am I vulnerable?

21Wednesday, September 18, 13

Am I vulnerable?

22Wednesday, 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 nilend

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

26Wednesday, September 18, 13

Look for Cross Site Scripting(reflected)

27Wednesday, September 18, 13

Look for Cross Site Scripting

28Wednesday, September 18, 13

Look for Cross Site Scripting

29Wednesday, 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]

endattack_url.reset

endend

Exploiting GETs...

$ gem install cross$ cross -u http://localhost:4567/hello?name=paolo

Wednesday, September 18, 13

Look for Cross Site Scripting

32

beginpage = @agent.get(url)

rescue Mechanize::UnauthorizedErrorputs 'Authentication failed. Giving up.'return false

rescue Mechanize::ResponseCodeErrorputs '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>"endpp = @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

33Wednesday, 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.orghttp://brakemanscanner.org/

Not mine, here because they’re cool

http://www.youtube.com/user/armoredcodedotcom

Wednesday, September 18, 13

Questions?

36Wednesday, September 18, 13

Thank you!

37Wednesday, September 18, 13

top related