100%_upload
用短标签绕过内容检测,把php更改为jpg后缀,上传然后在index.php?file进行包含即可
Not just unserialize
简单的反序列化
然后就是环境变量注入rce?get[BASH_FUNC_echo%25%25]=()%20{%20cat%20/f*;%20}
hacker
无列名注入1'/**/union/**/select/**/group_concat(table_name)/**/from/**/mysql.innodb_table_stats%23
得到:flag,users,gtid_slave_pos
爆破flag脚本

但是flag里的英文字母都是小写的,比赛的时候一直说flag不对还很疑惑
其实应该用
直接注的,但是比赛的时候少写了个as a,所以就没读到。因为flag表是两列,所以要select 1,2,如果select 1,2,3就也读不到了,还是没有真正理解无列名注入。


EZ_SSRF
ssrf,不过藏了个admin.php,ssrf访问/admin.php就可以了。一开始没扫,想了好久
Oyst3rPHP
访问/www.zip下源码
md5绕过,preg_match回溯次数绕过,thinkphp6.0漏洞?left=s878926199a&right=s155964671a
key='1'*1000000+'603THINKPHP'

[进阶]elInjection
先看一下这多到离谱的hint,真喂饭了属于是。

根据第一个hint,我们找到 java el表达式+scriptengine webshell 分享
得到payload:
${"".getClass().forName("javax.script.ScriptEngineManager").newInstance().getEngineByName("js").eval("new+java.lang.ProcessBuilder['(java.lang.String[])'](['cmd','/c','calc']).start()")}
在本地先去掉过滤,成功弹计算器,说明可行,把过滤加回去,主要是eval里的内容会被检测,要根据base64绕过
因为eval里的是js代码,所以要按js的语法写,具体可以参考,要注意的点主要是把类的路径写全,如String要写成java.lang.String,然后定义变量的时候用var。 HGAME 2024 WEEK1 jhat
我们先用java代码来写个思路
先想想题目对我们的代码有什么要求,就是要不出现Runtime等关键字来执行系统命令
hint4已经说的很明白了
所以我们的代码如下:
成功本地弹计算器

然后我们把代码改写成js的形式,并把eval里js代码的"用\进行转义
成功弹计算器

接下来就是要执行什么命令,根据测试,无法回显同时curl不出来,根据hint2,知道dns是出网的,然后根据hint3,我们知道要执行/readflag
所以
这里本来想用Runtime,但是会报下面的错

把我们的代码base64编码

得到最终的payload
成功读到flag

这里看了一下其他师傅的wp,发现还可以用js的String.fromCharCode和绕过 charAt与toChars获取字符再由toString转字符串concat拼接
CC_deserialization
出题人的hint基本把链子给出来了,但是我还是不会,菜鸡一个。

这里主要参考这篇博客
hint里AbstractInputCheckedMapDecorator.setValue->TransformedMap.checkSetValue用了两次,这里会比较疑惑。为了理解这个,我们先把题目设置的简单一点,现在可以出网,那么我们就可以不用rmi的二次反序列化了。
先看一下CC1的链子

但是serialkiller.xml里过滤了chainedTransformer,所以我们CC1的链子就在TransformedMap.checkSetValue那里断了。
也就是说我们现在只能进行一次xxxTransformer.transformer,但是在AbstractInputCheckedMapDecorator$MapEntry#setValue里在进行一次checkSetValue即触发transformer还有entry.setValue(value),如果我们能够让entry为AbstractInputCheckedMapDecorator$MapEntry,因为value是我们transformer后获得的值,那么我们不就能再调用一次setValue,也就能再调用一次xxxTransformer.transformer

我们先调试看一下调用一次setValue时,entry是什么?

Map transformedMap4 = TransformedMap.decorate(map,new ConstantTransformer(4),new ConstantTransformer(Runtime.class));
我们序列化的是transformedMap4,可以看到entry是transformedMap4进行decorate的来源map的键值对,即我们的HashMap$Node,猜测entry是序列化对象decorate的第一个map里面的键值对,我们再写一个transformedMap3 map.put("value","aaaa");
Map transformedMap3 = TransformedMap.decorate(map,new ConstantTransformer(3),new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}));
Map transformedMap4 = TransformedMap.decorate(transformedMap3,new ConstantTransformer(4),new ConstantTransformer(Runtime.class));

这里要解释一下我们为什么TransformedMap的键值对在这里是AbstractInputCheckedMapDecorator$MapEntry


可以看到TransformerMap继承了AbstractMapEntryDecorator,AbstractInputCheckedMapDecorator$MapEntry的parent是AbstractMapEntryDecorator。entry是map里键值对的意思,那么entry的parent是谁呢?当然就是map。所以TransformerMap的entry就是AbstractInputCheckedMapDecorator$MapEntry,所以接下来会调用entry.parent#checkSetValue

即transformedMap3#checkSetValue,即InvokerTransformer.transformer

而且value是我们之前ConstantTransformer(Runtime.class).transform(value)返回的Runtime.class,接下来就会调用InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}).transform(Runtime.class)

返回了getRuntime,这不就跟ChainedTransformer一样了吗?
直接给出payload
成功弹计算器

如果这题出网的话,我们就已经过关了。
但是这题不出网,我们要写内存马,需要用CC3的链加载字节码。这就是为什么要通过rmiConnector#connect进行二次反序列化。因为一次的话我们最多只能用到ChainedTransformer,而加载不了字节码。那么我们现在想调用rmiConnector#connect就很轻松了,先用ConstantTransformer返回rmiConnector,在调用InvokerTransformer执行connect,因为我不会内存马,这里就直接CC4加载弹计算器的代码
不是你的公告是个什么鬼,私宅蒸恐怖
章鱼 2024-03-04