FortiGate: I can get CEF logs over UDP and Syslog over TLS, but not CEF over TLS. Why?

I’m trying to get Graylog to accept incoming CEF logs from a FortiGate firewall over a TLS connection. Everything works fine with a CEF UDP input, but when I switch to a CEF TCP input (with TLS enabled) the connection is established, bytes go in and out, but no messages are received by the input.

For troubleshooting, I created a Syslog TCP input (with TLS enabled) and configured the firewall to send CEF formatted logs there. Those messages were received and logged as raw syslog messages, but were CEF formatted, so the TLS connection between the firewall and Graylog is fine.

At first glance, I don’t see anything wrong with the formatting of the CEF either.

For some reason, Graylog is not properly accepting or parsing CEF logs sent to a CEF TCP input by a FortiGate. Does anyone know how to fix this?

Hey @seanthegeek

I have a few Fortinet/Fortgate Firewalls, Not sure how to fix you CEF inputs but I used Raw/Plaintext TCP/TLS. What I did was use extractors and/or pipelines to create the fields need. then drop whats not needed to save room. FYI the more fields the more storage will be used.

Example:

So my first guess is you are on the right track and its a format issue. Graylog will throw out messages that dont follow the format that they should (you should be able to see that in the server.log)

There is a pipeline rule posted in this thread and some instructions that should help Fortinet CEF Formatting issues - #11 by rfinney

1 Like

Where can I find those logs?

/var/log/graylog-server/server.log most likely

Looks like there’s an issue with the timestamp.

