Lab Goal: Debug L2 vs L3 vs L4
Setup: VyOS on Oracle VM - single terminal
L2 - Data Link
Listener on same terminal:
sudo tcpdump -i eth0 -e arp -n &
Send: sendp(Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst="192.168.56.101"))
# 1. SUMMARY
a.summary()
'Ether / ARP who has 192.168.56.1 says 192.168.56.101'
2. FULL DECODE - a.show()
[ Ethernet ]
dst = None (Broadcast FF:FF:FF:FF:FF:FF)
src = 08:00:27:bf:9a:64
type = ARP
[ ARP ]
hwtype = Ethernet (10Mb)
ptype = IPv4
hwlen = None
plen = None
op = who-has
hwsrc = 08:00:27:bf:9a:64
psrc = 192.168.56.101
hwdst = 00:00:00:00:00:00
pdst = 192.168.56.1
3. RAW BYTES - hexdump(a) - 42 bytes on wire
0000 FF FF FF FF FF FF 08 00 27 BF 9A 64 08 06 00 01
0010 08 00 06 04 00 01 08 00 27 BF 9A 64 C0 A8 38 65
0020 00 00 00 00 00 00 C0 A8 38 01
4. SEND + PROOF IT WAS SENT
sendp(a, iface="eth0")
.
Sent 1 packets.
tcpdump listener confirmed:
22:48:40 eth0 Out ... ARP, Request who-has 192.168.56.1 tell 192.168.56.100
L3 - Network
One Terminal:
I only have one VyOS terminal, but Linux has &. This puts tcpdump in background and gives me my prompt back:
sudo tcpdump -i eth0 -n icmp &
[1] 5966
listening on eth0, link-type EN10MB (Ethernet)
In the same terminal, Scapy. You have to tell it what a is first:
sudo python3
from scapy.all import *
a = Ether()/IP(dst="192.168.56.101")/ICMP()
Then interrogate it:
a.show()
version = 4, ihl = None, tos = 0x0, len = None, id = 1, flags =, frag = 0
ttl = 64, proto = icmp, src = 192.168.56.101, dst = 192.168.56.101
[ICMP] type = echo-request, code = 0, chksum = None, id = 0x0, seq = 0x0
a.summary()
Ether / IP / ICMP 192.168.56.101 > 192.168.56.101 echo-request 0
len(a)
42
hexdump(a)
0000 FF FF FF FF FF FF 08 00 27 BF 9A 64 08 00 45 00
0010 00 1C 00 01 00 00 40 01 88 C5 C0 A8 38 65 C0 A8
0020 38 65 08 00 F7 FF 00 00 00 00
= dst MAC broadcast, src MAC 08:00:27:BF:9A:64, type IPv4, ICMP echo-request
Send it:
sendp(a)
WARNING: MAC address to reach destination not found. Using broadcast.
Sent 1 packets.
Try to get a reply:
reply = srp1(a, timeout=2)
Begin emission
WARNING: MAC address to reach destination not found. Using broadcast.
Finished sending 1 packets
Received 0 packets, got 0 answers, remaining 1 packets
reply.show()
AttributeError: 'NoneType' object has no attribute 'show'
Lesson: Ether() with no dst MAC = broadcast FF:FF:FF:FF:FF:FF. Target ignores it.
My hexdump even showed ARP who-has. sendp is L2 - needs a MAC.
For a real L3 ping, next time: a = IP(dst="192.168.56.101")/ICMP() and sr1(a).
Three checks before you send: summary(), show(), len().
L4 to L7 - Transport + Data
Listener on same terminal:
sudo tcpdump -i eth0 -n tcp port 22 -X &
Send: sendp(Ether()/IP(dst='192.168.56.101')/TCP(dport=22)/Raw(b'SSH-'))
LAB: L4-L7 Packet Crafting with Scapy + VyOS/tcpdump
Objective:
To demonstrate manual control of OSI Layers 2-7 by crafting a custom TCP packet with an SSH banner as payload and verifying it with tcpdump -X on VyOS.
- Packet Construction (Final Working Command):
from scapy.all import *
a = Ether()/IP(dst="192.168.56.1")/TCP(dport=22)/Raw(load=b"SSH-2.0-MyLab\r\n")
sendp(a)
Fixes from initial errors: Use TCP not tcp, Raw not RAW, and / between every layer. Correct syntax is Ether()/IP()/TCP()/Raw()
- Packet Analysis (from screenshots):
a) a.summary()
Output: Ether / IP / TCP 192.168.56.101:ftp_data > 192.168.56.1:ssh S / Raw
Analysis: Confirms L2 Ether, L3 IP, L4 TCP with SYN flag (S), random source port ftp_data=20 to destination ssh=22, plus L7 Raw layer.
b) a.show() - Layer Breakdown:
[ IP Layer ]
ttl = 64
proto = tcp
src = 192.168.56.101
dst = 192.168.56.1
[ TCP Layer ]
sport = ftp_data (20)
dport = ssh (22)
seq = 0
ack = 0
flags = S (SYN)
window = 8192
[ Raw Layer - L7 Payload ]
load = b'SSH-2.0-MyLab\r\n'
This shows full OSI control: Ether (L2) -> IP (L3) -> TCP (L4) -> Raw SSH banner (L7).
c) len(a)
Output: 69
Analysis: Total packet size on wire is 69 bytes. Breakdown: 14 bytes Ethernet + 20 bytes IP + 20 bytes TCP + 15 bytes payload (SSH-2.0-MyLab\r\n).
d) hexdump(a)
Output:
0000 FF FF FF FF FF FF 08 00 27 BF 9A 64 08 00 45 00
0010 00 37 00 01 00 00 40 06 89 09 C0 A8 38 65 C0 A8
0020 38 01 00 14 00 16 00 00 00 00 00 00 00 00 50 02
0030 20 00 9A 2E 00 00 53 53 48 2D 32 2E 30 2D 4D 79
0040 4C 61 62 0D 0A
Analysis: Hex at offset 0030-0040 decodes to ASCII: 53 53 48 = "SSH", 2D 32 2E 30 = "-2.0". This is exactly what tcpdump -X on VyOS captures, proving L7 payload injection. The FF FF FF FF FF FF is broadcast MAC because Scapy warning "MAC address to reach destination not found. Using broadcast."
- VyOS Verification:
On VyOS: sudo tcpdump -i eth0 tcp port 22 -X
This captures the packet and shows the hex/ASCII SSH-2.0-MyLab even though no real SSH handshake occurred.
Conclusion:
The packet is not a real SSH connection - we skipped the TCP 3-way handshake (SYN, SYN-ACK, ACK) and just threw the SSH banner at port 22. Tcpdump sees it because it sniffs the wire before the OS validates it. This proves Scapy gives full control of Raw payload (L7) inside TCP/IP envelopes.
Top comments (0)