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
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

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

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Hello Woo. Writing Your First Script Using the Woocommerce API
  • Designing a Java Connector for Software Integrations
  • Vibe Coding With GitHub Copilot: Optimizing API Performance in Fintech Microservices
  • Revolutionizing Financial Monitoring: Building a Team Dashboard With OpenObserve

Trending

  • Top Book Picks for Site Reliability Engineers
  • How Trustworthy Is Big Data?
  • Using Python Libraries in Java
  • Measuring the Impact of AI on Software Engineering Productivity
  1. DZone
  2. Data Engineering
  3. Databases
  4. WordPress Core — Unauthenticated Blind SSRF

WordPress Core — Unauthenticated Blind SSRF

In this blog post, Sonar's R and D team describes a surprisingly simple vulnerability in WordPress’s implementation of pingbacks.

By 
Thomas Chauchefoin user avatar
Thomas Chauchefoin
·
Updated Dec. 16, 22 · Analysis
Likes (2)
Comment
Save
Tweet
Share
7.6K Views

Join the DZone community and get the full member experience.

Join For Free

WordPress is the world’s most popular content management system, used by over 40% of all websites. This wide adoption makes it a top target for threat actors and security researchers that get paid for reporting security issues through their public bug bounty program. 

Vulnerability brokers are also very interested in acquiring unpatched vulnerabilities enabling them to take over WordPress instances, sometimes offering up to $300,000 for critical ones. As such, WordPress has a heavily reviewed code base in which researchers are not expected to find low-hanging fruits anymore. My previous research on this target required extensive expertise and effort to uncover security issues. 

This blog post describes a surprisingly simple vulnerability in WordPress’s implementation of pingbacks. While the impact of this vulnerability is low for most users in the case of WordPress, the related vulnerable code pattern is fairly interesting to document as it is also probably present in most web applications. The goal of this blog post is to educate about this pattern and to raise awareness.

Disclosure

This vulnerability was reported to WordPress on January 21; no fix is available yet. Please refer to the section Patch to obtain guidance on potential remediations to apply to your WordPress instances. 

It is the first time my team and I have released details about an unpatched vulnerability, and this decision was not taken lightly. This issue was first reported about six years ago in January 2017 by another researcher and numerous others over the years. After my report and further investigation, I could also identify multiple public blog posts documenting the same behavior as the one I'll be covering today. 

Because of its low impact as-is, its prior publication, and the need to chain it to additional vulnerabilities in third-party software, I believe this release won't endanger WordPress users and can only help them harden their instances.

Impact

I couldn't generically identify ways to leverage this behavior to take over vulnerable instances without relying on other vulnerable services. 

It could ease the exploitation of other vulnerabilities in the affected organization's internal network, for instance, using one of the recent Confluence OGNL injections, the epic remote code execution in Jenkins found by @orange_8361, or one of the other chains documented by AssetNote. 

Technical Details

Use of the Vulnerable Construct in the Pingback Feature

Pingbacks are a way for blog authors to be notified and displayed when other “friend” blogs reference a given article: they are displayed alongside comments and can be freely accepted or rejected. Under the hood, blogs have to perform HTTP requests to each other to identify the presence of links. Visitors can also trigger this mechanism.

This feature has been widely criticized, as it enables attackers to perform distributed denial of service attacks by maliciously asking thousands of blogs to check for pingbacks on a single victim server. Pingbacks are still enabled by default on WordPress instances because of the importance of social and community features when it comes to personal blogging. Though, it is not expected that these requests could be sent to other internal services hosted on the same server or local network segment.

The pingback functionality is exposed on the XML-RPC API of WordPress. As a reminder, this is an API endpoint expecting XML documents in which the client can choose a function to invoke along with arguments.

One of the implemented methods is pingback.ping, expecting arguments pagelinkedfrom and pagelinkedto: the first one is the address of the article referencing the second one. 

pagelinkedto has to point to an existing article of the local instance, here http://blog.tld/?p=1, and pagelinkedfrom to the external URL that should contain a link to pagelinkedto.

Below is what a request to this endpoint would look like:

HTTP
 
POST /xmlrpc.php HTTP/1.1
Host: blog.tld [...] 

<methodCall>
	<methodName>pingback.ping</methodName>
    <params>
    	<param>
    		<value><string>http://evil.tld</string></value>
    	</param>
    	<param>
		    <value><string>http://blog.tld/?p=1</string></value>
	    </param>
    </params>
</methodCall>


Implementation of the URL Validation

The WordPress Core method wp_http_validate_url() runs a couple of checks on user-provided URLs to reduce the risks of abuse. For instance: 

  1. The destination can't contain a username and password;
  2. The hostname must not contain the following characters: #:?[]
  3. The domain name should not point to a local or private IP address like 127.0.0.1, 192.168.*, etc.
  4. The destination port of the URL must be either 80, 443, or 8080.

The third step may involve resolving domain names if present in the URL (e.g., http://foo.bar.tld). In that case, the IP address of the remote server is obtained by parsing the URL [1] and later resolving it [2] before validating it to exclude non-public IP ranges:

src/wp-includes/http.php

PHP
 
<?

$parsed_url = parse_url( $url ); // [1]
// [...] 
$ip = gethostbyname( $host );    // [2]
// [...] 
    if ( $ip === $host ) {
        // Error condition for gethostbyname()
        return false;         
    }      
	// IP validation happens here 
}

