自加密破解--xor

  昨天做一个CTF,遇到了一个自加密的题目,听师傅们说都是原题了,奈何之前没怎么做过,于是昨天花了下时间好好看了一下,顺便学习下。

  首先由url格式和源码,容易猜测是文件包含,利用这个读取到index文件源码:

<?php
/**
 * Created by PhpStorm.
 * Date: 2015/11/16
 * Time: 1:31
 */
header('content-type:text/html;charset=utf-8');
if(! isset($_GET['jpg']))
    header('Refresh:0;url=./index.php?jpg=hei.jpg');
$file = $_GET['jpg'];
echo '<title>file:'.$file.'</title>';
$file = preg_replace("/[^a-zA-Z0-9.]+/","", $file);
$file = str_replace("config","_", $file);
$txt = base64_encode(file_get_contents($file));

echo "<img src='data:image/gif;base64,".$txt."'></img>";

/*
 * Can you find the flag file?
 *
 */

?>

  简单看下,发现是用_替换了config。做到这里还没思路,这里突破点是在.idea文件夹,.idea文件夹是很多工具编写代码时生成的文件夹,如pytharm、phpstorm等均可以生成,本地新建个项目,就会发现里面的内容,大致如下:

然后发现.idea/workspace.xml文件里可能有敏感信息泄露,访问得到

然后利用之前的文件读取,读取该文件源码,这里_换成config即可,得到源码如下:

<?php
/**
 * Created by PhpStorm.
 * Date: 2015/11/16
 * Time: 1:31
 */
error_reporting(E_ALL || ~E_NOTICE);
include('config.php');
function random($length, $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz') {
    $hash = '';
    $max = strlen($chars) - 1;
    for($i = 0; $i < $length; $i++)    {
        $hash .= $chars[mt_rand(0, $max)];
    }
    return $hash;
}

function encrypt($txt,$key){
    for($i=0;$i<strlen($txt);$i++){
        $tmp .= chr(ord($txt[$i])+10);
    }
    $txt = $tmp;
    $rnd=random(4);
    $key=md5($rnd.$key);
    $s=0;
    for($i=0;$i<strlen($txt);$i++){
        if($s == 32) $s = 0;
        $ttmp .= $txt[$i] ^ $key[++$s];
    }
    return base64_encode($rnd.$ttmp);
}
function decrypt($txt,$key){
    $txt=base64_decode($txt);
    $rnd = substr($txt,0,4);
    $txt = substr($txt,4);
    $key=md5($rnd.$key);

    $s=0;
    for($i=0;$i<strlen($txt);$i++){
        if($s == 32) $s = 0;
        $tmp .= $txt[$i]^$key[++$s];
    }
    for($i=0;$i<strlen($tmp);$i++){
        $tmp1 .= chr(ord($tmp[$i])-10);
    }
    return $tmp1;
}
$username = decrypt($_COOKIE['user'],$key);
if ($username == 'system'){
    echo $flag;
}else{
    setcookie('user',encrypt('guest',$key));
    echo "╮(╯▽╰)╭";
}
?>

这里要想获取flag,就必须要使得$_COOKIE['user']的值解密出来等于system,但我们并不知道加密的$key值,而我们是知道guest的密文的,这里是参考的http://bbs.heetian.com/forum.php?mod=viewthread&tid=28,代码如下:

function ss($txt,$m){
        for($i=0;$i<strlen($m);$i++){
        $tmp .= chr(ord($m[$i])+10);
    }
        $m=$tmp;
        $tmp='';
    $txt=base64_decode($txt);
    $rnd = substr($txt,0,4);
    $txt = substr($txt,4);
    for($i=0;$i<strlen($txt);$i++){
        $key .= $txt[$i] ^ $m[$i];
    }
    $s='0123456789abcdef';
    $txt1='system';
        for($i=0;$i<strlen($txt1);$i++){
        $tmp .= chr(ord($txt1[$i])+10);
    }
        $txt1=$tmp;
        $tmp='';
    for($i=0;$i<16;$i++){
        $tmp = $key.$s[$i];
        for($ii=0;$ii<strlen($txt1);$ii++){
            $txt2 .= $txt1[$ii] ^ $tmp[$ii];
        }
        file_put_contents('1.txt',base64_encode($rnd.$txt2)."\r\n",FILE_APPEND);   
        $txt2='';
        
    }
}
ss('eldUVRdOWRhI','guest'); // 设置获取的guest用户的cookie值。

我们先简单看看代码:

加密函数:首先是对明文每个字符ascii加10,然后获取一个4位随机字符串,然后利用该字符串和$key生成下面要进行异或的MD5值,这里异或次数是和加密明文的长度相关的,然后返回base64加密字符串。

解密函数:首先base64解密,然后截取出4位随机字符串,$key生成算法一样,然后同样根据密文长度进行异或,然后对结果字符串每个字符减10.

这里我们首先要知道的是,xor运算,这是可逆的,测试效果如下:

可以看到,只有在密文和密钥异或时得到结果少一位,这是因为密钥和明文长度不一致,php在异或时会自动转换成相同长度,如下:

回到这个题,他根据长度进行异或,由于根据guest获取的key进行异或出来的只有5位,知道他是和MD5值异或的,解密时的rnd又是和加密一样的,因此生成的md5也是一样的,加上system是6位,所以再暴力猜测一遍第6位的值,即可得到解密后为system的密文。

posted on 2016-09-04 11:39  镱鍚  阅读(3885)  评论(0编辑  收藏  举报

导航