Kiosk 9: Scapy Prepper
This challenge was a series of questions designed to get started with using Scapy, a python-based packet creation and manipulation tool. Scapy can be used to craft anything and send it across the wire. Personally speaking, it is probably one of the single most powerful toolsets I've ever come across, and am super happy whenever I get a chance to work with it.
This kiosk was located on the NetWars roof, next to Alabaster Snowball:
But enough gushing, let's get started!
Presenting: The Kiosk
╔════════════════════════════════════════════════════════════════╗
║ ___ ___ ___ ___ ___ _ _ _____ ___ _ ___ _ _____ _____ ║
║ | _ \ _ \ __/ __| __| \| |_ _| | _ \/_\ / __| |/ / __|_ _| ║
║ | _/ / _|\__ \ _|| .` | | | | _/ _ \ (__| ' <| _| | | ║
║ |_| |_|_\___|___/___|_|\_| |_| |_|/_/ \_\___|_|\_\___| |_| ║
║ ___ ║
║ | _ \_ _ ___ _ __ _ __ ___ _ _ ║
║ | _/ '_/ -_) '_ \ '_ \/ -_) '_| ║
║ |_| |_| \___| .__/ .__/\___|_| ║
║ |_| |_| ║
║ (Packets prepared with scapy) ║
╚════════════════════════════════════════════════════════════════╝
Type "yes" to begin.
After starting, I am presented with a series of questions, and to answer, I will have to use the task.submit()
function. This is done inside of a python REPL.
Start by running the task.submit() function passing in a string argument of 'start'.
task.submit('start')
Response: Correct! adding a () to a function or class will execute it. Ex - FunctionExecuted()
Submit the class object of the scapy module that sends packets at layer 3 of the OSI model
task.submit(send)
Response: Correct! The send
scapy class will send a crafted scapy packet out of a network interface.
Submit the class object of the scapy module that sniffs network packets and returns those packets in a list.
task.submit(sniff)
Response: Correct! the sniff
scapy class will sniff network traffic and return these packets in a list.
Submit the NUMBER only from the choices below that would successfully send a TCP packet and then return the first sniffed response packet to be stored in a variable named "pkt":
- pkt = sr1(IP(dst="127.0.0.1")/TCP(dport=20))
- pkt = sniff(IP(dst="127.0.0.1")/TCP(dport=20))
- pkt = sendp(IP(dst="127.0.0.1")/TCP(dport=20))
task.submit(1) # pkt = Sr1(IP(dst="127.0.0.1")/TCP(dport=20))
Response: Correct! sr1
will send a packet, then immediately sniff for a response packet.
Submit the class object of the scapy module that can read pcap or pcapng files and return a list of packets.
task.submit(rdpcap)
Response: Correct! the rdpcap
scapy class can read pcap files.
The variable UDP_PACKETS contains a list of UDP packets. Submit the NUMBER only from the choices below that correctly prints a summary of UDP_PACKETS:
- UDP_PACKETS.print()
- UDP_PACKETS.show()
- UDP_PACKETS.list()
task.submit(2) # UDP_PACKETS.show()
Response: Correct! .show()
can be used on lists of packets AND on an individual packet.
Submit only the first packet found in UDP_PACKETS
task.submit(UDP_PACKETS[0])
Response: Correct! Scapy packet lists work just like regular python lists so packets can be accessed by their position in the list starting at offset 0.
Submit only the entire TCP layer of the second packet in TCP_PACKETS.
task.submit(TCP_PACKETS[1].getlayer('TCP'))
Response: Correct! Most of the major fields like Ether, IP, TCP, UDP, ICMP, DNS, DNSQR, DNSRR, Raw, etc... can be accessed this way. Ex - pkt[IP][TCP]
Change the source IP address of the first packet found in UDP_PACKETS to 127.0.0.1 and then submit this modified packet
my_pkt = UDP_PACKETS[0]
my_pkt.src = '127.0.0.1'
task.submit(my_pkt)
Response: Correct! You can change ALL scapy packet attributes using this method.
Submit the password "task.submit('elf_password')" of the user alabaster as found in the packet list TCP_PACKETS.
Initially, I tried this to grab the password, and it worked, though it was ugly:
for i in TCP_PACKETS:
if scapy.packet.Raw in i:
print(i[Raw])
But after completion, the response gave me a way of accessing the same result using a generator!
password = [pkt[Raw].load for pkt in TCP_PACKETS if Raw in pkt]
print(password)
# Prints the following:
# [b'220 North Pole FTP Server\r\n', b'USER alabaster\r', b'331 Password
# required for alabaster.\r', b'PASS echo\r\n', b'230 User alabaster logged
# in.\r']
task.submit('echo')
Response: Correct! Here is some really nice list comprehension that will grab all the raw payloads from tcp packets:
[pkt[Raw].load for pkt in TCP_PACKETS if Raw in pkt]
The ICMP_PACKETS variable contains a packet list of several icmp echo-request and icmp echo-reply packets. Submit only the ICMP chksum value from the second packet in the ICMP_PACKETS list.
task.submit(ICMP_PACKETS[1][ICMP].chksum)
Response: Correct! You can access the ICMP chksum value from the second packet using ICMP_PACKETS[1][ICMP].chksum
.
Submit the number of the choice below that would correctly create a ICMP echo request packet with a destination IP of 127.0.0.1 stored in the variable named "pkt"
- pkt = Ether(src='127.0.0.1')/ICMP(type="echo-request")
- pkt = IP(src='127.0.0.1')/ICMP(type="echo-reply")
- pkt = IP(dst='127.0.0.1')/ICMP(type="echo-request")
task.submit(3) # pkt = IP(dst='127.0.0.1')/ICMP(type='echo-request')
Response: Correct! Once you assign the packet to a variable named pkt
you can then use that variable to send or manipulate your created packet.
Create and then submit a UDP packet with a dport of 5000 and a dst IP of 127.127.127.127. (all other packet attributes can be unspecified)
pkt = IP(dst='127.127.127.127')/UDP(dport=5000)
task.submit(pkt)
Response: Correct! Your UDP packet creation should look something like this: (removed because it was the same as the submitted answer, no need to duplicate it)
Create and then submit a UDP packet with a dport of 53, a dst IP of 127.2.3.4, and is a DNS query with a qname of "elveslove.santa". (all other packet attributes can be unspecified)
pkt = IP(dst='127.2.3.4')/UDP(dport=53)/DNS(rd=1, qd=DNSQR(qname='elveslove.santa'))
task.submit(pkt)
Response: Correct! Your UDP packet creation should look something like this: (also removed because it was the same)
The variable ARP_PACKETS contains an ARP request and response packets. The ARP response (the second packet) has 3 incorrect fields in the ARP layer. Correct the second packet in ARP_PACKETS to be a proper ARP response and then task.submit(ARP_PACKETS) for inspection.
ARP_PACKETS[1][ARP].op = 'is-at'
ARP_PACKETS[1][ARP].hwsrc=ARP_PACKETS[1][Ether].src
ARP_PACKETS[1][ARP].hwdst=ARP_PACKETS[1][Ether].dst
task.submit(ARP_PACKETS)
Response: Great, you prepared all the present packets!
Congratulations, all pretty present packets properly prepared for processing!