Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SSH: Unable to marshal data #318

Closed
TrueSkrillor opened this issue Jun 23, 2021 · 4 comments
Closed

SSH: Unable to marshal data #318

TrueSkrillor opened this issue Jun 23, 2021 · 4 comments

Comments

@TrueSkrillor
Copy link
Contributor

Hey everyone,

I stumbled across a fatal error while performing an internet-wide ssh scan as part of my masters thesis resulting in premature end of the scan. After some time, zgrab2 logs the following error and quits:

FATA[10636] unable to marshal data: json: error calling MarshalJSON for type ssh.kexAlgorithm: json: error calling MarshalJSON for type ssh.PublicKey: json: error calling MarshalJSON for type time.Time: Time.MarshalJSON: year outside of range [0,9999]

As the error message indicates the timestamp of the public key seems to be invalid (not within the valid range). By extending the call to the logging function I was able to isolate the list of IPs that caused this issue. As it turned out only six IPs in the entire IPv4 address space caused this issue but I will try to avoid sharing the IPs publicy due to obvious reasons.
For debugging purposes I performed a SSH handshake using OpenSSH with verbose output enabled (which was possible). See below for the captured output (I stripped the log file a little but it should still contain all necessary information):

OpenSSH_8.6p1, OpenSSL 1.1.1k 25 Mar 2021
debug1: Connecting to x.x.x.x [x.x.x.x] port 22.
debug1: Connection established.
debug1: Local version string SSH-2.0-OpenSSH_8.6
debug1: Remote protocol version 2.0, remote software version Go
debug1: compat_banner: no match: Go
debug1: Authenticating to x.x.x.x as 'none'
debug1: SSH2_MSG_KEXINIT sent
debug1: SSH2_MSG_KEXINIT received
debug1: kex: algorithm: curve25519-sha256@libssh.org
debug1: kex: host key algorithm: ecdsa-sha2-nistp384-cert-v01@openssh.com
debug1: kex: server->client cipher: chacha20-poly1305@openssh.com MAC: <implicit> compression: none
debug1: kex: client->server cipher: chacha20-poly1305@openssh.com MAC: <implicit> compression: none
debug1: expecting SSH2_MSG_KEX_ECDH_REPLY
debug1: SSH2_MSG_KEX_ECDH_REPLY received
debug1: Server host certificate: ecdsa-sha2-nistp384-cert-v01@openssh.com SHA256:[...], serial [...] ID "[...]" CA ssh-ed25519 SHA256:[...] valid from 2021-01-21T00:01:13 to 2038-01-19T04:14:07
debug1: No matching CA found. Retry with plain key

The expiration date of the host certificate suggests that this error may be directly related to the year 2038 problem, causing an arithmetic overflow in some 32 bit signed integer.

@TrueSkrillor
Copy link
Contributor Author

The workaround I used for this is to demote the Fatalf call to Errorf to avoid the application being exited prematurely.

log.Fatalf("unable to marshal data: %s", err)

jamadden added a commit to jamadden/zgrab2 that referenced this issue Jun 22, 2022
As called by grabTarget.

The proximate cause for this is
zmap#318 (SSH certificates with dates
too large crash the process), and the fix is due to @TrueSkrillor in
that same issue. The source of the error is the go standard library's
time
module (https://cs.opensource.google/go/go/+/master:src/time/time.go;drc=41b9d8c75e45636a153c2a31d117196a22a7fc6c;l=1317),
and it points us to golang/go#4556 (comment).
Essentially, time is trying to produce a RFC3339 string, and refuses
to do so with a year too big.

We began seeing this problem about the week of June 6, 2022, and this
change fixed it for us.

However, this does appear to be a global change, applying to all
scanners. We aren't currently affected by this (or we would have had
other uses of zgrab2 crashing with a similar error), but in the
future, should we hit bad data, we won't crash, we'll just get a
logged warning that we may not notice. That's both good and bad.

I don't know go well. I was a bit concerned about passing what must be
the nil return value back from grabTarget, into the outputQueue byte[]
channel, and ultimately into the OutputResults function which wants to
write it to the (buffered) output file. However, it appears that,
because len(v), where v is a byte[], is 0, nothing actually happens:
the empty result is swallowed.
kevin-he-01 added a commit to kevin-he-01/zgrab2 that referenced this issue Nov 3, 2022
kevin-he-01 added a commit to kevin-he-01/zgrab2 that referenced this issue Nov 17, 2022
@kevin-he-01
Copy link

It looks like the specific issue with the SSH scanner here has to do with the failure to marshal JSON time.Time object with a year outside of range [0,9999]. Such an object indeed exists in this serializable struct:

zgrab2/lib/ssh/certs.go

Lines 68 to 72 in 48f15ef

type JsonValidity struct {
ValidAfter time.Time `json:"valid_after"`
ValidBefore time.Time `json:"valid_before"`
Length uint64 `json:"length"`
}

The issue arises because it looks like Certificate objects can hold Unix timestamps (in c.ValidBefore and c.ValidAfter) that are before year 0 or after year 9999. However, when it is serialized to JSON, such times poses a Y10k problem since the string encoding of times does not permit years with more than 4 digits or negative years:

zgrab2/lib/ssh/certs.go

Lines 154 to 158 in 48f15ef

temp.Validity = &JsonValidity{
ValidAfter: time.Unix(int64(c.ValidAfter), 0).UTC(),
ValidBefore: time.Unix(int64(c.ValidBefore), 0).UTC(),
Length: validityLength,
}

The embedded unserializable time.Time objects ultimately causes this line to return an error:

return json.Marshal(temp)

dadrian pushed a commit that referenced this issue Jan 24, 2023
As called by grabTarget.

The proximate cause for this is
#318 (SSH certificates with dates
too large crash the process), and the fix is due to @TrueSkrillor in
that same issue. The source of the error is the go standard library's
time
module (https://cs.opensource.google/go/go/+/master:src/time/time.go;drc=41b9d8c75e45636a153c2a31d117196a22a7fc6c;l=1317),
and it points us to golang/go#4556 (comment).
Essentially, time is trying to produce a RFC3339 string, and refuses
to do so with a year too big.

We began seeing this problem about the week of June 6, 2022, and this
change fixed it for us.

However, this does appear to be a global change, applying to all
scanners. We aren't currently affected by this (or we would have had
other uses of zgrab2 crashing with a similar error), but in the
future, should we hit bad data, we won't crash, we'll just get a
logged warning that we may not notice. That's both good and bad.

I don't know go well. I was a bit concerned about passing what must be
the nil return value back from grabTarget, into the outputQueue byte[]
channel, and ultimately into the OutputResults function which wants to
write it to the (buffered) output file. However, it appears that,
because len(v), where v is a byte[], is 0, nothing actually happens:
the empty result is swallowed.
@mzpqnxow
Copy link
Contributor

mzpqnxow commented Aug 23, 2024

I see there was a commit pushed for this. Did it resolve your issue @TrueSkrillor ?

mentioning #355 to link it here

@TrueSkrillor
Copy link
Contributor Author

Yup, it works as expected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants