JsFu0k批量探测JS存在的敏感关键字

news2024/9/24 21:17:27

这是一个演示

GitHub地址:https://github.com/jumppppp/go/tree/master/htools/jsfu0k


输出窗口
在这里插入图片描述

输出的详细文件

在这里插入图片描述

以上演示的是全字匹配

这个自动化工具模仿人工在一个网页内进行寻找js中敏感信息

流程:

填写配置(输入批量域名) -》
选择模式 -》
爬取网站内连接 -》
判断后缀 -》
本域名下不同网页继续爬取(爬取深度自定义) -》
整体js链接 -》
保存到本地 -》
根据关键字进行搜索 -》
整理到输出和文档内

main.go

package main

import (
	"bufio"
	"fmt"
	"io"
	"jsfu0k/model"
	"net/url"
	"os"
	"strings"
	"time"
)

func main() {
	fmt.Printf("[1]模糊匹配\n[2]全字匹配\nSelect:")
	var keyy int
	_,err :=fmt.Scanf("%d\n",&keyy)
	if err != nil {
		fmt.Println("No=", err)
	}
	if keyy!=1||keyy!=2{
		keyy = 2
	}
	fmt.Println("You Select ",keyy)
	// 读取URL文件
	urls, err := readURLsFromFile("./config/urls.txt")
	if err != nil {
		fmt.Println("读取URL文件失败:", err)
	}
	
	// 获取当前日期作为数据库名称
	currentDate := time.Now().Format("2006-01-02")
	err = os.Mkdir("./out/"+currentDate, 0755)
	if err != nil {
		// fmt.Println("No=", err)
	}

	Ua:=&model.ReqTool_t{}
	Ua.UA,err = readUAsFromFile("./config/UA.txt")
	if err != nil {
		fmt.Println("读取UA文件失败:", err)
	}
	Keys,err:= readKeysFromFile("./config/Key.txt")
	if err != nil {
		
		fmt.Println("读取Key文件失败:", err)
	}

	// 创建表格
	for _, u := range urls {
		domain,Cdomain := DomainGet(u)
		DirPath:="./out/"+currentDate+"/"+domain
		err = os.Mkdir(DirPath, 0755)
		if err != nil {
			// fmt.Println("No=", err)
		}
		Ua.DirPath = DirPath
		Ua.MaxR = 2
		Ua.Domain = domain
		Ua.Cdomain = Cdomain
		Ua.AllUrls = make(map[string]bool)
		Ua.JsUrls = make(map[string]string)
		Ua.GoUrls = make(map[string]bool)
		Ua.KeyOut = make(map[string]map[string][]string)
		Ua.KeyOut[domain]= make(map[string][]string)
		for _,key:=range Keys{
			Ua.KeyOut[domain][key]= []string{}
		}
		Ua.CrawlURL(u,0)
		Ua.Wg.Wait()
		Ua.JS_Init()
		Ua.GetJsKey(keyy)
		Ua.ShowInfo()
	}
	fmt.Println("数据库和表格创建成功",urls)
}

// 从文件中读取URL列表
func readURLsFromFile(filename string) ([]string, error) {
	file, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	var urls []string
	reader := bufio.NewReader(file)
	for {
		line, err := reader.ReadString('\n')
		if err != nil && err != io.EOF {
			return nil, err
		}
		line = strings.TrimSpace(line)
		if line != "" {
			urls = append(urls, line)
		}
		if err == io.EOF {
			break
		}
	}

	return urls, nil
}
// 从文件中读取UA列表
func readUAsFromFile(filename string) ([]string, error) {
	file, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	var UAs []string
	reader := bufio.NewReader(file)
	for {
		line, err := reader.ReadString('\n')
		if err != nil && err != io.EOF {
			return nil, err
		}
		line = strings.TrimSpace(line)
		if line != "" {
			UAs = append(UAs, line)
		}
		if err == io.EOF {
			break
		}
	}

	return UAs, nil
}
// 从文件中读取Key列表
func readKeysFromFile(filename string) ([]string, error) {
	file, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	var Keys []string
	reader := bufio.NewReader(file)
	for {
		line, err := reader.ReadString('\n')
		if err != nil && err != io.EOF {
			return nil, err
		}
		line = strings.TrimSpace(line)
		if line != "" {
			Keys = append(Keys, line)
		}
		if err == io.EOF {
			break
		}
	}

	return Keys, nil
}
func DomainGet(u string)(domain string,Cdomain string){
	// 解析域名
	parsedURL, err := url.Parse(u)
	if err != nil {
		fmt.Println("解析域名失败:", err)
		return
	}

	// 获取主机名
	hostname := parsedURL.Hostname()

	// 分割主机名
	parts := strings.Split(hostname, ".")

	// 分解子域名和顶级域名
	Cdomain = strings.Join(parts[len(parts)-2:], ".")
	domain = strings.Join(parts[:len(parts)-2], ".")+"."+Cdomain


	// 输出结果
	fmt.Println("域名:", domain)
	fmt.Println("子域名:", Cdomain)
	return 
}

