从客户端加密到签名伪造、支付一分钱买下32元服务|金额篡改漏洞完整挖掘实录

admin 2026-05-17 04:28:11 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文详细记录了一次支付系统漏洞挖掘过程,从客户端加密配置分析入手,逆向还原签名算法,发现支付接口存在签名边界失效、业务订单绑定缺失和金额校验漏洞。通过本地脚本重签请求,成功将32元洗车订单在支付阶段篡改为1角支付,验证了完整的支付完整性缺陷。 综合评分: 86 文章分类: 渗透测试,漏洞分析,WEB安全,红队,安全开发


cover_image

从客户端加密到签名伪造、支付一分钱买下 32 元服务|金额篡改漏洞完整挖掘实录

tangkaixing tangkaixing

渗透安全HackTwo

2026年5月11日 00:01 新加坡

在小说阅读器读本章

去阅读

0x01 简介

这次分析的目标,是一个聚合了洗车、券包等能力的小程序支付链路。最初的切入点并不是“直接看到金额可改”,而是顺着一个更基础的问题往下挖:发往核心支付接口的签名,到底是服务端私有能力,还是客户端本地就能复现?很多时候,业务接口表面上看似“有签名保护”,实战中真正决定漏洞上限的,恰恰是这个签名能力归谁所有。如果签名只能由服务端私钥生成,那么前端即使把金额字段明文提交出来,也不一定能构成真正可利用的逻辑漏洞;但如果签名本身就在客户端本地完成,而且密钥还能被恢复出来,那整个问题的性质就完全变了。本篇文章记录的,就是一次从客户端加密配置入手,逐步恢复本地配置、还原签名算法、伪造合法请求,最后验证到真实业务订单付款阶段可被改价的完整过程。

本文仅用于技术学习与合规交流,严禁非法滥用。因违规使用产生的一切后果,由使用者自行承担,与作者无关。

现在只对常读和星标的公众号才展示大图推送,建议大家把渗透安全HackTwo“设为星标”,否则可能就看不到了啦!****

参考文章:

https://xz.aliyun.com/news/92096https://www.hacktwohub.com/

末尾可领取挖洞资料/加圈子 #渗透安全HackTwo

0x02 正文详情

从可疑接口开始:

在这个小程序里,多个业务最终都会落到统一的支付拉起如下接口:

POST /xxx/xxx/get-wx-payurl

从抓包结果看,这个接口的请求体里直接带了大量高价值字段:

{  "vaMchntNo": "...",  "vaTermNo": "...",  "totalAmount": 3200,  "notifyUrl": "https://.../xxxxxStartWashCar",  "mchntOrderId": "...",  "subOpenId": "...",  "subAppId": "...",  "instMid": "xxx",  "tradeType": "xxxxxxx",  "msgType": "wx.unifiedOrder",  "loginToken": "..."}

这类接口第一眼很容易让人怀疑“金额是不是客户端直传”,但这里不能急着下结论。因为只要 Authorization 无法伪造,就算看得到这些参数,也未必能成功构造有效请求。所以,真正的第一步不是直接改金额,而是回答下面这个问题:这个请求的签名能力,到底掌握在谁手里?

逆向入口:签名函数并不在服务端

对源码做静态分析后,支付请求最终走到一个统一请求封装模块。继续往里追,可以看到请求头中的 Authorization 并不是服务端返回,而是客户端本地调用签名函数生成的:

Authorization = getAuthorization(body, appId, appKey, "post")

这已经说明一个很关键的事实:

  • 签名不是“服务器下发一次性签名”

  • 也不是“客户端拿 token 去换临时签名”

  • 而是客户端本地直接计算

这时候再问两个问题:

  1. appId

    从哪里来?

  2. appKey

    从哪里来?

如果这两个值来自安全硬件、服务端临时下发、或运行时不可导出存储,那么问题还没完全成立;但如果这两个值只是本地配置,那么整个签名保护就会被直接击穿。

配置不明文,但仍然在客户端本地

源码里没有直接把配置明文摆出来,而是用了一个典型的“本地密文配置 + 本地固定密钥解密”的做法。

对应逻辑大致可以抽象成这样:

