在黑盒扫描nday漏洞的时候经常碰到公开poc质量良莠不齐,而且跑起来的方法也是各式各样。
nuclei作为安全一大开源神器,可以很好的解决公开poc格式杂乱的问题,同时基于go语言原生的并发优化,对于批量扫描url也有很好的效果。
下面来简单讲一讲nuclei的http模块,方便平常对一些漏洞进行自定义的批量扫描。
一、简要概述
项目所在地址:
https://github.com/projectdiscovery/nuclei
nuclei官方提供的template仓库:
https://github.com/projectdiscovery/nuclei-templates
nuclei由go语言编写而成,windows上不用安装go环境,可以直接用打包好的nuclei.exe。
windows版release链接:
https://github.com/projectdiscovery/nuclei/releases/download/v3.4.4/nuclei_3.4.4_windows_amd64.zip
对于命令行的使用,官方有提供中文文档,在此不赘述。
下面是我个人两条常用的命令,用于单次官方poc排查和批量poc排查
nuclei -u http://127.0.0.1:8080/ -t http/cves/2025/CVE-2025-24813.yaml.nuclei.exe -t templateList.txt -l urlList.txt --proxy "http://127.0.0.1:8080"
二、template编写
nuclei通过读取yaml文件作为模板来运行程序,模板中的键值对类型很多,碍于篇幅在此仅讲述常见的http协议扫描。下面以用于nacos指纹排查nacos资产的poc为例,所有的注意事项都在yaml的注释中。
#id字段:标识漏洞的id,只允许英文数字和,不允许空格。官方提供的模板中该处一般都是CVE编号,或者tomcat-RCE的资产-漏洞描述
id:nacos
#info字段:用于标识漏洞的信息,官方提供字段有name, author, severity, description, reference, tags 和metadata。其中,name,author,severity是必须字段,其他可以选用。
info:
name:nacos指纹扫描
author:cmq
severity:high
#http字段:指示nuclei调用http模块。该模块存在两种形式,basic http和raw http。basic http下有method和path字段,而raw http只用将原始的http请求整个复制在raw中即可。实际使用时会经常用到burpsuite,从burp中直接复制原始http请求比较方便,因此在此仅提供raw模块的示例。
http:
#raw字段,直接将burp中的发包复制过来即可。注意Host后面要替换为{{Hostname}}。{{path}}用于自定义路径,与后面的payloads模块相结合,可以对多个路径发包。
-raw:
-|
GET /{{path}} HTTP/1.1
Host: {{Hostname}}
#爆破模块,根据txt中的payload进行爆破。其中,"path"键可以自定义,例如finger: poc/path.txt,对应raw改为{{finger}}。attack有三种模式,batteringram,pitchfork,clusterbomb,与burp中的几种爆破模式相对应。如果payloads文档有多个,应使用pitchfork/clusterbomb。
attack: batteringram
payloads:
path: poc/path.txt
#是否跟随重定向,不开启该选项nuclei不会跟踪302直到最终网页
redirects: true
#matchers是匹配器,用于检测返回包的字段。type代表验证的类型。regex指正则表达式,与之类似的还有type:word(单词匹配),个人更偏好于regex,因为更灵活。status则是返回的状态码。
#除了regex和status外,还有type:dsl(官方提供的dsl语句),type:binary等,大多数情况下使用status+regex两项即可。
matchers:
-type:regex
#part这里的all是指将返回包的body和head都进行扫描,可以用part:head,part:body来指定扫描的部分。
part:all
regex:
#(?i)表示忽视大小写
-(?i)(nacos-logo)
-(?i)(alibaba)
#condition用于逻辑关系判断,这里的condition是type:regex内部的,需要同时满足两条正则才会返回true。
#如果没标明condition默认就是或逻辑,满足任意一条即可,具体可参考type:status。
condition:and
#http状态码
-type:status
status:
-200
-403
#matchers之间的逻辑关系,表示要同时满足regex和status条件
matchers-condition:and
该脚本对真实环境的扫描截图如下。
从burp中的抓包可以看出来,nuclei有跟踪302的结果,直到/nacos/。
nuclei还有其他大量的功能可用于各种其他复杂场景,详情可参考官方文档:
https://docs.projectdiscovery.io/templates/introduction
三、批量编写脚本分享
分享一个个人日常使用的用于快速生成template的脚本,本质就是读取excel表格中的数据然后插入到固定的模板中并生成。
yaml的格式要求比较严格,为了避免各种奇怪的格式生成问题直接一行一行都print出来了方便调试。
import pandas as pd
from datetime import datetime
EXCEL_FILE = '最新poc.xlsx' # Excel 文件名
# 用于检测burp包中的host替换为{{hostname}}
def indent_raw(raw_string, spaces=8):
lines = raw_string.strip().splitlines()
out = ''
for line in lines:
if line.lower().startswith('host:'):
line = 'Host: {{Hostname}}'
out += ' ' * spaces + line + 'n'
return out
def main():
# 读表
df = pd.read_excel(EXCEL_FILE, dtype=str)
#创建rows结构,存储excel表中信息
rows = []
now=datetime.now()
date=now.strftime('%Y%m%d')
# 遍历表中每一行
for idx, record in df.iterrows():
# 从表格里取值并去掉两端空白
id = str(record['漏洞编号']).strip()
name = str(record['漏洞名称']).strip()
raw = str(record['burp请求包']).strip()
match_type = str(record['校验方式']).strip().lower()
status = int(record['响应码'])
pattern = str(record['校验关键词']).strip()
rows.append({
'id' : id,
'name': name,
'raw' : raw,
'match_type': match_type,
'status': status,
'pattern': pattern,
})
# 逐行生成 YAML 文件
for i, r in enumerate(rows, start=1):
filename = f"poc/{date}{r['name']}.yaml"
with open(filename, 'w', encoding='utf-8') as f:
f.write(f"id: {r['id']}nn")#注意,id必须要满足正则^([a-zA-Z0-9]+[-_])*[a-zA-Z0-9]+$,所以不能带中文
f.write("info:n")
f.write(f" name: {r['name']}n")
f.write(" author: cmqn")
f.write(" severity: highnn")
f.write("http:n")
f.write(" - raw:n")
f.write(" - |n")
f.write(indent_raw(r['raw']))
f.write(" redirects: true")
f.write("n matchers-condition: andn")
f.write(" matchers:n")
# 如果是 re(正则),使用 regex matcher
if r['match_type'] == 're':
f.write(" - type: regexn")
f.write(" part: alln")
f.write(" regex:n")
f.write(f" - (?i){r['pattern']}n")
# 状态码 matcher
f.write(" - type: statusn")
f.write(" status:n")
f.write(f" - {r['status']}n")
print(f"已生成:{filename}n")
#输出命令到命令行
print(f"../nuclei.exe -t {filename} -l ../../urlList.txtn")
print(f"../nuclei.exe -t {filename} -l ../test.txtn")
#将文件名插入到txt中,方便批量扫描。程序未对pocs.txt做去重处理,多次运行会插入多个相同名字的yaml。
with open("pocs.txt", 'a', encoding='utf-8') as f2:
f2.write(f"poc/{date}{r['name']}.yamln")
if __name__ == '__main__':
main()
运行效果
生成yaml如下
id:geoserver
info:
name:geoserver指纹扫描
author:cmq
severity:high
http:
-raw:
-|
GET / HTTP/1.1
Host: {{Hostname}}
redirects:true
matchers-condition:and
matchers:
-type:regex
part:all
regex:
-(?i)(geoserver)
-type:status
status:
-200
原文始发于微信公众号(安全驾驶舱):【web安全】nuclei使用分享
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论