Dynamic payload modification causes Struts vuln misdetection

In the file gb_apache_struts_CVE_2017_5638.nasl used to detect CVE-2017-5638 (one of the most severe Struts CVE and definitely the most popular one following the Equifax breach) there exists a dynamic payload replacement on line 107 that tries to add some scanner identifying info:
ex = "%{(#" + vt_strings["default"] + "='multipart/form-data')

The reference to vt_strings["default"] from misc_func.inc on line 1881 causes this piece of string to be replaced by “OpenVAS-VT” or “GBN-VT” depending if this test is run on the open source version or the Greenbone appliances.

This replacement causes the payload to be modified as such: "%{(#OpenVAS-VT='multipart/form-data')" or "%{(#GBN-VT='multipart/form-data')". By comparison, the “standard/common” payload for a PoC for this CVE starts with "%{(#_='multipart/form-data')" as for instance in https://www.exploit-db.com/exploits/41570.

When Struts interprets this payload the #_ part is actually crucial since it is a variable name, which in Java can’t contain dashes (-) as per the Java spec: https://docs.oracle.com/javase/tutorial/java/nutsandbolts/variables.html

This means that with this dynamic replacement the payload fails at executing, and hence the detection of CVE-2017-5638 doesn’t take place (false negative). Modifying the payload to remove the dynamic replacement fixes this.

There might be other Struts vulns detection that have a similar issue.


Thanks for reporting this! This slipped into it after some recent changes. A fixed version will be available in one of the next feed updates.


Please do tell whether the fix is working for you, it should arrive tomorrow. :slight_smile:

Thanks, it should probably be tested against Docker vulnerable containers such as this one that encompasses multiple Struts CVEs: https://hub.docker.com/r/2d8ru/struts2

Generally speaking I think this is a good case against building dynamic payloads when unecessary for testing: some exploit-based testing need very precise conditions to work and any modification has to be tested completely (this is pretty much the reason why metasploit got to exist in the first place).

One other thing I want to bring to your attention is the fact that this dynamic exploit changes the payload from a Linux command to a Windows command based on OS detection. This is generally fine since OpenVAS does a fairly good job at OS detection, but in the case of this test it might be a mistake:

The commands run to test this end up in exploit_commands that gets set from misc_func.inc but the logic there is to treat the default (unknown) OS as if it was Windows (line 1624).
That’s the opposite from the standard exploit, that relies on the JVM to analyze if it’s Windows and if not, assumes Linux:

    payload += "(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win')))."
    payload += "(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd}))."

In the case of Apache/Struts, there is a much higher chance that it runs on Linux than Windows (probably more than 95% of the case), and as such the default behaviour of OpenVAS when unable to identify the OS would send a wrong command that would cause a false-negative.

All this to say that you should probably consider changing the payload to something that looks more like the standard/common one, or maybe run both commands if unsure of the OS (not going to make a big difference performance-wise).


Actually this is not correct. In this case exploit_commands is not called with any argument, so it will try to determine what OS is running on the target (res = host_runs( "windows" ); will do that).
So if the OS was detected beforehand it will set/return the appropriate payload. If it is unknown, both payloads (for Windows and Linux) will be tried.


Thanks for the clarification, I hadn’t looked in detail at the code in host_runs() and I assumed it was a yes/no thing, I see now it can be “unknown”, causing the array returned by exploit_commands() to include both testing commands. Good to know!