Arbitrary Configuration Injection

You are reading Sim4n6's newsletter, a publication designed for ethical hackers. Each issue features a selected vulnerability-related topic for the best of our learning experience.

This edition is about Arbitrary Configuration Injection.

What is an arbitrary configuration injection?

Setting values in a user configuration file without adequately sanitizing user input may permit an attacker to inject new keys and values.

Example

Suppose a user input reaches the configuration file as in INJECTION.

# A configuration file

[section1]
key1 = INJECTION

If the user input was written unsanitized to the configuration file, it may contain a carriage return \r . It may permit the breaking of a line in the configuration file. Thus, the injection of a new key/value association.

The payload would be:

key = INJECTION\rNEW__KEY = NEW__VALUE

The injection location is not always a value in the configuration file. It could be a section name or a key.

Vulnerable web application

The following Python code represents a vulnerable web application with two endpoints: One for updating the configuration file and the other for reading the same configuration file.

from flask import Flask, request, jsonify
import configparser

app = Flask(__name__)


@app.route("/update-config", methods=["POST"])
def update_config():
    try:
        # Create a sample configuration file
        config = configparser.ConfigParser()
        config.read("config.ini")

        # Get the value from the request JSON data
        data = request.get_json()
        new_value = data.get("new_value")

        # Update the configuration file
        config["section_name"]["key_name"] = new_value
        with open("config.ini", "w") as configfile:
            config.write(configfile)

        return jsonify({"message": "Configuration updated successfully"})
    except Exception as e:
        return jsonify({"error": str(e)})


@app.route("/read-config", methods=["GET"])
def read_config():
    try:
        # Read a configuration file
        config = configparser.ConfigParser()
        config.read("config.ini")

        # Read the configuration file and convert it to a dictionary
        config_dict = {section: dict(config[section]) for section in config.sections()}

        return jsonify(config_dict)
    except Exception as e:
        return jsonify({"error": str(e)})


if __name__ == "__main__":
    app.run(debug=True)

The screenshot displays the config.ini file before and after using the previous payload. You can notice the injection of a new key and a new value.

An Arbitrary Configuration Injection

Level up the impact

Under some circumstances, this may result in an arbitrary command execution.

  1. Consider a web application that retrieves a user input from an HTTP POST request and writes the unsanitized value directly to a user's configuration file. Arbitrary configuration injection is possible.

  2. Consider a case where the configuration values permit the mention of executables, like in a key for core.pager, or sshCommand.

  3. It would be possible to trick the application into remote command execution by injecting a payload as such old_value\rcore.pager=less;whoami into the configuration file.

References:

Thank you for reading this issue.
@Sim4n6