How to obfuscate a shell script? - bash

I am using Ubuntu 10.04. i have created a shell script. After writing the script, the code can be edited when right clicking the file and selecting Gedit. I want to know how to make the script unreadable in Gedit.

GEdit is just another tool that can be used to edit a file, much like "vi" or "nano" is. Only difference is, I believe it is graphical. Nevertheless, it appears that what the original poster is attempting to do here is to simply make it impossible for others to view certain scripts. If that's true, there are solutions that may be worth investigating.
SHC:
SHC is a great tool to use for this purpose. and based on the last post in this thread, it appears the OP has already tried it but, it didn't work on certain systems. If that's the case, heres's the reason why. The way SHC works is actually pretty straight-forward. When using it to obfuscate a script, you have to re-compile the script for whichever OS you intend to run it on. What that means is, you cannot run the SHC compiler on a ubuntu box and expect the produced script to work on a Red Hat/CentOS box. It appears the latest version of SHC can be accessed here.
EnScryption:
If your main goal is to discourage others from attempting to read your code, you can just paste your script to a site like this one. This site will automatically generate an obfuscated version of your script that should be able to run without issues on most common Unix systems.
If you do not wish to paste your code to the above site or use SHC for whatever reason, then, there's yet another solution. Use openssl!
OpenSSL:
If your scripts are really that sensitive, then Openssl(or a similar tool) is probably the best option for you. Why? Because the openssl tool in particular is present on most Unix systems...i.e. Ubuntu, CentOS, Red Hat, Macs, AIX. It comes as part of the default installation. If you decide to go this route, note, you will need to write your script in such a way that before it runs, the user has to provide a password.
Encrypting your script with OpenSSL:
cat yourscript.sh | openssl aes-128-cbc -a -salt -k (specify-a-password-here) > yourscript.enc.sh
(OR)
openssl aes-128-cbc -a -salt -in yourscript.sh -k (specify-a-password-here) > yourscript.enc.sh
(OR)
openssl aes-128-cbc -a -salt -in yourscript.sh -out yourscript.enc.sh -k (specify-a-password-here)
Decrypting your script with OpenSSL:
cat yourscript.enc.sh | openssl aes-128-cbc -a -d -salt -k (specify-a-password-here) > yourscript.dec.sh
(OR)
openssl aes-128-cbc -a -d -salt -in yourscript.sh -k (specify-a-password-here) > yourscript.dec.sh
(OR)
openssl aes-128-cbc -a -d -salt -in yourscript.sh -out yourscript.enc.sh -k (specify-a-password-here)
A quick thing to note about the openssl encryption mechanism 'aes-128-cbc':
There are probably more secure mechanisms out there. But there is a good chance some of the systems you wish to run your encrypted scripts on wont have those mechanisms, thereby making it impossible to run your script. So keep that in mind if you decide to change it.

Obfuscation (which is what most people mean when they say they want a "binary" shell script) is a Bad Idea(TM) - Been there, done that. It doesn't provide any security against a determined programmer (they'd just trace the script to figure out what it's doing), and it makes it really, really hard to debug (which, possibly unless you're GreyCat, you will need to do. A lot.).

You are probably looking for something like shc.
From the man page:
shc creates a stripped binary executable version of the
script specified with -f on the command line.
http://freecode.com/projects/shc
Disclaimer: I have not tested shc nor do I know how well/if it works

What you want to do is not readily possible. Scripts are interpreted, not compiled, that's why you see text in there.
For an script to be executed, the effective user must have read access to it. An alternative to giving execution permission or using shc (as KillerX has nicely proposed), without letting the user look at the contests of the script, would be to use sudo. You would edit the sudoers file like this (remember to use visudo to edit this file!):
username ALL=(ALL) /path/to/your_script.sh
Now the script would be executable by "username" but he wouldn't be able to read its contents. Of course, you need to remove all permissions to "username" from this file...

Related

Is it possible to run wget using both -O and -P options together?

