mirror of
https://github.com/shadow1ng/fscan.git
synced 2025-09-14 14:06:44 +08:00
Compare commits
5 Commits
235e2aee60
...
a245934cf2
Author | SHA1 | Date | |
---|---|---|---|
![]() |
a245934cf2 | ||
![]() |
0235bf5af5 | ||
![]() |
e624c3092f | ||
![]() |
86b6faec79 | ||
![]() |
8f2226987d |
106
Common/Flag.go
106
Common/Flag.go
@ -5,7 +5,6 @@ import (
|
||||
"fmt"
|
||||
"github.com/fatih/color"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Banner() {
|
||||
@ -31,109 +30,28 @@ func Banner() {
|
||||
}
|
||||
}
|
||||
|
||||
// 清屏并隐藏光标
|
||||
fmt.Print("\033[H\033[2J\033[?25l")
|
||||
defer fmt.Print("\033[?25h")
|
||||
|
||||
// 创建边框
|
||||
topBorder := "┌" + strings.Repeat("─", maxLength+2) + "┐"
|
||||
bottomBorder := "└" + strings.Repeat("─", maxLength+2) + "┘"
|
||||
|
||||
// 呼吸灯效果循环
|
||||
for cycle := 0; cycle < 2; cycle++ { // 2个完整循环
|
||||
// 亮度由暗到亮
|
||||
for i := 0; i <= 10; i++ {
|
||||
fmt.Print("\033[H")
|
||||
dim := float64(i) / 10.0
|
||||
|
||||
printDimmed(topBorder, colors[0], dim)
|
||||
fmt.Println()
|
||||
|
||||
for lineNum, line := range lines {
|
||||
printDimmed("│ ", colors[0], dim)
|
||||
for _, char := range line {
|
||||
printDimmed(string(char), colors[lineNum%2], dim)
|
||||
}
|
||||
padding := maxLength - len(line)
|
||||
printDimmed(strings.Repeat(" ", padding)+" │", colors[0], dim)
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
printDimmed(bottomBorder, colors[0], dim)
|
||||
fmt.Println()
|
||||
|
||||
vStr := fmt.Sprintf(" Fscan Version: %s", version)
|
||||
printDimmed(vStr, colors[1], dim)
|
||||
fmt.Print("\n\n")
|
||||
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
}
|
||||
|
||||
// 亮度由亮到暗
|
||||
for i := 10; i >= 0; i-- {
|
||||
fmt.Print("\033[H")
|
||||
dim := float64(i) / 10.0
|
||||
|
||||
printDimmed(topBorder, colors[0], dim)
|
||||
fmt.Println()
|
||||
|
||||
for lineNum, line := range lines {
|
||||
printDimmed("│ ", colors[0], dim)
|
||||
for _, char := range line {
|
||||
printDimmed(string(char), colors[lineNum%2], dim)
|
||||
}
|
||||
padding := maxLength - len(line)
|
||||
printDimmed(strings.Repeat(" ", padding)+" │", colors[0], dim)
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
printDimmed(bottomBorder, colors[0], dim)
|
||||
fmt.Println()
|
||||
|
||||
vStr := fmt.Sprintf(" Fscan Version: %s", version)
|
||||
printDimmed(vStr, colors[1], dim)
|
||||
fmt.Print("\n\n")
|
||||
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
// 最后显示完整亮度的版本
|
||||
fmt.Print("\033[H")
|
||||
printDimmed(topBorder, colors[0], 1.0)
|
||||
fmt.Println()
|
||||
// 打印banner
|
||||
fmt.Println(topBorder)
|
||||
|
||||
for lineNum, line := range lines {
|
||||
printDimmed("│ ", colors[0], 1.0)
|
||||
for _, char := range line {
|
||||
printDimmed(string(char), colors[lineNum%2], 1.0)
|
||||
}
|
||||
fmt.Print("│ ")
|
||||
// 使用对应的颜色打印每个字符
|
||||
c := color.New(colors[lineNum%2])
|
||||
c.Print(line)
|
||||
// 补齐空格
|
||||
padding := maxLength - len(line)
|
||||
printDimmed(strings.Repeat(" ", padding)+" │", colors[0], 1.0)
|
||||
fmt.Println()
|
||||
fmt.Printf("%s │\n", strings.Repeat(" ", padding))
|
||||
}
|
||||
|
||||
printDimmed(bottomBorder, colors[0], 1.0)
|
||||
fmt.Println()
|
||||
fmt.Println(bottomBorder)
|
||||
|
||||
vStr := fmt.Sprintf(" Fscan Version: %s", version)
|
||||
printDimmed(vStr, colors[1], 1.0)
|
||||
fmt.Print("\n\n")
|
||||
}
|
||||
|
||||
// 辅助函数:打印带透明度的文字
|
||||
func printDimmed(text string, col color.Attribute, dim float64) {
|
||||
if dim < 0.2 {
|
||||
fmt.Print(strings.Repeat(" ", len(text)))
|
||||
return
|
||||
}
|
||||
|
||||
intensity := int(255 * dim)
|
||||
fmt.Printf("\033[38;2;%d;%d;%dm%s\033[0m",
|
||||
int(float64(0)*dim),
|
||||
intensity,
|
||||
int(float64(0)*dim),
|
||||
text)
|
||||
// 打印版本信息
|
||||
c := color.New(colors[1])
|
||||
c.Printf(" Fscan Version: %s\n\n", version)
|
||||
}
|
||||
|
||||
func Flag(Info *HostInfo) {
|
||||
|
@ -148,6 +148,29 @@ func ParsePass(Info *HostInfo) error {
|
||||
LogInfo(fmt.Sprintf("从文件加载URL: %d 个", len(urls)))
|
||||
}
|
||||
|
||||
// 从文件加载主机列表
|
||||
if HostsFile != "" {
|
||||
hosts, err := Readfile(HostsFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("读取主机文件失败: %v", err)
|
||||
}
|
||||
|
||||
tmpHosts := make(map[string]struct{})
|
||||
for _, host := range hosts {
|
||||
if host != "" {
|
||||
if _, ok := tmpHosts[host]; !ok {
|
||||
tmpHosts[host] = struct{}{}
|
||||
if Info.Host == "" {
|
||||
Info.Host = host
|
||||
} else {
|
||||
Info.Host += "," + host
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
LogInfo(fmt.Sprintf("从文件加载主机: %d 个", len(hosts)))
|
||||
}
|
||||
|
||||
// 从文件加载端口列表
|
||||
if PortsFile != "" {
|
||||
ports, err := Readfile(PortsFile)
|
||||
|
@ -107,7 +107,7 @@ func parseIP(ip string) []string {
|
||||
|
||||
switch {
|
||||
case ip == "192":
|
||||
return parseIP("192.168.0.0/8")
|
||||
return parseIP("192.168.0.0/16")
|
||||
case ip == "172":
|
||||
return parseIP("172.16.0.0/12")
|
||||
case ip == "10":
|
||||
|
@ -16,7 +16,7 @@ const (
|
||||
)
|
||||
|
||||
// 插件分类映射表 - 所有插件名使用小写
|
||||
var pluginGroups = map[string][]string{
|
||||
var PluginGroups = map[string][]string{
|
||||
ModeAll: {
|
||||
"webtitle", "webpoc", // web类
|
||||
"mysql", "mssql", "redis", "mongodb", "postgres", // 数据库类
|
||||
@ -78,12 +78,12 @@ func ParseScanMode(mode string) {
|
||||
// 默认使用All模式
|
||||
ScanMode = ModeAll
|
||||
LogInfo(fmt.Sprintf("未识别的模式,使用默认模式: %s", ModeAll))
|
||||
LogInfo(fmt.Sprintf("包含插件: %v", pluginGroups[ModeAll]))
|
||||
LogInfo(fmt.Sprintf("包含插件: %v", PluginGroups[ModeAll]))
|
||||
}
|
||||
|
||||
// GetPluginsForMode 获取指定模式下的插件列表
|
||||
func GetPluginsForMode(mode string) []string {
|
||||
plugins, exists := pluginGroups[mode]
|
||||
plugins, exists := PluginGroups[mode]
|
||||
if exists {
|
||||
return plugins
|
||||
}
|
||||
|
14
Core/ICMP.go
14
Core/ICMP.go
@ -57,7 +57,7 @@ func handleAliveHosts(chanHosts chan string, hostslist []string, isPing bool) {
|
||||
if isPing {
|
||||
protocol = "PING"
|
||||
}
|
||||
fmt.Printf("目标 %-15s 存活 (%s)\n", ip, protocol)
|
||||
Common.LogSuccess(fmt.Sprintf("目标 %-15s 存活 (%s)", ip, protocol))
|
||||
}
|
||||
|
||||
AliveHosts = append(AliveHosts, ip)
|
||||
@ -76,7 +76,7 @@ func probeWithICMP(hostslist []string, chanHosts chan string) {
|
||||
}
|
||||
|
||||
Common.LogError(fmt.Sprintf("ICMP监听失败: %v", err))
|
||||
fmt.Println("正在尝试无监听ICMP探测...")
|
||||
Common.LogInfo("正在尝试无监听ICMP探测...")
|
||||
|
||||
// 尝试无监听ICMP探测
|
||||
conn2, err := net.DialTimeout("ip4:icmp", "127.0.0.1", 3*time.Second)
|
||||
@ -87,8 +87,8 @@ func probeWithICMP(hostslist []string, chanHosts chan string) {
|
||||
}
|
||||
|
||||
Common.LogError(fmt.Sprintf("ICMP连接失败: %v", err))
|
||||
fmt.Println("当前用户权限不足,无法发送ICMP包")
|
||||
fmt.Println("切换为PING方式探测...")
|
||||
Common.LogInfo("当前用户权限不足,无法发送ICMP包")
|
||||
Common.LogInfo("切换为PING方式探测...")
|
||||
|
||||
// 降级使用ping探测
|
||||
RunPing(hostslist, chanHosts)
|
||||
@ -100,8 +100,7 @@ func printAliveStats(hostslist []string) {
|
||||
if len(hostslist) > 1000 {
|
||||
arrTop, arrLen := ArrayCountValueTop(AliveHosts, Common.LiveTop, true)
|
||||
for i := 0; i < len(arrTop); i++ {
|
||||
output := fmt.Sprintf("B段 %-16s 存活主机数: %d", arrTop[i]+".0.0/16", arrLen[i])
|
||||
Common.LogSuccess(output)
|
||||
Common.LogSuccess(fmt.Sprintf("%s.0.0/16 存活主机数: %d", arrTop[i], arrLen[i]))
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,8 +108,7 @@ func printAliveStats(hostslist []string) {
|
||||
if len(hostslist) > 256 {
|
||||
arrTop, arrLen := ArrayCountValueTop(AliveHosts, Common.LiveTop, false)
|
||||
for i := 0; i < len(arrTop); i++ {
|
||||
output := fmt.Sprintf("C段 %-16s 存活主机数: %d", arrTop[i]+".0/24", arrLen[i])
|
||||
Common.LogSuccess(output)
|
||||
Common.LogSuccess(fmt.Sprintf("%s.0/24 存活主机数: %d", arrTop[i], arrLen[i]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,11 +33,57 @@ func Scan(info Common.HostInfo) {
|
||||
switch {
|
||||
case Common.LocalMode:
|
||||
// 本地信息收集模式
|
||||
Common.LogInfo("执行本地信息收集")
|
||||
LocalScan = true
|
||||
|
||||
// 定义本地模式允许的插件
|
||||
validLocalPlugins := make(map[string]bool)
|
||||
for _, plugin := range Common.PluginGroups[Common.ModeLocal] {
|
||||
validLocalPlugins[plugin] = true
|
||||
}
|
||||
|
||||
// 如果没有指定扫描模式或为默认的All,设置为 ModeLocal
|
||||
if Common.ScanMode == "" || Common.ScanMode == "All" {
|
||||
Common.ScanMode = Common.ModeLocal
|
||||
} else if Common.ScanMode != Common.ModeLocal {
|
||||
// 不是完整模式时,检查是否是合法的单插件
|
||||
if !validLocalPlugins[Common.ScanMode] {
|
||||
Common.LogError(fmt.Sprintf("无效的本地模式插件: %s, 仅支持 localinfo", Common.ScanMode))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if Common.ScanMode == Common.ModeLocal {
|
||||
Common.LogInfo("执行本地信息收集 - 使用全部本地插件")
|
||||
} else {
|
||||
Common.LogInfo(fmt.Sprintf("执行本地信息收集 - 使用插件: %s", Common.ScanMode))
|
||||
}
|
||||
|
||||
executeScans([]Common.HostInfo{info}, &ch, &wg)
|
||||
|
||||
case len(Common.URLs) > 0:
|
||||
// Web模式
|
||||
WebScan = true
|
||||
|
||||
// 从 pluginGroups 获取Web模式允许的插件
|
||||
validWebPlugins := make(map[string]bool)
|
||||
for _, plugin := range Common.PluginGroups[Common.ModeWeb] {
|
||||
validWebPlugins[plugin] = true
|
||||
}
|
||||
|
||||
// 如果没有指定扫描模式,默认设置为 ModeWeb
|
||||
if Common.ScanMode == "" || Common.ScanMode == "All" {
|
||||
Common.ScanMode = Common.ModeWeb
|
||||
}
|
||||
|
||||
// 如果不是 ModeWeb,检查是否是合法的单插件
|
||||
if Common.ScanMode != Common.ModeWeb {
|
||||
if !validWebPlugins[Common.ScanMode] {
|
||||
Common.LogError(fmt.Sprintf("无效的Web插件: %s, 仅支持 webtitle 和 webpoc", Common.ScanMode))
|
||||
return
|
||||
}
|
||||
// ScanMode 保持为单插件名
|
||||
}
|
||||
|
||||
var targetInfos []Common.HostInfo
|
||||
for _, url := range Common.URLs {
|
||||
urlInfo := info
|
||||
@ -47,7 +93,12 @@ func Scan(info Common.HostInfo) {
|
||||
urlInfo.Url = url
|
||||
targetInfos = append(targetInfos, urlInfo)
|
||||
}
|
||||
Common.LogInfo("开始Web扫描")
|
||||
|
||||
if Common.ScanMode == Common.ModeWeb {
|
||||
Common.LogInfo("开始Web扫描 - 使用全部Web插件")
|
||||
} else {
|
||||
Common.LogInfo(fmt.Sprintf("开始Web扫描 - 使用插件: %s", Common.ScanMode))
|
||||
}
|
||||
executeScans(targetInfos, &ch, &wg)
|
||||
|
||||
default:
|
||||
|
@ -44,8 +44,27 @@ func CheckMultiPoc(req *http.Request, pocs []*Poc, workers int) {
|
||||
for i := 0; i < workers; i++ {
|
||||
go func() {
|
||||
for task := range tasks {
|
||||
isVulnerable, details, vulName := executePoc(task.Req, task.Poc)
|
||||
|
||||
isVulnerable, err, vulName := executePoc(task.Req, task.Poc)
|
||||
if err != nil {
|
||||
wg.Done()
|
||||
continue
|
||||
}
|
||||
details := func(enable bool) string {
|
||||
data := ""
|
||||
if !enable {
|
||||
return data
|
||||
}
|
||||
if task.Poc.Detail.Author != "" {
|
||||
data += "\tauthor:" + task.Poc.Detail.Author + "\n"
|
||||
}
|
||||
if len(task.Poc.Detail.Links) != 0 || task.Poc.Detail.Links != nil {
|
||||
data += "\tlinks:" + strings.Join(task.Poc.Detail.Links, "\n") + "\n"
|
||||
}
|
||||
if task.Poc.Detail.Description != "" {
|
||||
data += "\tdescription:" + task.Poc.Detail.Description + "\n"
|
||||
}
|
||||
return data
|
||||
}(true)
|
||||
if isVulnerable {
|
||||
result := fmt.Sprintf("目标: %s\n 漏洞类型: %s\n 漏洞名称: %s\n 详细信息: %s",
|
||||
task.Req.URL,
|
||||
|
Loading…
Reference in New Issue
Block a user