add some tighter bounds checking in MSSQL scanner, and if there is an uncaught panic, log the body that caused it

This commit is contained in:
Justin Bastress 2018-10-01 11:08:26 -04:00
parent e7e7be1f6f
commit 6618920234
2 changed files with 35 additions and 2 deletions

View File

@ -11,7 +11,7 @@ import (
"strings"
"time"
logrus "github.com/sirupsen/logrus"
"github.com/sirupsen/logrus"
"github.com/zmap/zgrab2"
)
@ -401,6 +401,9 @@ func (options PreloginOptions) Encode() ([]byte, error) {
for _, ik := range sortedKeys {
k := PreloginOptionToken(ik)
v := options[k]
if len(cursor) < 5 {
return nil, fmt.Errorf("encode: size mismatch (options.Size()=%d)", options.Size())
}
cursor[0] = byte(k)
if offset > 0xffff {
return nil, ErrTooLarge
@ -411,6 +414,9 @@ func (options PreloginOptions) Encode() ([]byte, error) {
offset += len(v)
cursor = cursor[5:]
}
if len(cursor) < 1 {
return nil, fmt.Errorf("encode: size mismatch (options.Size()=%d, len(sortedKeys)=%d)", options.Size(), len(sortedKeys))
}
// Write the terminator after the last PL_OPTION header
// (and just before the first value)
cursor[0] = 0xff
@ -421,6 +427,9 @@ func (options PreloginOptions) Encode() ([]byte, error) {
// returned in rest.
// If body can't be decoded as a PRELOGIN body, returns nil, nil, ErrInvalidData
func decodePreloginOptions(body []byte) (result *PreloginOptions, rest []byte, err error) {
if len(body) < 1 {
return nil, nil, ErrInvalidData
}
cursor := body[:]
options := make(PreloginOptions)
max := 0
@ -506,7 +515,13 @@ func (options PreloginOptions) MarshalJSON() ([]byte, error) {
fedAuthRequired, hasFedAuthRequired := opts[PreloginFedAuthRequired]
if hasFedAuthRequired {
aux.FedAuthRequired = &fedAuthRequired[0]
temp := uint8(0)
if len(fedAuthRequired) > 0 {
temp = fedAuthRequired[0]
} else {
logrus.Debugf("fedAuthRequired was present but empty (options=%#v)", options)
}
aux.FedAuthRequired = &temp
}
nonce, hasNonce := opts[PreloginNonce]
@ -632,6 +647,7 @@ func (connection *Connection) readPreloginPacket() (*TDSPacket, *PreloginOptions
if packet.Type != TDSPacketTypeTabularResult {
return packet, nil, &zgrab2.ScanError{Status: zgrab2.SCAN_APPLICATION_ERROR, Err: err}
}
defer zgrab2.LogPanic("Error decoding Prelogin packet %#v", packet.Body)
plOptions, rest, err := decodePreloginOptions(packet.Body)
if err != nil {
return packet, nil, err

View File

@ -10,6 +10,8 @@ import (
"time"
"github.com/zmap/zflags"
"github.com/sirupsen/logrus"
"runtime/debug"
)
var parser *flags.Parser
@ -209,3 +211,18 @@ func IsTimeoutError(err error) bool {
return false
}
// LogPanic is intended to be called from within defer -- if there was no panic, it returns without
// doing anything. Otherwise, it logs the stacktrace, the panic error, and the provided message
// before re-raising the original panic.
// Example:
// defer zgrab2.LogPanic("Error decoding body '%x'", body)
func LogPanic(format string, args...interface{}) {
err := recover()
if err == nil {
return
}
logrus.Errorf("Uncaught panic at %s: %v", string(debug.Stack()), err)
logrus.Errorf(format, args...)
panic(err)
}