Web Developer / Security Analyst / System Administrator

ActiveCampaign On-Site 5.4.0 0-day

ActiveCampaign On-Site 5.4.0 0-day

Found a vulnerability in latest ActiveCampaign On-Site release, which allows to dump database and execute remote commands.

ActiveCampaign is a software allowing to:
– Send newsletters, design beautiful email campaigns, and keep in touch with your contacts and customers.
– Automate your marketing channels using personal and behavioral data about your contacts.
– Get more leads and close deals faster with our refreshing new take on customer relations.

November 18, 2016 0 comments Read More
Feed2JS/MagpieRSS 0day vulnerability (not really, it is actually CVE-2005-3330 / CVE-2008-4796)

Feed2JS/MagpieRSS 0day vulnerability (not really, it is actually CVE-2005-3330 / CVE-2008-4796)

Feed2JS is a tool for user-friendly(developer-wise) embedding the RSS feeds on the pages without messing with XML.

I’ve found out today that it’s vulnerable to local file disclosure (all your /etc/passwds could be stolen).
It could be used for remote file inclusion as well.

tl;dr – fixed file at the bottom of the post

Feed2JS uses MagpieRSS for parsing the feeds, and MagpieRSS uses Snoopy library for fetching the documents:

Snoopy - the PHP net client
Author: Monte Ohrt <monte@ispi.net>
Copyright (c): 1999-2000 ispi, all rights reserved
Version: 1.0

Snoopy 1.0 is 12 years old (sic!),6 years ago someone ‘found’ a vulnerability in Snoopy 1.2.3:

The _httpsrequest function (Snoopy/Snoopy.class.php) in Snoopy 1.2.3 and earlier, as used in (1) ampache, (2) libphp-snoopy, (3) mahara, (4) mediamate, (5) opendb, (6) pixelpost, and possibly other products, allows remote attackers to execute arbitrary commands via shell metacharacters in https URLs.

But this was actually discovered 3 years prior to that(9 years ago!):

The _httpsrequest function in Snoopy 1.2, as used in products such as (1) MagpieRSS, (2) WordPress, (3) Ampache, and (4) Jinzora, allows remote attackers to execute arbitrary commands via shell metacharacters in an HTTPS URL to an SSL protected web page, which is not properly handled by the fetch function.

As you can see, Snoopy 1.0 is definetely older than v1.2.3, so the _httpsrequest function should be vulnerable in the Snoopy library used in Feed2JS, even though I read somewhere that this issue is fixed in Magpie 0.7.2(it’s not)..

Some code snippets from Feed2JS/Magpie:


Function: fetch
Purpose: fetch the contents of a web page
(and possibly other protocols in the
future like ftp, nntp, gopher, etc.)
Input: $URI the location of the page to fetch
Output: $this->results the output text from the fetch

function fetch($URI)
$URI_PARTS = parse_url($URI);
case "https":
$path = $URI_PARTS["path"].($URI_PARTS["query"] ? "?".$URI_PARTS["query"] : "");
$this->_httpsrequest($path, $URI, $this->_httpmethod);

Function: _httpsrequest
Purpose: go get the https data from the server using curl
Input: $url the url to fetch
$URI the full URI
$body body contents to send if any (POST)

function _httpsrequest($url,$URI,$http_method,$content_type="",$body="")
exec($this->curl_path." -D \"/tmp/$headerfile\"".escapeshellcmd($cmdline_params)." ".escapeshellcmd($URI),$results,$return);

I cringe every time when I see “exec” functions, so lets check whats wrong in using it ..

From php.net:

escapeshellcmd() should be used on the whole command string, and it still allows the attacker to pass arbitrary number of arguments. For escaping a single argument escapeshellarg() should be used instead.

