Skip to main content
gamedev.net
🔒 Locked

Socket vulnerabilities

Started by yahastu Jun 11, 2009 at 4:40 PM 11 replies 2.4k views
Original Post
yahastu
yahastu
Are there any particular vulnerabilities that allow users to execute malicious code through the socket interface using winsock? What "best practices" should I be aware of?
hplus0603
hplus0603
Vulnerabilities in WinSock itself? None known.

However, when you write code to receive data, you have to consider:

1) The data sent may be maliciously crafted by an attacker that has the source code for your client.
2) Data may be sent faster, or slower, or more, or less, than you would normally expect.
3) Any field in any application-level packet may be out of range -- for example, if you allow a length of 0..2047 bytes, and use an int16 for that length, then the value may be sent as 4096 -- or -1.
4) Same thing for all other data. There is no guarantee that strings are zero terminated, or that a used ID is a valid existing ID.

If your program will not mis-behave, not address uninitialized memory, not overrun any buffers, and not take any surprising code paths under any combination of those problems, then your code will not be vulnerable to remote code execution exploits through bugs. However, if your protocol itself allows some kind of code execution (through RPC, scripting, or whatnot), then you have a protocol design challenge, in addition to a protocol implementation challenge.
enum Bool { True, False, FileNotFound };
Antheus
Antheus
- Standard buffer overrun issues. Using fixed-size char arrays (char name[30] can contain data from another packet unless erased).
- Same as above, but with serialization. Automated mechanisms can leave just data in unused fields
- DoS attacks - sanity check dynamic allocations caused by data received.
-- if sending data with length specifier, check the value received. Someone can send you several string lengths of 0x0fffffff, causing you to exhaust memory.
-- slamming, similar to above, but via other means, just trying to exhaust some resources. This can sometimes be checked at higher level. For example, limit number of commands a certain ip:port can make. There's various gotchas here to remain fair.
- In managed languages, avoid straight serialization using built-in mechanisms. If you just straight out deserialize a Message, and try to execute it, someone might send something unusual that you wouldn't have control over until serializer is done. The previously mentioned DoS vulnerabilities apply here - someone might craft a message that contains many bulky instances.

Of the top of my head...
yahastu
yahastu
Ok, so basically in order to be vulnerable to a buffer overflow attack my program would already need to have a bug that causes a segmentation fault on some input...well, I'd never write such code to begin with :P
Drew_Benton
Drew_Benton
Quote:
Original post by yahastu
Ok, so basically in order to be vulnerable to a buffer overflow attack my program would already need to have a bug that causes a segmentation fault on some input...well, I'd never write such code to begin with :P


Don't be so sure of yourself. [wink] Everyone can make such mistakes, even the professionals.

Most bugs like that are innocent intentions that you never see coming. Unless you deal with the security side of network programming, there's a lot of code you see often that can be exploited under the right conditions. It's hard catching them all, but as long as you are aware of the possibility of such in your code, you can program defensively around it.
hplus0603
hplus0603
My favorite illustration of this kind of bug was when someone could send enough data that a signed length counter wrapped negative, and could then write onto the stack through that. That was the big SSH exploit from a few years back! Before I saw that example, I would not have caught that bug in a code inspection.

Best would be to generate all your parsing and marshalling code using templates or an IDL code generator, and go over the core of that code generation with a microscope for vulnerabilities. The benefit of this is that the surface for attack is smaller, because the same code (templates or IDL generator) is used for all instances where it's needed.

Also, in general, I suggest immediately dropping a connection from any client that sends any data that does not pass a validation check. If it tries to send a buffer with too long, or negative, length, drop it. If it sends an unknown command code, drop it. If it sends too much data, or too little data, in a given time interval, drop it. Better safe than sorry, and a bug-free un-hacked client would *never* send that kind of data.
enum Bool { True, False, FileNotFound };
Anon Mike
Anon Mike
Not technically security issues, but so many people get tripped up that these bear pointing out anyway:

