【毕设扫描器】【参数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() []CrawlerData{
	var crawlerJson CrawlerJson

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

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

	return crawlerJson.ReqList

}
第二步

读取参数 Fuzz 的 payload 文件 paramsFuzz.json

// 定义结构体接收参数 Fuzz 的 Json 数据
type ParamsFuzzJson struct {
	Data			[]ParamData		`json:"data"`
}

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

func main() {

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


	// 2.读取参数 Fuzz 字典
	/*	功能说明:读取得到一个数组,数组里的元素是 Payload 字典。可以通过遍历数组来逐个读取装配 Payload。
		调用说明:每次装配 payload 都要绑定一个 request
				以便使用 payload 字典的关键字等字段判断漏洞是否存在,以及探测漏洞存在后打印 payload 信息
				也就是说,遍历 payload 数组,是遍历的第一层
	 */
	paramsArray := read_paramsPayload()

	// 遍历 Json 数据中 data 键的键值数组,用于获取每一个 payload 字典
	for _, payloadDict := range paramsArray.Data {
		fmt.Println(payloadDict.Payload)
	}

}

func read_paramsPayload() ParamsFuzzJson {
	var paramsFuzzJson ParamsFuzzJson

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

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

	}

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

	return paramsFuzzJson
}
第三四五步

第三步筛选,遍历爬虫结构体,通过条件判断找出传递动态参数的Url,根据传参方式分为 Get 和 Post。

第四步准备数据3:逐个添加 Payload 到动态参数末尾,然后对URL或者PostData进行字串替换。

第五步装配:把爬虫结构体的信息、以及处理后的动态参数信息,装配到请求对象 req。

嵌套的比较复杂,这三部分代码可以通过 封装函数进行优化。不过目前更重要的还是发送 req 对象,尤其是以多线程的方式发送请求,需要进一步深入查看 crawlergo 的项目代码。第六步和第七步都是其他阶段的任务,可以查看下一章。

func main() {

	// 定义 req 对象
	var reqFuzz Request
	// 代理字段,需要等合并代码时设置相同的字段
	// reqFuzz.Proxy = crawler.

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

	// 2.读取参数 Fuzz 字典
	/*
		功能说明:读取得到一个数组,数组里的元素是 Payload 字典。可以通过遍历数组来逐个读取装配 Payload。
		调用说明:每次装配 payload 都要绑定一个 request
				以便使用 payload 字典的关键字等字段判断漏洞是否存在,以及探测漏洞存在后打印 payload 信息
				也就是说,遍历 payload 数组,是遍历的第一层
	 */
	paramsPayloadArray := read_paramsPayload()
	//fmt.Println(paramsPayloadArray)

	// 3.从爬虫结果中筛选传递动态参数的请求
	for _,crawler:= range crawlerReq {
		if crawler.Method == "GET" {
			if strings.Contains(crawler.Url, "?") {

				// 4.逐个装配payload
				// 获取 Url 数组
				urlArray := strings.Split(crawler.Url, "?")

				// 分离Url中的Get参数
				// 字符串中不包含&时,并不会报错,而是返回只有一个元素的数组
				paramsArray := strings.Split(urlArray[1], "&")

				// 装配payload:直接使用 payload 分别替换参数,比如用 id=1<script>alert(/xss/)</script> 替换 id=1
				for _, value := range paramsArray {

					// 4.遍历payload装配到每个Get参数,逐个添加 Payload 到动态参数末尾
					for _, payloadDict := range paramsPayloadArray.Data {
						payload := value + payloadDict.Payload
						fmt.Println("原数据:" + value)
						fmt.Println("替换后的数据:" + payload)

						// 5.设置 req 对象,使用 payload 替换元素值,然后装配所有数据
						reqFuzz.URL = strings.Replace(crawler.Url, value, payload, 1)
						reqFuzz.Method = crawler.Method
						reqFuzz.Headers = crawler.Headers
						reqFuzz.PostData = crawler.Data

						// 6.发送 req 对象,接收响应信息

						// 7.根据响应信息、以及payload中的关键字、响应时间等信息验证漏洞,如果存在则打印。over
					}
				}


				// 保存传递动态参数的URL信息到文件:params_JsonPath
				outputParamsResult(crawler)
			}
		}
			if crawler.Method == "POST" {
				// 4.逐个装配Post参数
				paramsArray := strings.Split(crawler.Data, "&")

				// 遍历每个Post参数
				for _, value := range paramsArray {

					// 4.遍历payload装配到每个Get参数,逐个添加 Payload 到动态参数末尾
					for _, payloadDict := range paramsPayloadArray.Data {
						payload := value + payloadDict.Payload
						fmt.Println("原数据:" + value)
						fmt.Println("替换后的数据:" + payload)

						// 5.设置 req 对象,使用 payload 替换元素值,然后装配所有数据
						reqFuzz.URL = strings.Replace(crawler.Data, value, payload, 1)
						reqFuzz.Method = crawler.Method
						reqFuzz.Headers = crawler.Headers
						reqFuzz.PostData = crawler.Data

						// 6.发送 req 对象,接收响应信息

						// 7.根据响应信息、以及payload中的关键字、响应时间等信息验证漏洞,如果存在则打印。over
					}
				}
				outputParamsResult(crawler)
			}
	}
}

执行阶段

另开一篇文章进行记录,可以前往博客检索查看。

接收结果并验证阶段

另开一篇文章进行记录,可以前往博客检索查看。

【本科毕业设计项目 源码+说明书+PPT】 随着当今时代新型网络技术的迅速兴起,以及第三产业的蓬勃发展,互联网早已成为社会生活当中不可或缺的一部分,而网络安全问题也越来越不容忽视,越来越多的黑客通过利用系统漏洞实施安全攻击、偷盗、诈骗等违法行为,这就需要我们利用先进的技术手段去尽早、准确地检测和解决这些安全漏洞和安全隐患。但是上述这些扫描器一般都属于C/S架构,变更不够灵活,维护与管理的难度较大。当然当前也有很多款网页版扫描器,但大多系统功能较为单一,且缺少对用户的管理和扫描结果的保存和处理,仅支持一次性在线扫描。 针对这一背景,开发了本系统。本系统的特色主要有以下几个方面。 (1)适用于Windows操作系统环境下,采用了B/S架构,用户只需按照要求注册登录即可使用,方便快捷,分布性强,便于维护和管理,可扩展性高。 (2)界面较简单、直观、易操作,对系统用户的专业水平要求不高,便于专业知识储备较少的普通用户接受。并且本系统中增设了仿命令行功能,既可以帮助用户实现对本系统功能的快速了解以及快速使用,也可以调动喜爱命令行的使用者的兴趣。 (3)系统区分了管理员用户和普通用户,管理员用户拥有较多的特权,实现了较简单的基于角色的访问控制,增强了系统安全性和可管理性。 (4)支持用户上传及管理漏洞扫描所用的第三方插件,可以提高漏洞扫描的效率和性能,提高了系统功能的可扩展性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值