const encryptedConfig = CONFIG.dataconst aesKey = "固定字符串"const plain = AES_ECB_Decrypt(encryptedConfig, aesKey)const runtimeConfig = JSON.parse(plain)

这一步的意义很重要。它说明配置虽然不是明文写死,但依然满足两个条件:

  • 密文在客户端本地

  • 解密密钥也在客户端本地

因此只要拿到小程序包,就能离线恢复出运行时配置。

恢复后的配置中,至少包含了这些关键字段:

  • appId

  • appKey

  • wxAppId

  • 若干业务回调地址

出于安全和脱敏考虑,这里不在文章中展示完整值,只保留形态说明:

appId  = 8a81...0990appKey = b8a3...30e5

到这里为止,签名能力已经从“理论可能”推进到了“可被客户端离线恢复”。

签名算法还原:不是障眼法,而是标准 HMAC

继续分析签名函数后,可以把它抽象成下面这套流程:

  1. 将请求体序列化为紧凑 JSON

  2. 对请求体做 SHA256

  3. 拼接:

  • appId + timestamp + nonce + bodyHash
  1. 对拼接结果做:
  • HMAC-SHA256(appKey, raw)
  1. 最终再进行 Base64 编码

伪代码如下:

body_json = json.dumps(body, separators=(",", ":"))body_hash = sha256(body_json).hexdigest()raw = appId + timestamp + nonce + body_hashsignature = base64(hmac_sha256(appKey, raw))

这一点非常关键,因为它把漏洞链从“看见字段”变成了“能够稳定重签并发包”。

也就是说,从这一刻开始,攻击者已经不再依赖官方小程序,也不再依赖服务端额外发放签名。

直接开始复现

编写用脚本重签,再回填到 Repeater。

使用脚本:sign_get_wx_payurl.py

先把修改后的完整 JSON 保存成 body.json

#部分代码参考def canonical_json(data: Dict[str, Any]) -> str:    return json.dumps(data, ensure_ascii=False, separators=(",", ":"))def now_timestamp() -> str:    return dt.datetime.now().strftime("%Y%m%d%H%M%S")def random_nonce() -> str:    return str(random.randint(10**9, 10**10 - 1))def build_signature(body: Dict[str, Any], timestamp: str, nonce: str) -> str:    body_json = canonical_json(body)    body_hash = hashlib.sha256(body_json.encode("utf-8")).hexdigest()    raw = f"{APP_ID}{timestamp}{nonce}{body_hash}".encode("utf-8")    return base64.b64encode(hmac.new(APP_KEY.encode("utf-8"), raw, hashlib.sha256).digest()).decode("ascii")python sign_get_wx_payurl.py --body-file body.json

脚本会输出:

  1. Authorization

  2. Content-Length

  3. 标准化后的 Body

把这三项替换回 Burp Repeater 再发包即可。

直接篡改金额:真实 32 元业务订单,付款阶段改成 1 角

第一步:先创建真实业务订单

选择低风险业务链路,重新调用下单接口生成一笔真实订单。这里以洗车订单为例,业务原始金额是:32 元

下单接口成功返回:

  • outer_order_number

  • payAmount = 32

  • 对应业务回调地址

这说明前置订单是真实存在的,而不是伪造构造物。

第二步:在付款阶段改价

接着调用 get-wx-payurl,但不按正常逻辑提交 3200 分,而是手工改成:

totalAmount = 10结果服务端仍然返回:- `respCode = 0000`- `totalAmount = 10`- 新的 `miniPayRequest`

这个漏洞的原理

这个问题的危险性,不在于它只是一处“前端把金额放进请求体”,而在于它同时满足了三层条件:

签名边界失效

不需要官方客户端,不需要服务端私钥,也不需要中间人条件,就可以本地生成合法 Authorization

业务订单绑定失效

支付接口没有强制要求 mchntOrderId 必须来自某个已校验完成的前置订单。

金额绑定失效

即便是已经创建好的真实业务订单,付款阶段仍然可以把金额改成攻击者指定值。这三点叠加后,漏洞已经不是“支付风险”而是完整的支付完整性缺陷

0x03 总结

