mirror of
https://gitee.com/lauix/HFish
synced 2025-05-12 04:48:01 +08:00
359 lines
9.8 KiB
Go
359 lines
9.8 KiB
Go
package fish
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/csv"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
"github.com/gin-gonic/gin"
|
|
"HFish/core/dbUtil"
|
|
"HFish/error"
|
|
"HFish/utils/log"
|
|
"HFish/utils/page"
|
|
)
|
|
|
|
var header = []string{"编号", "蜜罐类型", "蜜罐名称", "集群名称", "攻击IP", "地理信息", "威胁情报", "详情信息", "详情长度", "攻击时间"}
|
|
|
|
var judgmentMap = map[string]string{
|
|
"C2": "远控",
|
|
"Botnet": "僵尸网络",
|
|
"Hijacked": "劫持",
|
|
"Phishing": "钓鱼",
|
|
"Malware": "恶意软件",
|
|
"Exploit": "漏洞利用",
|
|
"Scanner": "扫描",
|
|
"Zombie": "傀儡机",
|
|
"Spam": "垃圾邮件",
|
|
"Suspicious": "可疑",
|
|
"Compromised": "失陷主机",
|
|
"Whitelist": "白名单",
|
|
"Brute Force": "暴力破解",
|
|
"Proxy": "代理",
|
|
"Info": "基础信息",
|
|
"MiningPool": "矿池",
|
|
"CoinMiner": "私有矿池",
|
|
"Sinkhole C2": "安全机构接管C2",
|
|
"SSH Brute Force": "SSH 暴力破解",
|
|
"FTP Brute Force": "FTP 暴力破解",
|
|
"SMTP Brute Force": "SMTP 暴力破解",
|
|
"Http Brute Force": "HTTP AUTH 暴力破解",
|
|
"Web Login Brute Force": "撞库",
|
|
"HTTP Proxy": "HTTP Proxy",
|
|
"HTTP Proxy In": "HTTP 代理入口",
|
|
"HTTP Proxy Out": "HTTP 代理出口",
|
|
"Socks Proxy": "Socks 代理",
|
|
"Socks Proxy In": "Socks 代理入口",
|
|
"Socks Proxy Out": "Socks 代理出口",
|
|
"VPN": "VPN 代理",
|
|
"VPN In": "VPN 代理入口",
|
|
"VPN Out": "VPN 代理出口",
|
|
"Tor": "Tor 代理",
|
|
"Tor Proxy In": "Tor入口",
|
|
"Tor Proxy Out": "Tor出口",
|
|
"Bogon": "保留地址",
|
|
"FullBogon": "未启用IP",
|
|
"Gateway": "网关",
|
|
"IDC": "IDC 服务器",
|
|
"Dynamic IP": "动态IP",
|
|
"Edu": "教育",
|
|
"DDNS": "动态域名",
|
|
"Mobile": "移动基站",
|
|
"Search Engine Crawler": "搜索引擎爬虫",
|
|
"CDN": "CDN 服务器",
|
|
"Advertisement": "广告",
|
|
"DNS": "DNS 服务器",
|
|
"BTtracker": "BT 服务器",
|
|
"Backbone": "骨干网",
|
|
}
|
|
|
|
// 蜜罐 页面
|
|
func Html(c *gin.Context) {
|
|
c.HTML(http.StatusOK, "fish.html", gin.H{})
|
|
}
|
|
|
|
func isCondition(condition string) bool {
|
|
if condition == ">" || condition == "<" ||
|
|
condition == ">=" || condition == "<=" ||
|
|
condition == "=" {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func convertJudgment(judgmentArray []interface{}) string {
|
|
var judgments string
|
|
for _, j := range judgmentArray {
|
|
js := j.(string)
|
|
judgment, ok := judgmentMap[js]
|
|
if !ok {
|
|
judgment = js
|
|
}
|
|
if len(judgments) == 0 {
|
|
judgments = judgment
|
|
} else {
|
|
judgments += " " + judgment
|
|
}
|
|
}
|
|
return judgments
|
|
}
|
|
|
|
// 获取上钩列表
|
|
func GetFishList(c *gin.Context) {
|
|
pageNo, _ := c.GetQuery("page_no")
|
|
pageSize, _ := c.GetQuery("page_size")
|
|
typex, _ := c.GetQuery("type")
|
|
colony, _ := c.GetQuery("colony")
|
|
soText, _ := c.GetQuery("so_text")
|
|
condition, _ := c.GetQuery("condition")
|
|
length, _ := c.GetQuery("length")
|
|
startTime, _ := c.GetQuery("start_time")
|
|
endTime, _ := c.GetQuery("end_time")
|
|
|
|
// 拼接 SQL
|
|
db := dbUtil.DB().Table("hfish_info").Fields("id", "type", "project_name", "agent", "ip", "country", "region", "city", "intelligence", "create_time", "info", "info_len")
|
|
dbCount := dbUtil.DB().Table("hfish_info")
|
|
|
|
if typex != "all" {
|
|
db.Where("type", "=", typex)
|
|
dbCount.Where("type", "=", typex)
|
|
}
|
|
|
|
if colony != "all" {
|
|
db.Where("agent", "=", colony)
|
|
dbCount.Where("agent", "=", colony)
|
|
}
|
|
|
|
if isCondition(condition) && length != "" {
|
|
db.Where("info_len", condition, length)
|
|
dbCount.Where("info_len", condition, length)
|
|
}
|
|
|
|
if startTime != "" && endTime != "" {
|
|
stInt, err1 := strconv.ParseInt(startTime, 10, 64)
|
|
etInt, err2 := strconv.ParseInt(endTime, 10, 64)
|
|
if err1 == nil && err2 == nil {
|
|
st := time.Unix(stInt, 0).Format("2006-01-02 15:04:05")
|
|
et := time.Unix(etInt, 0).Format("2006-01-02 15:04:05")
|
|
db.Where("create_time", ">=", st).Where("create_time", "<=", et)
|
|
dbCount.Where("create_time", ">=", st).Where("create_time", "<=", et)
|
|
} else {
|
|
log.Pr("HFish", "127.0.0.1", "parseInt startTime err", err1)
|
|
log.Pr("HFish", "127.0.0.1", "parseInt endTime err", err2)
|
|
}
|
|
}
|
|
|
|
if soText != "" {
|
|
db.Where("project_name", "like", "%"+soText+"%").OrWhere("ip", "like", "%"+soText+"%")
|
|
dbCount.Where("project_name", "like", "%"+soText+"%").OrWhere("ip", "like", "%"+soText+"%")
|
|
}
|
|
// 统计查询数量
|
|
totalCount, errCount := dbCount.Count()
|
|
|
|
if errCount != nil {
|
|
log.Pr("HFish", "127.0.0.1", "统计分页总数失败", errCount)
|
|
}
|
|
|
|
// 查询列表
|
|
pageNoInt, _ := strconv.Atoi(pageNo)
|
|
pageSizeInt, _ := strconv.Atoi(pageSize)
|
|
pageStart := page.Start(pageNoInt, pageSizeInt)
|
|
|
|
result, err := db.OrderBy("id desc").Limit(pageSizeInt).Offset(pageStart).Get()
|
|
|
|
if err != nil {
|
|
log.Pr("HFish", "127.0.0.1", "查询上钩信息列表失败", err)
|
|
}
|
|
|
|
totalCountString := strconv.FormatInt(totalCount, 10)
|
|
totalCountInt, _ := strconv.Atoi(totalCountString)
|
|
|
|
pageCount := page.TotalPage(totalCountInt, pageSizeInt)
|
|
|
|
for i, info := range result {
|
|
intelligence, ok := info["intelligence"].(string)
|
|
if !ok || len(intelligence) == 0 {
|
|
continue
|
|
}
|
|
var intelligenceData json.RawMessage
|
|
err := json.Unmarshal([]byte(intelligence), &intelligenceData)
|
|
if err != nil {
|
|
log.Pr("HFish", "127.0.0.1", "json unmarshal err", err)
|
|
continue
|
|
}
|
|
result[i]["intelligence"] = intelligenceData
|
|
}
|
|
|
|
data := map[string]interface{}{
|
|
"result": result,
|
|
"pageCount": pageCount,
|
|
"totalCount": totalCount,
|
|
"page": pageNo,
|
|
}
|
|
|
|
c.JSON(http.StatusOK, error.ErrSuccessWithData(data))
|
|
}
|
|
|
|
// 批量导出蜜罐数据
|
|
func ExportFishList(c *gin.Context) {
|
|
typex, _ := c.GetQuery("type")
|
|
colony, _ := c.GetQuery("colony")
|
|
soText, _ := c.GetQuery("so_text")
|
|
condition, _ := c.GetQuery("condition")
|
|
length, _ := c.GetQuery("length")
|
|
startTime, _ := c.GetQuery("start_time")
|
|
endTime, _ := c.GetQuery("end_time")
|
|
|
|
// 拼接 SQL
|
|
db := dbUtil.DB().Table("hfish_info").Fields("id", "type", "project_name", "agent", "ip", "country", "region", "city", "intelligence", "create_time", "info", "info_len")
|
|
|
|
if typex != "all" {
|
|
db.Where("type", "=", typex)
|
|
}
|
|
|
|
if colony != "all" {
|
|
db.Where("agent", "=", colony)
|
|
}
|
|
|
|
if isCondition(condition) && length != "" {
|
|
db.Where("info_len", condition, length)
|
|
}
|
|
|
|
if startTime != "" && endTime != "" {
|
|
stInt, err1 := strconv.ParseInt(startTime, 10, 64)
|
|
etInt, err2 := strconv.ParseInt(endTime, 10, 64)
|
|
if err1 == nil && err2 == nil {
|
|
st := time.Unix(stInt, 0).Format("2006-01-02 15:04:05")
|
|
et := time.Unix(etInt, 0).Format("2006-01-02 15:04:05")
|
|
db.Where("create_time", ">=", st).Where("create_time", "<=", et)
|
|
} else {
|
|
log.Pr("HFish", "127.0.0.1", "parseInt startTime err", err1)
|
|
log.Pr("HFish", "127.0.0.1", "parseInt endTime err", err2)
|
|
}
|
|
}
|
|
|
|
if soText != "" {
|
|
db.Where("project_name", "like", "%"+soText+"%").OrWhere("ip", "like", "%"+soText+"%")
|
|
}
|
|
result, err := db.OrderBy("id desc").Get()
|
|
if err != nil {
|
|
log.Pr("HFish", "127.0.0.1", "查询上钩信息列表失败", err)
|
|
c.JSON(http.StatusOK, error.ErrExportData)
|
|
return
|
|
}
|
|
|
|
b := &bytes.Buffer{}
|
|
wr := csv.NewWriter(b)
|
|
wr.Write(header)
|
|
for i, info := range result {
|
|
id := fmt.Sprintf("%d", i+1)
|
|
ip := info["ip"].(string)
|
|
|
|
var infoLen string
|
|
iLen, ok := info["info_len"].(int64)
|
|
if ok {
|
|
infoLen = fmt.Sprintf("%d", iLen)
|
|
}
|
|
|
|
var intelligenceResult string
|
|
intelligenceData := make(map[string]map[string]interface{})
|
|
intelligence, _ := info["intelligence"].(string)
|
|
if len(intelligence) > 20 { // 没有威胁情报的就不用反序列化了
|
|
if err := json.Unmarshal([]byte(intelligence), &intelligenceData); err != nil {
|
|
log.Pr("HFish", "127.0.0.1", "intelligence json unmarshal err", err)
|
|
intelligenceResult = intelligence
|
|
} else {
|
|
judgments, ok := intelligenceData[ip]["judgments"].([]interface{})
|
|
if ok {
|
|
intelligenceResult = convertJudgment(judgments)
|
|
} else {
|
|
intelligenceResult = intelligence
|
|
}
|
|
}
|
|
} else {
|
|
intelligenceResult = intelligence
|
|
}
|
|
|
|
var geo string
|
|
country, ok := info["country"].(string)
|
|
if ok && country != "" {
|
|
geo = country
|
|
}
|
|
region, ok := info["region"].(string)
|
|
if ok && region != "" && region != country {
|
|
geo += "-" + region
|
|
}
|
|
city, ok := info["city"].(string)
|
|
if ok && city != "" && city != country && city != region {
|
|
geo += "-" + city
|
|
}
|
|
|
|
data := []string{id, info["type"].(string), info["project_name"].(string),
|
|
info["agent"].(string), info["ip"].(string), geo, intelligenceResult,
|
|
info["info"].(string), infoLen, info["create_time"].(string)}
|
|
wr.Write(data)
|
|
}
|
|
wr.Flush()
|
|
c.Writer.Header().Set("Content-Type", "text/csv")
|
|
c.Writer.Header().Set("Content-Disposition", "attachment;filename=hfish.csv")
|
|
c.String(http.StatusOK, b.String())
|
|
}
|
|
|
|
// 删除蜜罐
|
|
func PostFishDel(c *gin.Context) {
|
|
id := c.PostForm("id")
|
|
|
|
idx := strings.Split(id, ",")
|
|
inId := make([]interface{}, 20)
|
|
|
|
for _, x := range idx {
|
|
inId = append(inId, x)
|
|
}
|
|
|
|
_, err := dbUtil.DB().Table("hfish_info").WhereIn("id", inId).Delete()
|
|
|
|
if err != nil {
|
|
log.Pr("HFish", "127.0.0.1", "删除蜜罐失败", err)
|
|
}
|
|
|
|
c.JSON(http.StatusOK, error.ErrSuccess)
|
|
}
|
|
|
|
// 获取蜜罐信息
|
|
func GetFishInfo(c *gin.Context) {
|
|
id, _ := c.GetQuery("id")
|
|
|
|
result, err := dbUtil.DB().Table("hfish_info").Fields("info").Where("id", "=", id).First()
|
|
|
|
if err != nil {
|
|
log.Pr("HFish", "127.0.0.1", "获取蜜罐信息失败", err)
|
|
}
|
|
|
|
c.JSON(http.StatusOK, error.ErrSuccessWithData(result))
|
|
}
|
|
|
|
// 获取蜜罐分类信息,集群信息
|
|
func GetFishTypeInfo(c *gin.Context) {
|
|
resultType, errType := dbUtil.DB().Table("hfish_info").Fields("type").GroupBy("type").Get()
|
|
|
|
if errType != nil {
|
|
log.Pr("HFish", "127.0.0.1", "获取蜜罐分类失败", errType)
|
|
}
|
|
|
|
resultAgent, errAgent := dbUtil.DB().Table("hfish_info").Fields("agent").GroupBy("agent").Get()
|
|
|
|
if errAgent != nil {
|
|
log.Pr("HFish", "127.0.0.1", "获取集群分类失败", errAgent)
|
|
}
|
|
|
|
data := map[string]interface{}{
|
|
"resultInfoType": resultType,
|
|
"resultColonyName": resultAgent,
|
|
}
|
|
|
|
c.JSON(http.StatusOK, error.ErrSuccessWithData(data))
|
|
}
|