Apply a Sinkhole via Windows hosts file modification This content will modify the Windows hosts file by a configurable lookup table.
On application, the original configuration is backed up. When reapplying a sinkhole, the original configuration is restored then changes applied to maintain integrity of the restore process. If RestoreBackup is selected the artifact will restore the backup configuration, then delete the backup with no further processing.
NOTE: Modifying the hosts file may cause network communication issues. I have disabled any sinkhole settings on the Velociraptor agent configuration but there are no rail guards on other domains. Use with caution.
name: Windows.Remediation.Sinkhole
description: |
**Apply a Sinkhole via Windows hosts file modification**
This content will modify the Windows hosts file by a configurable
lookup table.
On application, the original configuration is backed up.
When reapplying a sinkhole, the original configuration is restored then
changes applied to maintain integrity of the restore process.
If RestoreBackup is selected the artifact will restore the backup
configuration, then delete the backup with no further processing.
NOTE:
Modifying the hosts file may cause network communication issues. I have
disabled any sinkhole settings on the Velociraptor agent configuration
but there are no rail guards on other domains. Use with caution.
author: Matt Green - @mgreen27
required_permissions:
- EXECVE
type: CLIENT
parameters:
- name: HostsFile
description: Path to hosts file
default: C:\Windows\System32\drivers\etc\hosts
- name: HostsFileBackup
description: Name to backup original hosts file. If reapplying the artifact this file is used as the base.
default: C:\Windows\System32\drivers\etc\hosts.velociraptor.backup
- name: CommentPrefix
description: Prefix to add to description in hosts file comments.
default: "Velociraptor sinkhole"
- name: RestoreBackup
description: "Restore hosts file backup"
type: bool
- name: SinkholeTable
description: Table of Domains to add to or modify in hosts file.
type: csv
default: |
Domain,Sinkhole,Description
evil.com,127.0.0.1,Evilcorp C2 domain
sources:
- precondition:
SELECT OS From info() where OS = 'windows'
query: |
-- Extract sink hole requirements from table
LET changes <= SELECT
Domain,
Sinkhole,
if(condition=Description,
then= CommentPrefix + ': ' + Description,
else= CommentPrefix) as Description
FROM SinkholeTable
-- Check for backup to determine if sinkhole applied
LET check_backup = SELECT OSPath FROM stat(filename=HostsFileBackup)
WHERE log(message="Found backup at " + OSPath)
-- Backup old config
LET backup = copy(filename=HostsFile,dest=HostsFileBackup)
-- Restore old config
LET restore = SELECT * FROM chain(
z=log(message="Will restore from backup"),
a=copy(filename=HostsFileBackup,dest=HostsFile),
b={
SELECT *
FROM if(condition=RestoreBackup,
then={
SELECT *
FROM execve(argv=['cmd.exe', '/c',
'del','/F',HostsFileBackup])
})
})
-- Write hosts file
LET write(DataBlob) = copy(filename=DataBlob,dest=HostsFile,accessor='data')
-- FlushDNS
LET flushdns = SELECT *
FROM execve(argv=['cmd.exe', '/c','ipconfig','/flushdns'])
-- Find existing entries to modify
LET existing <= SELECT
parse_string_with_regex(
string=Line,
regex=[
"^\\s+(?P<Resolution>[^\\s]+)\\s+" +
"(?P<Hostname>[^\\s]+)\\s*\\S*$"
]) as Record,
Line
FROM parse_lines(filename=HostsFile)
WHERE
Record AND Line
AND NOT Line =~ '^#'
-- Parse a URL to get domain name.
LET get_domain(URL) = parse_string_with_regex(
string=URL, regex='^https?://(?P<Domain>[^:/]+)').Domain
-- extract Velociraptor config for policy
LET extracted_config <= SELECT * FROM foreach(
row=config.server_urls,
query={
SELECT get_domain(URL=_value) AS Domain
FROM scope()
})
-- Set existing entries to sinkholed values
LET find_modline <= SELECT * FROM foreach(row=changes,
query={
SELECT
format(format='\t%v\t\t%v\t\t# %v',
args=[Sinkhole,Domain,Description]) as Line,
Domain,
'modification' as Type
FROM existing
WHERE
Record.Hostname = Domain
AND NOT Domain in extracted_config.Domain
GROUP BY Line
})
-- Add new hostsfile entries
LET find_newline <= SELECT * FROM foreach(row=changes,
query={
SELECT
format(format='\t%v\t\t%v\t\t# %v',
args=[Sinkhole,Domain,Description]) as Line,
Domain,
'new entry' as Type
FROM scope()
WHERE
NOT Domain in find_modline.Domain
AND NOT Domain in extracted_config.Domain
})
-- Determine which lines should stay the same
LET find_line <= SELECT
Line,
Record.Hostname as Domain,
'old entry' as Type
FROM existing
WHERE
NOT Domain in find_modline.Domain
AND NOT Domain in find_newline.Domain
-- Add all lines to staging object
LET build_lines <= SELECT Line FROM chain(
a=find_modline,
b=find_newline,
c=find_line
)
-- Join lines from staging object
LET HostsData = join(array=build_lines.Line,sep='\r\n')
-- Force start of backup or restore if applicable
LET backup_restore <= if(
condition= RestoreBackup AND log(message="Will attempt to restore backup"),
then= if(
condition= check_backup,
then= restore,
-- then= { SELECT * FROM restore },
else= log(message='Can not restore hosts file as backup does not exist.')),
else= if(
condition= check_backup,
then={
SELECT * FROM chain(
a= log(message='Backup hosts file already exists.'),
b= restore)
},
else= backup)
)
-- Do kick off logic
LET do_it <= SELECT * FROM if(condition= NOT RestoreBackup,
then= {
SELECT * FROM chain(
a= log(message='Adding hosts entries.'),
b= write(DataBlob=HostsData),
c= flushdns
)})
-- Finally show resultant HostsFile
SELECT * FROM Artifact.Windows.System.HostsFile(HostsFile=HostsFile)