You can pass additional curl arguments (you can check curl manual @ http://curl.haxx.se/docs/manpage.html), for example:


This code will send something:test in the headers (can be used to get sensitive information about the server).

You can also download a file and save it locally using curl -o flag.


this will download https://example.com/shell and save it into cache/ directory (which has 777 permissions by design)

Or you can submit


to get the /etc/passwd POSTed to your malicious URL and save it using $_FILES['file'].


I have notified Alan Levine, original developer of Feed2JS, and Kellan Elliot-McCrea, developer of MagpieRSS, but you can fix it yourself by updating  magpie/extlib/Snoopy.class.inc to Snoopy 1.2.4  (you can get it here: http://sourceforge.net/projects/snoopy/files/Snoopy/Snoopy-1.2.4/)

UPD. Sorry for disinformation, Snoopy 1.2.4 is vulnerable as well, so this IS a 0day..

Snoopy 1.2.4 ‘fixed’ the CVE-2008-4796 by using quotes around the escapeshellcmd, but it is still vulnerable, you can exploit it like this:


To fix this, you need to use escapeshellarg instead of escapeshellcmd.

1.2.4 also removed gzip support and messed up the compatibility with MagpieRSS..

Fixed version of Snoopy.class.inc is here:


UPD2. Snoopy 1.2.5 is available:


UPD3. (thanks to Tomas Hoger) Upstream fix is incomplete / insufficient.
Host name from a provided URL is extracted for use in the Host: HTTP header, provided to curl using -H option without proper escaping.
So you can do bad things with URLs as:

Fixed in Snoopy 1.2.9 and above


July 3, 2014 6 comments Read More
WordPress Plugin: Google map with custom filters

WordPress Plugin: Google map with custom filters

I’ve created a plugin which creates a shortcode for generating a map and auto-generated side menu (based on subcategories of specific parent category) with options to set the size, center point, default zoom, clusterer settings, etc.

April 29, 2014 0 comments Read More
Product management

Product management

I was asked to create an order page for hosting provider:

You can manage products and product parts easily using admin area:

April 29, 2014 0 comments Read More
Local/Remote File Inclusion vulnerability

Local/Remote File Inclusion vulnerability

Found yet another bug,


anything suspicious?

It is possible to pass ?footer=SOME_FILE and it will get passed to include() function.

There are many ways to exploit this:

You can read files with

You can also read remote files if allow_url_include is set to true

but the system I’ve found this bug in didn’t have allow_url_include and it didn’t have php filters because they were only introduced in PHP 5..but there is a way to exploit this anyway.

If you are able to upload the files to the server(usually you can upload them in forums), you can upload an image with malicious payload within EXIF headers or within PNG iDAT chunks, and include that file like so:

If that’s not possible, you can always send a GET request to the server and include /var/log/httpd/access_log, or send a mail and include /var/log/maillog.. But sometimes there are not enough permissions to read /var/log..you shouldn’t stop trying!

If the server provides PHPSESSID cookie, you can include
/var/lib/php/session/sess_PHPSESSID (sessions are saved in files by default)

Then find out what variables are stored there, and if you are as lucky as I am, you could change some variable like username to something like this: “<?php echo phpinfo(); ?>“, then re-login to update the session, and then by including the session file find out if disable_functions is enabled, after that there are 2 ways:

1) if system/exec functions are disabled you can change your username to:
“<?php $_GET[0]($_POST[1]); ?>”

2) otherwise change your username to:
 ”<?php system($_POST[1]); ?>”

Then you can do whatever you want with the system.

Lessons learned:
1) Never believe user input
2) Never believe user input
3) Never believe user input


P.S. or at least do use extract($_REQUEST,EXTR_SKIP) so variables don’t get overwritten

January 22, 2014 0 comments Read More
UserPro exploit based on previous post

UserPro exploit based on previous post

Here’s the Proof-Of-Concept script which allows to activate or change the password for any UserPro user


P.S. all requests are logged

January 16, 2014 0 comments Read More
Another 0day in UserPro — Remote file upload / Stealing WordPress admin access / UserPro Privilege Escalation

Another 0day in UserPro — Remote file upload / Stealing WordPress admin access / UserPro Privilege Escalation

So, after I’ve pointed out that UserPro has file upload vulnerability, DeluxeThemes (developer of UserPro) deleted my comment and updated their plugin..

This should fix the vulnerability and clients can have a good night’s sleep, right?




it is still possible to upload other kinds of files (e.g. php5 or php4 works on some servers)


But the fun isn’t over..I have checked other parts of the code as well, and I’m not surprised that there are other vulnerabilities too
It’s convenient to use AJAX, but it’s easy to overlook the vulnerabilities when using it
userpro/functions/ajax.php :