I want to download a program. For example "package.zip"
I want to download it in, for example "~/programs/downloaded"
I want to name it, for example "new.zip"
So I tried:
wget -P ~/programs/downloaded \
-O new.zip https://somewebsite.com/package.zip
But it only downloaded the package in the terminal's current directory and renamed it. The -P command does not work. Any idea how to make it work?
This is a feature of wget that has bitten many people. Unfortunately, it was a design decision taken many years ago and cannot be changed now for fear of breaking existing scripts. The crucial thing to understand here is that -O acts like shell redirection and hence is unaffected by the -P option.
The way to do what you want would be to directly provide the filename:
wget -O ~/programs/downloaded/new.zip <url>

Using curl with an unpredictable target filename

The filename of my curl download target is unpredictable and globbing with an asterisk isn't possible. I can download the file using the following command, but only after I've determined its' name in advance:
curl -O -vvv -k -u user:password https://myURL/ws/myfile.zip
How can I tailor my curl command to succeed with an unpredictable target name?
There's no easy way to get a directory listing using HTTP. You can use curl to just print the HTML generated by the site. If there's an index with links to the files on that server, simply running
curl -s -u user:password https://myURL/ws/ | grep .zip
will print HTML-formatted links to the zip files available for download on that page.
Intro:
Like the OP, I had a similar issue scripting the download of a binary- for docker-compose- from Github because the version number keeps iterating making the file name unpredictable.
This is how I solved it. Might not be the tidiest solution, but if you have a more elegant way, ping me a comment and I'll update the answer.
Solution:
I merely used an auto-populating variable that takes the output of curl, prints the 1st line- which will be the most recent release- and thengrep for the release number prefaced by a "v". The result is saved to the the path /home/ubuntu as the arbitrary file name "docker-compose-latest"
curl -L "https://github.com/docker/compose/releases/download/$(curl https://github.com/docker/compose/releases | grep -m1 '<a href="/docker/compose/releases/download/' | grep -o 'v[0-9:].[0-9].[0-9]')/docker-compose-$(uname -s)-$(uname -m)" -o /home/ubuntu/docker-compose-latest
And we validate that we received the correct binary (I'm downloading to a Raspberry Pi which has an ARM processor on 64 bit Ubuntu 20.04 LTS:
file /home/ubuntu/docker-compose-latest
Produces the following feedback on the file:
/home/ubuntu/docker-compose-latest: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), statically linked, Go BuildID=QqyJMzYMWOofWehXt3pb/T7U4zg-t8Xqz_11RybNZ/ukJOlZCpzQuZzBcwSK3b/d6ecQ2m2VfqKb_EQRUZA, stripped
To validate this solution works, just execute the above commands remembering to change the path of the file command if not using Ubuntu.
Conclusion:
Again, might not be the most elegant solution, but it's a solution for how one can download a target with curl that has an unpredictable filename.

Alias for a shell script

I need wget to be always used with --no-check-certificate option. This can be accomplished by typing the following line in a Unix terminal:
alias wget='wget --no-check-certificate'
However, when I execute shell scripts .sh that include wget command, the original wget is used not the aliased one. How can I resolve this issue?
You have to ensure your alias is defined, where the Shell-script is also sourcing it. If you are using Bash and the Shell-script is using /bin/bash as interpreator, putting into file .bashrc might bei a good idea.
However, --no-check-certificate is in about 99.9% of all cases a very bad idea as SSL is there for a reason.
Also I recommend not to overwrite common commands with custom aliases as this might change behavior of tools a script is relying on in unexpected way. I really recommend to fix up the environment so you don't need this dirty hack.

Change the language of gnupg on a Mac?

I am running OS-X El-Capitan with MacPorts. System language of my Mac is Spanish. How can I tell gnupg to use English as language for any output such as error messages?
I have installed gpg 1.4.19 via macports and gpg 2.0.28 via GPGTools. Both gpg -h and gpg2 -h produce Spanish output, while other unix commands such as git --help or man -h produce English output.
In this post a similar problem is discussed, but I could not apply the recommendations given there to my OS:
http://www.gossamer-threads.com/lists/gnupg/users/52908
Like lots of other internationalized tools, GnuPG takes the LANG environment variable into account. Either export the variable for the whole session, where it will be valid for all executed applications from this terminal (you could also add this to your dotfiles):
export LANG=en
gpg --version
or prefix LANG=en for individual calls of gpg if you only want to run it in English language a single time:
LANG=en gpg --version

