[Search for users] [Overall Top Noters] [List of all Conferences] [Download this site]

Conference noted::hackers_v1

Title:-={ H A C K E R S }=-
Notice:Write locked - see NOTED::HACKERS
Moderator:DIEHRD::MORRIS
Created:Thu Feb 20 1986
Last Modified:Mon Aug 03 1992
Last Successful Update:Fri Jun 06 1997
Number of topics:680
Total number of notes:5456

289.0. "How do I SECURE a command procedure?" by KRYPTN::CROWELL (Jon Crowell) Thu Aug 14 1986 21:20

    I want to write a SECURE command file that reads in
    a node name and performs a "SET HOST node" but won't 
    let that person escape into my account. I tried "ON
    control_Y" and "on sever_error.." but someone on the
    command procedures note showed me that "'F$PID(GOTO)'"
    will bomb out of the command file once it gets parsed.
    Tried using READ instead of INQUIRE but that didn't 
    help.  My command procedure is in COMMAND_PRO.. 288.
    
    1) What does the "f$pid(goto)" LEXICAL Do?
    
    2) How do you write a "secure" command procedure?

    Jon~
T.RTitleUserPersonal
Name
DateLines
289.1Captive account's your best betJON::MORONEYMadmanThu Aug 14 1986 23:460
289.2Filter your input tooTUNDRA::HARRIMANVisit Scenic WinooskiFri Aug 15 1986 15:0749
    re: -1
    
    > Captive account's your best bet
    
    Yabbut...
    
    You can still break out of a captive account (we do it all the time).
    
    Re: .0
    
    
    You may be doing something like:
    
    $ read sys$command foo
    $ set host 'foo'
    
    This isn't any better than having the inquire there in the first
    place.
    
    You must filter all input before you do ANY DCL command. The reason
    is that most if not all DCL commands do the same interpretations
    in their own parse trees. For instance, the command
    
    $ Directory @tt:
    
    will yield:
    
    _$ 
    
    and it won't matter if you are in a captive account or not. I strongly
    suspect that's the sort of thing that's happening. 
    
    The main (a little philosophy here) reason one uses a READ SYS$COMMAND
    instead of an INQUIRE is to prevent the  typed input from having
    an immediate effect on the command procedure/environment. However,
    the wise command procedure author must "insulate" all input from
    any dcl command which may use that input. If you issue a READ
    SYS$COMMAND and you don't search for obvious substrings like "F$",
    or "@", or ":=", or "-" or "&", you aren't gaining anything by using
    the READ.
    
    Like I said earlier, just a simple command like PRINT @TT: will
    get you to a dollar sign no matter what kind of account you have.
    If the user types 'F$PID(LOGOUT)' to your READ command, sure, the
    READ won't execute it, but what happens when you do a SET HOST
    'F$PID(LOGOUT)'? 
    
    /pjh
    
289.3CLT::GILBERTeager like a childFri Aug 15 1986 16:1233
    Check the "Guide to VAX/VMS System Security" -- it's one of the
    small 'handbooks'.  Duplicate the beginning of the example captive
    command procedure given there.

    You must justify *every* use of a ' (single quote) before a
    user-provided input.  I think it is sufficient to ensure that
    the symbol itself contains no single quotes.  Something like:

	$read:	read sys$command sym
	$clean:	tmp = sym
	$	sym = sym - "'"
	$	if sym .nes. tmp then goto clean
	$	set host 'sym
	$	...

    If there are qualifiers that must be avoided, remove /s (slashes) too.
    If the input must consist of a particular set of characters, try:

	$read:	read sys$command sym
	$	chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +-
	$		"abcdefghijklmnopqrstuvwxyz" +-
	$		"_$0123456789"
	$	i = -1
	$10$:	i = i + 1
	$20$:	if i .ge. f$length(sym) then goto 30$
	$	tmp = f$extract(i,1,sym)
	$	if f$locate(tmp,chars) .lt. f$length(chars) then goto 10$
	$	sym = sym - tmp
	$	goto 20$
	$30$:	!
	$	! Any other checks, like checking the symbol length
	$	!
	$	...
