【BUUCTF】【WEB】Nmap

【BUUCTF】【WEB】Nmap 考点escapeshellarg() escapeshellcmd()组合参数注入漏洞Nmap 命令参数Bash 字符串解析规则错误信息泄露的利用。打开题目尝试输入127.0.0.1尝尝咸淡发现这个页面貌似什么有用的信息都没有。回到主界面尝试输入一个单引号有个result.php文件同时发现主机被“吃掉”了这代表着我们输入的被转义了。这证明了有escapeshellarg()函数的存在。为什么呢因为escapeshellarg()的作用是确保输入作为一个完整的参数详细描述就是把任意输入变成一个 安全的、完整的单个 shell 参数。至于具体工作原理......这里留个悬念后面在解释。尝试输入 -v 后发现主机还是被“吃掉”了 -v 由六个字符组成解释一下各个字符的含义 提前关闭后台escapeshellarg()给我们输入加上的单引号-v Nmap本身的一个参数用于打印版本信息 语法闭合符闭合后台escapeshellarg()给我们输入末尾加上的单引号当输入 -v 后主机仍被吃掉就代表这另一个函数escapeshellcmd()也存在。为什么呢因为escapeshellcmd()的作用是转义了单引号字符串内部的反斜杠目前可以确定是escapeshellarg() escapeshellcmd()组合漏洞现在讲明整个paylaod的处理过程先说escapeshellarg()的算法用一对单引号 把整个输入包裹起来把输入中所有的单引号都替换成\也就是说当输入 -v 时经过escapeshellarg()的处理将 -v //发现没有格式不是-v转化为注意是两对单引号不是一对双引号。至于单引号中间为什么有空格先填个坑...... -v 再把中间的两个单引号替换为\ \ -v \ 再说escapeshellcmd()的算法escapeshellcmd()会扫描整个字符串不管上下文只要看到它认为是 shell 特殊字符 的东西就在前面加一个反斜杠escapeshellcmd()认为的特殊字符包括 \ $ | ; ( ) 等它会将 \ -v \ 它看到了两个反斜杠 \\ -v \\ 这里有个问题为什么最终结果是执行成功呢经过两次转义后关键部分是 \\ \\ Bash是什么所有的命令注入漏洞本质上都是利用了 Bash 的解析规则。Bash 会做这几件事解析把你输入的字符串拆分成 命令 和 参数翻译把人类能看懂的命令翻译成内核能执行的机器指令执行调用操作系统内核执行对应的操作返回把执行结果显示在屏幕上所以——Bash 逐字符解析过程字符序号字符当前解析状态解析动作结果1初始状态进入单引号字符串模式-2空格单引号模式普通字符保留3单引号模式遇到单引号退出单引号模式-4\无引号模式反斜杠转义后面的一个字符-5\无引号模式被前面的反斜杠转义变成一个普通的\\6无引号模式普通的单引号字符7无引号模式遇到单引号重新进入单引号模式-我们可以发现escapeshellcmd()加的那个额外的反斜杠跑到了单引号字符串的外面在无引号上下文中\\被解析为一个普通的\然后后面的在无引号上下文中就是一个普通的单引号所以整个字符串 \\ -v \\ 在 Bash 中最终被解析为 \ -v \ 也就是 -v 两个连续的单引号在 Bash 中就是一个空字符串所以整个命令等价于nmap -v按理说会出现版本信息对吧那为什么没有显示版本信息呢这是因为Nmap 的命令行参数解析规则和后台默认参数的顺序导致的。Nmap 的命令行语法是绝对严格的nmap [扫描类型] [选项参数] {目标}所有选项参数比如-v、-iL、-o等必须放在目标的前面。任何放在目标后面的内容即使以-开头也会被 Nmap 当作另一个扫描目标而不是选项。对比一下漏洞是否存在的区别情况输入Nmap的行为页面显示漏洞存在 -v 尝试扫描空字符串作为目标Host maybe down漏洞不存在 -v 尝试扫描整个字符串作为目标Failed to resolve -v 这个漏洞的本质是escapeshellarg()创建了一个安全的单引号字符串escapeshellcmd()愚蠢地转义了单引号字符串内部的反斜杠导致这个反斜杠在 Bash 解析时跑到了单引号字符串的外面从而产生了一个未被转义的单引号打破了整个参数的边界让我们可以注入任意的 Nmap 命令参数既然知道最终还是会等于nmap的参数想到nmap的几个参数-iL file从文件读取扫描目标本题核心用于读取任意文件-oN/-oG/-oX file将扫描结果写入文件用于写 webshell 或保存结果--scriptexec执行 Nmap 脚本用于执行系统命令第三个想来没什么用毕竟我们只需要读取文件扫描里面的内容并且把它输入到另一个文件就行了。所以我们得出一个payload -iL /flag -o result.txt 这里有个特别重要的细节这个细节出错整个payload用不了是时候填坑了——最左和最右两个单引号的各两旁都有个空格这与Bash绝对不能打破的一个铁律有关只有被空格分隔开的东西才会被当作不同的参数。把单引号比作门如果没有空格即使你把门打开了这些参数还是会和门粘在一起变成一个东西。只有加了空格参数才会和门分开变成两个不同的东西。也就是开头单引号 空格结尾空格 单引号把payload输入进去看着是不是没什么区别别慌因为我们把内容输入到了result.txt里面所以我们直接查看这个文件就好了。一顿分析后终于看到flag了。最后分析一下这个输出作为结尾......因为flag不是一个有效的域名或 IP 地址所以 Nmap 会抛出一个错误Failed to resolve flag{}.而 Nmap 有一个特性所有的错误信息和扫描结果都会同时输出到两个地方标准输出stdout会被 PHP 的system()函数直接打印到网页上指定的输出文件也就是我们用-o result.txt指定的文件END