🔒 Locked
Socket vulnerabilities
Advertisement
Original Post
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.
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.
- 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...
- 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...
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.
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.
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.
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.
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.
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?
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]
Quote: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.
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.
Quote:
Original post by nuvem Quote: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.
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.
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
Quote:Again, please understand what is being discussed; the topic is security and best practices with respect to recieving data via sockets.
Original post by wood_brian
Boost Serialization is a well known example of the template based approach.
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.
Advertisement