

Expose any Ruby object over the web. An interesting little snippet... - steveklabnik
https://gist.github.com/675667

======
petercooper
Do not try this but off the top of my head, I think this vector could be
slightly unnice: _/send/exec/rm%20-rf%20%2F_ .. Will give it a go when I'm off
the iPad :-)

 _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 ;-)_

~~~
steveklabnik
I don't think it'd actually work, since it sends all of the calls to an Array.
Array doesn't respond_to exec.

~~~
petercooper

      [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)._

~~~
steveklabnik
Weird...

    
    
        ruby-1.8.7-p302 > [].respond_to? :exec
         => false
    

Guess I shouldn't trust it. (Also, I originally ran Array.respond_to?...)

~~~
petercooper
Try:

    
    
      [].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 :-))

~~~
steveklabnik
No, don't feel bad. That's awesome. I knew that thing about adding true, I
just didn't realize that exec was private.

------
rauljara
Depending on your point of view, this is a perfect example of either what
makes ruby so amazing or so awful. I don't know of another language that gives
you the power to so concisely potentially screw yourself in such a creative
way.

~~~
andreyf
Let's not be too eager to accept the "tradeoff metaphor".

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).

~~~
rauljara
Don't get me wrong, I fall squarely on the side that Ruby's power is well
worth it's danger. But let's not kid ourselves, monkey-patching Object is
dangerous. In this example, exposing all of an object's methods to the web
means that anyone could further modify whatever object you stuck up there,
adding whatever methods they wanted. Yes, you could expose it to the web in a
safe manner, but that would be a lot more work. Ruby holds out that simple,
easy, even elegant monkey-patching solution to tempt you in ways that you have
to be really careful about.

~~~
andreyf
_Don't get me wrong, I fall squarely on the side that Ruby's power is well
worth it's danger._

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.

------
kingkilr
A Python version for the kids at home: <https://gist.github.com/702001>

~~~
wwortiz
I don't know much about python and webapps but what would you serve this with?
I'm just curious as I don't see the equivalent serving in this as the node.js
and ruby snippets.

~~~
Ixiaus
A WSGI server (like paste, tornado, etc...) - you just wrap it in an app()
function or object. It's very similar to Ruby's rack...