mount a drive on Mac OS X with bash script (and NOT use expect)

I'd like to mount a Samba drive in OS X using bash. This line does the trick:
mount -t smbfs //$SAMBAUSER#$ADRESS/$NAMEOFSHARE $MACOSXPATH
only one problem. I want it done without user input - which means no password can be manually put in. And I'm not going to ask my users to download fink just so they can install expect (as seen here).
I tried applying the accepted solution to a similar StackOverflow problem shown here by doing this:
echo "mypassword" | mount -t smbfs //$SAMBAUSER#$ADRESS/$NAMEOFSHARE $MACOSXPATH --stdin
but no luck - that doesn't work and Mac OS X tells me I used mount command improperly:
usage: mount [-dfruvw] [-o options] [-t ufs | external_type] special node
mount [-adfruvw] [-t ufs | external_type]
mount [-dfruvw] special | node
Any suggestions? This would be easy with an expect script - but that would ruin the user experience to have that prerequisite in my mind.
If mount(8) can't just call the mount syscall on the filesystem, it looks for a program to help it. On FreeBSD and Mac OS X, those helper programs follow the naming convention mount_XXX, where XXX is the -t argument's value.
That means you want to check the mount_smbfs(8) man page, which tells us about -N:
-N Do not ask for a password. At run time, mount_smbfs reads the ~/Library/Preferences/nsmb.conf
file for additional configuration parameters and a password. If no password is found,
mount_smbfs prompts for it.
Unfortunately the man page trail ends with one for nsmb.conf that doesn't mention anything about storing passwords. On FreeBSD 8.0, at least, the solution is to put a password key with a plain text(!) password value under a [SERVER:USER] heading. That would be type C according to the linked nsmb.conf man page.
So it seems that you'll want to dump a pre-configured nsmb.conf into your user's ~/Library/Preferences/ directory and then call your mount command with -N. As far as I know you can't provide a hashed value, which is not especially awesome. I'll try to get access to a MacBook in a few hours to test this.
NB: This is not how to do it with the GNU toolchain. If you're on Linux, you're probably going to be using something like mount.cifs(8). The correct solution in that case is the credentials=filename option (used after -o, of course), where filename is a file of credentials in key=value form, separated by newlines. See http://linux.die.net/man/8/mount.cifs
The answer in this apple support discussion thread worked for me:
osascript -e 'mount volume "smb://user:password#server/share"'
I'll give you 2 options. First, include the password on the command line:
mount -t smbfs //$SAMBAUSER:$PASSWORD#$ADRESS/$NAMEOFSHARE $MACOSXPATH
This is not a great option because the command line (including password) is visible to anyone who happens to be logged in at the moment. Not great, but it is a possibility.
Second, use expect. The Mac OS X Hints article you linked dates from 2002, when OS X v10.2 would've been current. While 10.2 apparently didn't include expect as a standard component, 10.6 does, and I'm pretty sure it's been included for several versions now.
#!/usr/bin/expect -f
spawn mount -t smbfs //fred#12.34.56.78/myfiles /tmp/mountpoint
expect "Password:"
send "wibble\r"
wait
You not only can use a hashed value, you're expected to, at least in older releases. The crypt option for smbutil is not DOD-level security but as with most security, you're trying to keep the honest people honest: the bent ones will find a way. It seems to be broken in Mountain Lion but the nsmb.conf file in ~/Library/Preferences should be secure at the OS level. The /etc/nsmb.conf would override it if it exists. I'm sure there's a reason why plain text files are obsolete but didn't we go this with NetInfo? How long did it take for Apple to allow the old standbys (/etc/hosts, /etc/passwd) to be used?

Resources