This morning, I noticed specific sources "hunting" for vulnerabilities in URLs that I haven't noticed before. All of these URLs appear to be associated with diagnostic tools:
| URL | Count | Vulnerability |
|---|---|---|
| / | 1 | (simple recon for index page) |
| /apply.cgi | 20 | CVE-2024-12856 Four-Faith router command injection |
| /cgi-bin/adv_ping.cgi | 20 | ? |
| /cgi-bin/diagnostic.cgi | 20 | CVE-2013-7179 Seowon Intech WiMAX SWU-9100 mobile route |
| /cgi-bin/DiagnosticsMsg.cgi | 20 | ? |
| /cgi-bin/ping.cgi | 20 | |
| /cgi-bin/system_mgr.cgi | 20 | |
| /cgi-bin/traceroute.cgi | 20 | |
| /diag_ping.cgi | 20 | CVE-2020-8949 (maybe.. slightly different URL) Gocloud devices |
| /goform/diagTool | 20 | CVE-2024-48419 (maybe..) Edimax Routers |
| /goform/ping | 20 | |
| /ping_test.cgi | 20 | |
| /sys_diag.html | 20 |
The naming of these URLs points to diagnostic tools. I was unable to find any specific vulnerabilities associated with many of the URLs, but the table above reflects those I found. But diagnostic tools often suffer from file inclusion and code execution vulnerabilities.
These tools will often call operating system commands directly, without properly separating user-provided arguments. Here is a sample vulnerability in a ping utility:
response = os.system("ping -c 1 -w2 " + hostname )
The above example is in Python. But most (all?) languages have something equivalent to "os.system" (often called "exec", "shell_exec", "process" …) Often, proper input validation and output encoding are used to prevent this vulnerability, but, in my opinion, there is a better approach that should always be used in addition to input validation, and I do not see it used much.
As with many other vulnerabilities, the root cause of command injection is the concatenation of user data and commands. Mixing control plane and data plane has been an issue since blue boxing and continues today with prompt injection. The real fix is to avoid this comingling of data and commands and instead properly separate them. Prepared statements in SQL are probably the best-known approach following this principle.
For OS command execution, we do have a very similar solution. The "system" command in your language will typically call the standard C function "exec" [1]. This family of function implements some meant to pass command line arguments: execv ("exec vector"). In addition to the command, it accepts an array of command-line arguments that are then passed to the command, properly separating the command from the arguments.
Python implements execv as part of the subprocess module:
response = subprocess.run("ping", "-c", 1, "-w", 2, hostname )
Using "subprocess.run" eliminates the possibility of command injection in this example.
For example, if you are using "google.com; ls" as a hostname, you get:
ping: cannot resolve google.com; ls: Unknown host
The entire string "google.com; ls" was used as a hostname, and the ";" no longer acted as a separator. Give it a try with other command injection strings, and you will see similar results.
There are a few cases where "execv" is not sufficient. Some operating system commands may execute additional commands passed on the command line. For example, tcpdump offers the "-z" option to execute a "postrotate command". But these cases are rare, and if you are running into them, you are back to proper input validation to use these specific command line options. In most cases, users cannot specify the command-line option itself but only the parameter; using the "execv" API will help.
A while ago, I also made a brief video with more details on preventing OS command injection: https://www.youtube.com/watch?v=7QDO3pZbum8. It also covers some of the issues around Windows, which implements different APIs.
[1] https://man7.org/linux/man-pages/man3/exec.3.html
—
Johannes B. Ullrich, Ph.D. , Dean of Research, SANS.edu
Twitter|
(c) SANS Internet Storm Center. https://isc.sans.edu Creative Commons Attribution-Noncommercial 3.0 United States License.
Last week I had the joy of participating in Amazon’s “Bring Your Kids to Work Day” with my 7 year old son. We commuted together into the New York City office, his first real rush hour train ride, and spent the day exploring how Amazon uses AI, machine learning, and robotics to deliver packages to customers all over the world. Watching his eyes light up as he saw robots navigating a fulfillment center reminded me why so many of us got into technology in the first place. There’s nothing quite like seeing that sense of wonder when something complex clicks.














