Académique Documents
Professionnel Documents
Culture Documents
==
--[ introduction
rpc as you know it has been used in a lot of services for decades such
as in nis or nfs. however these have never been available to multi-tier
applications and web-applications in paricular (or at least rpc wasn't
really made for it).
since a few years, 'rpc over xml', so called "xml-rpc" has been defined
which should enable developers (web-developers in paricular) to _easily_
use the rpc capability which has been available to system-programmers for
years. application-developers today use corba (common object request broker
architecture), which (in short) adds the ability of accessing objects
remotely with rpc. since the blinking oo world began, developers felt they
need to access objects remotely and they are quite happy with corba. it
allows nice things such as
today = timeserver_ptr->date();
that is it looks like you are accessing a local object, but indeed it is
located on some other box. the underlying so called "middleware" libraries
translate this call into sending data in a special format to the server
which invokes the request on an object the server registered for remote
usage.
the reason for this is that programs have grown so much in recent years
that programmers want to have easy ways to access ressources remotely,
without the pain of platform-specifics such as byte-ordering, different
socket-semantics etc. etc.. there also exist a lot of tools and
pre-compilers which do a lot of work for the programmer already (such as
translating an interface-description into valid c++ code).
xml-rpc was there already, so why not building a remote object access
facility on top of it? soap was born. it allows you to call methods on
objects remotely, similar to the example above. somewhat like oo xml-rpc.
unlike the 'normal' rpc where program and version-numbers were required
to specify which function should be called, xml-rpc allows you to send the
full functionname across the socket enveloped into a xml document. you
usually need to register the objects (with the corresponding methods) which
may be accessed from the outside; at least when i wrote a distributed
banking-application in c++ using corba, it worked that way ;-). this is
also true for soap technology, as i will explain a few lines later,
(indeed, i do not care much about soap specification, but on the specific
implemenatations) but this time we may send function and object-names as
strings and we will see registering objects does not make the whole thing
secure as it is expected to be.
i will focus on perl implementations of soap because perl has the special
capability to call functions indirectly:
#!/usr/bin/perl -w
use posix;
sub autoload
{
print "autoload: called $autoload(@_)\n";
}
sub func1
{
print "called func1(@_)\n";
}
$name = "posix::system";
$name->("/usr/bin/id");
isn't that nice, we can specify at runtime which function is called via
$name, posix::system in this case. every unknown function you try to invoke
i.e. posix::nonexisiting will trigger the autoload subroutine which is a
special gift from perl. that way, you may load unloaded stuff at runtime
when you notice that a function-call does not 'resolve'. things are even
better, because indirect function-calls also work fine with tainted data!
#!/usr/bin/perl -w -t
use posix;
$env{path}="/usr/bin";
$env{env}="";
sub autoload
{
print "autoload: called $autoload(@_)\n";
}
sub func1
{
print "called func1(@_)\n";
}
for (;;) {
print "enter function-name: ";
$name = <stdin>; chop $name;
print "enter argument: ";
$arg = <stdin>; chop $arg;
$name->($arg);
}
func1("that");
lets now start right away with a demo-program that uses soap::lite
[soaplite] to show what xml-rpc means:
#!/usr/bin/perl -w
use soap::transport::http;
$daemon = soap::transport::http::daemon
-> new (localport => 8081)
-> dispatch_to('demo');
sub authenticated
{
return "hi @_, you are authenticated now!";
}
package demo;
sub callme
{
return "called callme";
}
ok. that was basicly taken from a how-to-use-soap guide from [soaplite].
what you do here is starting a small http-server which listens on port 8081
and delegates the xml-rpc's to the package 'demo'. that way, clients may
call the callme() function remotely. http is used here, but soap works
protocol-independant, so you may use smtp or whatever here - there are lots
of modules shipped with soap::lite. calling a function basicly works by
posting a xml-document to this server now. here is a small client calling
the offered function "callme()":
#!/usr/bin/perl -w
use soap::lite;
print $soap->callme()->result();
and thats it! isnt that nice? rpc can't be easier. the
$soap->callme()
why not trying to call other functions which do not belong to the
package? i guess main::authenticated() would be a nice target.
#!/usr/bin/perl -w
use soap::lite;
stealth@linux:soap> ./c.pl
hi demo me, you are authenticated now!stealth@linux:soap>
...
$class->$method_name(soap::server::object->objects(@parameters))
...
the three dots before the method-call parse the xml-document, retrieving
class-name method-uri and method-name from it. actually,
demo->main::authenticated("me");
sub handler
{
# dave developer: we are safe, restricting
# access to calculator package
calculator->$method($args);
...
}
you are able to 'breakout' of the package calculator by giving the full
package-name to $method (main::authenticated in above case). it is
something like *package reverse traversal*. that's the whole point. again,
this will work in tainted mode too! a note on soap-namespaces: you have
probably seen that we sent indeed 'x:main::authenticated' (prepended 'x:').
do not ask why, but there is a prefix needed in soap::lite case, otherwise
the remote xml-parser will complain. on the other hand another soap module
required to have i.e. posix as namespace and system as method which
assembled to posix::system on the other end. the xml-document generated by
that module produced somehow wrong package::method invokations, so i had to
handle that with raw port 80/http requests by myself. seems that either i
got namespace-handling wrong or the module parsing was broken. (probably
first case, i said the book did not arrived yet, no? :-)
hm. i just remember perl has some nice tricks which are possible via
open(). let's see whether we can find some. my requires-script shows me that
soap::transport::http requires http::daemon (via 'new' call that is invoked
by the server, so it's available at runtime). let's just look at http::daemon
package:
...
package http::daemon::clientconn;
...
sub send_file
{
my($self, $file) = @_;
my $opened = 0;
if (!ref($file)) {
local(*f);
open(f, $file) || return undef;
...
ok. i think now you have got an idea of what's going on here, even when
the open() call would not be there, it's still dangerous enough as we may
call *any*, let me repeat, *any* function in the perl-daemon that is
availabe at runtime (either in main-package or a package that is 'use'ed
or 'require'd, except core which is not accessible).
/usr/lib/perl5/site_perl/5.6.1/i586-linux/xml/parser.pm
which tells us that perl is used, and that's it.
--[ 6. no trespassing
it is very interesting that people think security is when they use https
instead of http. i have seen 'secure' soap servers which just used https
as underlying protocol and were declared as 'secure servers'.
so, how to protect? difficult. the -t switch to force tainted mode works
against direct shell-escapes but being able to call any internal daemon
function is bad enough. maybe the package-qualifiers "::" should be
stripped. if you allow them it's like allowing ".." in pathnames which leads
to reverse traversal (there are better ways to protect against reverse
traversal than stripping "..", though) in some cases. tainting the
functionname that comes via the socket will disallow _any_ rpc.
a way might be to put all allowed classes and function-names into a hash
and look whether the received string is contained there. frontier xml-rpc
module for perl does it that way, it has a hash of methods it allows like
where you may only call 'callme' function. you can try to call other
functions until your face turns into green, you won't suceed.
this is not just a perl issue afaik, because other languages also allow
indirect calling of functions, such as java or php. :-) i did not look at
java or corba for perl but i would not be surprised if similar problems
exist there too.
--[ 7. references