Libcurl remote code execution
blog.volema.com
blog.volema.com
As a general rule, if you use libcurl in an application and follow redirects you should probably restrict CURLOPT_REDIR_PROTOCOLS to just HTTP and HTTPS (and maybe FTP). Otherwise a nefarious site could redirect curl to, for example, a IMAP, POP, or SMTP URL, which is potentially undesirable even without this vulnerability. If you're just using curl to talk HTTP(S) you really don't need any of these other protocols.
However, the actual build loops in a patch called curl-7.15.5-CVE-2009-0037.patch, and that adds in all of the CURLPROTO_* magic required to lock down an application. I discovered this tonight when updating my client-side code to restrict redirects and found that it would build fine on RHEL 5 even though I expected it to die. A little digging around in the source RPM explained it.
So, if you're on an OS like RHEL and you think you might not be able to use this feature, try looking in your curl.h file. You might actually have support courtesy of some backported patch from your distributor.
In this case, a automated system rejecting anything that uses the non "n"(strcat vs strncat, etc.) version of the string functions in C would have worked.
Obviously they can still arbitrarily write the instruction pointer, which is very bad and possibly bootstrappable into fully RCE, but I still see more conventional RCE described in recent books and wonder if and why it's still doable.
NX pages would make some classes of RCE exploit difficult or hard (such as including shellcode directly in the POP3 response, and returning directly to it) but doesn't help for many other classes (return-to-libc, or finding or installing 'gadgets' elsewhere in executable pages).
ASLR is a working countermeasure for other classes of exploit, as long as addresses are unpredictable enough to make a search is hard.
$ curl --version
curl 7.21.0 (x86_64-pc-linux-gnu) libcurl/7.21.0 OpenSSL/0.9.8o zlib/1.2.3.4 libidn/1.15 libssh2/1.2.6
Protocols: dict file ftp ftps http https imap imaps ldap ldaps pop3 pop3s rtsp scp sftp smtp smtps telnet tftp
Features: GSS-Negotiate IDN IPv6 Largefile NTLM SSL libz
Looks pretty impressive.All the networking code for Python, Ruby, Perl, Haskell, Java, Scala, Clojure, Erlang, and just about every other language in existence eventually makes calls to the sockets API, which is written entirely in C.
Where were the "Ruby is unfit for networking code" comments for all the recent Rails remote code execution exploits?
Lazy developers will write unsafe code in any language.
The first and most important is to assume any tool that reaches out to the internet and other machines is suspect no matter what language it's written in, and to treat the entire machine as tainted.
The industrial data approach to this is to have a sacrificial machine that's almost completely network isolated from which all FTP's, curl's, wget's et al are run - once setup 'securely' then image the machine to be able to wipe reset on a regular basis. Use that machine to fetch all data from foreign sites and have it dump incoming files to an in coming queue folder. Network security should be such that one other machine on the network can read from that folder and all other network traffic related to the fetch machine rings alarms.
Another approach, when using C to develop your own in house tools is to understand that 'C Strings" are not and never have been "part of the language" - go read the spec. in the latter half, after the language specification, it mentions that a particular byte pattern is referred to a string in a C context, it's just a label of convenience. Don't use the C stdlib functions that manipulate C string patterns, think of them as just an early example of the kinds of things you can build with C, when dealing with tainted data (any data from a network, a user, a foreign source) use hard blocks and hard sizes. Don't fall into the tacit trap that input is "well behaved" .. it never is.
It has a similar set of capabilities to C (including pointers, in line ASM, arbitrary memory access, etc.), ability to call C code, so integrates nicely with C libs.
It has slightly better type handling - e.g. you can declare "feet" and "metres" types based on float, but the compiler won't let you assign one to the other (unless you force a cast).
The major safety advantage is that by default access to strings, arrays and memory management is bounds checked. You can turn this off with pragmas in the code for performance sensitive bits.
In fact, standard practice in C now is to use bounds-checked functions (the strn* functions, etc). Except instead of the compiler keeping track of data sizes for you, you have to do it manually!
Normal string handling is also faster in TP since it stores the length of the string, so it doesn't have to scan through to find the zero char during string operations.
Of course, all this is possible in C, but it's not part of the standard language and API. This has two disadvantages: 1) Lazy or inexperienced programmers will write the most dangerous code. Yikes! 2) Each careful programmer will solve the safety problems in their own way, code from different sources will not necessarily be compatible, forcing library APIs to fall back to the unsafe standard structures.
The biggest advantage that C++ has over just about everything else, is that you can use it to write libraries usable from everything else, and you can do it very easily. You can expose a C-style API trivially, and bind it to everything you want; that advantage can't be overstated.
While I'd love for everything to be written in pure safe, managed code, that's not viable right now. C++ is the best alternative we have, when safe languages aren't usable for the task.
or properly written C, either. :-)
Also, grouping C and C++ together in the context of security is a Bad Thing (TM). They have completely different security issues that plague them, and while C++ may be (mostly) a superset of C, it's truly a completely different language. Things like buffer overflows in string handling are next to nonexistent in proper C++ code, while they exist all over the place in C.
C and C++, as you note, permit a similar lowest-common-denominator programming style and so a similar class of low-level bugs. While the C++ libraries (std::string, etc) and other differences can help, they can be subverted through ignorance or will, and often are. The strict typing in C and C++ helps eliminate bugs over the same task written in assembly (or Forth, etc). In the same way, goto might best be used sparingly, since the sharper the tool, the more likely the damage done by accident. C and C++ sit at approximately the same "danger" level (potential for low-level access) whereas I think functional languages can be automatically "safer" (admittedly ill-defined), assuming you are willing to subjugate yourself to them and can trust the implementation (which is not always a fair assumption), since compilation boils down to a relational proof. (That's not to say it's my preferred style.)
Furthermore, Haskell and OCaml, for example, can both be compiled to linkable objects (C interface-able), so I don't see the loss of interoperability as you suggest. A Haskell .o looks like any other.
I'd argue about the performance hit. (And I programme in Haskell for a living.) But FFI, on the other hand, isn't too unpleasant in functional languages.
If you're really concerned about security, something that does not support "eval" is also a good idea. Replacing your buffer exploit which still requires some skill to exploit with the opportunity to create a "Please tell me what code you would like to execute, in source code form" exploit isn't exactly a good trade. You'd think it would be easy to prevent users from executing code, but evidence suggests you'd be wrong.
Go is not a C replacement.
A clever hacker would use this to jump into some malicious code instead; that's how stack overflow exploits usually work.
So, yes, the actual payload is left as an exercise for the reader, but this shows that there's already everything there to make it possible.
The buffer overflow is the demonstration. There is enough other work that shows how to create payloads.
curl --version
Gives me 7.24 or so.wget --quota: "Note that quota will never affect downloading a single file. However, quota is respected when retrieving either recursively, or from an input file."
These options are not that much different in practice. If single-file size is uber-important, pipe it through something that will break the pipe after the limit point. For ad-hoc scripting usage, wget is almost always more usable than curl IMO. Of course, wget isn't a library.