req.go

package model

import (
	"crypto/md5"
	"fmt"
	"io"
	"io/ioutil"
	"math/rand"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"sync"
	"time"
)
type ReqTool_t struct{
	UA []string
	Domain string
	Cdomain string
	DirPath string
	JsUrls map[string]string //url >> name
	AllUrls map[string]bool
	GoUrls map[string]bool
	MaxR int
	KeyOut map[string]map[string][]string // domain >> key >>{path1,path2}
	mutex   sync.Mutex
	Wg      sync.WaitGroup
}
// 提取链接的正则表达式
var linkRegex = regexp.MustCompile(`(?i)(?:href|src)=["']([^"']+)["']`)

func (this * ReqTool_t)CrawlURL(url string,MaxR int) {

	if MaxR > this.MaxR {
		return
	}
	// 加锁
	this.mutex.Lock()
	defer this.mutex.Unlock()
	
	// 检查是否已经访问过该链接
	if this.GoUrls[url] {
		return
	}

	// 标记该链接已访问
	this.GoUrls[url] = true

	// 创建一个 HTTP 客户端
	client := &http.Client{}
	// 创建一个 HTTP 请求
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		fmt.Println("创建请求失败:", err)
		return
	}
	// 设置随机数种子
	rand.Seed(time.Now().UnixNano())
	rUA := rand.Intn(len(this.UA))
	// 设置 User-Agent 头
	req.Header.Set("User-Agent", this.UA[rUA])
	rSleep := rand.Intn(5)+1
	delay := time.Duration(rSleep) * time.Second
	// 发送请求前进行延迟
	time.Sleep(delay)
	// 发送 HTTP 请求
	resp, err := client.Do(req)
	if err != nil {
		fmt.Println("发送请求失败:", err)
		return
	}
	defer resp.Body.Close()

	// 读取响应内容
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("读取响应内容失败:", err)
		return
	}
	// 获取响应状态码
	statusCode := resp.StatusCode


	fmt.Printf("<%d>%s\t[%d]\n", statusCode,url,MaxR)
	if statusCode == 200{
			MaxR +=1
			bodyString := string(body)
			// 使用正则表达式提取链接
			linksMap:= extractUniqueLinks(bodyString, resp.Request.URL)
			// 启动子协程前增加等待计数

			for key, value := range linksMap {
				this.AllUrls[key] = value
			}
			// 输出链接
			for key,_ := range linksMap {
				if key!=url{
					isGoflag := this.isGo(key)
					if isGoflag{
						this.Wg.Add(1)
						go func(url string) {
							// 在子协程执行完毕后减少等待计数
							defer this.Wg.Done()
		
							// 递归调用CrawlURL
							this.CrawlURL(url, MaxR+1)
						}(key)
					} else if strings.Contains(key, ".js") {
						this.JsUrls[key] = ""

					}
				}
			}
	}
}
func (this * ReqTool_t)JS_Init(){
	// 创建一个 HTTP 客户端
	client := &http.Client{}
	// 创建一个 HTTP 请求
	for key,value:=range this.JsUrls{
		value = MD5(key)
		this.JsUrls[key]=value
		req, err := http.NewRequest("GET", key, nil)
		if err != nil {
			fmt.Println("创建请求失败:", err)
			return
		}
		rSleep := rand.Intn(5)+1
		delay := time.Duration(rSleep) * time.Second
		// 发送请求前进行延迟
		time.Sleep(delay)
		// 发送 HTTP 请求
		resp, err := client.Do(req)
		if err != nil {
			fmt.Println("发送请求失败:", err)
			return
		}

	
		// 读取响应内容
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			fmt.Println("读取响应内容失败:", err)
			return
		}
		resp.Body.Close()
		name:=this.DirPath+"/"+value+".js"
		var NewBody string 
		NewBody = fmt.Sprintf("\n\t\t[%s]\t\t\n\t\t<%s>\t\t\n\n",key,name)+string(body)

		err = ioutil.WriteFile(name, []byte(NewBody), 0644)
		if err != nil {
			fmt.Println("写入文件失败:", err)
			return
		}
		fmt.Printf("%s\t>>>\t%s\n",key,name)
	}
	
}
func MD5(str string) string {
	h := md5.New()
	io.WriteString(h, str)
	return fmt.Sprintf("%x", h.Sum(nil))
}
func (this * ReqTool_t)ShowInfo(){
	for domain,keys := range this.KeyOut{
		fmt.Printf("[+]%s\n",domain)
		for key,values := range keys{
			fmt.Printf("\t<%s>\t[%d]\n",key,len(values))
			for _,v:=range values{
				path:=this.findJSurl(v)
				fmt.Printf("\t\t%s\t<%s>\n",v,path)
			}
		}
	}
}
func (this * ReqTool_t)findJSurl(name string)(string){
	for url,value:= range this.JsUrls{
		if value+".js" == name{
			return url
		}
	}
	return ""
}
func (this * ReqTool_t)GetJsKey(Mod int){
	filey, err := os.OpenFile("./out/res.txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		fmt.Println("打开文件失败:", err)
		return
	}
	defer filey.Close()
	_, err = filey.WriteString(fmt.Sprintf("\n\t\t====%s====\t\t\n\n",this.Domain))
	if err != nil {
		fmt.Println("写入文件失败:", err)
		return
	}
	for key,_ := range this.KeyOut[this.Domain]{
		files, err := ioutil.ReadDir(this.DirPath)
		if err != nil {
			fmt.Println("No=",err)
		}
	
		// 遍历并打印文件名
		for _, file := range files {
			if !file.IsDir() {
				content, err := ioutil.ReadFile(filepath.Join(this.DirPath, file.Name()))
				if err != nil {
					fmt.Printf("Failed to read file: %s\n", file.Name())
					continue
				}
				// fmt.Printf("File: %s\n", file.Name())
				// fmt.Printf("Content: %s\n", content)
				var OutList []string
				switch Mod {
				case 1:
					OutList = SelectKey(key,string(content))
				case 2:
					OutList = FullSelectKey(key,string(content))
				default:
				}
				if len(OutList) != 0{
					this.KeyOut[this.Domain][key] = append(this.KeyOut[this.Domain][key],file.Name())
					for _,info:=range OutList{
						text1 := fmt.Sprintf("<%s>\t~%s~\t[%s]\n",key,info,this.DirPath+"/"+file.Name())
						_, err = filey.WriteString(text1)
						if err != nil {
							fmt.Println("写入文件失败:", err)
							return
						}
					}
				}
				
			}
		}
		
	}
	
}
func SelectKey(key string,content string)(outList []string){
	lowerStr := strings.ToLower(content)
	search := strings.ToLower(key)
	start := 0
	for {
		pos := strings.Index(lowerStr[start:], search)
		if pos == -1 {
			break
		}

		pos += start
		subStart := max(0, pos-20)
		subEnd := min(len(content), pos+20+len(search))
		start = pos + len(search)
		outList = append(outList,content[subStart:subEnd])
	}
	return 
}
func FullSelectKey(key string,content string)(outList []string){
	// 创建一个正则表达式来进行全词匹配
	re := regexp.MustCompile(`\b` + regexp.QuoteMeta(key) + `\b`)
	
	// 将句子和搜索词都转换为小写进行不区分大小写的搜索
	lowerStr := strings.ToLower(content)
	
	// 找到所有的匹配项
	matches := re.FindAllStringIndex(lowerStr, -1)
	
	// 遍历每一个匹配项并输出它们
	for _, match := range matches {
		subStart := max(0, match[0]-20)
		subEnd := min(len(content), match[1]+20)
		outList = append(outList,content[subStart:subEnd])
	}
	return
}
func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}
// 提取并去重链接函数
func extractUniqueLinks(text string, baseURL *url.URL) map[string]bool {
	matches := linkRegex.FindAllStringSubmatch(text, -1)
	linksMap := make(map[string]bool)
	for _, match := range matches {
		absURL, err := joinURL(baseURL, match[1])
		if err != nil {
			// fmt.Println("拼接URL失败:", err,baseURL,match[1])
			continue
		}
		if strings.HasPrefix(absURL, "http://") || strings.HasPrefix(absURL, "https://"){
			linksMap[absURL] = true
		}

	}

	return linksMap
}

