Nmap Development mailing list archives

Status Report #8 of 15


From: Dražen Popović <drazen.popovic () fer hr>
Date: Tue, 22 Jun 2010 03:37:18 +0200

Hi everyone.
I started working on "ndr.lua", an Lua library that will be used for
handling NDR packing and unpacking [1]. This is a very important library
as it represents the very basis for MSRPC protocol. Till now
"msrpctypes.lua" was used for the same purpose, but I came across many
irregularities and design flaws which convinced me to make "ndr.lua". So
far things are going great, mostly to my newly developed MIDL_BENCH
testing environment which saves me a lot of trouble and time.
So...

Accomplishments:
      * "ndr.lua" has a working code that packs all of the NDR primitive
        types (boolean, small, short, long, octet, char, enum) and all
        of the NDR unidimensional arrays (conformant, varying and
        conformant-varying). These have been tested against DRAZEN_SVC
        custom built RPC service used for testing purposes (within
        MIDL_BENCH). Test cases were developed so that they target the
        most tricky alignment issues...and so far "ndr.lua" passes
        smoothly.
      * DRAZEN_SVC MSRPC service is a project within MIDL_BENCH VS
        solution used for testing NDR packing and unpacking as well as
        IDL to NDR mapping. This project contains the IDL definition of
        the service interface, the server code and the client code which
        can be used to resolve any NDR packing issues (shark sniff). So
        far it contains 7 RPC procedures which are used for testing
        "ndr.lua" NDR packing correctness.
      * "cli-drazen-svc.nse" is a NSE script which represents the RPC
        client to the DRAZEN_SVC interface. There you can find the
        actual client side methods that pack the NDR and calls the
        server side RPC procedure. It's used for testing "ndr.lua".
      * Started working on NDR structure packing which lead to the
        drastic design changes. This is the most complex NDR type and
        thus it must be implemented elegantly and clean to avoid future
        problems. So far I have a design draft, new classes and such.

Priorities:
      * Finish the NDR structure type packing and begin the first
        test/debug iteration. When this is done, the rest of NDR types
        packing will follow shortly because the hard part is over. 
      * Make NDR packing methods for top-level and embedded pointers
        (full, unique and referent), unions, strings and
        multidimensional arrays.
      * When done with packing, get to unpacking which should go rather
        smoothly as the concept is similar (if not the same).
      * Test the "ndr.lua" on a real service...this is where all the fun
        begins where I will make the "epmapper.nse" [2] script which
        lists all of the Endpoint Mapper registered services (for you
        not familiar with MSRPC Endpoint Mapper that's the TCP port 135)
        and is in a way similar to portmapper NSE script.
      * Once we have a stable "ndr.lua" the time is wright for LIDL to
        come. :) LIDL is a IDL parser that will use PIDL to do most of
        the hard work and thus we will generate clients for various RPC
        services automatically providing just the IDL definition of the
        RPC interface (similar to rpcgen used in SUN RPC). 

Notes:
To validate my motivation for making "ndr.lua" let me show everyone the
code I used to prove flaws in "msrpctypes.lua" code. For the testing
purposes I made an RPC procedure called TestPrimTypesPacking1 in
DRAZEN_SVC. This is the IDL definition of this procedure:

--##################################
void TestPrimTypesPacking1(
        [in] small _small,
        [in] unsigned small _usmall,
        [in] short _short,
        [in] unsigned short _ushort,
        [in] long _long,
        [in] unsigned long _ulong,
        [in] hyper _hyper,
        [in] unsigned hyper _uhyper,
        [in] boolean _bool,
        [in] char _char,
        [in] byte _byte
        );
--##################################

To call with the above procedure I made two client stubs
DRAZEN_SVC_TestPrimTypesPacking1 and
DRAZEN_SVC_TestPrimTypesPacking1_msrpctypes.
A short code snippet for both of them:

--##################################
function DRAZEN_SVC_TestPrimTypesPacking1(smbstate, sm, usm, sh, ush, l,
ul, h, uh, bo, c, by)
        --sanity check
        --pack the request
        local tptp1_ndr;
        tptp1_ndr = NDR:new()
        tptp1_ndr:push_small(sm)
        tptp1_ndr:push_small(usm)
        tptp1_ndr:push_short(sh)
        tptp1_ndr:push_short(ush)
        tptp1_ndr:push_long(l)
        tptp1_ndr:push_long(ul)
        tptp1_ndr:push_hyper(h)
        tptp1_ndr:push_hyper(uh)
        tptp1_ndr:push_bool(bo)
        tptp1_ndr:push_char(c)
        tptp1_ndr:push_octet(by)
        --call the function
...
--##################################

and

--##################################
function DRAZEN_SVC_TestPrimTypesPacking1_msrpctypes(smbstate, sm, usm,
sh, ush, l, ul, h, uh, bo, c, by)
        --sanity check
        --pack the request
        local tptp1_req_blob;
        tptp1_req_blob = msrpctypes.marshall_int8(sm)
        tptp1_req_blob = tptp1_req_blob .. msrpctypes.marshall_int8(usm)
        tptp1_req_blob = tptp1_req_blob .. msrpctypes.marshall_int16(sh)
        tptp1_req_blob = tptp1_req_blob .. msrpctypes.marshall_int16(ush)
        tptp1_req_blob = tptp1_req_blob .. msrpctypes.marshall_int32(l)
        tptp1_req_blob = tptp1_req_blob .. msrpctypes.marshall_int32(ul)
        tptp1_req_blob = tptp1_req_blob .. msrpctypes.marshall_int64(h)
        tptp1_req_blob = tptp1_req_blob .. msrpctypes.marshall_int64(uh)
        local bo_val
        if(bo == true)  then 
                bo_val = 1
        else
                bo_val = 0
        end
        tptp1_req_blob = tptp1_req_blob .. msrpctypes.marshall_int8(bo_val)     
        tptp1_req_blob = tptp1_req_blob .. msrpctypes.marshall_int8(c)
        tptp1_req_blob = tptp1_req_blob .. msrpctypes.marshall_int8(by)
        --call the function
...
--##################################

As you can see the difference between them is that the first uses
"ndr.lua" packing methods, and the other uses "msrpctypes.lua". The
later resulted with incorrect NDR unpacking on the server side, which
was expected as it does not handle the alignment correctly.
These are only the issues concerning the primitive types, unfortunately
more follow . :(
As I stated before NDR is the MSRPC base, and till now I looked at few
implementations of NDR ("msrpctypes.lua", PyMSRPC, Ruby REX:Ndr and
SAMBA). And it seems that only SAMBA guys did the job correctly, but not
too elegantly. The reason for that is that no one seems to have realized
that the NDR is context dependent as far as the alignment calculations
are concerned and that pointers have a scope inside which they must obey
certain rules.
When in debugging nightmare I turn to MIDL_BENCH, also I use the
--ndr-parser output of the PIDL parser and I use the WShark sniff of the
MIDL generated client only to find out that it's all there in The Book
[4], but sometimes too hard to read. :)

Cheers,
Dražen.

[1] http://en.wikipedia.org/wiki/Network_Data_Representation
[2] http://www.cultdeadcow.com/tools/rpcdump.html
[3] http://wiki.wireshark.org/Pidl
[4] http://www.opengroup.org/onlinepubs/9629399/toc.htm

-- 
Laboratory for Systems and Signals
Department of Electronic Systems and Information Processing
Faculty of Electrical Engineering and Computing
University of Zagreb


_______________________________________________
Sent through the nmap-dev mailing list
http://cgi.insecure.org/mailman/listinfo/nmap-dev
Archived at http://seclists.org/nmap-dev/

Current thread: