Jboss漏洞回显

这周根据师傅的思路调试了一下Jboss漏洞的回显。Java漏洞利用过程中大多技巧都用到了反射机制。本来这篇文章中也准备写写Java反射的,但写完感觉反射写的还是不够清楚,决定拆成两篇,反射之后再发吧。

1. Jboss调试环境

从网上下载jboss安装包,本文的环境是在Windows Server2008虚拟机中,故以Windows说明。
找到Windows下的JBoss的启动文件:run.bat,查找8787,存在此句话,则去掉注释(rem),重新启动run.bat即可。

rem set JAVA_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=n %JAVA_OPTS%

但是可能有的run.bat里没有,则可在run.conf中找到,放入run.bat的RESTART语句后即可。

然后把Jboss安装包放入IDEA,另外将lib和server下的文件加入library,并将server\all\deploy\httpha-invoker.sar\invoker.war\WEB-INF\classes打包jar cvf org.jar ./org
配置其Debug方式,如果直接是在本机起的服务可以直接设成localhost:8787,但是因为本文在虚拟机中配置,要将Host设成虚拟机IP地址。

Debug配置

如果连接虚拟机的过程没有报错但是也没连上的话,可以考虑是不是Windows防火墙没有关闭。关闭即可解决连接问题。

在org.jboss.invocation.http.servlet.ReadOnlyAccessFilter#doFilter的if语句前下断点,然后虚拟机中模拟发包 curl http://127.0.0.1:8080/invoker/readonly --data-binary @copyright.txt,此时就可以看到IDEA中的断点已经命中,点击计算器可以在当前上下文执行Java代码,也就可以开始调试。

2. Jboss调试

Thread.currentThread().threadLocals.table中逐个查看相关变量,找到request和response。

request所在变量

找到request,是刚才curl所发的包,发现其table编号为30,可以通过Thread.currentThread().threadLocals.table[30].value定位到value{Response},因为value是Response对象,通过反射即可获取到Response对象的属性,根据上文获取类属性的方式,
value.getClass()->获取到Response对象(org.apache.catalina.connector.Response),然后.getDeclaredFields()即可获取所有属性,.getDeclaredMethods()获取所有方法
getDeclaredMethods

图中显示类路径为org.apache.catalina.connector.Response,但是在IDEA中并没有直接搜到,说明有很多jar没有被引进来,想要查询完整路径可以在上述内存调试基础上

Thread.currentThread().threadLocals.table[30].value.getClass().getResourceAsStream(".");
或
Thread.currentThread().threadLocals.table[30].value.getClass().getResource("").getPath();

获取Response类所在路径,将该类所在的jar包引入,可以看到Response中相关内容


Response类

其中getOutputStream函数没有参数,生成的是一个coyoteOutputStream对象。该对象中包括了write、flush和close方法。


coyoteOutputStream类

write可以写入内容,flush则可以显示,两者共同调用就可以完成想要内容的回显,先拿个固定字符串"hello"试试。
Object resp=Thread.currentThread().threadLocals.table[30].value;
Object writer=resp.getClass().getDeclaredMethod("getOutputStream").invoke(resp);
writer.getClass().getDeclaredMethod("write",byte[].class).invoke(writer,"hello".getBytes());
writer.getClass().getDeclaredMethod("flush").invoke(writer);
hello回显测试

页面回显

既然这种方式可行,就要考虑如何执行命令,一种方式是将命令写在请求头里,然后根据命令获得相应的回显。那么此时上段代码中需要加入 request header的获取方法。首先获取 request对象,它存在于Response类的字段中,然后获取request对象的值,进而获取对象对应的header。并通过上述getOutputStream的方式进行回显。

Object resp=Thread.currentThread().threadLocals.table[30].value;
Field reqFiled=resp.getClass().getDeclaredField("request");//获取Response对象的request字段
reqFiled.setAccessible(true);//request字段值为protected,改变其访问权限
Object req=reqFiled.get(resp);//获取request字段值
Object contentType=req.getClass().getDeclaredMethod("getHeader",String.class).invoke(req,"Content-Type");//调用request对象中的getHeader方法
Object writer=resp.getClass().getDeclaredMethod("getOutputStream").invoke(resp);
writer.getClass().getDeclaredMethod("write",byte[].class).invoke(writer,contentType.toString().getBytes());//将请求头的内容写入
writer.getClass().getDeclaredMethod("flush").invoke(writer);

以上都是在内存中的调试,真正写成通用的工具,就不可能指定table[30],要全部通过反射来写。

那这里就要更深入的理解一下ThreadLocal类。该类中还定义了一个内部类ThreadLocalMap,但是对ThreadLocalMap真正的引用是在Thread类中。

    static class ThreadLocalMap {
        static class Entry extends WeakReference<ThreadLocal<?>> {
            Object value;

            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }
        private static final int INITIAL_CAPACITY = 16;
        private Entry[] table;
        private int size = 0;
        private int threshold; // Default to 0
        private void setThreshold(int len) {
            threshold = len * 2 / 3;
        }
        private static int nextIndex(int i, int len) {
            return ((i + 1 < len) ? i + 1 : 0);
        }
        private static int prevIndex(int i, int len) {
            return ((i - 1 >= 0) ? i - 1 : len - 1);
        }
        ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
            table = new Entry[INITIAL_CAPACITY];
            int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
            table[i] = new Entry(firstKey, firstValue);
            size = 1;
            setThreshold(INITIAL_CAPACITY);
        }

接下来的思路就是Entry[] table中某个值如何获取,table属于ThreadLocalMap的字段值,可以通过如下方式获取

Class threadLocalMapClazz=Class.forName("java.lang.ThreadLocal$ThreadLocalMap");
Field tableField=threadLocalMapClazz.getDeclaredField("table");
tableField.setAccessible(true);

这里获得的table是个数组,其具体值要通过get获得。value则属于Entry类的属性,同样它的值也需要反射get方法获得。

Class entryClass=Class.forName("java.lang.ThreadLocal$ThreadLocalMap$Entry");
Field entryValueField=entryClass.getDeclaredField("value");
entryValueField.setAccessible(true);

后面的写法就和上述调试过程中的回显代码没有什么差别了。

最后要说一下,这个Jboss漏洞最后的利用代码还用到了BCEL类,这个部分不属于回显范畴,就不多说了。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容