// 拼接URL函数
func joinURL(baseURL *url.URL, link string) (string, error) {
	linkURL, err := url.PathUnescape(link)
	if err != nil {
		return "", err
	}

	parsedLinkURL, err := url.Parse(linkURL)
	if err != nil {
		return "", err
	}

	absURL := baseURL.ResolveReference(parsedLinkURL).String()
	return absURL, nil
}

// 检查链接是否符合子域名规则
func (this * ReqTool_t)isGo(url string) bool {
	a1 := strings.Contains(url, this.Domain)
	a0 := []string {".gif",".png",".jpg",".js",".ico",".css",".jepg",".swf"}
	a2 := true
	for _,Ni:=range a0{
		if strings.Contains(url,Ni){
			a2 = false
		}
	}
	if a2 && a1{
		return true
	}else{
		return false
	}
}

本项目还在开发过程中,正在探测可能存在的bug,如有问题可以联系我

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/696602.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【每天40分钟,我们一起用50天刷完 (剑指Offer)】第九天 9/50

专注 效率 记忆 预习 笔记 复习 做题 欢迎观看我的博客&#xff0c;如有问题交流&#xff0c;欢迎评论区留言&#xff0c;一定尽快回复&#xff01;&#xff08;大家可以去看我的专栏&#xff0c;是所有文章的目录&#xff09;   文章字体风格&#xff1a; 红色文字表示&#…