TCP does not guarantee that the number of bytes received in a single call matches the number of bytes sent in a single call. e.g. you can do a send() of 100 bytes and get 50 2-byte recv()'s on the other side. You can also do two send()'s of 100 bytes and recv them as (e.g.) 175,3,22.

On the UDP side most people understand that it's possible to drop packets. It's also possible to get duplicated packets. There is no guarantee that packets will be received in the same order sent. I actually watched this happen once - I sent out ~10 packets and recieved them in reverse order on the other side.
-Mike
yahastu
yahastu
Quote:
Original post by hplus0603
My favorite illustration of this kind of bug was when someone could send enough data that a signed length counter wrapped negative, and could then write onto the stack through that. That was the big SSH exploit from a few years back! Before I saw that example, I would not have caught that bug in a code inspection.


Could you demonstrate a minimalistic example of that?
hplus0603
hplus0603
I believe this is a reasonable explanation of the vulnerability I was thinking of. The details don't match exactly, but it might just as well be my memory being old. Or there was another one very similar to it, too :-)
enum Bool { True, False, FileNotFound };
wood_brian
wood_brian
Original post by hplus0603
Best would be to generate all your parsing and marshalling code using templates or an IDL code generator, and go over the core of that code generation with a microscope for vulnerabilities.

Most C++ compilers aren't open source so you can't examine them. Those that are open source may be a mess internally and it would require months to study them for this purpose. The same could probably be said of IDL code generators. Studying the template code is fine, but that doesn't guarantee anything as far as what code is generated. Also since Ebenezer Enterprises' approach is more efficient than Boost Serialization across a variety of tests, I would not use the word "best" for a template based approach.


Brian Wood
Ebenezer Enterprises
www.webEbenezer.net

Do you consider yourself to be a Torah scholar? If so, you might be interested in this offer -- www.webEbenezer.net/TorahConnections.html.

[Edited by - wood_brian on June 14, 2009 4:21:51 PM]
nuvem
nuvem
Quote:
Original post by wood_brian
Quote:
Original post by hplus0603
Best would be to generate all your parsing and marshalling code using templates or an IDL code generator, and go over the core of that code generation with a microscope for vulnerabilities.


Most C++ compilers aren't open source so you can't examine them. Those that are open source may be a mess internally and it would require months to study them for this purpose. The same could probably be said of IDL code generators. Studying the template code is fine, but that doesn't guarantee anything as far as what code is generated. Also since Ebenezer Enterprises' approach is more efficient than Boost Serialization across a variety of tests, I would not use the word "best" for a template based approach.
It usually helps to understand what is being discussed before you start pimping. First, no one has mentioned boost serialization, and second your approach is an IDL code generator.
wood_brian
wood_brian
Quote:
Original post by nuvem
Quote:
Original post by wood_brian

Most C++ compilers aren't open source so you can't examine them. Those that are open source may be a mess internally and it would require months to study them for this purpose. The same could probably be said of IDL code generators. Studying the template code is fine, but that doesn't guarantee anything as far as what code is generated. Also since Ebenezer Enterprises' approach is more efficient than Boost Serialization across a variety of tests, I would not use the word "best" for a template based approach.
It usually helps to understand what is being discussed before you start pimping. First, no one has mentioned boost serialization, and second your approach is an IDL code generator.



Boost Serialization is a well known example of the template based approach. I guess my approach is an IDL code generator, but I just think of it as an on line code generator.

Brian Wood
Ebenezer Enterprises
www.webEbenezer.net



nuvem
nuvem
Quote:
Original post by wood_brian
Boost Serialization is a well known example of the template based approach.
Again, please understand what is being discussed; the topic is security and best practices with respect to recieving data via sockets.

Not to mention, while Boost Serialization is an excellent example of template-based object serialization, it is rare to find games that actually serialize whole objects for transmission. It is much more common to send deltas, quantized values, etc. The speed of serialization is much less of a concern than the resulting packet size.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.