hacktricks/pentesting-web/race-condition.md

373 lines
22 KiB
Markdown
Raw Normal View History

2023-08-03 19:12:22 +00:00
# 竞争条件
2022-04-28 16:01:33 +00:00
<figure><img src="../.gitbook/assets/image (3) (1) (1).png" alt=""><figcaption></figcaption></figure>
2022-08-31 22:35:39 +00:00
\
2023-08-03 19:12:22 +00:00
使用[**Trickest**](https://trickest.com/?utm\_campaign=hacktrics\&utm\_medium=banner\&utm\_source=hacktricks)轻松构建和自动化由全球**最先进**的社区工具提供支持的工作流程。\
立即获取访问权限:
2022-08-31 22:35:39 +00:00
{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}
2022-04-28 16:01:33 +00:00
<details>
2023-04-25 18:35:28 +00:00
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
2022-04-28 16:01:33 +00:00
* 你在**网络安全公司**工作吗你想在HackTricks中看到你的公司广告吗或者你想获得PEASS的**最新版本或下载PDF格式的HackTricks**吗?查看[**订阅计划**](https://github.com/sponsors/carlospolop)
2023-08-03 19:12:22 +00:00
* 发现我们的独家[**NFTs**](https://opensea.io/collection/the-peass-family)收藏品[**The PEASS Family**](https://opensea.io/collection/the-peass-family)
* 获取[**官方PEASS和HackTricks周边产品**](https://peass.creator-spring.com)
* **加入**[**💬**](https://emojipedia.org/speech-balloon/) [**Discord群组**](https://discord.gg/hRep4RUj7f)或[**电报群组**](https://t.me/peass),或在**Twitter**上**关注**我[**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**。**
* **通过向**[**hacktricks repo**](https://github.com/carlospolop/hacktricks) **和**[**hacktricks-cloud repo**](https://github.com/carlospolop/hacktricks-cloud) **提交PR来分享你的黑客技巧。**
2022-04-28 16:01:33 +00:00
</details>
## 利用竞争条件
滥用竞争条件的主要问题是需要请求在非常短的时间差内并行处理(通常>1ms。在下一节中提出了不同的解决方案以实现这一点。
<figure><img src="../.gitbook/assets/image (5) (1).png" alt=""><figcaption></figcaption></figure>
### 单数据包攻击HTTP/2/ 最后一个字节同步HTTP/1.1
HTTP2允许在**单个TCP连接**中发送**2个请求**而在HTTP/1.1中,它们必须是顺序的)。\
使用单个TCP数据包完全**消除了网络抖动的影响**,因此这对于竞争条件攻击也具有潜力。然而,**两个请求对于可靠的竞争攻击来说是不够的**,这要归功于**服务器端抖动** - 应用程序请求处理时间的变化由于CPU争用等不可控变量引起。
但是使用HTTP/1.1的'**最后一个字节同步**'技术可以预先发送大部分数据并保留每个请求的一个小片段然后使用一个单个TCP数据包'完成'**20-30个请求**。
要**预先发送每个请求的大部分数据**
- 如果请求没有主体请发送所有标头但不设置END\_STREAM标志。保留一个带有设置了END\_STREAM的空数据帧。
- 如果请求有主体,请发送标头和除最后一个字节之外的所有主体数据。保留一个包含最后一个字节的数据帧。
接下来,**准备发送最后的帧**
- 等待100ms以确保初始帧已发送。
- 确保禁用TCP\_NODELAY - Nagle算法批处理最后的帧至关重要。
- 发送一个ping数据包以预热本地连接。如果不这样做操作系统的网络堆栈将把第一个最后的帧放在一个单独的数据包中。
最后发送被保留的帧。您应该能够使用Wireshark验证它们是否落在一个单独的数据包中。
{% hint style="info" %}
请注意,这**对于某些服务器上的静态文件不起作用**,但静态文件对于竞争条件攻击是无关紧要的。
{% endhint %}
使用这种技术您可以使20-30个请求同时到达服务器 - 不受网络抖动的影响:
<figure><img src="../.gitbook/assets/image (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png" alt=""><figcaption></figcaption></figure>
**适应目标架构**
值得注意的是,许多应用程序位于前端服务器后面,这些服务器可能决定将某些请求转发到后端的现有连接,并为其他请求创建新的连接。
因此,重要的是不要将不一致的请求时间归因于应用程序行为,例如只允许单个线程同时访问资源的锁定机制。此外,前端请求路由通常是基于每个连接的,因此您可以通过在攻击之前在服务器端进行连接预热 - **在连接上发送几个无关紧要的请求**(这只是在开始实际攻击之前发送几个请求)来平滑请求时间。
#### 基于会话的锁定机制 <a href="#session-based-locking-mechanisms" id="session-based-locking-mechanisms"></a>
一些框架尝试通过使用某种形式的**请求锁定**来防止意外数据损坏。例如,**PHP的本机会话处理程序**模块一次只处理**一个会话的请求**。
发现此类行为非常重要,因为否则它可能掩盖了可以轻松利用的漏洞。如果注意到所有请求都按顺序处理,请尝试使用不同的会话令牌发送每个请求。
#### **滥用速率或资源限制**
如果连接预热没有任何效果,有多种解决方案可解决此问题。
使用Turbo Intruder您可以引入短暂的客户端延迟。然而由于这涉及将实际攻击请求分割成多个TCP数据包您将无法使用单数据包攻击技术。因此在高抖动目标上无论您设置了什么延迟攻击都不太可能可靠地工作。
<figure><img src="../.gitbook/assets/image (2) (1) (1) (1) (1) (1) (1) (1) (1).png" alt=""><figcaption></figcaption></figure>
相反,您可以通过滥用常见的安全功能来解决此问题。
Web服务器通常会**延迟处理请求,如果发送得太快**。通过发送大量的虚拟请求来故意触发速率或资源限制,您可能会导致适当的服务器端延迟。这使得即使需要延迟执行,单数据包攻击也是可行的。
<figure><img src="../.gitbook/assets/image (3) (1) (1) (1) (1).png" alt=""><figcaption></figcaption></figure>
{% hint style="warning" %}
有关此技术的更多信息,请查看原始报告[https://portswigger.net/research/smashing-the-state-machine](https://portswigger.net/research/smashing-the-state-machine)
{% endhint %}
#### 攻击示例
* **Tubo Intruder - HTTP2单数据包攻击1个端点**:您可以将请求发送到**Turbo intruder**`Extensions` -> `Turbo Intruder` -> `Send to Turbo Intruder`),您可以在请求中更改要暴力破解的值**`%s`**,例如`csrf=Bn9VQB8OyefIs3ShR2fPESR0FzzulI1d&username=carlos&password=%s`,然后从下拉菜单中选择**`examples/race-single-packer-attack.py`**
<figure><img src="../.gitbook/assets/image (4) (1) (1) (1).png" alt=""><figcaption></figcaption></figure>
如果您要**发送不同的值**,您可以使用以下代码,该代码使用剪贴板中的字典文件:
```python
passwords = wordlists.clipboard
for password in passwords:
engine.queue(target.req, password, gate='race1')
```
{% hint style="warning" %}
如果网站不支持HTTP2只支持HTTP1.1),请使用`Engine.THREADED`或`Engine.BURP`代替`Engine.BURP2`。
{% endhint %}
* **Tubo Intruder - HTTP2单数据包攻击多个端点**如果您需要向一个端点发送请求然后向其他端点发送多个请求以触发RCE您可以将`race-single-packet-attack.py`脚本更改为以下内容:
```python
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint,
concurrentConnections=1,
engine=Engine.BURP2
)
# Hardcode the second request for the RC
confirmationReq = '''POST /confirm?token[]= HTTP/2
Host: 0a9c00370490e77e837419c4005900d0.web-security-academy.net
Cookie: phpsessionid=MpDEOYRvaNT1OAm0OtAsmLZ91iDfISLU
Content-Length: 0
'''
# For each attempt (20 in total) send 50 confirmation requests.
for attempt in range(20):
currentAttempt = str(attempt)
username = 'aUser' + currentAttempt
# queue a single registration request
engine.queue(target.req, username, gate=currentAttempt)
# queue 50 confirmation requests - note that this will probably sent in two separate packets
for i in range(50):
engine.queue(confirmationReq, gate=currentAttempt)
# send all the queued requests for this attempt
engine.openGate(currentAttempt)
```
* 它还可以通过Burp Suite中的新的“并行发送组”选项在Repeater中使用。
* 对于limit-overrun您可以在组中添加相同的请求50次。
* 对于连接预热您可以在组的开头添加一些请求到Web服务器的非静态部分。
* 对于在两个子状态步骤之间延迟处理一个请求和另一个请求,您可以在两个请求之间添加额外的请求。
* 对于多端点的RC您可以开始发送到隐藏状态的请求然后在其后发送50个利用隐藏状态的请求。
<figure><img src="../.gitbook/assets/image (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png" alt=""><figcaption></figcaption></figure>
### 原始BF
在之前的研究中这些是一些用于尝试尽快发送数据包以引发RC的有效载荷。
* Repeater请参考前一节中的示例。
* Intruder将请求发送到Intruder将线程数设置为30在选项菜单中选择Null有效载荷并生成30个。
* Turbo Intruder
```python
def queueRequests(target, wordlists):
2023-08-03 19:12:22 +00:00
engine = RequestEngine(endpoint=target.endpoint,
concurrentConnections=5,
requestsPerConnection=1,
pipeline=False
)
a = ['Session=<session_id_1>','Session=<session_id_2>','Session=<session_id_3>']
for i in range(len(a)):
engine.queue(target.req,a[i], gate='race1')
# open TCP connections and send partial requests
engine.start(timeout=10)
engine.openGate('race1')
engine.complete(timeout=60)
def handleResponse(req, interesting):
2023-08-03 19:12:22 +00:00
table.add(req)
```
* **Python - asyncio**
2023-08-03 19:12:22 +00:00
Python的asyncio模块
2022-10-11 22:51:42 +00:00
```python
import asyncio
import httpx
async def use_code(client):
2023-08-03 19:12:22 +00:00
resp = await client.post(f'http://victim.com', cookies={"session": "asdasdasd"}, data={"code": "123123123"})
return resp.text
2022-10-11 22:51:42 +00:00
async def main():
2023-08-03 19:12:22 +00:00
async with httpx.AsyncClient() as client:
tasks = []
for _ in range(20): #20 times
tasks.append(asyncio.ensure_future(use_code(client)))
# Get responses
results = await asyncio.gather(*tasks, return_exceptions=True)
# Print results
for r in results:
print(r)
# Async2sync sleep
await asyncio.sleep(0.5)
print(results)
2022-10-11 22:51:42 +00:00
asyncio.run(main())
```
## **RC方法论**
### 限制超出/TOCTOU
这是最基本的一种竞争条件,其中**漏洞**出现在**限制您执行某个操作的次数的地方**。比如在网店中多次使用相同的折扣码。一个非常简单的例子可以在[**这份报告**](https://medium.com/@pravinponnusamy/race-condition-vulnerability-found-in-bug-bounty-program-573260454c43)或者[**这个漏洞**](https://hackerone.com/reports/759247)**中找到**。
这种攻击有很多变种,包括:
* 多次兑换礼品卡
* 多次评价产品
* 超出账户余额提取或转账
* 重复使用单个验证码解决方案
* 绕过反暴力破解速率限制
### **隐藏的子状态**
其他最复杂的竞争条件将利用机器状态中的**子状态**,这可能允许攻击者滥用他本不应该访问的状态,但攻击者有一个**小窗口**可以访问它。
1. **预测潜在的隐藏和有趣的子状态**
第一步是识别所有写入它或从中读取数据并将该数据用于某些重要事项的端点。例如,用户可能存储在一个数据库表中,该表通过注册、配置文件编辑、密码重置启动和密码重置完成进行修改。
我们可以使用三个关键问题来排除不太可能引起冲突的端点。对于每个对象和相关的端点,问:
* **状态是如何存储的?**
存储在持久的服务器端数据结构中的数据非常适合利用。某些端点将其状态完全存储在客户端例如通过电子邮件发送JWT的密码重置 - 这些可以安全地跳过。
应用程序通常会在用户会话中存储一些状态。这些通常在一定程度上受到子状态的保护 - 关于此后面会有更多介绍。
* **我们是在进行编辑还是追加操作?**
对现有数据进行编辑的操作(例如更改帐户的主电子邮件地址)具有充足的冲突潜力,而仅仅追加到现有数据的操作(例如添加额外的电子邮件地址)不太可能受到除了限制超出攻击之外的任何漏洞。
2022-10-11 22:51:42 +00:00
* **操作的键是什么?**
大多数端点都是在特定记录上操作的,该记录是使用“键”查找的,例如用户名、密码重置令牌或文件名。为了成功攻击,我们需要使用相同的键进行两个操作。例如,想象两个合理的密码重置实现:
<figure><img src="../.gitbook/assets/image (2) (1) (1) (1) (1) (1) (1) (1) (1) (1).png" alt=""><figcaption></figcaption></figure>
2. **寻找线索**
此时是时候对潜在有趣的端点发起一些RC攻击以尝试找到与常规响应不同的意外结果。任何与预期响应的改变如一个或多个响应的变化或者第二阶效应如电子邮件内容的不同或会话中的可见变化都可能是指示出现问题的线索。
3. **验证概念**
最后一步是**验证概念并将其转化为可行的攻击**。
当您发送一批请求时,您可能会发现早期的请求对一个易受攻击的最终状态进行了触发,但后来的请求覆盖/使其无效,最终状态无法利用。在这种情况下,您将希望消除所有不必要的请求 - 两个请求应足以利用大多数漏洞。然而,减少到两个请求将使攻击更加时间敏感,因此您可能需要多次重试攻击或自动化攻击。
### 时间敏感攻击
有时您可能找不到竞争条件,但是**以精确的时间传递请求的技术**仍然可以揭示其他漏洞的存在。
一个例子是当使用**高分辨率时间戳**而不是加密安全的随机字符串来生成安全令牌时。
考虑一个仅使用时间戳进行随机化的**密码重置令牌**。在这种情况下,可能可以**触发两个不同用户的两个密码重置**,它们都使用**相同的令牌**。您只需要计时请求,以使它们生成相同的时间戳。
{% hint style="warning" %}
要确认前面的情况,您只需同时请求**2个重置密码令牌**(使用单个数据包攻击),并检查它们是否**相同**。
{% endhint %}
在[**这个实验**](https://portswigger.net/web-security/race-conditions/lab-race-conditions-exploiting-time-sensitive-vulnerabilities)中检查示例。
## 隐藏的子状态案例研究
### 支付并添加商品
[**查看此实验**](https://portswigger.net/web-security/logic-flaws/examples/lab-logic-flaws-insufficient-workflow-validation)以了解如何在商店中**支付**并**添加一个额外的**商品,而无需为其付款。
### 确认其他电子邮件
这个想法是**同时验证一个电子邮件地址并将其更改为另一个地址**,以查看平台是否验证了新的更改后的地址。
### 将电子邮件更改为2个电子邮件地址基于Cookie
根据[**这篇文章**](https://portswigger.net/research/smashing-the-state-machine)Gitlab容易受到这种方式的接管因为它可能会将一个电子邮件的**电子邮件验证令牌发送到另一个电子邮件**。
您还可以查看[**这个实验**](https://portswigger.net/web-security/race-conditions/lab-race-conditions-single-endpoint)以了解更多信息。
### 隐藏的数据库状态/确认绕过
如果使用**2个不同的写入**将**信息添加**到**数据库**中,那么在**只有第一个数据被写入**数据库的一小段时间内。例如,创建用户时,**用户名**和**密码**可能会被**写入**,然后写入用于确认新创建的帐户的**令牌**。这意味着在短时间内**确认帐户的令牌为空**。
因此,**注册一个帐户并发送多个带有空令牌**`token=`或`token[]=`或任何其他变体)的请求来立即确认帐户,可以允许确认一个您无法控制电子邮件的帐户。
在[**这个实验**](https://portswigger.net/web-security/race-conditions/lab-race-conditions-partial-construction)中检查一个示例。
### 绕过2FA
以下伪代码演示了一个网站如何容易受到这种攻击的竞争变体的影响:
```python
def login(username, password):
if verify_credentials(username, password):
if not is_2fa_enabled(username):
return "Login successful"
else:
token = generate_2fa_token()
send_2fa_token(username, token)
return "Please enter 2FA token"
else:
return "Invalid credentials"
def verify_2fa_token(username, token):
if is_2fa_enabled(username):
stored_token = get_stored_2fa_token(username)
if token == stored_token:
return True
else:
return False
else:
return False
def process_login(username, password, token):
if verify_credentials(username, password):
if verify_2fa_token(username, token):
return "Login successful"
else:
return "Invalid 2FA token"
else:
return "Invalid credentials"
```
在这个示例中攻击者可以利用竞争条件来绕过2FA验证。攻击者可以在发送2FA令牌之后但在验证令牌之前尽快完成登录过程从而绕过2FA验证。这种攻击的成功取决于攻击者能够在验证令牌之前完成登录过程。
```python
session['userid'] = user.userid
if user.mfa_enabled:
session['enforce_mfa'] = True
# generate and send MFA code to user
# redirect browser to MFA code entry form
```
正如你所看到的,这实际上是一个**在单个请求的范围内的多步骤序列**。最重要的是,它会在一个子状态中**临时拥有有效的登录会话但尚未强制执行MFA**。攻击者可以通过发送登录请求以及对敏感的经过身份验证的端点的请求来利用这一点。
### OAuth2永久持久性
有几个[**OAuth提供者**](https://en.wikipedia.org/wiki/List\_of\_OAuth\_providers)。这些服务将允许您创建一个应用程序并对提供者注册的用户进行身份验证。为了做到这一点,**客户端**将需要**允许您的应用程序**访问**OAuth提供者**内部的一些数据。\
所以到目前为止只是一个常见的与Google/LinkedIn/GitHub等登录您会看到一个页面上面写着“_应用程序\<InsertCoolName>想要访问您的信息您是否允许_”
2023-08-03 19:12:22 +00:00
#### `authorization_code`中的竞争条件
**问题**出现在您**接受并自动发送一个`authorization_code`**给恶意应用程序时。然后,该**应用程序滥用OAuth服务提供者中的竞争条件从`authorization_code`为您的帐户生成多个AT/RT**(身份验证令牌/刷新令牌)。基本上,它会滥用您已经接受应用程序访问您的数据的事实,以**创建多个帐户**。然后,如果您**停止允许应用程序访问您的数据一个AT/RT对将被删除但其他对仍然有效**。
2023-08-03 19:12:22 +00:00
#### `Refresh Token`中的竞争条件
一旦您**获得了一个有效的RT**,您可以尝试**滥用它来生成多个AT/RT**,即使用户取消了恶意应用程序访问其数据的权限,**多个RT仍然有效**。
## WebSockets中的竞争条件
在[**WS\_RaceCondition\_PoC**](https://github.com/redrays-io/WS\_RaceCondition\_PoC)中您可以找到一个Java的PoC用于以**并行**方式发送websocket消息以滥用**WebSockets中的竞争条件**。
2023-08-03 19:12:22 +00:00
## 参考资料
* [https://hackerone.com/reports/759247](https://hackerone.com/reports/759247)
* [https://pandaonair.com/2020/06/11/race-conditions-exploring-the-possibilities.html](https://pandaonair.com/2020/06/11/race-conditions-exploring-the-possibilities.html)
* [https://hackerone.com/reports/55140](https://hackerone.com/reports/55140)
* [https://portswigger.net/research/smashing-the-state-machine](https://portswigger.net/research/smashing-the-state-machine)
* [https://portswigger.net/web-security/race-conditions](https://portswigger.net/web-security/race-conditions)
2022-04-28 16:01:33 +00:00
<details>
2023-04-25 18:35:28 +00:00
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
2022-04-28 16:01:33 +00:00
* 你在**网络安全公司**工作吗你想在HackTricks中看到你的**公司广告**吗或者你想获得最新版本的PEASS或下载PDF格式的HackTricks吗查看[**订阅计划**](https://github.com/sponsors/carlospolop)
* 发现我们的独家[NFT](https://opensea.io/collection/the-peass-family)收藏品[**The PEASS Family**](https://opensea.io/collection/the-peass-family)
* 获取[**官方PEASS和HackTricks衣物**](https://peass.creator-spring.com)
* **加入**[**💬**](https://emojipedia.org/speech-balloon/) [**Discord群组**](https://discord.gg/hRep4RUj7f)或[**电报群组**](https://t.me/peass),或在**Twitter**上**关注**我[**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**。**
* **通过向**[**hacktricks repo**](https://github.com/carlospolop/hacktricks) **和**[**hacktricks-cloud repo**](https://github.com/carlospolop/hacktricks-cloud) **提交PR来分享您的黑客技巧。**
2022-04-28 16:01:33 +00:00
</details>
<figure><img src="../.gitbook/assets/image (3) (1) (1).png" alt=""><figcaption></figcaption></figure>
2022-08-31 22:35:39 +00:00
\
使用[**Trickest**](https://trickest.com/?utm\_campaign=hacktrics\&utm\_medium=banner\&utm\_source=hacktricks)可以轻松构建和**自动化工作流程**,使用全球**最先进**的社区工具。\
2023-08-03 19:12:22 +00:00
立即获取访问权限:
2022-04-28 16:01:33 +00:00
2022-08-31 22:35:39 +00:00
{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}