Empowering Weak Primitives: File Truncation to Code Execution With Git
Empowering Weak Primitives: File Truncation to Code Execution With Git
In this article, SonarSource's R and D team discusses how they discovered a code vulnerability that allows you to truncate arbitrary files to execute arbitrary commands!
During recent security research, I came up with a fun "trick" that I later shared in a Capture the Flag challenge for the Hack.lu CTF and my Code Security Advent Calendar. I received good feedback and wanted to share the details with a broader audience.
Let's say that you discovered a code vulnerability that allows you to truncate arbitrary files. It sounds like a pretty weak exploitation primitive, but if you are dealing with an application that involves operations on a Git repository under your control, you're in luck!
The Vulnerable Snippet
For example, let's use the code snippet of Day 16 of this year's Code Security Advent Calendar. It implements a service that allows cloning an arbitrary Git repository and later running git blame on specific files and lines.
challenge.py
Exploiting argument injection vulnerabilities depends heavily on the features offered by the invoked binary.
For instance, if a hypothetic program supports the option --output=foo that writes the program output to the file foo, attackers who can inject this argument could create new files or overwrite existing ones. The attacker's goal is usually to gain the ability to execute arbitrary code on the server, and such primitives are very powerful but also quite rare.
Finding an Interesting Argument
Let's get back to the code snippet, where I can add new arguments to the git blame invocation.
After looking at the manual of git-blame, I couldn't find any "interesting" option to execute arbitrary code. Most arguments alter the behavior of the blame process or the way it renders its output. Most importantly, the manual does not document the presence of the option --output, which is usually present on other git sub-commands.
It is then surprising to see this behavior when running git blame --output=foo; notice the presence of a new file named foo:
Comments