Introduction

Sysmon is a well known tool provided by Microsoft frequently used in the fields of threat hunting, incident response and security monitoring. One of its best features is that it allows one to log any network connection issued by the processes running on the system. We will quickly review what information is provided in those events and what is the issue we have noticed. In order to overcome the issue we will present our work around which comes in a form of a new feature called event hooks introduced in the latest version of WHIDS.

The Issue

Before going further describing the issue, let's show what kind of information we can find in Sysmon Network Connection logs. The following example shows what is generated when I browsed to http://rawsec.lu from Edge on a test machine. Concerning the experimental setup, I ran all the following experiments on a Windows 10 VM with Sysmon version 7.01 installed on it.

{
  "Event": {
    "EventData": {
      "DestinationHostname": "pf-lb-2.online.net",
      "DestinationIp": "62.210.16.62",
      "DestinationIsIpv6": "false",
      "DestinationPort": "80",
      "DestinationPortName": "http",
      "Image": "C:\\Windows\\SystemApps\\Microsoft.MicrosoftEdge_8wekyb3d8bbwe\\MicrosoftEdgeCP.exe",
      "Initiated": "true",
      "ProcessGuid": "{B2796A13-61E0-5B27-0000-00108D544202}",
      "ProcessId": "5196",
      "Protocol": "tcp",
      "SourceHostname": "DESKTOP-5SUA567.lan",
      "SourceIp": "10.0.2.15",
      "SourceIsIpv6": "false",
      "SourcePort": "51262",
      "SourcePortName": "",
      "User": "DESKTOP-5SUA567\\Gen Eric",
      "UtcTime": "2018-06-18 05:22:53.759"
    },
    "System": {
      "..." : "..."
    }
  }
}

Maybe you see the issue already, the destination hostname is absolutely not what we expected. I do not know exactly how the DestinationHostname field is set in the Sysmon internals but I can assume with a high level of confidence that it is using reverse DNS lookup (you can see what happens when we do a reverse DNS lookup for that IP).

> host 62.210.16.62
62.16.210.62.in-addr.arpa domain name pointer pf-lb-2.online.net.

If you have spent some time analyzing your Sysmon Network Connection logs, probably you have also noticed events like this.

{
  "Event": {
    "EventData": {
      "DestinationHostname": "",
      "DestinationIp": "13.74.179.117",
      "DestinationIsIpv6": "false",
      "DestinationPort": "443",
      "DestinationPortName": "https",
      "Image": "C:\\Windows\\System32\\svchost.exe",
      "Initiated": "true",
      "ProcessGuid": "{B2796A13-A339-5B00-0000-001040000100}",
      "ProcessId": "1044",
      "Protocol": "tcp",
      "SourceHostname": "DESKTOP-5SUA567.lan",
      "SourceIp": "10.0.2.15",
      "SourceIsIpv6": "false",
      "SourcePort": "52234",
      "SourcePortName": "",
      "User": "NT AUTHORITY\\SYSTEM",
      "UtcTime": "2018-06-17 13:34:06.418"
    },
    "System" : {
      "...": "..."
    }
  }
}

Great! It seems it can be worst than our previous example, the DestinationHostname is empty. Now we have two hypothesis for this to happen, either it is a direct network connection (there is no DNS resolution) or the reversed domain name for this IP address is not found.

> host 13.74.179.117
Host 117.179.74.13.in-addr.arpa. not found: 3(NXDOMAIN)

This previous command just reject our second hypothesis but it does not tell us whether it was a direct network connection or not. Personally, I am convinced it is not a direct network connection because this is a Microsoft IP address and it would be quite a mistake from them to use hardcoded IP addresses. So, let's verify our assumption by enabling the Microsoft-Windows-DNS-Client logs on the host and search for any DNS resolution returning this IP. Bingo !

{
  "Event": {
    "EventData": {
      "InterfaceIndex": "0",
      "NetworkIndex": "0",
      "QueryName": "sls.update.microsoft.com",
      "QueryResults": "type:  5 sls.update.microsoft.com.nsatc.net;13.74.179.117;",
      "QueryType": "1",
      "Status": "0"
    },
    "System": {
      "...": "...",
      "TimeCreated": {
        "SystemTime": "2018-06-17T13:34:05.350869400Z"
      },
    }
  }
}

So, there was indeed a network resolution returning this IP address prior to the network connection. So, why does Sysmon do not show any valid DestinationHostname for this network connection? Because it is now confirmed that it is using reverse DNS lookup to get the destination hostname, and as we have shown above no domain exists for this IP in reverse DNS lookup.

