CBC翻转字节攻击
CBC加密过程(密文分组链接模式
异或后加密
攻击点为IV或者加密后的某段密文
改第一组明文的信息,需要更改IV
$A = Plaintext[0] = 'h' ;
$B = IV[0] = 可控;
$C = Decrypt(Ciphertext)[0] = ?;
//所以我们需要伪造一个新的IV向量,使得$C ^ New_IV = 我们需要的明文
//因为有
$C ^ Old_IV = Source_str
//所以
$C = Old_IV ^ Source_str
//并且我们还需要
$C ^ New_IV = Target_str
//即
$C = New_IV ^ Target_str
//所以
Old_IV ^ Source_str = New_IV ^ Target_str
//所以
New_IV = Old_IV ^ Source_str ^ Target_str
已知异或之后的第N-1组密文(Decrypt之后的密文),我们就可以通过字节翻转改变第N组明文
下面假设我们要更改第3组明文
$Old_pt[1]为第2组明文,$Old_ct[1]为第2组密文,$Old_ct[2]为第3组密文
$Plaintext = [
'comment1=wowsuch',
'%20CBC;userdata=',
'*admin=true;come',
'nt2=%20suchsafe%',
'20very%20encrypt',
'wowww'
];//我们要使$Plaintext[2]中的*变成;
//密文全部已知并可控
$Old_pt[1] = Plaintext[1] = '%20CBC;userdata=';
$Old_ct[1] = Decrypt(Ciphertext)[1] = 已知 并且我们攻击的点在这;
$Old_ct[2] = Decrypt(Ciphertext)[2] = 已知;
//所以我们需要伪造一个新的第2组密文,使得$Old_ct[2] ^ $New_ct[1] = 我们需要的明文$New_pt[2]
//因为有
$Old_ct[1] ^ $Old_ct[2] = $Old_pt[2];
//所以
$Old_ct[2] = $Old_ct[1] ^ $Old_pt[2];
//并且还已知
$New_ct[1] ^ $Old_ct[2] = $New_pt[2];
//即
$Old_ct[2] = $New_ct[1] ^ $New_pt[2];
//所以
$Old_ct[1] ^ $Old_pt[2] = $New_ct[1] ^ $New_pt[2];
//所以
$New_ct[1] = $Old_ct[1] ^ $Old_pt[2] ^ $New_pt[2];
https://resources.infosecinstitute.com/cbc-byte-flipping-attack-101-approach/#
https://www.jianshu.com/p/7f171477a603
bugku login4
http://123.206.31.85:49168/
flag格式:SKCTF{xxxxxxxxxxxxxxxx}
hint:CBC字节翻转攻击
有备份文件
恢复
<?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();//随机iv,加密的post提交的username和password的结果—>cipher
$plain = serialize($info);
$cipher = openssl_encrypt($plain, METHOD, SECRET_KEY, OPENSSL_RAW_DATA, $iv);
$_SESSION['username'] = $info['username'];
setcookie("iv", base64_encode($iv));//设置cookie
setcookie("cipher", base64_encode($cipher));
}
function check_login(){
if(isset($_COOKIE['cipher']) && isset($_COOKIE['iv'])){//如果cookie中有cipher和iv
$cipher = base64_decode($_COOKIE['cipher']);
$iv = base64_decode($_COOKIE["iv"]);
//进行CBC模式的AES解密,并对解密结果进行反序列化,设置session中的username为反序列化后数组中的username的值
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'){//username=admin->flag
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'])){//post username!=admin
$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>';
}
}
?>
提交cookie->base64解密->AES(CBC)解密->反序列化->得到username、password
禁止直接提交用户名为admin进行登陆,但是返回flag的条件又是session中用户名要是admin。所以需要构造类似"xdmin"形式的用户名,之后通过修改iv和cipher,通过CBC翻转攻击将字符x还原成"admin"
a:2:{s:8:"username";s:5:"ddmin";s:8:"password";s:3:"123";}
iv的值是随机变化的,即使同一个用户名,多次发送POST数据,也会改变iv,所以提交一次POST后就一次完成,否则就从头再来
序列化内容分组,16个一组
a:2:{s:8:"userna
me";s:5:"ddmin";
s:8:"password";s
:3:"123";}
我们想要改的d->a在第二组的9位(从0开始),那我们要改第一组的第9位。
<?php
$enc=base64_decode("wcj5C0sDD3hBduHkKhFN%2FlYyWtwSUtTbMvCNLIzQESHlZQALF%2F1M5lMIU3atTVIznl%2F1U8whHODSSBFL5EGOZQ%3D%3D");
$enc[9] = chr(ord($enc[9]) ^ ord("d") ^ ord ("a"));
echo base64_encode($enc);
?>
wcj5C0sDD3hBc%2bHkKhFN%2FlYyWtwSUtTbMvCNLIzQESHlZQALF%2F1M5lMIU3atTVIznl%2F1U8whHODSSBFL5EGOZQ%3D%3D
+ / = 要url编码(%2b、%2F、%3D
(enc只要%2F之前的其实就够
<?php
$enc=base64_decode("ABLICF5SX1TTIjjSWuVo821lIjtzOjU6ImFkbWluIjtzOjg6InBhc3N3b3JkIjtzOjM6IjEyMyI7fQ==");
$iv=base64_decode("fnPzpI/TgpGT2Y8THFilug==");
$cleartext = 'a:2:{s:8:"userna';
$newiv = '';
for ($i=0;$i<16;$i++){
$newiv=$newiv.chr(ord($iv[$i]) ^ ord($enc[$i]) ^ ord ($cleartext[$i]));
}
echo base64_encode($newiv);
?>
H1sJlqry5/162cKyI8+jKA==