Malware traffic

GuLoader to AgentTesla: passwords to an FTP drop in 12.5 seconds

Updated

File
2026-02-03-GuLoader-for-AgentTesla-style-infection-with-FTP-data-exfil.pcap
Format
pcap, ether
Size
288.74 KB
Packets
353
Duration
2 min 12 s
Captured (UTC)
2026-02-03 16:13:50
SHA-256
2fa7e8b80d9f0b460b98ed053fbfc9710ff21a4b689b16acb58e0cdc13bf9769

From the first DNS query to the second stolen file landing on a drop server, the GuLoader FTP exfiltration in this PCAP takes 12.5 seconds. The capture is a lab infection that malware-traffic-analysis.net published on 3 February 2026: a phishing e-mail titled "SHIPPING DOC || INVOICE NO. USF/23-26/072 IGR23110" carried inv. 5234353.rar, and the file inside it, named like a batch script but actually a 32-bit Windows executable, was GuLoader.

GuLoader is a downloader. It does not steal anything itself; it fetches an encrypted second stage, decrypts it in memory and hands over, here to what the publisher identifies as AgentTesla, a .NET credential stealer sold as a service for years. This build ships its loot over FTP with the password in clear text, which makes this one of the few malware captures where the attacker's own account sits in the packets.

FTP view of the GuLoader FTP exfiltration PCAP in A-Packets. The expanded FTP session shows the login to ftp.corwineagles.com and the STOR commands used to upload stolen data.
The expanded FTP session shows the login to ftp.corwineagles.com and the STOR commands used to upload stolen data.

GuLoader to AgentTesla in twelve seconds

The host is 10.2.3.101 behind a lab gateway at 10.2.3.1, which also answers its DNS. Each step of the infection starts with a lookup, so the DNS view doubles as a table of contents: four names, all answered, no failures. Laid next to the packet times, they give the following sequence.

GuLoader timeline: Google Drive download, hosting check, FTP login, then two completed uploads.
GuLoader timeline: Google Drive download, hosting check, FTP login, then two completed uploads.
Time (UTC)OffsetEvent
16:13:50.330.00 sDNS for drive.google.com, answer 142.250.115.138
16:13:50.450.11 sTLS Client Hello to drive.google.com
16:13:50.900.56 sTLS Client Hello to drive.usercontent.google.com (142.251.186.132), the 253 KB download
16:13:59.799.45 sGET ip-api.com/line/?fields=hosting, answer "false"
16:14:01.2510.92 sDNS for ftp.corwineagles.com, a CNAME to corwineagles.com at 162.241.123.75
16:14:01.8711.54 sFTP login accepted, 230
16:14:02.4812.15 sFirst upload complete, 754 bytes
16:14:02.8312.50 sSecond upload complete, 724 bytes

10.2.3.101 to 10.2.3.1, DNS, 4 names

drive.google.com, drive.usercontent.google.com, ftp.corwineagles.com, ip-api.com

Open the DNS view β†’

The capture runs on for another two minutes, but nothing new happens: the two TLS sessions to Google sit idle until the capture stops, which is why the file is 132 seconds long. The download finishes at 2.1 seconds, and the 7.3 seconds between that and the ip-api.com request belong to the host: GuLoader decrypting and starting the stealer, the stealer collecting. No packet covers that stretch, but the timestamp the stealer writes into its first file, 16:13:59, falls at its end, less than a second before the ip-api.com lookup.

To rebuild the same table in Wireshark, set the time display format to UTC date and time of day, then filter on dns.flags.response == 0 || ftp.request.command == "STOR" || http.request: every step of the chain shows up as one or two lines. The Ethernet view adds the setting: the host's network card is a Hewlett Packard part (00:08:02:1C:47:AE) and the gateway a Netgear router (20:E5:2A:B6:93:F1), the look of a small office rather than a typical sandbox.

The Google Drive download GuLoader hides behind TLS

GuLoader's operators host the encrypted payload on mainstream cloud storage because almost no organisation can block drive.google.com. The SSL/TLS view shows exactly two sessions, both TLS 1.2 with TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 and Google Trust Services certificates (issuer WE2). The first, to drive.google.com, returns about 7 KB, the redirect that points the client at the file. The second, to drive.usercontent.google.com, returns about 253 KB, the encrypted second stage. Both figures are connection bytes with protocol overhead included. The file identifier itself is inside TLS; the published infection notes give it as 1WsTpqstK9Luuk41e8fNVM9xO-QZwN1Ho.

