Spending spring days crafting packets at NahamCon 2022
f0rked
Posted on May 30, 2022
A CTF writeup of Networking challenges at NahamCon 2022
NahamCon2022 is over and we're glad we managed to finish in top 5% with our team at Stack Labs (3049 points, 195 on 4034 teams). This year, they came up with exciting Networking challenges made by @Kkevsterrr#7469. Although we didn't manage to solve these, it was a nice introduction to network analysis and packets manipulation using Scapy.
Here's what I learned.
Challenges:
- 1. Contemporaneous Open - hard - 14 solves - 500 points - first blooded by StaticFlow
- 2. Freaky Flag Day - hard - 9 solves - 500 points - first blooded by Maple Bacon
1. Contemporaneous Open
Author: @Kkevsterrr#7469
We want to give you the flag, we really do. just give us a TCP HTTP server to send it to, and we'll make a POST request with all the deets you need! we've just got a firewall issue on our side and we're dropping certain important packets (specifically, any inbound SYN+ACK packet is dropped). Shouldn't be a problem for a networking pro like you, though - just make a TCP server that doesn't need to send those!
Tools used:
Traditional 3-way handshake
Let's start with some useful reminders about TCP Protocol. In a traditional TCP 3-way handshake:
- the client sends a SYN (Synchronize Sequence Number) to inform the server he wants to start a communication. The SYN signifies with what sequence number it will start the segments with.
- the server responds to the client with SYN-ACK. The ACK signifies the response of client's SYN. Meanwhile the SYN signifies with what sequence number it will start the segments with.
- Finally, the client acknowledges (ACK) the response of the server and the connection enters the ESTABLISHED state so they can start exchanging data.
SYN-ACK get dropped by a distrustful firewall
In this challenge the flag is given by a POST request to a server we're supposed to create at port 80. The thing is: the client's firewall drops every inbound SYN-ACK packet. So we must find a solution to establish a connection without having to send a SYN-ACK-flagged packet.
While I was spending hours refreshing my memory about TCP/IP internals, learning the basics of scapy and exploring many ways to solve the problem (fragmenting the SYN/ACK response, attempting an HTTP3 over QUIC conection), the solution was laying in the challenge's name.
TCP Simultaneous Open
Contemporaneous Open is a reference to TCP's Simultaneous Open state transition. Also called "simultaneous active open on both side", it refers to an old TCP feature used to handle edge cases in TCP handshakes, as when a server and a client send a SYN to each other at the same time. This process makes it possible for two applications to send a SYN to each other to start a TCP connection.
When both ends send a SYN at the same time, both ends enter the SYN_SENT state. When they receive the SYN, their state changes to SYN_RCVD and they resend the SYN and acknowledge the received SYN. When they both receive the SYN and the acknowledged SYN, the connection enters the ESTABLISHED state. In such a state, both ends act as a client and server.
So the client doesn't need a SYN/ACK answer from the server in order to complete the three-way handshake. All we need is to send a SYN and wait for the client's SYN/ACK to establish the connection and start HTTP exchange. This can save us from sending a SYN/ACK packet that would be dropped by the client. We'll use Scapy to mimic a server with such a behavior.
Crafting with scapy
Before executing any Scapy scripts, we must disable the Linux Kernel's response to avoid any RST-flagged answers. Scapy operates in user space so the Kernel has no idea of what Scapy is doing.
Using iptables, we can drop RST-flagged packets the kernel sends from port 80.
sudo iptables -A OUTPUT -p tcp --tcp-flags RST RST --sport 80 -j DROP
The idea is to create a customized server that does the following:
- receive client's SYN (seq=n)
- send a SYN (seq=m)
- send a ACK (seq=m+1, ack=n+1) to acknowledge client's SYN
- client acknowledges our SYN, receives our ACK and establish session
We'll use tshark as a complementary tool to track the incoming packets.
1. First, let's get client's SYN packet.
Note that IP addresses have been changed to "MY_IP" and "CLIENT_IP".
# server.py
#! /usr/bin/python
from scapy import *
S_ADDR = "MY_IP"
S_PORT = 80
# 1. Listen for client's SYN and get IP and port
c_syn = sniff(
filter="tcp and port 80",
count=1,
prn=lambda x:x.sprintf("Received SYN from {IP:%IP.src%:%TCP.dport%, seq=%TCP.seq}%")
)
We connect to the challenge:
❯ nc challenge.nahamcon.com 31334
so glad you're here! i would love to give you the flag. just give me the IP address that's running an HTTP server, and I'll shoot you the flag immediately.
oh one snag, we've got some firewall issues on our side, and some important packets are getting dropped. shouldn't be a problem for you, though.
>>> MY_IP
here it comes!
hmm nope looks like you didn't get it...
# server.py output
Received SYN from CLIENT_IP:http, seq=510141201
❯ sudo tshark -f "tcp port 80"
Running as user "root" and group "root". This could be dangerous.
Capturing on 'ens3'
1 0.000000000 CLIENT_IP → MY_IP TCP 74 58356 → 80 [SYN] Seq=0 Win=42600 Len=0 MSS=1420 SACK_PERM=1 TSval=3977333110 TSecr=0 WS=128
2 1.015633580 CLIENT_IP → MY_IP TCP 74 [TCP Retransmission] 58356 → 80 [SYN] Seq=0 Win=42600 Len=0 MSS=1420 SACK_PERM=1 TSval=3977334125 TSecr=0 WS=128
Great! We now can use the IP and port for sending our packets.
2. Now let's send our SYN and acknowledge client's SYN
# server.py
# ...
# 2. Send Syn
C_ADDR = c_syn[0][IP].src
C_PORT = c_syn[0].sport
C_SEQ = c_syn[0].seq
S_SEQ = 1234 # random number
ip = IP(src=S_ADDR, dst=C_ADDR)
tcp_syn = TCP(
sport=S_PORT,
dport=C_PORT,
flags="S",
seq=S_SEQ,
)
s_syn = send(ip/tcp_syn)
print(f"Send SYN with seq={S_SEQ}")
# 3. Send Ack
S_SEQ+=1
C_SEQ+=1
tcp_ack = TCP(
sport=S_PORT,
dport=C_PORT,
flags="A",
seq=S_SEQ,
ack=C_SEQ,
)
s_ack = send(ip/tcp_ack)
print(f"Send ACK with seq={S_SEQ} and ack={C_SEQ}")
Received SYN from CLIENT_IP:http, seq=3800804531
Send SYN with seq=1234
Send ACK with seq=1235 and ack=3800804532
We'll use the flag -z "follow,tcp,hex,0"
to display the contents of the first TCP Stream (CLIENT_IP → MY_IP)
❯ sudo tshark -f "tcp port 80" -z "follow,tcp,hex,0"
Running as user "root" and group "root". This could be dangerous.
Capturing on 'ens3'
1 0.000000000 CLIENT_IP → MY_IP TCP 74 34206 → 80 [SYN] Seq=0 Win=42600 Len=0 MSS=1420 SACK_PERM=1 TSval=3979143134 TSecr=0 WS=128
2 0.009865804 MY_IP → CLIENT_IP TCP 54 80 → 34206 [SYN] Seq=0 Win=8192 Len=0
3 0.012471996 MY_IP → CLIENT_IP TCP 54 80 → 34206 [ACK] Seq=1 Ack=1 Win=8192 Len=0
4 0.114386572 CLIENT_IP → MY_IP TCP 74 [TCP Retransmission] 34206 → 80 [SYN, ACK] Seq=0 Ack=1 Win=42600 Len=0 MSS=1420 SACK_PERM=1 TSval=3979143248 TSecr=0 WS=128
5 0.115899112 CLIENT_IP → MY_IP TCP 268 POST / HTTP/1.1 [TCP segment of a reassembled PDU]
6 0.115899266 CLIENT_IP → MY_IP HTTP 104 POST / HTTP/1.1 (application/x-www-form-urlencoded)
7 0.319132750 CLIENT_IP → MY_IP TCP 318 [TCP Retransmission] 34206 → 80 [PSH, ACK] Seq=1 Ack=1 Win=333 Len=264
8 0.727116985 CLIENT_IP → MY_IP TCP 318 [TCP Retransmission] 34206 → 80 [PSH, ACK] Seq=1 Ack=1 Win=333 Len=264
9 1.551128826 CLIENT_IP → MY_IP TCP 318 [TCP Retransmission] 34206 → 80 [PSH, ACK] Seq=1 Ack=1 Win=333 Len=264
10 3.119495767 CLIENT_IP → MY_IP TCP 54 34206 → 80 [FIN, ACK] Seq=265 Ack=1 Win=333 Len=0
11 3.215170188 CLIENT_IP → MY_IP TCP 318 [TCP Retransmission] 34206 → 80 [FIN, PSH, ACK] Seq=1 Ack=1 Win=333 Len=264
^C11 packets captured
===================================================================
Follow: tcp,hex
Filter: tcp.stream eq 0
Node 0: CLIENT_IP:34206
Node 1: MY_IP:80
00000000 50 4f 53 54 20 2f 20 48 54 54 50 2f 31 2e 31 0d POST / H TTP/1.1.
00000010 0a 48 6f 73 74 3a 20 ■ ■ ■ ■ ■ ■ ■ ■ ■ .Host: ■ ■■■■■■■■
00000020 ■ ■ ■ ■ 0d 0a 55 73 65 72 2d 41 67 65 6e 74 ■■■■..Us er-Agent
00000030 3a 20 70 79 74 68 6f 6e 2d 72 65 71 75 65 73 74 : python -request
00000040 73 2f 32 2e 32 37 2e 31 0d 0a 41 63 63 65 70 74 s/2.27.1 ..Accept
00000050 2d 45 6e 63 6f 64 69 6e 67 3a 20 67 7a 69 70 2c -Encodin g: gzip,
00000060 20 64 65 66 6c 61 74 65 0d 0a 41 63 63 65 70 74 deflate ..Accept
00000070 3a 20 2a 2f 2a 0d 0a 43 6f 6e 6e 65 63 74 69 6f : */*..C onnectio
00000080 6e 3a 20 6b 65 65 70 2d 61 6c 69 76 65 0d 0a 43 n: keep- alive..C
00000090 6f 6e 74 65 6e 74 2d 4c 65 6e 67 74 68 3a 20 35 ontent-L ength: 5
000000A0 30 0d 0a 43 6f 6e 74 65 6e 74 2d 54 79 70 65 3a 0..Conte nt-Type:
000000B0 20 61 70 70 6c 69 63 61 74 69 6f 6e 2f 78 2d 77 applica tion/x-w
000000C0 77 77 2d 66 6f 72 6d 2d 75 72 6c 65 6e 63 6f 64 ww-form- urlencod
000000D0 65 64 0d 0a 0d 0a ed....
000000D6 66 6c 61 67 3d 66 6c 61 67 25 37 42 36 61 63 66 flag=fla g%7B6acf
000000E6 64 66 63 39 33 36 39 65 61 64 66 64 62 39 34 33 dfc9369e adfdb943
000000F6 39 62 30 61 63 33 39 36 39 37 31 31 25 37 44 25 9b0ac396 9711%7D%
00000106 30 41 0A
===================================================================
And so we get this lovely flag:
flag{6acfdfc9369eadfdb9439b0ac3969711}
Improvements
A much more elegant solution would be to act like a real HTTP server by acquitting each client's packet, answering the POST request and then gracefully ending the connection when the client sends a FIN.
Check out nneonneo's solution that implements this feature in addition to using an asynchronous sniffer that pushes incoming packets to a queue, making client's packets easier to iterate on. Also he uses many helper functions to track, filter and incoming and outcoming packets. I would definitely use these as a template for next challenges. Clean and smooth.
In the next part, we'll cover the Freaky Flag Day challenge. I hope you enjoy poetry and TCP flags.
2. Freaky Flag Day
Author: @Kkevsterrr#7469
Our TCP flags have decided that they'd like to change places today; all you need to do is reach the HTTP server!
Roses are red, and SYNs are FINs too.
RST+ACKs are now SYN+ACKs for you.
ACKs are now Es, and what else have we done?
PSH+ACKs are FIN+SYNs just for the fun.
Hint: If you want to run this challenge from your home or a VM, make sure you are not behind a NAT that could eat your unexpected packets.
Interact with this challenge at: http://SERVER_IP
Tools used:
- scapy for packet manipulation
- tshark wireshark's cli version
- curl for the http client
- nfqueue to intercept packets queued by the kernel packet filter
So after defeating a suspicious client that drops every incoming SYN/ACK packet, our next challenger a server that swaps the flags of every request (both inbound and outbound).
Want to establish a session? The server understands that you want to finish it.
Want to acknowledge that a packet is successfully received? The server understands that you're under a network congestion. Nonsense.
The goal is to reach the server correctly. Thus we must speak his language. The flags mapping is the following:
S ⇔ F
RA ⇔ SA
A ⇔ E
PA ⇔ FS
Preliminary tests
Let's try to connect to the server using curl.
❯ curl --local-port 44444 http://SERVER_IP
❯ sudo tshark -f "tcp port 80 and host SERVER_IP"
1 0.000000000 MY_IP → SERVER_IP TCP 74 44444 → 80 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 SACK_PERM=1 TSval=1756025715 TSecr=0 WS=128
2 1.021102385 MY_IP → SERVER_IP TCP 74 [TCP Retransmission] 44444 → 80 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 SACK_PERM=1 TSval=1756026736 TSecr=0 WS=128
As expected, nothing happens as the SYN flag is interpreted as a FYN flag on server-side.
Now let's use scapy and send a FIN-flagged with a random sequence number segment.
#! /usr/bin/python
from scapy import *
C_ADDR = "MY_IP"
C_PORT = 44444
S_ADDR = "SERVER_IP"
S_PORT = 80
C_SEQ = 1234 # random
ip = IP(src=C_ADDR, dst=S_ADDR)
tcp = TCP(
sport=C_PORT,
dport=S_PORT,
flags="F",
seq=C_SEQ,
)
p = send(ip/tcp)
❯ sudo tshark -f "tcp port 80 and host SERVER_IP"
1 0.000000000 MY_IP → SERVER_IP TCP 54 44444 → 80 [FIN] Seq=1 Win=8192 Len=0
2 0.144079153 SERVER_IP → MY_IP TCP 58 80 → 44444 [RST, ACK] Seq=1 Ack=2 Win=65320 Len=0 MSS=1420
The server understands "SYN" and sends us RST-ACK (which is SYN-ACK). So now he must be waiting for a a ECN (which is an ACK)... And so on. You got it.
Packet interception and modification with scapy and nfqueue
We could rewrite an HTTP client with scapy using the modified flags. But it is a long and tedious task as we must craft every request with scapy. A less painful solution would be to have a layer that intercepts every packet and just update the flags before sending/accepting them. And that's where nfqueue can help us.
Using a standard http client like curl, intercept all the incoming and outcoming packages with nfqueue, pass them to our scapy script that will change the flags accordingly and then send the modified packets to their destination.
Netfilter Queue is an iptables target which gives the decision on packets to the userspace. It is part of the Netfilter project that also provides iptables and nftables. It is commonly used as a proxy or for Man in the Middle attacks.
To intercept packets with nfqueue you must set firewall's chain rules accordingly. In this situation we want to intercept:
- incoming packets from SERVER_IP (INPUT chain)
- outgoing packets to SERVER_IP (OUTPUT chain)
Let's try this.
1. Let's set nfqueue
#!/usr/bin/python3
from netfilterqueue import NetfilterQueue
from scapy import *
import os
S_ADDR = "SERVER_IP"
# Update iptables rules
output_rule = f"iptables -A OUTPUT --destination {S_ADDR} -j NFQUEUE"
input_rule = f"iptables -A INPUT --source {S_ADDR} -j NFQUEUE"
flush_rules = "iptables -F OUTPUT && iptables -F INPUT"
os.system(input_rule)
os.system(output_rule)
def callback(raw_pkt):
# Get a scapy object from raw packet
p = IP(raw_pkt.get_payload())
print(p.show())
# Tell nfqueue to accept the packet
raw_pkt.accept()
# Init nfqueue
q = NetfilterQueue()
q.bind(0, callback)
try:
q.run()
except KeyboardInterrupt:
q.unbind()
os.system(flush_rules)
First we update iptables rules to intercept the interesting packets to nfqueue. Then we init nfqueue and bind the queue number 0 to our callback function. We use the same queue for both incoming and outgoing packets.
In our callback function, we get a raw packet. To manipulate it, we create a scapy IP layer with the packet's payload as an argument. We print it and finally we accept the packet. If we interrupt the process (with Ctrl+C) then we unbind the queue and flush the iptables rules.
Important: check your INPUT and OUTPUT chain rules before flushing it as it flushes everything.
Let's see if it works.
❯ curl http://SERVER_IP --local-port 44444
# Script output
###[ IP ]###
version= 4
ihl= 5
tos= 0x0
len= 60
id= 60025
flags= DF
frag= 0
ttl= 64
proto= tcp
chksum= 0xa981
src= SERVER_IP
dst= CLIENT_IP
\options\
###[ TCP ]###
sport= 44444
dport= http
seq= 1190907934
ack= 0
dataofs= 10
reserved= 0
flags= S
window= 64240
chksum= 0xfaf1
urgptr= 0
options= [('MSS', 1460), ('SAckOK', b''), ('Timestamp', (2004053730, 0)), ('NOP', None), ('WScale', 7)]
❯ sudo tshark -f "tcp port 80 and host SERVER_IP"
1 0.000000000 CLIENT_IP → SERVER_IP TCP 74 44444 → 80 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 SACK_PERM=1 TSval=2004025682 TSecr=0 WS=128
Great! Curl tries to initiate the session with the server using a SYN-flagged packet. When the packet reaches the raw_pkt.accept()
instruction, it is sent to the client and we can notice it in tshark's output.
2. Changing the flag
In our callback function, let's try changing the packet's flag with 'F' and see what happens.
def callback(raw_pkt):
# Get a scapy object from raw packet
p = IP(raw_pkt.get_payload())
print(p.show())
# Set S flag to F flag
if p.haslayer(TCP):
if p[TCP].flags = "S"
p[TCP].flags = "F"
# Update raw packet and then accept it
raw_pkt.set_payload(bytes(p))
raw_pkt.accept()
❯ sudo tshark -f "tcp port 80 and host SERVER_IP"
1 0.000000000 CLIENT_IP → SERVER_IP TCP 74 44444 → 80 [FIN] Seq=1 Win=64240 Len=0 MSS=1460 SACK_PERM=1 TSval=2005103907 TSecr=0 WS=128
2 1.005513362 CLIENT_IP → SERVER_IP TCP 74 [TCP Retransmission] 44444 → 80 [FIN] Seq=1 Win=8222720 Len=0 MSS=1460 SACK_PERM=1 TSval=2005104912 TSecr=0 WS=128
Something is wrong, we send a FIN but get no answer... Oh right! checksums, of course. Let's update checksums accordingly.
3. Update checksums
# Set S flag to F flag
if p.haslayer(TCP):
if p[TCP].flags = "S"
p[TCP].flags = "F"
# Update checksums
del p[IP].chksum
del p[TCP].chksum
p.show2()
I use the function show2()
that recalculate checksums if they are none. This is functional but loud as it also prints the packet. I didn't find any other solution that does it quietly.
Let's try now.
❯ sudo tshark -f "tcp port 80 and host SERVER_IP"
1 0.000000000 CLIENT_IP → SERVER_IP TCP 74 44444 → 80 [FIN] Seq=1 Win=64240 Len=0 MSS=1460 SACK_PERM=1 TSval=2005448037 TSecr=0 WS=128
2 0.154677103 SERVER_IP → CLIENT_IP TCP 74 80 → 44444 [RST, ACK] Seq=1 Ack=2 Win=64768 Len=0 MSS=1420 SACK_PERM=1 TSval=1006897750 TSecr=2005448037 WS=128
Yes! The server answers us back with a RST-ACK. But our curl client still doesn't understand what he means by that. Let's map all the flags accordingly now.
4. Map all the flags (final code)
#!/usr/bin/python3
from netfilterqueue import NetfilterQueue
from scapy import *
import os
S_ADDR = "SERVER_IP"
# Update iptables rules to intercept incoming and outcoming packets from/to S_ADDR
output_rule = f"iptables -A OUTPUT --destination {S_ADDR} -j NFQUEUE"
input_rule = f"iptables -A INPUT --source {S_ADDR} -j NFQUEUE"
flush_rules = "iptables -F OUTPUT && iptables -F INPUT"
os.system(input_rule)
os.system(output_rule)
# Dictionary with flag mapping
fd = {
"S":"F",
"RA":"SA",
"A":"E",
"PA":"FS"
}
# Append the inverted dictionnary
fd.update(dict((v,k) for k,v in fd.items()))
# Helper function to set the flags accordingly
def set_flags(flags):
return fd[flags] if flags in fd else flags
# Callback function that modifies our packets before sending them
def callback(raw_pkt):
# Get a scapy raw packet that we can modify
p = IP(raw_pkt.get_payload())
# Set flags accordingly
if p.haslayer(TCP):
p[TCP].flags = set_flags(str(p[TCP].flags))
# Calculate new chksums
del p[IP].chksum
del p[TCP].chksum
p.show2()
# Update
raw_pkt.set_payload(bytes(p))
# Now we tell nfqueue to accept the modified packet
raw_pkt.accept()
# Init nfqueue
q = NetfilterQueue()
q.bind(0, callback)
try:
q.run()
except KeyboardInterrupt:
q.unbind()
os.system(flush_rules)
We use a dictionary to map all the flags. And then we use the Dict.update()
method to add the same tuples but with the keys and values swaped. (e.g. "S":"F"
adds "F":"S"
).
Let's try our new code now.
❯ curl http://SERVER_IP --local-port 44444
<!doctype html>
<html>
<head>
<title>FreakyFlagday</title>
</head>
<body>
<p>It's freakyflagday and you've made it so far! Well done. All you've gotta do is download the text file from '/gimmedafile.txt' and it'll send you a big important file with the flag at the very end.</p>
</body>
</html>
❯ sudo tshark -f "tcp port 80 and host SERVER_IP"
1 0.000000000 MY_IP → SERVER_IP TCP 74 44444 → 80 [FIN] Seq=1 Win=64240 Len=0 MSS=1460 SACK_PERM=1 TSval=1784676225 TSecr=0 WS=128
2 0.145262609 SERVER_IP → MY_IP TCP 74 80 → 44444 [RST, ACK] Seq=1 Ack=2 Win=64768 Len=0 MSS=1420 SACK_PERM=1 TSval=786145437 TSecr=1784676225 WS=128
3 0.160854317 MY_IP → SERVER_IP TCP 66 44444 → 80 [ECN] Seq=2 Win=64256 Len=0 TSval=1784676385 TSecr=786145437
4 0.170014574 MY_IP → SERVER_IP HTTP 144 [TCP Port numbers reused] GET / HTTP/1.1
5 0.287621647 SERVER_IP → MY_IP TCP 66 80 → 44444 [ECN] Seq=1 Win=506 Len=0 TSval=786145607 TSecr=1784676385
6 0.290354873 SERVER_IP → MY_IP HTTP 220 [TCP Port numbers reused] HTTP/1.1 200 OK
7 0.311377282 MY_IP → SERVER_IP TCP 66 [TCP Keep-Alive] 44444 → 80 [ECN] Seq=78 Win=501 Len=0 TSval=1784676535 TSecr=786145609
8 0.426628596 SERVER_IP → MY_IP TCP 376 [TCP Port numbers reused] 80 → 44444 [FIN, SYN] Seq=0 Win=506 Len=310 TSval=786145748 TSecr=1784676535
9 0.444996568 MY_IP → SERVER_IP TCP 66 [TCP Keep-Alive] 44444 → 80 [ECN] Seq=78 Win=501 Len=0 TSval=1784676668 TSecr=786145748
10 0.449897000 MY_IP → SERVER_IP TCP 66 [TCP ACKed unseen segment] [TCP Retransmission] 44444 → 80 [FIN, ACK] Seq=78 Ack=465 Win=501 Len=0 TSval=1784676669 TSecr=786145748
11 0.562439239 SERVER_IP → MY_IP TCP 66 [TCP Retransmission] 80 → 44444 [FIN, ACK] Seq=310 Ack=1 Win=506 Len=0 TSval=786145885 TSecr=1784676669
12 0.583268378 MY_IP → SERVER_IP TCP 66 44444 → 80 [ECN] Seq=79 Win=501 Len=0 TSval=1784676807 TSecr=786145885
Seems like it worked pretty well. The flag seems to be in this gimmedafile.txt
file. Let's try and get the file.
❯ curl http://SERVER_IP/gimmedafile.txt --local-port 44445
Voluptatem ipsum [...39404 characters...] dolor ut.
flag{e2960da061a85fbcabb0670e4ddb9e93}
❯ sudo tshark -f "tcp port 80 and host SERVER_IP"
1 0.000000000 MY_IP → SERVER_IP TCP 74 44445 → 80 [FIN] Seq=1 Win=64240 Len=0 MSS=1460 SACK_PERM=1 TSval=1784824675 TSecr=0 WS=128
2 0.142799620 SERVER_IP → MY_IP TCP 74 80 → 44445 [RST, ACK] Seq=1 Ack=2 Win=64768 Len=0 MSS=1420 SACK_PERM=1 TSval=786293873 TSecr=1784824675 WS=128
3 0.159637964 MY_IP → SERVER_IP TCP 66 44445 → 80 [ECN] Seq=2 Win=64256 Len=0 TSval=1784824834 TSecr=786293873
4 0.165712720 MY_IP → SERVER_IP HTTP 159 [TCP Port numbers reused] GET /gimmedafile.txt HTTP/1.1
5 0.278158205 SERVER_IP → MY_IP TCP 66 80 → 44445 [ECN] Seq=1 Win=506 Len=0 TSval=786294039 TSecr=1784824834
6 0.281436371 SERVER_IP → MY_IP HTTP 227 [TCP Port numbers reused] HTTP/1.1 200 OK
7 0.286101671 SERVER_IP → MY_IP TCP 1474 80 → 44445 [ECN] Seq=161 Win=506 Len=1408 TSval=786294048 TSecr=1784824834
8 0.290101742 SERVER_IP → MY_IP TCP 1474 80 → 44445 [ECN] Seq=1569 Win=506 Len=1408 TSval=786294052 TSecr=1784824834
9 0.293428900 SERVER_IP → MY_IP TCP 1474 80 → 44445 [ECN] Seq=2977 Win=506 Len=1408 TSval=786294056 TSecr=1784824834
10 0.300100620 SERVER_IP → MY_IP TCP 1474 80 → 44445 [ECN] Seq=4385 Win=506 Len=1408 TSval=786294060 TSecr=1784824834
11 0.303058929 SERVER_IP → MY_IP TCP 1474 80 → 44445 [ECN] Seq=5793 Win=506 Len=1408 TSval=786294060 TSecr=1784824834
12 0.305803295 SERVER_IP → MY_IP TCP 1474 80 → 44445 [ECN] Seq=7201 Win=506 Len=1408 TSval=786294061 TSecr=1784824834
13 0.308359956 SERVER_IP → MY_IP TCP 1474 80 → 44445 [ECN] Seq=8609 Win=506 Len=1408 TSval=786294061 TSecr=1784824834
14 0.311371415 SERVER_IP → MY_IP TCP 1474 80 → 44445 [ECN] Seq=10017 Win=506 Len=1408 TSval=786294067 TSecr=1784824834
15 0.314342631 SERVER_IP → MY_IP TCP 1474 80 → 44445 [ECN] Seq=11425 Win=506 Len=1408 TSval=786294070 TSecr=1784824834
16 0.317448713 MY_IP → SERVER_IP TCP 66 [TCP Keep-Alive] 44445 → 80 [ECN] Seq=93 Win=501 Len=0 TSval=1784824974 TSecr=786294043
17 0.322497523 MY_IP → SERVER_IP TCP 66 [TCP Keep-Alive] 44445 → 80 [ECN] Seq=93 Win=497 Len=0 TSval=1784824980 TSecr=786294048
18 0.345296346 MY_IP → SERVER_IP TCP 66 [TCP Keep-Alive] 44445 → 80 [ECN] Seq=93 Win=497 Len=0 TSval=1784824986 TSecr=786294052
19 0.363030999 MY_IP → SERVER_IP TCP 66 [TCP Keep-Alive] 44445 → 80 [ECN] Seq=93 Win=497 Len=0 TSval=1784824992 TSecr=786294056
20 0.374327694 MY_IP → SERVER_IP TCP 66 [TCP Keep-Alive] 44445 → 80 [ECN] Seq=93 Win=497 Len=0 TSval=1784825009 TSecr=786294060
21 0.379388653 MY_IP → SERVER_IP TCP 66 [TCP Keep-Alive] 44445 → 80 [ECN] Seq=93 Win=497 Len=0 TSval=1784825014 TSecr=786294060
22 0.384474051 MY_IP → SERVER_IP TCP 66 [TCP Keep-Alive] 44445 → 80 [ECN] Seq=93 Win=497 Len=0 TSval=1784825020 TSecr=786294061
23 0.389563243 MY_IP → SERVER_IP TCP 66 [TCP Keep-Alive] 44445 → 80 [ECN] Seq=93 Win=497 Len=0 TSval=1784825031 TSecr=786294061
24 0.395089952 MY_IP → SERVER_IP TCP 66 [TCP Keep-Alive] 44445 → 80 [ECN] Seq=93 Win=497 Len=0 TSval=1784825038 TSecr=786294067
25 0.400325803 MY_IP → SERVER_IP TCP 66 [TCP Keep-Alive] 44445 → 80 [ECN] Seq=93 Win=497 Len=0 TSval=1784825049 TSecr=786294070
26 0.429292547 SERVER_IP → MY_IP TCP 1474 80 → 44445 [ECN] Seq=12833 Win=506 Len=1408 TSval=786294190 TSecr=1784824974
27 0.432396491 SERVER_IP → MY_IP TCP 1474 80 → 44445 [ECN] Seq=14241 Win=506 Len=1408 TSval=786294190 TSecr=1784824974
28 0.435011224 SERVER_IP → MY_IP TCP 1474 80 → 44445 [ECN] Seq=15649 Win=506 Len=1408 TSval=786294195 TSecr=1784824980
29 0.437501469 SERVER_IP → MY_IP TCP 1474 80 → 44445 [ECN] Seq=17057 Win=506 Len=1408 TSval=786294195 TSecr=1784824980
30 0.455718674 SERVER_IP → MY_IP TCP 1276 [TCP Port numbers reused] 80 → 44445 [FIN, SYN] Seq=0 Win=506 Len=1210 TSval=786294218 TSecr=1784824986
31 0.459562289 SERVER_IP → MY_IP TCP 1474 80 → 44445 [ECN] Seq=1210 Win=506 Len=1408 TSval=786294222 TSecr=1784824986
32 0.473141161 MY_IP → SERVER_IP TCP 66 [TCP Keep-Alive] 44445 → 80 [ECN] Seq=93 Win=497 Len=0 TSval=1784825125 TSecr=786294190
33 0.473160024 SERVER_IP → MY_IP TCP 1474 80 → 44445 [ECN] Seq=2618 Win=506 Len=1408 TSval=786294235 TSecr=1784824992
34 0.476471278 SERVER_IP → MY_IP TCP 1474 80 → 44445 [ECN] Seq=4026 Win=506 Len=1408 TSval=786294235 TSecr=1784824992
35 0.478176107 MY_IP → SERVER_IP TCP 66 [TCP Keep-Alive] 44445 → 80 [ECN] Seq=93 Win=497 Len=0 TSval=1784825133 TSecr=786294190
36 0.483052912 SERVER_IP → MY_IP TCP 1474 80 → 44445 [ECN] Seq=5434 Win=506 Len=1408 TSval=786294246 TSecr=1784825009
37 0.489734170 MY_IP → SERVER_IP TCP 66 [TCP Keep-Alive] 44445 → 80 [ECN] Seq=93 Win=497 Len=0 TSval=1784825140 TSecr=786294195
38 0.490446940 SERVER_IP → MY_IP TCP 1474 80 → 44445 [ECN] Seq=6842 Win=506 Len=1408 TSval=786294246 TSecr=1784825009
39 0.495628297 SERVER_IP → MY_IP TCP 1474 80 → 44445 [ECN] Seq=8250 Win=506 Len=1408 TSval=786294252 TSecr=1784825014
40 0.498457646 SERVER_IP → MY_IP TCP 1474 80 → 44445 [ECN] Seq=9658 Win=506 Len=1408 TSval=786294252 TSecr=1784825014
41 0.502477260 MY_IP → SERVER_IP TCP 66 [TCP Keep-Alive] 44445 → 80 [ECN] Seq=93 Win=497 Len=0 TSval=1784825148 TSecr=786294195
42 0.503250048 SERVER_IP → MY_IP TCP 1474 80 → 44445 [ECN] Seq=11066 Win=506 Len=1408 TSval=786294256 TSecr=1784825020
43 0.508097290 SERVER_IP → MY_IP TCP 1474 80 → 44445 [ECN] Seq=12474 Win=506 Len=1408 TSval=786294261 TSecr=1784825031
44 0.529693000 MY_IP → SERVER_IP TCP 66 [TCP Keep-Alive] 44445 → 80 [ECN] Seq=93 Win=497 Len=0 TSval=1784825165 TSecr=786294218
45 0.547629433 MY_IP → SERVER_IP TCP 66 [TCP Keep-Alive] 44445 → 80 [ECN] Seq=93 Win=497 Len=0 TSval=1784825177 TSecr=786294222
46 0.569959311 MY_IP → SERVER_IP TCP 66 [TCP Keep-Alive] 44445 → 80 [ECN] Seq=93 Win=497 Len=0 TSval=1784825198 TSecr=786294235
47 0.574834351 MY_IP → SERVER_IP TCP 66 [TCP Keep-Alive] 44445 → 80 [ECN] Seq=93 Win=497 Len=0 TSval=1784825216 TSecr=786294246
48 0.582698364 MY_IP → SERVER_IP TCP 66 [TCP Keep-Alive] 44445 → 80 [ECN] Seq=93 Win=497 Len=0 TSval=1784825234 TSecr=786294252
49 0.590039492 MY_IP → SERVER_IP TCP 66 [TCP Keep-Alive] 44445 → 80 [ECN] Seq=93 Win=497 Len=0 TSval=1784825245 TSecr=786294256
50 0.640226149 SERVER_IP → MY_IP TCP 651 [TCP Port numbers reused] 80 → 44445 [FIN, SYN] Seq=0 Win=506 Len=585 TSval=786294402 TSecr=1784825165
51 0.663333652 MY_IP → SERVER_IP TCP 66 [TCP Keep-Alive] 44445 → 80 [ECN] Seq=93 Win=501 Len=0 TSval=1784825334 TSecr=786294402
52 0.669714648 MY_IP → SERVER_IP TCP 66 [TCP ACKed unseen segment] [TCP Retransmission] 44445 → 80 [FIN, ACK] Seq=93 Ack=32933 Win=501 Len=0 TSval=1784825335 TSecr=786294402
53 0.776541498 SERVER_IP → MY_IP TCP 66 [TCP Retransmission] 80 → 44445 [FIN, ACK] Seq=585 Ack=1 Win=506 Len=0 TSval=786294541 TSecr=1784825335
54 0.793113070 MY_IP → SERVER_IP TCP 66 44445 → 80 [ECN] Seq=94 Win=501 Len=0 TSval=1784825466 TSecr=786294541
And voilà! Here's the second flag: flag{e2960da061a85fbcabb0670e4ddb9e93}
I hope you enjoyed this introduction to packets manipulation. I would like to thank nneonneo and Kkevsterrr for their explanations. Join Nahamsec on Discord to reach them out.
Until next time!
Further Lectures
Posted on May 30, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.