[网鼎杯 2020 朱雀组]Nmap-wp
信息收集
首先我们拿到题目页面:
打开页面后,你看到的是一个 Nmap 在线扫描工具,输入框写着 "Enter host or IP address to scan"。
我们右击查看源码
发现了一个关键信息,说明flag在服务器根目录/flag文件里,我们的目标就是读取这个文件。
我们尝试输入IP,抓包查看信息。
这里我们发现两个关键点,响应头中X-Powered-By:PHP/5.5.38,php这个版本信息后面会用到。并且页面返回302重定向到result.php?f=715d2,这个f看起来是一个哈希值/文件名。
访问这个页面能看到端口80和主机名localhost等一些信息。我们尝试访问result.php。
返回No filename.给一个不存在的文件名。
试试能不能返回源码,访问result.php?f=index,发现报错信息。
这是一个重要线索,源代码路径暴露了!文件在/var/www/html/,result.php 第 23 行用了 simplexml_load_file("xml/$f"),并且扫描结果保存在xml/目录下的XML文件里。
再看看list.php。
显示已有的扫描记录列表,文件名是 5 位十六进制哈希。
现在我们大致能猜出后端的工作流程:
用户输入IP → PHP执行nmap扫描 → 结果存为XML文件 → result.php读取XML展示
尝试注入
现在我们正常扫描没问题,但不能读取/flag文件。普通输入127.0.0.1只能扫IP,不能读文件。这适合我们需要想办法注入额外的命令或参数来实现读取文件。
我们开始尝试黑名单
host=127.0.0.1 → 正常
host=127.0.0.1 test → 正常(空格没被拦)
host=127.0.0.1 -oG → 正常
host=test.php → Hacker...(拦截了)
host=test.phtml → 正常
host=test.php5 → Hacker...
host=test%20php%20test → Hacker...(php这3个字母被拦)
host=phpinfo → Hacker...(phpinfo被拦)
host=<?php → Hacker...(PHP标签被拦)
host=<?= → 正常黑名单如下:
.php,php,<?php
但是.phtml 没被拦,<?= 也没被拦。
我们尝试-p指定端口扫描
输入127.0.0.1 -p 8080,但是页面返回只扫到 80 端口,-p 8080被当成了主机名的一部分。这就说明整个输入被当作一个参数传给了 nmap,而不是作为多个独立的参数。
我们可以猜测到后端代码把输入用引号包裹起来了,类似于这样:
shell_exec("nmap ... '$host'");这时候我们可以尝试用单引号拼接进行注入,尝试输入' -oG test.phtml '(-oG的意思是将扫描结果以Grepable格式保存,具体其他nmap常见命令可以参考我的https://eternal3.top/archives/61/这篇文章),则拼出来的命令为:
nmap ... -oX xml/xxx '' -oG test.phtml ''这时候第一个单引号和host前面引号拼接为''形成空字符,最后一个引号和host后面的引号形成了空字符,那么这个时候-p变成了nmap的选项,test.phtml是参数。
输入后,访问 /test.phtml
文件被创建了!
那么我们怎么读取/flag呢?
我当时第一个想法是写个webshell,用-oG shell.phtml创建一个.phtml文件,然后在文件内容里塞PHP代码`<?= cat /flag ?>。但问题来了:nmap输出文件的内容是nmap自己生成的,我不能直接控制它写什么。
换一个思路,让nmap自己读文件。
正好nmap有一个-iL选项,功能是从文件中读取目标列表,他会把文件里的每一行当作一个IP或域名来扫描。如果使用-iL /flag,nmap 就会打开 /flag,读取里面的内容,一行一行当作目标来处理。
假设flag文件里的内容是flag{xxx},然后 nmap 会尝试解析它:先当 IP 地址解析 → 格式不对,再当域名 DNS 解析 → 查不到,最后报错:Failed to resolve "flag{xxx}"
这个报错信息会出现在 nmap 的输出里!如果我把这个输出写到文件里,就能看到 flag 了!
开始操作。
但是我们需要把-oG选项替换为-oN选项,因为-oG格式只包含成功扫描的主机的信息,解析失败的错误信息就会被丢弃,因此我们看不到flag,但-oN可以,它包含所有信息,包括错误和警告。
完整payload:
' -oN flag.txt -iL /flag '
访问/flag.txt,拿到flag




