Wireshark Introduction

 “Packets don't lie.” ― Laura Chappell

Wireshark Into Screen

Warning! Be sure to get the appropriate system administrator’s permission before using any of these tools! You have been advised!

Wireshark is a tool I’ve used for decades to debug network programs.  It used to be called Ethereal and you can learn all about it at Wikipedia. It is a packet analyzer which is a tool I first learned about in the 1990s when my company password was sniffed off an unencrypted Telnet session. Since then I have striven to always encrypt my communications with tools such as Secure Shell.

This was done on a Windows 11 machine with Wireshark version 4.2.3.

Avoid the temptation to be frustrated if you don’t get this all at once. I myself am still learning about computer network protocols!

First Steps

See: Setup and Build Instructions in the Wireshark online documentation.

After installation, the first screen of Wireshark should look something like this:

Wireshark First Screen

There may be more or less info on your screen depending on your network configuration. I will select the interface on my machine I wish to analyze. Your selection will depend on what network interface you wish to look at.

With no filter your screen should fill up fast if you are connected to the Internet! You should see something like this:

Wireshark Ethernet Frame Capture

Make sure to hit the red stop button so you can conserve your computer’s memory. Let’s analyze the traffic we’ve just captured. We’ll start with a source that I know to be my local IP address.

Traffic on an Ethernet line is divided into frames. The frame we are analyzing is shown below:

Sample Wireshark Ethernet Frame

Some details about this frame are:

1.    Ethernet II Header:

  • Source MAC address2c:16:db:a0:6a:41

  • Destination MAC Address: 58:60:d8:7e:f4:40

2.    IPv4 Header:

  • Source IP Address: 192.168.1.150

  • Destination IP Address: 67.222.250.2

  • Protocol: Transmission Control Protocol (TCP)

  • Total Length: 1500 bytes

  • 010. .... = Flags: 0x2, Don't fragment

  • Time to Live: 128

3.    TCP Segment:

This packet represents a TCP acknowledgment (ACK) from your local IP address (192.168.1.150) to the destination IP address (67.222.250.2) on port 4287. The sequence number indicates the relative position of this segment in the stream.

Another PDU (see: Understanding PDU at Every TCP/IP Layer: A Comprehensive Guide - Cyber Insight) relevant to this frame (because it is fragmented) is frame 13. Packet fragmentation is outside the scope of this article but you can learn more about it here IP fragmentation - Wikipedia.

Again, there is not time to get into the nitty gritty details of the frame or packet, but there are resources on the Internet you can study including my blog post on network sockets: https://www.keypuncher.net/blog/network-sockets

An Example Analysis:

Why don’t we stop drowning ourselves in traffic and implement some filtering? For that we are going to need some actual traffic to filter on.

Here keypuncher/C++/Networking/httpSocket/crossPlatform you can find my cross platform — Winsock for Windows or Berkeley sockets for Linux — library for setting up and tearing down a simple Hypertext Transfer Protocol (HTTP) socket. Code provided includes the socket code and the Makefile. The below sample Wireshark capture is included as file httpCapExamleDotCom.pcapng as well.

Put the following C++ code into your Integrated Development Environment (IDE) of choice:

#include <iostream>
#include <cstring> // for strlen

#ifdef _WIN32
    #include <winsock2.h>
    #pragma comment(lib,"ws2_32.lib") //Winsock Library
#else
    #include <sys/socket.h>
    #include <arpa/inet.h> //for inet_addr
    #include <unistd.h> // for close
#endif

#define MAX_BUFFER 1024

int main() {
    #ifdef _WIN32
        WSADATA wsa;
        SOCKET s;
    #else
        int s;
    #endif

    struct sockaddr_in server;
    const char *message;
    char server_reply[MAX_BUFFER];
    int recv_size;

    std::cout << "Initialising Socket...";
    #ifdef _WIN32
        if (WSAStartup(MAKEWORD(2,2),&wsa) != 0) {
            std::cout << "Failed. Error Code : " << WSAGetLastError();
            return 1;
        }
    #endif

    std::cout << "Initialised.\n";

    //Create a socket
    if((s = socket(AF_INET , SOCK_STREAM , 0 )) < 0) {
        std::cout << "Could not create socket";
        return 1;
    }

    std::cout << "Socket created.\n";

    server.sin_addr.s_addr = inet_addr("93.184.216.34"); // example.com's IP
    server.sin_family = AF_INET;
    server.sin_port = htons(80); // HTTP Port

    //Connect to remote server
    if (connect(s, (struct sockaddr *)&server, sizeof(server)) < 0) {
        std::cout << "connect error";
        return 1;
    }

    std::cout << "Connected\n";

    //Send some data
    message = "GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n";
    if (send(s, message, strlen(message), 0) < 0) {
        std::cout << "Send failed";
        return 1;
    }
    std::cout << "Data Send\n";

    //Receive a reply from the server
    while((recv_size = recv(s, server_reply, MAX_BUFFER-1, 0)) > 0) {
        server_reply[recv_size] = '\0';
        std::cout << server_reply;
    }

    if(recv_size < 0) {
        std::cout << "recv failed";
        return 1;
    }

    // Cleanup and close the connection
    #ifdef _WIN32
        closesocket(s);
        WSACleanup();
    #else
        close(s);
    #endif

    return 0;
}

