BasicAsaParser extends BasicParser { @Override public List<JSONObject> parse(byte[] rawMessage) { String logLine = ""; String messagePattern = ""; JSONObject metronJson = new JSONObject(); List<JSONObject> messages = new ArrayList<>(); Map<String, Object> syslogJson = new HashMap<String, Object>(); logLine = new String(rawMessage, StandardCharsets.UTF_8); try { LOG.debug("[Metron] Started parsing raw message: {}", logLine); Match syslogMatch = syslogGrok.match(logLine); syslogMatch.captures(); if (!syslogMatch.isNull()) { syslogJson = syslogMatch.toMap(); LOG.trace("[Metron] Grok CISCO ASA syslog matches: {}", syslogMatch::toJson); metronJson.put(Constants.Fields.ORIGINAL.getName(), logLine); metronJson.put(Constants.Fields.TIMESTAMP.getName(), SyslogUtils.parseTimestampToEpochMillis((String) syslogJson.get("CISCOTIMESTAMP"), deviceClock)); metronJson.put("ciscotag", syslogJson.get("CISCOTAG")); metronJson.put("syslog_severity", SyslogUtils.getSeverityFromPriority((int) syslogJson.get("syslog_pri"))); metronJson.put("syslog_facility", SyslogUtils.getFacilityFromPriority((int) syslogJson.get("syslog_pri"))); if (syslogJson.get("syslog_host") != null) { metronJson.put("syslog_host", syslogJson.get("syslog_host")); } if (syslogJson.get("syslog_prog") != null) { metronJson.put("syslog_prog", syslogJson.get("syslog_prog")); } } else throw new RuntimeException( String.format("[Metron] Message '%s' does not match pattern '%s'", logLine, syslogPattern)); } catch (ParseException e) { LOG.error("[Metron] Could not parse message timestamp", e); throw new RuntimeException(e.getMessage(), e); } catch (RuntimeException e) { LOG.error(e.getMessage(), e); throw new RuntimeException(e.getMessage(), e); } try { messagePattern = (String) syslogJson.get("CISCOTAG"); Grok asaGrok = grokers.get(messagePattern); if (asaGrok == null) LOG.info("[Metron] No pattern for ciscotag '{}'", syslogJson.get("CISCOTAG")); else { String messageContent = (String) syslogJson.get("message"); Match messageMatch = asaGrok.match(messageContent); messageMatch.captures(); if (!messageMatch.isNull()) { Map<String, Object> messageJson = messageMatch.toMap(); LOG.trace("[Metron] Grok CISCO ASA message matches: {}", messageMatch::toJson); String src_ip = (String) messageJson.get("src_ip"); if (src_ip != null) metronJson.put(Constants.Fields.SRC_ADDR.getName(), src_ip); Integer src_port = (Integer) messageJson.get("src_port"); if (src_port != null) metronJson.put(Constants.Fields.SRC_PORT.getName(), src_port); String dst_ip = (String) messageJson.get("dst_ip"); if (dst_ip != null) metronJson.put(Constants.Fields.DST_ADDR.getName(), dst_ip); Integer dst_port = (Integer) messageJson.get("dst_port"); if (dst_port != null) metronJson.put(Constants.Fields.DST_PORT.getName(), dst_port); String protocol = (String) messageJson.get("protocol"); if (protocol != null) metronJson.put(Constants.Fields.PROTOCOL.getName(), protocol.toLowerCase()); String action = (String) messageJson.get("action"); if (action != null) metronJson.put("action", action.toLowerCase()); } else LOG.warn("[Metron] Message '{}' did not match pattern for ciscotag '{}'", logLine, syslogJson.get("CISCOTAG")); } LOG.debug("[Metron] Final normalized message: {}", metronJson::toString); } catch (RuntimeException e) { LOG.error(e.getMessage(), e); throw new RuntimeException(e.getMessage(), e); } messages.add(metronJson); return messages; }  @Override void configure(Map<String, Object> parserConfig); @Override void init(); @Override List<JSONObject> parse(byte[] rawMessage);  }
@Test public void testCISCOFW106023() { String rawMessage = "<164>Aug 05 2016 01:01:34: %ASA-4-106023: Deny tcp src Inside:10.30.9.121/54580 dst Outside:192.168.135.51/42028 by access-group \"Inside_access_in\" [0x962df600, 0x0]"; JSONObject asaJson = asaParser.parse(rawMessage.getBytes(StandardCharsets.UTF_8)).get(0); assertEquals(asaJson.get("original_string"), rawMessage); assertEquals("10.30.9.121", asaJson.get("ip_src_addr")); assertEquals("192.168.135.51", asaJson.get("ip_dst_addr")); assertEquals(54580, asaJson.get("ip_src_port")); assertEquals(42028, asaJson.get("ip_dst_port")); assertEquals(1470358894000L, (long) asaJson.get("timestamp")); }
@Test public void testCISCOFW106006() { String rawMessage = "<162>Aug 05 2016 01:02:25: %ASA-2-106006: Deny inbound UDP from 10.25.177.164/63279 to 10.2.52.71/161 on interface Inside"; JSONObject asaJson = asaParser.parse(rawMessage.getBytes(StandardCharsets.UTF_8)).get(0); assertEquals(asaJson.get("original_string"), rawMessage); assertEquals("10.25.177.164", asaJson.get("ip_src_addr")); assertEquals("10.2.52.71", asaJson.get("ip_dst_addr")); assertEquals(63279, asaJson.get("ip_src_port")); assertEquals(161, asaJson.get("ip_dst_port")); assertEquals(1470358945000L, (long) asaJson.get("timestamp")); }
@Test public void testNoPatternForTag() { String rawMessage = "<165>Aug 16 2016 04:08:36: %ASA-5-713049: Group = 172.22.136.20, IP = 172.22.136.20, Security negotiation complete for LAN-to-LAN Group (172.22.136.20) Initiator, Inbound SPI = 0x891fb03f, Outbound SPI = 0xbe4b5d8d"; JSONObject asaJson = asaParser.parse(rawMessage.getBytes(StandardCharsets.UTF_8)).get(0); assertEquals(asaJson.get("original_string"), rawMessage); assertEquals(1471320516000L, (long) asaJson.get("timestamp")); }
@Test public void testInvalidIpAddr() { String rawMessage = "<164>Aug 05 2016 01:01:34: %ASA-4-106023: Deny tcp src Inside:10.30.9.121/54580 dst Outside:192.168.256.51/42028 by access-group \"Inside_access_in\" [0x962df600, 0x0]"; JSONObject asaJson = asaParser.parse(rawMessage.getBytes(StandardCharsets.UTF_8)).get(0); assertEquals(asaJson.get("original_string"), rawMessage); assertEquals(1470358894000L, (long) asaJson.get("timestamp")); assertNull(asaJson.get("ip_dst_addr")); }
@Test public void testIp6Addr() { String rawMessage = "<174>Jan 05 2016 14:52:35 10.22.8.212 %ASA-6-302015: Built inbound UDP connection 76245506 for outside:2001:db8:85a3::8a2e:370:7334/49886 (10.22.8.110/49886) to inside:2001:0db8:85a3:0000:0000:8a2e:0370:7334/8612 (192.111.72.8/8612) (user.name)"; JSONObject asaJson = asaParser.parse(rawMessage.getBytes(StandardCharsets.UTF_8)).get(0); assertEquals(rawMessage, asaJson.get("original_string")); assertEquals("2001:db8:85a3::8a2e:370:7334", asaJson.get("ip_src_addr")); assertEquals("2001:0db8:85a3:0000:0000:8a2e:0370:7334", asaJson.get("ip_dst_addr")); assertEquals(49886, asaJson.get("ip_src_port")); assertEquals(8612, asaJson.get("ip_dst_port")); assertEquals(1452005555000L, asaJson.get("timestamp")); }
@Test public void testSyslogIpHost() { String rawMessage = "<174>Jan 5 14:52:35 10.22.8.212 %ASA-6-302015: Built inbound UDP connection 76245506 for outside:10.22.8.110/49886 (10.22.8.110/49886) to inside:192.111.72.8/8612 (192.111.72.8/8612) (user.name)"; JSONObject asaJson = asaParser.parse(rawMessage.getBytes(StandardCharsets.UTF_8)).get(0); assertEquals("10.22.8.212", asaJson.get("syslog_host")); }
@Test public void testSyslogHost() { String rawMessage = "<174>Jan 5 14:52:35 hostname-2 %ASA-6-302015: Built inbound UDP connection 76245506 for outside:10.22.8.110/49886 (10.22.8.110/49886) to inside:192.111.72.8/8612 (192.111.72.8/8612) (user.name)"; JSONObject asaJson = asaParser.parse(rawMessage.getBytes(StandardCharsets.UTF_8)).get(0); assertEquals("hostname-2", asaJson.get("syslog_host")); }
@Test public void testSyslogHostAndProg() { String rawMessage = "<174>Jan 5 14:52:35 hostname-2 progName-2 %ASA-6-302015: Built inbound UDP connection 76245506 for outside:10.22.8.110/49886 (10.22.8.110/49886) to inside:192.111.72.8/8612 (192.111.72.8/8612) (user.name)"; JSONObject asaJson = asaParser.parse(rawMessage.getBytes(StandardCharsets.UTF_8)).get(0); assertEquals("hostname-2", asaJson.get("syslog_host")); assertEquals("progName-2", asaJson.get("syslog_prog")); }
@Test public void testUnexpectedMessage() { String rawMessage = "-- MARK --"; UnitTestHelper.setLog4jLevel(BasicAsaParser.class, Level.FATAL); RuntimeException e = assertThrows(RuntimeException.class, () -> asaParser.parse(rawMessage.getBytes(StandardCharsets.UTF_8)).get(0)); assertTrue(e.getMessage().startsWith("[Metron] Message '-- MARK --'")); UnitTestHelper.setLog4jLevel(BasicAsaParser.class, Level.ERROR); }