Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support encoded rules to avoid AV false positives #1369

Closed
YamatoSecurity opened this issue Jun 20, 2024 · 22 comments · Fixed by #1419
Closed

Support encoded rules to avoid AV false positives #1369

YamatoSecurity opened this issue Jun 20, 2024 · 22 comments · Fixed by #1419
Assignees
Labels
enhancement New feature or request

Comments

@YamatoSecurity
Copy link
Collaborator

YamatoSecurity commented Jun 20, 2024

In order to prevent Windows defender from alerting on false positives on yml rules and to minimize the amount of files we need to save to the system, Hayabusa will have the option to use encoded rules from a single file hosted at https://github.com/Yamato-Security/hayabusa-encoded-rules

We originally planned to encrypt and zip the rules and config files in the hayabusa-rules repository but that would greatly affect performance so we are now planning on using a file contains all rules and rules config files in an XOR-encoded form.

@YamatoSecurity YamatoSecurity added enhancement New feature or request pending labels Jun 20, 2024
@YamatoSecurity YamatoSecurity added this to the v2.17.0 milestone Jun 20, 2024
@YamatoSecurity
Copy link
Collaborator Author

Update: The encrypted rules.zip has been created through this issue: Yamato-Security/hayabusa-encoded-rules#1
So we can download the file from this URL: https://github.com/Yamato-Security/hayabusa-encrypted-rules/raw/main/rules.zip

@YamatoSecurity YamatoSecurity modified the milestones: v2.17.0, 2.18.0 Aug 9, 2024
@YamatoSecurity
Copy link
Collaborator Author

@hitenkoku Please wait on this issue. I recently tried uncompressing the hayabusa rules without encryption and it took quite a long time so I think it will slow down the scan quite a bit if we used an encrypted zip. The only other solution I can think of is by merging all of the rules into a single file and doing a simple XOR or something on it to bypass anti-virus signatures.
@fukusuket said he would look into this and make a prototype when he gets time.

@fukusuket
Copy link
Collaborator

fukusuket commented Aug 16, 2024

Prototype memo

Merge YAMLs and XOR

use std::fs::{self, File};
use std::io::{self, Read, Write};
use std::path::Path;
use yaml_rust::{YamlLoader, YamlEmitter};

fn list_yaml_files(dir: &Path) -> io::Result<Vec<String>> {
    let mut yaml_files = Vec::new();
    for entry in fs::read_dir(dir)? {
        let entry = entry?;
        let path = entry.path();
        if path.is_dir() {
            yaml_files.extend(list_yaml_files(&path)?);
        } else if path.extension().and_then(|s| s.to_str()) == Some("yml") {
            yaml_files.push(path.to_string_lossy().to_string());
        }
    }
    Ok(yaml_files)
}

fn merge_yaml_files(files: Vec<String>) -> Result<String, Box<dyn std::error::Error>> {
    let mut merged_yaml = Vec::new();
    for file in files {
        let mut content = String::new();
        File::open(&file)?.read_to_string(&mut content)?;
        let docs = YamlLoader::load_from_str(&content)?;
        merged_yaml.extend(docs);
    }
    let mut out_str = String::new();
    for (i, doc) in merged_yaml.iter().enumerate() {
        if i > 0 {
            out_str.push_str("\n"); // Add separator between documents
        }
        {
            let mut emitter = YamlEmitter::new(&mut out_str);
            emitter.dump(doc)?;
        }
    }
    Ok(out_str)
}

fn xor_encrypt(data: &str, key: u8) -> Vec<u8> {
    data.bytes().map(|b| b ^ key).collect()
}

fn xor_decrypt(data: &[u8], key: u8) -> Vec<u8> {
    data.iter().map(|&b| b ^ key ).collect()
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
   // encrypt
    let dir = Path::new("/Users/fukusuke/Hayabusa/hayabusa-2.16.0-mac-arm/rules");
    let yaml_files = list_yaml_files(dir)?;
    let merged_yaml = merge_yaml_files(yaml_files)?;
    let encrypted_yaml = xor_encrypt(&merged_yaml, 0xAA); // Example key: 0xAA
    let mut output_file = File::create("encrypted_output.yml")?;
    output_file.write_all(&encrypted_yaml)?;

    // decrypt
    let encrypted_file_path = Path::new("encrypted_output.yml");
    let mut encrypted_file = File::open(encrypted_file_path)?;
    let mut encrypted_content = Vec::new();
    encrypted_file.read_to_end(&mut encrypted_content)?;
    let decrypted_content = xor_decrypt(&encrypted_content, 0xAA); // Example key: 0xAA
    println!("Decrypted YAML content:\n{}", decrypted_content);

    Ok(())
}
[package]
name = "hayabusa-encrypted-rules"
version = "0.1.0"
edition = "2021"

[dependencies]
yaml-rust = "0.4.*"

hayabusa side

