Re: Elevate privileges in a program

From: Richard Maher (maher_rj_at_hotspamnotmail.com)
Date: 07/26/03

  • Next message: Richard Maher: "Re: Elevate privileges in a program"
    Date: Sat, 26 Jul 2003 09:17:30 +0000 (UTC)
    
    

    Hi Mark,

    UWSSs are definitely the right way to go. (Exactly why Hoff continues to
    persue his Nanny-State/Ferenheit-451 agenda of banning people from using
    UWSSs and in particular the MACRO compiler is beyond me! Certainly doesn't
    bode well for how these facilities will be implemented on Itanium :-()

    Simply drop the /PROTECT and /NOSYSSHR qualifiers on your $LINK and you now
    have the ability to call whatever RTL you like. I believe it's
    SECURESHRP.EXE if you want $GETUAI. That's the easy part. You are now at
    your most vulnerable!!! It is up to you to protect your working-storage and
    I/O channels and everything else from outer-mode corruption and
    exploitation. (See the COLLECT and PROTECT linker options bellow)

    So now you've made sure that your memory is protected from a dodgy or
    mallicious user-mode pointers and all *your* channels are $ASSIGNed and
    $QIOed at EXEC mode but how can you vouch for $getuai or other RTL routine?
    How can you trust them to do the right thing? What if a hacker is writing
    $QIOs to a random channel selector seeing if he gets a result 'cos PRIVs
    were used to access SYSUAF but the channel was mistakenly open in USER mode?
    What if *they* forget to protect their memory?

    All wonderful questions which undoubtedly can be answered by the VMS and Rdb
    engineering people who do this every day. (Please run an analyze/image over
    a couple of privileged shareables (eg: RDB$COSIP) and see *all* of the
    plethora of other RTLs that these images are linked against. So don't do as
    they do just do as they say? I don't think so. *SOME OF THESE LAND MINES
    EVEN CALL OUT to CRTL!!!* Let's all pray that it's not from inner-mode!)

    Anyway please search through the COV archives (search for blade guard) for
    other fruitless discussions on this subject. I have asked for guidence on
    dropping /PROTECT (but still being secure) hundreds of bloody times without
    any joy. I even dragged myself across North London to a "Hints and Kinks"
    session that supposed to discuss this stuff but the room was packed with
    System Managers and not Developers and tha air-conditioning was off so you
    know what a hoot that was :-)

    I'm also about to post another UWSS example that let's an unprivileged user
    wait until a file is created in a directory!

    (Did you know that any user can do a $dir/fid on any file. I thought telling
    you whether or not a file exists (if you don't have priv) was wrong? See, my
    RTL with tell you the filename that I'm waiting for but if (when it gets
    created) you don't have priv to see it then your AST will fire and give you
    SS$_NOPRIV in the IOSB. But that sought of defeats the purpose don't you
    think?)

    Regards Richard Maher

    $ on warning then exit
    $ if .not. f$privilege("cmkrnl,sysprv,pfnmap,bypass") then goto no_priv
    $ if f$getsyi("arch_name") .nes. "Alpha" then goto no_vax
    $!
    $ create maher$share.mar
    ;++
    ;
    ; (c) Copyright Tier3 Software. All rights reserved.
    ;
    ; Ownership of this software and all associated intellectual
    ; property rights remain vested in Tier3 Software Ltd. This
    ; software or any other copies thereof may not be provided
    ; or otherwise made available to any other person.
    ;
    ; Do not remove this copyright notice.
    ;
    ; Author: Richard Maher
    ;
    ;--
            .macro define_service,name,narg=0,mode=exec,?endmacro

            'mode'_routine_count='mode'_routine_count+1

            .call_entry max_args=narg, -
                            home_args=true, -
                            label=name

            .save_psect local_block

            .psect 'mode'_list

            .address name

            .restore_psect

            .if not_equal narg

             cmpb (ap),#narg
             bgeq endmacro
             movzwl #ss$_insfarg,r0
             ret

    endmacro:

            .endc
            .endm

            .title maher$share - Demo User Written System Services
            .ident "V2.0"

            .library "sys$library:lib.mlb"

            $plvdef
            $prvdef
            $psldef
            $dscdef
            $ssdef
            $uaidef

    usrnam_max=12
    out_len=94
    enable=1
    disable=0

    kernel_routine_count=0
    exec_routine_count=0

            .psect exec_list,pic,con,rel,lcl,noshr,noexe,rd,nowrt,long
    exec_table:

            .psect kernel_list,pic,con,rel,lcl,noshr,noexe,rd,nowrt,long
    kernel_table:

            .page
            .psect _maher$data,pic,con,rel,lcl,noshr,noexe,rd,wrt,quad

    uai_ctx:
            .long 0

    uai_lst:
            .word 32, uai$_defdev
            .address -
                    def_dev
            .long 0

            .word 64, uai$_defdir
            .address -
                    def_dir
            .long 0

            .long 0

    def_dev:
            .blkb 32
    def_dir:
            .blkb 64
    fao_ctl:
            .ascid "!AC!AC"
    out_dsc:
            .long out_len
    out_adr:
            .blkl 1

            .align quad
    sys_prv:
            .quad <prv$m_sysprv!prv$m_audit> ; Just to test HO-LW
    del_prv:
            .quad 0
    old_prv:
            .blkq 1

    persona_id:
            .long 0
    byte_cnt:
            .long 10
    vm_addr:
            .blkl 1
    msg_vec:
            .long 1
            .long ss$_abort

            .psect _maher$scratch,pic,con,rel,lcl,noshr,noexe,rd,wrt,quad

    scratch_lw:
            .long 0

            .psect _maher$code,pic,con,rel,lcl,shr,exe,rd,nowrt,quad

            .sbttl Get directory info

            define_service maher$get_user_dir,3

             ifnord #8,@4(ap),99$ ; Can descriptor be read
             movzwl @4(ap),r8 ; Get username len
             bnequ 10$ ; Check length <> zero
             movzwl #ss$_badparam,r0
             ret

    10$: cmpw #usrnam_max,r8 ; Check length <= 12
             bgequ 20$
             movzwl #ss$_badparam,r0
             ret

    20$: addl3 #dsc$a_pointer,4(ap),r7 ; Get -> to username ->
             ifnord r8,(r7),99$ ; R access to username
    string
             ifnowrt #out_len,@8(ap),99$ ; W access to output buff
             ifnowrt #2,@12(ap),99$ ; W access to output len
             brb 100$

    99$: movzwl #ss$_accvio,r0 ; Indicate access violation
             ret

    100$: $setprv_s -
                     enbflg=#enable,-
                     prvadr=sys_prv,-
                     prvprv=old_prv

             $getuai_s -
                     contxt=uai_ctx,-
                     usrnam=@4(ap),-
                     itmlst=uai_lst
             blbc r0, 999$

             $persona_create_s - ;\
                     persona=scratch_lw,- ; \
                     usrnam=@4(ap) ; |
             blbc r0, 999$ ; |
             movl scratch_lw,persona_id ; > Just a couple
                                                    ; > of dodgy tests
             pushl #0 ; |
             pushal vm_addr ; |
             pushal byte_cnt ; /
             calls #3,g^lib$get_vm ;/
             blbc r0, 999$

             movl 8(ap),out_adr ; Set descriptor address
             $fao_s ctrstr=fao_ctl,-
                     outlen=@12(ap),-
                     outbuf=out_dsc,-
                     p1=#def_dev,-
                     p2=#def_dir

    999$: movl r0,r5
             evax_bic -
                     sys_prv,old_prv,del_prv ; Turn off privs before
    exit!
             $setprv_s -
                     enbflg=#disable,-
                     prvadr=del_prv
             movl r5,r0
             ret

    exec_rundown: .jsb_entry ; Entry point for rundown
                                                    ; handler

            $putmsg_s - ; sys$examples:uwss.c says
    no?
                    msgvec=msg_vec ; but Exec mode is ok

            rsb

            .PAGE
            .SBTTL Privileged Library Vector

    ;+
    ; Any psect with the VEC attribute will be automatically moved to the start
    ; of the image.
    ;-
            .psect dickie$services,page,vec,pic,nowrt,exe

            .long plv$c_typ_cmod ; Set type of vector to change
                                             ; mode dispatcher
            .long 0 ; Reserved
            .long kernel_routine_count ; # of Kernel mode routines
            .long exec_routine_count ; # of Executive mode routines
            .address kernel_table ; Kernel routine list
            .address exec_table ; Exec routine list
            .long 0 ; Kernel rundown handler
            .address exec_rundown ; Exec rundown handler
            .long 0 ; RMS Dispatcher
            .long 0 ; Kernel routine flags
            .long 0 ; Exec routine flags

            .end

    $!
    $ macro/list/enable=quad maher$share
    $!
    $ link /share=maher$share -
            /sysexe -
            /map -
            /cross -
            /full -
            /notrace -
            /section_binding -
            maher$share, -
            sys$input:/options

    gsmatch=lequal,2,0

    symbol_vector = (maher$get_user_dir=procedure)

    protect=no
    collect=scratch,_maher$scratch

    protect=yes
    collect=safe,_maher$data

    $!
    $copy/log maher$share.exe sys$common:[syslib]
    $!
    $if f$file_attributes("sys$share:maher$share.exe","KNOWN")
    $then
    $ installx replace sys$share:maher$share.exe
    $else
    $ installx add sys$share:maher$share.exe -
                    /open/header/share=address/protect
    $!
    $! If you have your GH_RSRVPGCNT SYSGEN parameter geared up for it,
    $! you can install maher$share as /RESIDENT as in:
    $!
    $! installx add sys$share:maher$share.exe
    $! /open/share=address/protect/resident
    $endif
    $!
    $! Need SYSPRV to link against these services
    $!
    $set file/protection=(w:e) sys$share:maher$share.exe
    $purge sys$share:maher$share.exe
    $!
    $create maher$user.cob
    identification division.
    program-id. ef_get_user_dir with ident "V2.0".
    *
    data division.
    working-storage section.
    01 ss$_normal pic 9(9) comp value external ss$_normal.
    01 rms$_rnf pic 9(9) comp value external rms$_rnf.
    01 sys_status pic 9(9) comp.
    *
    linkage section.
    *
    01 username_desc pic x(8).
    *
    01 out_dir.
        03 out_dir_len pic 9(4) comp.
        03 out_dir_text pic x(94).
    *
    procedure division
            using out_dir,
                    username_desc.
    00.
        move spaces to out_dir_text.
        move zeroes to out_dir_len.

        call "maher$get_user_dir"
            using username_desc, out_dir_text, out_dir_len
            giving sys_status.
        if sys_status = rms$_rnf
            move "NL:" to out_dir_text
            move 3 to out_dir_len
        else
            if sys_status not = ss$_normal
                call "lib$stop" using by value sys_status.

        exit program.
    *
    end program ef_get_user_dir.
    $!
    $cobol/lis maher$user.cob
    $link/share=maher$user.exe maher$user.obj,sys$input/opt

    sys$library:maher$share/share

    symbol_vector=(ef_get_user_dir=procedure)

    gsmatch=lequal,2,0
    $!
    $define/nolog maher$user 'f$parse("maher$user.exe")
    $sql:==$sql$
    $sql
    attach 'file mf_personnel';

    drop function ef_get_user_dir;

    create function ef_get_user_dir (in char(32) by descriptor)
            returns varchar(94) by reference
            language sql
    ;
            external name ef_get_user_dir
            location 'maher$user' with all logical_name translation
            language cobol
            general parameter style variant
            comment is 'Get UAF device and directory info for user'
            BIND ON CLIENT SITE
            bind scope connect
    ;
    commit;
    exit;
    $exit
    $!
    $no_priv:
    $ write sys$output -
            "Insufficient privilege. You need (CMKRNL,SYSPRV,PFNMAP,BYPASS)"
    $ exit 44
    $no_vax:
    $ write sys$output "This code only works on alpha"
    $ exit 44

    Mark Hemker <hemker@insightbb.com> wrote in message
    news:5752ivskpr05bvsve4iikpnvscjlggbaee@4ax.com...
    > I'm working with some of our programmers on a new product and we have
    > run into a stumbling block with regards to needing privileges for
    > certain system function calls. What we have is a PASCAL program that
    > needs to be able to make several function calls where the code in the
    > functions requires elevated privileges. We looked at installing a
    > shareable image with these functions, but as you know that won't work
    > We also looked into writing a User-Written System Service and
    > discovered that some of system service calls that we need can't be
    > used in a UWSS.
    >
    > To take this in baby steps, we have cut back to just trying to get one
    > of the functions implemented. This one function really just issues a
    > series of about 5 DCL commands that work with a very protected
    > directory and the files in it. We are currently creating a standalone
    > image that issues the needed commands and I can install that with the
    > necessary privileges. I know this isn't the best solution because now
    > anyone can run the image from DCL and get to the protected directory.
    > For this standalone image, we are looking writing it in C so that we
    > can use the SYSTEM() function or one of the EXEC() functions. We are
    > planning to use LIB$SPAWN from the PASCAL code to run this new image.
    > Is there a PASCAL equivalent to SYSTEM() or EXEC() or is there
    > something better?
    >
    > If anyone has any suggestions, I would love to hear them.
    >
    > By the way, if you reply via private email, please use
    > mhemker@remember.com since that is my work address.
    >
    > Thanks,
    > Mark Hemker
    > hemker@insightbb.com


  • Next message: Richard Maher: "Re: Elevate privileges in a program"