毕设扫描器参数Fuzz第一篇:数据的定义读取和装配(爬虫数据和Payload数据)

Posted 区块链市场观察家

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了毕设扫描器参数Fuzz第一篇:数据的定义读取和装配(爬虫数据和Payload数据)相关的知识,希望对你有一定的参考价值。

文章目录

字典文件的数据结构

在项目根目录创建 fuzzDicts 目录,创建 fuzzDicts/params.json,用于测试参数。(使用 json 是因为常见/易读/复用性强)

参数测试Payload格式:不同的漏洞类型、漏洞类型下不同的软件系统、对应Payload。

一级数据是漏洞类型,如 SQLI、XSS等,数据结构是字典格式。(添加字段 description 描述payload,不需要专门使用一个字段进行分类。该部分是在读取 Json 文件时进行的修改)

二级数据是漏洞类型的下一级数据,可能需要根据不同软件类型选择 Payload,所以也要使用字典格式。二级数据如果不分软件类型,则定义键名为 universal(还要单独输入一个字段,而大多数情况都不知道软件类型,还是要枚举测试所有Payload,所以该字段不是很有必要)

二级数据是Payload,根据不同Payload需要选择不同的响应判断,如时间延迟注入的响应时间、响应内容中的关键字,所以使用字典格式。(Payload直接作为污染参数数据的键名即可)(实际读取 Json 文件时做出的优化)

一级数据是一个键 data,其键值是数据类型,用于存储 payload 的字典信息。

二级数据是最底层的数据,注入参数可能有很多、响应时间是整数、关键词是字符串等,所以根据实际需要分别使用 List、Int、String等数据类型。

未考虑的场景问题

  • 根据比较不同Payload下返回的响应信息来判断漏洞是否存在。

排版如下。


	"data":[
		"description": "SQLI-001: mysql-数字型延迟注入",
		"payload": "/**/and/**/sleep(5)",
		"time": 5,
		"keyword": ""
	,
	
		"description": "SQLI-002: MySQL-字符型延迟注入",
		"payload": "'/**/and/**/sleep(5)--+",
		"time": 5,
		"keyword": ""
	,
	
		"description": "SQLI-003: MySQL-字符型延迟注入",
		"payload": "\\"/**/and/**/sleep(5)--+",
		"time": 5,
		"keyword": ""
	,
	
		"description": "SQLI-004: MySQL-报错注入",
		"payload": "'\\"+,",
		"keyword": "You have an error in your SQL syntax"
	,
	
	
	
		"description": "XSS-001: 跨站脚本攻击漏洞"
		"payload": "<script>alert(/xss/)</script>",
		"keyword": "xxx"
	
	]
	

读取嵌套的 Json 数据

读取值为基本数据类型的Json文件

这里的单层是指,Json数据的值是基本数据类型,不是列表、字典等数据结构。

创建 test.json 文件,文件内容如下。


	"name": "pumpkin",
	"date": "2022-04-05"

查找网上文章 Go 对象序列化 等,编写读取Json文件代码。

  • 读取配置文件的字节数据:bytesJSON, err := ioutil.ReadFile(“example.json”)

  • go 内置对 json 数据的处理包是 encoding/json

  • 把字节数据解析成Json编码数据:json.Unmarshal

  • 接收Json数据:需要事先定义一个结构体

成功运行解析的代码和打印结果如下。

/* 打印结果
	pumpkin
	2022-04-05
*/

//定义配置文件解析后的结构
type Test struct 
	Name	string 	`json:"name"`
	Date	string `json:"date"`


func main() 

	var test Test

	bytes, err := ioutil.ReadFile("./test.json")
	if err != nil 
		fmt.Println("读取json文件失败", err)
		return
	

	err = json.Unmarshal(bytes, &test)
	if err != nil 
		fmt.Println("解析数据失败", err)
		return
	
	fmt.Println(test.Name)
	fmt.Println(test.Date)

