cbc字节翻转攻击

  1. CBC字节翻转攻击
    1. CBC原理
    2. 对cbc的攻击
    3. 实例说明
    4. CTF实例
      1. iscc2018-Only admin can see flag
      2. bugku

CBC字节翻转攻击

CBC原理

对cbc的攻击

实例说明

  我们举例说明一下这个例子,这里有一个明文序列:

a:2:{s:4:"name";s:6:"sdsdsd";s:8:"greeting";s:20:"echo 'Hello sdsdsd!'";}

  我们的目标是将“s:6”当中的数字6转换成数字“7”。我们需要做的第一件事就是把明文分成16个字节的块:

- Block 1:a:2:{s:4:"name"; 
- Block 2:s:6:”sdsdsd”;s:8
- Block 3::”greeting”;s:20
- Block 4::”echo ‘Hello sd
- Block 5:sdsd!’”;}

  我们需要更改的字符位于块2,因此我们需要改变块1的密文来改变块2的明文。在密文中改变的字节,只会影响到在下一明文当中,具有相同偏移量的字节。
  因此我们只需要改变在第一个密文块当中,偏移量是2的字节。在第2行我们得到了整个数据的密文,然后在第3行中,我们改变块1中偏移量为2的字节,最后我们再调用解密函数。

$v = "a:2:{s:4:"name";s:6:"sdsdsd";s:8:"greeting";s:20:"echo 'Hello sdsdsd!'";}";
$enc = @encrypt($v);
$enc[2] = chr(ord($enc[2]) ^ ord("6") ^ ord ("7"));
$b = @decrypt($enc);

  这样我们就把“s:6”当中的数字6转换成数字“7”,达到来了我们想要的目的。

CTF实例

iscc2018-Only admin can see flag

查看源码得提示index.txt,访问得到源码

<?php
include 'sqlwaf.php';
define("SECRET_KEY", "................");
define("METHOD", "aes-128-cbc");
session_start();

function get_random_iv(){
    $iv='';
    for($i=0;$i<16;$i++){
        $iv.=chr(rand(1,255));
    }
    return $iv;
}
// 使用aes-128-cbc 模式加密
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));// cookie[iv] = 随机生成的iv 的base64
    setcookie("cipher", base64_encode($cipher));// cookie[cipher] = 加密值的base64
}
function show_homepage(){
    if ($_SESSION["username"]==='admin'){//发现当账号为admin,才会显示flag,
        echo '<p>Hello admin</p>';
        echo '<p>Flag is *************</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>';
    die();
}
// 解密cipher
function check_login(){
    if(isset($_COOKIE['cipher']) && isset($_COOKIE['iv'])){
        $cipher = base64_decode($_COOKIE['cipher']);
        $iv = base64_decode($_COOKIE["iv"]);//cipher和iv变量均中cookie数组中取
        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!");
        }
    }
}

if (isset($_POST['username'])&&isset($_POST['password'])) {
  $username=waf((string)$_POST['username']);
  $password=waf((string)$_POST['password']);
  if($username === 'admin'){
        exit('<p>You are not real admin!</p>');//当我们以admin账号登录时,程序会直接跳出
    }else{
        $info = array('username'=>$username,'password'=>$password);
        login($info);
        show_homepage();
    }//否则正常登录,并将用户信息存在info数组中传入login函数,并调用show_homepage函数。
}
else{
  if(isset($_SESSION["username"])){
        check_login();
        show_homepage();
    }
}
?>
<!DOCTYPE html>
<html lang="en" >
<head>
  <meta charset="UTF-8">
  <title>Paper login form</title>
      <link rel="stylesheet" href="css/style.css">
</head>
<body>
  <div id="login">
  <form action="" method="post">
    <h1>Sign In</h1>
    <input name='username' type="text" placeholder="Username">
    <input name='password' type="password" placeholder="Password">
    <button>Sign in</button>
</div>
</body>
</html>

思路就是构造一个Admin用户,然后将大写的A翻转成小写的a,即是admin。我们点击登录之后,可以在cookie中获取到iv和cipher的值(看14行的login函数),然后我们先将cipher的第9个字符使用异或运算翻转成小写字母a,因为info数组序列化后,我们要翻转的大写字母A在下标为9的位置,每个分组的长度为16,因为返回的iv变量长度为16(要先经过base64解密)

  1. s:2:{s:8:”userna
  2. me”;s:5:”Admin”;
  3. s:8:”password”;s
  4. :5:”admin”;}

要第二组的b变为d 就要第一组的u改变

python脚本:

import urllib,base64,requests,re

url = "http://118.190.152.202:8001/index.php"
datas = {
    "username" : "Admin",
    "password" : "admin"
}

