CVE-2019-16278 - Unauthenticated Remote Code Execution in Nostromo web server

Welcome to my blog!

In this post, I will analyze CVE-2019-16278, how to exploit and why it vulnerable. This CVE is about the Nostromo web server, aka nhttpd, an open-source web server that is very popular on Unix system like FreeBSD, OpenBSD,...

Nostromo fails to verify a URL that leads to path traversal to any file in the system. An unauthenticated attacker can force the server points to a shell file like /bin/sh and execute arbitrary commands. It's critical due to all Nostromo's versions, include the lasted release 1.9.6, are vulnerable. Even its developers' website,, is exploitable.

In the past, Nostromo had also a path traversal which could lead to unauthenticated remote code execution named CVE-2011-0751. The web server checked for the string /../ before decoded escaped characters in the URI and the RedTeam Pentesting GmbH found it. They just encoded the character / to %2f and passed it to the server like this:

Although Nostromo fixed CVE-2011-0751 in version 1.9.4 by decoding escaped characters before checking for the string /../, it's still bypassed by sp0re and we have CVE-2019-16278, the return of path traversal in Nostromo.

Exploit in the wild:

Searching on Shodan, you can find about 2000 Nostromo web servers exposed to the Internet by using the query:
"Server: nostromo"

Let's use my PoC written in Python to check some servers. In fact, all of them are vulnerable,.

If you look at my exploit, you can see I send a request with /.%0d./.%0d./.%0d./.%0d./bin/sh in the URI. Compare to CVE-2011-0751, I just change %2f to %0d, which is not checked by Nostromo. You may wonder how the system can traverse to the upper directory by a path contains the carriage return (CR) like this .%0d./.%0d./, instead of ../../. Actually, the system receives ../../ without any CR characters. So, where those CR characters have gone?
Let's take a look at the source code of Nostromo version 1.9.6.


First, when a request header comes, it is verified and then processed.

In the function http_verify(), the header is URL decoded and then check for the existing of /../.  The header now will be: /.\r./.\r./.\r./.\r./bin/sh.

Next, in the function http_proc(), the header is passed to the function http_header().

The root cause is here, in the function http_header(), it parses the header by the function strcutl().

Take a look inside the function strcutl(), you can see it take a string and return it with \r (carriage return) is cut off.

Now the path is  /../../../../bin/sh. So, the path traversal part is done, how it can be executed?
Because of the function execve() in the function http_proc(). It executes rh->rq_filef, which is indeed the path /../../../../bin/sh.

Now, we have a path traversal to RCE!

If you find it valuable, please share it with other people.
If you have any questions, please don't hesitate to ask me on Twitter or leave a comment.
Thank you for reading!


  1. I am unable to execute the payload .. it is showing unexpected token '('

    1. Could you give me more information about your case?
      I don't understand the context of "unexpected token '('".

      Did you check the target Nostromo's version whether it's vulnerable?
      Only Nostromo version 1.9.6 and before are exploitable.


Post a Comment