读取值为数组的Json数据

test.json 配置文件的内容如下。

此时使用上一小节读取基本数据类型的代码,json.Unmarshal(bytes, &test) 会报错并退出程序,无法把数组结构解析成 Go 结构体的 string 类型:
解析数据失败 json: cannot unmarshal array into Go struct field Test.name of type string


	"name": ["pumpkin", "watermelon"],
	"date": "2022-04-05"

修改结构体的参数类型为字符串数组:[]string。运行成功且打印结果如下。

/*	打印结果
	[pumpkin watermelon]
	2022-04-05
*/
//定义配置文件解析后的结构
type Test struct 
	Name	[]string 	`json:"name"`
	Date	string 		`json:"date"`

读取值为字典的Json文件

参考文章 golang 数据三 (字典),golang基本数据结构Map也叫字典,字典的声明格式是:map[KeyType]ValueType

此时 test.json 配置文件的内容如下。


	"name": ["pumpkin", "watermelon"],
	"date": "2022-04-05"
	"sex":
		"man":1,
		"woman":0
	

定义接收 Json 数据的结构体如下,成功读取并打印 Json 数据内容。

//定义配置文件解析后的结构
type Test struct 
	Name	[]string 		`json:"name"`
	Date	string 			`json:"date"`
	Sex 	map[string]int	`json:"sex"`


// main()函数中的操作代码
func main() 
	var test Test

	bytes, err := ioutil.ReadFile("./test.json")
	if err != nil 
		fmt.Println("读取json文件失败", err)
		return
	

	err = json.Unmarshal(bytes, &test)
	if err != nil 
		fmt.Println("解析数据失败", err)
		return
	
		fmt.Println(test.Name)
		fmt.Println(test.Date)
		fmt.Println("man: ", test.Sex["man"])
		fmt.Println("woman: ", test.Sex["woman"])

读取包含两个层级键名的Json文件

此时 test.json 配置文件的内容如下。


	"req_list": [
		"url": "http://127.0.0.1/sqli-labs-master/Less-1/?id=1",
		"method": "GET",
		"headers": 
			"Spider-Name": "crawlergo",
			"User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/79.0.3945.0 Safari/537.36"
		,
		"data": "",
		"source": "Target"
	],

	"all_req_list": [
		"url": "http://127.0.0.1/sqli-labs-master/Less-1/?id=1",
		"method": "GET",
		"headers": 
			"Spider-Name": "crawlergo",
			"User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.0 Safari/537.36"
		,
		"data": "",
		"source": "Target"
	],

	"all_domain_list": ["127.0.0.1"],
	"sub_domain_list": ["127.0.0.1"]

尝试定义 req_list 的值为数组 array,json.Unmarshal() 函数报错:解析数据失败 json: cannot unmarshal object into Go struct field Crawler.req_list of type string。

type Crawler struct 
	ReqList         []string `json:"req_list"`
	AllReqList      []string `json:"all_req_list"`
	AllDomainList 	[]string `json:"all_domain_list"`
	SubDomainList 	[]string `json:"sub_domain_list"`

数组的元素值类型应该是字典 map,尝试定义如下结构体,仍然是相同的报错信息。

type Crawler struct 
	ReqList         []map[string]string `json:"req_list"`
	AllReqList      []map[string]string `json:"all_req_list"`
	AllDomainList 	[]map[string]string `json:"all_domain_list"`
	SubDomainList 	[]map[string]string `json:"sub_domain_list"`

由于 Json 文件包含不同层级的键名,所以定义结构体的结构也肯定不同,参考文章:Go 解析嵌套 json

如果 Json 数据有多层键,那么每层键都需要定义一个结构体接收对应的键名,并且定义变量时需要嵌套结构体类型。

查看参考文章编写代码,成功读取嵌套 Json 文件的代码和打印结果如下。

