SMB Create Remote File#

Hypothesis#

Adversaries might be creating a file remotely via the Server Message Block (SMB) Protocol.

Technical Context#

Client systems use the Common Internet File System (CIFS) Protocol to request file and print services from server systems over a network. CIFS is a stateful protocol, in which clients establish a session with a server and use that session to make a variety of requests to access files, printers, and inter-process communication (IPC) mechanisms, such as named pipes. The extended CIFS Protocol is known as the Server Message Block (SMB). The SMB2 CREATE Request packet is sent by a client to request either creation of or access to a file. In case of a named pipe or printer, the server MUST create a new file.

Offensive Tradecraft#

Adversaries leverage SMB to copy files over the network to either execute code remotely or exfiltrate data.

Pre-Recorded Security Datasets#

Metadata

Value

docs

https://securitydatasets.com/notebooks/atomic/windows/lateral_movement/SDWIN-200806015757.html

link

https://raw.githubusercontent.com/OTRF/Security-Datasets/master/datasets/atomic/windows/lateral_movement/host/covenant_copy_smb_CreateRequest.zip

Download Dataset#

import requests
from zipfile import ZipFile
from io import BytesIO

url = 'https://raw.githubusercontent.com/OTRF/Security-Datasets/master/datasets/atomic/windows/lateral_movement/host/covenant_copy_smb_CreateRequest.zip'
zipFileRequest = requests.get(url)
zipFile = ZipFile(BytesIO(zipFileRequest.content))
datasetJSONPath = zipFile.extract(zipFile.namelist()[0])

Read Dataset#

import pandas as pd
from pandas.io import json

df = json.read_json(path_or_buf=datasetJSONPath, lines=True)

Analytics#

A few initial ideas to explore your data and validate your detection logic:

Analytic I#

Look for non-system accounts SMB connecting (Tree Connect) to a file share that is not IPC$.

Data source

Event Provider

Relationship

Event

File

Microsoft-Windows-Security-Auditing

User accessed file share

5140

Logic#

SELECT `@timestamp`, Hostname, ShareName, SubjectUserName, SubjectLogonId,  AccessMask
FROM dataTable
WHERE LOWER(Channel) = 'security'
    AND (EventID = 5140)
    AND NOT ShareName LIKE '%IPC$'
    AND NOT SubjectUserName LIKE '%$'

Pandas Query#

(
df[['@timestamp','Hostname','ShareName','SubjectUserName','SubjectLogonId','AccessMask']]

[(df['Channel'].str.lower() == 'security')
    & (df['EventID'] == 5140)
    & (~df['ShareName'].str.contains('.*IPC.*', regex=True, na=True))
    & (~df['SubjectUserName'].str.endswith('$', na=False))
]
.head()
)

Analytic II#

Look for non-system accounts SMB connecting (Tree Connect) to an IPC$ Share and administrative shares (i.e C$) with the same logon session ID.

Data source

Event Provider

Relationship

Event

File

Microsoft-Windows-Security-Auditing

User accessed file share

5140

Logic#

SELECT `@timestamp`, Hostname, ShareName, SubjectUserName, b.SubjectLogonId, IpAddress, IpPort
FROM dataTable b
INNER JOIN (
    SELECT SubjectLogonId
    FROM dataTable
    WHERE LOWER(Channel) = "security"
        AND EventID = 5140
        AND ShareName LIKE '%IPC$'
        AND NOT SubjectUserName LIKE '%$'
    ) a
ON b.SubjectLogonId = a.SubjectLogonId
WHERE LOWER(b.Channel) = 'security'
    AND b.EventID = 5140
    AND b.ShareName LIKE '%C$'
    AND NOT SubjectUserName LIKE '%$'

Pandas Query#

IPCShareDf = (
df[['@timestamp','Hostname','ShareName','SubjectUserName','SubjectLogonId','AccessMask']]

[(df['Channel'].str.lower() == 'security')
    & (df['EventID'] == 5140)
    & (df['ShareName'].str.contains('.*IPC.*', regex=True))
    & (~df['SubjectUserName'].str.endswith('$', na=False))
]
)

CShareDf = (
df[['@timestamp','Hostname','ShareName','SubjectUserName','SubjectLogonId','AccessMask']]

[(df['Channel'].str.lower() == 'security')
    & (df['EventID'] == 5140)
    & (df['ShareName'].str.endswith('\\C$', na=False))
    & (~df['SubjectUserName'].str.endswith('$', na=False))
]
)

(
pd.merge(IPCShareDf, CShareDf,
    on = 'SubjectLogonId', how = 'inner')
)

Analytic III#

Look for non-system accounts SMB accessing a file with write (0x2) access mask via administrative share (i.e C$).

Data source

Event Provider

Relationship

Event

File

Microsoft-Windows-Security-Auditing

User accessed File

5145

Logic#

SELECT `@timestamp`, Hostname, ShareName, SubjectUserName, SubjectLogonId, IpAddress, IpPort, RelativeTargetName
FROM dataTable
WHERE LOWER(Channel) = "security"
    AND EventID = 5145
    AND ShareName LIKE '%C$'
    AND NOT SubjectUserName LIKE '%$'
    AND AccessMask = '0x2'

Pandas Query#

