Files

59 lines
3.2 KiB
Python
Raw Permalink Normal View History

import ctypes as C
import os
import json
import subprocess
import sys
import unittest
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / 'apps/network-broker'))
from windows_wfp_receiver import service_sddl, service_descriptor
from windows_wfp_install import NativeBackend
from windows_wfp_probe import Filter, Blob
class ReceiverTests(unittest.TestCase):
def test_service_sid_only_and_minimum_match_right(self):
self.assertEqual(service_sddl('S-1-5-80-1-2-3-4-5'), 'D:(A;;CC;;;S-1-5-80-1-2-3-4-5)')
for sid in ['S-1-5-19', 'S-1-5-80-01-2-3-4-5', 'S-1-5-80-4294967296-2-3-4-5']:
with self.assertRaises(Exception): service_sddl(sid)
@unittest.skipUnless(os.name == 'nt', 'Native Windows SD validation')
def test_actual_native_self_relative_sd_and_exact_ace_mask(self):
api = C.WinDLL('advapi32')
api.IsValidSecurityDescriptor.argtypes = [C.c_void_p]
api.IsValidSecurityDescriptor.restype = C.c_int
with service_descriptor('S-1-5-80-1-2-3-4-5') as blob:
self.assertTrue(api.IsValidSecurityDescriptor(blob.data))
raw = C.string_at(blob.data, blob.size)
self.assertTrue(int.from_bytes(raw[2:4], 'little') & 0x8000)
dacl = int.from_bytes(raw[16:20], 'little')
self.assertEqual(int.from_bytes(raw[dacl+4:dacl+6], 'little'), 1)
self.assertEqual(int.from_bytes(raw[dacl+12:dacl+16], 'little'), 1)
@unittest.skipUnless(os.name == 'nt', 'Native Windows SD marshalling')
def test_actual_sd_lifetime_and_uint64_soft_permit_marshalling_without_add(self):
backend = NativeBackend.__new__(NativeBackend)
backend.engine = C.c_void_p(1)
captured = []
def capture(name, _engine, pointer, _security, _id):
self.assertEqual(name, 'FwpmFilterAdd0')
value = C.cast(pointer, C.POINTER(Filter)).contents
self.assertEqual(value.flags, 1) # PERSISTENT only; no clear-action.
self.assertEqual(value.action.type, 0x1002)
self.assertEqual(value.weight.type, 4)
self.assertEqual(C.cast(value.weight.pointer, C.POINTER(C.c_uint64)).contents.value, 2)
self.assertEqual(value.count, 5)
condition = value.conditions[4]
self.assertEqual(condition.value.type, 14)
blob = C.cast(condition.value.pointer, C.POINTER(Blob)).contents
captured.append(C.string_at(blob.data, blob.size))
backend._call = capture
script = "const {planServiceReceiver}=require('./apps/network-broker/wfp-topology.cjs');console.log(JSON.stringify(planServiceReceiver({appId:Buffer.from(process.argv[1],'hex'),brokerPort:43120,serviceSid:'S-1-5-80-1-2-3-4-5'}).filters[0]));"
identity = '\\device\\harddiskvolume3\\safetynet\\node.exe\0'.encode('utf-16le').hex()
result = subprocess.run(['node','-e',script,identity],cwd=Path(__file__).resolve().parents[1],capture_output=True,text=True,check=True,timeout=10)
rule = json.loads(result.stdout)
backend.add_filter(rule)
rule['conditions'] = rule['conditions'][-1:]
with self.assertRaises(Exception): backend.add_filter(rule)
self.assertEqual(len(captured), 1)
if __name__ == '__main__': unittest.main()