Manticore is the Go library of offensive and defensive security primitives that underpins the tools of The Manticore Project: protocol stacks, cryptography, parsers, and the wire structures you need when you cannot rely on a host’s native client. Until now, the SMB stack in Manticore was effectively SMB1-only. That is enough to talk to legacy targets, but it leaves out the dialect that has been the default on Windows for more than a decade.
This release closes that gap. v1.1.0 introduces a full SMB 2.0 implementation, wraps it in a generic client that negotiates a connection once and routes traffic to the right dialect, and builds the first DCE/RPC and MS-SRVS layers on top of it. Alongside the new surface, I spent a good part of this cycle hardening the existing code against malformed and attacker-controlled input. This is the largest single release Manticore has had, so the sections below group the work by theme rather than enumerating every change.
A complete SMB 2.0 implementation
The headline of this release is smb_v20. I built it in phases, starting with the SMB2 header and packet envelope and then implementing all 19 commands. On top of the core request/response handling, the engine now covers the parts of the protocol that real-world servers actually exercise:
- File information:
QUERY_INFOandSET_INFO, backed by the MS-FSCC information-class structures, so you can read and write file, filesystem, and security metadata rather than just opening and closing handles. - IOCTL and named-pipe transceive, which is the piece that enables DCE/RPC over SMB2, and which the RPC and enumeration sections below build on.
- ECHO, FLUSH, and byte-range LOCK/UNLOCK, plus ECHO/CANCEL alongside CHANGE_NOTIFY for directory change subscriptions.
- Asynchronous
STATUS_PENDINGhandling and large read/write chunking, so long-running or oversized operations behave correctly instead of stalling or truncating. - OPLOCK_BREAK handling with oplock requests issued at
CREATEtime, and NextCommand compounding so multiple requests can be packed into a single send.
For security tooling this matters because SMB2 is no longer a dialect you have to work around: you can speak it natively. Named-pipe transceive in particular gives access to the RPC interfaces that drive most remote-administration and lateral-movement techniques, and having it in-library means no shelling out to an external client and no losing control over the wire format.
A generic SMB client that routes across dialects
Implementing SMB2 is only half the story if callers have to know in advance which dialect a target speaks. The new generic SMB client negotiates once and then routes to the SMB1, SMB2, or SMB3 engine based on what the server agreed to. Callers get a single API and a single authentication flow regardless of the negotiated dialect.
The client is wired to a new windows/fileflags package that centralises the Windows file open and attribute constants, so opening files and directories uses named, audited values instead of magic numbers. Directory parsing is delegated to the typed MS-FSCC parser rather than ad-hoc byte slicing, and the client exposes the negotiated connection capabilities, the server OS name and NTLMv2 support, and server identity captured from NTLM authentication. Those properties are exactly the kind of reconnaissance data you want as a side effect of simply connecting, fingerprinting the target during the handshake.
DCE/RPC and SMB enumeration
With named-pipe transceive in place, this release builds the RPC layer that sits above it. Manticore now has a ncacn_ip_tcp transport for DCE/RPC and a DCE/RPC endpoint mapper (epmapper) interface, so RPC interfaces can be reached both over SMB named pipes and directly over TCP, with the endpoint mapper resolving where a given interface is listening.
On top of that, I implemented SMB enumeration via the MS-SRVS interface (srvsvc):
- Share enumeration via
NetrShareEnum, - Session enumeration via
NetrSessionEnum, - Server information via
NetrServerGetInfo.
MS-SRVS now runs over the generic SMB client and therefore over any negotiated dialect, so the same enumeration code works whether the target speaks SMB1, SMB2, or SMB3. Share, session, and server enumeration are bread-and-butter operations for both attackers mapping a network and defenders inventorying exposure, and having them in a portable Go library makes them trivial to embed in custom tooling.
Security and reliability hardening
A protocol library is only as trustworthy as its behaviour on hostile input, and a large part of this cycle went into hardening. The fixes fall into a few categories.
Cryptographic enforcement. The SMB2 client previously accepted unsigned responses even when signing was active; it now rejects them. This is the difference between thinking you have an authenticated channel and actually having one.
Out-of-bounds and parsing safety on attacker-controlled input. I fixed an out-of-bounds slice on an attacker-controlled AVPair length in BuildBlobTargetInfo, an out-of-bounds index on an empty negState ENUMERATED in NegTokenResp.Unmarshal, and a WriteFile panic triggered by an oversized server-supplied write count. AvPair.Unmarshal now honours AvLen and returns the bytes it consumed. These are the kinds of bugs that let a malicious server crash (or worse) anything built on the library.
NTLM correctness. Several authentication bugs are fixed: NTLMv1 was ignoring the supplied LM hash when computing the LM challenge response, an NTLM DomainName case mismatch was breaking FQDN-based authentication, debug output was being written to stdout from NegotiateMessage.Unmarshal, and NT_STATUS.Error() was returning nil for unmapped non-success codes, masking real failures.
Connection and state-machine reliability. Negotiation no longer blocks when a server silently drops dialect probes, the SMB2 send/receive path no longer desyncs on unsolicited messages, the SMB1 AndX chain follower no longer loops forever on a cyclic chain, and SMB1 session setup now works against strict servers that reject an empty NativeOS field. SET_INFO setters no longer discard marshal errors. Individually small, together these make the stack behave predictably against the full range of conforming and non-conforming servers you encounter in the field.