Server nameServerVersion and cipherCertificate
drive.google.com142.250.115.138:443TLS 1.2TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256CN=*.google.com expiredissued by CN=WE2, O=Google Trust Services, C=USvalid 2026-01-12 to 2026-04-06
drive.usercontent.google.com142.251.186.132:443TLS 1.2TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256CN=*.usercontent.google.com expiredissued by CN=WE2, O=Google Trust Services, C=USvalid 2026-01-12 to 2026-04-06

Open the SSL/TLS view β†’

One property of those Client Hello messages stands out against normal browsing: neither offers ALPN. Browsers advertise h2 and http/1.1 in that extension, so a session to Google Drive without it points to a program built on a plain HTTP library, not a person clicking a link. Wireshark shows the field under the Client Hello's extensions, and the filter tls.handshake.type == 1 && !tls.handshake.extension.type == 16 lists Client Hello messages without it. Some legitimate agents omit ALPN too, so in a corporate capture pair that filter with the Drive server names: together they are a cheap way to find downloaders that borrow Google's reputation.

The bytes tell the rest. In the Connections view, 253 KB from 142.251.186.132 is 97 percent of everything the host received, and no further download follows. That fits how GuLoader works: it decrypts the blob in memory and injects the stealer into a legitimate process, so the next stage never crosses the network again.

FromToBytes
πŸ‡ΊπŸ‡Έ 142.251.186.13210.2.3.101253.45 KB
πŸ‡ΊπŸ‡Έ 142.250.115.13810.2.3.1017.02 KB
10.2.3.101πŸ‡ΊπŸ‡Έ 162.241.123.751.66 KB
πŸ‡ΊπŸ‡Έ 162.241.123.7510.2.3.101805 Bytes
10.2.3.101πŸ‡ΊπŸ‡Έ 142.251.186.132564 Bytes
10.2.3.101πŸ‡ΊπŸ‡Έ 142.250.115.138510 Bytes

4 more pairs in the interactive report.

Open the Connections view β†’

ip-api.com and the hosting check

Nine seconds later the stealer asks one question over plain HTTP: GET /line/?fields=hosting to ip-api.com. The line format returns bare values, one per line, and the hosting field is true when the caller's public address belongs to a hosting, colocation or data centre network. Sandboxes and analysis VMs often sit in such ranges, so the field works as a cheap sandbox check. Here the answer is six bytes, false and a newline, and the stealer carries on.

HostRequestStatusType
ip-api.comGET /line/?fields=hosting200 OKtext/plain 6 Bytes

Open the HTTP view β†’

The request has no User-Agent header at all, which is why the HTTP view shows no UA line for it. Most legitimate clients send one, so a header-less request for exactly this field is a dependable hunting string in proxy logs. MITRE ATT&CK files such checks under T1497, Virtualization/Sandbox Evasion: the malware probes its surroundings before it does anything worth watching.

Why plain HTTP, when everything else in the capture is encrypted? ip-api.com serves its free, keyless endpoint over HTTP only and reserves HTTPS for paying customers, and malware authors take the free option. The side effect is useful to defenders: the IP lookup is the single cleartext request this stealer makes, and it arrives seconds before the theft. Other samples contact different services; the SHub Stealer capture asks api.ipify.org over TLS instead, which is why its report has to lean on server names.

Reading the AgentTesla FTP exfiltration line by line

AgentTesla builds can send their loot by SMTP, FTP, HTTP or a Telegram bot; the operator picks one when the sample is configured, and this one was built for FTP. Each kind of stolen data becomes a separate file, so the two STOR commands here are two files, each on its own data connection with its own 226 reply. A host left infected for hours usually adds more uploads on a timer, keystroke logs or screenshots depending on the build, each in its own short FTP session to the same account.

The exfiltration starts at 11.27 seconds with the banner of a Pure-FTPd server and ends 1.2 seconds later. A-Packets rebuilds the control connection in full; only the password is masked on this page.

10.2.3.101:54049 to 162.241.123.75:21

