Part 2 -- Computer Browser Service
This article is a logical continuation of the previous one. This time around, I will give an introduction—again, with a few practical tricks—to how computers appear in the Windows Network window and why network neighborhood discovery in Windows is, well… not particularly reliable, to say the least.
Architectural Overview
Network discovery is the job of the so-called Computer Browser service (this browser has absolutely nothing to do with Microsoft Internet Explorer). One crucial thing to understand about the architecture of this service is this: when a Windows Network client builds a list of other computers around you, it does not even try to scan surroundings on its own! Instead, it relies on master browser servers to gather information and then distribute it to other interested parties.
Now, where do these master browsers come from? They get elected! I’m not kidding here. Computers run elections and decide who will be a master browser of the workgroup. Your own computer may get elected as the master browser, and you would not even know it! However, let’s put the politics aside and
concentrate on the actual process of discovery.
After a client knows where the master browsers are, it establishes a named pipe connection to \\<browser>\pipe\LANMAN over an SMB/NBT/TCP stack and sends a so-called NetServerEnum request. In turn, a master browser returns a list of all the computers it knows. Now a client can repeat the process with the rest of master browsers, after which the process is complete.
But how does a master browser itself know all the computers? This is where we start understanding the reasons for the unreliability of network discovery in Windows.
Master browser has to collect so-called HostAnnouncement frames which are broadcasted by computers upon startup, after 1 minute, then after 2, then 4, 8, and finally every 12 minutes.
Intervals between announcements are huge, and furthermore, these announcements could be easily lost as they are sent as non-repetitive unconfirmed UDP broadcasts to mailslot \\*\mailslot\LANMAN. Even worse, after a computer is disconnected from the network, the memory of it remains in the master browser’s cache until this computer misses three announcements in a row – only then the record is removed! The rest of the network sees a zombie for 36 minutes!
So basically, Windows discovery shows us an extremely unreliable snapshot based on unconfirmed single UDP broadcast announcements, and the snapshot itself is updated with horrible time resolution!
Can anything be done to improve the situation? Well, obviously, we can’t patch the Windows browser service (unless you work for Microsoft?), but I will show you two more reliable methods of building a list of neighbor computers – both methods avoid making queries to the cached lists of hosts stored on Master Browsers.
Scanning with NodeStatus
Method one should be pretty obvious if you have read my previous article about the NetBIOS name service. NetBIOS provides a way of getting a name from the IP address with the NodeStatus request. Nothing precludes us from sending this request in a loop to a range of IPs and then memorizing all the replies!
The answer to a NodeStatus request includes the information about the name and the workgroup of the NetBIOS node, and also whether or not this node has been elected as a Master Browser. It misses some fields of useful information HostAnnouncement packet carries with it (such as OS version, capabilities,
user-supplied comment, etc.), but we’re going to have more than enough information to build a useful tool.
This method works very well and is way more reliable than the built-in Windows Network discovery. At the end of this article, you will find a link to the IO Ninja plugin that performs a simple IP-address range scan with NodeStatus request.
However, this is a form of brute-force IP-scan, and it carries all the downsides of one – most importantly, flooding the network with a barrage of probe packets and taking quite some time (should we scan a range of IP-s larger than a common IP class-C subnet).
So now I will move on to discussing a method that does not involve scanning of the entire IP range.
Discovery with Announcement Request
Another approach is to solicit HostAnnouncement-s. We have to go back to politics—particularly, to the moment of winning master browser elections. When a computer is elected as the new master browser, it has to somehow speed up the process of building its initial host lists, or it will have to wait for another 12 minutes before all neighbor nodes re-announce themselves. Designers of Computer Browser protocol have created a special facility just for that—the AnnouncementRequest query.
In response to this query, all the computers have to send HostAnnouncement response frames. They will do so with a random delay of up to 30 seconds. It’s clear to see the designer’s intentions here—the delay is supposed to minimize the chances for the new Master Browser to miss some replies. This is a rather questionable design decision again—there are much better ways of dealing with the packet loss, and this massive up-to-30 seconds delay only adds to uncertainty during the discovery process. Has the node received AnnouncementRequest and is exercising its random delay? Or has it not received anything and we should maybe send another AnnouncementRequest? We shall find out no sooner than 30 seconds later!
There are good news as well. Computers reply to this request even when it’s sent not from a master browser, but from any random node. So we can do this too!
Forcing Announcements Manually
AnnouncementRequest is sent over SMB/NBT/UDP stack to a mailslot \\<group>\mailslot\BROWSE. The query itself consists of 2 bytes 0x02 0x00 followed by a null-terminated computer name (which is completely ignored, so you can type whatever you want).
As before, I will be using IO Ninja programmable terminal/sniffer (free download here: http://tibbo.com/ninja/downloads.html ). You can also write a program in your language and tool of choice. Also, if you are using a non-Windows machine, you would need to build the whole SMB/NBT/UDP stack manually.
I will now show you how to do this in IO Ninja. Start new File Stream Session, set Access Mode to “Write-only” (otherwise the File Stream will try to read from a client mailslot, which would obviously fail) and then open the \\*\mailslot\BROWSE mailslot. The asterisk (*) here stands for the workgroup of your own computer. Now, fill in the AnnouncementRequest packet as shown in the screenshot below and hit Send.
During the next 30 seconds, you will be collecting replies from all the computers in your workgroup. You will not see them in your File Stream Session – you have opened the client mailslot for sending only,remember? To observe those announcements, you have to either open a UDP socket on port 138 (Browser Service opens this UDP address as re-usable so you can open it, too) or use a packet sniffer.
Below you can see how replies solicited by the packet we’ve just sent from IO Ninja get decoded in Wireshark.
However, if you carefully compare the list of computers discovered with this method and the list of computers yielded by a brute-force scan (or even the list from your Windows Network window), you will notice missing hosts.
It turns out, some hosts will not send HostAnnouncement in response to AnnouncmentRequest if the latter was not directed to the host’s group. When sending to \\*\mailslot\BROWSE we actually set the target group as your own.
So, to build a full list you need to discover all the workgroups on the network first.
Enumerating Groups
We can actually enumerate workgroups by enumerating master browsers – each workgroup should have one Master Browser elected. You can locate master browsers by executing an NBNS name query for a special name “\x01\x02__MSBROWSE__\x02\x01”. We already have a program to do NBNS name queries (shown in my previous article on NetBIOS Name Service). Why not try this special name real quick?
There are two tricky parts with the name above, though. First, it contains special characters 0x01 and 0x02; second, it’s already 16 characters long (if you remember, NetBIOS name must be 15 characters plus a type suffix). Therefore, we cannot directly use our existing template code to send this name. No worries, let’s add the following method to our packet template NbnsNameQueryReq to take care of this particular name’ specifics:
[ packetTemplateAction ] void setMasterBrowserName () { encodeNetBiosName (m_question.m_name, "\x01\x02__MSBROWSE__\x02\x01", 0, 1); }
Now if we click our new setMasterBrowser action and then send the resulting packet, we will see all the master browsers on the network. Each workgroup elects a single master browser, so if you have a large intranet, you are likely to see multiple replies:
There! Now we have a list of the IPs of all master browsers. To find out which groups each master browser belongs to, send a NodeStatus request and look for the group’s name in the response. Voila!
So, to summarize our algorithm:
- Locate master browser servers with a NameQuery for __MSBROWSE__;
- Send each master browser a NodeStatus request;
- Extract workgroup information from the NodeStatus reply;
- Send an AnnouncementRequest to each workgroup (including the default group *);
- Collect the replies and build a list of neighbor computers.
In the links below you can find the source code for the IO Ninja plugin, which implements the above algorithm and contains all the necessary NBT/MSBRWS structure definitions for you to play with. It also logs all the packets it sends and receives in the process, so you are going to have a clear overview of what’s going on under the hood:
Also, it should be easy to copy-paste definitions of NBT/ MSBRWS header structures to a C/C++ program of yours since the Jancy scripting language is highly compatible with C on both source and binary levels.
Announcing Ourselves
Finally, let me show you what’s going to happen if you send some bogus HostAnnouncements. It turns out, Windows implementation of Master Browser eagerly eats everything and hardly does do any checks, like whether the announced name matches the source name in the NBT header, whether the name matches the IP address in NetBIOS cache, etc. Nothing gets verified!
Let’s create a File Stream session in IO Ninja and open a \\*\mailslot\LANMAN mailslot—that’s where unsolicited HostAnnouncements should be sent.
After that, go to the Packet Template editor and punch in the following:
struct HostAnnouncement_lanman { uint8_t m_opcode; uint8_t m_reserved; uint32_t m_serverType; uint8_t m_osVersionMajor; uint8_t m_osVersionMinor; uint16_t m_periodicity; // in seconds char m_serverName [1]; // followed by a null-terminated comment [ packetTemplateAction ] initialize () { *this = null; m_opcode = 0x01; // HostAnnouncement m_periodicity = 12 * 60; // 12 min m_osVersionMajor = 0x06; // Windows 7 m_osVersionMinor = 0x01; // Windows 7 m_serverType = 0x11003; // Windows NT Workstation } }
It’s worth noting that the format of unsolicited mailslot\LANMAN HostAnnouncement packet is different from the HostAnnouncement sent as a reply to AnnouncementRequest to mailslot\BROWSE. Strangely, they share the same opcode. Yes, I know. Don’t try to wrap your head around this.
Anyway, proceed to the hex editor and type any random double-null-terminated name (the second null will serve as a terminator for an empty comment), then hit Send. One packet is all it takes. Do it again with a different name, then again, again, and again:
Now go to the Windows Network discovery and enjoy the army of fake PCs you’ve just created:
And yes, these zombies will linger here for half an hour until they fail to re-announce themselves three times in a row. So, make sure to warn people around you before starting those experiments.
Have fun!
Useful Links
How Browser Service Works: https://technet.microsoft.com/en-us/library/cc737661(v=ws.10).aspx
Common Internet File System (CIFS) Browser Protocol: https://msdn.microsoft.com/en-us/library/cc224428.aspx
IO Ninja packet templates for sending HostAnnouncement frames: http://www.tibbo.com/downloads/open/ioninja-plugin-samples/MsBrowsePacketTemplates.jnc
IO Ninja plugin for NetBIOS name scan (IP-scan & HostAnnouncement scan): http://www.tibbo.com/downloads/open/ioninja-plugin-samples/NbScan.7z
Originally published at: dzone.com