Save the file as http-start.cpp or similar. Then build it with this Makefile (see GNU Make):

all:
	g++ http-start.cpp -o http-start -lws2_32
#For Linux builds remove "-lws2_32"

Now set up the Wireshark filter:

  • Open Wireshark

  • set capture filter to http.host == "example.com"

  • push the right-facing arrow near the top right

  • push the shark’s dorsal fin near the top left

  • build http_start.cpp with the Makefile:

cd <path to http code>
make

If building on Linux be sure to comment out or remove the -lws2_32!

  • Then run the program httpStart.exe (drop the .exe if on Linux) and you should get a single packet something like this:

Single HTTP packet from example.com

Double click on the packet and you will get all the juicy details about it. For simplicity, we will limit our analysis to the Application layer of the TCP/IP protocol suite. In this case that corresponds to the HTTP protocol. An overview of the chatter on the line for this particular packet as captured by Wireshark can be obtained by double clicking on the packet number on the capture screen. After expansion the packet looks something like this:

note that \r\n scattered throughout the line endings means “carriage return” and “line feed.” See: Does Windows carriage return \r\n consist of two characters or one character?

Here we can see an HTTP GET request. For other types of requests see here: HTTP Methods GET vs POST (w3schools.com) -- the most common one I’ve seen other than GET is POST. GET is used to request data from a web site, POST is for sending data to it.

The text we are interested in is as follows:

  • Request Method: GET: The method the client is using to request information from the server.

  • Request URI: /: The Uniform Resource Identifier, which specifies the resource the client wants. In this case, it’s the root directory of the server.

  • Request Version: HTTP 1.1: This is the version of HTTP protocol that the client is using to make the request.

  • Host: example.com: This is the domain name of the server that the client is trying to connect to.

  • Connection: close: This directive tells the server to close the connection after the response.

“Severity Level” might be used in a debugging logger local to example.com -- see: logging - When to use the different log levels.

I don’t know what “Group: Sequence” is. Microsoft co-pilot speculates it is:

  • Group: This term could refer to the team or department responsible for handling the incident or bug.

I am skeptical of this definition. Most likely it is just an unused HTTP field.

There is a reference to another frame as well, frame 85. For that we need to remove our filter to get an expanded view of the entire traffic capture of our full HTTP GET request. To do so, simply delete the text:

http.host == “example.com”

in the bar near the top and push enter. This will remove our filter but don’t despair! We now have a reference frame, 82. Scrolling down to that frame reveals something interesting on my screen, color coding for frames 79-89! This means that Wireshark has recognized these frames likely are all part of the same request. See below image:

Frames 79-81 are the TCP 3-Way Handshake.

Frame 82 was discussed above.

Frames 83-84 are not going to be discussed. In a nutshell they are setting up for the server responding to the HTTP GET request.

Frame 85 is the actual response to our request from example.com and an analysis will be done a little farther down the page.

And finally Frames 86-89 are not going to be discussed in detail but they are chatter between the server and client to close the connection.

Deep Dive on Server Response

Frame 85 is formatted as an HTTP response status code that looks like this in the Wireshark GUI:

A summary of the HTTP traffic follows.

  • HTTP/1.1: This is the version of HTTP that’s being used.

  • 200: This is the status code. A status code of 200 means OK, indicating that the request was successful.

  • OK: This is the reason phrase associated with the status code. For a status code of 200, the reason phrase is OK. Since this is a GET request, it contains the requested resource in the data Payload.

  • The Age field in an HTTP header indicates the time in seconds the object has been in a proxy cache. The Age header is usually included by proxies, not by origin servers.

    • In this case, Age: 101317 means that the object has been in the cache for 101,317 seconds. This is approximately 28.14 hours or about 1.17 days.

  • Cache-Control is an HTTP header used to specify browser caching policies in both client requests and server responses1. It holds directives (instructions) that control caching in browsers and shared caches (e.g., Proxies, CDNs). Here are some common directives that can be used in the Cache-Control header:

    • max-age: Specifies the maximum amount of time (in seconds) that a resource is considered fresh. After this time, the browser will contact the server to see if the resource has been updated.

    • s-maxage: Similar to max-age, but it applies to shared caches (e.g., CDN) and overrides max-age or Expires header.

    • no-cache: The cache must verify the status of the stale resources before using it and expired ones should not be used.

    • no-store: No caches can store the request or response. This directive is used for sensitive data.

    • must-revalidate: The cache must verify the status of the stale resources before using it.

    • public: The response may be stored by any cache, even if the response is normally non-cacheable or cacheable only within a private cache.

    • private: The response may be stored only by a browser’s cache, even if the response is normally non-cacheable.

  • The Content-Type header indicates that the returned content is HTML text in UTF-8 encoding.

  • Etag is an HTTP response header that provides a unique identifier for a specific version of a resource. It’s used to determine whether a resource has changed since the last time it was requested, which can help save bandwidth and improve efficiency. See: Etag.

    • In this case, Etag: "3147526947+gzip+ident" is the unique identifier for the specific version of the resource you requested. The server generates this tag, and it changes every time the resource does. If you were to request the same resource again, the server would compare the Etag in your request with the Etag for the current version of the resource. If they match, the server would return a 304 Not Modified status, indicating that your cached version of the resource is still valid.

    • The method by which Etag values are generated is not specified in the HTTP specification. Common methods include using a collision-resistant hash function of the resource’s content, a hash of the last modification timestamp, or even just a revision number.

  • Expires is an HTTP header that provides the date/time after which the response is considered stale. This header is used to control the caching of the resource by the client. See Expires.

    • In this case, Expires: Mon, 01 Apr 2024 14:09:11 GMT means the resource will be considered stale after Monday, April 1, 2024 at 14:09:11 GMT. After this time, the client (usually a web browser) should check back with the server to see if the resource has been updated.

    • Please note that if there is a Cache-Control header with the max-age or s-maxage directive in the response, the Expires header is ignored.

  • Last-Modified is an HTTP response header that provides the date and time at which the origin server believes the resource was last modified. It is used as a validator to determine if a resource received or stored is the same. Less accurate than an ETag header, it is essentially a fallback mechanism. See: Last-Modified

    • In your case, Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT means the resource was last modified on Thursday, October 17, 2019 at 07:18:26 GMT. If a request is made after this timestamp, the server will check if the resource has been modified. If it hasn’t, the server can return a 304 Not Modified status, indicating that the cached version of the resource is still valid

  • The Server HTTP response header provides information about the software used by the origin server to handle the request. This can include the name of the server software, and information about other technologies used by the server.

    • In your case, Server: ECS (agb/A437) indicates that the server software is ECS. This could possibly refer to the Amazon Elastic Container Service.

    • The (agb/A437) part could be an internal identifier used by the server, but without more context, it’s hard to say exactly what it represents.

  • Vary: Accept-Encoding is an HTTP response header that informs the client that the server’s response may be different based on the Accept-Encoding request header. See Vary: Accept-Encoding.

  • X-Cache: HIT is a non-standard HTTP response header that indicates the status of the requested resource in the cache. See: X-Cache.

    • HIT means that the requested resource was served from the cache, not directly from the origin server. This typically results in faster response times because the server doesn’t have to process the request and generate a full response.

    • This header is often added by Content Delivery Networks (CDNs) or caching proxies to indicate whether they were able to serve the requested resource from their cache.

  • Connection: close is an HTTP header that indicates the client or the server would like to close the network connection after the current transaction finishes. This is the default behavior in HTTP/1.0. See: Connection: close.

    • When a client sends a request with Connection: close, it’s signaling that it will close the connection after receiving the response. Similarly, if a server includes Connection: close in its response, it’s indicating that it will close the connection after sending the response.

    • In the code sent in our http socket, we explicitly asked the server to do this (see bolded text):

      message = "GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n"; 

  • The Content-Length header indicates that the length of the response body is 1256 bytes.

This concludes our traffic analysis via Wireshark (specifically HTTP traffic). Hope you enjoyed it!

Previous
Previous

VirtualBox Shared Folders

Next
Next

Git SSH Keys for Windows and WSL