(
df[['@timestamp','Hostname','ShareName','SubjectUserName','SubjectLogonId','IpAddress','IpPort','RelativeTargetName']]

[(df['Channel'].str.lower() == 'security')
    & (df['EventID'] == 5145)
    & (df['AccessMask'] == '0x2')
    & (df['ShareName'].str.endswith('\\C$', na=False))
    & (~df['SubjectUserName'].str.endswith('$', na=False))
]
)

Analytic IV#

Look for non-system accounts SMB connecting (Tree Connect) to an IPC\( Share and administrative shares (i.e C\)) and accessing/creating a file with write (0x2) access mask with the same logon session ID.

Data source

Event Provider

Relationship

Event

File

Microsoft-Windows-Security-Auditing

User accessed file share

5140

File

Microsoft-Windows-Security-Auditing

User accessed File

5145

Logic#

SELECT `@timestamp`, Hostname, ShareName, SubjectUserName, d.SubjectLogonId, IpAddress, IpPort, RelativeTargetName
FROM dataTable d
INNER JOIN (
    SELECT b.SubjectLogonId
    FROM dataTable b
    INNER JOIN (
        SELECT SubjectLogonId
        FROM dataTable
        WHERE LOWER(Channel) = "security"
            AND EventID = 5140
            AND ShareName LIKE '%IPC$'
            AND NOT SubjectUserName LIKE '%$'
    ) a
    ON b.SubjectLogonId = a.SubjectLogonId
    WHERE LOWER(b.Channel) = 'security'
        AND b.EventID = 5140
        AND b.ShareName LIKE '%C$'
) c
ON d.SubjectLogonId = c.SubjectLogonId
WHERE LOWER(d.Channel) = 'security'
    AND d.EventID = 5145
    AND d.ShareName LIKE '%C$'
    AND d.AccessMask = '0x2'

Pandas Query#

IPCShareDf = (
df[['@timestamp','Hostname','ShareName','SubjectUserName','SubjectLogonId','AccessMask']]

[(df['Channel'].str.lower() == 'security')
    & (df['EventID'] == 5140)
    & (df['ShareName'].str.contains('.*IPC.*', regex=True))
    & (~df['SubjectUserName'].str.endswith('$', na=False))
]
)

CShareDf = (
df[['@timestamp','Hostname','ShareName','SubjectUserName','SubjectLogonId','AccessMask']]

[(df['Channel'].str.lower() == 'security')
    & (df['EventID'] == 5140)
    & (df['ShareName'].str.endswith('\\C$', na=False))
]
)


firstJoinDf = (
pd.merge(IPCShareDf, CShareDf,
    on = 'SubjectLogonId', how = 'inner')
)

fileAccessedDf = (
df[['@timestamp','Hostname','ShareName','SubjectUserName','SubjectLogonId','IpAddress','IpPort','RelativeTargetName']]

[(df['Channel'].str.lower() == 'security')
    & (df['EventID'] == 5145)
    & (df['AccessMask'] == '0x2')
    & (df['ShareName'].str.endswith('\\C$', na=False))
]
)

(
pd.merge(firstJoinDf, fileAccessedDf,
    on = 'SubjectLogonId', how = 'inner')
)

Analytic V#

Look for files that were accessed over the network with write (0x2) access mask via administrative shares (i.e C$) and that were created by the System process on the target system.

Data source

Event Provider

Relationship

Event

File

Microsoft-Windows-Security-Auditing

User accessed File

5145

File

Microsoft-Windows-Sysmon/Operational

Process created File

11

Logic#

SELECT `@timestamp`, Hostname, ShareName, SubjectUserName, SubjectLogonId, IpAddress, IpPort, RelativeTargetName
FROM dataTable b
INNER JOIN (
    SELECT LOWER(REVERSE(SPLIT(TargetFilename, '\'))[0]) as TargetFilename
    FROM dataTable
    WHERE Channel = 'Microsoft-Windows-Sysmon/Operational'
        AND Image = 'System'
        AND EventID = 11
) a
ON LOWER(REVERSE(SPLIT(RelativeTargetName, '\'))[0]) = a.TargetFilename
WHERE LOWER(b.Channel) = 'security'
    AND b.EventID = 5145
    AND b.AccessMask = '0x2'

Pandas Query#

fileAccessedDf = (
df[['@timestamp','Hostname','ShareName','SubjectUserName','SubjectLogonId','IpAddress','IpPort','RelativeTargetName']]

[(df['Channel'].str.lower() == 'security')
    & (df['EventID'] == 5145)
    & (df['AccessMask'] == '0x2')
]
)

fileAccessedDf['Filename'] = fileAccessedDf['RelativeTargetName'].str.split('\\').str[-1]

fileCreateDf = (
df[['@timestamp','Hostname','Image','TargetFilename']]

[(df['Channel'] == 'Microsoft-Windows-Sysmon/Operational')
    & (df['EventID'] == 11)
    & (df['Image'].str.lower() == 'system')
]
)

fileCreateDf['Filename'] = fileCreateDf['TargetFilename'].str.split('\\').str[-1]

(
pd.merge(fileAccessedDf, fileCreateDf,
    on = 'Filename', how = 'inner')
)

Known Bypasses#

False Positives#

Hunter Notes#

  • Baseline your environment to identify normal activity. Document all accounts creating files over the network via administrative shares.