Eclipse中的实用工具之Debug

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于Debug的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 一.什么是Debug 二.为什么要使用Debug 三…

springboot+element-ui多文件一次上传

前端&#xff1a; <el-uploaddrag:multiple"true":limit"10":auto-upload"false":file-list"fileList"ref"fileUpload"><i class"el-icon-upload"></i><div class"el-upload__text&quo…

【云原生】Pause 容器介绍

Pause 容器 Pause 容器&#xff0c;又叫 Infra 容器 我们知道在 kubelet 的配置中有这样一个参数&#xff1a; KUBELET_POD_INFRA_CONTAINER--pod-infra-container-imageregistry.access.redhat.com/rhel7/pod-infrastructure:latest上面是 openshift 中的配置参数&#xff…

关于Java类加问题我竟让面试官哑口无言

学习类加载之前我们先看看从面试官的角度会问哪些问题&#xff1f;毕竟带着问题学习会比较高效。 直击面试 看你简历写得熟悉 JVM&#xff0c;那你说说类的加载过程吧&#xff1f; 我们可以自定义一个 String 类来使用吗&#xff1f; 什么是类加载器&#xff0c;类加载器有哪些…

雨水情自动监测报警系统解决方案

随着夏季雨季的到来&#xff0c;对全国各地的防汛工作形成挑战&#xff0c;为了实现有效的雨水管理和应对极端天气情况&#xff0c;建立一套科学高效的雨水情监测系统有着重要作用。雨水情监测系统能够提供及时准确的雨水信息&#xff0c;帮助决策者进行全面的天气分析和预警&a…

数字化转型排头兵,金融行业如何利用科技赋能业务 | TVP金融交流会

引言 金融行业&#xff0c;是数字化转型浪潮中的排头兵。这个上千年来&#xff0c;不断创新的行业&#xff0c;从以物易物到纸币发行再到数字资产&#xff0c;承袭至今的是保障客户资产安全&#xff0c;提升资产流通效率的本心。进入产业互联网时代以后&#xff0c;金融科技的发…

第5讲:使用ajax技术实现局部刷新功能(xml数据)

使用ajax技术实现局部刷新功能&#xff0c;每2秒刷新一次数据&#xff0c;本案例使用原生态xmlhttprequest对象&#xff0c;GET方法通讯&#xff0c;使用responseXML属性返回xml格式数据&#xff0c;同时刷新界面数据。 ajax封装库(ajax.js) var xmlhttpnull; //创建XMLHttpRe…

adb-学会查看日志文件

目录 一、获取日志文件 二、日志级别 三、日志缓冲区 四、缓冲区的类型 &#x1f381;更多干货 完整版文档下载方式&#xff1a; 一、获取日志文件 一般情况下&#xff0c;我们在做app测试时&#xff0c;其实并不需要经常使用adb去抓取我们的日志&#xff0c;通常情况下…