https://github.com/Yamato-Security/hayabusa/blob/main/src/yaml.rs#L148

    pub fn read_encrypted_file(path: &PathBuf) -> Result<String, String> {
        let mut fr = fs::File::open(path)
            .map(BufReader::new)
            .map_err(|e| e.to_string())?;
        let mut encrypted_content = Vec::new();
        let _ = fr.read_to_end(&mut encrypted_content);
        let decrypted_content =  encrypted_content.iter().map(|&b| b ^ 0xAA ).collect(); // Example key: 0xAA
        let decrypted_string = String::from_utf8(decrypted_content).expect("Invalid UTF-8 sequence");
        Ok(decrypted_string)
    }
   ...

Test Perspective

Test Result

current rule
Total detection rules: 4,218

Elapsed time: 00:00:28.983

Rule Parse Processing Time: 00:00:22.339
Analysis Processing Time: 00:00:06.272
Output Processing Time: 00:00:00.357

Events with hits / Total events: 19,764 / 47,476 (Data reduction: 27,712 events (58.37%))

Memory usage stats:
heap stats:     peak       total       freed     current        unit       count
  reserved:     2.0 GiB     2.0 GiB     0           2.0 GiB

encrypted and merged rule
Total detection rules: 4,222

Elapsed time: 00:00:07.1284

Rule Parse Processing Time: 00:00:01.591
Analysis Processing Time: 00:00:06.345
Output Processing Time: 00:00:00.327

Events with hits / Total events: 19,764 / 47,476 (Data reduction: 27,712 events (58.37%))

heap stats:     peak       total       freed     current        unit       count
  reserved:     2.0 GiB     2.0 GiB     0           2.0 GiB

encrypted rule's result

"2021-10-06 18:34:50.881 +09:00","Tamper Windows Defender - ScriptBlockLogging","high","win10-02.offsec.lan","PwSh",4104,1328816,"ScriptBlock: Set-MpPreference -DisableIOAVProtection $true","MessageNumber: 1 ¦ MessageTotal: 1 ¦ Path: ¦ ScriptBlockId: df8e876c-abd8-42f1-b7c6-e26e8f74c221"
"2021-10-06 18:34:51.010 +09:00","Tamper Windows Defender - ScriptBlockLogging","high","win10-02.offsec.lan","PwSh",4104,1328822,"ScriptBlock: Set-MpPreference -DisableBehaviorMonitoring $true","MessageNumber: 1 ¦ MessageTotal: 1 ¦ Path: ¦ ScriptBlockId: 1738dc77-dbb9-457a-ad3a-f03b03d63a42"
"2021-10-06 18:34:51.118 +09:00","Tamper Windows Defender - ScriptBlockLogging","high","win10-02.offsec.lan","PwSh",4104,1328828,"ScriptBlock: Set-MpPreference -DisableIntrusionPreventionSystem $true","MessageNumber: 1 ¦ MessageTotal: 1 ¦ Path: ¦ ScriptBlockId: 8e52c5f3-5b28-4e67-966c-e0a02af1f69c"
  • Windows Defender not detects (after fix) : OK(not detected by windows defender)
  • Performance: OK
    • Speed: OK(much faster)
    • Memory: OK
    • CPU: OK
    • Encrypted rule's file size: 6.36 MB

@hitenkoku hitenkoku removed their assignment Aug 16, 2024
@fukusuket
Copy link
Collaborator

fukusuket commented Aug 16, 2024

@YamatoSecurity @hitenkoku
As far as I have confirmed with the prototype,

  • Execution time has been reduced (the number of files has been reduced to one, so it does not take longer to load the file the first time)
  • Not detected by Windows Defender

Based on the above results, merge of all Yaml files into one file with XOR seems to be good method :)
(The one concern is that there is no guarantee that this file will not be detected by WindowsDefender in the future, but there is nothing we can do about that...)

@YamatoSecurity
Copy link
Collaborator Author

@fukusuket Oh great! thanks so much!

@fukusuket
Copy link
Collaborator

I will implement it so that XOR files are also uploaded to https://github.com/Yamato-Security/hayabusa-encrypted-rules !

@YamatoSecurity
Copy link
Collaborator Author

@fukusuket Thanks! I renamed the repository to https://github.com/Yamato-Security/hayabusa-encoded-rules since we are going to encode instead of encrypt them. Sorry for the trouble!

@fukusuket
Copy link
Collaborator

I've implemented GitHub Actions for XOR file auto commit!💪

@YamatoSecurity
Copy link
Collaborator Author

@fukusuket Super quick! Thanks so much!

@YamatoSecurity YamatoSecurity changed the title Support encrypted rules Support encoded rules to avoid AV false positives Aug 27, 2024
@hitenkoku
Copy link
Collaborator

@fukusuket I checked in https://github.com/Yamato-Security/hayabusa-encoded-rules/blob/main/rules.zip

occured error when xor processed bytes convert utf8 string.

yml file is not xor converted in rules.zip.

I am very sorry for taking so long and not being able to do this. Could you please confirm this data?