add_action('wp_ajax_userpro_save_userdata', 'userpro_save_userdata');
function userpro_save_userdata(){
	global $userpro;
	$output = '';
	$userpro->set($field, $value, $user_id);

and the $userpro->set function is defined in userpro/functions/api.php

function set($field, $value, $user_id){
	update_user_meta($user_id, $field, esc_attr($value) );

you can POST almost any wp_usermeta key along with its value and user_id to wp-admin/admin-ajax.php?userpro_save_userdata and it will get updated..

That’s not all..Also, check out this part of code in userpro/functions/ajax.php:

add_action('wp_ajax_userpro_process_form', 'userpro_process_form');
function userpro_process_form(){
	global $userpro;
	foreach($_POST as $key=>$val) {
			$key = explode('-',$key);
			$key = $key[0];
			$form[$key] = $val;
	} extract($form);
	/* form action */
	switch($template) {
	case 'edit':
	userpro_update_user_profile( $user_id, $form );

and this part in userpro/functions/user-functions.php

function userpro_update_user_profile($user_id, $form) {
	foreach($form as $key => $form_value) {
		if ( isset($key) && in_array($key, array('user_url', 'display_name', 'role', 'user_login', 'user_pass', 'user_pass_confirm', 'user_email')) ) {
			/* Save passwords */
			if ($key == 'user_pass') {
				if (!empty($form_value)) {
					wp_update_user( array ( 'ID' => $user_id, $key => $form_value ) ) ;
			} else {
				wp_update_user( array ( 'ID' => $user_id, $key => $form_value ) ) ;
			if (isset($key) && !strstr($key, 'pass')){
				update_user_meta( $user_id, $key, $form_value );
			} else {
				delete_user_meta( $user_id, $key );

This function takes $_POST array, turns it into $form array stripping the dash from the variable (so template-1 becomes template), and then uses this array to update the wp_usermeta AND wp_user…such fail..
It is also possible to change password using other templates from userpro_process_form, but that’ll do

By the way, to get this plugin for free you can download the demo version, and do this change in functions/api.php (haven’t tested,but pretty sure it will work).

function verify_purchase($code, $api_key=null, $username=null, $item_id=null) {
	if (!$api_key) $api_key = userpro_get_option('envato_api');
	if (!$username) $username = userpro_get_option('envato_username');
	$Envato = new Envato_marketplaces();
	$Envato->set_api_key( $api_key );
	$verify = $Envato->verify_purchase( $username , $code); 
	if ($item_id != '') {
		if ( isset($verify->buyer) && $verify->item_id == $item_id )
			return true;
		return false;
	} else {
		if ( isset($verify->buyer) )
			return true;
		return false;


function verify_purchase($code, $api_key=null, $username=null, $item_id=null) {
	return true;


P.S. just got a message from UserPro relating to the vulnerabilities, and it said just 4 words — “fuck off upme slave” (upme is a plugin from previous post), now I’m even more surprised how such blatant ignorant guy got 700 sales

January 16, 2014 4 comments Read More
0day vuln – Remote file upload in User Profiles Made Easy – WordPress Plugin

0day vuln – Remote file upload in User Profiles Made Easy – WordPress Plugin

After finding out that UserPro is vulnerable client decided to choose another plugin, but it seems that other similar plugins are vulnerable too..


This one is a bit more secure, but still not enough (hehe..there are no such thing as “a lot of security”)

Will follow with details once vendor fixes the issue

The vulnerability is in

foreach ($_FILES as $key => $array) {
	if ($name) {
		// Security Check Start
		// Checking for Image size. If this is the real image (not tempered) then this function will return width and height and other values in return.
		$image_data = getimagesize($tmp_name);
		$clean_file = true;
		if (!isset($image_data[0]) || !isset($image_data[1]))
			$clean_file = false;
		// Security Check End
		$clean_key = str_replace('-' . $this->userid, '', $key);
		if (!in_array($type, $this->allowed_extensions)) {
			$this->errors[$clean_key] = __('The image file extention is not allowed!', 'upme');
		} elseif ($size > $this->max_size) {
			$this->errors[$clean_key] = __('The file you have selected exceeds the maximum allowed image size.', 'upme');
		} elseif ($clean_file == false) {
			$this->errors[$clean_key] = __('The file you selected appears to be corrupt or not a real image file.', 'upme');
		} else {
			// Checking for valid uploads folder
			if ($upload_dir = upme_get_uploads_folder_details()) {
				$target_path = $upload_dir['basedir'] . "/upme/";

				$base_name = sanitize_file_name(basename($name));
				$target_path = $target_path . time() . '_' . $base_name;
				$nice_url = $upload_dir['baseurl'] . "/upme/";
				$nice_url = $nice_url . time() . '_' . $base_name;
				move_uploaded_file($tmp_name, $target_path);

this script doesn’t check for the image extension, just the mime-type supplied by the user

It is possible to change mime-type manually and upload an image with php code inside it (either in EXIF data, or technique described here: https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/) and save it as “*.php”

The only bit which causes some difficulties is this line:

$nice_url = $nice_url . time() . '_' . $base_name;

So you need to get the Date from the server to find out the filename.

January 15, 2014 1 comment Read More
0day vuln – Remote file upload in UserPro – User Profiles with Social Login

0day vuln – Remote file upload in UserPro – User Profiles with Social Login

Found 0day vulnerability in UserPro


Will follow with details once vendor fixes the issue


check userupload/lib/fileupload/fileupload.php

This function takes “userpro_file” from $_FILES and just moves it to wp-content/uploads/userpro/..
No security checks whatsoever, so malicious users can upload ANYTHING to the server

P.S. how the hell it got ~700 purchases with such code?

January 15, 2014 0 comments Read More
Website with ffmpeg conversion of uploaded videos

Website with ffmpeg conversion of uploaded videos

World Cast Movie

World Cast Movie (1)

July 25, 2013 0 comments Read More