mirror of
https://github.com/wikiZ/RedGuard
synced 2026-06-08 18:18:32 +00:00
Update RedGuard Version 23.05.14
This commit is contained in:
@@ -1,3 +1,7 @@
|
||||
## [23.05.14.2020] - 2023-05-14
|
||||
### Added
|
||||
- Sample Fingerprint Identify
|
||||
|
||||
## [22.08.03.1214] - 2022-08-03
|
||||
### Added
|
||||
- Support custom domain names for communication between intranet hosts
|
||||
|
||||
@@ -293,6 +293,49 @@ The profile written by 风起 is recommended to use:
|
||||
|
||||
> <https://github.com/wikiZ/CobaltStrike-Malleable-Profile>
|
||||
|
||||
## Sample FingerPrint
|
||||
|
||||
RedGuard 23.05.13 has updated the trojan sample fingerprint recognition function, which is based on customizing the HTTP Header field of the Malleable Profile as the fingerprint “**sample salt value**” for uniquely identifying the same **C2 listener**/Header Host. In addition, the trojan sample fingerprint generated by combining other relevant request fields can be used to detect the custom sample liveliness. According to the attacker’s task requirements, the trojan sample fingerprint recognition function can perform “**offline operation**” on the samples you want to disable, to better evade malicious traffic analysis of the sample communication and the staged sample PAYLOAD attack payload acquisition analysis, and provide more personalized stealth measures for the attacker.
|
||||
|
||||
For different C2 listeners, we can give different aliases to the Malleable Profile configurations, customize the field names and values of related headers as the sample salt value, and use it as one of the distinctions between different samples. The following code is for illustration purposes, and in actual attack and defense scenarios we can use more realistic HTTP request packet fields as the basis for judgment.
|
||||
|
||||
```bash
|
||||
http-get "listen2" {
|
||||
set uri "/image.gif";
|
||||
client {
|
||||
header "Accept-Finger" "866e5289337ab033f89bc57c5274c7ca"; //Custom HTTP Header and Value
|
||||
metadata {
|
||||
print
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**HTTP traffic**
|
||||
|
||||

|
||||
|
||||
As shown in the figure, we use the above sample Salt value and Host field as the basis for fingerprint generation. Here we know:
|
||||
|
||||
- **Salt Value:866e5289337ab033f89bc57c5274c7ca**
|
||||
- **Host :redguard.com**
|
||||
|
||||
According to splicing the above values, the sample fingerprint is obtained as follows:
|
||||
|
||||
```bash
|
||||
22e6db08c5ef1889d64103a290ac145c
|
||||
```
|
||||
|
||||
Now that we know the above sample fingerprint, we can set the custom Header field and sample fingerprint in the RedGuard configuration file for malicious traffic interception. It is worth noting that we can extend multiple sample fingerprints, separated by commas, and the FieldName needs to be consistent with the Header field name configured in the Malleable Profile
|
||||
|
||||

|
||||
|
||||
Because RedGuard’s configuration file is a hot configuration, we don’t need to restart RedGuard to intercept the samples we want to disable. When we want the sample to be reactivated, we just need to delete the relevant sample fingerprint from the RedGuard configuration file.
|
||||
|
||||
**Demonstration effect:**
|
||||
|
||||

|
||||
|
||||
# 0x04 Case Analysis
|
||||
|
||||
## Cyberspace Search Mapping
|
||||
|
||||
+6
-5
@@ -78,16 +78,17 @@ func main() {
|
||||
fmt.Println(fmt.Sprintf(config.BANNER, config.VERSION, config.URL)) // output banner information.
|
||||
// Create the tool argument
|
||||
var (
|
||||
parse parameter.Parses // Basic parameter structure
|
||||
cert parameter.Cert // Certificate configuration parameter structure
|
||||
_proxy parameter.Proxy // Proxy configuration parameter structure
|
||||
parse parameter.Parses // Basic parameter structure
|
||||
_cert parameter.Cert // Certificate configuration parameter structure
|
||||
_proxy parameter.Proxy // Proxy configuration parameter structure
|
||||
_finger parameter.SampleFinger
|
||||
)
|
||||
core.CmdParse(&parse, &cert, &_proxy)
|
||||
core.CmdParse(&parse, &_cert, &_finger, &_proxy)
|
||||
// Check whether RedGuard has been initialized
|
||||
if num, isExits := lib.CreateConfig(parse.C2Type /* C2 Facility Type */, parse.ConfigPath); isExits {
|
||||
switch {
|
||||
case parse.Update:
|
||||
lib.UpdateConfig(&cert, &_proxy) // Update RedGuard Config
|
||||
lib.UpdateConfig(&_cert, &_proxy, &_finger) // Update RedGuard Config
|
||||
logger.Notice("RedGuard Configuration file updated successfully!")
|
||||
case parse.IP != "":
|
||||
if lib.CheckIP(parse.IP) == false {
|
||||
|
||||
+5
-5
@@ -3,8 +3,8 @@
|
||||
[2022-05-23 10:34:36] [RedGuard/core.ProxyManger] Proxy Listen Port :80 (HTTP)
|
||||
[2022-05-23 10:34:36] [RedGuard/core.ProxyManger] Proxy Listen Port :443 (HTTPS)
|
||||
[2022-05-23 10:34:57] [RedGuard/core.(*baseHandle).ServeHTTP] [REQUEST] GET /
|
||||
[2022-05-23 10:34:57] [RedGuard/core.(*baseHandle).ServeHTTP] [REQUEST] 111.14.218.206 - Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36 Edg/101.0.1210.53
|
||||
[2022-05-23 10:34:57] [RedGuard/core.(*baseHandle).ServeHTTP] [REDIRECT] Source IP: 111.14.218.206 -> Destination Site: https://360.net
|
||||
[2022-05-23 10:34:57] [RedGuard/core.(*baseHandle).ServeHTTP] [REQUEST] 111.14.218.xxx - Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36 Edg/101.0.1210.53
|
||||
[2022-05-23 10:34:57] [RedGuard/core.(*baseHandle).ServeHTTP] [REDIRECT] Source IP: 111.14.218.xxx -> Destination Site: https://360.net
|
||||
[2022-05-23 10:35:52] [RedGuard/core.(*baseHandle).ServeHTTP] [REQUEST] GET /
|
||||
[2022-05-23 10:35:52] [RedGuard/core.IPLookUp] {
|
||||
"status": "0",
|
||||
@@ -13,13 +13,13 @@
|
||||
"data": [
|
||||
{
|
||||
"ExtendedLocation": "",
|
||||
"OriginQuery": "111.14.218.206",
|
||||
"OriginQuery": "111.14.218.xxx",
|
||||
"appinfo": "",
|
||||
"disp_type": 0,
|
||||
"fetchkey": "111.14.218.206",
|
||||
"fetchkey": "111.14.218.xxx",
|
||||
"location": "山东省济南市 移动",
|
||||
"origip": "111.14.218.206",
|
||||
"origipquery": "111.14.218.206",
|
||||
"origipquery": "111.14.218.xxx",
|
||||
"resourceid": "6006",
|
||||
"role_id": 0,
|
||||
"shareImage": 1,
|
||||
|
||||
@@ -2,7 +2,7 @@ package config
|
||||
|
||||
var RedGuardConfig = `[cert]
|
||||
# User Optional name
|
||||
DNSName = *.aliyun.com,manager.channel.aliyun.com,*.acs-internal.aliyuncs.com,*.connect.aliyun.com,aliyun.com,whois.www.net.cn,tianchi-global.com
|
||||
DNSName = *.aliyun.com,manager.channel.aliyun.com,*.acs-internal.aliyuncs.com",*.connect.aliyun.com,aliyun.com,whois.www.net.cn,tianchi-global.com
|
||||
# Cert User CommonName
|
||||
CommonName = *.aliyun.com
|
||||
# Cert User Locality
|
||||
@@ -23,7 +23,7 @@ Port_HTTPS = :443
|
||||
# HTTP Reverse proxy port
|
||||
Port_HTTP = :80
|
||||
# RedGuard interception action: redirect / reset / proxy (Hijack HTTP Response)
|
||||
drop_action = proxy
|
||||
drop_action = redirect
|
||||
# URL to redirect to
|
||||
Redirect = https://360.net
|
||||
# IP address owning restrictions example:AllowLocation = 山东,上海,杭州 or shanghai,beijing
|
||||
@@ -35,7 +35,13 @@ AllowTime = *
|
||||
# C2 Malleable File Path
|
||||
MalleableFile = *
|
||||
# Edge Host Communication Domain
|
||||
EdgeHost = *
|
||||
EdgeHost = *
|
||||
# Edge Host Proxy Target example: EdgeTarget = 360.com
|
||||
EdgeTarget = *
|
||||
EdgeTarget = *
|
||||
|
||||
[SampleFinger]
|
||||
# HTTP Request Header Field
|
||||
FieldName = *
|
||||
# Sample Finger example:xxxxxx,xxxxxx
|
||||
FieldFinger = *
|
||||
`
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ Github:%s
|
||||
|
||||
RedGuard is a C2 front flow control tool,Can avoid Blue Teams,AVs,EDRs check.
|
||||
`
|
||||
VERSION = "22.08.03 Alpha"
|
||||
VERSION = "23.05.13 Alpha"
|
||||
TITLE = "RedGuard"
|
||||
LICENSE = "GPL-2.0"
|
||||
URL = "https://github.com/wikiZ/RedGuard"
|
||||
|
||||
@@ -119,9 +119,22 @@ func ProxyFilterManger(req *http.Request) (status bool) {
|
||||
allowIP = lib.ReadConfig("proxy", "AllowIP", cfg) // Obtain the online IP address whitelist
|
||||
allowTime = lib.ReadConfig("proxy", "AllowTime", cfg) // Gets the allowed online time in the configuration file
|
||||
malleableFile = lib.ReadConfig("proxy", "MalleableFile", cfg) // Obtain the profile path
|
||||
fieldName = lib.ReadConfig("SampleFinger", "FieldName", cfg)
|
||||
fieldFinger = lib.ReadConfig("SampleFinger", "FieldFinger", cfg)
|
||||
banJA3 = data.BANJA3
|
||||
banIP = data.BANIP
|
||||
)
|
||||
|
||||
// sample finger verify
|
||||
if f := req.Header.Get(fieldName); fieldName != "*" && fieldFinger != "*" && f != "" {
|
||||
finger := lib.EncodeMD5(req.Header.Get("Host") + f)
|
||||
logger.Noticef("Sample Finger: %s", finger)
|
||||
if strings.Contains(fieldFinger, finger) /* finger Check*/ {
|
||||
logger.Errorf("[DROP] Requested Sample Finger is forbidden to access")
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Check whether ban ip is matched
|
||||
for _, banAddr := range strings.Split(banIP, "\n") {
|
||||
// Check whether the requested IP address is in the correct IP address format or network segment format
|
||||
|
||||
@@ -99,11 +99,11 @@ func (h *baseHandle) ServeHTTP(write http.ResponseWriter, req *http.Request) {
|
||||
if IPHash := lib.EncodeMD5(req.JA3); arrays.ContainsString(_addressArray, req.JA3) == -1 {
|
||||
logger.Noticef("JA3 FingerPrint: %s", IPHash)
|
||||
logger.Noticef("[REQUEST] %s %s", req.Method, req.RequestURI)
|
||||
logger.Noticef("[REQUEST] %s - %s", req.RemoteAddr, req.UserAgent())
|
||||
// Request filtering method
|
||||
if !ProxyFilterManger(req) {
|
||||
goto LOOK // Redirect to the specified site
|
||||
}
|
||||
logger.Noticef("[REQUEST] %s - %s", req.RemoteAddr, req.UserAgent())
|
||||
_addressArray = append(_addressArray, IPHash) // Add to the list after verification for the first time
|
||||
}
|
||||
// Fetch directly from cache
|
||||
|
||||
+3
-1
@@ -13,7 +13,7 @@ import (
|
||||
"RedGuard/core/parameter"
|
||||
)
|
||||
|
||||
func CmdParse(parse *parameter.Parses, cert *parameter.Cert, proxy *parameter.Proxy) {
|
||||
func CmdParse(parse *parameter.Parses, cert *parameter.Cert, finger *parameter.SampleFinger, proxy *parameter.Proxy) {
|
||||
flag.BoolVar(&parse.Update, "u", false, `Enable configuration file modification`)
|
||||
flag.StringVar(&parse.C2Type, "type", `CobaltStrike`, `C2 Server Type`)
|
||||
flag.StringVar(&parse.IP, "ip", ``, `IPLookUP IP`)
|
||||
@@ -36,5 +36,7 @@ func CmdParse(parse *parameter.Parses, cert *parameter.Cert, proxy *parameter.Pr
|
||||
flag.StringVar(&proxy.MalleableFile, "malleable", "*", "Set Proxy Requests Filter Malleable File")
|
||||
flag.StringVar(&proxy.EdgeHost, "EdgeHost", "*", "Set Edge Host Communication Domain")
|
||||
flag.StringVar(&proxy.EdgeTarget, "EdgeTarget", "*", "Set Edge Host Proxy Target")
|
||||
flag.StringVar(&finger.FieldName, "FieldName", "", "Set the name of the HTTP Header identification field")
|
||||
flag.StringVar(&finger.FieldFinger, "FieldFinger", "", "Set HTTP Header identification field Info")
|
||||
flag.Parse()
|
||||
}
|
||||
|
||||
@@ -45,3 +45,10 @@ type ProxyConf struct {
|
||||
Action string
|
||||
Pattern string
|
||||
}
|
||||
|
||||
// SampleFinger Set listener fingerprint identification rules
|
||||
// example [Accept-Finger: 866e5289337ab033f89bc57c5274c7ca]
|
||||
type SampleFinger struct {
|
||||
FieldName string // Set the name of the HTTP Header identification field
|
||||
FieldFinger string
|
||||
}
|
||||
|
||||
@@ -291,6 +291,49 @@ MalleableFile = /root/cobaltstrike/Malleable.profile
|
||||
|
||||
> https://github.com/wikiZ/CobaltStrike-Malleable-Profile
|
||||
|
||||
## Sample FingerPrint
|
||||
|
||||
RedGuard 23.05.13已更新木马样本指纹识别功能,该功能基于对Malleable Profile自定义设置HTTP Header字段,作为该指纹“**样本Salt值**”为相同**C2监听器/**Header Host提供唯一辨识并结合其他相关请求字段生成木马样本指纹,用于自定义样本存活性。根据攻击方任务需求,针对希望失效的样本进行**“下线操作”**,更好的规避恶意研判流量的样本通联性关联及分阶段样本PAYLOAD攻击载荷获取分析,给予攻击方更加个性化的隐匿措施。
|
||||
|
||||
针对不同C2监听器,我们可以设置不同Malleable Profile配置别称并自定义相关header的字段名及值,作为样本Salt值并以此作为区分不同样本之间的辨识之一。下列代码是为了方便说明,而在实际攻防场景下我们可以给予更加贴合实际的HTTP请求包字段作为判断依据。
|
||||
|
||||
```bash
|
||||
http-get "listen2" {
|
||||
set uri "/image.gif";
|
||||
client {
|
||||
header "Accept-Finger" "866e5289337ab033f89bc57c5274c7ca"; //用户自定义字段名及值
|
||||
metadata {
|
||||
print
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**HTTP流量**
|
||||
|
||||

|
||||
|
||||
如图所示,我们根据上述样本Salt值及Host字段作为指纹生成依据,这里我们已知:
|
||||
|
||||
- **Salt值:866e5289337ab033f89bc57c5274c7ca**
|
||||
- **Host字段值:redguard.com**
|
||||
|
||||
这里根据对上述值进行拼接得到sample指纹为:
|
||||
|
||||
```bash
|
||||
22e6db08c5ef1889d64103a290ac145c
|
||||
```
|
||||
|
||||
目前已知上述样本指纹,现在我们在RedGuard配置文件中设置自定义的Header字段及样本指纹用于恶意流量拦截,值得注意的是我们可以拓展多个样本指纹,不同指纹之间以逗号分隔,FieldName需要和Malleable Profile中配置的Header字段名称达成一致。
|
||||
|
||||

|
||||
|
||||
因为RedGuard的配置文件为热配置,所以这里我们不需要重新启停RG即可实现针对希望失效的样本进行拦截,当我们希望该样本重新生效时,只需在RG配置文件中删除相关样本指纹即可实现。
|
||||
|
||||
**演示效果**
|
||||
|
||||

|
||||
|
||||
# 0x04 案例分析
|
||||
|
||||
## 空间测绘
|
||||
|
||||
@@ -73,18 +73,21 @@ func ReadConfig(section, key string, cfg *ini.File) string {
|
||||
|
||||
// UpdateConfig Modify the content of the configuration file
|
||||
// Oh, my God, this is not elegant!
|
||||
func UpdateConfig(cert *parameter.Cert, proxy *parameter.Proxy) {
|
||||
func UpdateConfig(cert *parameter.Cert, proxy *parameter.Proxy, finger *parameter.SampleFinger) {
|
||||
var (
|
||||
_certList = map[string]string{
|
||||
"Locality": cert.Locality, "Country": cert.Country, "Organization": cert.Organization,
|
||||
"CommonName": cert.CommonName, "DNSName": cert.DNSNameTo, "HasCert": cert.HasCert,
|
||||
}
|
||||
_proxyLIst = map[string]string{
|
||||
_proxyList = map[string]string{
|
||||
"Port_HTTP": proxy.HTTPort, "Port_HTTPS": proxy.HTTPSPort, "Redirect": proxy.Redirect,
|
||||
"AllowIP": proxy.AllowIP, "AllowTime": proxy.AllowTime, "AllowLocation": proxy.AllowLocation,
|
||||
"drop_action": proxy.DropAction, "HostTarget": proxy.HostTarget, "MalleableFile": proxy.MalleableFile,
|
||||
"EdgeHost": proxy.EdgeHost, "EdgeTarget": proxy.EdgeTarget,
|
||||
}
|
||||
_sampleFinger = map[string]string{
|
||||
"FieldName": finger.FieldName, "FieldFinger": finger.FieldFinger,
|
||||
}
|
||||
cfg = InitConfig()
|
||||
)
|
||||
// re cert Write Config
|
||||
@@ -92,7 +95,10 @@ func UpdateConfig(cert *parameter.Cert, proxy *parameter.Proxy) {
|
||||
WriteConfig("cert", k, v, cfg)
|
||||
}
|
||||
// re proxy Write Config
|
||||
for k, v := range _proxyLIst {
|
||||
for k, v := range _proxyList {
|
||||
WriteConfig("proxy", k, v, cfg)
|
||||
}
|
||||
for k, v := range _sampleFinger {
|
||||
WriteConfig("SampleFinger", k, v, cfg)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user