2023-04-15T03:22:33.110+01:00 ERROR [DecodingProcessor] Unable to decode raw message RawMessage{id=61087542-db34-11ed-91bf-0242c81e95c5, messageQueueId=1544122, codec=CEF, payloadSize=852, timestamp=2023-04-1
5T02:22:33.108Z, remoteAddress=/10.23.1.99:17006} on input <643862a851727d49a5b23ea6>.
2023-04-15T03:22:33.110+01:00 ERROR [DecodingProcessor] Error processing message RawMessage{id=61087540-db34-11ed-91bf-0242c81e95c5, messageQueueId=1544120, codec=CEF, payloadSize=873, timestamp=2023-04-15T02
:22:33.108Z, remoteAddress=/10.23.1.99:17006}
java.lang.IllegalStateException: Could not parse timestamp. '870 <189>Apr 15 02:22:32'
        at com.github.jcustenborder.cef.CEFParserImpl.parse(CEFParserImpl.java:162) ~[graylog.jar:?]
        at org.graylog.plugins.cef.codec.CEFCodec.decodeCEF(CEFCodec.java:128) ~[graylog.jar:?]
        at org.graylog.plugins.cef.codec.CEFCodec.decode(CEFCodec.java:117) ~[graylog.jar:?]
        at org.graylog2.shared.buffers.processors.DecodingProcessor.processMessage(DecodingProcessor.java:156) ~[graylog.jar:?]
        at org.graylog2.shared.buffers.processors.DecodingProcessor.onEvent(DecodingProcessor.java:94) [graylog.jar:?]
        at org.graylog2.shared.buffers.processors.ProcessBufferProcessor.onEvent(ProcessBufferProcessor.java:95) [graylog.jar:?]
        at org.graylog2.shared.buffers.processors.ProcessBufferProcessor.onEvent(ProcessBufferProcessor.java:49) [graylog.jar:?]
        at com.lmax.disruptor.WorkProcessor.run(WorkProcessor.java:143) [graylog.jar:?]
        at com.codahale.metrics.InstrumentedThreadFactory$InstrumentedRunnable.run(InstrumentedThreadFactory.java:66) [graylog.jar:?]
        at java.lang.Thread.run(Unknown Source) [?:?]```

FWIW, I also opened up a GitHub issue that has much more detail on how to reproduce the issue. Multiple CEF messages are treated as one long timestamp field when a TCP CEF input is used, but not when a UDP CEF input is used · Issue #15231 · Graylog2/graylog2-server (github.com)

@Joel_Duffield I have a much better understanding of the bug now (and I’ve updated the GitHub issue accordingly). I just don’t know if the bug is in the FortiGate firmware or Graylog. I suspect it is more likely in Graylog.

CEF messages are parsed correctly by Graylog over a CEF UDP input when a FortiGate firewall is configured to send CEF formatted logs over UDP. When the configuration is changed to send CEF logs over a TLS connection to a Graylog CEF TCP input, the connection is successful, and bytes in and bytes out are shown, but the message count remains at 0.

The Graylog server.log shows that parsing of the CEF message is failing because multiple CEF messages are being treated by the Graylog CEF parser as the timestamp of a single CEF message.

2023-04-15T16:03:32.467+01:00 ERROR [DecodingProcessor] Unable to decode raw message RawMessage{id=b0211ff0-db9e-11ed-b17c-0242c81e95c5, messageQueueId=1989011, codec=CEF, payloadSize=332981, timestamp=2023-04-15T15:03:32.463Z, remoteAddress=/REDACTED9:22867} on input <643862a851727d49a5b23ea6>.
2023-04-15T16:03:32.468+01:00 ERROR [DecodingProcessor] Error processing message RawMessage{id=b0211ff0-db9e-11ed-b17c-0242c81e95c5, messageQueueId=1989011, codec=CEF, payloadSize=332981, timestamp=2023-04-15T15:03:32.463Z, remoteAddress=/REDACTED9:22867}
java.lang.IllegalStateException: Could not parse timestamp. '705 <190>Apr 15 15:03:09 gateway CEF:0|Fortinet|Fortigate|v7.2.4|54000|utm:dns dns-query|2|deviceExternalId=REDACTED FTNTFGTeventtime=1681570989531024360 FTNTFGTtz=+0000 FTNTFGTlogid=1500054000 cat=utm:dns FTNTFGTsubtype=dns FTNTFGTeventtype=dns-query FTNTFGTlevel=information FTNTFGTvd=root FTNTFGTpolicyid=0 externalId=33799373 src=REDACTED spt=58665 FTNTFGTsrccountry=Reserved deviceInboundInterface=internal FTNTFGTsrcintfrole=lan dst=REDACTED9 dpt=53 FTNTFGTdstcountry=Reserved deviceOutboundInterface=root FTNTFGTdstintfrole=undefined proto=17 FTNTFGTprofile=default FTNTFGTsrcmac=REDACTED FTNTFGTxid=55650 FTNTFGTqname=www.google.com FTNTFGTqtype=A FTNTFGTqtypeval=1 FTNTFGTqclass=IN909 <189>Apr 15 15:03:09 gateway CEF:0|Fortinet|Fortigate|v7.2.4|54802|utm:dns dns-response|3|deviceExternalId=REDACTED FTNTFGTeventtime=1681570989531135600 FTNTFGTtz=+0000 FTNTFGTlogid=1501054802 cat=utm:dns FTNTFGTsubtype=dns FTNTFGTeventtype=dns-response FTNTFGTlevel=notice FTNTFGTvd=root FTNTFGTpolicyid=0 externalId=33799373 src=REDACTED spt=58665 FTNTFGTsrccountry=Reserved deviceInboundInterface=internal FTNTFGTsrcintfrole=lan dst=REDACTED9 dpt=53 FTNTFGTdstcountry=Reserved deviceOutboundInterface=root FTNTFGTdstintfrole=undefined proto=17 FTNTFGTprofile=default FTNTFGTsrcmac=REDACTED FTNTFGTxid=55650 FTNTFGTqname=www.google.com FTNTFGTqtype=A FTNTFGTqtypeval=1 FTNTFGTqclass=IN FTNTFGTipaddr=108.177.122.104, 108.177.122.105, 108.177.122.103, 108.177.122.106, 108.177.122.147, 108.177.122.99 msg=Domain is monitored act=pass FTNTFGTcat=41 FTNTFGTcatdesc=Search Engines and Portals1267 <189>Apr 15 15:03:09 gateway CEF:0|Fortinet|Fortigate|v7.2.4[...]<190>Apr 15 15:03:31 gateway CEF:0|Fortinet|Fortigate|v7.2.4|44546|event:system|2|deviceExternalId=REDACTED FTNTFGTeventtime=1681571011398864700 FTNTFGTtz=+0000 FTNTFGTlogid=0100044546 cat=event:system FTNTFGTsubtype=system FTNTFGTlevel=information FTNTFGTvd=root FTNTFGTlogdesc=Attribute configured duser=sean sproc=ssh(REDACTED) act=Edit FTNTFGTcfgtid=1013514248 FTNTFGTcfgpath=log.syslogd.setting FTNTFGTcfgattr=port[6514->5555]mode[reliable->udp] msg=Edit log.syslogd.setting 1350 <189>Apr 15 15:03:31'
        at com.github.jcustenborder.cef.CEFParserImpl.parse(CEFParserImpl.java:162) ~[graylog.jar:?]
        at org.graylog.plugins.cef.codec.CEFCodec.decodeCEF(CEFCodec.java:128) ~[graylog.jar:?]
        at org.graylog.plugins.cef.codec.CEFCodec.decode(CEFCodec.java:117) ~[graylog.jar:?]
        at org.graylog2.shared.buffers.processors.DecodingProcessor.processMessage(DecodingProcessor.java:156) ~[graylog.jar:?]
        at org.graylog2.shared.buffers.processors.DecodingProcessor.onEvent(DecodingProcessor.java:94) [graylog.jar:?]
        at org.graylog2.shared.buffers.processors.ProcessBufferProcessor.onEvent(ProcessBufferProcessor.java:95) [graylog.jar:?]
        at org.graylog2.shared.buffers.processors.ProcessBufferProcessor.onEvent(ProcessBufferProcessor.java:49) [graylog.jar:?]
        at com.lmax.disruptor.WorkProcessor.run(WorkProcessor.java:143) [graylog.jar:?]
        at com.codahale.metrics.InstrumentedThreadFactory$InstrumentedRunnable.run(InstrumentedThreadFactory.java:66) [graylog.jar:?]
        at java.lang.Thread.run(Unknown Source) [?:?]

For troubleshooting I replaced the CEF TLS input with a Syslog TCP input and kept the firewall configuration the same. Graylog received the message successfully and logged each CEF message separately as a raw syslog message, so the TLS connection between the firewall and Graylog is fine.

I’m not very familiar with CEF, but at first glance the raw log captured by the syslog input looks like a properly formatted CEF message to me.

Either the FortiGate is doing something different with the format of the CEF logs when TCP/TLS is used, or some internal Graylog process is breaking when it tries to read CEF from a TCP input, but I’m not sure which is the case.

So i wonder if you would see the exact same format if you also tried a syslog udp (or even raw input) and compare the CEF format between the two udp and tcp coming from the fortigate.

@Joel_Duffield

Syslog UDP

Raw UDP

Raw TCP (TLS) is treating separate messages like one giant message, just like the kind the CEF parser rejected.

@Joel_Duffield When I enabled the null byte delimiter on the RAW TCP input, the messages were properly split. However, as shown in this GIF, the throughput of messages kept dropping for some reason, and eventually stopped, even with TCP keepalive enabled, and the global in/out numbers never changed.

2023-04-15_17-00-28

When I try the null byte delimiter setting on a TCP (TLS) CEF input, server.log reports very small payloads

2023-04-15T22:10:03.286+01:00 ERROR [DecodingProcessor] Unable to decode raw message RawMessage{id=e3ada81b-dbd1-11ed-9f68-0242c81e95c5, messageQueueId=2236944, codec=CEF, payloadSize=1, timestamp=2023-04-15T21:10:03.281Z, remoteAddress=/10.23.1.99:2149} on input <643b127b673fff3ab0da76a5>.
2023-04-15T22:10:03.286+01:00 ERROR [DecodingProcessor] Unable to decode raw message RawMessage{id=e3ada81c-dbd1-11ed-9f68-0242c81e95c5, messageQueueId=2236945, codec=CEF, payloadSize=1, timestamp=2023-04-15T21:10:03.281Z, remoteAddress=/10.23.1.99:2149} on input <643b127b673fff3ab0da76a5>.
2023-04-15T22:10:03.286+01:00 ERROR [DecodingProcessor] Error processing message RawMessage{id=e3ada81b-dbd1-11ed-9f68-0242c81e95c5, messageQueueId=2236944, codec=CEF, payloadSize=1, timestamp=2023-04-15T21:10:03.281Z, remoteAddress=/10.23.1.99:2149}
java.lang.NullPointerException: Cannot invoke "com.github.jcustenborder.cef.Message.extensions()" because "message" is null
        at org.graylog.plugins.cef.parser.MappedMessage.<init>(MappedMessage.java:37) ~[graylog.jar:?]
        at org.graylog.plugins.cef.codec.CEFCodec.decodeCEF(CEFCodec.java:128) ~[graylog.jar:?]
        at org.graylog.plugins.cef.codec.CEFCodec.decode(CEFCodec.java:117) ~[graylog.jar:?]
        at org.graylog2.shared.buffers.processors.DecodingProcessor.processMessage(DecodingProcessor.java:156) ~[graylog.jar:?]
        at org.graylog2.shared.buffers.processors.DecodingProcessor.onEvent(DecodingProcessor.java:94) [graylog.jar:?]
        at org.graylog2.shared.buffers.processors.ProcessBufferProcessor.onEvent(ProcessBufferProcessor.java:95) [graylog.jar:?]
        at org.graylog2.shared.buffers.processors.ProcessBufferProcessor.onEvent(ProcessBufferProcessor.java:49) [graylog.jar:?]
        at com.lmax.disruptor.WorkProcessor.run(WorkProcessor.java:143) [graylog.jar:?]
        at com.codahale.metrics.InstrumentedThreadFactory$InstrumentedRunnable.run(InstrumentedThreadFactory.java:66) [graylog.jar:?]
        at java.lang.Thread.run(Unknown Source) [?:?]
2023-04-15T22:10:03.286+01:00 ERROR [DecodingProcessor] Error processing message RawMessage{id=e3ada81c-dbd1-11ed-9f68-0242c81e95c5, messageQueueId=2236945, codec=CEF, payloadSize=1, timestamp=2023-04-15T21:10:03.281Z, remoteAddress=/10.23.1.99:2149}
java.lang.NullPointerException: Cannot invoke "com.github.jcustenborder.cef.Message.extensions()" because "message" is null
        at org.graylog.plugins.cef.parser.MappedMessage.<init>(MappedMessage.java:37) ~[graylog.jar:?]
        at org.graylog.plugins.cef.codec.CEFCodec.decodeCEF(CEFCodec.java:128) ~[graylog.jar:?]
        at org.graylog.plugins.cef.codec.CEFCodec.decode(CEFCodec.java:117) ~[graylog.jar:?]
        at org.graylog2.shared.buffers.processors.DecodingProcessor.processMessage(DecodingProcessor.java:156) ~[graylog.jar:?]
        at org.graylog2.shared.buffers.processors.DecodingProcessor.onEvent(DecodingProcessor.java:94) [graylog.jar:?]
        at org.graylog2.shared.buffers.processors.ProcessBufferProcessor.onEvent(ProcessBufferProcessor.java:95) [graylog.jar:?]
        at org.graylog2.shared.buffers.processors.ProcessBufferProcessor.onEvent(ProcessBufferProcessor.java:49) [graylog.jar:?]
        at com.lmax.disruptor.WorkProcessor.run(WorkProcessor.java:143) [graylog.jar:?]
        at com.codahale.metrics.InstrumentedThreadFactory$InstrumentedRunnable.run(InstrumentedThreadFactory.java:66) [graylog.jar:?]
        at java.lang.Thread.run(Unknown Source) [?:?]
2023-04-15T22:10:13.037+01:00 ERROR [DecodingProcessor] Unable to decode raw message RawMessage{id=e97db190-dbd1-11ed-9f68-0242c81e95c5, messageQueueId=2236946, codec=CEF, payloadSize=33, timestamp=2023-04-15T21:10:13.033Z, remoteAddress=/10.23.1.99:2149} on input <643b127b673fff3ab0da76a5>.
2023-04-15T22:10:13.038+01:00 ERROR [DecodingProcessor] Error processing message RawMessage{id=e97db190-dbd1-11ed-9f68-0242c81e95c5, messageQueueId=2236946, codec=CEF, payloadSize=33, timestamp=2023-04-15T21:10:13.033Z, remoteAddress=/10.23.1.99:2149}
java.lang.NullPointerException: Cannot invoke "com.github.jcustenborder.cef.Message.extensions()" because "message" is null
        at org.graylog.plugins.cef.parser.MappedMessage.<init>(MappedMessage.java:37) ~[graylog.jar:?]
        at org.graylog.plugins.cef.codec.CEFCodec.decodeCEF(CEFCodec.java:128) ~[graylog.jar:?]
        at org.graylog.plugins.cef.codec.CEFCodec.decode(CEFCodec.java:117) ~[graylog.jar:?]
        at org.graylog2.shared.buffers.processors.DecodingProcessor.processMessage(DecodingProcessor.java:156) ~[graylog.jar:?]
        at org.graylog2.shared.buffers.processors.DecodingProcessor.onEvent(DecodingProcessor.java:94) [graylog.jar:?]
        at org.graylog2.shared.buffers.processors.ProcessBufferProcessor.onEvent(ProcessBufferProcessor.java:95) [graylog.jar:?]
        at org.graylog2.shared.buffers.processors.ProcessBufferProcessor.onEvent(ProcessBufferProcessor.java:49) [graylog.jar:?]
        at com.lmax.disruptor.WorkProcessor.run(WorkProcessor.java:143) [graylog.jar:?]
        at com.codahale.metrics.InstrumentedThreadFactory$InstrumentedRunnable.run(InstrumentedThreadFactory.java:66) [graylog.jar:?]
        at java.lang.Thread.run(Unknown Source) [?:?]

I ran into the same issue with the Fortigates sending one large message. Interestingly enough I found that FortiAnalyzer handled it correctly when forwarding the Fortigates logs over TCP to Graylog. Leading me to believe that the issue was with the Fortigate itself. This was back in the 6.0 releases and it appears it hasn’t been resolved.

I’ve spent a lot of time working with the Fortinet products and bringing the logs into Graylog. The best method I found was using Fortianalyzer to forward the messages to Graylog. I ended up using CEF for everything but the Fortigates in the Fortinet product line. But Fortinet still isn’t following the CEF standards so that causes a lot of cleanup. For the Fortigates I ended up using Syslog over TCP and it worked great.

Any reason why you need to use CEF?

1 Like

Funny you mentioned that. I gave up on CEF with the FortiGate and switched to syslog.

As a weekend project, I created a guide that explains how to set up a production-ready single node Graylog instance for analyzing FortiGate logs, complete with HTTPS, bidirectional TLS authentication, and premade dashboards. How to analyze FortiGate logs with a single-node Graylog instance

seanthegeek/graylog-fortigate-syslog: A Graylog Content Pack of dashboards for FortiGate syslog data (github.com)

I still have the Fortinet TAC case open for the CEF logs. Who knows, maybe they’ll finally get around to fixing it at some point.

Glad you got it working, and excellent blog post! These vendors and their messed up logs… I’m loosing hair way faster than i should.

That’s a great guide Sean. Thanks for posting it. If you would like to level it up even further, you could apply the Graylog Information Model Schema to your parsing rules and dashboards.

The GIM is relatively new, and we’re trying to build support for it in the community. If everyone adopts the schema, all community created content will work together. The GIM normalizes fields across products, allowing a single name for common fields (e.g. source_ip, destination_ip, etc.).

https://schema.graylog.org/en/stable/

Keep up the good work!

1 Like

Hey ,
Nice web site :+1: and great work @seanthegeek

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.