Skip to main content

Log injection

Need

Prevention of log injection attacks

Context

  • Usage of Swift for iOS and macOS app development
  • Usage of UIKit for building modern and responsive user interfaces
  • Usage of os.log for logging system events and messages

Description

Non compliant code

import UIKit
import os.log

class ViewController: UIViewController {

@IBOutlet weak var userInput: UITextField!

override func viewDidLoad() {
super.viewDidLoad()
}

@IBAction func logButtonPressed(_ sender: Any) {
os_log("%@", type: .debug, userInput.text!)
}
}

In the above Swift code, a ViewController class is defined for an iOS application. This class has a UITextField userInput and a function logButtonPressed(_:) that logs the text entered in the userInput field.

The vulnerability lies in the logButtonPressed(_:) function, where the os_log function is used to log the user's input directly without any validation, sanitization, or escaping.

The os_log function accepts a format string and arguments, similar to printf. In this case, the format string is "%@", which means the function will interpret the user input as a string and log it.

If an attacker can provide input that is interpreted as a control sequence by the log viewer, they could inject malicious content into the log. For example, they might provide input that causes the log viewer to execute arbitrary code or to write arbitrary data to an arbitrary location. This is known as a log injection attack.

To fix this vulnerability, you should sanitize and validate all user inputs before logging them. Sanitization could involve escaping any control sequences in the user input, while validation could involve checking that the user input does not contain any unexpected characters.

Steps

  • Validate and sanitize user input before logging it
  • Use a logging framework that automatically escapes user input
  • Avoid logging sensitive information
  • Implement proper access controls to restrict who can view the logs

Compliant code

import UIKit
import os.log

class ViewController: UIViewController {

@IBOutlet weak var userInput: UITextField!

override func viewDidLoad() {
super.viewDidLoad()
}

@IBAction func logButtonPressed(_ sender: Any) {
guard let userInputText = userInput.text else { return }
let sanitizedInput = sanitize(input: userInputText)
os_log("%@", type: .debug, sanitizedInput)
}

func sanitize(input: String) -> String {
return input.replacingOccurrences(of: "[^a-zA-Z0-9]", with: "", options: .regularExpression)
}
}

The original code was vulnerable to log injection because it directly logged user input without any validation or sanitization. This could allow an attacker to inject malicious content into the logs.

The fixed code includes a sanitize function that removes any non-alphanumeric characters from the user input before logging it. This helps prevent log injection by ensuring that only safe characters are logged.

The sanitize function uses a regular expression ([^a-zA-Z0-9]) to match any characters that are not alphanumeric and replaces them with an empty string. This effectively removes any potentially harmful characters from the user input.

In addition, the fixed code uses optional binding (guard let) to safely unwrap the user input. If the user input is nil, the function returns early and does not attempt to log anything. This helps prevent a potential crash that could occur if the user input is nil.

Finally, it's important to note that this code does not log any sensitive information. Logging sensitive information can expose it to unauthorized individuals who have access to the logs. Therefore, it's best to avoid logging sensitive information whenever possible.

References