The Log Forging Vulnerability And How To Fix It

The Log Forging vulnerability, also known as Log Manipulation is a really low ranked vulnerability that in a lot of cases its to farfetched to be reliably exploited, but on others can be quite easy and cause real damage.

In this post we’ll understand what is log forging and see many different conditions that can cause the vulnerability or to increase the risk.

What is Log Forging

Log forging is a vulnerability where an attacker can manipulate the logs, by creating new entries. This usually happens because user input gets directly to the logs without any sanitisation.

Most traditional log format is a plain text file, where each line is a new entry in the log. If an attacker sends some content with a new line character it can create a new log entry.

Example:

starting webserver
received request from 192.168.1.1
received username: thesecurityvault
received request from 192.168.1.2
sending ok message

In red is the content received from user input. Since it wasn’t properly handled, the user introduced a new line and then faked a new log entry.

In this case it could mean that the request to 192.168.1.1 failed somewhere, and that a request to 192.168.1.2 was properly done.

Not that easy to fake

If you look to the example above, to actually fake the behaviour of the log, the attacker needed to know how to log outputs messages, otherwise it won’t be that reliable.

Lets see other example of logs:

WordPress error log:

[15-Jun-2018 17:24:03 UTC] PHP Warning:  Use of undefined constant theme_section - ....
[15-Jun-2018 17:24:31 UTC] PHP Warning:  Use of undefined constant theme_section ...
[20-May-2018 20:39:14 UTC] WordPress database error Table 'xyz' doesn't exist

Checkmarx’s scan log:

08/03/2018 11:41:54,726 [MainThread_CxEng] INFO Available memory: 9790 Used memory: 307 Elapsed Time: 00:00:07.4013541 [Unspecified] - No Unified languages configured
08/03/2018 11:41:54,776 [MainThread_CxEng] INFO Available memory: 9650 Used memory: 308 Elapsed Time: 00:00:07.4511596 [Unspecified] - Scanning or Auditing Project type code is ...

As you can see in both cases, applications tend to prepend some content to the log message, but the format is not the same for all applications so for an attacker to successfully do a log forging attack it would need to know the format of the prepended data.

An attacker can also count with an “uneducated” user looking at the logs, or hope it wont notice the wrong data.

Increased risk for open source or on prem projects

If you have an application vulnerable to log forging (and almost all applications I reviewed professionally were) and open source the risk increases significantly because an attacker can study the code and see where user input ends up in the logs and the proper log format.

The risk also increases with proprietary software where you have access to logs, like on prem installations, as an attacker can see the log format and can also test locally for vulnerable entry points, then exploit them on other systems.

Variants

JSON

Sometimes applications use JSON formatted logs. In this case the new line may not be that relevant as everything inside the string content is part of the log.

But there are other issues to take into account here. First, if the logs still uses one line per entry, an attacker can try to trick the victim, the same way, by creating new lines.

This is easily spotted by an experienced user, that can see that the string content didn’t end on the line break.

On the other hand if the JSON log is prepared just by concatenating strings, this can still be an issue.

console.log(`{"Severity": "INFO", message: "bad username: ${username}"}`)

In the example above (in javascript), although the log is in JSON format, it was done by just concatenating some user input into a string and an attacker, can escape the string content and create new log entries (attacker input in red):

{"Severity": "INFO", message: "bad username: "}
{ "Severity": "INFO", message: "DUMPING USER CREDENTIALS " }

To mitigate this attack, in javascript, work with regular JS Objects and at the end use JSON.stringify to convert the object into well formatted javascript. This will prevent the issue.

Log Viewer

Another exploitable scenario may be the log viewer itself, instead of the log. If an application uses a tool to visualize the logs, you can trick the tool to display the log like it was a new entry.

Lets say you created your own log viewer, that parses each line of the log as an entry, and you removed all new lines from user input so that no new lines could be maliciously created.

And when you write the log entries to the webpage, you use something like:

<?php echo $logentry; ?>

This can still cause an issue, as an attacker can inject an html new line (<br>) that will be interpreted by the browser. If you just create a new div for each log entry, an attacker could close that div and open a new one.