使用GPIO来模拟UART

前言 最近在看一些秋招的笔试和面试题&#xff0c;刚好看到一个老哥的经验贴&#xff0c;他面试的时候被问到了如果芯片串口资源不够了该怎么办&#xff1f;其实可以用IO口来模拟串口&#xff0c;但我之前也没有具体用代码实现过&#xff0c;借此机会用32开发板上的两个IO口来…

力扣 404. 左叶子之和

题目来源&#xff1a;https://leetcode.cn/problems/sum-of-left-leaves/description/ C题解1&#xff1a;递归法&#xff0c;前序遍历。 1. 确定输入参数&#xff1a;当前节点&#xff0c;左叶子的和&#xff1b; 2. 确定终止条件&#xff1a;空节点时返回&#xff1b; 3. …

【每日一短语】在必要情况下

1、短语及释义 in a pinch 释义&#xff1a; 在紧要关头&#xff1b;在必要情况下 2、示例及出处 美剧&#xff1a;《生活大爆炸》第七季第21集 The Big Bang Theory, Season 7 Episode 21 Sheldon Cooper: Penny, there’s only one cookie with something in the middle tha…

基于STM32设计的城市绿化云端监控系统(华为云IOT)

一、设计需求 1.1 项目背景 随着科技的蓬勃发展改变了很多传统行业的作业方式,当我们用移动支付代替现金交易时,当我们足不出户就能满足饥饿的身体时,我们的生活方式因为科技而发生了改变;同样科技也在改变着我们周围的点点滴滴,城市绿化养护亦是如此。 通过智慧控制系统…

在Docker中使用MindSpore GPU版本

文章目录 在Docker中使用MindSpore GPU版本获取安装命令安装安装nvidia-container-toolkit获取MindSpore镜像测试运行MindSpore镜像运行代码 使用VSCode开发 在Docker中使用MindSpore GPU版本 参考官方文档&#xff1a;安装指南 获取安装命令 如图所示 命令为 docker pull…

MFC将二维数组写入文件中并进行读取

MFC将二维数组写入文件中并进行读取 当前项目需要将二维数组写入到本地文件中&#xff0c;并在另一个对话框中进行读取。网上查了很多资料&#xff0c;基本都是写字符串到文件中的&#xff0c;想依葫芦画瓢仿照字符串的写法来写二维数组&#xff0c;发现在写文件状态下&#x…

护网是什么?为什么【网安人】都想参加!

一、什么是护网行动&#xff1f; 护网行动是以公安部牵头的&#xff0c;用以评估企事业单位的网络安全的活动。 具体实践中。公安部会组织攻防两方&#xff0c;进攻方会在一个月内对防守方发动网络攻击&#xff0c;检测出防守方&#xff08;企事业单位&#xff09;存在的安全漏…

Flink之FileSink将数据写入parquet文件

Flink之FileSink将数据写入parquet文件 在使用FileSink将数据写入列式存储文件中时必须使用forBulkFormat,列式存储文件如ORCFile、ParquetFile,这里就以ParquetFile为例结合代码进行说明. 在Flink1.15.3中是通过构造ParquetWriterFactory然后调用forBulkFormat方法将构造好的…

第9章 异常处理

第9章 异常处理 9.1 Java异常处理 try-catch-finally ​ ​ 9.2 Scala异常处理 ​ ​ package chapter09object Test01_Exception {def main(args: Array[String]): Unit {try {val n 10 / 1} catch {case e: ArithmeticException > {println("发生算数异常&quo…

【Java高级编程】Java常用类

Java常用类 1、字符串相关的类1.1、字符串相关的类&#xff1a;String1.2、字符串相关的类&#xff1a;String常用方法1.3、String与基本数据类型、包装类之间的转换1.4、String与char[]之间的转换1.5、String与byte[]之间的转换1.6、String、StringBuffer、StringBuilder三者的…

element-plus中的el-table如何动态合并行(复制粘贴即可使用 亲测有效!)

demo场景&#xff1a; 一个 table&#xff0c;由5列组成&#xff0c;其 prop 分别为’resource_name’, ‘scene_name’, ‘type’, ‘content’, ‘desc’&#xff0c;渲染 table 的数据来源于接口。现在需要将 propdesc的这一列&#xff0c;按照resource_name 相等时进行合并…