/*	打印结果
	http://127.0.0.1/sqli-labs-master/Less-1/?id=1
	GET

	Spider-Name crawlergo
	User-Agent Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.0 Safari/537.36
*/
// 接收第一层 Json 数据
type CrawlerFirst struct 
	ReqList			[]CrawlerSecond			`json:"req_list"`
	AllReqList      []CrawlerSecond 		`json:"all_req_list"`
	AllDomainList 	[]string 				`json:"all_domain_list"`
	SubDomainList 	[]string 				`json:"sub_domain_list"`



type CrawlerSecond struct 
	Url			string						`json:"url"`
	Method      string 						`json:"method"`
	Headers 	map[string]string 			`json:"headers"`
	Data 		string 						`json:"data"`
	Source 		string						`json:"source"`



// Test 定义配置文件解析后的结构
type Test struct 
	Name	[]string 		`json:"name"`
	Date	string 			`json:"date"`
	Sex 	map[string]int	`json:"sex"`


func main() 

	//var req model.Request

	var crawlerFirst CrawlerFirst

	bytes, err := ioutil.ReadFile("./debug.json")
	if err != nil 
		fmt.Println("读取json文件失败", err)
		return
	

	err = json.Unmarshal(bytes, &crawlerFirst)
	if err != nil 
		fmt.Println("解析数据失败", err)
		return
	

	for _,req:= range crawlerFirst.ReqList


		fmt.Println(req.Url)
		fmt.Println(req.Method)
		fmt.Println(req.Data)

		for key,value:= range req.Headers 

			fmt.Println(key, value)

		
	


准备数据阶段

修改爬虫保存结果(结合报错和实际情况未修改代码,可忽略)

读取爬虫结果的前提是,爬虫结果是我们需要的数据。原项目中把如下 4 种数据保存到一个 Json 文件,我们首先需要分离这些数据,使每种数据分别保存到各自的文件。

type Result struct 
	ReqList       []Request `json:"req_list"`
	AllReqList    []Request `json:"all_req_list"`
	AllDomainList []string  `json:"all_domain_list"`
	SubDomainList []string  `json:"sub_domain_list"`

crawlergo_cmd.go 文件保存结果的相关代码,调试打印 result 变量值发现,此时爬虫结果按照 Result 结构体都已经填充内容。先酱紫,后续对爬虫结果结构体有想法,再另外进行修改。

考虑到报错、以及直接可以读取 Json 文件,不修改代码。

	// 代码 350 行
	// 输出结果
	outputResult(result)

// 代码 403 行
func outputResult(result *pkg.Result) 
	// 输出结果
	if outputMode == "json" 
		fmt.Println("--[Mission Complete]--")
		resBytes := getJsonSerialize(result)
		fmt.Println(string(resBytes))
	 else if outputMode == "console" 
		for _, req := range result.ReqList 
			req.FormatPrint()
		
	

	// 写入文件的主要代码
	if len(outputJsonPath) != 0 
		resBytes := getJsonSerialize(result)
		tools.WriteFile(outputJsonPath, resBytes)
	

	// 修改该部分主要代码为如下内容(不更改代码,直接读取 json 文件)
	/*
		注意,
		1.结构体中的变量名需要开启调试查看、或从其他代码中找到
		2.序列化结构体的变量时,报错如下。
		在结构体定义代码中,前两个变量的类型是 []Request,域名变量是 []string
		
		考虑到可以直接读取Json文件,不更改代码。
		cannot use result.ReqList (type []*model.Request) as type *pkg.Result in argument to getJsonSerialize
		cannot use result.AllDomainList (type []string) as type *pkg.Result in argument to getJsonSerialize
	*/
	if len(outputJsonPath) != 0 
		resBytes1 := getJsonSerialize(result.req_list)
		resBytes2 := getJsonSerialize(result.all_req_list)
		resBytes3 := getJsonSerialize(result.all_domain_list)
		resBytes4 := getJsonSerialize(result.sub_domain_list)
		tools.WriteFile("req_" + outputJsonPath, resBytes1)
		tools.WriteFile("all_req_" + outputJsonPath, resBytes2)
		tools.WriteFile("all_domain_" + outputJsonPath, resBytes3)
		tools.WriteFile("sub_domain_" + outputJsonPath, resBytes4)
	
	

