Update RedGuard Version 23.05.14

This commit is contained in:
风起
2023-05-14 20:26:46 +08:00
parent a49d862c79
commit 874a03793e
12 changed files with 247 additions and 122 deletions
+4
View File
@@ -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
+43
View File
@@ -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 attackers 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**
![image.png](https://raw.githubusercontent.com/wikiZ/RedGuardImage/main/10b7b4d8f1d66bbf98e404332bf5d87.png)
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 Value866e5289337ab033f89bc57c5274c7ca**
- **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
![image.png](https://raw.githubusercontent.com/wikiZ/RedGuardImage/main/aa7488ece6370ff2559400a108664a4.png)
Because RedGuards configuration file is a hot configuration, we dont 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:**
![image.png](https://raw.githubusercontent.com/wikiZ/RedGuardImage/main/4d37798254ba9b5729ac886f90a10f7.png)
# 0x04 Case Analysis
## Cyberspace Search Mapping
+6 -5
View File
@@ -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
View File
@@ -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,
+10 -4
View File
@@ -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
View File
@@ -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"
+13
View File
@@ -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
+1 -1
View File
@@ -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
View File
@@ -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()
}
+7
View File
@@ -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
}
+43
View File
@@ -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流量**
![image.png](https://raw.githubusercontent.com/wikiZ/RedGuardImage/main/10b7b4d8f1d66bbf98e404332bf5d87.png)
如图所示,我们根据上述样本Salt值及Host字段作为指纹生成依据,这里我们已知:
- **Salt值:866e5289337ab033f89bc57c5274c7ca**
- **Host字段值:redguard.com**
这里根据对上述值进行拼接得到sample指纹为:
```bash
22e6db08c5ef1889d64103a290ac145c
```
目前已知上述样本指纹,现在我们在RedGuard配置文件中设置自定义的Header字段及样本指纹用于恶意流量拦截,值得注意的是我们可以拓展多个样本指纹,不同指纹之间以逗号分隔,FieldName需要和Malleable Profile中配置的Header字段名称达成一致。
![image.png](https://raw.githubusercontent.com/wikiZ/RedGuardImage/main/aa7488ece6370ff2559400a108664a4.png)
因为RedGuard的配置文件为热配置,所以这里我们不需要重新启停RG即可实现针对希望失效的样本进行拦截,当我们希望该样本重新生效时,只需在RG配置文件中删除相关样本指纹即可实现。
**演示效果**
![image.png](https://raw.githubusercontent.com/wikiZ/RedGuardImage/main/4d37798254ba9b5729ac886f90a10f7.png)
# 0x04 案例分析
## 空间测绘
+9 -3
View File
@@ -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)
}
}