首页
社区
课程
招聘
[原创] 第三题 统一门派非预期题解
发表于: 2021-5-13 15:59 5720

[原创] 第三题 统一门派非预期题解

2021-5-13 15:59
5720

应该是非预期解...在找到flag后虽然尽力去找正常解, 但并没找出来, 只能说说在找解的过程中发现的信息

首先说非预期解

挂好burp代理访问题目地址, 在一番探索后发现请求了 /static/js/2.js这个文件, 审计了一番之后想着是不是还有1.js, 3.js什么的, 试了下真有, 然后就...

image-1

然后说说发现的信息

首先从登录页面可以发现是ruoyi管理系统, 而且下面版权信息只到2020年, gitee上找到的源码2021年还在更新, 所以使用的应该是旧版. 一个思路是找2021年它修复了哪些bug, 看了下主要修复是涉及fastjson, mybatis等的反序列化相关漏洞, 后来发现6379端口有个redis, 有可能是redis缓存+反序列化, 但是这个方式最后也没试出来.

从源码可以审计出除了登录页面还有其它几个可以访问的地方:

image-1.5

/dev-api/druid/index.html

image-2

是alibaba的druid系统, 但是ruoyi-vue不使用session作为登录凭证所以无法从session监控偷到cookies, sql监控也只记录了执行的模板, 所以最后发现这里好像除了uri监控能看看其它选手都在干啥以外没其他用处...

/dev-api/swagger-ui.html

这里是一个api文档页面, 但是里面描述的一系列/test/user下的api只能登陆后才能访问, 从这里也没找到其它更多信息.

/dev-api/common/download[/resource]/profile/**

image-3

这里的接口即使是2020年的旧版, 存在过的任意文件读取漏洞也已经被修复过. checkAllowDownload禁止了..且只允许一些特定扩展名, RuoYiConfig.getProfile()默认返回/home/RuoYi/UploadPath,访问/dev-api/profile/*也是访问这个目录下的文件, 在不知道这个目录下有什么文件的情况下没能获得更多的信息.

在翻redis时发现有时候存在login_token, 通过审计ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/TokenService.java发现客户端验证方式是通过jwt信息附带在请求头中, 请求头以及jwt密钥配置在ruoyi-admin/src/main/resources/application.yml里, 算法是HS512.

image-20210513153153798

尝试使用如下代码伪造jwt:

放在请求头里:

Authorization Bearer eyJ0eXA...

然并卵, 或许并没有使用默认的jwt secret, 这样的话这个思路也不正确.

分析到这里还有两种方法, 一是爆破用户密码, 在能访问redis的情况下能直接拿到验证码. 二是反序列化漏洞.

然而它们建立在能够访问redis的基础上, 此时redis已经被多人运动玩坏了...

想着flag也已经拿到了就到此为止吧, 等着看看其他解题思路(绝对不是因为我懒)

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/**
 * 获取用户身份信息
 *
 * @return 用户信息
 */
public LoginUser getLoginUser(HttpServletRequest request)
{
    // 获取请求携带的令牌
    String token = getToken(request);
    if (StringUtils.isNotEmpty(token))
    {
        Claims claims = parseToken(token);
        // 解析对应的权限以及用户信息
        String uuid = (String) claims.get(Constants.LOGIN_USER_KEY); // "login_user_key"
        String userKey = getTokenKey(uuid);
        LoginUser user = redisCache.getCacheObject(userKey);
        return user;
    }
    return null;
}
/**
 * 获取请求token
 *
 * @param request
 * @return token
 */
private String getToken(HttpServletRequest request)
{
    String token = request.getHeader(header); // "Authorization"
    if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX))
    {
        token = token.replace(Constants.TOKEN_PREFIX, ""); // "Bearer "
    }
    return token;
}
 
private String getTokenKey(String uuid)
{
    return Constants.LOGIN_TOKEN_KEY + uuid;
}
/**
 * 从令牌中获取数据声明
 *
 * @param token 令牌
 * @return 数据声明
 */
private Claims parseToken(String token)
{
    return Jwts.parser()
            .setSigningKey(secret)
            .parseClaimsJws(token)
            .getBody();
}
/**
 * 获取用户身份信息
 *
 * @return 用户信息
 */
public LoginUser getLoginUser(HttpServletRequest request)
{
    // 获取请求携带的令牌
    String token = getToken(request);
    if (StringUtils.isNotEmpty(token))
    {
        Claims claims = parseToken(token);
        // 解析对应的权限以及用户信息

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 2
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//