<jupyter_start><jupyter_text>Attacking an ML classifier for malicious IDS trafficIn this part of the workshop we will generate adversarial samples to fool the classifiers from part 1There are many ways that an ML classifier can be manipulated. Model evasion attacks use adversarial samples, specially crafted samples which retain the original class in reality but are misclassified by the modelThere are many open source implemenations of adversarial attacks. Here we will use the [Adversarial Robustness Toolbox (ART)](https://github.com/Trusted-AI/adversarial-robustness-toolbox) which has the advantage of compatibility with multiple python machine learning libraries across many types of attack.<jupyter_code>from art.attacks.evasion import DecisionTreeAttack, HopSkipJump
from art.estimators.classification import SklearnClassifier
from art.estimators.classification.scikitlearn import ScikitlearnDecisionTreeClassifier

from models import Model
from utils import compare_data, parse_df_for_pcap_validity
import numpy as np<jupyter_output><empty_output><jupyter_text>White Box Attack First we will assume the adversary has full knowledge of the classifier and use the [Decision Tree Attack (Papernot, <NAME> 2016)](https://arxiv.org/abs/1605.07277) (on the decision tree models).<jupyter_code># Adversary has a pcap of 1 minute of Ping flood DDos that they have crafted 
# For the adversary: success = 0 packet detection but will settle for 90% getting through

attack_data_pcap = "datasets/AdversaryPingFlood.pcap"

# load up the stolen IDS classifier
model = Model(None, save_model_name="time_model_dt")

# check how well the model works at detecting the packets so far
print("Classification before adversarial evasion")
target_attack_x, target_attack_y, preds = model.test(attack_data_pcap, malicious=1, return_x_y_preds=True)
# get packets classified as malicious - these are the ones we want to manipulate
target_attack_x, target_attack_y = target_attack_x[np.where(preds == 1)], target_attack_y[np.where(preds == 1)]

# add ART wrapper to classifier
art_classifier = ScikitlearnDecisionTreeClassifier(model=model.get_classifier())

# create DecisionTreeAttack instance and pass ART classifier 
dt_attack = DecisionTreeAttack(classifier=art_classifier)

# generate adversarial samples
x_test_adv = dt_attack.generate(x=target_attack_x)
# Check new classification accuracy
print("Classification after adversarial evasion")
model.test((x_test_adv, np.ones(len(x_test_adv))), malicious=target_attack_x)
# Checking for packet validity: compare the differences between the packets
for i, (before, after) in enumerate(zip(target_attack_x, x_test_adv)):
    if i >= 3:
        break
    print("sample", i)
    compare_data(before, after, model.features)
### fix the "illegal" changes:
x_test_adv = parse_df_for_pcap_validity(x_test_adv, original_data=target_attack_x, columns=model.features)

# compare against original
for i, (before, after) in enumerate(zip(target_attack_x, x_test_adv)):
    if i >= 3:
        break
    print("\n sample", i)
    compare_data(before, after, model.features)

# test new classification accuracy on "fixed" adversarial samples
print("Classification after adversarial evasion + packet validation")
model.test((x_test_adv, np.ones(len(x_test_adv))), malicious=target_attack_x)<jupyter_output>sample 0
   IP__ttl
0     64.0
1     32.0
sample 1
   time_delta  IP__ttl
0    0.000515     64.0
1    0.000000     32.0
sample 2
   time_delta  IP__proto_1.0
0    0.049520          1.000
1    0.004405          0.499
Classification after adversarial evasion + packet validation
-----
Testing acc: 0.00, f1: 0.00, tpr: 0.00, tnr 0.00
[[   0    0]
 [1885    1]]
-----<jupyter_text>Black(ish) Box AttackNow we assume the attacker can only see the label coming out of the IDS, does not know the algorithm being used, the features being used or how they are represented (we actually do know a little how they are represented - hence black-ish). Here we use the [HopSkipJump Attack (Chen, Jordan, Wainwright)](https://arxiv.org/abs/1904.02144)<jupyter_code>model = Model(None, save_model_name="time_model_dt")

# review test accuracy
print("Original accuracy")
model.test(x_test_adv, malicious=target_attack_x)
# create ART wrapper for model
art_classifier = SklearnClassifier(model=model.get_classifier())

# Initiate HopSkipJump and 
attack = HopSkipJump(classifier=art_classifier)
x_test_adv = attack.generate(x=target_attack_x, y=np.zeros(len(target_attack_x)))

# check new classification accuracy
print("Classification after black-box adversarial evasion")
model.test((x_test_adv, np.ones(len(x_test_adv))), malicious=target_attack_x)
# compare against original
for i, (before, after) in enumerate(zip(target_attack_x, x_test_adv)):
    if i >= 3:
        break
    print("\n sample", i)
    compare_data(before, after, model.features)
### parse packets for illegal changes 
x_test_adv = parse_df_for_pcap_validity(x_test_adv, target_attack_x, columns=model.features)
    
# test new classification accuracy on "fixed" adversarial samples
print("Classification after adversarial evasion + packet validation")
model.test((x_test_adv, np.ones(len(x_test_adv))), malicious=target_attack_x)<jupyter_output>Classification after adversarial evasion + packet validation
-----
Testing acc: 0.00, f1: 0.00, tpr: 0.00, tnr 0.00
[[   0    0]
 [1886    0]]
-----<jupyter_text>Part 2 Exercises<jupyter_code># Try different decision tree models for the white box attack above 
# i.e. replace model name in the first section with one of these: 
decision_tree_models = ["time_model_dt", 
                        "all_except_src_dst_dt", 
                        "all_dt", 
                        "tcp_udp_modbus_icmp_boot_dt", 
                        "src_dst_features_dt", 
                        "IP_features_dt"]
# or use a model you trained in the previous section!
# Try the black-box attack with different models (any algorithm)
# Do the adversarial samples generated for one model also fool another (is there transferability)?
# Questions
# Does it always matter if the packets are valid?
# Which features are most commonly manipulated?
# Does changing the algorithm change which features are changed?
# Did you predictions from the previous section hold here?
# Which scenario do you think is more likely? 
### ----- end of part 1 ------<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.08093299937382592, 'fraction_numerical': 0.020976831559173452, 'mean_word_length': 4.808181818181819, 'pattern_counts': {'":': 0, '<': 16, '<?xml version=': 0, '>': 19, 'https://': 3, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '4', 'dir': 'jupyter-structured-clean-dedup', 'id': '406822', 'license': 'Apache-2.0', 'n_tokens_mistral': 2058, 'n_tokens_neox': 1860, 'n_words': 640, 'path': 'part2.ipynb', 'repo_name': 'mprhode/ICS_advml_workshop', 'size': '6402'}