mirror of
https://github.com/activecm/rita
synced 2026-06-08 13:02:45 +00:00
b923c39e2d
* Update on config structure, functionality, and tests Co-Authored-By: Naomi Kramer <naomiagoddard@gmail.com> * Extend subnet type to read/write from db, update tests Co-Authored-By: Liza Tsibur <liza@activecountermeasures.com> * updated read file config test and subnet tests * fixed config and util tests, updated subnet related functions Co-Authored-By: Naomi Kramer <naomiagoddard@gmail.com> * Remove error return from GetDefaultConfig Co-Authored-By: Liza Tsibur <liza@activecountermeasures.com> * added json tags to database struct * Updated beacon weights validation for config * updates to score thresholds validation tags * changes to config subnet validation and testing * Update subnet.go * Write missing host entries to http to populate http_proto * Updating some fields to uint64 * WIP update some field types * Update zeek count types and fix tests * Add clickhouse credentials * Misc fixes * Update pointer * Add ability to mark datasets as sample datasets * fix column name * Fix datasets exiting import if hour is empty * Fix zeek count parsing from TSV files * Remove storing dns conns in arrays, Fix historical first seen dns lag * Remove unused columns * Update config.hjson * Update config.hjson * updated impact category score functions to use float64 Co-Authored-By: Naomi Kramer <naomiagoddard@gmail.com> * Update subnet.go * Store import version in imports table * Fix duplicated SNI/IP long connections * Update subnet_test.go * Cleanup output * Rolling files updates (#39) * Limit number of days to import for rolling datasets * Fix breaking imports when import was interrupted * Remove debug output --------- Co-authored-by: Naomi Kramer <naomi@activecountermeasures.com> * Omit parts of env from output * Set max for threat intel datasize * Remove SELinux neutering for QA * Add network size column * Fix http_proto for missing host, update tests for missing host fixes * Add online feeds to default config * Update sshprep (#45) * Update sshprep Co-Authored-By: William Stearns <3538265+william-stearns@users.noreply.github.com> * Update sshprep Add Bradley's suggestion of using head -1 to limit to a single address. --------- Co-authored-by: Naomi Kramer <naomi@activecountermeasures.com> Co-authored-by: William Stearns <3538265+william-stearns@users.noreply.github.com> * Installer Behavior Tweaks (#41) * Add --yes flag to add-apt-repository command * Add missing sudo flags, make sure we're using the SUDO variable instead * Add ability to perform zone transfers (#48) * Store zone transfer records Co-Authored-By: moth <25512187+0x6d6f7468@users.noreply.github.com> * Update config * Add tests * Tests, connectivity test * Update tests --------- Co-authored-by: moth <25512187+0x6d6f7468@users.noreply.github.com> * Support RedHat/RHEL as a valid target (#47) * Update sshprep Co-Authored-By: William Stearns <3538265+william-stearns@users.noreply.github.com> * Supporrt RedHat/RHEL as a valid target --------- Co-authored-by: Naomi Kramer <naomi@activecountermeasures.com> Co-authored-by: William Stearns <3538265+william-stearns@users.noreply.github.com> Co-authored-by: moth <moth@blackhillsinfosec.com> * Fix tests (#49) * Fix tests * Update WalkFiles to use UTC * fixed issue with rolling datasets over 24hours old not getting historical first seen timestamp set (#52) * Change values from float32 to float64 (#50) * Switch float32 to float64 * Update threat category calculation to match CalculateBucketedScore (#51) --------- Co-authored-by: Liza Tsibur <liza@activecountermeasures.com> * Bump max query execution time default value * Use string instead of error for ZoneTransferConnectivityErrors struct fields (#61) * Upgrade Golang to version 1.24 (#59) (#60) * Replace get_url with shell and curl (#58) * Update sshprep Co-Authored-By: William Stearns <3538265+william-stearns@users.noreply.github.com> * Replace get_url with shell and curl * Use get_url by default, fall back to curl if it fails --------- Co-authored-by: Naomi Kramer <naomi@activecountermeasures.com> Co-authored-by: William Stearns <3538265+william-stearns@users.noreply.github.com> Co-authored-by: moth <moth@blackhillsinfosec.com> * add automated log transfer, AC-Hunter issue 135 (#62) * Update sshprep Co-Authored-By: William Stearns <3538265+william-stearns@users.noreply.github.com> * add automated log transfer, PR135 * cron requires non-executable permission * Specify suggested YAML plugin and config in VSCode workspace * Linting and light cleanup * Update generate_installer.sh Download zeek_log_transport.sh to send to the sensor. * Create cron file if remote zeek installation * Only run zeek log import steps for remote sensor installations --------- Co-authored-by: Naomi Kramer <naomi@activecountermeasures.com> Co-authored-by: William Stearns <3538265+william-stearns@users.noreply.github.com> Co-authored-by: moth <moth@blackhillsinfosec.com> * Temporarily disable RITA/Zeek log transport until installer is modular (#66) * Uniform -y flag usage for repo management/package installation; Uniform SUDO variable usage (#68) * Resolve Installer Side Effects and Formalize RHEL Support (#73) * Add missing necessary wildcards for RHEL versions * Remove Ansible task replacing python3-requests to avoid RHEL distro installation side effects * Update supported distros in README * Update scoring defaults * Resolve Ansible Reboot Errors (#75) * Clean up conditionals; Fix reboot step for Ubuntu * Suppress erroneous error output on RPM systems, ignore errors on reboot necessity checks * Ignore missing host rows for openhttp (#76) * Fix integration tests due to prevalence (#77) --------- Co-authored-by: Liza Tsibur <liza@activecountermeasures.com> Co-authored-by: moth <moth@blackhillsinfosec.com> Co-authored-by: William Stearns <william.l.stearns@gmail.com> Co-authored-by: William Stearns <3538265+william-stearns@users.noreply.github.com> Co-authored-by: moth <25512187+0x6d6f7468@users.noreply.github.com>
299 lines
11 KiB
Go
299 lines
11 KiB
Go
package config
|
|
|
|
import (
|
|
"github.com/activecm/rita/v5/util"
|
|
|
|
"net"
|
|
)
|
|
|
|
// Filter provides methods for excluding IP addresses, domains, and determining proxy servers during the import step
|
|
// based on the user configuration
|
|
type Filter struct {
|
|
InternalSubnetsJSON []string `json:"internal_subnets"`
|
|
InternalSubnets []*net.IPNet
|
|
|
|
AlwaysIncludedSubnetsJSON []string `json:"always_included_subnets"`
|
|
AlwaysIncludedSubnets []*net.IPNet
|
|
|
|
NeverIncludedSubnetsJSON []string `json:"never_included_subnets"`
|
|
NeverIncludedSubnets []*net.IPNet
|
|
|
|
AlwaysIncludedDomains []string `json:"always_included_domains"`
|
|
NeverIncludedDomains []string `json:"never_included_domains"`
|
|
|
|
FilterExternalToInternal bool `json:"filter_external_to_internal"`
|
|
}
|
|
|
|
// func GetMandatoryNeverIncludeSubnets() []string {
|
|
// // s2 := make([]string, len(mandatoryNeverIncludeSubnets))
|
|
|
|
// // _ = copy(s2, mandatoryNeverIncludeSubnets) // s2 is now an independent copy of s
|
|
// // return s2
|
|
// return []string{
|
|
// "0.0.0.0/32", // current host
|
|
// "127.0.0.0/8", // loopback
|
|
// "169.254.0.0/16", // link local
|
|
// "224.0.0.0/4", // multicast
|
|
// "255.255.255.255/32", // limited broadcast
|
|
// "::1/128", // loopback
|
|
// "::", // unspecified IPv6
|
|
// "fe80::/10", // link local
|
|
// "ff00::/8", // multicast
|
|
// "ff02::2", // local multicast
|
|
// }
|
|
// }
|
|
|
|
func GetMandatoryNeverIncludeSubnets() []util.Subnet {
|
|
// s2 := make([]string, len(mandatoryNeverIncludeSubnets))
|
|
|
|
// _ = copy(s2, mandatoryNeverIncludeSubnets) // s2 is now an independent copy of s
|
|
// return s2
|
|
return []util.Subnet{
|
|
{IPNet: &net.IPNet{IP: net.IP{0, 0, 0, 0}.To16(), Mask: net.CIDRMask(128, 128)}}, // 0.0.0.0/32 current host
|
|
{IPNet: &net.IPNet{IP: net.IP{127, 0, 0, 0}.To16(), Mask: net.CIDRMask(104, 128)}}, // "127.0.0.0/8" loopback
|
|
{IPNet: &net.IPNet{IP: net.IP{169, 254, 0, 0}.To16(), Mask: net.CIDRMask(112, 128)}}, // "169.254.0.0/16", link local
|
|
{IPNet: &net.IPNet{IP: net.IP{224, 0, 0, 0}.To16(), Mask: net.CIDRMask(100, 128)}}, // "224.0.0.0/4", multicast
|
|
{IPNet: &net.IPNet{IP: net.IP{255, 255, 255, 255}.To16(), Mask: net.CIDRMask(128, 128)}}, // "255.255.255.255/32", limited broadcast
|
|
{IPNet: &net.IPNet{IP: net.ParseIP("::1"), Mask: net.CIDRMask(128, 128)}}, //"::1/128", loopback
|
|
{IPNet: &net.IPNet{IP: net.ParseIP("::"), Mask: net.CIDRMask(128, 128)}}, // "::", unspecified IPv6
|
|
{IPNet: &net.IPNet{IP: net.ParseIP("fe80::"), Mask: net.CIDRMask(10, 128)}}, // fe80::/10", link local
|
|
{IPNet: &net.IPNet{IP: net.ParseIP("ff00::"), Mask: net.CIDRMask(8, 128)}}, // "ff00::/8", multicast
|
|
{IPNet: &net.IPNet{IP: net.ParseIP("ff02::2"), Mask: net.CIDRMask(128, 128)}}, // "ff02::2", local multicast
|
|
}
|
|
}
|
|
|
|
// func ()
|
|
|
|
// func (cfg *Config) parseFilter() error {
|
|
// // parse internal subnets
|
|
// internalSubnetList, err := util.ParseSubnets(cfg.Filtering.InternalSubnetsJSON)
|
|
// if err != nil {
|
|
// return err
|
|
// }
|
|
// cfg.Filtering.InternalSubnets = internalSubnetList
|
|
|
|
// // parse always included subnets
|
|
// alwaysIncludedSubnetList, err := util.ParseSubnets(cfg.Filtering.AlwaysIncludedSubnetsJSON)
|
|
// if err != nil {
|
|
// return err
|
|
// }
|
|
// cfg.Filtering.AlwaysIncludedSubnets = alwaysIncludedSubnetList
|
|
|
|
// // validate that all mandatory never include subnets are present
|
|
// cfg.Filtering.NeverIncludedSubnetsJSON = util.EnsureSliceContainsAll(cfg.Filtering.NeverIncludedSubnetsJSON, GetMandatoryNeverIncludeSubnets())
|
|
|
|
// // parse never included subnets
|
|
// neverIncludedSubnetList, err := util.ParseSubnets(cfg.Filtering.NeverIncludedSubnetsJSON)
|
|
// if err != nil {
|
|
// return err
|
|
// }
|
|
// cfg.Filtering.NeverIncludedSubnets = neverIncludedSubnetList
|
|
|
|
// return nil
|
|
// }
|
|
|
|
// FilterSNIPair returns true if a SNI connection pair is filtered/excluded.
|
|
func (fs *Filtering) FilterSNIPair(srcIP net.IP) bool {
|
|
// check if src is internal
|
|
isSrcInternal := util.ContainsIP(fs.InternalSubnets, srcIP)
|
|
|
|
// filter out connections that have external source IPs
|
|
return !isSrcInternal
|
|
}
|
|
|
|
// FilterConnPairForHTTP returns true if a connection pair is filtered
|
|
// based on criteria that should apply regardless of whether or not there is a proxy connection for it
|
|
func (fs *Filtering) FilterConnPairForHTTP(srcIP net.IP, dstIP net.IP) bool {
|
|
|
|
// check if on always included list
|
|
isSrcIncluded := util.ContainsIP(fs.AlwaysIncludedSubnets, srcIP)
|
|
isDstIncluded := util.ContainsIP(fs.AlwaysIncludedSubnets, dstIP)
|
|
|
|
// check if on never included list
|
|
isSrcExcluded := util.ContainsIP(fs.NeverIncludedSubnets, srcIP)
|
|
isDstExcluded := util.ContainsIP(fs.NeverIncludedSubnets, dstIP)
|
|
|
|
// if either IP is on the AlwaysInclude list, filter does not apply
|
|
if isSrcIncluded || isDstIncluded {
|
|
return false
|
|
}
|
|
|
|
// if either IP is on the NeverInclude list, filter applies
|
|
if isSrcExcluded || isDstExcluded {
|
|
return true
|
|
}
|
|
|
|
// check if src and dst are internal
|
|
isSrcInternal := util.ContainsIP(fs.InternalSubnets, srcIP)
|
|
isDstInternal := util.ContainsIP(fs.InternalSubnets, dstIP)
|
|
|
|
// if both addresses are external, filter applies
|
|
if (!isSrcInternal) && (!isDstInternal) {
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// filterConnPair returns true if a connection pair is filtered/excluded.
|
|
// This is determined by the following rules, in order:
|
|
// 1. Not filtered if either IP is on the AlwaysInclude list
|
|
// 2. Filtered if either IP is on the NeverInclude list
|
|
// 3. Not filtered if InternalSubnets is empty
|
|
// 4. Filtered if both IPs are internal or both are external
|
|
// 5. Filtered if the source IP is external and the destination IP is internal and FilterExternalToInternal has been set in the configuration file
|
|
// 6. Not filtered in all other cases
|
|
func (fs *Filtering) FilterConnPair(srcIP net.IP, dstIP net.IP) bool {
|
|
|
|
// check if on always included list
|
|
isSrcIncluded := util.ContainsIP(fs.AlwaysIncludedSubnets, srcIP)
|
|
isDstIncluded := util.ContainsIP(fs.AlwaysIncludedSubnets, dstIP)
|
|
|
|
// check if on never included list
|
|
isSrcExcluded := util.ContainsIP(fs.NeverIncludedSubnets, srcIP)
|
|
isDstExcluded := util.ContainsIP(fs.NeverIncludedSubnets, dstIP)
|
|
|
|
// if either IP is on the AlwaysInclude list, filter does not apply
|
|
if isSrcIncluded || isDstIncluded {
|
|
return false
|
|
}
|
|
|
|
// if either IP is on the NeverInclude list, filter applies
|
|
if isSrcExcluded || isDstExcluded {
|
|
return true
|
|
}
|
|
|
|
// if no internal subnets are defined, return false
|
|
// note: this should not happen since we validate the config to ensure
|
|
// that internal subnets is not empty
|
|
if len(fs.InternalSubnets) == 0 {
|
|
return false
|
|
}
|
|
|
|
// check if src and dst are internal
|
|
isSrcInternal := util.ContainsIP(fs.InternalSubnets, srcIP)
|
|
isDstInternal := util.ContainsIP(fs.InternalSubnets, dstIP)
|
|
|
|
// if both addresses are internal, filter applies
|
|
if isSrcInternal && isDstInternal {
|
|
return true
|
|
}
|
|
|
|
// if both addresses are external, filter applies
|
|
if (!isSrcInternal) && (!isDstInternal) {
|
|
return true
|
|
}
|
|
|
|
// filter external to internal traffic if the user has specified to do so
|
|
if fs.FilterExternalToInternal && (!isSrcInternal) && isDstInternal {
|
|
return true
|
|
}
|
|
|
|
// default to not filter the connection pair
|
|
return false
|
|
}
|
|
|
|
// filterDNSPair returns true if a DNS connection pair is filtered/excluded.
|
|
// DNS is treated specially since we need to capture internal -> internal DNS traffic
|
|
// in order to detect C2 over DNS with an internal resolver.
|
|
// This is determined by the following rules, in order:
|
|
// 1. Not filtered if either IP is on the AlwaysInclude list
|
|
// 2. Filtered if either IP is on the NeverInclude list
|
|
// 3. Not filtered if InternalSubnets is empty
|
|
// 4. Filtered if both IPs are external (this is different from filterConnPair which filters internal to internal connections)
|
|
// 5. Filtered if the source IP is external and the destination IP is internal and FilterExternalToInternal has been set in the configuration file
|
|
// 6. Not filtered in all other cases
|
|
func (fs *Filtering) FilterDNSPair(srcIP net.IP, dstIP net.IP) bool {
|
|
// check if on always included list
|
|
isSrcIncluded := util.ContainsIP(fs.AlwaysIncludedSubnets, srcIP)
|
|
isDstIncluded := util.ContainsIP(fs.AlwaysIncludedSubnets, dstIP)
|
|
|
|
// check if on never included list
|
|
isSrcExcluded := util.ContainsIP(fs.NeverIncludedSubnets, srcIP)
|
|
isDstExcluded := util.ContainsIP(fs.NeverIncludedSubnets, dstIP)
|
|
|
|
// if either IP is on the AlwaysInclude list, filter does not apply
|
|
if isSrcIncluded || isDstIncluded {
|
|
return false
|
|
}
|
|
|
|
// if either IP is on the NeverInclude list, filter applies
|
|
if isSrcExcluded || isDstExcluded {
|
|
return true
|
|
}
|
|
|
|
// if no internal subnets are defined, filter does not apply
|
|
// this is was the default behavior before InternalSubnets was added
|
|
if len(fs.InternalSubnets) == 0 {
|
|
return false
|
|
}
|
|
|
|
// check if src and dst are internal
|
|
isSrcInternal := util.ContainsIP(fs.InternalSubnets, srcIP)
|
|
isDstInternal := util.ContainsIP(fs.InternalSubnets, dstIP)
|
|
|
|
// if both addresses are external, filter applies
|
|
if (!isSrcInternal) && (!isDstInternal) {
|
|
return true
|
|
}
|
|
|
|
// filter external to internal traffic if the user has specified to do so
|
|
if fs.FilterExternalToInternal && (!isSrcInternal) && isDstInternal {
|
|
return true
|
|
}
|
|
|
|
// default to not filter the connection pair
|
|
return false
|
|
}
|
|
|
|
// filterSingleIP returns true if an IP is filtered/excluded.
|
|
// This is determined by the following rules, in order:
|
|
// 1. Not filtered IP is on the AlwaysInclude list
|
|
// 2. Filtered IP is on the NeverInclude list
|
|
// 3. Not filtered in all other cases
|
|
func (fs *Filtering) FilterSingleIP(ip net.IP) bool {
|
|
|
|
// check if on always included list
|
|
if util.ContainsIP(fs.AlwaysIncludedSubnets, ip.To16()) {
|
|
return false
|
|
}
|
|
|
|
// check if on never included list
|
|
if util.ContainsIP(fs.NeverIncludedSubnets, ip.To16()) {
|
|
return true
|
|
}
|
|
|
|
// default to not filter the IP address
|
|
return false
|
|
}
|
|
|
|
// FilterDomain returns true if a domain is filtered/excluded.
|
|
// This is determined by the following rules, in order:
|
|
// 1. Not filtered if domain is on the AlwaysInclude list
|
|
// 2. Filtered if domain is on the NeverInclude list
|
|
// 3. Not filtered in all other cases
|
|
func (fs *Filtering) FilterDomain(domain string) bool {
|
|
// check if on always included list
|
|
isDomainIncluded := util.ContainsDomain(fs.AlwaysIncludedDomains, domain)
|
|
|
|
// check if on never included list
|
|
isDomainExcluded := util.ContainsDomain(fs.NeverIncludedDomains, domain)
|
|
|
|
// if either IP is on the AlwaysInclude list, filter does not apply
|
|
if isDomainIncluded {
|
|
return false
|
|
}
|
|
|
|
// if either IP is on the NeverInclude list, filter applies
|
|
if isDomainExcluded {
|
|
return true
|
|
}
|
|
|
|
// default to not filter the connection pair
|
|
return false
|
|
}
|
|
|
|
func (fs *Filtering) CheckIfInternal(host net.IP) bool {
|
|
return util.ContainsIP(fs.InternalSubnets, host)
|
|
}
|