The finding said RCE. The second tester asked one question and the ticket died.
Last year I inherited a “critical RCE” from an automated pass. The request looked perfect. Parameter host. Payload 8.8.8.8; sleep 5. Status 200. Response time jumped from ~800ms to ~6s. The scanner wrote OS command injection, confidence high. The client had already seen the word critical in the draft. I replayed it once. Same delay. Replay again. 1.1s. Again. 7s. Again. 900ms. The sleep was not in the response body. id came back as the literal string id. expr 41 + 1 came back as the literal string. The page was a diagnostics form. It echoed the query and, under load, the WAF in front of it spent extra time on anything that looked like a shell metacharacter. That is a known failure mode, not a rare one. Time-based command-injection checks fire when the response is merely slower, which also happens when the scan itself saturates the app, when a WAF inspects a “more suspicious” request, when a CDN queues you, or when the page is just doing a heavier search. SANS has been writing this up for years: ping -c 20 127.0.0.1 during a busy scan is not proof. ZAP’s sleep payloads have the same problem, and in some rules even reflecting the command string is enough to raise the issue. A 200 that contains bash -c is often a docs page, not a shell.  The useful question is not “did a payload land.” It is “what value in this response can only exist if the server evaluated my input?” What I do now, on the same request, before I write the word confirmed: Send a benign twin. Same cookies, same content-type, same parameter, no metacharacters. That is the control. If the “interesting” string is already there, stop. That is echo, not execution. Do not ask the server to say whoami. Ask it to compute something it has never seen. Two random integers, added, wrapped in canaries that are also random for that probe. If the body contains the sum and the control does not, you have a result that reflection cannot invent. If there is no output channel, do not promote a single slow request. Change the delay. Plot it. If 3 / 7 / 11 seconds do not track the payload, it is jitter or a WAF. PortSwigger has a nice version of this trap: an exec-looking parameter delayed because the WAF worked harder, not because a binary ran.  A DNS callback is a sink, not a shell. Collaborator lighting up after you plant a URL is often a link previewer, a safe-browsing fetch, or a JNDI lookup that never loaded a class. Fastjson / Log4j writeups on here keep dying at that step: four DNS hits, zero command. Say lookup. Do not say RCE until a value only the target could have computed comes back, or you have a class-load you can show. If your flags never built a probe for that sink, the result is not negative. It is untested. I have watched people paste “not vulnerable” into a report because the scanner used shell separators against an OGNL parameter. Struts will happily evaluate %{7*7} and still return nothing useful to ; id. Wrong claim, clean-looking ticket. The ticket I inherited was closed as a false positive in fifteen minutes once the control existed. The next one, on a lab Webmin box, survived because the response contained a sum the request never sent. Same scanner family. Different question. If you only remember one thing from this: before you file P1, ask whether a second person can reproduce a value, not a delay. Triage queues are full of the second kind. That is why “not reproducible” shows up on reports that felt obvious at 1 a.m. I later wrapped the control + random-arithmetic check into a small stdlib-only helper so I would stop doing it by hand on jump boxes. That is not the point of the post. The point is the question. If you want the benches against Webmin / Struts2 / a Log4j lookup so you can disagree with the verdict names, I will drop the repo in a comment. submitted by /u/No-View3333 [link] [comments]Technical Information Security Content & DiscussionRead More