Expose any Ruby object over the web. An interesting little snippet...
gist.github.com
gist.github.com
Update: I forgot exec wants its input in a different format. /send/exec/date prints the date and stops the server so this vector is certainly potent. /send/exec/ls/-l/%2f does NOT do what I expect though as Rack seems to turn / back into %2f server side but /send/exec/ls/-l/. does what I'd expect.
Update 2: James Golick notes that calling ` works through send too and suggests using /`/. This has the benefit of returning the output of what was run like cat /etc/passwd, for example ;-)
[18:54:40 ~]$ irb
>> [].send('exec', 'date')
Tue Nov 16 18:54:48 GMT 2010
You can call Kernel's methods on any object (usually - there are some cases where not) through send, e.g. [].send(:puts, 10) .. I was working with Sven Fuchs on some "sandboxing" stuff a couple of years ago and we discovered this little doozy! (Though it's possible to figure out by noting that [].puts tells you private method `puts' called and send gets you around that problem.)Typically you pass a symbol as the first argument but a string works too which, I believe, would make my attack vector work. Going to try it now.
Update: /send/exec/date works as expected (and stops the server).
ruby-1.8.7-p302 > [].respond_to? :exec
=> false
Guess I shouldn't trust it. (Also, I originally ran Array.respond_to?...) [].respond_to?(:exec, true) # => true
respond_to? doesn't include private methods by default but can be made to do so with the second argument. I didn't know this either till I just looked it up.This made sense to me since I'd assume respond_to? would only yield true if it were possible to make the call without error. Yet, this logic does not hold true:
class X; def y; respond_to? :exec; end; end
X.new.y # => FALSE
So it seems it doesn't matter if the private method is callable or not, respond_to? won't give you a true for any private method, accessible in the current scope or not, unless you pass the extra flag.(I'm not really writing all of this to give you an education, more to give me one. I was totally unaware of all this and found it interesting :-))
Just because something is powerful doesn't mean it can't be safe. I just got a handheld vacuum that has no safety mechanisms: no latches to disable the power button when it's folded shut, no kill switches when I take it apart. I can fold over the nozzle, take off the dust holder, and turn it on. I would never need to operate it in that way (unless I was using it as an air pump, which I could, now that I think of it), but it doesn't need any complexity to be safe, because safety is part of its design.
Similarly, a VM could expose a REST-ful API to its objects without needing to have any of the things which people find "unsafe" about Ruby (regardless of how valid those complaints are).
For kicks, go open script/console, type [].methods.size, and create a passing test for that number. It will fail, eventually. The code that kills it may surprise you.
as it should.
Would you hold the same view if you were tech lead of a team of a dozen engineers who've never worked together and loved monkey patching? You can agree to not monkey patch simply by saying "don't monkey patch" and hope everyone follows it, but then you'd probably need to and putting social processes in place to make sure people don't do it (e.g. code review), you can pick a platform that doesn't allow it, or you can recompile the Ruby runtime you use to disallow allow monkey patching.
Another option would be to automate some kind of monkey-patch detection in a staging VM that keeps a list of monkey patches in your code and publishes it to an architecture doc page. Then you can either call that list "tech debt" and strive to constantly refactor the code to get rid of monkey patches, or you can make it part of whatever communication the team does to discuss/agree on what monkey patches are acceptable to use globally in the system. In that case, you also have to make sure that whatever process is in place for deciding yay/nay on keeping a monkey patch treats everyone's contributions fairly. Etc, etc.
All in all, monkey patching is just one example of changes that affect the VM globally. Personally, I prefer that whatever complexity comes with global changes be dealt with by the programming team, not the VM designers (which is what the JVM often does), but I can certainly imagine a team where everyone is making global changes and nobody is aware of the complexity such changes bring to a project. Then everything simply stalls while people bitch at each other about X's code breaking Y's code because of dependency Z, the business guys start yelling because deadlines are missed, and the entire project goes to hell in a handbasket.
It's the same principle but with more features, more development, and test coverage.
gunicorn webapp
For example (if you have gunicorn installed).* https://gist.github.com/703620 - Perl using Plack
* https://gist.github.com/703651 - Perl using Continuity
* https://gist.github.com/703431 - Io using no external modules!
The Perl/Continuity is multiuser out of the box.