mirror of
https://github.com/shadow1ng/fscan.git
synced 2026-09-26 05:01:53 +08:00
Harden scan robustness and tests
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
//go:build plugin_nfs || !plugin_selective
|
||||
|
||||
package services
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type nfsTestConn struct {
|
||||
data []byte
|
||||
chunkSize int
|
||||
w bytes.Buffer
|
||||
}
|
||||
|
||||
func (c *nfsTestConn) Read(p []byte) (int, error) {
|
||||
if len(c.data) == 0 {
|
||||
return 0, io.EOF
|
||||
}
|
||||
n := len(c.data)
|
||||
if c.chunkSize > 0 && n > c.chunkSize {
|
||||
n = c.chunkSize
|
||||
}
|
||||
if n > len(p) {
|
||||
n = len(p)
|
||||
}
|
||||
copy(p, c.data[:n])
|
||||
c.data = c.data[n:]
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (c *nfsTestConn) Write(p []byte) (int, error) { return c.w.Write(p) }
|
||||
|
||||
func TestNFSRPCNullCallHandlesFragmentedReads(t *testing.T) {
|
||||
p := NewNFSPlugin()
|
||||
xid := uint32(0x12340000 + 100003)
|
||||
reply := make([]byte, 24)
|
||||
binary.BigEndian.PutUint32(reply[0:4], xid)
|
||||
binary.BigEndian.PutUint32(reply[4:8], 1)
|
||||
|
||||
if err := p.rpcNullCall(&nfsTestConn{data: wrapNFSReply(reply), chunkSize: 2}, 100003, 3); err != nil {
|
||||
t.Fatalf("rpcNullCall() error = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNFSGetExportsHandlesVerifierPadding(t *testing.T) {
|
||||
p := NewNFSPlugin()
|
||||
var reply []byte
|
||||
reply = binary.BigEndian.AppendUint32(reply, 0x12345678) // xid
|
||||
reply = binary.BigEndian.AppendUint32(reply, 1) // reply
|
||||
reply = binary.BigEndian.AppendUint32(reply, 0) // accepted
|
||||
reply = binary.BigEndian.AppendUint32(reply, 0) // verifier flavor
|
||||
reply = binary.BigEndian.AppendUint32(reply, 3) // verifier length
|
||||
reply = append(reply, 'a', 'b', 'c', 0) // padded verifier
|
||||
reply = binary.BigEndian.AppendUint32(reply, 0) // accept success
|
||||
reply = binary.BigEndian.AppendUint32(reply, 1) // export follows
|
||||
reply = binary.BigEndian.AppendUint32(reply, 2) // path length
|
||||
reply = append(reply, '/', 'x', 0, 0) // padded path
|
||||
reply = binary.BigEndian.AppendUint32(reply, 0) // no groups
|
||||
reply = binary.BigEndian.AppendUint32(reply, 0) // no more exports
|
||||
|
||||
exports, err := p.getExports(&nfsTestConn{data: wrapNFSReply(reply), chunkSize: 3})
|
||||
if err != nil {
|
||||
t.Fatalf("getExports() error = %v", err)
|
||||
}
|
||||
if len(exports) != 1 || exports[0] != "/x" {
|
||||
t.Fatalf("exports = %#v, want [/x]", exports)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNFSReadRPCFragmentRejectsInvalidSize(t *testing.T) {
|
||||
header := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(header, 0x80000000)
|
||||
if _, err := readRPCFragment(&nfsTestConn{data: header}, 4096); err == nil {
|
||||
t.Fatal("readRPCFragment() error = nil, want invalid zero-size fragment error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNFSParseExportListStopsOnTruncatedGroup(t *testing.T) {
|
||||
p := NewNFSPlugin()
|
||||
var data []byte
|
||||
data = binary.BigEndian.AppendUint32(data, 1)
|
||||
data = binary.BigEndian.AppendUint32(data, 2)
|
||||
data = append(data, '/', 'x', 0, 0)
|
||||
data = binary.BigEndian.AppendUint32(data, 1)
|
||||
data = binary.BigEndian.AppendUint32(data, 100)
|
||||
|
||||
exports := p.parseExportList(data)
|
||||
if len(exports) != 1 || exports[0] != "/x" {
|
||||
t.Fatalf("exports = %#v, want [/x]", exports)
|
||||
}
|
||||
}
|
||||
|
||||
func wrapNFSReply(payload []byte) []byte {
|
||||
out := make([]byte, 4+len(payload))
|
||||
binary.BigEndian.PutUint32(out[:4], uint32(len(payload))|0x80000000)
|
||||
copy(out[4:], payload)
|
||||
return out
|
||||
}
|
||||
Reference in New Issue
Block a user