Simply adds a new inbound or outbound firewall rule that filters traffic by allowing or blocking network packets that match the specified criteria via netsh advfirewall add rule
command. Applicable in case of blocking Internet access.
HOW it does:
nslookup
command first to get IP from specific domainMessageBox
may also be configured to alert all logged in users.RemoveRule
checkbox.WHY advfirewall?
netsh ipsec
and netsh firewall
contexts are provided for backwards-compatibility with Windows 2000/XP/2003 (Now they are all EOL).Netsh AdvFirewall
applies to: Windows 7, Windows Server 2008, Windows Server 2008 R2, Windows Vista.NOTE: Test carefully before running at scale in production environment
Inspired by Windows.Remediation.Quarantine
from Matt Green - @mgreen27 (use netsh IPsec)
name: Windows.Generic.Internet.BlockAccess
description: |
Simply adds a new inbound or outbound firewall rule that filters traffic by allowing or blocking network packets that match the specified criteria via `netsh advfirewall add rule` command. Applicable in case of blocking Internet access.
HOW it does:
- Use a configurable lookup table to generate additional entries.
- Using `nslookup` command first to get IP from specific domain
- An optional `MessageBox` may also be configured to alert all logged in users.
- The message will be truncated to 256 characters.
- After advfirewall rules application, connection back to the Velociraptor
frontend is tested and the rule removed if connection unavailable.
- To remove rule, select the `RemoveRule` checkbox.
- To update rule, simply rerun the artifact.
WHY advfirewall?
- The `netsh ipsec` and `netsh firewall` contexts are provided for backwards-compatibility with Windows 2000/XP/2003 (Now they are all **EOL**).
- `Netsh AdvFirewall` applies to: Windows 7, Windows Server 2008, Windows Server 2008 R2, Windows Vista.
- If you are new to advfirewall, please check reference link from MS first for more information.
NOTE: Test carefully before running at scale in production environment
Inspired by `Windows.Remediation.Quarantine` from Matt Green - @mgreen27 (use netsh IPsec)
author: TueDenn - @tuedenn
reference:
- https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-r2-and-2008/dd734783(v=ws.10)
- https://serverfault.com/questions/851922/blocking-ip-address-with-netsh-filter
- https://docs.velociraptor.app/artifact_references/pages/windows.remediation.quarantine/
required_permissions:
- EXECVE
precondition: SELECT OS From info() where OS = 'windows'
parameters:
- name: RuleName
default: "VeloBlockAccess"
- name: RuleLookupTable
type: csv
default: |
dir,remoteip,protocol,interface,action,enable,description
out,13.107.237.39,any,any,block,yes,block openai.com 1
out,13.107.238.39,any,any,block,yes,block openai.com 2
out,157.240.199.35,any,any,block,yes,block facbook.com
- name: MessageBox
description: |
Optional message box notification to send to logged in users. 256
character limit.
- name: RemoveRule
type: bool
description: Tickbox to remove advfirewall rule.
sources:
- query: |
// If a MessageBox configured truncate to 256 character limit
LET MessageBox <= parse_string_with_regex(
regex='^(?P<Message>.{0,255}).*',
string=MessageBox).Message
// extract configurable policy from lookuptable
LET configurable_rule <= SELECT
dir,remoteip,protocol,interface,action,enable,description
FROM RuleLookupTable
// Emit the message if no output is emitted, otherwise emit the output.
LET combine_results(Stdout, Stderr, ReturnCode, Message) = if(
condition=Stdout =~ "[^\\s]", then=Stdout,
else= if(condition=Stderr =~ "[^\\s]", then=Stderr,
else= if(condition= ReturnCode=0,
then=Message )))
// Removes empty options from the command line
LET clean_cmdline(CMD) = filter(list=CMD, regex='^(\\w+|\\w+=.+)$')
LET delete_cmdline = clean_cmdline(
CMD=('netsh','advfirewall','firewall','delete','rule', 'name=' + RuleName))
LET entry_cmdline(RuleName, dir,interface,action,remoteip,protocol,enable) = clean_cmdline(
CMD=('netsh','advfirewall','firewall','add','rule',
format(format='name=%s', args=RuleName),
format(format='dir=%s', args=dir),
format(format='interface=%s', args=interface),
format(format='action=%s', args=action),
format(format='remoteip=%s', args=remoteip),
format(format='protocol=%s', args=protocol),
format(format='enable=%s', args=enable)))
// delete old or unwanted policy
LET delete_rule = SELECT
timestamp(epoch=now()) as Time,
RuleName + ' firewall rule deleted.' AS Result
FROM execve(argv=delete_cmdline, length=10000)
// loop over configurable_rule to create advfirewall rule
LET create_rule = SELECT * FROM foreach(
row=configurable_rule,
query= {
SELECT
timestamp(epoch=now()) as Time,
combine_results(Stdout=Stdout, Stderr=Stderr,
ReturnCode=ReturnCode,
Message='Rule added: ' +
join(array=entry_cmdline(RuleName=RuleName,
dir=dir,
interface=interface,
action=action,
remoteip=remoteip,
protocol=protocol,
enable=enable), sep=" ")) AS Result
FROM execve(argv=entry_cmdline(RuleName=RuleName,
dir=dir,
interface=interface,
action=action,
remoteip=remoteip,
protocol=protocol,
enable=enable), length=10000)
})
// Parse a URL to get domain name.
LET get_domain(URL) = parse_string_with_regex(
string=URL, regex='^https?://(?P<Domain>[^:/]+)').Domain
// Parse a URL to get the port
LET get_port(URL) = if(condition= URL=~"https://[^:]+/", then="443",
else=if(condition= URL=~"http://[^:]+/", then="80",
else=parse_string_with_regex(string=URL,
regex='^https?://[^:/]+(:(?P<Port>[0-9]*))?/').Port))
// extract Velociraptor config to get domain and port information
LET extracted_config <= SELECT * FROM foreach(
row=config.server_urls,
query={
SELECT
get_domain(URL=_value) AS DstAddr,
get_port(URL=_value) AS DstPort,
'VelociraptorFrontEnd' AS Description,
_value AS URL
FROM scope()
})
// Check connection to Velociraptor frontend server
LET test_connection = SELECT * FROM foreach(
row={
SELECT * FROM extracted_config
WHERE Description = 'VelociraptorFrontEnd'
},
query={
SELECT *
Url,
response
FROM
http_client(url='https://' + DstAddr + ':' + DstPort + '/server.pem',
disable_ssl_security='TRUE')
WHERE Response = 200
LIMIT 1
})
// final check to keep or remove policy
LET final_check = SELECT * FROM if(condition= test_connection,
then={
SELECT
timestamp(epoch=now()) as Time,
if(condition=MessageBox,
then= RuleName + ' connection test successful. MessageBox sent.',
else= RuleName + ' connection test successful.'
) AS Result
FROM if(condition=MessageBox,
then= {
SELECT * FROM execve(argv=['msg','*',MessageBox])
},
else={
SELECT * FROM scope()
})
},
else={
SELECT
timestamp(epoch=now()) as Time,
RuleName + ' failed connection test. Removing advfirewall rule.' AS Result
FROM delete_rule
})
// Execute content
SELECT * FROM if(condition=RemoveRule,
then=delete_rule,
else={
SELECT * FROM chain(
a=delete_rule,
b=create_rule,
c=final_check)
})