从 Json 文件读取需要的爬虫数据

关于嵌套 Json 文件数据的读取,在本文的上一章节《读取嵌套的 Json 数据》已完成了代码的编写和调试。

读取数据的任务完成了,Fuzz 需要用到哪些数据呢?

url
method
headers	// 为了避免被反爬虫限制访问,必须使用合适的请求头
data

读取爬虫Json文件

// 接收第一层 Json 数据
type CrawlerFirst struct 
	ReqList			[]CrawlerSecond			`json:"req_list"`
	AllReqList      []CrawlerSecond 		`json:"all_req_list"`
	AllDomainList 	[]string 				`json:"all_domain_list"`
	SubDomainList 	[]string 				`json:"sub_domain_list"`



type CrawlerSecond struct 
	Url			string						`json:"url"`
	Method      string 						`json:"method"`
	Headers 	map[string]string 			`json:"headers"`
	Data 		string 						`json:"data"`
	Source 		string						`json:"source"`


// 封装函数
func read_crawler() CrawlerFirst
	var crawlerFirst CrawlerFirst

	bytes, err := ioutil.ReadFile("./debug.json")
	if err != nil 
		fmt.Println("读取json文件失败", err)
		os.Exit(1)
	

	err = json.Unmarshal(bytes, &crawlerFirst)
	if err != nil 
		fmt.Println("解析数据失败", err)
		os.Exit(1)
	

	return crawlerFirst


读取 paramsFuzz.json 文件

读取代码改了又改,总是报错。无奈从基本数据类型开始编写 Json 文件进行读取,然后逐渐嵌套数据并完成读取 Json 数据,最终代码和打印结果如下。

读取的 Json 文件见本文第一章 字典文件的数据结构

/* 打印 sqli 键值的结果
//	/**/and/**/sleep(5)
//	MySQL-数字型延迟注入
//	5
	
//	'/**/and/**/sleep(5)--+
//	MySQL-字符型延迟注入
//	5
	
//	"/**/and/**/sleep(5)--+
//	MySQL-字符型延迟注入
//	5
	
//	'"+,
//	MySQL-报错注入
//	0
//	You have an error in your SQL syntax
*/

// 定义配置文件解析后的结构
type ParamsFuzzJson struct 
	SqlInjection	[]ParamData		`json:"sqli"`
	Xss				[]ParamData		`json:"xss"`


type ParamData struct 
	Payload 	string		`json:"payload"`
	Description string 		`json:"description"`
	Time 		int			`json:"time"`
	Keyword		string		`json:"keyword"`


func main() 

	//var req model.Request

	var paramsFuzzJson ParamsFuzzJson

	bytes, err := ioutil.ReadFile("./fuzzDicts/paramsFuzz.json")

	if err != nil 
		fmt.Println("读取json文件失败", err)
		// os.Exit(1)
		return
	

	err = json.Unmarshal(bytes, &paramsFuzzJson)
	if err != nil 
		fmt.Println("解析数据失败", err)
		return
		//os.Exit(1)
	
	
	// fmt.Println(paramsFuzzJson.SqlInjection)

	// 读取 Json 的 sqli 键
	for _, param:= range paramsFuzzJson.SqlInjection
		// for _,param:= range param.key
		fmt.Println(param.Payload)
		fmt.Println(param.Description)
		fmt.Println(param.Time)
		fmt.Println(param.Keyword)

	
	



装配数据阶段

配置请求对象 req

项目文件 crawlergo/pkg/model 定义的请求对象结构体包含 8 个变量,考虑只保留如下 5 个变量,重新在 paramsFuzz.go 文件定义请求对象结构体。

