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

Lighthouse replies to undersized RANDOM PACKETS #1568

Closed
jrhea opened this issue Aug 25, 2020 · 4 comments
Closed

Lighthouse replies to undersized RANDOM PACKETS #1568

jrhea opened this issue Aug 25, 2020 · 4 comments

Comments

@jrhea
Copy link

jrhea commented Aug 25, 2020

Description

Lighthouse doesn't properly validate the RANDOM PACKET size before replying with WHOAREYOU. Per the discv5 protocol a RANDOM_PACKET is sent to initiate a handshake and the receiving node replies with WHOAREYOU. The RANDOM_PACKET should have the following layout:

tag -> 32 bytes
auth-tag -> 12 bytes (RLP format)
random_data -> 44+ bytes

The Discv5 rationale document specifically mentions that the RANDOM PACKET size should be > WHOAREYOU to ensure that an attack using the RANDOM PACKET format will require more bandwidth for the attacker. Lighthouse will reply to RANDOM PACKETS as small as 46 bytes - in other words, the random_data field does not seem to be required in this implementation. 88 bytes + 2 bytes for RLP length prefix should be the minimum acceptable size.

The following is screenshot showing Lighthouse's reply to a malformed RANDOM PACKET that is undersized:

Invalid RANDOM PACKET:
image

Lighthouse's WHOAREYOU response:
image

Steps to Reproduce

You can recreate the issue by using this command to send a malformed message to Lighthouse:

> hping3 -d 46 --fast --udp -p [PORT] [IP] -E lh.payload

where lh.payload is the following hex string converted to binary:

> cat lh.input 
01010101010101010101010101010101010101010101010101010101010101018c020202020202020202020202

if it helps, you can use the following python code to convert the hex string above to the appropriate format:

import binascii
 
with open('lh.input') as f, open('lh.payload', 'wb') as fout:
     for line in f:
         fout.write(
             binascii.unhexlify(''.join(line.split()))
         )

or just modify one of the mysteriously similar discv5 unit tests 😉

@AgeManning
Copy link
Member

Ah yeah cool. I'll check this out and update discv5 accordingly. Will close this once complete.

Thanks for the work done here!

@fjl
Copy link

fjl commented Aug 30, 2020

I think this is a great finding, and go-ethereum probably has the same issue. But there is an issue in the spec that we need to address also: requiring the random-packet to be larger than 44 bytes exists because it is supposed to prevent traffic amplification attacks, i.e. for any packet you can send that would trigger a WHOAREYOU response, the incoming packet should be equal in size or larger than WHOAREYOU.

Consider the scenario where A and B had a session going on, but then B drops the session because it restarts or something. The next PING sent by A cannot be decrypted by B and it should respond with WHOAREYOU to get the session back on.

So what we need to change in the spec is requiring all request packets to be larger than WHOAREYOU, not just the initial random packet.

@jrhea
Copy link
Author

jrhea commented Aug 30, 2020

I think this is a great finding, and go-ethereum probably has the same issue.

I can confirm it does + it also allows invalid RLP length prefixes before the Auth_tag. @fjl checkout the issue I opened here:

prysmaticlabs/prysm#7110

@AgeManning
Copy link
Member

This requires a spec update to properly address. I'm going to close this for now.

We will keep up to date with the spec which should in the future address this.

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