RSS Feed
更好更安全的互联网
  • BlueKeep 漏洞利用分析

    2019-09-20

    作者:SungLin@知道创宇404实验室
    时间:2019年9月18日

    0x00 信道的创建、连接与释放

    通道的数据包定义在MCS Connect Inittial PDU with GCC Conference Create Request中,在rdp连接过程如下图所示:

    信道创建数据包格式如下:

    在MCS Connect Inittial中属于Client Network Data数据段,MS_T120将会在连接一开始的时候通过函数termdd!_IcaRegisterVcBin创建一个虚拟通道id是0x1f大小为0x18的结构体,之后就调用termdd!IcaCreateChannel开始创建大小为0x8c的信道结构体之后将会与虚拟通道id是0x1f绑定,也就是这个结构体将会被我们利用

    信道的定义字段主要是名字加上配置,配置主要包括了优先级等

    在server对MCS Connect Inittial应答包,将会依次给出对应虚拟通道的id值:

    在rdp内核中依次注册的值对应应该是0、1、2、3, MS_T120信道将会通过我们发送的用户虚拟id为3的值再一次绑定,首先通过termdd!_IcaFindVcBind找到了刚开始注册的虚拟通道id是0x1f,如下所示:

    但是在termdd!_IcaBindChannel时,却将我们自定义的id值为3与信道结构体再一次绑定在一起了,此信道结构体就是MS_T120

    同时我们自己的用户id将内部绑定的0x1f给覆盖了

    我们往信道MS_T120发送数据主动释放其分配的结构体,其传入虚拟通道id值为3通过函数termdd!IcaFindChannel在channeltable中查找返回对应的信道结构体:

    下图为返回的MS_T120信道结构体,其中0xf77b4300为此信道可调用的函数指针数组:

    在这个函数指针数组中主要存放了三个函数,其中对应了termdd!IcaCloseChanneltermdd!IcaReadChanneltermdd!IcaWriteChannel

    我们传入释放MS_T120信道的数据如下,字节大小为0x12,主要数据对应了0x02

    之后将会进入nt! IofCompleteRequest函数,通过apc注入后,将会通过nt! IopCompleteRequestnt!IopAbortRequest进行数据请求的响应,最终在termdd!IcaDispatch完成我们发送数据的的请求,_BYTE v2就是我们发送的数据,所以我们发送的数据0x02将会最终调用到IcaClose函数进入IcaCloseChannel函数,最后主动释放掉了MS_T120信道结构体

    0x01 通过RDPDR信道进行数据占位

    我们先来了解下rdpdr信道,首先rdpdr信道是文件系统虚拟通道扩展,该扩展在名为rdpdr的静态虚拟通道上运行。目的是将访问从服务器重定向到客户端文件系统,其数据头部将会主要是两种标识和PacketId字段组成:

    在这里我们刚好利用到了rdpde客户端name响应的数据来进行池内存的占位

    在完全建立连接后,将会创建rdpdr信道的结构体

    在window7中,在建立完成后接收到server的rdpdr请求后,通过发送客户端name响应数据,将会调用到termdd! IcaChannelInputInternal中的ExAllocatePoolWithTag分配非分页池内存,并且其长度是我们可以控制的,基本满足了UAF利用的需求:

    可是在windowsxp中,直接发送client name request将会导致内存分配失败,直接进入termdd! _IcaCopyDataToUserBuffer,并且在Tao Yan and Jin Chen[1]一文中也提到了通过发送client name request在触发一定的条件后将会绕过termdd!_IcaCopyDataToUserBuffer而进入ExAllocatePoolWithTag分配我们想要的非分页内存,而打破条件如下:

    我们先来看看最开始信道结构体的创建,我们可以发现从一开始创建信道结构体的时候,将会出现两个标志,而这两个标志是按照地址顺序排列的,而在上面需要打破的条件中,只要channelstruct +0x108的地址存放的是同一个地址,循环就会被break

    我们发送一个正常的rdpdr的name request数据包,头部标识是0x7244和0x4e43

    经过termdd!_IcaCopyDataToUserBuffer之后,将会进入nt!IofCompleteRequest,在响应请求后进入rdpdr!DrSession::ReadCompletion,此函数处理逻辑如下,其将会遍历一个链表,从链表中取出对应的vftable函数数组

    遍历第一次取出第一张函数数组

    传入我们发送的数据后,通过函数数组调用rdpdr!DrSession::RecognizePacket进行读取

    判断头部标志是否为(RDPDR_CTYP_CORE)0x7244

    接着将会读取函数vftable第二个地址,进行转发

    如下图可以看到rdpdr的数据包处理逻辑

    rdpdr经过一系列数据包处理后最终进入了我们关心的地方,将会传入channelstruct通过调用termdd! _IcaQueueReadChannelRequest进行标志位的处理

    最初rdpdr的channelstruct的标志位如下

    经过函数termdd! _IcaQueueReadChannelRequest对此标志的处理后变成如下,所以下一个数据依然会进入termdd!_IcaCopyDataToUserBuffer,导致我们进行池喷射的失败

    回到rdpdr头部处理函数rdpdr!DrSession::RecognizePacket,我们发现在链表遍历失败后将会进行跳转,最后将会进入读取失败处理函数rdpdr!DrSession::ChannelIoFailed,然后直接return了

    我们构造一个头部异常的数据包发送,头部标志我们构造的是0x7240,将会导致rdpdr!DrSession::RecognizePacket判断失败,之后将会继续遍历链表依次再取出两张函数数组

    最后两个函数数组依次调用rdpdr!DrExchangeManager::RecognizePacketrdpdr!DrDeviceManager::RecognizePacket,都会判断错误的头部标志0x7240,最后导致链表遍历完后进行错误跳转,直接绕过了termdd! _IcaQueueReadChannelRequest对标志位的修改,将会打破循环

    最后我们连续构造多个错误的数据包后将会进入ExAllocatePoolWithTag,分配到我们需要的非分页内存!

    0x02 win7 EXP 池喷射简要分析

    首先被释放的MS_T120池大小包括是0x170,池的标志是TSic

    分析Win7 exp 可以知道数据占位是用的rdpsnd信道,作者没有采用rdpdr信道,应该也和喷射的稳定性有关,rdpsnd喷射是再建立完了rdpdr初始化后开始的,在free掉MS_T120结构体前,发送了1044个数据包去申请0x170大小的池内存,这样做可以说应该是为了防止之后被free掉的内存被其他程序占用了,提高free后内存被我们占用的生存几率

    占位被free的实际数据大小为0x128,利用的中转地址是0xfffffa80ec000948

    之后开始池喷射,将payload喷射到可以call [rax] == 0xfffffa80ec000948的地方,喷射的payload大小基本是0x400,总共喷射了200mb的数据大小,我们先来看下喷射前带标志TSic总共占用池内存大小是58kib左右

    喷射完后带TSic标志池内存大小大约就是201mb,池内存喷射基本是成功的,我的win7是sp1,总共内存大小是1GB,再喷射过程中也没有其他干扰的,所以喷射很顺利

    图中可以发现基本已经很稳定的0x400大小的池喷射payload,地址越高0x400大小的内存基本就很稳定了

    最后断开连接时候,被free的内存已经被我们喷射的0x128大小的数据给占用了

    执行call指令后稳定跳转到了我们的payload,成功执行!

    参考链接:
    [0] https://github.com/rapid7/metasploit-framework/pull/12283
    [1] https://unit42.paloaltonetworks.com/exploitation-of-windows-cve-2019-0708-bluekeep-three-ways-to-write-data-into-the-kernel-with-rdp-pdu/
    [2] https://wooyun.js.org/drops/%E7%BE%8A%E5%B9%B4%E5%86%85%E6%A0%B8%E5%A0%86%E9%A3%8E%E6%B0%B4%EF%BC%9A%20%E2%80%9CBig%20Kids%E2%80%99%20Pool%E2%80%9D%E4%B8%AD%E7%9A%84%E5%A0%86%E5%96%B7%E6%8A%80%E6%9C%AF.html

    作者:吴烦恼 | Categories:安全研究技术分享 | Tags:
  • Java 反序列化工具 gadgetinspector 初窥

    2019-09-17

    作者:Longofo@知道创宇404实验室 
    时间:2019年9月4日

    起因

    一开始是听@Badcode师傅说的这个工具,在Black Hat 2018的一个议题提出来的。这是一个基于字节码静态分析的、利用已知技巧自动查找从source到sink的反序列化利用链工具。看了几遍作者在Black Hat上的演讲视频PPT,想从作者的演讲与PPT中获取更多关于这个工具的原理性的东西,可是有些地方真的很费解。不过作者开源了这个工具,但没有给出详细的说明文档,对这个工具的分析文章也很少,看到一篇平安集团对这个工具的分析,从文中描述来看,他们对这个工具应该有一定的认识并做了一些改进,但是在文章中对某些细节没有做过多的阐释。后面尝试了调试这个工具,大致理清了这个工具的工作原理,下面是对这个工具的分析过程,以及对未来工作与改进的设想。

    关于这个工具

    • 这个工具不是用来寻找漏洞,而是利用已知的source->...->sink链或其相似特征发现分支利用链或新的利用链。
    • 这个工具是在整个应用的classpath中寻找利用链。
    • 这个工具进行了一些合理的预估风险判断(污点判断、污点传递等)。
    • 这个工具会产生误报不是漏报(其实这里还是会漏报,这是作者使用的策略决定的,在后面的分析中可以看到)。
    • 这个工具是基于字节码分析的,对于Java应用来说,很多时候我们并没有源码,而只有War包、Jar包或class文件。
    • 这个工具不会生成能直接利用的Payload,具体的利用构造还需要人工参与。

    序列化与反序列化

    序列化(Serialization)是将对象的状态信息转化为可以存储或者传输形式的过程,转化后的信息可以存储在磁盘上,在网络传输过程中,可以是字节、XML、JSON等格式;而将字节、XML、JSON等格式的信息还原成对象这个相反的过程称为反序列化。

    在JAVA中,对象的序列化和反序列化被广泛的应用到RMI(远程方法调用)及网络传输中。

    Java中的序列化与反序列化库

    • JDK(ObjectInputStream)
    • XStream(XML,JSON)
    • Jackson(XML,JSON)
    • Genson(JSON)
    • JSON-IO(JSON)
    • FlexSON(JSON)
    • Fastjson(JSON)
    • ...

    不同的反序列化库在反序列化不同的类时有不同的行为、被反序列化类的不同"魔术方法"会被自动调用,这些被自动调用的方法就能够作为反序列化的入口点(source)。如果这些被自动调用的方法又调用了其他子方法,那么在调用链中某一个子方法也可以作为source,就相当于已知了调用链的前部分,从某个子方法开始寻找不同的分支。通过方法的层层调用,可能到达某些危险的方法(sink)。

    • ObjectInputStream

    例如某个类实现了Serializable接口,ObjectInputStream.readobject在反序列化类得到其对象时会自动查找这个类的readObject、readResolve等方法并调用。

    例如某个类实现了Externalizable接口,ObjectInputStream.readobject在反序列化类得到其对象时会自动查找这个类的readExternal等方法并调用。

    • Jackson

    ObjectMapper.readValue在反序列化类得到其对象时,会自动查找反序列化类的无参构造方法、包含一个基础类型参数的构造方法、属性的setter、属性的getter等方法并调用。

    • ...

    在后面的分析中,都使用JDK自带的ObjectInputStream作为样例。

    控制数据类型=>控制代码

    作者说,在反序列化漏洞中,如果控制了数据类型,我们就控制了代码。这是什么意思呢?按我的理解,写了下面的一个例子:

    为了方便我把所有类写在一个类中进行测试。在Person类中,有一个Animal类的属性pet,它是Cat和Dog的接口。在序列化时,我们能够控制Person的pet具体是Cat对象或者Dog对象,因此在反序列化时,在readObject中pet.eat()具体的走向就不一样了。如果是pet是Cat类对象,就不会走到执行有害代码Runtime.getRuntime().exec("calc");这一步,但是如果pet是Dog类的对象,就会走到有害代码。

    即使有时候类属性在声明时已经为它赋值了某个具体的对象,但是在Java中通过反射等方式依然能修改。如下:

    在Person类中,不能通过构造器或setter方法或其他方式对pet赋值,属性在声明时已经被定义为Cat类的对象,但是通过反射能将pet修改为Dog类的对象,因此在反序列化时依然会走到有害代码处。

    这只是我自己对作者"控制了数据类型,就控制了代码"的理解,在Java反序列化漏洞中,很多时候是利用到了Java的多态特性来控制代码走向最后达到恶意执行目的。

    魔术方法

    在上面的例子中,能看到在反序列化时没有调用Person的readobject方法,它是ObjectInputStream在反序列化对象时自动调用的。作者将在反序列化中会自动调用的方法称为"魔术方法"。

    使用ObjectInputStream反序列化时几个常见的魔术方法:

    • Object.readObject()
    • Object.readResolve()
    • Object.finalize()
    • ...

    一些可序列化的JDK类实现了上面这些方法并且还自动调用了其他方法(可以作为已知的入口点):

    • HashMap
    • Object.hashCode()
    • Object.equals()
    • PriorityQueue
    • Comparator.compare()
    • Comparable.CompareTo()
    • ...

    一些sink:

    • Runtime.exec(),这种最为简单直接,即直接在目标环境中执行命令
    • Method.invoke(),这种需要适当地选择方法和参数,通过反射执行Java方法
    • RMI/JNDI/JRMP等,通过引用远程对象,间接实现任意代码执行的效果
    • ...

    作者给出了一个从Magic Methods(source)->Gadget Chains->Runtime.exec(sink)的例子:

    上面的HashMap实现了readObject这个"魔术方法",并且调用了hashCode方法。某些类为了比较对象之间是否相等会实现equals方法(一般是equals和hashCode方法同时实现)。从图中可以看到AbstractTableModel$ff19274a正好实现了hashCode方法,其中又调用了f.invoke方法,f是IFn对象,并且f能通过属性__clojureFnMap获取到。IFn是一个接口,上面说到,如果控制了数据类型,就控制了代码走向。所以如果我们在序列化时,在__clojureFnMap放置IFn接口的实现类FnCompose的一个对象,那么就能控制f.invokeFnCompose.invoke方法,接着控制FnCompose.invoke中的f1、f2为FnConstant就能到达FnEval.invoke了(关于AbstractTableModel$ff19274a.hashcode中的f.invoke具体选择IFn的哪个实现类,根据后面对这个工具的测试以及对决策原理的分析,广度优先会选择短的路径,也就是选择了FnEval.invoke,所以这也是为什么要人为参与,在后面的样例分析中也可以看到)。

    有了这条链,只需要找到触发这个链的漏洞点就行了。Payload使用JSON格式表示如下:

    gadgetinspector工作流程

    如作者所说,正好使用了五个步骤:

    Step1 枚举全部类以及每个类的所有方法

    要进行调用链的搜索,首先得有所有类及所有类方法的相关信息:

    来看下classes.dat、methods.dat分别长什么样子:

    • classes.dat

    找了两个比较有特征的

    第一个类com/sun/deploy/jardiff/JarDiffPatcher:

    和上面的表格信息对应一下,是吻合的

    • 类名:com/sun/deploy/jardiff/JarDiffPatcher
    • 父类: java/lang/Object,如果一类没有显式继承其他类,默认隐式继承java/lang/Object,并且java中不允许多继承,所以每个类只有一个父类
    • 所有接口:com/sun/deploy/jardiff/JarDiffConstants、com/sun/deploy/jardiff/Patcher
    • 是否是接口:false
    • 成员:newBytes!2![B,newBytes成员,Byte类型。为什么没有将static/final类型的成员加进去呢?这里还没有研究如何操作字节码,所以作者这里的判断实现部分暂且跳过。不过猜测应该是这种类型的变量并不能成为污点所以忽略了

    第二个类com/sun/corba/se/impl/presentation/rmi/InvocationHandlerFactoryImpl$CustomCompositeInvocationHandlerImpl:

    和上面的表格信息对应一下,也是吻合的

    • 类名:com/sun/corba/se/impl/presentation/rmi/InvocationHandlerFactoryImpl$CustomCompositeInvocationHandlerImpl,是一个内部类
    • 父类: com/sun/corba/se/spi/orbutil/proxy/CompositeInvocationHandlerImpl
    • 所有接口:com/sun/corba/se/spi/orbutil/proxy/LinkedInvocationHandler,java/io/Serializable
    • 是否是接口:false
    • 成员:stub!130!com/sun/corba/se/spi/presentation/rmi/DynamicStub!this$0!4112!com/sun/corba/se/impl/presentation/rmi/InvocationHandlerFactoryImpl,!*!这里可以暂时理解为分割符,有一个成员stub,类型com/sun/corba/se/spi/presentation/rmi/DynamicStub。因为是内部类,所以多了个this成员,这个this指向的是外部类
    • methods.dat

    同样找几个比较有特征的

    sun/nio/cs/ext/Big5#newEncoder:

    • 类名:sun/nio/cs/ext/Big5
    • 方法名: newEncoder
    • 方法描述信息: ()Ljava/nio/charset/CharsetEncoder; 无参,返回java/nio/charset/CharsetEncoder对象
    • 是否是静态方法:false

    sun/nio/cs/ext/Big5_HKSCS$Decoder#\<init>:

    • 类名:sun/nio/cs/ext/Big5_HKSCS$Decoder
    • 方法名:\<init>
    • 方法描述信息: (Ljava/nio/charset/Charset;Lsun/nio/cs/ext/Big5_HKSCS1;)V参数1是java/nio/charset/Charset类型,参数2是sun/nio/cs/ext/Big5HKSCS1;)V参数1是java/nio/charset/Charset类型,参数2是sun/nio/cs/ext/Big5HKSCS1类型,返回值void
    • 是否是静态方法:false

    继承关系的生成:

    继承关系在后面用来判断一个类是否能被某个库序列化、以及搜索子类方法实现等会用到。

    这一步的结果保存到了inheritanceMap.dat:

    Step2 生成passthrough数据流

    这里的passthrough数据流指的是每个方法的返回结果与方法参数的关系,这一步生成的数据会在生成passthrough调用图时用到。

    以作者给出的demo为例,先从宏观层面判断下:

    FnConstant.invoke返回值与参数this(参数0,因为序列化时类的所有成员我们都能控制,所以所有成员变量都视为0参)、arg(参数1)的关系:

    • 与this的关系:返回了this.value,即与0参有关系
    • 与arg的关系:返回值与arg没有任何关系,即与1参没有关系
    • 结论就是FnConstant.invoke与参数0有关,表示为FnConstant.invoke()->0

    Fndefault.invoke返回值与参数this(参数0)、arg(参数1)的关系:

    • 与this的关系:返回条件的第二个分支与this.f有关系,即与0参有关系
    • 与arg的关系:返回条件的第一个分支与arg有关系,即与1参有关系
    • 结论就是FnConstant.invoke与0参,1参都有关系,表示为Fndefault.invoke()->0、Fndefault.invoke()->1

    在这一步中,gadgetinspector是利用ASM来进行方法字节码的分析,主要逻辑是在类PassthroughDiscovery和TaintTrackingMethodVisitor中。特别是TaintTrackingMethodVisitor,它通过标记追踪JVM虚拟机在执行方法时的stack和localvar,并最终得到返回结果是否可以被参数标记污染。

    核心实现代码(TaintTrackingMethodVisitor涉及到字节码分析,暂时先不看):

    拓扑排序

    有向无环图(DAG)才有拓扑排序,非 DAG 图没有拓扑排序。 当有向无环图满足以下条件时:

    • 每一个顶点出现且只出现一次
    • 若A在序列中排在B的前面,则在图中不存在从B到A的路径

    这样的图,是一个拓扑排序的图。树结构其实可以转化为拓扑排序,而拓扑排序 不一定能够转化为树。

    以上面的拓扑排序图为例,用一个字典表示图结构

    代码实现

    但是在方法的调用中,我们希望最后的结果是c、b、e、d、a,这一步需要逆拓扑排序,正向排序使用的BFS,那么得到相反结果可以使用DFS。为什么在方法调用中需要使用逆拓扑排序呢,这与生成passthrough数据流有关。看下面一个例子:

    那么这里arg与返回值到底有没有关系呢?假设Obj.childMethod为

    由于childMethod的返回值carg与有关,那么可以判定parentMethod的返回值与参数arg是有关系的。所以如果存在子方法调用并传递了父方法参数给子方法时,需要先判断子方法返回值与子方法参数的关系。因此需要让子方法的判断在前面,这就是为什么要进行逆拓扑排序。

    从下图可以看出outgoingReferences的数据结构为:

    而这个结构正好适合逆拓扑排序

    但是上面说拓扑排序时不能形成环,但是在方法调用中肯定是会存在环的。作者是如何避免的呢?

    在上面的dfsTsort实现代码中可以看到使用了stack和visitedNodes,stack保证了在进行逆拓扑排序时不会形成环,visitedNodes避免了重复排序。使用如下一个调用图来演示过程:

    从图中可以看到有环med1->med2->med6->med1,并且有重复的调用med3,严格来说并不能进行逆拓扑排序,但是通过stack、visited记录访问过的方法,就能实现逆拓扑排序。为了方便解释把上面的图用一个树来表示:

    对上图进行逆拓扑排序(DFS方式):

    从med1开始,先将med1加入stack中,此时stack、visited、sortedmethods状态如下:

    med1还有子方法?有,继续深度遍历。将med2放入stack,此时的状态:

    med2有子方法吗?有,继续深度遍历。将med3放入stack,此时的状态:

    med3有子方法吗?有,继续深度遍历。将med7放入stack,此时的状态:

    med7有子方法吗?没有,从stack中弹出med7并加入visited和sortedmethods,此时的状态:

    回溯到上一层,med3还有其他子方法吗?有,med8,将med8放入stack,此时的状态:

    med8还有子方法吗?没有,弹出stack,加入visited与sortedmethods,此时的状态:

    回溯到上一层,med3还有其他子方法吗?没有了,弹出stack,加入visited与sortedmethods,此时的状态:

    回溯到上一层,med2还有其他子方法吗?有,med6,将med6加入stack,此时的状态:

    med6还有子方法吗?有,med1,med1在stack中?不加入,抛弃。此时状态和上一步一样

    回溯到上一层,med6还有其他子方法吗?没有了,弹出stack,加入visited和sortedmethods,此时的状态:

    回溯到上一层,med2还有其他子方法吗?没有了,弹出stack,加入visited和sortedmethods,此时的状态:

    回溯到上一层,med1还有其他子方法吗?有,med3,med3在visited中?在,抛弃。

    回溯到上一层,med1还有其他子方法吗?有,med4,将med4加入stack,此时的状态:

    med4还有其他子方法吗?没有,弹出stack,加入visited和sortedmethods中,此时的状态:

    回溯到上一层,med1还有其他子方法吗?没有了,弹出stack,加入visited和sortedmethods中,此时的状态(即最终状态):

    所以最后的逆拓扑排序结果为:med7、med8、med3、med6、med2、med4、med1。

    生成passthrough数据流

    在calculatePassthroughDataflow中遍历了sortedmethods,并通过字节码分析,生成了方法返回值与参数关系的passthrough数据流。注意到下面的序列化决定器,作者内置了三种:JDK、Jackson、Xstream,会根据具体的序列化决定器判定决策过程中的类是否符合对应库的反序列化要求,不符合的就跳过:

    • 对于JDK(ObjectInputStream),类否继承了Serializable接口
    • 对于Jackson,类是否存在0参构造器
    • 对于Xstream,类名能否作为有效的XML标签

    生成passthrough数据流代码:

    最后生成了passthrough.dat:

    Step3 枚举passthrough调用图

    这一步和上一步类似,gadgetinspector 会再次扫描全部的Java方法,但检查的不再是参数与返回结果的关系,而是方法的参数与其所调用的子方法的关系,即子方法的参数是否可以被父方法的参数所影响。那么为什么要进行上一步的生成passthrough数据流呢?由于这一步的判断也是在字节码分析中,所以这里只能先进行一些猜测,如下面这个例子:

    如果不进行生成passthrough数据流操作,就无法判断TestObject.childMethod1的返回值是否会受到参数1的影响,也就无法继续判断parentMethod的arg参数与子方法MyObject.childmethod的参数传递关系。

    作者给出的例子:

    AbstractTableModel$ff19274a.hashcode与子方法IFn.invoke:

    • AbstractTableModel$ff19274a.hashcode的this(0参)传递给了IFn.invoke的1参,表示为0->IFn.invoke()@1
    • 由于f是通过this.__clojureFnMap(0参)获取的,而f又为IFn.invoke()的this(0参),即AbstractTableModel$ff19274a.hashcode的0参传递给了IFn.invoke的0参,表示为0->IFn.invoke()@0

    FnCompose.invoke与子方法IFn.invoke:

    • FnCompose.invoked的arg(1参)传递给了IFn.invoke的1参,表示为1->IFn.invoke()@1
    • f1为FnCompose的属性(this,0参),被做为了IFn.invoke的this(0参数)传递,表示为0->IFn.invoke()@1
    • f1.invoke(arg)做为一个整体被当作1参传递给了IFn.invoke,由于f1在序列化时我们可以控制具体是IFn的哪个实现类,所以具体调用哪个实现类的invoke也相当于能够控制,即f1.invoke(arg)这个整体可以视为0参数传递给了IFn.invoke的1参(这里只是进行的简单猜测,具体实现在字节码分析中,可能也体现了作者说的合理的风险判断吧),表示为0->IFn.invoke()@1

    在这一步中,gadgetinspector也是利用ASM来进行字节码的分析,主要逻辑是在类CallGraphDiscovery和ModelGeneratorClassVisitor中。在ModelGeneratorClassVisitor中通过标记追踪JVM虚拟机在执行方法时的stack和localvar,最终得到方法的参数与其所调用的子方法的参数传递关系。

    生成passthrough调用图代码(暂时省略ModelGeneratorClassVisitor的实现,涉及到字节码分析):

    最后生成了passthrough.dat:


    Step4 搜索可用的source

    这一步会根据已知的反序列化漏洞的入口,检查所有可以被触发的方法。例如,在利用链中使用代理时,任何可序列化并且是java/lang/reflect/InvocationHandler子类的invoke方法都可以视为source。这里还会根据具体的反序列化库决定类是否能被序列化。

    搜索可用的source:

    这一步的结果会保存在文件sources.dat中:

    Step5 搜索生成调用链

    这一步会遍历全部的source,并在callgraph.dat中递归查找所有可以继续传递污点参数的子方法调用,直至遇到sink中的方法。

    搜索生成调用链:

    作者给出的sink方法:

    对于每个入口节点来说,其全部子方法调用、孙子方法调用等等递归下去,就构成了一棵树。之前的步骤所做的,就相当于生成了这颗树,而这一步所做的,就是从根节点出发,找到一条通往叶子节点的道路,使得这个叶子节点正好是我们所期望的sink方法。gadgetinspector对树的遍历采用的是广度优先(BFS),而且对于已经检查过的节点会直接跳过,这样减少了运行开销,避免了环路,但是丢掉了很多其他链。

    这个过程看起来就像下面这样:

    通过污点的传递,最终找到从source->sink的利用链

    :targ表示污染参数的index,0->1这样的表示父方法的0参传递给了子方法的1参

    样例分析

    现在根据作者的样例写个具体的demo实例来测试下上面这些步骤。

    demo如下:

    :下面截图中数据的顺序做了调换,同时数据也只给出com/demo中的数据

    Step1 枚举全部类及每个类所有方法

    classes.dat:

    methods.dat:

    Step2 生成passthrough数据流

    passthrough.dat:

    可以看到IFn的子类中只有FnConstant的invokeCall在passthrough数据流中,因为其他几个在静态分析中无法判断返回值与参数的关系。同时TestDemo的cMethod与pMethod都在passthrough数据流中,这也说明了拓扑排序那一步的必要性和正确性。

    Step3 枚举passthrough调用图

    callgraph.dat:

    Step4 搜索可用的source

    sources.dat:

    Step5 搜索生成调用链

    在gadget-chains.txt中找到了如下链:

    可以看到选择的确实是找了一条最短的路径,并没有经过FnCompose、FnConstant路径。

    环路造成路径爆炸

    上面流程分析第五步中说到,如果去掉已访问过节点的判断会怎么样呢,能不能生成经过FnCompose、FnConstant的调用链呢?

    陷入了爆炸状态,Search space无限增加,其中必定存在环路。作者使用的策略是访问过的节点就不再访问了,这样解决的环路问题,但是丢失了其他链。

    比如上面的FnCompose类:

    由于IFn是接口,所以在调用链生成中会查找是它的子类,假如f1,f2都是FnCompose类的对象,这样形成了环路。

    隐式调用

    测试隐式调用看工具能否发现,将FnEval.java做一些修改:

    结果:

    隐式调用了tostring方法,说明在字节码分析中做了查找隐式调用这一步。

    不遵循反射调用

    在github的工具说明中,作者也说到了在静态分析中这个工具的盲点,像下面这中FnEval.class.getMethod("exec", String.class).invoke(null, arg)写法是不遵循反射调用的,将FnEval.java修改:

    经过测试,确实没有发现。但是将FnEval.class.getMethod("exec", String.class).invoke(null, arg)改为this.getClass().getMethod("exec", String.class).invoke(null, arg)这种写法却是可以发现的。

    特殊语法

    测试一下比较特殊的语法呢,比如lambda语法?将FnEval.java做一些修改:

    经过测试,没有检测到这条利用链。说明目前语法分析那一块还没有对特殊语法分析。

    匿名内部类

    测试匿名内部类,将FnEval.java做一些修改:

    经过测试,没有检测到这条利用链。说明目前语法分析那一块还没有对匿名内部类的分析。

    sink->source?

    既然能source->sink,那么能不能sink->source呢?因为搜索source->sink时,source和sink都是已知的,如果搜索sink->source时,sink与soure也是已知的,那么source->sink与sink->source好像没有什么区别?如果能将source总结为参数可控的一类特征,那么sink->source这种方式是一种非常好的方式,不仅能用在反序列化漏洞中,还能用在其他漏洞中(例如模板注入)。但是这里也还有一些问题,比如反序列化是将this以及类的属性都当作了0参,因为反序列化时这些都是可控的,但是在其他漏洞中这些就不一定可控了。

    目前还不知道具体如何实现以及会有哪些问题,暂时先不写。

    缺陷

    目前还没有做过大量测试,只是从宏观层面分析了这个工具的大致原理。结合平安集团分析文章以及上面的测试目前可以总结出一下几个缺点(不止这些缺陷):

    • callgraph生成不完整
    • 调用链搜索结果不完整,这是由于查找策略导致的
    • 一些特殊语法、匿名内部类还不支持
    • ...

    设想与改进

    • 对以上几个缺陷进行改进
    • 结合已知的利用链(如ysoserial等)不断测试
    • 尽可能列出所有链并结合人工筛选判断,而作者使用的策略是只要经过这个节点有一条链,其他链经过这个节点时就不再继续寻找下去。主要解决的就是最后那个调用链环路问题,目前看到几种方式:
    • DFS+最大深度限制
    • 继续使用BFS,人工检查生成的调用链,把无效的callgraph去掉,重复运行
    • 调用链缓存(这一个暂时还没明白具体怎么解决环路的,只是看到了这个方法)

    我的想法是在每条链中维持一个黑名单,每次都检查是否出现了环路,如果在这条链中出现了环路,将造成环路的节点加入黑名单,继续使其走下去。当然虽然没有了环,也能会出现路径无限增长的情况,所以还是需要加入路径长度限制。

    • 尝试sink->source的实现
    • 多线程同时搜索多条利用链加快速度
    • ...

    最后

    在原理分析的时候,忽略了字节码分析的细节,有的地方只是暂时猜测与测试得出的结果,所以可能存在一些错误。字节码分析那一块是很重要的一环,它对污点的判断、污点的传递调用等起着很重要的作用,如果这些部分出现了问题,整个搜索过程就会出现问题。由于ASM框架对使用人员要求较高,所以需要要掌握JVM相关的知识才能较好使用ASM框架,所以接下来的就是开始学习JVM相关的东西。这篇文章只是从宏观层面分析这个工具的原理,也算是给自己增加些信心,至少明白这个工具不是无法理解和无法改进的,同时后面再接触这个工具进行改进时也会间隔一段时间,回顾起来也方便,其他人如果对这个工具感兴趣也可以参考。等以后熟悉并能操纵Java字节码了,在回头来更新这篇文章并改正可能有错误的地方。

    如果这些设想与改进真的实现并且进行了验证,那么这个工具真的是一个得力帮手。但是这些东西要实现还有较长的一段路要走,还没开始实现就预想到了那么多问题,在实现的时候会遇到更多问题。不过好在有一个大致的方向了,接下来就是对各个环节逐一解决了。

    参考


    Paper

    本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/1034/

    作者:吴烦恼 | Categories:安全研究技术分享 | Tags:
  • Confluence 文件读取漏洞(CVE-2019-3394)分析

    2019-08-30

    Author: Badcode@知道创宇404实验室 
    Date: 2019/08/29 
    英文版本: https://paper.seebug.org/1026/

    前言

    下午 @fnmsd 师傅发了个 Confluence 的预警给我,我看了下补丁,复现了这个漏洞,本篇文章记录下这个漏洞的应急过程。

    看下描述,Confluence Server 和 Data Center 在页面导出功能中存在本地文件泄露漏洞:具有“添加页面”空间权限的远程攻击者,能够读取 <install-directory>/confluence/WEB-INF/ 目录下的任意文件。该目录可能包含用于与其他服务集成的配置文件,可能会泄漏认证凭据,例如 LDAP 认证凭据或其他敏感信息。和之前应急过的一个漏洞一样,跳不出WEB目录,因为 confluence 的 web 目录和 data 目录一般是分开的,用户的配置一般保存在 data 目录,所以感觉危害有限。

    漏洞影响

    • 6.1.0 <= version < 6.6.16
    • 6.7.0 <= version < 6.13.7
    • 6.14.0 <= version < 6.15.8

    补丁对比

    看到漏洞描述,触发点是在导出 Word 操作上,先找到页面的这个功能。

    接着看下代码层面,补丁是补在什么地方。

    6.13.7是6.13.x的最新版,所以我下载了6.13.6和6.13.7来对比。

    去除一些版本号变动的干扰,把目光放在confluence-6.13.x.jar上,比对一下

    对比两个jar包,看到有个 importexport 目录里面有内容变化了,结合之前的漏洞描述,是由于导出Word触发的漏洞,所以补丁大概率在这里。 importexport 目录下面有个PackageResourceManager 发生了变化,解开来对比一下。

    看到关键函数getResourceReaderresource = this.resourceAccessor.getResource(relativePath);,看起来就是获取文件资源的,relativePath的值是/WEB-INF拼接resourcePath.substring(resourcePath.indexOf(BUNDLE_PLUGIN_PATH_REQUEST_PREFIX))而来的,而resourcePath是外部传入的,看到这里,也能大概猜出来了,应该是resourcePath可控,拼接/WEB-INF,然后调用getResource读取文件了。

    流程分析

    找到了漏洞最终的触发点,接下来就是找到触发点的路径了。之后我试着在页面插入各种东西,然后导出 Word,尝试着跳到这个地方,都失败了。最后我在跟踪插入图片时发现跳到了相近的地方,最后通过构造图片链接成功跳到触发点。

    首先看到com.atlassian.confluence.servlet.ExportWordPageServerservice方法。

    在导出 Word 的时候,首先会获取到被导出页面的pageId,之后获取页面的内容,接着判断是否有查看权限,跟进this.outputWordDocument

    前面会设置一些 header 之类的,然后将页面的内容渲染,返回renderedContent,之后交给this.extractImagesFromPage处理

    这个函数的功能是提取页面中的图片,当被导出的页面包含图片时,将图片的链接提取出来,交给this.createInputStreamFromRelativeUrl处理

    这个函数就是获取图片资源的,会对不同格式的图片链接进行不同的处理,这里重点是this.downloadResourceManager.matches(decodedUri),当跟到这里的时候,此时的this.downloadResourceManagerDelegatorDownloadResourceManager,并且下面有6个downloadResourceManager,其中就有我们想要的PackageResourceManager

    跟到DelegatorDownloadResourceManagermatches方法。

    matches方法会调用managersForResource方法,分别调用每个downloadResourceManagermatches方法去匹配resourcePath,只要有一个downloadResourceManager匹配上了,就返回 true。来看下PackageResourceManagermatches方法

    resourcePath要以BUNDLE_PLUGIN_PATH_REQUEST_PREFIX开头才返回true,看下BUNDLE_PLUGIN_PATH_REQUEST_PREFIX,是DownloadResourcePrefixEnum中的PACKAGE_DOWNLOAD_RESOURCE_PREFIX,也就是/packages

    所以,resourcePath要以/packages开头才会返回true。

    回到createInputStreamFromRelativeUrl方法中,当有downloadResourceManager匹配上了decodedUri,就会进入分支。继续调用DownloadResourceReader downloadResourceReader = this.getResourceReader(decodedUri, userName, strippedUri);

    跳到DelegatorDownloadResourceManager中的getResourceReader

    这里会继续调用managersForResource去调用每个downloadResourceManagermatches方法去匹配resourcePath,如果匹配上了,就继续调用对应的downloadResourceManagergetResourceReader方法。到了这里,就把之前的都串起来了,如果我们让PackageResourceManager中的matches方法匹配上了resourcePath,那么这里就会继续调用PackageResourceManager中的getResourceReader方法,也就是漏洞的最终触发点。所以要进入到这里,resourcePath必须是以/packages开头。

    整个流程图大概如下

    构造

    流程分析清楚了,现在就剩下怎么构造了。我们要插入一张链接以/packages开头的图片。

    新建一个页面,插入一张网络图片

    不能直接保存,直接保存的话插入的图像链接会自动拼接上网站地址,所以在保存的时候要使用 burpsuite 把自动拼接的网站地址去掉。

    发布时,抓包

    去掉网址

    发布之后,可以看到,图片链接成功保存下来了

    最后点击 导出 Word 触发漏洞即可。成功读取数据后会保存到图片中,然后放到 Word 文档里面,由于无法正常显示,所以使用 burp 来查看返回的数据。

    成功读取到了/WEB-INF/web.xml的内容。

    其他

    这个漏洞是无法跳出web目录去读文件的,getResource最后是会调到org.apache.catalina.webresources.StandardRoot里面的getResource方法,这里面有个validate函数,对路径有限制和过滤,导致无法跳到/WEB-INF/的上一层目录,最多跳到同层目录。有兴趣的可以去跟一下。

    利用 Pocsuite3 演示该漏洞: https://images.seebug.org/archive/CVE-2019-3394.mp4

    参考链接

    Local File Disclosure via Word Export in Confluence Server - CVE-2019-3394


    Paper

    本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/1025/

    作者:吴烦恼 | Categories:安全研究 | Tags:
  • Webmin(CVE-2019-15107) 远程代码执行漏洞之 backdoor 探究

    2019-08-23

    作者:Ethan@知道创宇404实验室

    时间:2019年8月21日

    漏洞概述

    Webmin是一个基于Web的界面,用于Unix的系统管理。使用任何支持表和表单的浏览器,可以设置用户帐户,Apache,DNS,文件共享等。

    2019年8月10日,在pentest上发布了Webmin CVE-2019-15107远程代码执行漏洞。

    该漏洞由于password_change.cgi文件在重置密码功能中存在一个代码执行漏洞,该漏洞允许恶意第三方在缺少输入验证的情况下而执行恶意代码,后经知道创宇404实验室发现,该漏洞的存在实则是sourceforge上某些版本的安装包和源码被植入了后门导致的。

    漏洞复现

    官方给的漏洞影响版本为Webmin<=1.920,于是当晚我使用了Webmin 1.920的版本进行的测试。

    在1.920版本中漏洞的触发需要开启密码重置功能,“Webmin-> Webmin Configuration-> Authentication”下把允许用户使用旧密码设置新密码的选项给选上,并保存!

    Webmin重启后,查看webmin的配置文件,可以发现passwd_mode的值已经从0变为了2

    然后在密码修改处处执行抓包,然后在old参数上加上|ifconfig

    发现成功执行了命令!

    想着换个用户试试吧,23333,结果出现下面的情况!

    为什么换个root用户就不行了,这里的root用户是Linux系统的root用户,我登陆使用的就是这个用户。。

    我再随便使用个用户试试?

    经测试用户为空也可以,用户为webmin用户也可以,其创建方式如下:

    其中root是Linux系统账户,认证方式为Unix authenticaton,ethan账户是自己创建的webmin 账户,认证方式无。

    这样问题就来了,为什么会有这样的区别?这就不得不开启一个perl菜鸟审计perl代码的道路,感谢@Longofo的帮助!

    漏洞点分析

    首先在password_change.cgi的第12行,我们可以得知想触发漏洞必须passwd_mode=2,也就必须开启密码重置功能。否则就会显示Password changing is not enabled!

    接着分析password_change.cgi的12行到31行,如下:

    从注释看,这段代码主要判断是不是webmin user。并且请求了一个acl-lib.pl,看名字就知道是功能性文件,功能应该就是访问控制之类的。在第21~22行的作用是获取请求中的user,并且判断是否属于Webmin user!但是这个x让我不知所然,为什么把$wuserx这个值比较呢?。于是我把acl::list_users()的值尝试着打印出来!

    返回如下数据:

    通过返回的数据,我们可以知道root用户并且使用Unix authenticaton设置(默认)的pass的值为x,而我自己创建没有选择认证方式的用户,pass的值为一串加密的字符串。也就是说如果我们传进的user是系统用户登陆且认证方式为Unix authenticaton的账户时,$wuser 的值会被赋值为undef

    在if条件语句外,我们把$wuser的值给打印下

    if条件语句里面把$wuser 的值打印出来印证一下

    而在perl语言中undef是变量未初始化时的默认值,一般情况下,将其当作空或0就好了,在需要作为数值的时候,undef代表的就是0,需要字符串的时候,undef就是空字符串。这里应该是对系统用户密码的修改和其它用户进行了区分。

    由我们上面的分析可知,在用户为root的情况下$wuser的值为undef

    也就是说如果传入的user为系统用户无法进入第37行的if条件语句,从而无法执行第40行qx/...../的命令执行代码。当我们传入的用户为空或者不存在时,$wuser的值为{},但是会进入if条件语句

    关于命令执行是否需要|,我们通过分析第207行到217行的pass_error可知,不需要|,亦可进行命令执行回显。

    另有蹊跷

    继续探究的原因是觉得qx/..../的蹊跷,因为官方给的修补是直接删除了qx/..../如图:

    是不是越看越感觉这个漏洞是被"加上去的",在Github上下载的1.920版本并无qx/..../,啊咧咧,一头雾水啊。。。通过git log -p命令并未发现与qx/..../相关的记录。而在sourceforge上下载的源码和安装包却有漏洞代码。后门?

    2012年在网站SourceForge韩国CDN节点疑似被入侵,热门下载资源phpMyadmin被植入后门。在Seebug上有收录:https://www.seebug.org/vuldb/ssvid-60402

    在Github上找到另外一些讯息,https://github.com/webmin/webmin/issues/947

    在1.890版本中,同样存在漏洞代码,这一次简直是赤裸裸的后门。。。

    我从sourceforge下载1.890版本,进行了探究。漏洞点如下:

    通过分析我们可以得知,这个漏洞点的触发只需要传一个expired参数执行命令即可。不需要之前的passwd_mode=2的必要条件。

    也就是说,在1.890版本中漏洞的触发不需要任何依赖。是代码疏漏还是恶意后门?

    验证想法

    这里我们通过更直观的方式来验证,通过把Github和sourceforge的源码下载下来,然后进行diff

    Webmin 1.920版本的password_change.cgi文件

    Webmin 1.890版本的password_change.cgi文件

    通过Github和sourceforge的文件对比,我们可以发现,sourceforge的代码明显存在问题,极有可能是被植入了后门。

    后经验证确认,只有sourceforge的代码和安装包存在后门漏洞。各版本的情况如下:

    其中以1.890版本的后门漏洞触发依赖最小,危害最大!猜测这应该是最初始的后门,后来植入后门的时候没有考虑到代码逻辑的问题,导致漏洞触发受到了限制!

    漏洞修补

    • 直接升级到1.930版本
    • 临时修补方案,可以定位漏洞代码所在的行,然后剔除,下图为1.920版本:

    下图为1.890版本:

    将所示标注替换为$miniserv{'passwd_mode'} == 2 || die "Password changing is not enabled!";即可,替换的代码为Github无后门代码。

    事后感想

    本来正常的一次应急没想到,发展成了对后门文件的探究。果然是生活不息,搞事不止啊!感谢@Longofo,帮忙测试大量文件和代码。黑哥也在medium上发表了The stories behind Webmin CVE-2019–15107这篇文章来描述后门发现的过程:https://medium.com/@80vul/the-stories-behind-cve-2012-5159-198eaad2449d


    Paper

    本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/1019/

    作者:吴烦恼 | Categories:安全研究 | Tags:
  • 分析 Curl-P 以及攻击 IOTA 加密货币

    2019-08-21

    作者:Ethan Heilman, Neha Narula, Garrett Tanzer, James Lovejoy, Michael Colavita, Madars Virza, and Tadge Dryja 
    原文:Cryptanalysis of Curl-P and Other Attacks on the IOTA Cryptocurrency 
    译者:知道创宇404实验室

    摘要

    本文介绍了使用伪造签名攻击IOTA区块链的方法。加密哈希函数Curl-P-27中存在一些弱点,允许攻击者快速生成可碰撞的短消息,并且这个方法也适用于相同长度的消息,利用这些弱点我们实现了对加密哈希函数Curl-P-27的攻击,破解了前IOTA签名方案(ISS)的EU-CMA。本文最后我们将介绍如何在消息已经被签署的情况下伪造有效支出的签名和多重签名(在IOTA中称为bundle)。

    关键词:加密货币,签名伪造,加密哈希函数,密码分析

    1 介绍

    加密货币通过数字签名来鉴别用户的转账行为。为了提高性能,在许多签名方案中,用户签署的是消息的哈希值而不是消息本身。在此情况下,如果底层哈希函数受到了攻击,攻击者便可以在付款时伪造数字签名。

    IOTA 的付款操作需要获得签名方案的授权。本文介绍了对该签名方案的攻击,这些攻击利用了哈希函数Curl-P-27的弱点。重要的是,我们在2017年8月披露并修补了此漏洞,由此保证了IOTA签名方案的安全性[20]。

    IOTA是一种加密货币,被应用于物联网(IoT)和汽车生态系统。截至2018年7月24日,它以26亿美元的市值成为全球第九大最有价值的加密货币[9]。许多公司与 IOTA 有过合作,包括汽车制造商大众汽车公司和欧洲大型工业公司博世公司。 IOTA 曾发布公告称大众汽车计划在2019年初发布一款使用 IOTA 的产品[7]。 2017年底,博世购买了“大量 IOTA代币”[6]。此外,IOTA 基金会与台北市签署了一项协议,将 IOTA 用于其智能城市计划,其中包括数字市民卡项目[8]。

    IOTA使用加密签名来授权用户付款。基于 Winternitz 一次性签名[25],IOTA建立了自己的签名方案(ISS)。但与传统的 Winternitz 签名不同,IOTA 用户签署的是消息的哈希值。由此可见,ISS的安全性依赖于其加密哈希函数,即 Curl-P-27。通过常见的差分密码分析方法,我们可以使用Curl-P-27快速创建哈希值相同且长度相同的消息,从而打破了功能的碰撞阻力。我们做到了每次都能在一个上限值之内实现碰撞。

    使用此碰撞攻击,我们可以在 IOTA 中伪造签名。我们从被签署的消息着手,为攻击者分别创建良性支付和恶意支付,并且使这两种支付具有相同的有效签名。我们的攻击适用于正常付款和多签名付款,并且只针对IOTA 签名方案,而没有包括整个 IOTA 网络。从多签名地址支出需要一个用户为另一个用户签名支付,这完全取决于如何设置被签署消息。我们详细介绍了如何攻击多签名地址支出,并提供了在单签名和多签名付款中生成碰撞的工具,并且评估了攻击的效率。在使用80个核的条件下,我们可以在不到20秒的时间内制造 IOTA 付款碰撞。

    1.1 漏洞状况和影响

    2017年7月14日,我们与 IOTA 开发人员准备披露这个攻击,并且就修补漏洞的时间安排以及发布日期进行了协商。 2017年8月7日,IOTA 开发人员部署了一个向后兼容的升级,通过将 Curl-P-27 替换为另一个哈希函数来消除漏洞[32]。为了进行升级,Bitfinex 暂停了其存取款业务,时间接近三天 [4]。所有直接持有 IOTA(不通过交易所)的用户都被鼓励升级他们的钱包和地址。 2017年9月7日,我们发布了漏洞报告[20],描述了此攻击的原理。

    在报告中,我们给出了有效碰撞和签名伪造的示例以及验证他们的软件。在此基础上,本文详细分析了破解 Curl-P-27 抗碰撞性的方法,并介绍了开发伪造签名的软件的流程。我们还研发了应对多签名方案的技术——选择消息攻击特别适用于多签名方案。我们没有向 IOTA 发送任何伪造签名或以任何方式攻击 IOTA。由于 Curl-P-27 不再用于 ISS,本文提出的签名伪造不适用于当前的 IOTA,同样不适用的还包括 5.2 节提到的的多重签名攻击。 Curl-P-27 仍然用于 IOTA 的其他部分[14],但我们不会对他们进行攻击。

    2 相关工作

    在我们发布了初始报告之后,Colavita和Tanzer [10]分别复现了我们的分析,并验证了Curl-P 的round函数,即这个函数通过排列的方法,根据特定的表达式进行舍入。他们二人也参与了本论文的撰写。

    1991年,Biham 和 Shamir [3]首次发布了差分密码分析技术(IBM的研究人员在1974年发现了类似技术但没有对外公布[11])。在本篇论文中,我们通过平衡三元加密哈希函数实现了差分密码分析的一个简单应用。除了我们的漏洞报告[10]以外,还有其他研究对基于三元的加密伪随机序列发生器进行了设计分析[16],但是没有研究过此函数的差分密码。

    通过对 Curl-P-27 的加密分析,我们对 ISS 的不可伪造性进行了选择消息攻击。或许我们还看不出降低碰撞抵抗性和建立攻击模型有多大的作用,但 MD5 哈希函数的研究过程可以给我们答案。王小云在 2004 年首次实现了 MD5 哈希算法的碰撞[35],并在随后发布了生成随机碰撞的通用程序[34]。 2005年,Lenstra 与王小云合作将这个加密漏洞应用于X.509 认证中。X.509 支持 HTTPS 等协议,并且能够构建成对的碰撞证书[24],是公钥基础设施的基石。有人认为证书颁发机构不会签署此类可疑证书,而且由于 X.509 认证缺乏“有意义的”结构,它很有可能被滥用。2007 年, Stevens 加入 Lenstra 等人,将 MD5 的原始随机碰撞攻击扩展到选择前缀碰撞攻击[30]。2009年,Stevens 等人宣布他们已经成功伪造了一个 X.509 证书,其拥有的证书权限能够通过所有主流浏览器的验证 [31] ,导致供应商立即废弃 MD5。

    之后,IOTA 开发人员替换了 IOTA 签名方案中的哈希函数, Curl-P-27变成了基于 Keccak 的 Kerl。2017年10月,他们发现了一个名为13攻击(也叫 M 攻击)的无关漏洞[23]。对于哈希值在[-13,13]区间内的消息,数字13的签名(又记作“M”)显示明文是私钥的衍生物,并可以被用于伪造所有的后续消息块,由此造成漏洞。为解决此问题,IOTA 基金会要求用户必须更改消息,直到摘要中没有 13。另一种补救措施是,开发人员将可能受到损害的资金转移到其他地址,用户之后可以通过向基金会提出申请,并收回其资金[27]。

    3背景

    在本节中,为了读者能更好地了解这个攻击,让我们首先简要回顾一下 IOTA 的一些不常见的设计特性和术语。我们还会对 Curl-P 哈希函数和IOTA 签名方案(ISS)进行概述。

    3.1 IOTA设计

    IOTA 有一些特别之处。首先,IOTA 使用平衡三进制而不是二进制;第二,IOTA 的付款被称为bundle;第三,IOTA 使用一种称为 tangle 的新数据结构而不是传统的块链;第四,IOTA 聘请一个称为协调员的可信方来检查状态并批准付款。

    IOTA 的数据结构使用平衡三进制而不是二进制,其中用于计数的符码为{-1,0,1},一个三进制字节由三位符码组成,每个字节代表了 [-13,13] 的整数。 IOTA经常将三进制字节序列化为字母A-Z和数字9。

    IOTA 内的付款方式用一种叫做 bundle 的数据结构来表示。Bundle 由多个交易组成,但 IOTA 交易与其他加密货币交易不同,它们是负责存储输入或输出的缓存,除此之外还有地址,签名,价值和标记等字段。在第 5 节中对这个攻击进行描述时,我们也会详细描述 IOTA 的 bundle 和交易格式。

    IOTA 是基于 tangle 的概念建立的[26],其类似于DAG链,其中每个块可以引用多个块父[29]。然而,在 IOTA 中,没有块可以汇总多笔付款。相反,每个交易必须有一个 nonce 以用于 PoW,还需要含有指向其他两个交易的指针。为了将交易添加到 tangle 中,用户从 tangle 中选择两个小费以在其交易中引用。一旦创建并且得到签名,用户就会有足够的工作证明,并将交易(或bundle的情况下的交易)广播到IOTA网络。

    在目前部署的IOTA中,bundle只能在获得协调员的批准之后才可以被接收。协调员是由IOTA开发人员运营的可信方,检查和批准tangle的状态,并对tangle签名。人们担心IOTA是集成的,或者受到IOTA开发人员的控制 [33]。 IOTA开发人员称IOTA不是集成的,协调员是一种临时措施,且IOTA没有公开其源代码。由于我们没有与IOTA沟通,我们无法确定协调员将如何影响我们发起的攻击,但是据我们所知,协调员没有机制可以防止本文提到的攻击。

    3.2 IOTA的签名方案(ISS)

    受到Winternitz一次性签名(W-OTS)的启发,IOTA使用了类似的签名方案[25]。 W-OTS对Lamport签名进行了优化 [22],同时操作多位,不惜计算成本来缩短公钥长度。

    ISS与W-OTS有很多不同。首先,与传统的W-OTS一样,ISS操作的是消息的哈希值,而不是像 W-OTS那样直接在消息上进行操作。其次,ISS没有使用校验和,而是对消息的哈希值进行规范化。

    ISS有三个安全级别。安全级别1仅签署消息的哈希值的三分之一,安全级别1签署前三分之二,安全级别3签署整个哈希值。因为我们的攻击是针对最高安全级别的,所以它也应当适用于其他所有安全级别。因此,当下文涉及到ISS时,我们将默认其使用了安全级别3。

    3.3 Curl-P

    在本节中,我们将描述Curl-P哈希函数。 Curl-P(有时称为Curl)是一种加密哈希函数,被用于设计IOTA。 它的用途包括创建交易地址、消息摘要,工作证明(PoW)和基于哈希的签名。 在高层次上,Curl-P遵循海绵结构模式[2,18],但在一些关键位置上有变化。 由于IOTA项目尚未提供任何官方规范说明或分析,我们对Curl-P的开源部分进行说明。

    与大多数加密哈希函数不同,Curl-P使用的是平衡三进制。为表达清楚,我们用小写字母表示单个三进制符码,例如a; b; c; x; y; z, 再用大写字母表示连续的三进制符码,如S; N; X; Y。使用下标符号表示一个序列中的单个字符,例如Si。遵循IOTA惯例,Curl-P-R中的R表示轮次(例如,Curl-P-27表示27轮Curl-P)。

    Curl-P运行过程如图一所示:(1)Curl-P的初始化状态S是一个长度为729的全零三进制序列。 (2)消息被分成消息块mb0 · · · mbn,每块长度为243。 Curl-P不使用消息填充,如果一条消息的长度不是243的倍数,允许最后一个消息块小于243。4(3)每个消息块mb0 · · · mbn依次被复制到状态S的前三分之一,并由函数f r进行转换。 (4)当没有消息块之后,Curl-P返回最终状态的前三分之一。有关更详细的描述,请参阅算法1。

    现在来看负责转换状态S的函数fr 。转换函数fr 就是将f函数递归调用r次,例如f 3(S) = f (f (f (S)))。 Curl-P-27就是Curl-P哈希函数,其变换函数是f27

    调用一次fr 就能获得S的新状态。 如算法2中所述,初始状态中的每相邻两位符码通过简单函数g的转换,变成新状态中的一位数字。 当前状态中的每一位都会被使用两次,一次作为g的第一个参数(由a表示),一次作为g的第二个参数(由b表示)。 在表1中,我们给出g作为替换表(s-box)。

    !

    4 Curl-P的密码分析

    在本节中,我们应用常见的差分密码分析法来构造完全碰撞。我们构造两条相同长度的消息,设置他们只有一个符码不同,而且他们通过 Curl-P-27 会映射到相同的值。我们可以控制碰撞消息的内容,包括任意消息前缀和后缀。在下一节中,我们将利用他们来伪造有效IOTA支付的签名。

    除了IOTA开源项目发布的一部分源代码,我们无法找到 Curl-P 或 Curl-P-27 的正式规范文档。此外,IOTA开发人员表示,Curl-P-27 旨在对特定的输入组[5]进行碰撞。事实上,Curl-P-27 是非随机的。正如[10]中详细探讨的那样,可以在相同长度的消息中观察到 Curl-P-27 的非随机行为;碰撞和第二个预成像对于生成不同长度的消息是微不足道的。因此,为了确保我们真正破解了 Curl-P-27,我们表明我们的碰撞攻击破坏了 Curl-P-27 的安全属性(参见第5节)。

    在高层次上,我们的攻击工作如下所示。我们选择两条长度至少为三个消息块的消息,并且他们只有一位符码不同。为了降低困难,我们使这两条消息满足某些约束方程(在第 4.2 节中详细说明)。一旦我们进入包含不同符码的消息块,我们就需要确保会发生碰撞。为此,我们在两个消息中随机翻转一组三进制数,并且每组不能超出其所在的消息块。我们的思路是对两条消息做变换处理,并且使不同的那一位在转换完成后处于结果状态的前三分之一的位置。

    27(S)[243,729] = f27(S‘)[243,729]

    因为Curl-P用下一个消息块替换了S的前三分之一,这导致原本的差异被覆盖,造成完全碰撞。我们利用Curl-P-27的不同特性多次强制转换函数,这样的话,在最后一轮时这些差异可能还保持在状态的前三分之一。经过多轮转换之后还保持着一位差异,找到这样的两条消息需要调用Curl-P-27次数的上限是760 万次或 22287次。

    在图2中,我们可以看到在Curl-P-27中,不同的轮数会导致不同的结果。我们用颜色代表发生碰撞的可能性,x轴表示差异点的位置,y轴表示在该轮数内差异没有扩散。我们对每个位置和深度执行100个样本(总共11 243 100 = 267300个样本),每个样品随机初始化,差异点的内容设置也是随机的。更多数学分析请参阅[10]中的复现。

    我们设置差异符码出现在第 17 位。根据实验结果,知道了轮次和差异点的位置,我们可以计算碰撞的概率。在此条件下递归20次后,碰撞的概率是1.0。因此,只要我们保证差异不会扩散,我们就可以制造碰撞。这种攻击应该同样适用于输入的消息块中的其他位置(如[10]所示)。请注意,这是确保发生碰撞的上限,因为递归次数少于20次时也可能发生碰撞。

    4.1 Curl-P变换函数f r的不同性质

    在本节中,我们将展示如何找到目标状态,将差异保持至少20轮。这需要我们分析Curl-P变换函数f的不同性质。

    差分密码分析涉及研究两组及两组以上的输入之间的差异传播模式。最常见的技术是寻找差异轨迹。差异轨迹是一组概率偏差,表示一组差异如何通过多轮加密函数传播到另一组差异。这里我们只使用特定的差异轨迹,即在转换函数f的重复应用下,两个状态S,S‘之间的某一位的差异。我们证明了 Curl-P 强烈偏向于保持一轮的单符码差异(即f的应用)。

    首先介绍其中涉及的术语。由于Curl-P使用三进制符码∈{?1,0,1},我们必须使用新的三元符号表示法。为了表示两个符码 x 和 x' 之间的差异,我们使用Θ ( 0Θ ?1 代表 x = 0 ,x’ = ?1 或者 x = ?1 , x‘ = 0)。通过术语扩散,我们指出在调用f之后,两个状态之间的差异的数量已经增加(即,差异已被使用)。

    我们的攻击是围绕着一个事实,即s-box g不会一直传播差异。例如,考虑g的两组输入和输出:g: a,b,c and a‘, b’, c‘ such that g( a, b ) = c and g( a', b' ) = c'。我们做出以下观察:

    1.对于所有可能的值,如果 a ≠ a' 且 b = b',那么 c ≠ c' 。

    2.如果a = a' 且 b ≠ b',则可能有 c = c' 或 c≠c'(例如,a = a'= 1,b = 0且b' = 1,则c = c' = 0)。

    每调用一次 f 就是更新一次状态。如3.3节所述,g 中每两位符码经过转换以后变成新状态中的一位符码。先前状态的每一位最多被转换两次:一次作为第一个变量a,一次作为第二个变量b。这意味着单位符码差异将延续到下一轮,因为当它是s-box g的第一个变量a时,g的输出将与a不同(如图1所示)。因此,如果将f应用于两个状态S,S',更新后的状态f(S),f(S')将始终有一位或两位的不同,不会出现无符码差异。

    我们模拟了状态在k轮Curl-P后保持单位符码差异的概率。 如图3所示,此马尔可夫模型列举出了所有可能的输入与其转换后的结果。 例如,如果当前的差异为 0Θ1,那么它有 1/9 的概率在下一轮中保持不变(即0 1),2/9 的概率变为 -1Θ0,或者有 6/9 的概率使差异个数从1增加到2(标记为失败状态,因为它未能保持单符码差异)。

    顶行表示 0Θ1 的转换到各个结果的概率,第二行是 -1Θ0,第三行 -1Θ1,第四行是差异由一位变为两位。使用这个矩阵,我们计算了在调用 k 次 f 之后差异保持一位的概率的下界,因为我们没有计算差异位数超过 1 位之后再变回1位的情况,所以这是一个下限。

    因此,从 0Θ1 开始,通过将矩阵提高到我们希望的轮数并计算概率。例如我们将矩阵幂 3 次,那么得到的矩阵中的数字就是符码在转换 3 次以后变成对应新符码的概率。因此,我们可以测量k轮后也不失败的概率。

    之前,我们通过实验验证了,如果经过 20 轮 Curl-P-27(即调用20次f)转换仍保持单符码差异,那么碰撞的概率是1.0。使用我们的状态转移矩阵,我们计算20轮,我们的攻击有一个每个查询成功概率下限为 2-42。也就是说,我们需要尝试242次才有可能找到将差异保持到20轮以后的消息对,这样的消息对可以产生碰撞。在下一节中,我们将展示如何显着减少对 Curl-P-27 的必要查询次数。

    4.2差分求解

    在本节中,我们将展示如何通过选择具有特定属性的消息来减少 Curl-P-27 的查询次数。我们首先展示如何约束有一位差异符码的状态 S 和 S‘,使得他们需要至少9次递归才能保持一位的差异(即差异没有扩散)。为此,我们将f表示为方程组,并求解状态S和S’中的特定值。

    我们可以将变换函数f r(S) 表示为一系列方程。例如,调用一次 f 可以写为

    f (S)0 = g(S0,S364),f (S)1 = g(S364,S728),...,f (S)728 = g(S365,S0)

    其中f (S)0是调用f后获得的新状态的第0位的数字。由于每一轮只是f的递归应用,我们可以根据状态S的初始值在f轮后写出特定位的值。我们使用上标来表示轮次。例如,用

    2(S)6 = g(g(S366,S1),g(S184,S548))

    表示在位置6进行两次递归运算。

    使用这种表示,我们找到可以使得 0Θ1 的差异保持9轮的方程。然后我们找到满足这些方程的消息前缀。 目前,我们可以在一秒之内查找到此消息前缀(有关我们的性能评估,请参见第 5.3 节)。 另外,给定一个特定的消息模板,我们只需要在两个消息块中更改一小组三进制位,便可以将其转换为令人满意的消息。

    4.3 寻找碰撞

    攻击需要至少3个信息块:mba, mbb, 和 mbc。其中mbb含有一个差异符码。mba前面的消息块数量没有限制,mba和mbb之间也没有,mbc总是跟在mbb之后并且重写mbb在前三分之一制造的差异。mbc的取值不会对攻击造成影响,可以取任意值。

    完整的攻击过程如下。首先,在我们攻击的约束阶段,我们通过调整mba和mbb来找到合适的消息前缀,这样它们可以保证 9 轮的单位符码差异。 接下来,在蛮力阶段,我们在mbb中的特定位置随机改变符码,目的是找到两个消息,使得从位置 17 开始的差异保持 20 轮。 由于约束阶段确保蛮力阶段的每次尝试在 9 轮中保持单符码差异不同,因此蛮力阶段的攻击复杂性从 20 轮减少到 11 轮。 结果,每个查询的成功率的下限减少到大约2 -22.87或 760 万分之一。

    正如差分密码所分析的,我们的概率计算简化了假设,即输入值是均匀随机的。考虑到 Curl-P-27 的低扩散率和Curl-P 的非随机性,这种假设可能不会总是成立。 但是,如第 5.3 节所示,本节给出的界限与实际结果相当接近。

    5 利用Curl-P中的碰撞来伪造签名

    本节中,我们将使用Curl-P-27碰撞对IOTA签名方案(ISS)执行签名伪造攻击。结合上一节的内容,我们将展示如何创建两个有效的IOTA bundle(即支付),这两个bundle最多只有两位不同,并且他们具有相同的Curl-P-27哈希值。然后,我们将描述攻击的设置,利用这些碰撞的 bundle 来伪造签名。最后,我们将展示如何攻击ISS多重签名。

    5.1 对ISS的选择消息攻击

    我们的攻击是一种选择消息攻击,恶意用户 Eve 欺骗用户Alice,先是要求Alice签署b1,然后根据b1生成相应的b2,这个b2也能通过验证。具体过程如下:

    1. Alice生成密钥对(PK, SK)。
    2. Eve通过碰撞攻击产生两个bundle b1,b2,并使得 b1 ≠ b2 且 CurlHash(b1)= CurlHash(b2)。
    3. Eve将b1发送给Alice并要求Alice签名。Alice检查b1,确认它是安全的。
    4. Alice在夏娃上给b1签名,即Sign(SK, b1)→ σ。
    5. Eve产生一个bundle对(σ,b2),使得 b1≠b2,b2是一个有效的 bundle,就算 Alice从未见过b2,b2也能够通过Alice的公钥验证。

    在4.3节中,我们介绍了攻击的一般格式,它至少需要三个消息块 mba,mbb和mbc。 为了执行攻击的第一阶段,我们将 mba 和 mbb 中的某些特性设置为特定值。 在暴力阶段,我们每次尝试更改 mbb 中的其他符码并检查我们是否已经实现了碰撞。 但是,bundle必须通过 IOTA 软件中的有效性检查才能被 IOTA 视作有效bundle,这限制了我们可以修改的位数。

    要想计算 bundle 的哈希,需要对每个交易的地址,值,标记,时间戳,当前字节和最后字节的串联结果计算哈希值。交易的格式如图4所示。大多数字段的格式都有严格的规范格式。例如,bundle 中值的求和结果不能为负,时间戳必须在一定范围内,并且索引必须与 bundle 中的交易对齐。标签不会影响 bundle 的语义或有效性,并且可以包含任意的符码。因此,对于约束阶段和暴力阶段中的每次尝试,我们只更改 tag 中的符码。

    另一个重要的问题是要在哪里生成碰撞。在最初的漏洞报告中,我们展示了两种不同攻击方式的碰撞 bundle:一种将碰撞置于地址范围内,使得 Alice 无意中签署了一项交易,该交易将取走 Eve 的资金,Eve 可以声明 Alice 犯了一个错误。第二次将两个碰撞放在一个 bundle 中的两个地方,导致 Alice 无意中签署了一个交易,该交易比预期更多地支付 Eve。在下一节中,我们将详细描述需要多个签名的 bundle 的后一种攻击方式,这些签名是我们选择的消息设置。

    5.2 多重签名攻击

    我们在漏洞报告[20]中伪造的攻击是选择消息攻击,也就是说,Eve必须要求Alice签署bundle。为了证明保障被签署消息的安全性有多么重要,我们现在将攻击扩展到 IOTA 多重签名方案[28]。在多重签名中,只有在多方签名以后才可以支出资金。为了达到这个目的,一方创建一个bundle并要求另一方签名,这便是选择消息攻击。 IOTA基金会鼓励部署热存储/冷藏解决方案5,以达到使用多重签名来安全存储资金[12]的目的。多重签名迫使攻击者必须使多方妥协,这是它被使用在加密货币环境中的一个主要原因。我们的攻击恰好消除了多重签名的这种安全优势。我们将考虑一个2-of-2 的简单案例,其中两方都签署了花费资金。这个攻击还会推广到更复杂的设置。

    考虑 Eve 和 Alice 各持一对 ISS 密钥:(PKE, SKE)和(PKA,SKA),只有Eve的密钥签名和Alice的密钥签名同时存在才能取出资金。这意味着Eve和Alice之前已经进入了 2-of-2 的多重签名,并且现在正共同使用这笔资金。我们的攻击将做如下工作:Eve将计算两个相互碰撞的bundle,一个向Alice支付资金,另一个向Eve支付资金。 Eve将签署并发送bundle给Alice,这个bundle负责向Alice支付资金。一旦Eve拥有 Alice 的签名,她就会在创建一个Alice从未见过或未授权的有效bundle,并且广播这个bundle.6。在此设置中,Eve要么是恶意的,要么已被恶意方攻击。

    为了构造这样的bundle,Eve将碰撞置于某个碰撞的某个value字段。图5显示了bundle的前四个消息块。突出显示的字段与攻击相关。通过在碰撞前后操纵标记字段中的特征,Eve导致第二交易(消息块3)中的value字段的第17位发生碰撞。这样,Eve可以在第二个交易中生成两个不同的bundle,这些值具有相同的哈希值。 Eve随后在第四个交易(消息块7)中生成了第二个碰撞,这次使两个bundle的值仍然总和为零。这用于设置向谁支付多少金额。

    为了生成这些碰撞,一般需要我们按顺序进行两次攻击。在我们当前的碰撞工具中,我们在两个交易之间还需要一个交易。满足了这个要求,以及冲突不在第一个或最后一个交易中的要求,我们就可以处理具有不同数量的交易的bundle。我们的工具只能在消息块的第17位中产生碰撞,不过这是工具的限制,而不是因为第 4 节中的密码分析有误。我们的工具在生成碰撞时不依赖于交易中特定的地址和值,但是必须保证对应位的符码不同才能产生有效的bundle。例如,如果在 b1 中 Alice 和 Eve 的输出值的 17 位为零,那么在b2中将Eve的输出值的17位变为1会导致b2的总和不为0。在 b1 中,Alice 的输出值的第 17 位应为1,Eve的应为零。

    在附录B中,我们展示了使用此技术创建的两个示例bundle。其中bundle为支出500,000,000 IOTA货币,由Alice和Eve控制。Alice丽丝签了一个bundle,它支付Eve 1 IOTA,其余的支付给其他地址。在碰撞的bundle中,Eve收到 129,140,164 IOTA货币,支出地址为Alice的地址。

    碰撞单签名bundle的生成方式与此类似。我们在漏洞报告中伪造了bundle的签名,其向三个地址进行支付。在良性bundle b1中,Alice在她控制的两个地址收到 50,000 和 810,021,667 IOTA 货币并向Eve支付100 IOTA货币。在恶意bundle b2 中, Eve进行了调整并且收到了 129,140,263 IOTA货币,这些是Alice的钱。我们还没有研究在value和address字段之外制造碰撞会带来哪些影响,可能会生成其他攻击。

    5.3 性能分析

    我们在 64 位Linux 4.9.74 环境下,使用一台配备了 8 个 2.4GHz 10 核 Intel 芯片和 256 GB RAM 的 Intel 机器运行此攻击。 我们的攻击占用了全部的 CPU,但占用的 RAM 空间可以忽略不计。 如第 4.3 节所述,碰撞包括两个阶段:约束阶段计算约束集,而暴力阶段在 tag 中产生随机数以产生碰撞。

    约束阶段生成并求解十八个等式,前九轮 Curl-P-27 中的每一个都有两个。 约束阶段在 Python 中实现,并且是单核运行。 我们没有尝试优化第一阶段。 表2 显示了取第 17 位不同并且在第一阶段运行 5000 次后所需要的平均,最小和最大时间。

    表2 还显示了强力阶段的测试结果。该阶段使用第一阶段的符码和模板来强制生成碰撞。因为这在 Go 中执行并且并行,因此我们需要使用服务器的所有 80 个核。 使用第一阶段的输出生成碰撞平均只需7.2秒。 一次碰撞平均需要测试 520 万次,最小和最大尝试次数分别超过 5000 次 1279 和 53M。 这证实了我们在4.3节中的分析。

    为了实现第 5.2 节中描述的多重攻击,我们必须顺序地运行约束和强制阶段,以生成两次碰撞。 我们的碰撞工具平均 15.2 秒就可以生成两个多重签名的bundle。 表2 显示了各阶段运行5000次所对应的平均时间以及最小和最大时间。

    6 讨论

    IOTA开发人员对漏洞的产生原因及其影响有过多次声明,我们对其进行了总结,并对部分问题作出了回应。

    IOTA开发人员认为我们的攻击模型与IOTA网络环境没有联系:具体来说就是,我们无法设置被签署过的消息,因为“在IOTA中,攻击者不会选择签名过的消息“[5]。为了应对这个问题,我们将攻击扩展到多重签名地址,因为多重签名协议明确允许一个用户选择另一个用户签名的消息。

    IOTA的开发人员还认为,”即使是大多数有效的攻击“都会在IOTA网络中失败,因为在闭源协调员中存在”保护机制” [5,13]。漏洞报告和本文中提出的攻击只单纯考虑如何应对IOTA签名方案,未在完整的IOTA系统的环境中分析这些攻击。

    此外,他们声称 Curl-P-27 可以接受碰撞输入是他们有意为之,其目的是防止克隆欺诈。其原话是:“IOTA 团队故意引入 Curl-P 哈希函数,以此预防[克隆欺诈],这还使得克隆欺诈无法用于 DLT 协议,同时保证了整个 IOTA 协议和网络的安全。”他们认为 “协调员会保护IOTA网络,不受故意引入的影响,并且称之为“复制保护机制”[13]。这么看来,我们除了发现一个新型攻击,似乎还发现了一个故意放置的后门。

    7 结论

    本文介绍了如何通过伪造消息签名来攻击IOTA签名方案。我们在两条消息只有一位字符不同的情况下构造了全状态碰撞。并且运用这个方法创建了两个有效的IOTA bundle,这样,就算两个bundle互不相同也仍然会映射到相同的值,也就是同一个签名将适用于两个bundle。 作为示例,我们在bundle中设置了不同的符码,攻击者可以在几十秒内使用简单的设备生成符合要求的bundle。

    8 致谢

    在此我们对 Andy Sellars, Weijia Gu, Rachael Walker, Joi Ito, Vincenzo Iozzo, Sharon Goldberg, and Ward Heilman 致以感谢,感谢你们对此论文的指导与建议。

    9 References

    [1] Mihir Bellare and Phillip Rogaway. “The exact security of digital signaturesHow to sign with RSA and Rabin”. In: International Conference on the Theory and Applications of Cryptographic Techniques. Springer. 1996, pp. 399– 416. 
    [2] Guido Bertoni et al. “On the indifferentiability of the sponge construction”. In: Lecture Notes in Computer Science 4965 (2008), pp. 181–197. 
    [3] Eli Biham and Adi Shamir. “Differential cryptanalysis of DES-like cryptosystems”. In: Journal of CRYPTOLOGY 4.1 (1991), pp. 3–72. 
    [4] Bitfinex. IOTA Protocol Upgrade August 08, 2017. https://www.bitfinex.com/posts/215, archived at https://web.archive.org/web/20180722235151/https://www.bitfinex.com/posts/215
    [5] Tangle blog. Full Emails of Ethan Heilman and the Digital Currency Initiative with the IOTA Team Leaked. http://www.tangleblog.com/wpcontent/uploads/2018/02/letters.pdf, archived at https://web. archive.org/web/20180228182122/http://www.tangleblog.com/wpcontent/uploads/2018/02/letters.pdf, https://archive.is/6imWR
    [6] Bosch. Press release: Robert Bosch Venture Capital makes first investment in distributed ledger technology. https://www.bosch- presse.de/pressportal/de/en/robert-bosch-venture-capital-makesfirst-investment-in-distributed-ledger-technology-137411.html, archived at https://web.archive.org/web/20180724022550/ https://www.bosch-presse.de/pressportal/de/en/robert-boschventure-capital-makes-first-investment-in-distributed-ledgertechnology-137411.html
    [7] Crypt Briefing. First VW IOTA Product Will Be Released Early Next Year. https://cryptobriefing.com/vw-iota-product-released/, archived at https://web.archive.org/web/20180724021409/https: //cryptobriefing.com/vw-iota-product-released/
    [8] Coindesk. City of Taipei Confirms It’s Testing IOTA Tech for ID. https://www.coindesk.com/city-of-taipei-confirms-its-testing-iotablockchain-for-id/
    [9] CoinmarketCap. CoinmarketCap IOTA July 23 2018. https://coinmarketcap. com/currencies/iota/, archived at https://web.archive.org/web/ 20180724020019/https://coinmarketcap.com/currencies/iota/
    [10] Michael Colavita and Garrett Tanzer. “A Cryptanalysis of IOTA’s Curl Hash Function”. In: (2018). 
    [11] Don Coppersmith. “The Data Encryption Standard (DES) and its strength against attacks”. In: IBM journal of research and development 38.3 (1994), pp. 243–250. 
    [12] IOTA Foundation. IOTA Guide – Generating Secure Multisig Addresses (hot and coldwallet). https://domschiener.gitbooks.io/iota-guide/content/exchange-guidelines/generating-multisignature-addresses.html, archived at https://archive.is/087kP
    [13] IOTA Foundation. Official IOTA Foundation Response to the Digital Currency Initiative at the MIT Media LabPart 4 / 4. https://blog.iota.org/official-iota-foundation-response-to-the-digitalcurrency-initiative-at-the-mit-media-lab-part-4-11fdccc9eb6d, archived at http://web.archive.org/web/20180727155405/https://blog.iota.org/official-iota-foundation-response-to-thedigital-currency-initiative-at-the-mit-media-lab-part-411fdccc9eb6d?gi=4be3ca82ed48
    [14] IOTAledger (github). IOTA Kerl specification. https://github.com/iotaledger/kerl/blob/master/IOTA-Kerl-spec.md, archived at https://web.archive.org/web/20180617175320/ 
    https://github.com/iotaledger/kerl/blob/master/IOTA-Kerl-spec.md. 2017. 
    [15] Oded Goldreich. Foundations of Cryptography: Basic Applications. Vol. 2. New York, NY, USA: Cambridge University Press, 2004. 
    [16] Guang Gong and Shaoquan Jiang. “The editing generator and its cryptanalysis”. In: International Journal of Wireless and Mobile Computing 1.1 (2005), pp. 46–52. 
    [17] Leon Groot Bruinderink and Andreas Hu¨lsing. ““Oops, I Did It Again” – Security of One-Time Signatures Under Two-Message Attacks”. In: Selected Areas in Cryptography – SAC 2017. 2018, pp. 299–322. 
    [18] Bertoni Guido et al. Cryptographic sponge functions. 2011. 
    [19] Paul Handy. Merged Kerl Implementation. https://github.com/iotaledger/iri/commit/539e413352a77b1db2042f46887e41d558f575e5, archived at https://archive.is/jCisX.
    [20] Ethan Heilman et al. IOTA Vulnerability Report: Cryptanalysis of the Curl Hash Function Enabling Practical Signature Forgery Attacks on the IOTA Cryptocurrency. 
    [21] Jonathan Katz and Yehuda Lindell. Introduction to Modern Cryptography. Second Edition. CRC Press, 2014. 
    [22] Leslie Lamport. Constructing digital signatures from a one-way function. Tech. rep. Technical Report CSL-98, SRI International Palo Alto, 1979. 
    [23] Willem Pinckaers (Lekkertech). IOTA Signatures, Private Keys and Address Reuse? http://blog.lekkertech.net/blog/2018/03/07/iotasignatures/, archived at https://archive.is/CnydQ. 2018. 
    [24] Arjen K. Lenstra, Xiaoyun Wang, and Benne de Weger. Colliding X.509 Certificates. Cryptology ePrint Archive, Report 2005/067. https://eprint. iacr.org/2005/067. 2005. 
    [25] Ralph C Merkle. “A certified digital signature”. In: Conference on the Theory and Application of Cryptology. Springer. 1989, pp. 218–238. 
    [26] Serguei Popov. “The tangle”. In: cit. on (2016), p. 131. 
    [27] Ralf Rottmann. IOTA Reclaim Identification Verification Process. https://blog.iota.org/iota-reclaim-identification-verificationprocess-e316647e06e6, archived at https://web.archive.org/web/ 20180710000243/https://blog.iota.org/iota-reclaim-identificationverification-process-e316647e06e6?gi=b8190e111e7f
    [28] Dominik Schiener. IOTA Multi-Signature Scheme. https://github.com/ iotaledger/wiki/blob/master/multisigs.mdIOTA Multi-Signature Scheme. 2017 (accessed February 3, 2018). 
    [29] Yonatan Sompolinsky and Aviv Zohar. “Secure high-rate transaction processing in bitcoin”. In: International Conference on Financial Cryptography and Data Security. Springer. 2015, pp. 507–527. 
    [30] Marc Stevens, Arjen Lenstra, and Benne de Weger. “Chosen-Prefix Collisions for MD5 and Colliding X. 509 Certificates for Different Identities”. In: Advances in Cryptology – EUROCRYPT 2007. Springer. 2007, pp. 1–22. 
    [31] Marc Stevens et al. “Short Chosen-Prefix Collisions for MD5 and the Creation of a Rogue CA Certificate”. In: Advances in Cryptology – CRYPTO 2009. Springer, 2009, pp. 55–69. 
    [32] David Snsteb. Upgrades & Updates. https://blog.iota.org/upgradesupdates-d12145e381eb, archived at https://web.archive.org/web/ 20180722232608/ 
    https://blog.iota.org/upgrades-updates-d12145e381eb?gi=51123f82db22
    [33] Eric Wall. IOTA is centralized. https://medium.com/@ercwl/iotais-centralized-6289246e7b4d, archived at https://web.archive.org/web/20180616231657/https://medium.com/@ercwl/iota-iscentralized-6289246e7b4d. 2017. 
    [34] Xiaoyun Wang and Hongbo Yu. “How to Break MD5 and Other Hash Functions”. In: Advances in Cryptology – EUROCRYPT 2005. Springer. 2005, pp. 19–35. 
    [35] Xiaoyun Wang et al. Collisions for Hash Functions MD4, MD5, HAVAL128 and RIPEMD. Cryptology ePrint Archive, Report 2004/199. https://eprint.iacr.org/2004/199.2004.


    Paper

    本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/1015/

    作者:吴烦恼 | Categories:安全研究 | Tags:
  • 对某单位的 APT 攻击样本分析

    2019-08-21

    作者:SungLin@知道创宇404实验室
    时间:2019年7月30日

    一.恶意邮件样本的信息与背景

    在六月份的某单位HW行动中,知道创宇HW安全团队通过创宇云图APT威胁感知系统并结合腾讯御点终端安全管理系统成功处置了一起APT攻击事件。

    7月份对同一样本的补充截图如下:

    在本次APT攻击中,攻击者通过发送鱼叉式钓鱼邮件,配合社会工程学手段诱导用户运行宏代码,进而下载尾部带有恶意payload压缩包的可执行文件。通过层层释放最终运行可窃取受害人员各类机密信息、维持权限、接收远端控制的木马。

    文档打开后,会诱导用户需要开启宏才能查看被模糊的图片,一旦用户点击开启宏,恶意样本将会在用户电脑上运行、潜伏、收集相应的信息、等待攻击者的进一步指令。

    该APT样本整体运行流程图如下:

    二.宏病毒文档的提取与调试

    使用OfficeMalScanner解压Office文档并提取文档所带的vba宏代码,打开Office文档启用宏后,采用快捷键Alt+F11开启宏代码的动态调试。该宏代码作为实施攻击的入口,实现了恶意样本的下载和执行。本章也将分析下载和执行的整体流程。

    解压该Office文档后,宏代码被封装在xl文件夹下的vbaProject.bin文件中。

    使用OfficeMalScanner这个工具的命令info从vbaProject.bin中提取宏代码,提取完后可以知道有6个宏代码,其中fdrhfaz2osd是主要的宏代码:

    动态调试分析宏代码,首先宏代码传入两个值u和f,分别是请求的url和写入的filepath。

    通过调用WinHttp.WinHttpRequest模块的方法Get请求来获取Response并写入到文件gc43d4unx.exe中。

    最后通过调用WScript.Shell来启动程序gc43d4unx.exe。

    三.gc43d4unx.exe释放pkk.exe等文件并执行

    程序gc43d4unx.exe在文件的末尾存放了一个RAR的压缩文件,gc43d4unx.exe程序通过解压缩后在用户Temp目录下的29317159文件夹释放了49个文件,并以pkk.exe xfj=eaa命令继续执行恶意样本。

    压缩文件在gc43d4unx.exe中的分布情况。

    gc43d4unx.exe主要逻辑在对话框的回调函数sub_419B4E中,识别Rar!的头部标识

    解压缩到映射的内存文件中,然后再挨着写到各个文件中

    在用户Temp目录下的29317159文件夹生成隐藏文件

    最后通过SHELL32.ShellExecuteExW执行qwb.vbs代码,qwb.vbs则会使用WshShell.Run运行pkk.exe xfj=eaa。

    四.PayLoad之pkk.exe运行分析

    pkk.exe是个名为AutoIt v3的脚本软件,可以加载自定义脚本。主要是就是通过定义DllStruct,然后再通过DllCall来调用函数。qwb.vbs运行代码为WshShell.Run”pkk.exe xfj=eaa”,通过pkk.exe加载一个叫xfj=eaa的二进制文件。

    软件先判断载入的是不是DLL,xfj=eaa是个编码后的脚本,判断后程序将会尝试解码。

    解码成功后,将解码数据写入一个临时文件中,软件将会重新创建一个进程来重新加载脚本。

    解码后的Autolt脚本,代码被混淆了。

    根据混淆的脚本,只是函数名混淆,而且脚本只是一个纯文本代码,通过重写此脚本后,可以看到基本还原的Autolt脚本代码了。

    Autolt软件解析完脚本后根据字符串功能通过分发函数来执行相应的函数。

    五.PayLoad之Autolt脚本分析

    Autolt脚本包含的功能有:检测运行环境、修改注册表、解密最终的.net木马并运行。

    通过检测进程名、设备是否有D盘等操作实现反虚拟机检测

    注册表禁用UAC策略函数

    注册表禁用任务管理器函数

    注册表开启自启函数,AuEx和ExE_c的值分别是xfj=eaa、pkk.exe。

    解密.net木马:

    读取K3ys这个键值和mmm.ini文件中[Data]段到[eData],将此数据进行字符替换正则匹配。

    载入Advapi32.dll,将K3ys键值进行Hash计算获取到真正的key,后再调用CryptDecrypt函数解密,利用ollydbg动态调试dump出解密数据,解密后的数据就是一个PE结构的程序,用IDA分析程序后,为.NET程序,这个.NET程序就是最后核心木马了,Autolt脚本后续将此PE结构加载进去,创建线程去单独运行此程序。

    六..NET木马分析

    木马主要功能进行了敏感信息收集,敏感信息收集完后会判断目标主机是否符合收集目标,以判断6个人名为主,符合本机收集目标,将会通过smtp或者ftp服务器上传文件,并且也通过web服务和c&c进行信息交流等。

    木马程序的基本信息:

    用.net反编译工具dnSpy打开此程序,程序入口处就是在类afg.agu,此木马经我判定进行了控制流扁平化和字符串加密的混淆方式,采用工具de4dot无法进行反混淆。

    字符串的解密:

    如下图所示,经过字符串加密后静态分析已经无法分析到字符串,而且可以看出控制流进行了扁平化的处理,加密字符串的入口函数为<Module>.\u206E()

    字符串的加密方式主要是通过传入加密的索引,通过固定值的替换与拆分计算后找到对应存储在uint型数组对象\u2009的加密Data、key、IV,\u2009数组对象大概有1047个字符串加密数组,字符串加密采用AES,模式为CBC。

    编写python脚本进行了字符串解密,解密后的效果如下所示:

    字符串解密核心算法如下:

    入口处获取主机名进行判断是否包含以下6个主机名,攻击目标是否符合:

    自我复制到C:\Users\l\AppData\Roaming\MyApp\MyApp.exe,设置为系统文件,并设置为无法删除的文件Zone.Identifier,在注册表设置为自启应用并且隐藏。

    感谢前辈的指点,此处有错误,更正如下:定时请求 http://checkip.amazonaws.com/ 获取出口的IP。

    httpweb服务器进行交互,进行信息的交流包括("update"、"info"、"uninstall"、"cookies"、"screenshots"、"keylog")。

    DNS查询等:

    进行ftp和smtp服务操作,并且绑定了一个邮箱地址 。

    以下可能是此地址的密码:

    收集信息如下:

    系统信息
    ManagementObjectSearcher managementObjectSearcher = new ManagementObjectSearcher("root\CIMV2", "SELECT * FROM Win32_VideoController")
    managementObjectSearcher2 = new ManagementObjectSearcher("SELECT * FROM Win32_Processor");
    浏览器
    CatalinaGroup\Citrio\User Dataliebao\User Data
    Fenrir Inc\Sleipnir5\setting\modules\ChromiumViewerYandex\YandexBrowser\User Data
    360Chrome\Chrome\User DataChedot\User Data
    Elements Browser\User DataEpic Privacy Browser\User Data
    CocCoc\Browser\User DataMapleStudio\ChromePlus\User Data
    Chromium\User DataTorch\User Data
    Iridium\User DataComodo\Dragon\User Data
    7Star\7Star\User DataAmigo\User Data
    BraveSoftware\Brave-Browser\User DataCentBrowser\User Data
    Vivaldi\User DataQIP Surf\User Data
    Kometa\User DataOrbitum\User Data
    Sputnik\Sputnik\User DatauCozMedia\Uran\User Data
    Coowon\Coowon\User Data
    ftp列表
    \CoreFTP\sites.idx\FTP Navigator\Ftplist.txt
    \SmartFTP\Client 2.0\Favorites\Quick Connect\
    \SmartFTP\Client 2.0\Favorites\Quick Connect*.xml\Ipswitch\WS_FTP\Sites\ws_ftp.ini
    \cftp\Ftplist.txt\FTPGetter\servers.xml
    \FTP Navigator\Ftplist.txt
    Mail列表
    \VirtualStore\Program Files\Foxmail\mail\\Opera Mail\Opera Mail\wand.dat
    Software\IncrediMail\Identities\
    注册表
    "HKEY_CURRENT_USER\Software\FTPWare\COREFTP\Sites\" + str + "Host""HKEY_CURRENT_USERSoftwareFTPWareCOREFTPSites" + str + "Port"
    "HKEY_CURRENT_USERSoftwareFTPWareCOREFTPSites" + str + "User""HKEY_CURRENT_USERSoftwareFTPWareCOREFTPSites" + str + "PW"
    "HKEY_CURRENT_USERSoftwareFTPWareCOREFTPSites" + str + "Name"

    http通信信息

    七.安全建议

    强烈推荐采用知道创宇云图、腾讯御点等产品,提高企业安全保护,降低外部威胁水平。

    知道创宇云图威胁监测系统系列产品,实时分析网络全流量,结合威胁情报数据及网络行为分析技术,深度检测所有可疑活动。文件检测采用全面沙箱分析,通过在沙箱(Sandbox)中运行(行为激活/内容“引爆”)各种文件,分析文件行为,识别出未知威胁。网络检测与文件检测同步进行,采用情报共享机制,构筑检测生态圈,准确、快速地掌握攻击链条,以便进一步采取相关措施,将APT(高级持续性威胁)攻击阻止在萌芽状态。

    腾讯御点是腾讯出品、领先国际的企业级安全服务提供者。依托腾讯19年的安全经验积累,为企业级用户提供私有云防病毒和漏洞修复解决方案。御点具备终端杀毒统一管控、修复漏洞统一管控,以及策略管控等全方位的安全管理功能,可帮助企业管理者全面了解、管理企业内网安全状况、保护企业安全。

    八.IOC信息

    domain & IP:

    相关 hash:

    7b478598b056d1f8e9f52f5ef1d147437b7f0da5
    a73816ebcfc07d6da66de7c298a0912a3dd5d41a
    b65884f1e833ea3eec8a8be4c7057a560da4511e
    8827b2c1520fb41034d5171c5c4afd15158fd4a3
    491b221f68013a2f7c354e4bb35c91fe45a1c0c0


    Paper

    本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/1011/

    作者:吴烦恼 | Categories:安全研究 | Tags:
  • Apache Solr DataImportHandler远程代码执行漏洞(CVE-2019-0193) 分析

    2019-08-21

    作者:Longofo@知道创宇404实验室 
    时间:2019年8月8日

    漏洞概述

    2019年08月01日,Apache Solr官方发布预警,Apache Solr DataImport功能 在开启Debug模式时,可以接收来自请求的"dataConfig"参数,这个参数的功能与data-config.xml一样,不过是在开启Debug模式时方便通过此参数进行调试,并且Debug模式的开启是通过参数传入的。在dataConfig参数中可以包含script恶意脚本导致远程代码执行。

    我对此漏洞进行了应急,由于在应急时构造的PoC很鸡肋,需要存在数据库驱动,需要连接数据库并且无回显,这种方式在实际利用中很难利用。后来逐渐有新的PoC被构造出来,经过了几个版本的PoC升级,到最后能直接通过直接传递数据流的方式,无需数据库驱动,无需连接数据库且能回显。下面记录下PoC升级的历程以及自己遇到的一些问题。感谢@Badcode与@fnmsd师傅提供的帮助。

    测试环境

    分析中涉及到的与Solr相关的环境如下:

    • Solr-7.7.2
    • JDK 1.8.0_181

    相关概念

    一开始没有去仔细去查阅Solr相关资料,只是粗略翻了下文档把漏洞复现了,那时候我也觉得数据应该能回显,于是就开始调试尝试构造回显,但是没有收获。后来看到新的PoC,感觉自己还没真正明白这个漏洞的原理就去盲目调试,于是又回过头去查阅Solr资料与文档,下面整理了与该漏洞有关的一些概念。

    Solr工作机制

    1.solr是在lucene工具包的基础之上进行了封装,并且以web服务的形式对外提供索引功能

    2.业务系统需要使用到索引的功能(建索引,查索引)时,只要发出http请求,并将返回数据进行解析即可

    (1) 索引数据的创建

    根据配置文件提取一些可以用来搜索的数据(封装成各种Field),把各field再封装成document,然后对document进行分析(对各字段分词),得到一些索引目录写入索引库,document本身也会被写入一个文档信息库

    (2) 索引数据的查询

    根据关键词解析(queryParser)出查询条件query(Termquery),利用搜索工具(indexSearcher)去索引库获取文档id,然后再根据文档id去文档信息库获取文档信息

    Solr DataImportHandler

    Solr DataImportHandler可以批量把数据导入到索引库中,根据Solr文档中的描述,DataImportHandler有如下功能:

    • 读取关系数据库中数据或文本数据
    • 根据配置从xml(http/file方式)读取与建立索引数据
    • 根据配置聚合来自多个列和表的数据来构建Solr文档
    • 使用文档更新Solr(更新索引、文档数据库等)
    • 根据配置进行完全导入的功能(full-import,完全导入每次运行时会创建整个索引)
    • 检测插入/更新字段并执行增量导入(delta-import,对增加或者被修改的字段进行导入)
    • 调度full-import与delta-import
    • 可以插入任何类型的数据源(ftp,scp等)和其他用户可选格式(JSON,csv等)

    通过搜索到的资料与官方文档中对DataImportHandler的描述,根据我的理解整理出DataImport处理的大致的流程图如下(只画了与该漏洞相关的主要部分):

    几个名词解释:

    • Core:索引库,其中包含schema.xml/managed-schema,schema.xml是模式文件的传统名称,可以由使用该模式的用户手动编辑,managed-schema是Solr默认使用的模式文件的名称,它支持在运行时动态更改,data-config文件可配置为xml形式或通过请求参数传递(在dataimport开启debug模式时可通过dataConfig参数传递)

    通过命令行创建core

    -d 参数是指定配置模板,在solr 7.7.2下,有_default与sample_techproducts_configs两种模板可以使用

    通过web页面创建core

    一开始以为从web页面无法创建core,虽然有一个Add Core,但是点击创建的core目录为空无法使用,提示无法找到配置文件,必须在solr目录下创建好对应的core,在web界面才能添加。然后尝试了使用绝对路径配置,绝对路径也能在web界面看到,但是solr默认不允许使用除了创建的core目录之外的配置文件,如果这个开关设为了true,就能使用对应core外部的配置文件:

    后来在回头去查阅时在Solr Guide 7.5文档中发现通过configSet参数也能创建core,configSet可以指定为_default与sample_techproducts_configs,如下表示创建成功,不过通过这种方式创建的core的没有conf目录,它的配置是相当于链接到configSet模板的,而不是使用copy模板的方式:

    通过以上两种方式都能创建core,但是要使用dataimport功能,还是需要编辑配置solrconfig.xml文件,如果能通过web请求方式更改配置文件以配置dataimport功能就能更好利用这个漏洞了。

    schema.xml/managed-schema:这里面定义了与数据源相关联的字段(Field)以及Solr建立索引时该如何处理Field,它的内容可以自己打开新建的core下的schema.xml/managed-schema看下,内容太长就不贴了,解释下与该漏洞相关的几个元素:

    dataConfig:这个配置项可以通过文件配置或通过请求方式传递(在dataimport开启Debug模式时可以通过dataConfig参数),他配置的时怎样获取数据(查询语句、url等等)要读什么样的数据(关系数据库中的列、或者xml的域)、做什么样的处理(修改/添加/删除)等,Solr为这些数据数据创建索引并将数据保存为Document

    PoC进化历程

    PoC第一阶段--数据库驱动+外连+无回显

    根据官方漏洞预警描述,是DataImportHandler在开启Debug模式时,能接收dataConfig这个参数,这个参数的功能与data-config.xml一样,不过是在开启Debug模式时方便通过此参数进行调试,并且Debug模式的开启是通过参数传入的。在dataConfig参数中可以包含script脚本,在文档搜到一个ScriptTransformer的例子:

    可以看到在script中能执行java代码,于是构造下PoC(通过logs查看相关报错信息查看PoC构造出现的问题),这个数据库是可以外连的,所以数据库的相关信息可以自己控制,测试过是可以的(只是演示使用的127.0.0.1):

    在ScriptTransformer那个例子中,能看到row.put的字样,猜测应该是能回显的,测试下:

    这里只能查看id字段,name字段看不到,也没有报错,然后尝试了下把数据put到id里面:

    能看到回显的信息。一开始不知道为什么put到name不行,后来看到在第三阶段的PoC,又回过头去查资料才意识到dataConfig与schema是配合使用的。因为在schema中没有配置name这个field,但是默认配置了id这个fileld,所以solr不会把name这个字段数据放到Document中去而id字段在其中。在第三阶段的PoC中,每个Field中的name属性都有"_s",然后去搜索发现可以在schema配置文件中可以配置dynamicField,如下是默认配置好的dynamicField:

    在上面的相关概念中对这个字段有介绍,可以翻上去查看下,测试下,果然是可以的:

    只要dynamicField能匹配dataConfig中field的name属性,solr就会自动加到document中去,如果schema配置了相应的field,那么配置的field优先,没有配置则根据dynamicField匹配。

    PoC第二阶段--外连+无回显

    在文档中说到JdbcDataSource可以使用JNDI,

    测试下能不能进行JNDI注入:

    这里有一个JNDI+LDAP的恶意demo。使用这种方式无需目标的CLASSPATH存在数据库驱动。

    PoC第三阶段--无外连+有回显

    这个阶段的PoC来自@fnmsd师傅,使用的是ContentStreamDataSource,但是文档中没有对它进行描述如何使用。在stackoverflower找到一个使用例子:

    在相关概念中说到了ContentStreamDataSource能接收Post数据作为数据源,结合第一阶段说到的dynamicField就能实现回显了。

    只演示下效果图,不给出具体的PoC:

    后来回过头去看其他类型的DataSource时,使用URLDataSource/HttpDataSource也可以,文档中提供了一个例子:

    构造测试也是可行的,可以使用http、ftp等协议

    参考链接


    Paper

    本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/1009/

    作者:吴烦恼 | Categories:安全研究 | Tags:
  • KDE4/5 命令执行漏洞 (CVE-2019-14744) 简析

    2019-08-21

    作者: HACHp1@知道创宇404实验室 
    日期: 2019/08/08

    漏洞简介

    KDE Frameworks是一套由KDE社群所编写的库及软件框架,是KDE Plasma 5及KDE Applications 5的基础,并使用GNU通用公共许可证进行发布。其中所包含的多个独立框架提供了各种常用的功能,包括了硬件集成、文件格式支持、控件、绘图功能、拼写检查等。KDE框架目前被几个Linux发行版所采用,包括了Kubuntu、OpenMandriva、openSUSE和OpenMandriva。

    2019年7月28日Dominik Penner(@zer0pwn)发现了KDE framework版本<=5.60.0时存在命令执行漏洞。

    2019年8月5日Dominik Penner在Twitter上披露了该漏洞,而此时该漏洞还是0day漏洞。此漏洞由KDesktopFile类处理.desktop或.directory文件的方式引起。如果受害者下载了恶意构造的.desktop或.directory文件,恶意文件中注入的bash代码就会被执行。

    2019年8月8日,KDE社区终于在发布的更新中修复了该漏洞;在此之前的三天内,此漏洞是没有官方补丁的。

    一些八卦

    • 在Dominik Penner公开此漏洞时,并没有告诉KDE社区此漏洞,直接将该0day的攻击详情披露在了Twitter上。公布之后,KDE社区的人员与Penner之间发生了很多有意思的事情,在这里不做描述。

    影响版本

    • 内置或后期安装有KDE Frameworks版本<=5.60.0的操作系统,如Kubuntu。

    漏洞复现

    环境搭建

    • 虚拟机镜像:kubuntu-16.04.6-desktop-amd64.iso
    • KDE Framework 5.18.0
    • 搭建时,注意虚拟机关闭网络,否则语言包下载十分消耗时间;此外,安装完成后进入系统要关掉iso影响,否则无法进入系统。

    复现过程及结果

    PoC有多种形式,此处使用三种方式进行复现,第1、2种为验证性复现,第3种为接近真实情况下攻击者可能使用的攻击方式。

    1.PoC1: 
    创建一个文件名为”payload.desktop”的文件:

    在文件中写入payload:

    保存后打开文件管理器,写入的payload被执行:

    文件内容如下:

    2.PoC2:

    创建一个文件名为” .directory”的文件:

    使用vi写入内容(此处有坑,KDE的vi输入backspace键会出现奇怪的反应,很不好用):

    写入payload:

    保存后打开文件管理器,payload被成功执行:

    3.PoC3: 
    攻击者在本机启动NC监听:

    攻击者将payload文件打包挂载至Web服务器中,诱导受害者下载:

    受害者解压文件:

    解压后,payload会被执行,攻击者接收到反连的Shell:

    • 漏洞影响:虽然直接下载文件很容易引起受害者注意,但攻击者可以将恶意文件打包为压缩文件并使用社会工程学诱导受害者解开压缩包。不管受害者有没有打开解压后的文件,恶意代码都已经执行了,因为文件解压后KDE系统会调用桌面解析函数。此时受害者就容易中招。

    漏洞原理简析

    • 在Dominik Penner公布的细节中,对该漏洞已经有着比较详细的解释。在着手分析漏洞前,我们先学习一下Linux的desktop entry相关的知识。

    desktop entry

    • XDG 桌面配置项规范为应用程序和桌面环境的菜单整合提供了一个标准方法。只要桌面环境遵守菜单规范,应用程序图标就可以显示在系统菜单中。
    • 每个桌面项必须包含 Type 和 Name,还可以选择定义自己在程序菜单中的显示方式。
    • 也就是说,这是一种解析桌面项的图标、名称、类型等信息的规范。
    • 使用这种规范的开发项目应该通过目录下的.directory.desktop文件记录该目录下的解析配置。

    详见:https://wiki.archlinux.org/index.php/Desktop_entries_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)

    漏洞的产生

    KDE的桌面配置解析参考了XDG的方式,但是包含了KDE自己实现的功能;并且其实现与XDG官方定义的功能也有出入,正是此出入导致了漏洞。

    在KDE文档中有如下的话(https://userbase.kde.org/KDE_System_Administration/Configuration_Files#Shell_Expansion):

    • 为了提供更加灵活的设置解析,KDE实现并支持了动态配置,而此处的${USER}尤其令人注意,该项取自环境变量,可以推测,此处与命令执行肯定有联系。
    • 每当KDE桌面系统要读取图标等桌面配置时,就会调用一次readEntry函数;从Dominik Penner给出的漏洞细节中,可以看到追踪代码的过程。整个漏洞的执行过程如下: 
      首先,创建恶意文件:

    进入文件管理器,此时系统会对.desktop文件进行解析;进入解析Icon的流程,根据文档中的说明,参数中带有[$e]时会调用shell动态解析命令:

    kdesktopfile.cpp:

    跟进,发现调用了KConfigPrivate::expandString(aValue): 
    kconfiggroup.cpp:

    再跟进,结合之前对KDE官方文档的解读,此处是对动态命令的解析过程,程序会把字符串中第一个出现的$(与第一个出现的)之间的部分截取出来,作为命令,然后调用popen执行: 
    kconfig.cpp

    自此,漏洞利用过程中的代码执行流程分析完毕;可以看到KDE在解析桌面设置时,以直接使用执行系统命令获取返回值的方式动态获得操作系统的一些参数值;为了获得诸如${USER}这样的系统变量直接调用系统命令,这个做法是不太妥当的。

    官方修补方案分析

    • 官方在最新版本中给出了简单粗暴的修复手段,直接删除了popen函数和其执行过程,从而除去了调用popen动态解析[e]属性的功能:
    • 此外,官方还不忘吐槽了一波:

    总结

    • 个人认为这个漏洞在成因以外的地方有着更大的意义。首先,不太清楚当初编写KDE框架的开发人员的用意,也许是想让框架更灵活;但是在文档的使用用例中,只是为了获取${USER}变量的值而已。在命令执行上有些许杀鸡用牛刀的感觉。
    • 从这个漏洞可以看出灵活性与安全性在有的时候是互相冲突的,灵活性高,也意味着更有可能出现纰漏,这给开发人员更多的警示。
    • 漏洞发现者在没有通知官方的情况下直接公布了漏洞细节,这个做法比较有争议。在发现漏洞时,首先将0day交给谁也是个问题,个人认为可以将漏洞提交给厂商,待其修复后再商议是否要公布。可能国际上的hacker思维与国内有着比较大的差异,在Dominik Penner的Twitter下竟然有不少的人支持他提前公布0day,他自己也解释是想要在defcon开始之前提交自己的0day,这个做法以及众人的反应值得去品味。

    参考资料


    Paper

    本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/1006/

    作者:吴烦恼 | Categories:安全研究 | Tags:
  • 总结:IOTA反驳DCI实验室提出的漏洞荒谬至极

    2019-08-21

    原文:https://medium.com/@noahruderman/a-summary-of-why-iotas-refutation-of-a-vulnerability-by-dci-labs-is-absurd-128e894781b1 
    作者:Noah Ruderman 
    译者:知道创宇404实验室

    DCI实验室发布报告称,他们发现了针对IOTA交易签名方案中存在性不可伪造(EU-CMA)的安全问题,允许攻击者窃取资金。

    而对于密码学来说,这个漏洞正是密码学安全研究的向量。如果你不同意这一点,你就是在反对密码学。

    1. 前言

    争议开始于由麻省理工学院旗下的DCI实验室撰写的漏洞报告。IOTA开发人员否认密码学和互联网安全对漏洞的定义,指控DCI实验室学术欺诈,并骚扰DCI的安全研究员伊森·海尔曼,威胁说要对这份不利的漏洞报告采取法律行动。

    尽管DCI声称的漏洞在每一位加密专家、安全研究人员和主要加密货币开发人员看来都是正确的,但这很难令常人所理解。在这基础上,IOTA强烈反对curl-p易受攻击的观点,并发布了相关文章

    本篇文章的目的: 
    (a) 向几乎没有密码学知识的人解释该漏洞的性质; 
    (b) 为什么IOTA的反驳并不能说服密码学专家和安全研究人员; 
    (c) 如何论证哈希函数的安全性。

    2. DCI实验室声明的摘要

    DCI实验室表示,用于保护交易安全的数字签名方案不符合EU-CMA的安全概念。该数字签名方案的安全性之所以能被打破,是因为所使用的哈希函数curl-p没有抗碰撞的属性。

    3. 什么是curl-p?

    Curl-p是一个哈希函数。哈希函数将任意长度的数据转换为固定长度的输出。你可以将这些输出看作数字指纹。哈希函数旨在满足以下主要特性:

    • 确定性:给定相同的输入,获取的哈希值始终相同。
    • 一致性:预期的输入应尽可能一致地映射到输出范围。
    • 不可逆性:给定哈希值,应该很难找到相应的输入。但“非常困难”的定义很宽泛,因为它取决于许多外部因素,比如随着时间推移而变化的技术,但专家们对此没有争议。在普通硬件上计算冲突是不可能的,并且对于安全的哈希函数来说,任何人都很难找到冲突。如果政府能够找到冲突,那么哈希函数就不会被认为是安全的。

    curl-p的目的是使哈希函数表现出高度随机的行为,它使我们将哈希值视为唯一的且防篡改的。

    4. curl-p的作用是什么?

    Curl-p是由Sergey Ivancheglo编写的自定义哈希函数,他也被称为Come-from-Beyond。它是数字签名方案的一部分,用于确保交易的身份验证的完整性。在消息上构造数字签名的过程包括将数据哈希并用私钥加密哈希值。这是加密货币的标准做法。详细解释如下:

    • 身份验证:证明消息是由公钥所有者创建的。如果消息未经过哈希处理,则签名会更长,则需要更多时间进行验证。
    • 完整性:防止消息在创建后被篡改,同时仍然在数字签名下进行验证。

    数字签名是通过用公钥解密签名并将交易数据哈希来进行验证的。如果未加密签名和相应的哈希值相同,则认为数字签名有效。

    然而,预期中的数字签名要求哈希函数表现出高度的随机行为。如果curl-p表现出足够的非随机行为,攻击者就可以构造一个没有私钥签名但具有相同签名的消息,因为消息的哈希值是相同的。这意味着数字签名方案被破坏,攻击者可能会伪造交易来窃取资金,因此交易的数字签名(扩展为curl-p)在软件生产中具有关键的安全作用。

    5. curl-p必须满足哪些安全属性才能防止攻击?

    我们可以简单的把这个问题归结为冲突,即两则不同的消息可以用curl-p哈希得到相同值的频率。如果两则消息哈希值相同,那么签名将是相同的,如果攻击者的消息是有效的交易,这意味着可能有人通过使用前一个交易的签名来使用你的Iota币。任何curl-p的冲突都会对数字签名方案发起攻击,因此curl-p应该具有最强的安全性。

    用于满足最严格的安全属性的哈希函数被称为加密哈希函数。这些安全属性包括:

    • 抗碰撞性:攻击者应该无法找到两则消息m1和m2使得hash(m1) = hash(m2)。
    • 抗原像攻击:如果提供哈希值h,攻击者应该无法找到消息m使得m = hash(h)。
    • 抗第二原像攻击:如果提供消息m1,攻击者应该无法找到消息m2,使得hash(m1)= hash(m2),m1!= m2。

    6. curl-p是加密哈希函数吗?

    IOTA开发人员一直含糊其辞,但更频繁地声称curl-p并非旨在成为加密哈希函数。他们反驳了DCI实验室关于漏洞的说法,因为他们认为在curl-p中不需要抗碰撞性。换句话说,他们不能因为curl-p是一个不安全的哈希函数而被指责,因为它从来没有打算保证curl-p是安全的。

    然而,curl-p在确保使用拥有超过10亿美元生产系统的安全方面发挥了关键作用。curl-p的充分非随机行为可能使资金被盗。除非允许资金窃取是curl-p的预期功能,否则其应该被设计为满足我概述的最严格的安全属性,这将使其成为加密哈希函数。如果按照IOTA开发人员所说,curl-p并不是一个加密哈希函数,那么这就是一个重大的设计缺陷。

    因此,IOTA开发人员要么为其极其糟糕的设计负责,要么认为他们自己构建了一个安全的哈希函数,因为他们无法找到破解它的方法。两者都表现出极差的判断力,第一种是健忘,第二种是对其安全性过于自信。

    7. 是否存在漏洞?

    存在。DCI实验室发现curl-p并不具有抗碰撞性,他们展示了两则消息的真实例子,这两则消息被网络视为有效交易,但是哈希到相同的值。他们通过利用curl-p中的非随机行为来改变消息中的一些位以生成哈希值相同的新值。这些位就是交易金额。因此,如果你向某人发送了一些Iota币,那么你可以通过修改交易来发送不同的金额。

    DCI实验室还展示了理论上的攻击是如何通过破坏抗碰撞性来实现的。你可以构造两项哈希值相同的交易来发送Alice的Iota币,然后让Alice签署第一项交易,然后用这个签名发送第二项交易。

    正如密码学专家、安全研究人员等普遍理解的那样,漏洞确实存在,原因如下:商用硬件上的curl-p上发生了碰撞;curl-p中被打破的抗碰撞性是用来自同一地址的事务来表示的;使用curl-p来哈希交易数据意味着用户资金可能被盗;加密哈希函数不可能实现这一点……

    但如果我认为这次攻击没有那么严重呢?

    “安全”(secure)一词用于哈希函数,“漏洞”(vulnerability)一词用于软件,它们都有明确的定义,这些定义独立于任何人对这些攻击破坏力的感受。密码学对数字签名方案的安全性有严格的定义,且数字签名方案的安全性也与个人感受无关。因此,我们完全可以说curl-p是不安全的,并且其存在一个漏洞,但攻击并没有那么严重。因为攻击没有那么严重,所以不存在漏洞这种说法是不正确的。

    8. 为什么要考虑标准的EU-CMA而不是实际的攻击呢?

    没有受过软件工程或密码学培训的人最常犯的一个错误是,EU-CMA攻击是一个抽象的游戏,不能很好地转化为实际的结果。毕竟,IOTA的协调员可能自己做了一些验证,这肯定会影响概述的攻击的可行性,而这并不是EU-CMA模拟的一部分。当然也有一些外部组件对攻击很重要——不建议重用地址。让我们先把明显的细节放在一边,即协调器是一个临时措施,而且它是闭源的——这意味着没有人知道它到底做了什么。

    如果关于系统安全性的评判标准是“能否在生产系统中演示实际的攻击”,那么在实际部署这些演示时,会出现一些明显的问题。首先,黑客攻击计算机系统是违法的。其次是关于安全漏洞的微妙本质——你真的认为等到商用硬件上的SHA-1被破坏后再将其用于关键的互联网基础设施是一个好主意吗?还有一个事实是,闭源代码是不能进行公开访问的——你认为我们应该忽略那些闭源系统的安全性吗?这样的例子不胜枚举。

    如何解释安全性的标准,你可以将其视为最佳实践。最佳实践就像专家的常识一样,因为同样的错误往往会重复出现——比如创建自定义的哈希函数。EU-CMA攻击包含了我们期望从构建了安全方面的最佳实践的系统中看到的行为。也就是说,如果你实现了EU-CMA关于数字签名安全的概念,那么你就知道存在某些安全保证,甚至不需要为系统的各个部分创建巨大的流程图。从另一个角度来看,如果你系统的安全性依靠外部验证来维护被破坏的协议的完整性,那么你就会有一个过于草率、复杂的系统,它很容易出现安全漏洞。

    Sergey说EU-CMA对数字签名不重要,因为他的系统会做额外的验证,这就像在说:

    • 你不用担心把所有的硬币都放在一个热钱包里,因为没有人知道这台电脑在哪里以及它的密码。
    • 你不必用VPN来向政府隐藏你的IP,因为他们的隐私政策说他们不保存日志。
    • 你无需为重复使用密码而担心,因为密码的安全性很高。

    这些例子听起来很愚蠢吗?当然!但它们本质一样。安全漏洞在技术上可以通过外部因素得到缓解。但是这种缓和因素是非常脆弱的,特别是对那些安全因素至关重要的东西来说。如果与大型热钱包交易可以获得10亿美元呢?它完全打破了你的安全模式。IOTA开发人员冒着损失用户10亿美元的风险——用他们自己的话说,因为他们不知道有比在生产系统中测试未经同行评审的自定义加密原语更好的方法,也不知道有比只是部署它并查看是否有人破坏了它更好的方法——这极其荒谬。(参见:泄露邮件第4封)

    9. 如果现实生活中的攻击看起来还不那么切合实际,为什么安全研究人员还会担心呢?

    因为哈希函数的历史给了我们一些教训,那就是第一个漏洞只是开始,随着时间的推移,会发现更多的漏洞。DCI团队非常接近于找到一个原像攻击,他们先发制人地声明他们与IOTA进行了私下交流。DCI实验室表示,他们认为这是有可能的,但还无法对其进行量化。他们还认为curl-p也破坏了抗原像攻击,而并不难以置信。

    如果发现了curl-p的原像攻击,那么实际的攻击将十分危急且无法恢复。原像攻击意味着你不需要为消息签名攻击就可以成功。想象一下攻击者设置了大量的Iota完整节点。现在使用一个轻钱包连接这些节点,并传播你的交易。该交易不会被传到网上。相反地,他们会伪造一个假交易,然后用你的签名进行传播。

    10. 将SHA-1作为哈希函数安全性的案例研究

    显示非随机行为迹象的哈希函数只是一个开始。SHA-1于1995年被正式指定。2005年,在其规范化整整十年后,漏洞开始被发布,其攻击力比暴力攻击更有效。与curl-p不同的是,在2005年的时候还没有发现实际的碰撞。SHA-1提供的安全性比承诺的要低,差距太小而不容忽视,可能在政府的预算范围内无法攻破,但这足以让密码学界认为它是不安全的。

    在接下来的几年里,打破SHA-1安全性的障碍不断变小,并且完全在政府的掌控之中。同样地,尽管没有发现碰撞事实,但许多组织都建议用SHA-2或SHA-3来代替SHA-1。2017年,终于发现了一次碰撞。这是一次碰撞攻击,他们证明它可以用来做一些事情,比如构造一个低租金的合同,用具有相同哈希值的高租金合同来交换数字签名。

    SHA-1的历史总结:

    • 第一个漏洞是在其规范之后整整十年才发现的。
    • 一旦攻击被证明比暴力更有效时,密码学家就认为它是不安全的,尽管这是不切实际的。没有一个密码学家认为SHA-1是安全的,因为它太难攻击了。
    • 尽管在2017年之前,没有人负担得起在SHA-1中发现碰撞的计算能力,但政府完全有能力做到这一点。
    • 自2005年以来,每年对SHA-1的攻击都变得越来越高效。换句话说,一旦SHA-1显示出非随机行为,对它的尝试性利用变得越来越好。

    与此curl-p比较:

    • 第一个漏洞是在IOTA在交易所上市后一个月内发现的,该项目也因此受到公众关注,市值超过10亿美元。而SHA-1花了10年的时间才得到研究人员的关注。
    • 尽管curl-p在保护签名完整性方面与SHA-1有类似的作用,但Sergey Ivancheglo并不认为抗碰撞性很重要。整个密码学界都认为SHA-1的抗碰撞能力非常重要。这种几乎被破坏的抗碰撞性会导致SHA-1的不安全调用。
    • 根据泄露的电子邮件,IOTA开发人员使用curl-p来处理关键的安全应用程序,但并不认为有必要将其提交给密码学专家的同行进行评审。用他们自己的话来说,他们觉得确保自制的加密技术安全性的唯一方法就是在生产系统中使用它然后看它是否受到攻击。
    • 根据DCI实验室的数据,对curl-p的攻击花费了20个小时。

    11. 但你确定真的有漏洞吗?

    根据密码学的定义,有漏洞。

    评估说curl-p不安全是因为它在生产系统中发挥着关键的安全作用(意味着它应该是一个加密哈希函数),但是它已经破坏了抗碰撞性(它不是一个安全的加密哈希函数)。

    评估认为在交易的数字签名方案中存在漏洞是因为有不安全的哈希函数,它意味着你可以使用以前交易的签名来伪造交易。

    12. 但你说这是密码学的定义……

    更严格地说,DCI实验室表明,根据EU-CMA,IOTA使用curl-p的交易数字签名方案失败了。在这种攻击中,攻击者能够签署他们选定的任何消息,并可以根据需要重复生成和签署消息。如果任意两条消息生成相同的签名,则攻击成功。

    对于此次攻击,消息来源是未签名的IOTA交易。由于交易的签名实际上是交易数据的curl-p哈希函数的签名,因此打破curl-p的抗碰撞性就足以赢得这场游戏。DCI实验室的研究人员通过产生碰撞消息打破了curl-p的抗碰撞性。这些碰撞消息是良构事务,这是一个额外收获。

    但是IOTA反驳说,EU-CMA的安全也被破坏了……

    相信我,我们现在都已经习惯了。

    泄露的电子邮件中,Sergey反驳了这一说法,理由是对EU-CMA安全的定义过于抽象。(这就是他提到的“真空中的球形签名方案”。)他的观点十分令人困惑,部分原因是他反复引用维基百科(Wikipedia)和security.stackexchange.com等网站上的非正式信息来为自己的观点辩护,他认为这些信息具有权威性。Sergey反复引用安全的定义,但是不考虑加密货币协议。其他时候,他对EU-CMA安全的定义提出异议,称其需要进行原像攻击。在推特上,他经常挑战那些认为IOTA很容易受到原像攻击的人,Heilman反复强调,这对于他们所概述的EU-CMA攻击来说不是必要的。

    Sergey在一篇文章中更仔细地阐述了他的理解。很明显,他的理解力还很差劲。他努力地从一个非常直截了当的角度来看待EU-CMA安全的各个方面。例如,EU-CMA允许攻击者获取从目标生成的任何消息的签名。因此,DCI实验室通过使用由他们控制的私钥来模拟提供这些消息的受害者。Sergey认为这违规了,因为他们模拟的是可以创建密钥的虚拟受害者,而不是无法创建密钥的虚拟受害者。

    Sergey也误解了“微不足道”这个词的概念。他一再强调,如果DCI实验室不提供在curl-p中查找碰撞的代码,那么他们就没有任何可信度,就好像这改变了curl-p在普通硬件上存在碰撞的事实,意味着碰撞对密码学者来说是微不足道的。

    Sergey并不是提出几个问题而已,而是在质疑密码学中他所能质疑的一切。如果他不理解这些概念,他应该去上与密码学相关的课程,在课堂上提出自己的问题,而不是去骚扰撰写漏洞报告的安全研究人员。如果做不到这一点,他应该聘请密码学专家来回答他的问题,因为他要求的细节如此之多,以至于DCI实验室能够主动满足其要求变得遥遥无期。

    13. 结论

    DCI实验室对IOTA存在漏洞的评估与密码学的定义一致。每一位密码学家、安全研究员和主要加密货币的开发者都公开发表了言论,他们都同意DCI实验室的观点。

    IOTA对此提出异议的原因如下:

    • 他们缺乏对密码学的功能性理解,以至于将security.stackexchange.com上的的非正式答案作为严格的定义;
    • 他们缺乏研究安全问题的直觉,以至于在没有同行评审的情况下,他们就开始使用自己的加密原语并在生产系统上进行测试;
    • 他们缺乏社会技能,无法准确解释密码学定义中更定性的方面,比如“微不