type Request struct 
	URL             *URL
	Method          string
	Headers         map[string]interface
	PostData        string
	Proxy           string

明确参数 Fuzz 的需求

  • 遍历 req_list:爬虫结果中 req_list 键的内容,如果存在Get参数或Post参数则进行 Fuzz
  • 遍历 paramJson 中的每一个键:sqli、xss等

保存传递动态参数的 Url 信息

对于爬虫结果,要筛选出传递动态参数的URl进行参数Fuzz测试。

顺便把传递动态参数的Url保存到新的Json文件,方便人工查看,如下代码把传递动态参数的爬虫结果保存到指定文件 params_debug.json。

// 接收第一层 Json 数据
type CrawlerJson struct 
	ReqList			[]CrawlerData			`json:"req_list"`
	AllReqList      []CrawlerData 		`json:"all_req_list"`
	AllDomainList 	[]string 				`json:"all_domain_list"`
	SubDomainList 	[]string 				`json:"sub_domain_list"`


type CrawlerData struct 
	Url			string						`json:"url"`
	Method      string 						`json:"method"`
	Headers 	map[string]string 			`json:"headers"`
	Data 		string 						`json:"data"`
	Source 		string						`json:"source"`


// 调用代码
for _,crawler:= range crawlerReq 
	outputParamsResult(crawler)


func outputParamsResult(result CrawlerData) 

	// 写入的文件名变量,在合并代码时需要调整修改
	outputJsonPath := "debug.json"

	// 输出结果
	if len(outputJsonPath) != 0 
		resBytes := getParamsJsonSerialize(result)
		tools.WriteFile("params_" + outputJsonPath, resBytes)
	



func getParamsJsonSerialize(paramsResult CrawlerData) []byte 

	resBytes, err := json.Marshal(paramsResult)
	if err != nil 
		log.Fatal("Marshal result error")
	
	return resBytes

装配数据

算法步骤:

  • 准备数据1:读取爬虫结果,调用爬虫结构体的参数信息
  • 准备数据2:读取参数 Fuzz 字典,调用结构体
  • 筛选:遍历爬虫结构体,通过条件判断找出传递动态参数的Url,根据传参方式分为 Get 和 Post
  • 准备数据3:逐个添加 Payload 到动态参数末尾,如果是 Get 方式则拼接 Url 和参数
  • 装配:把爬虫结构体的信息、以及处理后的动态参数信息,装配到请求对象 req
  • 运行和验证:发送请求,查看响应信息验证漏洞是否存在(运行阶段)
  • 标记去重:如果动态参数测试过了,则加入 Array ,并且在测试动态参数前检查是否在 Array 中(验证阶段)
第一步

读取爬虫结果

// 接收第一层 Json 数据
type CrawlerJson struct 
	ReqList			[]CrawlerData			`json:"req_list"`
	AllReqList      []CrawlerData 		`json:"all_req_list"`
	AllDomainList 	[]string 				`json:"all_domain_list"`
	SubDomainList 	[]string 				`json:"sub_domain_list"`


type CrawlerData struct 
	Url			string						`json:"url"`
	Method      string 						`json:"method"`
	Headers 	map[string]string 			`json:"headers"`
	Data 		string 						`json:"data"`
	Source 		string						`json:"source"`


func main() 
	// 1.读取爬虫结果
	crawlerReq := read_crawlerReq()



func read_crawlerReq() [毕设扫描器参数Fuzz第二篇:动态爬虫的创建启动和协程池

毕设扫描器动态爬虫CrawlerGo源码分析1:cli库的使用

毕设扫描器动态爬虫CrawlerGo源码分析1:主文件cli库的使用

毕设扫描器动态爬虫CrawlerGo直观使用效果分析

毕设扫描器动态爬虫CrawlerGo直观使用效果分析

Spring框架第一篇之Bean的装配