r = requests.post(url,data=datas)
cipher = r.cookies.get("cipher")
cipher = base64.b64decode(urllib.unquote(cipher))
offset = 9
new_cipher = cipher[:offset] + chr(ord(cipher[offset])^ord("A")^ord("a")) + cipher[offset+1:]
new_cookies = requests.utils.dict_from_cookiejar(r.cookies)
new_cookies["cipher"] = urllib.quote_plus(base64.b64encode(new_cipher))

r2 = requests.get(url,cookies=new_cookies)
plain = base64.b64decode(re.findall("decode\('(.*)'\)",r2.text)[0])
iv = base64.b64decode(urllib.unquote(new_cookies["iv"]))
old = plain[:len(iv)]
new = 'a:2:{s:8:"userna'
new_iv = "".join([chr(ord(iv[i])^ord(old[i])^ord(new[i])) for i in xrange(16)])
new_cookies["iv"] = urllib.quote_plus(base64.b64encode(new_iv))

r3 = requests.get(url,cookies=new_cookies)
print(r3.text)

bugku

Bugku上的一道题来做分析:
题目链接:http://47.93.190.246:49168/
进入后发现页面存在源码泄露:index.php.swp
恢复后审计源码:

function get_random_iv(){
    $random_iv='';
    for($i=0;$i<16;$i++){
        $random_iv.=chr(rand(1,255));
    }
    return $random_iv;
}

首先随机生成了一个16位的iv;
然后从

$info = array('username'=>$username,'password'=>$password);
        login($info);

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));
}

可见,对传入的账号和密码进行序列化,作为明文,然后对其进行AES加密,其中使用到了随机生成的iv
后将加密后的内容进行base64编码,放入cookie中。

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!");
        }
    }
}

然后再对传入的cookie中的密文解密,然后对明文就行反序列化(如果反序列化失败就打印出明文的base64编码),后把反序列化后的明文,即Info中的username还给username,最后进行判定:

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>';
}

如果用户名是admin,就给出flag,否则不给,但值得一提的是:

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();
    }
}

登录时做出了限制,如果用admin登录是显然不行的。
所以这时就需要CBC字节翻转攻击来实现了
登录时:可以使用

username=1dmin;
password=Mang0;

此时我们要做的就是把1dmin通过翻转攻击,把’1‘变成‘a’,即可变成admin登录成功得到Flag
首先按照步骤:将我们传入的Info进行序列化,得到明文:
a:2:{s:8:"username";s:5:"1dmin";s:8:"password";s:5:"Mang0";}
然后对其进行分组:

block 1 : a:2:{s:8:"userna
block 2 : me";s:5:"1dmin";
block 3 : s:8:"password";s
block 4 : :5:"Mang0";}

我们所要改变的即block 2中的偏移量为9的那个明文,即1
所以按照攻击方式,应该改变block 1中有相同偏移量的那个密文,即偏移量为9的值
所以得到以下公式:
cipher = cipher[:9] + chr(ord(cipher[9]) ^ ord(‘1’) ^ ord(‘a’)) + cipher[10:]
故可将1dmin变成admin,但有一点需要注意,这样改变后,密文的值发生了改变,将其进行解密后反序列化,是会失败的,从而会把无法反序列化的明文打印出来(因为我们对block 1进行了改变,虽然block 2变成了我们所希望的值,但block 1却变成了未知的量)
所以此时,需要改变iv的值来改变block 1的值
(注:这就是cbc的处理方式,iv的值改变block1的值,block1的值改变block2的值……)
故此,我们需要一个正确的Iv,使block 1依旧为a:2:{s:8:"userna
故此得到第二个公式:(plain为无法反序列化打印出来的被base64编码的明文)

want = 'a:2:{s:8:"userna'
first_16 = ''
iv = base64.b64decode('你一开始随机生成的被base64编码过的iv')
for i in range(16):
    first_16 += chr(ord(plain[i]) ^ ord(iv[i]) ^ ord(want[i]))
newiv = first_16

这样就可以将密文前16位的值,即block 1的明文变成我们想要的a:2:{s:8:"userna
故此即plain伪造成功,此时的plain是绝对可以被反序列化的
最后,我们将伪造的密文和伪造的iv传入cookie,即可被解密还原成我们伪造的plain
即:
a:2:{s:8:"username";s:5:"1dmin";s:8:"password";s:5:"Mang0";}
变成了
a:2:{s:8:"username";s:5:"admin";s:8:"password";s:5:"Mang0";}
最后即可以admin的身份成功登入网站,拿到flag


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 951207194@qq.com

文章标题:cbc字节翻转攻击

文章字数:1,964

本文作者:Mang0

发布时间:2018-06-01, 00:47:50

最后更新:2018-11-02, 21:52:11

原始链接:http://mang0.me/archis/2947d8f2/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录
×

喜欢就点赞,疼爱就打赏