Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

How to hide a password in a script?

by dataking (Acolyte)
on Aug 06, 2004 at 05:40 UTC ( [id://380451]=perlquestion: print w/replies, xml ) Need Help??

dataking has asked for the wisdom of the Perl Monks concerning the following question:

This is not obfuscated code, which is why I posted here instead in the Obfu section. This is a real world problem. ;) I need to be able to do 2 different obfuscations, 1 is easier than the other. First, I need to be able to obfuscate a password which will be stored in a clear text script. I've got some ideas, and the end result of my beginnings should be relatively well enough hidden. You can probably guess, the next thing I need to do is obfuscate the the password obfuscation code. My question is this... Where can I go to learn what all the funky stuff the guys in the Obfu section do, means!? Is there any written "guidance"? I've googled about every way I can think of, and have found some interesting reads. But they are mostly about principles, theory and such. Is there anywhere out there that says:" you can turn this:

print "Hello World\!\n";

into this:

aksfjdhjdsafhjdsagfjklag

by doing this:

blah%${blah&{ (blah{;}())} ....

Am I asking for too much?? ;) :D Isn't there some sensei out that that needs a young grasshopper?

Edited by davido: Retitled to reflect actual question.

Replies are listed 'Best First'.
Re: How to hide a password in a script?
by davido (Cardinal) on Aug 06, 2004 at 05:49 UTC

    Don't store obfuscated passwords in a script. There will always be a Perl-genius somewhere who can figure it out. Better is to store a cryptographic one-way hash of the password. That makes the password itself inaccessible, no matter what (theoretically), while allowing for simple authentication. The idea is that when the user enters the password, it is hashed using the same algorithm that created the cryptographic hash you've got in your script. This is an irreversible process, but when the algorithm is applied to the password entered by the user, it will match the hashed value you've stored in the script, and you will thus be able to authenticate. However, it's impossible to take that hashed value and use it to figure out the original password.

    The other good thing about this approach is that it is unnecessary to obfuscate the code that crypts the password to check against the encrypted hashed value stored in the script, because though the algorithm is known, no way of reversing is known. Most good encryption mechanisms operate this way; they produce irreversible results; results that are impossible to reverse-engineer into the original clear text, even though the encryption algorithm is known.

    Update: As with most things in Perl, this has already been done, and tested exhaustively. I recommend the Digest::MD5 module. It will allow you to store a 128bit checksum (an MD5 hash) of the password, against which you can check passwords entered by the user, after passing their entry through the same MD5 algorithm. Bingo!

    Update2: I wanted to comment on 'obfu' also. Don't view obfu as a means of writing code that cannot be deciphered. It is only a game, a toy, and at best, a means of exploring the dusty corners of Perl syntax. It's not a way to hide code. It's just for fun.


    Dave

      davido: While I really appreciate your comments, this is a situation that cannot be satisfied by an encrypted solution. This is something that is on a fairly well protected network (1), gives access to a read-only user (2), and deals with a proprietary software client which doesn't support externally encrypted authentication methods(3). Finally, the reason for obfuscation, as opposed to encryption, is that the "stored" password has to be de-obfuscated in order to be passed to an expect program to log into another device (with the read-only account). So, disguising the password, and the disguising the code that disguises the password is sufficient for this particular situation. I understand and acknowledge the risks, and if the situation were different would most likely consider a (permanently) encrypted solution. However, for this particular situation, that simply won't work. Thus, the choice to go with obfuscation. We DO have a "Red Team" that likes to "play", but for the most part, they seem to be more concerned with the windows boxes in our environment, and this particular script resides on a Solaris box. Bottom line, encryption was considered as the preferred option, specifically SSH public key authentication, however, the device we're trying to connect to doesn't support it.

      In response to 'Update2', it's all a game anyway. ;) For this particular situation, I'm not too interested in completely prohibiting *someone* from getting the data (password). But I definitely want to make them work for it. ;)

      So, again, some tips on how to play "the game" would be much appreciated. :D Or at least directions to do some studying.

        Here's why it won't work: no matter how you obfuscate the password and the code to unobfuscate it, the program will still be able to generate the password. And that's where "Red Team" will strike. Observe:

        sub run { do_something(); my $data = get_data(); system("externalprogram -p $data"); } sub get_data { $data = unobfuscate(); return $data; }

        Along comes "Red Team" and tries to crack the system. They read the manual for "externalprogram" and find out that the "-p" flag is for the password, so they edit the run() subroutine to this:

        sub run { do_something(); my $data = get_data(); print "DING DING DING! PASSWORD = $data DING DING!\b"; system("externalprogram -p $data"); }

        If they have access to the script which generates the password, they can find out what the password is, no matter how you obfuscate it.

        Probably the best you can do is to chmod go-rwx script. Then they'll have to crack the user account or root to read the script.

        "and deals with a proprietary software client which doesn't support externally encrypted authentication methods"

        davido wasn't suggesting that the client did any encryption. All encrpytion is down by the script, nothing external. For example:

        $encrypted_passwd = 'ABS5SGh1EL6bk';  # crypt('secret', 'AB');
        
        $submitted_clear_text_passwd = ...from user input, client socket or whatever...;
        
        $submitted_encrypted_passwd = crypt($clear_text_passwd, substr($encrypted_passwd, 0, 2));
        if ($submitted_encrypted_passwd ne $encrypted_passwd)
        {
          # wrong password
          ...
          exit;
        }
        ...
        

        (Except use MD5 instead of crypt().)

