44using Microsoft . CST . AttackSurfaceAnalyzer . Utils ;
55using Serilog ;
66using System ;
7+ using System . ComponentModel . DataAnnotations ;
78using System . Net . NetworkInformation ;
89using System . Runtime . InteropServices ;
910using System . Text . RegularExpressions ;
@@ -41,6 +42,19 @@ internal override void ExecuteInternal(CancellationToken cancellationToken)
4142 }
4243 }
4344
45+ /* Examples
46+ // Sockets
47+ Netid State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
48+ u_str LISTEN 0 4096 /run/libvirt/virtlockd-sock 26200 * 0 users:(("systemd",pid=1,fd=77))
49+
50+ // Ports
51+ Netid State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
52+ nl UNCONN 0 0 0:530 *
53+ */
54+ private static Regex LinuxSsParsingRegex { get ; } = new Regex (
55+ "([\\ S]+)\\ s+([\\ S]+)\\ s+([\\ S]+)\\ s+([\\ S]+)\\ s+([\\ S]+)[\\ s+|:]([\\ S]+)\\ s+([\\ S]+)(\\ s+([\\ S]+)\\ s+([\\ S]+))?" ,
56+ RegexOptions . Compiled ) ;
57+
4458 /// <summary>
4559 /// Executes the OpenPortCollector on Linux. Calls out to the `ss` command and parses the output,
4660 /// sending the output to the database.
@@ -59,46 +73,42 @@ internal void ExecuteLinux(CancellationToken cancellationToken)
5973 {
6074 continue ;
6175 }
62- var parts = Regex . Split ( line , @"\s\s+" ) ;
63- if ( parts . Length < 5 )
76+
77+ var ssParts = LinuxSsParsingRegex . Match ( line ) ;
78+ if ( ! ssParts . Success )
6479 {
6580 continue ; // Not long enough, must be an error
6681 }
6782
68- var addressMatches = Regex . Match ( parts [ 4 ] , @"^(.*)[:\s](\d+)$" ) ;
69- Console . WriteLine ( parts [ 4 ] ) ;
70- if ( addressMatches . Success )
83+ var address = ssParts . Groups [ 5 ] . Value ;
84+ var port = ssParts . Groups [ 6 ] . Value ;
85+ if ( int . TryParse ( port , out int portInt ) )
7186 {
72- var address = addressMatches . Groups [ 1 ] . Value ;
73- var port = addressMatches . Groups [ 2 ] . Value ;
74- if ( int . TryParse ( port , out int portInt ) )
87+ var transport = ssParts . Groups [ 1 ] . Value . ToUpperInvariant ( ) . Equals ( "TCP" ) ? TRANSPORT . TCP : ssParts . Groups [ 1 ] . Value . ToUpperInvariant ( ) . Equals ( "UDP" ) ? TRANSPORT . UDP : TRANSPORT . UNKNOWN ;
88+ var family = address . Contains ( '.' ) ? ADDRESS_FAMILY . InterNetwork : address . Contains ( ':' ) ? ADDRESS_FAMILY . InterNetworkV6 : ADDRESS_FAMILY . Unknown ;
89+ if ( ! string . IsNullOrWhiteSpace ( ssParts . Groups [ 10 ] . Value ) )
7590 {
76- var transport = parts [ 0 ] . ToUpperInvariant ( ) . Equals ( "TCP" ) ? TRANSPORT . TCP : parts [ 0 ] . ToUpperInvariant ( ) . Equals ( "UDP" ) ? TRANSPORT . UDP : TRANSPORT . UNKNOWN ;
77- var family = address . Contains ( '.' ) ? ADDRESS_FAMILY . InterNetwork : address . Contains ( ':' ) ? ADDRESS_FAMILY . InterNetworkV6 : ADDRESS_FAMILY . Unknown ;
78- if ( parts . Length > 6 && ! string . IsNullOrWhiteSpace ( parts [ 6 ] ) )
79- {
80- var processNameMatches = Regex . Matches ( parts [ 6 ] , @"""(.*?)"",pid=([0-9]*)" ) ;
81- foreach ( Match match in processNameMatches )
82- {
83- int ? pid = int . TryParse ( match . Groups [ 2 ] . Value , out int thePid ) ? thePid : null ;
84- var obj = new OpenPortObject ( portInt , transport , family )
85- {
86- Address = address ,
87- ProcessName = match . Groups [ 1 ] . Value ,
88- ProcessId = pid
89- } ;
90- HandleChange ( obj ) ;
91- }
92- }
93- else
91+ var processNameMatches = Regex . Matches ( ssParts . Groups [ 10 ] . Value , @"""(.*?)"",pid=([0-9]*)" ) ;
92+ foreach ( Match match in processNameMatches )
9493 {
94+ int ? pid = int . TryParse ( match . Groups [ 2 ] . Value , out int thePid ) ? thePid : null ;
9595 var obj = new OpenPortObject ( portInt , transport , family )
9696 {
97- Address = address
97+ Address = address ,
98+ ProcessName = match . Groups [ 1 ] . Value ,
99+ ProcessId = pid
98100 } ;
99101 HandleChange ( obj ) ;
100102 }
101103 }
104+ else
105+ {
106+ var obj = new OpenPortObject ( portInt , transport , family )
107+ {
108+ Address = address
109+ } ;
110+ HandleChange ( obj ) ;
111+ }
102112 }
103113 }
104114 }
0 commit comments