Compare commits

..
Author SHA1 Message Date
Mzack9999 8903942700 bump rod 2026-11-13 16:03:50 +01:00
Mzack9999 aec1420bdb rod module 2026-11-13 14:41:54 +01:00
20 changed files with 40 additions and 429 deletions

No files matched your search

+2 -6
View File
@@ -1,6 +1,6 @@
module github.com/projectdiscovery/nuclei/v3
go 1.27.3
go 1.27.4
require (
carvel.dev/ytt v0.52.0
@@ -46,7 +46,6 @@ require (
github.com/go-pdf/fpdf v0.9.0
github.com/go-pg/pg/v10 v10.15.0
github.com/go-playground/validator/v10 v10.26.0
github.com/go-rod/rod v0.116.2
github.com/go-sql-driver/mysql v1.10.0
github.com/gobwas/ws v1.4.0
github.com/goccy/go-json v0.10.5
@@ -102,6 +101,7 @@ require (
github.com/projectdiscovery/rdap v0.9.0
github.com/projectdiscovery/retryabledns v1.0.116
github.com/projectdiscovery/retryablehttp-go v1.3.31
github.com/projectdiscovery/rod v0.116.3-0.20261113150229-d775599ff53d
github.com/projectdiscovery/sarif v0.1.0
github.com/projectdiscovery/tlsx v1.4.3-0.20261020052910-acb80c2c7c75
github.com/projectdiscovery/uncover v1.2.1
@@ -427,11 +427,7 @@ require (
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
github.com/ysmood/fetchup v0.2.3 // indirect
github.com/ysmood/goob v0.4.0 // indirect
github.com/ysmood/got v0.40.0 // indirect
github.com/ysmood/gson v0.7.3 // indirect
github.com/ysmood/leakless v0.9.0 // indirect
github.com/yuin/goldmark v1.7.17 // indirect
github.com/yuin/goldmark-emoji v1.0.6 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
+6 -12
View File
@@ -493,8 +493,6 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k=
github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
github.com/go-rod/rod v0.116.2 h1:A5t2Ky2A+5eD/ZJQr1EfsQSe5rms5Xof/qj296e+ZqA=
github.com/go-rod/rod v0.116.2/go.mod h1:H+CMO9SCNc2TJ2WfrG+pKhITz57uGNYU43qYHh438Mg=
github.com/go-sourcemap/sourcemap v2.1.4+incompatible h1:a+iTbH5auLKxaNwQFg0B+TCYl6lbukKPc7b5x0n1s6Q=
github.com/go-sourcemap/sourcemap v2.1.4+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
github.com/go-sql-driver/mysql v1.10.0 h1:Q+1LV8DkHJvSYAdR83XzuhDaTykuDx0l6fkXxoWCWfw=
@@ -985,6 +983,8 @@ github.com/projectdiscovery/retryabledns v1.0.116 h1:tK28PJ4tLO7bgM89RpIFjkfTPMS
github.com/projectdiscovery/retryabledns v1.0.116/go.mod h1:r3vH0AKYtJ9fculcqRFrdVYe2ABcHwZeR4C6j3rqCbY=
github.com/projectdiscovery/retryablehttp-go v1.3.31 h1:0hSEZ5+jj6Oo1IL8qrytD36TK/qCxfe543jEaRqSTjs=
github.com/projectdiscovery/retryablehttp-go v1.3.31/go.mod h1:/WEa7YejxTCXEMLCGfGYaC3JsgXgzuqw8rv8cb4buEc=
github.com/projectdiscovery/rod v0.116.3-0.20261113150229-d775599ff53d h1:6mwNBdlYWe0hu1/QLLhIrZiz+G1JYsU7OIVmCOaF+q0=
github.com/projectdiscovery/rod v0.116.3-0.20261113150229-d775599ff53d/go.mod h1:FLVLMgXw6OFcOU5nd4Il8cdSWgDfAlDeRZMol3drmGs=
github.com/projectdiscovery/sarif v0.1.0 h1:O541T+a448nSJsmIMnXXSOeDQEzpnCAYvRfe0eG5h74=
github.com/projectdiscovery/sarif v0.1.0/go.mod h1:LBC+reM3bkI3qIIhE0rZaINaYX6VG+En6u2hHa5mA7E=
github.com/projectdiscovery/stringsutil v0.0.2 h1:uzmw3IVLJSMW1kEg8eCStG/cGbYYZAja8BH3LqqJXMA=
@@ -1212,20 +1212,14 @@ github.com/yl2chen/cidranger v1.0.2 h1:lbOWZVCG1tCRX4u24kuM1Tb4nHqWkDxwLdoS+Seva
github.com/yl2chen/cidranger v1.0.2/go.mod h1:9U1yz7WPYDwf0vpNWFaeRh0bjwz5RVgRy/9UEQfHl0g=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
github.com/ysmood/fetchup v0.2.3 h1:ulX+SonA0Vma5zUFXtv52Kzip/xe7aj4vqT5AJwQ+ZQ=
github.com/ysmood/fetchup v0.2.3/go.mod h1:xhibcRKziSvol0H1/pj33dnKrYyI2ebIvz5cOOkYGns=
github.com/ysmood/goob v0.4.0 h1:HsxXhyLBeGzWXnqVKtmT9qM7EuVs/XOgkX7T6r1o1AQ=
github.com/ysmood/goob v0.4.0/go.mod h1:u6yx7ZhS4Exf2MwciFr6nIM8knHQIE22lFpWHnfql18=
github.com/ysmood/gop v0.2.0 h1:+tFrG0TWPxT6p9ZaZs+VY+opCvHU8/3Fk6BaNv6kqKg=
github.com/ysmood/gop v0.2.0/go.mod h1:rr5z2z27oGEbyB787hpEcx4ab8cCiPnKxn0SUHt6xzk=
github.com/ysmood/got v0.40.0 h1:ZQk1B55zIvS7zflRrkGfPDrPG3d7+JOza1ZkNxcc74Q=
github.com/ysmood/got v0.40.0/go.mod h1:W7DdpuX6skL3NszLmAsC5hT7JAhuLZhByVzHTq874Qg=
github.com/ysmood/gop v0.4.2 h1:KtW1/RugapWs1iW9ynQdk52BK6TWdP9zC0qDOhW8EDE=
github.com/ysmood/gop v0.4.2/go.mod h1:K4LAB/BdLArknXrVSy+DyXcfb8P85JwAtwYM8zlb0mU=
github.com/ysmood/got v0.43.0 h1:bcHlKg+qnhFz5JxNZ+j4fIfxxB8WWjTh6qdqeS8FfZw=
github.com/ysmood/got v0.43.0/go.mod h1:rsfH2KJ5rcS/5n9pmybIGodoHlT/NTYxjgh3ob7UdSU=
github.com/ysmood/gotrace v0.6.0 h1:SyI1d4jclswLhg7SWTL6os3L1WOKeNn/ZtzVQF8QmdY=
github.com/ysmood/gotrace v0.6.0/go.mod h1:TzhIG7nHDry5//eYZDYcTzuJLYQIkykJzCRIo4/dzQM=
github.com/ysmood/gson v0.7.3 h1:QFkWbTH8MxyUTKPkVWAENJhxqdBa4lYTQWqZCiLG6kE=
github.com/ysmood/gson v0.7.3/go.mod h1:3Kzs5zDl21g5F/BlLTNcuAGAYLKt2lV5G8D1zF3RNmg=
github.com/ysmood/leakless v0.9.0 h1:qxCG5VirSBvmi3uynXFkcnLMzkphdh3xx5FtrORwDCU=
github.com/ysmood/leakless v0.9.0/go.mod h1:R8iAXPRaG97QJwqxs74RdwzcRHT1SWCGTNqY8q0JvMQ=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@@ -1,130 +0,0 @@
package kerberos
import (
"strings"
"testing"
"github.com/jcmturner/gokrb5/v8/messages"
"github.com/jcmturner/gokrb5/v8/types"
)
// buildTicketWithCipher creates a messages.Ticket whose EncPart.Cipher has the
// given length. The TktVNO, Realm and SName fields are filled with minimal
// valid values so the function does not panic before it reaches Cipher access.
func buildTicketWithCipher(cipherLen int) messages.Ticket {
cipher := make([]byte, cipherLen)
for i := range cipher {
cipher[i] = byte(i & 0xff)
}
return messages.Ticket{
TktVNO: 5,
Realm: "TEST.REALM",
SName: types.PrincipalName{
NameType: 1,
NameString: []string{"host", "server.test.realm"},
},
EncPart: types.EncryptedData{
EType: 17,
Cipher: cipher,
},
}
}
// buildASRepWithCipher creates a messages.ASRep whose EncPart.Cipher has the
// given length.
func buildASRepWithCipher(cipherLen int) messages.ASRep {
cipher := make([]byte, cipherLen)
for i := range cipher {
cipher[i] = byte(i & 0xff)
}
rep := messages.ASRep{}
rep.EncPart = types.EncryptedData{
EType: 17,
Cipher: cipher,
}
rep.CName = types.PrincipalName{
NameType: 1,
NameString: []string{"testuser"},
}
rep.CRealm = "TEST.REALM"
return rep
}
// --- TGStoHashcat ---
// TestTGStoHashcat_NoPanicOnShortCipher is the regression test.
// Without the bounds check, TGStoHashcat panics with:
//
// runtime error: slice bounds out of range [:16] with length N (N < 16)
//
// With the fix it must return an error instead.
func TestTGStoHashcat_NoPanicOnShortCipher(t *testing.T) {
for cipherLen := 0; cipherLen < 16; cipherLen++ {
cipherLen := cipherLen // capture
t.Run("", func(t *testing.T) {
tgs := buildTicketWithCipher(cipherLen)
result, err := TGStoHashcat(tgs, "user")
if err == nil {
t.Errorf("cipher length %d: expected error, got hashcat string %q", cipherLen, result)
}
if !strings.Contains(err.Error(), "too short") {
t.Errorf("cipher length %d: unexpected error message %q", cipherLen, err.Error())
}
})
}
}
// TestTGStoHashcat_Valid_16Bytes confirms that a cipher of exactly 16 bytes succeeds.
func TestTGStoHashcat_Valid_16Bytes(t *testing.T) {
tgs := buildTicketWithCipher(16)
result, err := TGStoHashcat(tgs, "user")
if err != nil {
t.Fatalf("unexpected error for 16-byte cipher: %v", err)
}
if !strings.HasPrefix(result, "$krb5tgs$") {
t.Errorf("unexpected hash format: %q", result)
}
}
// TestTGStoHashcat_Valid_Large confirms that a larger cipher also succeeds.
func TestTGStoHashcat_Valid_Large(t *testing.T) {
tgs := buildTicketWithCipher(256)
result, err := TGStoHashcat(tgs, "user")
if err != nil {
t.Fatalf("unexpected error for 256-byte cipher: %v", err)
}
if !strings.HasPrefix(result, "$krb5tgs$") {
t.Errorf("unexpected hash format: %q", result)
}
}
// --- ASRepToHashcat ---
// TestASRepToHashcat_NoPanicOnShortCipher is the regression test for ASRep.
func TestASRepToHashcat_NoPanicOnShortCipher(t *testing.T) {
for cipherLen := 0; cipherLen < 16; cipherLen++ {
cipherLen := cipherLen
t.Run("", func(t *testing.T) {
asrep := buildASRepWithCipher(cipherLen)
result, err := ASRepToHashcat(asrep)
if err == nil {
t.Errorf("cipher length %d: expected error, got hashcat string %q", cipherLen, result)
}
if !strings.Contains(err.Error(), "too short") {
t.Errorf("cipher length %d: unexpected error message %q", cipherLen, err.Error())
}
})
}
}
// TestASRepToHashcat_Valid_16Bytes confirms that a cipher of exactly 16 bytes succeeds.
func TestASRepToHashcat_Valid_16Bytes(t *testing.T) {
asrep := buildASRepWithCipher(16)
result, err := ASRepToHashcat(asrep)
if err != nil {
t.Fatalf("unexpected error for 16-byte cipher: %v", err)
}
if !strings.HasPrefix(result, "$krb5asrep$") {
t.Errorf("unexpected hash format: %q", result)
}
}
+2 -24
View File
@@ -167,11 +167,6 @@ func sendUDP(conn *net.UDPConn, b []byte) ([]byte, error) {
return r, nil
}
// maxKDCResponseSize caps the per-response allocation for a KDC TCP reply.
// RFC 4120 §7.2.2 uses a 4-byte big-endian length which could otherwise
// be set to 4 GB by a malicious or spoofed peer causing OOM.
const maxKDCResponseSize = 1 << 20 // 1 MiB
// sendTCP sends bytes to connection over TCP.
func sendTCP(conn *net.TCPConn, b []byte) ([]byte, error) {
defer func() {
@@ -189,18 +184,12 @@ func sendTCP(conn *net.TCPConn, b []byte) ([]byte, error) {
}
sh := make([]byte, 4)
// Use io.ReadFull to guarantee all 4 header bytes are read.
_, err = io.ReadFull(conn, sh)
_, err = conn.Read(sh)
if err != nil {
return r, fmt.Errorf("error reading response size header: %v", err)
}
s := binary.BigEndian.Uint32(sh)
// Reject unreasonably large responses before allocating.
if s > maxKDCResponseSize {
return r, fmt.Errorf("kdc response too large: %d bytes (max %d)", s, maxKDCResponseSize)
}
rb := make([]byte, s)
_, err = io.ReadFull(conn, rb)
if err != nil {
@@ -222,13 +211,7 @@ func CheckKrbError(b []byte) ([]byte, error) {
}
// TGStoHashcat converts a TGS to a hashcat format.
// The hashcat $krb5tgs$ format splits EncPart.Cipher into a 16-byte HMAC
// prefix and the remaining ciphertext. A cipher shorter than 16 bytes
// would cause a slice-bounds panic; guard against truncated KDC replies.
func TGStoHashcat(tgs messages.Ticket, username string) (string, error) {
if len(tgs.EncPart.Cipher) < 16 {
return "", fmt.Errorf("tgs cipher too short: need at least 16 bytes, got %d", len(tgs.EncPart.Cipher))
}
return fmt.Sprintf("$krb5tgs$%d$*%s$%s$%s*$%s$%s",
tgs.EncPart.EType,
username,
@@ -239,13 +222,8 @@ func TGStoHashcat(tgs messages.Ticket, username string) (string, error) {
), nil
}
// ASRepToHashcat converts an AS-REP message to a hashcat format.
// A cipher shorter than 16 bytes from a truncated KDC reply would cause
// a slice-bounds panic on Cipher[:16]; check before indexing.
// ASRepToHashcat converts an AS-REP message to a hashcat format
func ASRepToHashcat(asrep messages.ASRep) (string, error) {
if len(asrep.EncPart.Cipher) < 16 {
return "", fmt.Errorf("as-rep cipher too short: need at least 16 bytes, got %d", len(asrep.EncPart.Cipher))
}
return fmt.Sprintf("$krb5asrep$%d$%s@%s:%s$%s",
asrep.EncPart.EType,
asrep.CName.PrincipalNameString(),
-120
View File
@@ -1,120 +0,0 @@
package kerberos
import (
"encoding/binary"
"io"
"net"
"testing"
"time"
)
// serveKDCTCP is a minimal fake KDC that:
// 1. Reads the full framed Kerberos request from the client.
// 2. Writes a 4-byte big-endian length header containing bodyLen.
// 3. If bodyLen <= maxKDCResponseSize, writes exactly bodyLen bytes of body.
// For oversized values, only the header is sent (simulating a rogue peer).
func serveKDCTCP(ln net.Listener, bodyLen uint32) {
conn, err := ln.Accept()
if err != nil {
return
}
defer func() { _ = conn.Close() }()
_ = conn.SetDeadline(time.Now().Add(5 * time.Second))
// Drain the client's framed Kerberos request (4-byte length + body).
hdr := make([]byte, 4)
if _, err := io.ReadFull(conn, hdr); err != nil {
return
}
msgLen := binary.BigEndian.Uint32(hdr)
if msgLen > 0 && msgLen < 65536 {
body := make([]byte, msgLen)
_, _ = io.ReadFull(conn, body)
}
// Send the response length header.
rhdr := make([]byte, 4)
binary.BigEndian.PutUint32(rhdr, bodyLen)
_, _ = conn.Write(rhdr)
// Only write the body for valid sizes; for oversized we expect the client
// to reject the size before reading anything.
if bodyLen > 0 && bodyLen <= maxKDCResponseSize {
respBody := make([]byte, bodyLen)
respBody[0] = 0x01 // non-empty sentinel
_, _ = conn.Write(respBody)
}
}
// TestSendTCP_OversizedResponseRejected verifies that sendTCP returns an error
// when a spoofed KDC advertises a response body larger than maxKDCResponseSize,
// rather than allocating that many bytes and causing an OOM.
//
// Without the bounds check the code does:
//
// rb := make([]byte, s) // s == bodyLen, up to 2^32-1 bytes
//
// which would allocate up to 4 GiB per call.
func TestSendTCP_OversizedResponseRejected(t *testing.T) {
ln, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatalf("failed to listen: %v", err)
}
defer func() { _ = ln.Close() }()
oversized := uint32(maxKDCResponseSize + 1)
go serveKDCTCP(ln, oversized)
conn, err := net.DialTimeout("tcp", ln.Addr().String(), 3*time.Second)
if err != nil {
t.Fatalf("dial failed: %v", err)
}
tcpConn, ok := conn.(*net.TCPConn)
if !ok {
_ = conn.Close()
t.Fatalf("expected *net.TCPConn, got %T", conn)
}
// Set a generous timeout so the test does not hang.
_ = tcpConn.SetDeadline(time.Now().Add(10 * time.Second))
_, err = sendTCP(tcpConn, []byte{0x01})
if err == nil {
t.Fatal("expected error for oversized KDC response, got nil")
}
t.Logf("correctly rejected oversized response: %v", err)
}
// TestSendTCP_SmallValidResponseSucceeds confirms that sendTCP succeeds when
// the KDC returns a small, valid body.
func TestSendTCP_SmallValidResponseSucceeds(t *testing.T) {
ln, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatalf("failed to listen: %v", err)
}
defer func() { _ = ln.Close() }()
validLen := uint32(32)
go serveKDCTCP(ln, validLen)
conn, err := net.DialTimeout("tcp", ln.Addr().String(), 3*time.Second)
if err != nil {
t.Fatalf("dial failed: %v", err)
}
tcpConn, ok := conn.(*net.TCPConn)
if !ok {
_ = conn.Close()
t.Fatalf("expected *net.TCPConn, got %T", conn)
}
_ = tcpConn.SetDeadline(time.Now().Add(10 * time.Second))
resp, err := sendTCP(tcpConn, []byte{0x01})
if err != nil {
t.Fatalf("unexpected error for valid %d-byte KDC response: %v", validLen, err)
}
if len(resp) != int(validLen) {
t.Errorf("expected %d bytes, got %d", validLen, len(resp))
}
}
-11
View File
@@ -16,12 +16,6 @@ import (
const (
pkt = "\x00\x00\x00\xc0\xfeSMB@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$\x00\x08\x00\x01\x00\x00\x00\x7f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00x\x00\x00\x00\x02\x00\x00\x00\x02\x02\x10\x02\"\x02$\x02\x00\x03\x02\x03\x10\x03\x11\x03\x00\x00\x00\x00\x01\x00&\x00\x00\x00\x00\x00\x01\x00 \x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\n\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00"
// maxSMBGhostBodySize caps the per-connection allocation when reading the
// SMBv3 negotiate response body. The 4-byte NetBIOS length field is
// controlled by the remote peer; without this cap a malicious or spoofed
// server can claim a giant body and trigger an OOM/DoS.
maxSMBGhostBodySize = 10 * 1024 * 1024 // 10 MiB
)
// DetectSMBGhost tries to detect SMBGhost vulnerability
@@ -71,11 +65,6 @@ func detectSMBGhost(ctx context.Context, executionId string, host string, port i
}
length := args[0].(int)
// Guard against a malicious or spoofed server advertising a giant body:
// ConnReadNWithTimeout allocates `length` bytes before reading.
if length <= 0 || length > maxSMBGhostBodySize {
return false, fmt.Errorf("unexpected smbghost response body length %d (max %d)", length, maxSMBGhostBodySize)
}
_ = conn.SetReadDeadline(time.Now().Add(2 * time.Second))
data, err := reader.ConnReadNWithTimeout(conn, int64(length), time.Duration(5)*time.Second)
if err != nil {
-96
View File
@@ -1,96 +0,0 @@
package smb
import (
"encoding/binary"
"fmt"
"io"
"net"
"testing"
"time"
)
// serveGhostPacket is a minimal fake SMB server that:
// 1. Reads the probe packet from the client (and discards it).
// 2. Writes a 4-byte NetBIOS length header containing bodyLen.
// 3. If bodyLen > 0 and <= maxSMBGhostBodySize, writes exactly bodyLen bytes of body.
// For oversized values, only the header is sent (simulating a rogue peer).
func serveGhostPacket(ln net.Listener, bodyLen uint32) {
conn, err := ln.Accept()
if err != nil {
return
}
defer func() { _ = conn.Close() }()
_ = conn.SetDeadline(time.Now().Add(5 * time.Second))
// Drain the probe packet the client sends.
buf := make([]byte, 512)
_, _ = conn.Read(buf)
// Send the 4-byte length header.
hdr := make([]byte, 4)
binary.BigEndian.PutUint32(hdr, bodyLen)
_, _ = conn.Write(hdr)
if bodyLen > 0 && bodyLen <= maxSMBGhostBodySize {
// Send a valid-length body (all zeros).
body := make([]byte, bodyLen)
_, _ = conn.Write(body)
}
// For the giant bodyLen case we intentionally do NOT write a body;
// the fix should reject it before attempting to read.
}
// TestDetectSMBGhost_OversizedLengthIsRejected verifies that a spoofed server
// advertising a body length larger than maxSMBGhostBodySize is rejected with
// an error instead of causing an OOM allocation.
//
// Without the bounds check, detectSMBGhost would call
// reader.ConnReadNWithTimeout(conn, int64(length), ...) with a 2 GB value,
// allocating a ~2 GB byte slice on each request.
func TestDetectSMBGhost_OversizedLengthIsRejected(t *testing.T) {
ln, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatalf("failed to start listener: %v", err)
}
defer func() { _ = ln.Close() }()
oversizedLen := uint32(maxSMBGhostBodySize + 1)
go serveGhostPacket(ln, oversizedLen)
addr := ln.Addr().String()
_, portStr, _ := net.SplitHostPort(addr)
var port int
fmt.Sscanf(portStr, "%d", &port)
// Use a raw TCP connection to call detectSMBGhost so we don't need a
// real executionId / network-policy setup.
conn, err := net.DialTimeout("tcp", addr, 3*time.Second)
if err != nil {
t.Fatalf("dial failed: %v", err)
}
defer func() { _ = conn.Close() }()
// Reproduce detectSMBGhost's NetBIOS-length read logic so we can call
// the same guard path.
_ = conn.SetDeadline(time.Now().Add(3 * time.Second))
_, _ = conn.Write([]byte(pkt))
hdr := make([]byte, 4)
_, err = io.ReadFull(conn, hdr)
if err != nil {
t.Fatalf("failed to read header: %v", err)
}
length := int(binary.BigEndian.Uint32(hdr))
// Apply the same guard as the fix.
if length <= 0 || length > maxSMBGhostBodySize {
// This is the correct path — the fix catches it before allocating.
t.Logf("oversized length %d correctly rejected (max %d)", length, maxSMBGhostBodySize)
return
}
t.Errorf("length %d should have been rejected but was not (max %d)", length, maxSMBGhostBodySize)
}
@@ -7,10 +7,10 @@ import (
"strings"
"sync"
"github.com/go-rod/rod"
"github.com/go-rod/rod/lib/proto"
"github.com/projectdiscovery/networkpolicy"
"github.com/projectdiscovery/nuclei/v3/pkg/types"
"github.com/projectdiscovery/rod"
"github.com/projectdiscovery/rod/lib/proto"
"github.com/projectdiscovery/utils/errkit"
stringsutil "github.com/projectdiscovery/utils/strings"
urlutil "github.com/projectdiscovery/utils/url"
@@ -15,7 +15,7 @@ func TestMemGuardianGoroutineLeak(t *testing.T) {
defer goleak.VerifyNone(t,
goleak.IgnoreAnyContainingPkg("go.opencensus.io/stats/view"),
goleak.IgnoreAnyContainingPkg("github.com/syndtr/goleveldb"),
goleak.IgnoreAnyContainingPkg("github.com/go-rod/rod"),
goleak.IgnoreAnyContainingPkg("github.com/projectdiscovery/rod"),
goleak.IgnoreAnyContainingPkg("github.com/projectdiscovery/interactsh/pkg/server"),
goleak.IgnoreAnyContainingPkg("github.com/projectdiscovery/ratelimit"),
// expirable LRU cache creates a background goroutine for TTL expiration that persists
@@ -104,7 +104,7 @@ func TestMemGuardianReset(t *testing.T) {
defer goleak.VerifyNone(t,
goleak.IgnoreAnyContainingPkg("go.opencensus.io/stats/view"),
goleak.IgnoreAnyContainingPkg("github.com/syndtr/goleveldb"),
goleak.IgnoreAnyContainingPkg("github.com/go-rod/rod"),
goleak.IgnoreAnyContainingPkg("github.com/projectdiscovery/rod"),
goleak.IgnoreAnyContainingPkg("github.com/projectdiscovery/interactsh/pkg/server"),
goleak.IgnoreAnyContainingPkg("github.com/projectdiscovery/ratelimit"),
// expirable LRU cache creates a background goroutine for TTL expiration that persists
+3 -3
View File
@@ -7,10 +7,10 @@ import (
"strings"
"sync"
"github.com/go-rod/rod"
"github.com/go-rod/rod/lib/launcher"
"github.com/go-rod/rod/lib/launcher/flags"
"github.com/pkg/errors"
"github.com/projectdiscovery/rod"
"github.com/projectdiscovery/rod/lib/launcher"
"github.com/projectdiscovery/rod/lib/launcher/flags"
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v3/pkg/types"
+2 -2
View File
@@ -5,8 +5,8 @@ package engine
import (
"encoding/base64"
"github.com/go-rod/rod"
"github.com/go-rod/rod/lib/proto"
"github.com/projectdiscovery/rod"
"github.com/projectdiscovery/rod/lib/proto"
)
// NewHijack create hijack from page.
+2 -2
View File
@@ -5,11 +5,11 @@ import (
"errors"
"time"
"github.com/go-rod/rod"
"github.com/go-rod/rod/lib/utils"
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/interactsh"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/render"
"github.com/projectdiscovery/rod"
"github.com/projectdiscovery/rod/lib/utils"
)
// Instance is an isolated browser instance opened for doing operations with it.
@@ -5,9 +5,9 @@ import (
"testing"
"time"
"github.com/go-rod/rod"
"github.com/go-rod/rod/lib/cdp"
"github.com/go-rod/rod/lib/proto"
"github.com/projectdiscovery/rod"
"github.com/projectdiscovery/rod/lib/cdp"
"github.com/projectdiscovery/rod/lib/proto"
"github.com/stretchr/testify/require"
)
+2 -2
View File
@@ -11,8 +11,6 @@ import (
"sync"
"time"
"github.com/go-rod/rod"
"github.com/go-rod/rod/lib/proto"
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/generators"
@@ -21,6 +19,8 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/utils"
httputil "github.com/projectdiscovery/nuclei/v3/pkg/protocols/utils/http"
"github.com/projectdiscovery/nuclei/v3/pkg/types"
"github.com/projectdiscovery/rod"
"github.com/projectdiscovery/rod/lib/proto"
"github.com/projectdiscovery/utils/errkit"
urlutil "github.com/projectdiscovery/utils/url"
)
@@ -11,10 +11,6 @@ import (
"sync"
"time"
"github.com/go-rod/rod"
"github.com/go-rod/rod/lib/input"
"github.com/go-rod/rod/lib/proto"
"github.com/go-rod/rod/lib/utils"
"github.com/kitabisa/go-ci"
"github.com/pkg/errors"
"github.com/projectdiscovery/gologger"
@@ -24,6 +20,10 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/render"
"github.com/projectdiscovery/nuclei/v3/pkg/types"
filepathutil "github.com/projectdiscovery/nuclei/v3/pkg/utils/filepath"
"github.com/projectdiscovery/rod"
"github.com/projectdiscovery/rod/lib/input"
"github.com/projectdiscovery/rod/lib/proto"
"github.com/projectdiscovery/rod/lib/utils"
contextutil "github.com/projectdiscovery/utils/context"
"github.com/projectdiscovery/utils/errkit"
fileutil "github.com/projectdiscovery/utils/file"
+3 -3
View File
@@ -11,12 +11,12 @@ import (
"testing"
"time"
"github.com/go-rod/rod"
"github.com/go-rod/rod/lib/cdp"
"github.com/go-rod/rod/lib/proto"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolstate"
"github.com/projectdiscovery/nuclei/v3/pkg/types"
"github.com/projectdiscovery/rod"
"github.com/projectdiscovery/rod/lib/cdp"
"github.com/projectdiscovery/rod/lib/proto"
"github.com/stretchr/testify/require"
)
+3 -3
View File
@@ -10,12 +10,12 @@ import (
"testing"
"time"
"github.com/go-rod/rod"
"github.com/go-rod/rod/lib/launcher"
"github.com/go-rod/rod/lib/proto"
"github.com/projectdiscovery/networkpolicy"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolstate"
"github.com/projectdiscovery/nuclei/v3/pkg/types"
"github.com/projectdiscovery/rod"
"github.com/projectdiscovery/rod/lib/launcher"
"github.com/projectdiscovery/rod/lib/proto"
"github.com/stretchr/testify/require"
)
+2 -2
View File
@@ -6,10 +6,10 @@ import (
"net/http/httputil"
"strings"
"github.com/go-rod/rod"
"github.com/go-rod/rod/lib/proto"
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolstate"
"github.com/projectdiscovery/rod"
"github.com/projectdiscovery/rod/lib/proto"
)
// routingRuleHandler handles proxy rule for actions related to request/response modification
@@ -6,7 +6,7 @@ import (
"runtime"
"testing"
"github.com/go-rod/rod/lib/launcher/flags"
"github.com/projectdiscovery/rod/lib/launcher/flags"
"github.com/stretchr/testify/require"
"github.com/projectdiscovery/nuclei/v3/pkg/types"
+1 -1
View File
@@ -1400,7 +1400,7 @@ func TestExecuteParallelHTTP_GoroutineLeaks(t *testing.T) {
defer goleak.VerifyNone(t,
goleak.IgnoreAnyContainingPkg("go.opencensus.io/stats/view"),
goleak.IgnoreAnyContainingPkg("github.com/syndtr/goleveldb"),
goleak.IgnoreAnyContainingPkg("github.com/go-rod/rod"),
goleak.IgnoreAnyContainingPkg("github.com/projectdiscovery/rod"),
goleak.IgnoreAnyContainingPkg("github.com/projectdiscovery/interactsh/pkg/server"),
goleak.IgnoreAnyContainingPkg("github.com/projectdiscovery/interactsh/pkg/client"),
goleak.IgnoreAnyContainingPkg("github.com/projectdiscovery/ratelimit"),