这次挖掘最值得记录的,不只是最后把金额改成了 1,而是整个问题是怎么一步一步被确认的。一开始看到的是支付接口里有明文金额字段,但这还不能直接等价于可利用漏洞;漏洞危害关键,在于先确认签名是客户端本地可复现的,再确认新订单号可以独立生成支付会话,最后再把验证推进到真实业务订单付款阶段。这也是我一直以来的一个挖掘思路:不要看到“前端直传金额”就急着报漏洞,先看签名边界,再看订单绑定,再看金额绑定,最后再决定漏洞定性。最后愿各位师傅在后续挖洞之路中,精准定位漏洞、高效挖掘,天天出高危、次次有收获,挖洞顺利、不踩坑、多拿奖励,共同提升支付业务安全测试能力!🔥喜欢这类文章或挖掘SRC技巧文章师傅可以点赞转发支持一下谢谢!

内部星球VIP介绍V1.4(更多未公开挖洞技术欢迎加入星球)

如果你想学习更多另类渗透SRC挖洞技术/攻防/免杀/应急溯源/赏金赚取/工作内推,欢迎加入我们内部星球可获得内部工具字典和享受内部资源/内部群🔥

🚀1.每周更新1day/0day漏洞刷分上分,目前已更新至9394+;

🧰2.包含网上的各种付费工具/各种Burp漏洞检测插件/fuzz字典等等;

3.Fofa/Hunter/Ctfshow/360Quake/Shadon/零零信安/Zoomeye各种账号VIP会员共享等等;

🎥5.最新SRC挖洞文库/红队/代审/免杀/逆向视频资源等等;

🧪6.内部自动化漏扫赚赏金捡洞工具,免杀CS/Webshell工具等等;

💡7.漏洞报告文库、共享SRC漏洞报告学习挖洞技巧;

🎯6.最新0Day1Day漏洞POC/EXP分享地址(同步更新);

https://t.zsxq.com/jVcxV(全网最新最完整的漏洞库)

🔥7.详情直接点击下方链接进入了解,后台回复” 星球 “获取优惠先到先得!后续资源会更丰富在加入还是低价!(即将涨价)以上仅介绍部分内容还没完!点击下方地址全面了解👇🏻

👉点击了解加入–>>2026内部VIP星球福利介绍V1.5版本-1day/0day漏洞库及内部资源更新

结尾

免责声明

获取方法

回复“app” 获取  app渗透和app抓包教程

回复“渗透字典” 获取 一些字典已重新划分处理(需要内部专属fuzz字典可加入星球获取,内部字典多年积累整理好用!持续整理中!)

回复“书籍” 获取 网络安全相关经典书籍电子版pdf

最后必看

文章中的案例或工具仅面向合法授权的企业安全建设行为,如您需要测试内容的可用性,请自行搭建靶机环境,勿用于非法行为。如用于其他用途,由使用者承担全部法律及连带责任,与作者和本公众号无关。本项目所有收录的poc均为漏洞的理论判断,不存在漏洞利用过程,不会对目标发起真实攻击和漏洞利用。文中所涉及的技术、思路和工具仅供以安全为目的的学习交流使用。如您在使用本工具或阅读文章的过程中存在任何非法行为,您需自行承担相应后果,我们将不承担任何法律及连带责任。本工具或文章或来源于网络,若有侵权请联系作者删除,请在24小时内删除,请勿用于商业行为,自行查验是否具有后门,切勿相信软件内的广告!


往期推荐

1.内部VIP知识星球福利介绍V1.5版本0day推送

2.最新Nessus2026.2.9版本下载

3.最新BurpSuite2026.1.1专业版下载

4.最新xray1.9.11高级版下载Windows/Linux

5.最新HCL AppScan_Standard_10.9.1下载

渗透安全HackTwo

微信号:关注公众号获取

后台回复星球加入:知识星球

扫码关注 了解更多

上一篇文章:Nacos配置文件攻防思路总结|揭秘Nacos被低估的攻击面

喜欢的师傅可以点赞转发支持一下


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:渗透安全HackTwo tangkaixing tangkaixing《从客户端加密到签名伪造、支付一分钱买下 32 元服务|金额篡改漏洞完整挖掘实录》

评论:0   参与:  0