Decrypt Obfuscated Perl Script

Decrypt obfuscated perl script

Replace the s;(.*);$_;see; with print to get this. Replace s;(.*);$_;see; again with print in the first half of the payload to get this, which is the decryption code. The second half of the payload is the code to decrypt, but I can't go any further with it, because as you see, the decryption code is looking for a key in an envvar or a cookie (so that only the script's creator can control it or decode it, presumably), and I don't have that key. This is actually reasonably cleverly done.

Decrypt obfuscated perl script on hacked site

If you want to see the deobfuscated code, here are the steps to do it. Note that what you will be doing is dangerous, because if you accidentally execute the code, your machine will be attacked. You are warned.

Note that these steps are for THIS EXAMPLE only. Other attack scripts may have other things in them. They may need other changes than what is detailed below.

Here are the steps for the original example that was posted.

Copy all of your program into original.pl. It will look like this:

my $gVcoQXKQ='';$gVcoQXKQ.=$_ while(<DATA>);$gVcoQXKQ=unpack('u*',$gVcoQXKQ);$gVcoQXKQ=~s/295c445c5f495f5f4548533c3c3c3d29/616962786d6065606062697f7f7c6360/gs;print($gVcoQXKQ);
__DATA__
M(R$O=7-R+V)I;B]P97)L("UW"G5S92!S=')I8W0["G5S92!03U-)6#L*=7-E

Change the eval on the first line to print. IF YOU DON'T CHANGE THE eval TO print, THEN THE NEXT STEP WILL PERFORM THE ATTACK ON YOUR MACHINE.

Now, run the program, after you have changed the eval to print.

perl original.pl > unencoded.pl

The new unencoded.pl program will look like this, with no indentation:

#!/usr/bin/perl -w
use strict;
use POSIX;
use IO::Socket;
use IO::Select;

Now use the B::Deparse module to interpret and reformat the program. MAKE SURE YOU HAVE -MO=Deparse OR ELSE YOU WILL RUN THE ATTACK.

perl -MO=Deparse unencoded.pl > formatted.pl   # Note the -MO=Deparse!!!

Running through the Deparse module will say:

unencoded.pl syntax OK

The new formatted.pl program will be a nicely formatted copy of the attacker's payload, 213 lines long, and you can examine what the script does. Note that the final program is still dangerous, because it is the attack program that the attacker wanted to run.

How does this obfuscated Perl script work?

Let's start by cleaning up the obfuscated syntax of the first line. $_=<<''; becomes

$_ = <<'';

Which is just a heredoc without a delimiter; it reads everything below the line into the $_ variable.

y;\r\n;;d; becomes

tr/\r\n//d;

Which is just the transliteration operator using semicolons as delimiters and the sed-like y/// form, which means the exact same thing as tr///. The d flag means characters without replacements will be deleted, and tr operates on $_ by default, so this statement just removes DOS-style line endings from the contents of $_.

$_=pack'b*',$_; becomes

$_ = pack('b*', $_);

Which takes the contents of $_ and treats it as a bitstring, turning all that whitespace into a text string of Perl code.

$_=eval;$@&&die$@;$_ becomes

$_ = eval;
$@ && die $@;
$_

The first line here uses the "string eval" form of eval. It'll take the code that was transliterated and unpacked, then parse and execute it.

$@ && die $@; is just a silly way to write die $@ if $@;. $@ is the eval error variable; if the code failed to parse and execute correctly, it will hold a true value, so the script will die with that error if there was one.

The lone $_ after that will be the last statement the interpreter sees. It got assigned the return value of the eval statement, which will be true if and only if the code given to eval parsed successfully. Perl modules require some true value to be the last statement in the file (usually just a 1;). Putting the $_ here will indicate a module load failure if something went wrong with the deobfuscation.

Whether or not your friend was right about it connecting to external servers is much more difficult to determine. A couple of searches through it seems to indicate that it isn't importing any networking modules (the only use statements are use strict 'refs';, and there are no requires), and it doesn't appear to be using any suspicious built-ins (no evals beyond the one in the first line; no functions that interact with the filesystem besides an open that presumably is used to process the input text file; none of Perl's built-in networking functions (all of which begin with 'set', 'get', or 'end'); and none of Perl's socket functions.

Of course there's no guarantee that the JavaScript it's generating is benign, but the Perl script doesn't appear to be accessing the network. Provided the script isn't doing anything obviously harmful when executed, your friend could try using a tool like Wireshark to find any malicious networking that would otherwise require a grueling audit to discover.

How can I de-obfuscate or decode this Perl code?

As noted by another poster - the first pass to extract what this is doing is to print rather than eval to get yourself some source code:

Second phase is to run it through -MO=Deparse to see if anyhing odd is happening. (And then perltidy to make it a bit easier to read):

#!usr/bin/local/perl
print
"\n\e[33mWarning You May Need To Install some\n Modules\n Here is An Example:\n cpan Net::IP\n cpan LWP::UserAgent\n cpan URI::Title\n Thank you For Using My Script\n inj3ctor3\e[0m\n";
use Term::ANSIColor;
use LWP::UserAgent;
use vars ('$PROG');
my (@ip_team) = ();
my $PROG = $0;
my $ips = $ARGV[0];
open my $handle, '<', $ips;
chomp( my (@loadlist) = <$handle> );
close $handle;
my $threads = $ARGV[1];
print "\e[31mStarting with $threads threads\n[!]Scanning $ARGV[0] \e[0m\n";

foreach my $ip (@loadlist) {
print "$ip\n";
push @ip_team, ( $ip++ )->ip;
if ( $threads == @ip_team ) {
Scan(@ip_team);
@ip_team = ();
}
}
Scan(@ip_team);

sub Scan {
my @Pids;
foreach my $host (@_) {
my $pid = fork;
die "Could not fork! $!\n" unless defined $pid;
if ( 0 == $pid ) {
print "$host\n";
exit;
}
else {
push @Pids, $pid;
}
}
foreach my $pid (@Pids) {
waitpid $pid, 0;
}
}

Helpfully, that top chunk includes a signature of who wrote it. Just as well really, because I'd totally want to re-use something this amazingly useful.

[33mWarning You May Need To Install some
Modules
Here is An Example:
cpan Net::IP
cpan LWP::UserAgent
cpan URI::Title
Thank you For Using My Script
inj3ctor3[0m

So it looks like what it does is:

  • opens a file specified as $ARGV[0];
  • reads it in (one line at a time) to a list of IP addresses.
  • batches it into chunks limited by $ARGV[1].
  • uses Net::IP to format an address

ip
Return the IP address (or first IP of the prefix or range) in quad format, as a string.
print ($ip->ip());

  • Sends the chunks to Scan which:
  • just forks, and prints the IP address, without doing anything like actually scanning it.

So ... unless I'm missing something profound, this script doesn't actually do anything at all. It just prints a list of IP addresses, and could perhaps be used to fork-bomb if the number of forks were set really high.

But as you can see - one of the advantages of perl (some might call it a drawback) is that it's really difficult to obfuscate it, because it's an interpreted language.

Can somebody explain this obfuscated perl regexp script?

The basic idea of the code you posted is that each alphanumeric character has been replaced by a bitwise operation between two non-alphanumeric characters. For instance,

'`'|'%'

(5th line of the "star" in your code)
Is a bitwise or between backquote and modulo, whose codepoints are respectively 96 and 37, whose "or" is 101, which is the codepoint of the letter "e". The following few lines all print the same thing:

say '`' | '%' ;
say chr( ord('`' | '%') );
say chr( ord('`') | ord('%') );
say chr( 96 | 37 );
say chr( 101 );
say "e"

Your code starts with (ignore whitespaces which don't matter):

'' =~ (

The corresponding closing bracket is 28 lines later:

^'(').'"})')

(C-f this pattern to see it on the web-page; I used my editor's matching parenthesis highlighting to find it)

We can assign everything in between the opening and closing parenthesis to a variable that we can then print:

$x =                              '(?'
.'{'.(
'`'|'%'
).("\["^
'-').('`'|
'!').("\`"|
',').'"(\\$'
.':=`'.(('`')|
'#').('['^'.').
('['^')').("\`"|
',').('{'^'[').'-'.('['^'(').('{'^'[').('`'|'(').('['^'/').('['^'/').(
'['^'+').('['^'(').'://'.('`'|'%').('`'|'.').('`'|',').('`'|'!').("\`"|
'#').('`'|'%').('['^'!').('`'|'!').('['^'+').('`'|'!').('['^"\/").(
'`'|')').('['^'(').('['^'/').('`'|'!').'.'.('`'|'%').('['^'!')
.('`'|',').('`'|'.').'.'.('`'|'/').('['^')').('`'|"\'").
'.'.('`'|'-').('['^'#').'/'.('['^'(').('`'|('$')).(
'['^'(').('`'|',').'-'.('`'|'%').('['^('(')).
'/`)=~'.('['^'(').'|</'.('['^'+').'>|\\'
.'\\'.('`'|'.').'|'.('`'|"'").';'.
'\\$:=~'.('['^'(').'/<.*?>//'
.('`'|"'").';'.('['^'+').('['^
')').('`'|')').('`'|'.').(('[')^
'/').('{'^'[').'\\$:=~/('.(('{')^
'(').('`'^'%').('{'^'#').('{'^'/')
.('`'^'!').'.*?'.('`'^'-').('`'|'%')
.('['^'#').("\`"| ')').('`'|'#').(
'`'|'!').('`'| '.').('`'|'/')
.'..)/'.('[' ^'(').'"})';
print $x;

This will print:

(?{eval"(\$:=`curl -s https://enlacezapatista.ezln.org.mx/sdsl-es/`)=~s|</p>|\\n|g;\$:=~s/<.*?>//g;print \$:=~/(SEXTA.*?Mexicano..)/s"})

The remaining of the code is a bunch of assignments into some variables; probably here only to complete the pattern: the end of the star is:

$:="\."^'~';
$~='@'|'(';
$^=')'^'[';
$/='`'|'.';
$,='(';

Which just assigns simple one-character strings to some variables.

Back to the main code:

(?{eval"(\$:=`curl -s https://enlacezapatista.ezln.org.mx/sdsl-es/`)=~s|</p>|\\n|g;\$:=~s/<.*?>//g;print \$:=~/(SEXTA.*?Mexicano..)/s"})

This code is inside a regext which is matched against an empty string (don't forget that we had first '' =~ (...)). (?{...}) inside a regex runs the code in the .... With some whitespaces, and removing the string within the eval, this gives us:

# fetch an url from the web using curl _quitely_ (-s)
($: = `curl -s https://enlacezapatista.ezln.org.mx/sdsl-es/`)
# replace end of paragraphs with newlines in the HTML fetched
=~ s|</p>|\n|g;
# Remove all HTML tags
$: =~ s/<.*?>//g;
# Print everything between SEXTA and Mexicano (+2 chars)
print $: =~ /(SEXTA.*?Mexicano..)/s

You can automate this unobfuscation process by using B::Deparse: running

perl -MO=Deparse yourcode.pl

Will produce something like:

'' =~ m[(?{eval"(\$:=`curl -s https://enlacezapatista.ezln.org.mx/sdsl-es/`)=~s|</p>|\\n|g;\$:=~s/<.*?>//g;print \$:=~/(SEXTA.*?Mexicano..)/s"})];
$: = 'P';
$~ = 'h';
$^ = 'r';
$/ = 'n';
$, = '(';

How can I obfuscate my Perl script to make it difficult to reverse engineer?

I suggest that you get this person and his management to sign a legally enforceable agreement that forbids all forms of reverse engineering, and any other means of gaining access to the stuff you want to protect.

Obfuscation cannot protect you against a determined attempt to reverse engineer. It is theoretically and practically impossible.

How to open and edit encrypted perl script?

Best option: Just edit your unencrypted copy and reinstall it.

Alternative: Use decr (comes with Filter::decrypt) to decrypt an encrypted file.

What does this obfuscated bash/perl code do?

I found it here http://www.cypherspace.org/adam/rsa/ and it's said that it's

a perl program which implements RSA encryption and decryption,
and is small enough to use as a signature file

and here is the full explanation of the code - it uses dc (GNU desk calculator by the way).

How does this perl code print that output?

This is actually a rather straightforward JAPH. The two biggest features of it is the splitting of the data string that makes up most of the "image", and the semi-recursive printing.

This is the code I get when I clean up the formatting

my ($j,$a,$p,$h);
$j = sub {
print( chr( $p += $a->[$h++] ) );
$j
};
;;

$a = [0, split "[: \n]+", # the split regex
q/43 -002:1 # input string start: q/ ...
-084 065:13
0001 000005
-0012 -00003
000013 -82 00048
21:13:-6.00:-76:72
-007.:02:00008.00
:::-6.00:::013
-70:3::-70:.64
/]; # input string end: .../
# print Dumper $a; # <--- this is my line
$p = 0x4a;;
$h=0;

$j->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->();

The first part is the declaration and assignment of the 4 main variables:

$j

$j is a code reference that prints a character, then returns a reference to itself. The print consists of a few steps:

  1. $a->[$h++] iterates over the @$a array, returning one element
  2. $p += ... that element is added to $p
  3. print chr( $p ... ) then $p is returned to chr() and the resulting character is printed.

Last in the sub block is $j, which means each iteration, the return value of the sub will be a reference to itself. This is the part that allows for the semi-recursive feature.

$a

$a is a reference to an array that consists of 0 and the result of a split on the input string. Here also a few things are happening in one line of code:

  • q/43 .../ this is a regular q() single quoted string with the delimiter slash /. It ends right before the closing bracket ] that denotes the array reference.
  • split "[: \n]+", this is a split on a character class, repeated 1 or more times. There are extra spaces inside it (which I have removed here) to fill out the space in the JAPH itself. Basically this removes all colon, space and newline and returns the resulting list.
  • $a = [0, ... ] the list of the split is added to a list of 0 (just one element) and everything is surrounded with brackets to denote an array reference, which is then stored in $a.

I assume the list starts with 0 because the code has a one-off error, in that $p's original value is the first letter in the output.

This is the Data::Dumper output of $a:

$VAR1 = [
0,
'43',
'-002',
'1',
'-084',
'065',
'13',
'0001',
'000005',
'-0012',
'-00003',
'000013',
'-82',
'00048',
'21',
'13',
'-6.00',
'-76',
'72',
'-007.',
'02',
'00008.00',
'-6.00',
'013',
'-70',
'3',
'-70',
'.64'
];

$p and $h

$p and $h are only numbers, and their role in this is source number for the chr() function and iterator for the @$a array, respectively.

The last line is the part where the $j subroutine is run and the JAPH is printed. The chained ->() syntax means that the return value of each previous iteration is used for the next execution. And $j returns a reference to itself, which makes it a semi-recursive affair, only the values change.

I guess it is similar to doing this:

$x = $j->();
$y = $x->();
$z = $y->();
...

So lets walk through the first few steps

  • $j->() the execution
  • $a->[$h++] $h is incremented to 1, returns 0 to the $a substript, which returns the first element of $a, which is 0.
  • $p += 0 This 0 is added to $p, and this returns the value of $p (74) to chr
  • print chr(74) this now prints a J to standard output
  • $j is returned.
  • ->() another execution is performed on the return value, so $j is run again.
  • $a->[$h++] $h is incremented to 2, returns 1 to $a which returns the second element which is 43.
  • $p += 43 74 + 43 = 117 is returned to chr
  • print chr(117) this prints u

The elements of $a are both positive and negative, moving the number where it needs to be. In the end, all the letters printed form: Just another Perl hacker,

Here's a rundown on the 10 first executions:

p => 74  += 0         =  74 output => chr( 74) J
p => 74 += 43 = 117 output => chr(117) u
p => 117 += -002 = 115 output => chr(115) s
p => 115 += 1 = 116 output => chr(116) t
p => 116 += -084 = 32 output => chr( 32)
p => 32 += 065 = 97 output => chr( 97) a
p => 97 += 13 = 110 output => chr(110) n
p => 110 += 0001 = 111 output => chr(111) o
p => 111 += 000005 = 116 output => chr(116) t
p => 116 += -0012 = 104 output => chr(104) h


Related Topics



Leave a reply



Submit