289.4Why 'f$pid(goto)' WorksVAXUUM::DYERDefine `Quality'Fri Aug 15 1986 19:1014
	    The 'f$pid(goto)' trick is something I learned from M.
	Gilbert.  The f$pid() lexical makes its argument a symbol
	whose value is a number, a Process ID.  So 'f$pid(goto)'
	creates a "goto" symbol whose value is a number that doesn't
	make any sense as a command.
	    My usual approach for protecting a command procedure is
	to create a "dcl" symbol equal to a space, and putting it in
	front of every command, like this:

		$ dcl = " "
		$ dcl goto TIBET

	That protects it from "goto" symbols.
			<_Jym_>
289.5'F$PID (DCL)'FROST::PIPERbill piperSat Aug 16 1986 23:3212
< Note 289.4 by VAXUUM::DYER "Define `Quality'" >

>>	That protects it from "goto" symbols.

But, Jym.  It doesn't protect you from 'F$PID(DCL)''F$PID(GOTO)' and
such.  If you're really worried about protecting things, and you need
a construction of the form $ VERB 'ARGUMENT', you have you go looking
for apostrophes, @'s and the like.

Sounds like disabling F$PID would be easier.  How do we do that?

-piper
289.6Make f$pid And f$pi SymbolsVAXUUM::DYERDefine `Quality'Mon Aug 18 1986 15:5221
	    Oops!  You're right.  The

			$ dcl = " "

	is something I use to make my command procedures safe from a
	user's symbol definitions; it doesn't help here.
	    However, I have thought up a way to turn f$pid() off.

			$ f$pid = "!"
			$ f$pi = "!"

	You can, of course, replace the "!" with anything else you
	imagine.  If you want to use f$pid() later on in the program,
	just turn off the symbol and then turn it back on.

			$ delete/symbol/local f$pid
			$ really use f$pid(foo)
			$ f$pid = "!"

	    Kludgesville.
			<_Jym_>
289.7Why even give them the chance?FROST::HARRIMANACK Phfft!Mon Aug 18 1986 16:089
    Nice idea, Jym. The point here is that to hack-proof a command
    procedure, you have to remove the ability for something like
    'F$PID(Whatever)' to be executed in the first place. That's why
    I maintain that if you filter your input in the first place you
    won't have problems and you can write cleaner code anyway.
    
    Besides, it's so much more fun to keep 'em guessing, right bill?
    
    /pjh
289.8This should be fixed...JON::MORONEYMadmanMon Aug 18 1986 17:249
re .*:  Seems to me that this is a security breach in DCL, there should be a
guaranteed way to execute a GOTO or something and KNOW that you aren't
executing a symbol a clever hacker placed.  I used to use CDC's NOS system and
a similar hack on it was to create a local file with the same name as the
command you wanted to disable.  But if the command in the procedure file was
preceded with a "$", you were GUARANTEED the command interpreter used its own
definition of the command you wished to execute. 

-Mike 
289.9But there is a way.DELNI::CANTORDave CantorTue Aug 19 1986 04:1011
      Re .8
      
      > ... there should be a guaranteed way to execute a GOTO or
      >something and KNOW that you aren't executing a symbol a clever
      >hacker placed.   
      
      There is:  put in $ GOTO = "GOTO" immediately before each GOTO
      statement.


      Dave C.
289.10Should be easierJON::MORONEYMadmanTue Aug 19 1986 19:3114
re .9:  True, but DCL should be set up so that it's TRIVIAL to guarantee a
known command FOO is executed when you say $ FOO.  This is so it would be easy
for marginal programmers to make secure command files, captive accounts, etc.
The system I mentioned (NOS) will do this with the leading special character
"$". (It does not need a leading char in its command files like the DCL "$")
This is similar to the "really" in the previously mentioned sequence

$ really = " "
$ really goto foo

but the special symbol could not be redefined, unlike the above which could be
broken by 'F$PID(really) or something similar. 

-Mike