As a Sysmon user, this is probably not a behaviour you want to because you know that reverse DNS is inaccurate and likely hundreds of IP addresses would be resolved to point on the same generic hostname. In conclusion (and this is my opinion), it is very hard to build accurate detection rules based on those Sysmon events. This is only useful to built detection scenario based on IP addresses, which is quite limited and might generate a high number of false positives.

Our Response

In order to solve this problem, we have added a new feature to the latest version of Windows Host IDS (a.k.a WHIDS). The idea behind this new feature is quite simple, we want to be able to make some kind of host based correlation in order to grab the domain name resolution and modify the Sysmon event. To do so, we have introduced the concept of event hooks. So what a hook is? It is a lightweight function (defined programmatically in WHIDS) which applies on Windows events going through it. The hook might just pick information from some events and only poke to other ones. This is actually exactly what we want to make viable solution, pick data from local DNS logs and poke what we have extracted in the Sysmon network connection events. Hereafter is the implementation of both hooks; as you can see it is quite straightforward. You can have a deeper look at the source code if you want to implement your own hooks.

// hooks Windows DNS client logs and maintain a domain name resolution table
// e is a pointer to a Windows Event
func hookDNS(e *evtx.GoEvtxMap) {
    if qtype, err := e.GetInt(&dnsQueryType); err == nil {
        // request for A or AAAA records
        if qtype == 1 || qtype == 28 {
      // qresults is what is in QueryResults field
            if qresults, err := e.GetString(&dnsQueryResults); err == nil {
                if qresults != "" {
                    records := strings.Split(qresults, ";")
          // for any result
                    for _, r := range records {
                        // check if it is a valid IP
                        if net.ParseIP(r) != nil {
              // dnsResolution is a hash table where map[IP] = domain
              // we get what is in QueryValue field and we store it into
              // our resolution table
                            dnsResolution[r] = e.GetStringStrict(&dnsQueryValue)
                        }
                    }
                }
            }
        }
    }
}

// hook which replaces the DestinationHostname of Sysmon Network connection
// event with the one previously found in the DNS logs
func hookNetConn(e *evtx.GoEvtxMap) {
    if ip, err := e.GetString(&sysmonDestIP); err == nil {
        if dom, ok := dnsResolution[ip]; ok {
            e.Set(&sysmonDestHostname, dom)
        }
    }
}

This implemented, we can now see what is the result of this modification. Our experiment is exactly the same as the one described at the beginning of this article (i.e. visiting http://rawsec.lu with Edge) and voilà, we have what we wanted.

{
  "Event": {
    "EventData": {
      "DestinationHostname": "rawsec.lu",
      "DestinationIp": "62.210.16.62",
      "DestinationIsIpv6": "false",
      "DestinationPort": "80",
      "DestinationPortName": "http",
      "Image": "C:\\Windows\\SystemApps\\Microsoft.MicrosoftEdge_8wekyb3d8bbwe\\MicrosoftEdgeCP.exe",
      "Initiated": "true",
      "ProcessGuid": "{B2796A13-6059-5B27-0000-0010954D3A02}",
      "ProcessId": "5784",
      "Protocol": "tcp",
      "SourceHostname": "DESKTOP-5SUA567.lan",
      "SourceIp": "10.0.2.15",
      "SourceIsIpv6": "false",
      "SourcePort": "51224",
      "SourcePortName": "",
      "User": "DESKTOP-5SUA567\\Gen Eric",
      "UtcTime": "2018-06-18 05:20:38.857"
    },
    "System": {
      "...": "..."
    }
  }
}

It is worth noting that the hooks applies before going into Gene (the detection engine behind WHIDS) so we can now design better detection rules based on the real hostnames.

Discussions

It is important to note that those experiments and this trick have been validated with direct connection to the Web (i.e. no non-transparent proxy). It is very likely it would not work with a non-transparent proxy since the DestinationIP (field we use for correlation) would be the one of the proxy.

The new concept of hook offers quite interesting perspective and can be used to enrich the Sysmon logs. We can imagine whatever hook we want as long as it is fast to run (not to block the engine). For instance, we have also implemented a hook which sets a new field in Sysmon events 1, 6 and 7 containing the file size of the PE images. To conclude, hooks is a generic way to give you full control over your logs which can be used to enrich Windows events and build better detection rules.