Re: How to hide a password in a script?
by Aristotle (Chancellor) on Aug 06, 2004 at 06:21 UTC

    How to hide a password in a script?

    The answer is: you don't.

    If your script, when run, can reproduce the password, then everyone who can read that script's code can, as well. They don't even need to figure out how your obfuscation works, if that's the only obfuscated part of the program.

    There is no way to do what you want.

    davido has provided some good advice on what you should do instead. Heed it.

    Makeshifts last the longest.

      Using your own quote against you... ;) This is a makeshift solution to a lack of feature-set that a vendor has failed to provide. (does that make sense???) Anyhow, this is only meant to be a band-aid. I agree that davido's advice is good, and well founded. I'm not trying to deny that. But what I'm saying is that an ecrypted solution simply won't work in this situation. If it would, then my team wouldn't have spent the last couple months developing the script(s) they have to accomplish the task in the manner they have.

      So, to hopefully set you're security minds at ease, no one has ever gotten in through our boundary, so the biggest threat is internal. The biggest of the internal threats is our "Red Team". And this particular "storage medium" is an unlikely target for that team. The intended obfuscation simpy removes it that much farther. Trust me, if the situation were different, I would be the one preaching the same things you are.

      However, I believe that there is a time and place for everything, and this particular situation calls for obfuscation, NOT encryption. I don't mean to knock the suggestions of Aristotle and davido. But, they simply don't apply here. I've seen the things that you (they) do in the "Obfuscated Perl" section, and I'm merely asking for guidance on how to reproduce and apply it to my particular application.

        The point I was making in my post is exactly what beable says in Re^3: How to hide a password in a script?. By definition, the obfuscated code will have to generate an unobfuscated password; anyone who can read and therefor run the code, can thus recover the password. And they don't need to deobfuscate your code.

        Do you understand now? Whether you obfuscate the code or not is irrelevant. It does not hold up an attacker for even a moment.

        You did not understand the point of my signature either. It is a monition to remember that solutions are often used beyond the scope they were originally built in; and that you should therefor never forgo a certain measure of robustness. It actually underscores my point with regard to your situation: do you know how long your false security measure will be in use, or in what context it will exist five years from now?

        Do not do this. Put the plaintext password in a permissions-protected file. Not only will this prevent anyone from getting the wrong impression about the security of the password, it will actually be effective.

        Makeshifts last the longest.