The validation code looks correctly implemented, and the URL is now considered trusted. What happens next?

Implementation of the HTTP Client(s)

Two HTTP clients can handle pingback requests after validating the URL based on available PHP features: Requests_Transport_cURL and Requests_Transport_fsockopen. They are both parts of the Requests library, developed independently under the WordPress umbrella. 

Let's have a look at the implementation of the latter. I know that it uses the PHP streams API from its name. It operates at the transport level, and the client has to craft the HTTP request manually. The URL is parsed again using parse_url(), and then its host part is used to create a destination compatible with the PHP streams API (e.g., tcp://host:port):

wp-includes/Requests/Transport/fsockopen.php

PHP
 
<?

public function request($url, $headers = array(), $data = array(), $options = array()) {
  // [...]
  $url_parts = parse_url($url);
  // [...]
  $host = $url_parts['host'];
  // [...]
    else {
        $remote_socket = 'tcp://' . $host;
    }     
  // [...]
  $remote_socket .= ':' . $url_parts['port'];

Further away, this destination is used to create a new stream with stream_socket_client(), and the HTTP request is crafted and written to it:

wp-includes/Requests/Transport/fsockopen.php

PHP
 
<?

$socket = stream_socket_client($remote_socket, $errno, $errstr, ceil($options['connect_timeout']), STREAM_CLIENT_CONNECT, $context); 
// [...] 
$out = sprintf("%s %s HTTP/%.1F\r\n", $options['type'], $path, $options['protocol_version']); 
// [...]
if (!isset($case_insensitive_headers['Host'])) {
    $out .= sprintf('Host: %s', $url_parts['host']);     
    // [...] 
}
// [...] 
fwrite($socket, $out);

As we can see, this process implies another DNS resolution, so stream_socket_client() can identify the host's IP to send the packets.

The behavior of the other HTTP client, cURL, is very similar and won't be covered here. 

The Vulnerability

This construct has a problem: the HTTP client has to re-parse the URL and re-resolve the hostname to send its request. Meanwhile, an attacker could have changed the domain to point to a different address than the one validated before! 

This bug class is also called Time-of-Check-Time-of-Use: a resource is validated but can be changed later before its effective use. It is common to find such vulnerabilities in mitigations against Server-Side Request Forgeries (SSRF). 

I summarized what these successive steps look like with the diagram below:


Exploitation Scenarios

I've audited the code in the hope of finding parser differential bugs that would allow reaching unintended ports or performing POST requests without success: the initial URL validation steps are restrictive enough to prevent their exploitation. As mentioned earlier, attackers would have to chain this behavior with another vulnerability to impact the targeted organization's security significantly.

Patch

I am not aware of any public patch available at the time of writing this publication; the details above are based on an intermediate patch shared with us during the disclosure process.

Addressing such vulnerabilities requires persisting the validated data until it is used to perform the HTTP request. It should not be discarded or transformed after the validation step. 

The WordPress maintainers followed this path by introducing a second, optional argument to wp_http_validate_url(). This parameter is passed by reference and contains the IP addresses on which WordPress performed the validation. The final code is slightly more verbose to accommodate older versions of PHP, but the main idea is here. 

As a temporary workaround, I recommend system administrators remove the handler pingback.ping of the XML-RPC endpoint. One way to do this is to update the functions.php of the theme in use to introduce the following call:

PHP
 
<?

add_filter('xmlrpc_methods', function($methods) {
  	unset($methods['pingback.ping']);
    return $methods;  
});


It is also possible to block access to xmlrpc.php at the web server level. 

Timeline

Date Action
2022-01-21 My team and I submit the vulnerability to the maintainers with a 90-day disclosure policy.
2022-01-21 My submission is triaged as Duplicate against a report originally sent (exactly) 5 years ago (2017-01-21).
2022-04-11 WordPress requests an extension of 30 days to our 90-day disclosure policy, as they need more time to work on backports. I agree.
2022-05-23 Maintainers share a patch for WordPress 5.9.3.
2022-06-01 My team and I provided positive feedback on the patch.
2022-07-16 My team and I communicate our intent to release this publication on September 6.
2022-09-01 Final heads up about the upcoming publication.
2022-09-06 This article is released, 228 days after our report and 2054 days after the initial report by another researcher.

Summary

In this article, I described a blind SSRF vulnerability affecting WordPress Core. While the impact is deemed low in this case, this is a widespread vulnerable code pattern that my team and I continue to encounter even in big projects. I encourage developers to check their own code bases for this type of code vulnerability that, as I have demonstrated, can hide in even highly popular and well-reviewed code.

I want to thank the WordPress maintainers for their help in addressing this issue, even if I couldn't reach the best outcome possible.

WordPress API Patch (computing)

Published at DZone with permission of Thomas Chauchefoin. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Hello Woo. Writing Your First Script Using the Woocommerce API
  • Designing a Java Connector for Software Integrations
  • Vibe Coding With GitHub Copilot: Optimizing API Performance in Fintech Microservices
  • Revolutionizing Financial Monitoring: Building a Team Dashboard With OpenObserve

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

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

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!