mirror of
https://github.com/mandiant/gopacket
synced 2026-06-21 13:57:02 +00:00
100500df41
Fixes #8. smbclient's interactive shell now supports list_snapshots, which enumerates VSS shadow copies on the currently selected share via FSCTL_SRV_ENUMERATE_SNAPSHOTS. Matches Impacket smbclient.py's list_snapshots output format. The response follows MS-SMB2 2.2.32 and requires a two-call size probe: the first ioctl uses a 16-byte output buffer to read the SRV_SNAPSHOT_ARRAY header (SnapShotArraySize tells us how large the second buffer needs to be), then a second ioctl asks for the full payload and parses the UTF-16LE NUL-separated @GMT-... tokens. Changes: - pkg/third_party/smb2/client.go: add an exported Ioctl method on *File as a thin wrapper over the internal ioctl helper, so FSCTL operations beyond FSCTL_PIPE_TRANSCEIVE don't need their own dedicated method in the vendored library. - pkg/smb/client.go: EnumerateSnapshots() method on *Client. Handles the size-probe dance, parses the UTF-16LE token list via pkg/utf16le, returns []string. Empty slice when no snapshots exist. - tools/smbclient/main.go: wire list_snapshots into the shell's command switch and help text. Unblocks the VSS-based NTDS extraction path: use c$ list_snapshots # get @GMT-YYYY.MM.DD-HH.MM.SS get @GMT-...\Windows\NTDS\ntds.dit secretsdump -ntds ntds.dit -system SYSTEM
smb2
Description
SMB2/3 client implementation.
Installation
go get github.com/hirochachacha/go-smb2
Documentation
http://godoc.org/github.com/hirochachacha/go-smb2
Examples
List share names
package main
import (
"fmt"
"net"
"github.com/hirochachacha/go-smb2"
)
func main() {
conn, err := net.Dial("tcp", "SERVERNAME:445")
if err != nil {
panic(err)
}
defer conn.Close()
d := &smb2.Dialer{
Initiator: &smb2.NTLMInitiator{
User: "USERNAME",
Password: "PASSWORD",
},
}
s, err := d.Dial(conn)
if err != nil {
panic(err)
}
defer s.Logoff()
names, err := s.ListSharenames()
if err != nil {
panic(err)
}
for _, name := range names {
fmt.Println(name)
}
}
File manipulation
package main
import (
"io"
"io/ioutil"
"net"
"github.com/hirochachacha/go-smb2"
)
func main() {
conn, err := net.Dial("tcp", "SERVERNAME:445")
if err != nil {
panic(err)
}
defer conn.Close()
d := &smb2.Dialer{
Initiator: &smb2.NTLMInitiator{
User: "USERNAME",
Password: "PASSWORD",
},
}
s, err := d.Dial(conn)
if err != nil {
panic(err)
}
defer s.Logoff()
fs, err := s.Mount("SHARENAME")
if err != nil {
panic(err)
}
defer fs.Umount()
f, err := fs.Create("hello.txt")
if err != nil {
panic(err)
}
defer fs.Remove("hello.txt")
defer f.Close()
_, err = f.Write([]byte("Hello world!"))
if err != nil {
panic(err)
}
_, err = f.Seek(0, io.SeekStart)
if err != nil {
panic(err)
}
bs, err := ioutil.ReadAll(f)
if err != nil {
panic(err)
}
fmt.Println(string(bs))
}
Check error types
package main
import (
"context"
"fmt"
"net"
"os"
"github.com/hirochachacha/go-smb2"
)
func main() {
conn, err := net.Dial("tcp", "SERVERNAME:445")
if err != nil {
panic(err)
}
defer conn.Close()
d := &smb2.Dialer{
Initiator: &smb2.NTLMInitiator{
User: "USERNAME",
Password: "PASSWORD",
},
}
s, err := d.Dial(conn)
if err != nil {
panic(err)
}
defer s.Logoff()
fs, err := s.Mount("SHARENAME")
if err != nil {
panic(err)
}
defer fs.Umount()
_, err = fs.Open("notExist.txt")
fmt.Println(os.IsNotExist(err)) // true
fmt.Println(os.IsExist(err)) // false
fs.WriteFile("hello2.txt", []byte("test"), 0444)
err = fs.WriteFile("hello2.txt", []byte("test2"), 0444)
fmt.Println(os.IsPermission(err)) // true
ctx, cancel := context.WithTimeout(context.Background(), 0)
defer cancel()
_, err = fs.WithContext(ctx).Open("hello.txt")
fmt.Println(os.IsTimeout(err)) // true
}
Glob and WalkDir through FS interface
package main
import (
"fmt"
"net"
iofs "io/fs"
"github.com/hirochachacha/go-smb2"
)
func main() {
conn, err := net.Dial("tcp", "SERVERNAME:445")
if err != nil {
panic(err)
}
defer conn.Close()
d := &smb2.Dialer{
Initiator: &smb2.NTLMInitiator{
User: "USERNAME",
Password: "PASSWORD",
},
}
s, err := d.Dial(conn)
if err != nil {
panic(err)
}
defer s.Logoff()
fs, err := s.Mount("SHARENAME")
if err != nil {
panic(err)
}
defer fs.Umount()
matches, err := iofs.Glob(fs.DirFS("."), "*")
if err != nil {
panic(err)
}
for _, match := range matches {
fmt.Println(match)
}
err = iofs.WalkDir(fs.DirFS("."), ".", func(path string, d iofs.DirEntry, err error) error {
fmt.Println(path, d, err)
return nil
})
if err != nil {
panic(err)
}
}