Re: How to hide a password in a script?
by maa (Pilgrim) on Aug 06, 2004 at 06:33 UTC

    While I agree strongly with the other comments you do seem determined that this is the only way. I don't personally know much about obfu, my brain doesn't work like that. I have used Acme::Bleach though (just to see what it did).

    You could put the password/decryption in a separate file which uses the Acme::Bleach module... it's not secure but it'll make decyphering everything just a little harder.

    HTH - Mark

      I agree as well. (If any of you would like some "gory details" to help clear your mental security defenses, please feel free to email me at dataking <at> cox <dot> net, and I'll be glad to fill you in.)

      I'll be checking out the Acme::Bleach module you suggested. Sounds interesting.

      And please trust that if there were a better solution for this I would definitely be going that route.

      Thanks again for all of your advice and guidance.

        Grasshopper,

        You have mail.

        Regards,

        PN5

      I hate to say it, but the Acme section of CPAN has more than one relavent module. If Acme::EyeDrops actually does even one-tenth of what it claims, it might help.
Re: How to hide a password in a script?
by hv (Prior) on Aug 06, 2004 at 10:34 UTC

    I'd suggest that putting obfuscated code into any production arena is always a bad thing.

    Instead if I were in this situation I'd make the script setuid root (or give it a setuid wrapper if you don't have secure setuid scripts on your O/S) and arrange that the user cannot read or modify it.

    That frees you up to put both code and password in plain text.

    Hugo

