mirror of
https://github.com/shadow1ng/fscan.git
synced 2026-09-22 03:10:42 +08:00
167 lines
4.0 KiB
Go
167 lines
4.0 KiB
Go
//go:build plugin_ms17010 || !plugin_selective
|
|
|
|
package services
|
|
|
|
import (
|
|
"context"
|
|
"net"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/shadow1ng/fscan/common"
|
|
)
|
|
|
|
func TestMS17010CheckDetectsVulnerableStatus(t *testing.T) {
|
|
addr, cleanup := startMS17010FakeServer(t, true, 45)
|
|
defer cleanup()
|
|
|
|
session := newMS17010TestSession()
|
|
vulnerable, _, _, err := NewMS17010Plugin().checkMS17010VulnerabilityAt(context.Background(), addr, session)
|
|
if err != nil {
|
|
t.Fatalf("checkMS17010VulnerabilityAt returned error: %v", err)
|
|
}
|
|
if !vulnerable {
|
|
t.Fatal("expected vulnerable status to be detected")
|
|
}
|
|
}
|
|
|
|
func TestMS17010CheckAcceptsMinimalSessionSetupResponse(t *testing.T) {
|
|
addr, cleanup := startMS17010FakeServer(t, true, 36)
|
|
defer cleanup()
|
|
|
|
session := newMS17010TestSession()
|
|
vulnerable, _, _, err := NewMS17010Plugin().checkMS17010VulnerabilityAt(context.Background(), addr, session)
|
|
if err != nil {
|
|
t.Fatalf("checkMS17010VulnerabilityAt returned error: %v", err)
|
|
}
|
|
if !vulnerable {
|
|
t.Fatal("expected vulnerable status to be detected")
|
|
}
|
|
}
|
|
|
|
func TestMS17010CheckRejectsPatchedStatus(t *testing.T) {
|
|
addr, cleanup := startMS17010FakeServer(t, false, 45)
|
|
defer cleanup()
|
|
|
|
session := newMS17010TestSession()
|
|
vulnerable, _, _, err := NewMS17010Plugin().checkMS17010VulnerabilityAt(context.Background(), addr, session)
|
|
if err != nil {
|
|
t.Fatalf("checkMS17010VulnerabilityAt returned error: %v", err)
|
|
}
|
|
if vulnerable {
|
|
t.Fatal("expected patched status to be treated as not vulnerable")
|
|
}
|
|
}
|
|
|
|
func TestMS17010CheckDetectsDoublePulsar(t *testing.T) {
|
|
addr, cleanup := startMS17010FakeServer(t, true, 45, withDoublePulsar())
|
|
defer cleanup()
|
|
|
|
session := newMS17010TestSession()
|
|
vulnerable, _, hasBackdoor, err := NewMS17010Plugin().checkMS17010VulnerabilityAt(context.Background(), addr, session)
|
|
if err != nil {
|
|
t.Fatalf("checkMS17010VulnerabilityAt returned error: %v", err)
|
|
}
|
|
if !vulnerable {
|
|
t.Fatal("expected vulnerable status to be detected")
|
|
}
|
|
if !hasBackdoor {
|
|
t.Fatal("expected DOUBLEPULSAR status to be detected")
|
|
}
|
|
}
|
|
|
|
func newMS17010TestSession() *common.ScanSession {
|
|
cfg := common.NewConfig()
|
|
cfg.Timeout = time.Second
|
|
return common.NewScanSession(cfg, common.NewState(), &common.FlagVars{})
|
|
}
|
|
|
|
type ms17010FakeServerOption func(*ms17010FakeServerConfig)
|
|
|
|
type ms17010FakeServerConfig struct {
|
|
doublePulsar bool
|
|
}
|
|
|
|
func withDoublePulsar() ms17010FakeServerOption {
|
|
return func(cfg *ms17010FakeServerConfig) {
|
|
cfg.doublePulsar = true
|
|
}
|
|
}
|
|
|
|
func startMS17010FakeServer(t *testing.T, vulnerable bool, sessionSetupSize int, opts ...ms17010FakeServerOption) (string, func()) {
|
|
t.Helper()
|
|
|
|
var cfg ms17010FakeServerConfig
|
|
for _, opt := range opts {
|
|
opt(&cfg)
|
|
}
|
|
|
|
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
|
if err != nil {
|
|
t.Fatalf("listen: %v", err)
|
|
}
|
|
|
|
done := make(chan struct{})
|
|
go func() {
|
|
defer close(done)
|
|
conn, err := ln.Accept()
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer conn.Close()
|
|
|
|
responses := [][]byte{
|
|
makeMS17010Response(36),
|
|
makeMS17010Response(sessionSetupSize),
|
|
makeMS17010Response(36),
|
|
makeMS17010Response(36),
|
|
}
|
|
if len(responses[1]) >= 34 {
|
|
responses[1][32] = 0x34
|
|
responses[1][33] = 0x12
|
|
}
|
|
responses[2][28] = 0x78
|
|
responses[2][29] = 0x56
|
|
if vulnerable {
|
|
responses[3][9] = 0x05
|
|
responses[3][10] = 0x02
|
|
responses[3][11] = 0x00
|
|
responses[3][12] = 0xc0
|
|
responses = append(responses, makeMS17010Response(36))
|
|
if cfg.doublePulsar {
|
|
responses[4][34] = 0x51
|
|
}
|
|
}
|
|
|
|
buf := make([]byte, 4096)
|
|
for _, response := range responses {
|
|
_ = conn.SetDeadline(time.Now().Add(time.Second))
|
|
if _, err := conn.Read(buf); err != nil {
|
|
return
|
|
}
|
|
if _, err := conn.Write(response); err != nil {
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
|
|
cleanup := func() {
|
|
_ = ln.Close()
|
|
select {
|
|
case <-done:
|
|
case <-time.After(time.Second):
|
|
t.Fatal("fake server did not exit")
|
|
}
|
|
}
|
|
|
|
return ln.Addr().String(), cleanup
|
|
}
|
|
|
|
func makeMS17010Response(size int) []byte {
|
|
resp := make([]byte, size)
|
|
if size >= 4 {
|
|
resp[3] = byte(size - 4)
|
|
}
|
|
return resp
|
|
}
|