[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: LuaSocket: No way to protect against fuzzing attacks?
- From: Sean Conner <sean@...>
- Date: Tue, 11 Oct 2011 04:56:18 -0400
It was thus said that the Great HyperHacker once stated:
>
> Option 3 seems like the answer, but there's no way to read *up to* a
> certain number of bytes. If I specify 32, and the client only sends
> 16, the read will block forever or time out (and will *not* return
> those 16 bytes). So, the server would have to read one byte at a time,
> or else fail to accept legitimate requests. Of course this is terrible
> for performance.
>
> To properly defend against this attack, the server needs to be able to either:
> 1) Peek into the receive buffer, and don't actually read the data
> (removing it from the buffer) until a line break appears, rejecting
> the connection if too much data is buffered without a line break, or:
> 2) Read all data received in the next x seconds or the next n bytes,
> whichever comes first. (Bonus if "or until the next line break" is
> also an option.) The server can then buffer lines in the same manner
> as option 1.
>
> Unfortunately, LuaSocket doesn't seem to offer methods to do either of
> these, thus leaving every server using it vulnerable to such attacks.
Unfortunately, the low level socket interface doesn't offer said methods
either (at least under Unix; I have no idea how Windows handle sockets at
the lower levels). The three low level (read: this is what is ultimately
called) functions to receive data from a socket are:
read (int fd,void *buf,size_t count);
recv (int fd,void *buf,size_t count,int flags);
recvfrom(int fd,void *buf,size_t count,int flags,struct sockaddr *addr,socklen_t *addrlen);
The first parameter is the socket connection, the next two describe the
destination to read the data into and how much; flags modify what type of
data to read and usually this paramater is 0 but could be, at least under
Linux:
MSG_PEEK read incoming data, but the data returns is still
treated as unread
MSG_OOB retreive out of band data. Protocol specific.
MSG_WAITALL wait for all the data specified to be returned
The last two parameters for recvfrom() fill in the remote address.
Your possible answers still have issues:
1) peeking into the buffer is still subject to denial of service attack. As
an attacker, all I need to do is:
while(1)
{
write(yourwebserver,"x",1);
sleep(1);
}
And not only will you never see a line return, but I've tied up one
connection for a *very* long time until you consider I've sent a "very long
line". Also, using the MSG_PEEK for this means memory is wasted in kernel
space buffering and thus may be a bad thing, depending upon the operating
system in question.
2) is probably your best bet, but you need to provide the proper buffering,
because at the lowest level, there is no "line buffering" of socket
connections.
LuaSocket appears to be a wrapper around the recv() and recvfrom() calls
(at least for Unix). These functions, as you may have noticed, do not
timeout on their own. For timeouts, you have several options:
1) use the alarm() function to interrupt the recv()/recvfrom() call.
I do not recommend this route as it deals with signal handlers,
which are horrendous to get right.
2) select() or poll() (or more esoteric variations on these,
depending upon the operating system). The more esoteric variations
tend to have better performance, but aren't portable from system to
system (Linux has epoll(), Solaris uses /dev/poll, *BSD has
kqueue()), but failing that, you want to use poll() and only if you
have to, select().
Yes, doing the line buffering is a pain. I haven't used LuaSockets enough
to say if it does the buffering for you, but a quick search of the code does
show buffer_meth_receive() checking for a "*l", which leads me to believe it
may do such buffering, but you'll have to check the documentation (or the
code itself) to make sure.
I can outline the code you'll need, but you'll need to fill in some
details. It will look something like (system calls I'd use in C are
designated as system.something()):
-- connection is established
-- connection is sock
lastread = system.gettimeofday() -- returns current time to microsecond
readset = { sock }
line = ""
numreads = 0
while true do
rc = system.select(readset,nil,nil,TIMEOUT)
if rc == 0 then
handle_timeout()
elseif rc < 0 then
handle_error()
end
-- socket is read to read
data = system.recv(sock,0) -- read data from socket, no flags
if data:find("\n") then
-- return line .. data, minus the portion past the '\n'
-- which needs to be saved for the next line
-- also, you can check here to see if the line is too long,
-- or contains malicious data or what have you
end
line = line .. data
numreads = numreads + 1
if numreads > THRESHHOLD then
-- we've made too many calls to recv(), handle
end
now = system.gettimeofday()
if (now - lastread) > TOOMUCHTIME then
-- or you could go by how long it's taken to reach this point
-- in time.
end
lastread = now
end
Code is untested pseudocode, but it's approximately what you need to do.
Lord knows I've written enough code (in assembly and C) like this in the
past.
-spc (All abstractions leak, by the way ... )