220---------- Welcome to Pure-FTPd [privsep] [TLS] ----------
220-You are user number 1 of 150 allowed.
220-Local time is now 21:44. Server port: 21.
220-IPv6 connections are also welcome on this server.
220 You will be disconnected after 15 minutes of inactivity.
USER [email protected]
331 User [email protected] OK. Password required
PASS cβ€’β€’β€’β€’β€’β€’β€’β€’β€’β€’7
230 OK. Current restricted directory is /
OPTS utf8 on
504 Unknown command
PWD
257 "/" is your current location
TYPE I
200 TYPE is now 8-bit binary
PASV
227 Entering Passive Mode (162,241,123,75,183,189)
STOR PW_tyler-DESKTOP-W7F98GR_2026_02_03_16_13_59.html
150 Accepted data connection
226-File successfully transferred
226 0.090 seconds (measured here), 8.18 Kbytes per second
PASV
227 Entering Passive Mode (162,241,123,75,123,33)
STOR Contacts_Thunderbird.txt_tyler-DESKTOP-W7F98GR_2026_02_03_16_14_02.txt
150 Accepted data connection
226-File successfully transferred
226 0.084 seconds (measured here), 8.38 Kbytes per second

Open the FTP view β†’

The banner already contains two useful facts. [TLS] means the server would have accepted AUTH TLS; the client never asks for it, which is a choice of the malware author, not a limitation of the server. And Local time is now 21:44, sent when the capture clock reads 16:14 UTC, puts the server's clock at UTC+5:30, a property of the hosting server rather than of the operator. The client then sends OPTS utf8 on and ignores the 504 refusal, asks for the working directory, switches to binary with TYPE I and requests passive mode twice. The two 227 replies encode the data ports as the last two numbers, 183 Γ— 256 + 189 = 47037 and 123 Γ— 256 + 33 = 31521, which is why the Open Ports view lists 21, 31521 and 47037 for 162.241.123.75.

ProtocolClientServerLoginPassword
FTP10.2.3.101162.241.123.75:21[email protected]cβ€’β€’β€’β€’β€’β€’β€’β€’β€’β€’7 (12 chars)

Open the Credentials view β†’

The two STOR commands carry the stolen material. Their names follow AgentTesla's pattern: a prefix for the type of data, then the victim's user name, computer name and the collection time. PW_tyler-DESKTOP-W7F98GR_2026_02_03_16_13_59.html is 754 bytes of the stealer's HTML log, which opens with Time:, User Name:, Computer Name: and OSFullName: lines before the recovered credentials. Contacts_Thunderbird.txt_…_16_14_02.txt is 724 bytes: a plain list of addresses from the Thunderbird address book, the raw material for the next round of phishing from a trusted sender.

Frame 312 requests the password log and frame 321 confirms it at 12.146529 seconds; frames 330 and 338 do the same for the contacts at 12.497908 seconds. The commands ride TCP stream 3, while the files travel on the two passive data connections, so a filter on port 21 alone shows the theft without its content. A-Packets lists the commands and the server's 226 confirmations but does not carve the data connections. To read the files, follow the TCP streams to ports 47037 and 31521 in Wireshark, or print the first one with tshark -r file.pcap -qz follow,tcp,ascii,10.2.3.101:54050,162.241.123.75:47037, and handle the output like the credentials it contains.

What to block, rotate and report

The capture hands over a complete set of network indicators. ftp.corwineagles.com and its address 162.241.123.75 on TCP 21 are the drop. The receiving account, [email protected], lives on a shared hosting server, so it is either a compromised customer account or one the operator bought; either way the useful action is a report to the provider with the time of the session, rather than a lasting block of a shared hosting address. The header-less request to ip-api.com/line/?fields=hosting and outbound FTP from workstations are worth alerting on in general, since neither has a legitimate place on most desktops. From the original write-up come the file hashes: SHA-256 9fc244b6ba5c24fe50134870932f6dea852b8fa419ec7cdcf3d84eed70e0e331 for the RAR attachment and b7d239db797326e43a96fb228e93bbbfa1e12d610c8a79ba3148b74b0021ecb4 for the GuLoader executable inside it.

On the host, assume everything the stealer could read is gone: passwords saved in browsers and in the mail client, the Thunderbird contacts, and any session the user was logged in to. Rotate those accounts from a clean machine, warn the contacts that phishing may now arrive in the victim's name, and rebuild DESKTOP-W7F98GR rather than cleaning it. In ATT&CK terms the network side covers T1105, Ingress Tool Transfer, for the Drive download, T1497 for the hosting check and T1048.003, Exfiltration Over Unencrypted Non-C2 Protocol, for the FTP upload; the phishing attachment that started it is T1566.001.

The malware traffic analysis walkthrough sets this capture beside four other infections to build a triage order that holds for each of them. To do the same with an infection from your own network, upload the PCAP; captures from a live incident are better kept out of the public feed with a private plan, or analysed on your own servers with the self-hosted PCAP analyzer.

More sample reports