Here a log forging vulnerability wouldn’t be the major concern, as XSS attacks would be possible through the log input.

Logging libraries

From what I’ve seen so far, most log libraries do not have default mechanisms to prevent log forging, although they allow you to create a custom formatter to replace the new lines.

Let’s see some examples

Java

Log4j have built-in mechanisms to help prevent log forging. Unfortunately is up to the developer to specify them. And if you’re a developer looking in google how to use these libraries, nobody tell you to use it…

When configuring the log pattern in the log config file there’s a placeholder called encode that can be used to automatically encode new lines:

log4j.appender.stdout.layout.ConversionPattern=%encode{%m}%n

SLF4J

SLF4J doens’t have a default protection but, you can create a custom conversion rule to sanitise new lines, and configure the log pattern with that rule.

C#

Log4net doesn’t have a default protection either, but as slf4j you can create a custom pattern convertor to replace new lines. You can read more about it here.

Node

In node, with Winston, if you go with the JSON format it is safely serialised. But if you chose to use the simple format (one line per entry), you don’t have a built in way to protect log forging, but you can create a custom format rule.

Rails

For rails, the default library doesn’t offer any protection either. In the same way as in the other scenarios a custom formatter can be created to sanitise the user input:

class SafeFormatter < ::Logger::Formatter
  def call(severity, timestamp, progname, msg)
    "#{msg.gsub(/\n/, "\\n")}\n"
  end
end

Then set the formatter as the log formatter in “config.log_formatter” property in config/environment/*

Go

And for go, logrus was actually the only logger that I tested so far that by default sanitised new lines, no config needed, nothing. Kudos.

I’m not a Go dev so I didn’t test it a lot, but being safe by default is a huge win IMO.

TL;DR

  • Attackers can fake log entries, leading to bad triages or fixes
  • Log forging is hard to exploit if you don’t know the format of the log
    • Bigger issue for open source and on prom software
    • Less relevant for closed source online services (completely blind attacks)
  • Log viewers can also be leveraged to exploit the vulnerability, and worst case scenario cause XSS
  • JSON formatted logs have a different attack vector
  • Usually loggers are unsafe and is up to the developer to create a protection
  • Protections can usually be done by custom formatters
ClZHaGxVMlZqZFhKcGRIbFdZWFZzZEVobGNrWnZjbGx2ZFZSb1pWTmxZM1ZwZEhsV1lYVnNkRWhsY21WR2IzSlpiM1ZVYUdWVFkzVnlhWFI1Vm1GMWJIUklaWEpsUm05eVdXOTFWR2hsVTJWamRYSnBkSGxXWVhWc2RFaGxaVVp2Y2xsdmRWUm9aVk5qZFhKcGRIbFdZWFZzZEVobGNtVkdiM0paYjNWVWFGTmxZM1Z5YVhSNVZtRjFiSFJJWlhKbFJtOXlXVzkxVkdobFUyVmpkWEpwZEhsV1lYVnNkRWhsY21WdmNsbHZkVlJvWlZObFkzVnlhWFI1Vm1GMWJIUkljbVZHYjNKWmIzVlVhR1ZUWldOMWNuUjVWbUYxYkhSSVpYSmxSbTl5V1c5MVZHaGxVMlZqZFhKcGRIbFdZWFZzZEVobGNrWnZjbGx2ZFZSb1pWTmxZM1Z5YVhSNVZtRjFiSFJJWlhKbFJtOXlXWFZVYUdWVFpXTjFjbWwwZVZaaGRXeDBTR1Z5WlVaeVdXOTFhR1ZUWldOMWNtbDBlVlpoZFd4MFNHVnlaVVp2Y2xsdmRWUm9aVk5sWTNWeWFYUjVWbUYxYkhSSVpYSmxiM0paYjNWVWFHVlRaV04xY21sMGVXRjFiSFJJWlhKbFJtOXlXVzkxVkdobFUyVmpkWEpwZEhsV1lYVnNkRWhsY2tadmNsbHZkUT09