HackBlue

Tools · Forensics tools · 23 / 25

Sysmon: Event ID 3 and Event ID 22

Event ID 3 is a connection opened by a process. Event ID 22 is a DNS query. Together they name a peer. They still do not contain the file that may have been transferred.

16 min read · practice only with authorization

Event ID 3 is the tuple and the process

A network event carries ProcessGuid, Image, User, Protocol, SourceIp, SourcePort, DestinationIp, DestinationPort, and whether the connection was initiated. Initiated true means this process started the connection. The destination fields are the peer. Port 443 and protocol tcp are the usual shape of an encrypted session, and the event still has no payload. You cannot read a workbook out of Event ID 3. You can say this process opened a TCP connection to that address and port at that UtcTime.

DestinationHostname is whatever name resolution Sysmon attached, and it may be empty. When it is empty, Event ID 22 is where the name may live, joined on ProcessGuid and on time. Do not invent a hostname from an address with a later public lookup unless the case actually includes that lookup and you label it as your lookup, not as a field in the event. In this lab the name drop.lab.example and the address 203.0.113.44 are already the pair the other exhibits use.

Event ID 22 is the question the resolver asked

DNS events include QueryName, QueryStatus, QueryResults, Image, and ProcessGuid. QueryResults is the answer the host received, when it was logged. A status that means failure is a query that did not produce a usable answer, and you should not treat the name as a connection. A success with an address that later appears in Event ID 3 is the join you want: same ProcessGuid, query, then connection, with UtcTime in order.

Many queries are background noise from the operating system and from browsers. Filter to the ProcessGuid you already identified before you read the list. A powershell GUID that queries drop.lab.example is relevant. The same host’s browser querying a vendor update name is a different process, and it can stay in the filtered-out pile with a one-line count so the reader knows you saw the volume.

Snippet
Event ID 22
UtcTime: 2026-04-15 13:17:06.102
ProcessGuid: {1b2c-4812}
QueryName: drop.lab.example
QueryResults: 203.0.113.44

Event ID 3
UtcTime: 2026-04-15 13:17:06.440
ProcessGuid: {1b2c-4812}
Protocol: tcp
Initiated: true
DestinationIp: 203.0.113.44
DestinationPort: 443

Order the rows, and keep the payload gap

Sort the GUID’s network and DNS rows by UtcTime. A query at 13:17:06.102 and a connection at 13:17:06.440 is a sequence. A connection with no query can still be an address that was already cached, so the missing Event ID 22 does not erase Event ID 3. A query with no connection means the name was looked up and this log shows no following connection from that GUID. Write the sequence you have.

The memory image’s TIME_WAIT row to the same address and port, owned by the exited powershell, points the same direction and was taken later. Cite it as agreement on the peer, with the snapshot time, not as a second independent copy of the payload. You still have not seen the bytes on the wire. If the question is whether the server received the workbook, this log does not finish it. It establishes that the process opened the connection.

Other GUIDs are context

After the GUID you care about is written up, glance at other Event ID 3 rows in the same few minutes so you do not miss a second process talking to the same address. If none exist, say you looked. If the endpoint agent opened connections to its own cloud, label them as the agent’s Image and leave them out of the payroll sentence. The Image field is how you tell those rows apart without guessing from the port.

Store a small extract of the two events in the case folder so the report can quote them without attaching the entire morning. The full CSV remains the source. The extract’s line numbers or event record IDs should be in the note so someone can find the rows again.

Worked case: one query, one connection, no body

Filtering to ProcessGuid {1b2c-4812}, you find Event ID 22 for drop.lab.example at 13:17:06.102 UTC with result 203.0.113.44, then Event ID 3 to 203.0.113.44 port 443, initiated, a third of a second later. Brooklyn times are 09:17:06. No other GUID in the surrounding two minutes uses that destination. The decoded command line does not itself contain the URL. The JSON from the XOR recipe does contain the host name. You cite all three as separate exhibits that agree on the name.

The finding sentence stops at the connection. “The process opened TCP 443 to 203.0.113.44 after resolving drop.lab.example. The log does not include the payload, so it does not by itself show the workbook arriving.” The TIME_WAIT memory row is a cross-reference, acquired at 09:22 Brooklyn.

Diagram

From a ProcessGuid to a peer, without a payload

  1. Filter

    Select Event ID 22 and Event ID 3 for the ProcessGuid from the process-create event.

  2. Name

    Read QueryName and QueryResults. A failed status is not an address you can reuse.

  3. Tuple

    Read protocol, initiated, destination address, and port. Quote UtcTime.

  4. Gap

    Say the payload is absent. Point at disk hashes and memory only for what those sources actually contain.

    Sequence
    09:17:06.102 Brooklyn  DNS  drop.lab.example -> 203.0.113.44
    09:17:06.440 Brooklyn  TCP  -> 203.0.113.44:443 initiated
    Payload: not in these events

Check yourself

1. Event ID 22 shows drop.lab.example resolved to 203.0.113.44, and Event ID 3 shows the same ProcessGuid connected to that address on port 443. What is still missing if counsel asks whether the server received the workbook?