Re: How to hide a password in a script?
by chime (Friar) on Aug 06, 2004 at 08:32 UTC
    There is another important point which you should bear in mind.
    Because you have posted your problem on a public forum to which anyone will have access,
    you are advertising your security leak to the world
    (you don't have to be in the monastry to look at the posts)

    Also any possible solutions are also now out in the public arena

    These are just some words of caution.

Re: How to hide a password in a script?
by Solo (Deacon) on Aug 06, 2004 at 13:12 UTC
    See this node for more discussion of this topic.

    --Solo
    --
    You said you wanted to be around when I made a mistake; well, this could be it, sweetheart.
Re: How to hide a password in a script?
by archen (Pilgrim) on Aug 06, 2004 at 13:31 UTC
    This is a security problem and I wouldn't recommend it. But here's an idea to think about. Take a password, add a certain ammount of characters given by some algorithm in between each character (reversable obviously) then start using the pack/unpack functions. Once you have something that doesn't look anything like the password assign that value somewhere. Wherever your password is going to be transformed back, put a lot of pack/unpack statements that return values to a variable, but use the REAL pack and unpacking code to assign it to the default variable, then somewhere pick up the value in $_ . Adding a usless __DATA__ block might be a nice touch for a decoy.

    I would think this would be enough to keep casual snoopers (who aren't very technical) out, but anyone who really wants to know will probably be able to tear through your script no matter what. Some of us actually have fun tearing apart sudo security schemese like this =)
      I was actually working on a scheme which would do something like this, but character by character, then reassemble the keyword on the fly, as opposed to storing the whole word in a single variable. But I like the _DATA_ decoy.
Re: How to hide a password in a script?
by BrowserUk (Patriarch) on Aug 06, 2004 at 20:11 UTC

    If I really had no other choice than to do this, I wouldn't embed the password in the main script.

    I'd tuck it away in a module, probably one of the system module ( and include several that aren't required ), and export the password into the main namespace.

    I'd probably tie the variable and only return the correct password after a particular value has been assigned to it.

    And I'd only return the correct password once.

    Thereafter, I would return the value passed.

    In the script it would look like this:

    #! perl use strict; use warnings; use diagnostics; use LWP; use This; use That; use The::Other; our $password = 'mysecret'; .... system( "command -p $password" ); ... ## If you print $password here, you get "mysecret"; ## But for the first time it was FETCH'd ONLY, ## it would be different.

    Of course, now I've told you this, I'll have to kill you so that you can't tell anyone else.


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail
    "Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon

      Obviously, none of this will be documented.

      It's a very nice way to play mind games on someone. Particularly on the poor sap who inherits your job when you move on. :-)

      Makeshifts last the longest.

        Actually, I'd probably initialise the password (in the source) with a long hex string add a block of code that did some seriously complex bit-twiddling on it before its first use.

        I'd then surround it with a big block comments saying that:

        ################################################################### ## This block must not be altered or copy&pasted in any way. ### ## It will no longer work if it is. ### ## If this needs to be updated, ### ## a new block must be obtained from the systems security team! ### ###################################################################

        In any organisation, there has to be somebody who knows how things work!


        Examine what is said, not who speaks.
        "Efficiency is intelligent laziness." -David Dunham
        "Think for yourself!" - Abigail
        "Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon
      our $password = 'mysecret'; .... system( "command -p $password" ); ... ## If you print $password here, you get "mysecret"; ## But for the first time it was FETCH'd ONLY, ## it would be different.

      Right, so I print the password before the system call, and then I get the real password. What are you gonna do? Go and change the password? This won't work at all.

        First off. I almost certainly wouldn't do this. I cannot think of a situation where I could not come up with of a better place to put my passwords than in the source tree.

        And I certainly would not do it without adding several more twists to the theme that I described. It is not inconceivable that the correct password would only be returned at a given line of a given script (for example).

        However, there is an (as far as I recall) unaddressed problem here. We've probably all seen several instances of this type of news story. I haven't yet seen a good answer to the problem of where to retain ones DB passwords for use in perl scripts.

        Assuming that any script that requires a DB password is correctly secured against external access. That still leaves the problem of protecting assets against internal misuse. If a script is runnable by duly authorised and logged on employess, then most sources from which the password could be (directly) read whilst the script is being run by that employee, are also readable directly by that employee.

        With sufficient knowledge of the procedures in-place, a suitably authorised and knowledgable employee will always be able to circumvent simplistic security. However, sometimes the provision of a "decoy in plain view", a legitimate password that will successfully make a connection (albeit with a grossly constrained set of rights) that silently triggers an alarm when used, can alert you to those that are attempting such sedition, before they have the opportunity to do any real harm.

        Of course, there are better ways than embedding passwords directly in the source tree. A password server than hands them out at runtime, based upon the calling script runtime identity, time of day etc. But even these can be viewed and monitored and the runtime identity faked. But if the password appears to be embedded to the casual observer, you just might catch them out before they get more sophisticated.

        At the end of the day, my post was more in jest that seriousness and I see killing the OP is now a waste of time because somehow, he is not the only one that read my communique :)

        Maybe I should have added one of those email riders:

        This e-mail and any attachments may contain confidential and/or privileged material; it is for the intended addressee(s) only. If you are not a named addressee, you must not use, retain or disclose such information.

        That would have made things safer wouldn't it!


        Examine what is said, not who speaks.
        "Efficiency is intelligent laziness." -David Dunham
        "Think for yourself!" - Abigail
        "Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon

        He's gambling on the fact that people will not expect and therefor notice that $password is evaluating to something different on the first call.

        I think he'd manage to confuse someone for a while with his smoke and mirrors. Which is a problem — because this must not be documented, you can bet there's going to be at least one person will be freaked out, whether or not a cracker ever sees it: the maintenance programmer.

        Makeshifts last the longest.

Re: How to hide a password in a script?
by Anonymous Monk on Aug 06, 2004 at 19:44 UTC
    Have you looked into SRP? (srp.stanford.edu I think) It is a mutual authentication, where one side has a password and the other side has an one-way-hash of it. The password is never sent, but from password and hash a random secret key is calculated. Success is having the same key on both sides, proven by being able to decrypt messages from the other side. If your script contains the hash and your utility contains the password no one could get the password.
      That won't work for this application. But it might in others. I definitely check it out.

      Thanks. :)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://380451]
Approved by davido
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others avoiding work at the Monastery: (6)
As of 2024-04-20 00:33 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found