@fukusuket
Copy link
Collaborator

@hitenkoku
I see... I had checked the following code to make sure the zip file was readable, but it didn't work with this code, did it?🤔
#1369 (comment)

@fukusuket
Copy link
Collaborator

fukusuket commented Sep 5, 2024

I understand! Here is the file to read!(The file name is encoded_rules, not rules.zip)
https://github.com/Yamato-Security/hayabusa-encoded-rules/blob/main/encoded_rules

@hitenkoku
Copy link
Collaborator

@fukusuket Thanks for your quick reply.
I thought rules.zip was the encrypted file. My apologies.
I will check it.

@YamatoSecurity
Copy link
Collaborator Author

@hitenkoku Sorry the description in this issue is old and we changed our plans because it would be too slow to de-compress and decrypt the rules. Instead of compressing/decompressing and encryption/decryption, we are going to gather all of the YML rule information into one single file and XOR encode/decode it. So in the source code as well, please change the wording of encrypt -> encode, encryption -> encoding, decrypt -> decode, etc...

@hitenkoku
Copy link
Collaborator

@YamatoSecurity Thanks for your comment. The current version of hayabusa is based on the assumption that files are separated and rule counts are handled separately, so significant modifications are required.

@fukusuket
Copy link
Collaborator

fukusuket commented Sep 9, 2024

@hitenkoku @YamatoSecurity
I have tried it and it does not seem to affect the counting logic of rule as follows! The prototype has no changes except for the inclusion of the yaml XOR process. Please let me know if there are other concerns besides the rule count process..?🤔

main:

% ./hayabusa-main csv-timeline -d ../hayabusa-sample-evtx -w -o old.csv -q
Start time: 2024/09/09 21:53

Total event log files: 585
Total file size: 137.2 MB

Loading detection rules. Please wait.

Excluded rules: 20
Noisy rules: 12 (Disabled)

Deprecated rules: 216 (5.03%) (Disabled)
Experimental rules: 515 (11.99%)
Stable rules: 244 (5.68%)
Test rules: 3,537 (82.33%)
Unsupported rules: 45 (1.05%) (Disabled)

Hayabusa rules: 169
Sigma rules: 4,127
Total detection rules: 4,296

prototype:

% mv encoded_rules encoded_rules.yml
% ./hayabusa csv-timeline -d ../hayabusa-sample-evtx -w -o new.csv -q -r encoded_rules.yml
Start time: 2024/09/09 21:55

Total event log files: 585
Total file size: 137.2 MB

Loading detection rules. Please wait.

Excluded rules: 20
Noisy rules: 12 (Disabled)

Deprecated rules: 216 (5.02%) (Disabled)
Experimental rules: 517 (12.02%)
Stable rules: 244 (5.67%)
Test rules: 3,539 (82.30%)
Unsupported rules: 45 (1.05%) (Disabled)

Hayabusa rules: 169
Sigma rules: 4,131
Total detection rules: 4,300

The difference between the 4 rules is that the encoded_rule includes the yaml that Windows Defender detects

@hitenkoku hitenkoku removed their assignment Sep 17, 2024
@hitenkoku
Copy link
Collaborator

hitenkoku commented Sep 17, 2024

I apologize for the inconvenience.
I am truly sorry for commenting without having any idea what you are talking about!
I would prefer to code your prototype.

@YamatoSecurity
Copy link
Collaborator Author

@hitenkoku If it is ok with you, can I assign @fukusuket to this since he already made this prototype so might be easier this way?

@fukusuket
Copy link
Collaborator

@hitenkoku @YamatoSecurity
No problem at all! Thank you so much for checking it🙏 Yes, I will try to implement it. We will consult with you again if there are any further questions🙇

@fukusuket
Copy link
Collaborator

@YamatoSecurity
I have a question about the specification!

I think that many use cases will not use both rules and encoded_rules. If so, I don't think the -e option is needed for update-rules, If it is ok without the -e option, the implementation would be simpler :).

If you want to use encoded_rules, just use the zip included with encoded_rules from the release tag.

The internal logic of update-rules is that if there is encoded_rules, we update them. If not, update the rules folder as before. In addition, I think that the case where both rules and encoded_rules are placed will cause an error and will be used

what do you think?

@fukusuket
Copy link
Collaborator

fukusuket commented Sep 21, 2024

@YamatoSecurity
After careful consideration, it is difficult to notice this feature with the above specification.🤔
I will try to implement it with the first specification!

@fukusuket
Copy link
Collaborator

fukusuket commented Sep 22, 2024

@YamatoSecurity
One more point to confirm!
When using encoded_rules, the following restrictions.

  • -H
    • All URL links to detection results in HTML reports will be encoded_rules (thus, yml rules cannot be checked directly).
  • -p super-verbose
    • All values in the “RuleFile” column are encoded_rules

It could probably be tied to yml (only if there is a regular yml), but the implementation would probably be complex, so I would like to allow for the above constraints if possible🤔

what do you think?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment