Closed lawndoc closed 3 months ago
CC: #4275
There might be a race condition happening here.
As a workaround for this issue, we were able to use AsyncSniffer
to capture packets rather than relying on the data returned from sr1
. That code is below:
from scapy.all import *
from scapy.layers.inet import IP, UDP
from scapy.layers.netbios import NBNSQueryRequest, NBNSQueryResponse, NBNSHeader
# change IP(dst= to your local broadcast IP
packet = IP(dst="172.19.0.255")/UDP(sport=137, dport=137)/NBNSHeader(OPCODE=0x0, NM_FLAGS=0x11, QDCOUNT=1)/NBNSQueryRequest(SUFFIX="file server service", QUESTION_NAME="Loremipsumdolorsitamet", QUESTION_TYPE="NB")
sniffer = AsyncSniffer(filter="udp dst port 137", store=True)
sniffer.start()
sleep(0.5) # !!! needed to add a delay before or we would sometimes miss the packets
sr1(packet, timeout=self.timeout, verbose=0)
sleep(self.timeout)
response = sniffer.stop()
if not response:
if self.verbosity >= 1:
print("No response (NBNS -> {self.hostname})")
return
if self.verbosity >=1:
for p in response:
print(p)
# Print all resolved IP addresses
for sniffed_packet in response:
if sniffed_packet is not None and sniffed_packet.haslayer(NBNSQueryResponse):
for answer in sniffed_packet[NBNSQueryResponse].ADDR_ENTRY:
print(f"Got a response from: {response[NBNSQueryResponse].ADDR_ENTRY[i].NB_ADDRESS}")
Originally, we didn't have the sleep(0.5)
call between sniffer.start()
and sending the query with sr1
. We were running into a strange issue where it would inconsistently not capture any packets. After adding the delay between sniffer.start()
and sr1
, we were consistently capturing all requests and responses.
I wonder if this issue we are having with sr1
not capturing responses is due to the same reason, it's not starting the sniffer fast enough to capture the responses?
There might be a race condition happening here.
No.
You're missing conf.checkIPaddr = False
.
Matching Netbios Query answers was however not implemented. This is fixed by https://github.com/secdev/scapy/pull/4445. Thanks for reporting that
I see now that config flag was called out in the usage documentation in the DHCP section. I wish you wouldn't say it like it was obvious, though. I just started using Scapy 2 weeks ago. I was just trying to be helpful and provide ideas. 😄
Thank you for discovering the Netbios Query answer bug, that would have been the next thing I ran into. I appreciate the work you do as an open source maintainer. If there's anything I can do better when reporting or troubleshooting issues, let me know.
I wish you wouldn't say it like it was obvious, though
Sorry about that :P this flag is honestly hard to guess, it's alright.
I've added a doc example to #4445 for Netbios to make this a bit easier to find.
I appreciate the work you do as an open source maintainer.
You're welcome :)
Sorry to pester, but I tested again after the merge (scapy-2.6.0rc1.dev44
) using the code below and am still not getting the netbios response captured by Scapy.
from scapy.all import *
from scapy.layers.inet import IP, UDP
from scapy.layers.netbios import NBNSQueryRequest, NBNSQueryResponse, NBNSHeader
# required for broadcast requests
conf.checkIPaddr = False
hostname = "Loremipsumdolorsitamet"
# change IP(dst= to your local broadcast IP
packet = IP(dst="172.19.0.255")/UDP(sport=137, dport=137)/NBNSHeader(OPCODE=0x0, NM_FLAGS=0x11, QDCOUNT=1)/NBNSQueryRequest(SUFFIX="file server service", QUESTION_NAME="Loremipsumdolorsitamet", QUESTION_TYPE="NB")
response = sr1(packet, timeout=1, verbose=0)
if not response:
print("No response (NBNS -> {hostname})")
exit()
for p in response:
print(p)
# Print all resolved IP addresses
for sniffed_packet in response:
if sniffed_packet is not None and sniffed_packet.haslayer(NBNSQueryResponse):
for answer in sniffed_packet[NBNSQueryResponse].ADDR_ENTRY:
print(f"Got a response from: {response[NBNSQueryResponse].ADDR_ENTRY[i].NB_ADDRESS}")
pcap from host running the above code: netbios.zip
Also, this code will actually work unlike the code I sent originally which still had self
references. Sorry about that 😄
I'll do some of the troubleshooting steps you suggested here and report back.
Looks like we are getting the following results in the debug
object:
<Sent: TCP:0 UDP:1 ICMP:0 Other:0>
<Received: TCP:0 UDP:1 ICMP:0 Other:6>
<Results: TCP:0 UDP:0 ICMP:0 Other:0>
I'll also take a look around the code that was changed in the PR, but I'm not as well versed at the byte level implementation of the packets.
Based on the fact that your unit tests are passing, I'm guessing there's something else I'm doing wrong lol.
I figured out the problem! The hostname we were querying was longer than the max length 15 of the netbios host field.
I added logic to my code to slice the string to [:15]
before sending the request. Interestingly, it looks like Scapy already handles the slicing when it sends the packets, but the value of self.RR_NAME
in answers
contains the full-length hostname.
I might open a PR to handle that gracefully in the answers
function. It would prevent future noobs like me from making the same mistake, and I don't think it would hurt anything to have Scapy handle that.
Brief description
I am using sr1 to send UDP packets for protocols like LLMNR and NBNS. Using wireshark and tcpdump, I am able to see the packets being sent and the responses being received, but the Scapy library is not capturing the response after it hits the interface on the host.
Scapy version
2.6.0-dev (main)
Python version
3.12.3
Operating system
Ubuntu 24.04 LTS (Linux 6.8.0-35-generic)
Additional environment information
Both hosts in the below pcap are in 172.19.0.0/24. The pcaps were captured on the interface of the host running Scapy using tcpdump.
nbns pcap: nbns.zip llmnr pcap: llmnr.zip
The host sending responses is running Responder to ensure that all LLMNR and NBNS requests have a response sent back.
How to reproduce
Code to reproduce:
Have Responder running on the same subnet or query a valid hostname of a Windows host on that subnet to get a response.
Actual result
No response
Expected result
No response
Related resources
No response