Monday, April 27, 2009

Episode #28: Environment-a-list

Ed starts out:

At a cmd.exe prompt, you can list all environment variables using the "set" command by itself:
C:\> set
Pretty simple. By default, there are a typically a lot of variables set, upwards of two or three dozen.

Another property of set involves the listing of groups of environment variables that start with a substring. For example, to see all of your environment variables that start with the letters pr, you could type:
C:\> set pr
It's kinda weird, but environment variables in Windows cmd.exe are case insensitive.

We can refer to any one of these variables in a command by using the %[var]%. Thus, we can see the value of the username variable by running:
C:\> echo %username%
Or, we can see the value using the set command with:
C:\> set username
Prior to Vista, Windows didn't include a built-in whoami command. The closest thing we have is this "set username". However, be aware that, depending on how your shell is instantiated, you may or may not have this variable set. For example, this variable is typically not set when Metasploit launches a shell on a compromised box. Windows Vista does include a whoami command, but that's a story for another article. We must keep focus when performing command line kung fu.

Other environment variables besides username that are worthwhile include our path variable:
C:\> set path
Path=C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\Program
PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH
The output here will show you both your path, plus the pathext variable (remember, set [string] shows all variables that start with string). The pathext variable is particularly interesting, because it tells us the priority of execution on the machine for various file name suffixes. By default, if I type in "command", but don't specify a suffix, command.com will be run first. If that doesn't exist, the system tries command.exe. Then, it moves onto command.bat and so forth. That behavior can be used for some evil stuff by creating a backdoor called cmd.com or ipconfig.com and inserting it somewhere in the user's path.

Windows, by the way, includes an implicit "." at the very beginning of every user's path. That's a huge bummer from a security perspective, because users can be tricked into running a backdoor out of their current directory when they try to invoke some other command. Also, note that Windows doesn't seem to be too proud that "." is in the path, because it doesn't show it... but, it behaves as though it's there allright.

Other useful environment variables include %systemroot%, which tells you which partition and folder your primary Windows software is located in:
C:\> echo %systemroot%
Often when I'm handling an incident, I see attackers who assume the system root is on C:\. But, sometimes, it's not, and attackers get wrapped around the axel trying to figure out why their tweaks to the OS aren't having an impact. Whenever I'm doing a penetration test and I compromise a Windows box, I quickly display my systermroot and username variables, because that helps to orient me to the target machine.

Also, the prompt environment variable is called, simply enough, prompt. It's default value is $P$G, which indicates your current working directory ($P) followed by a greater than sign ($G). You could really freak yourself out by running:
C:\> set prompt=$$
$ ls

You now have a Linux wanna-be for your shell. I tell ya, when I see that $ prompt, and I just want to type "ls". Alas, no dice. :)

Hal responds:

It's interesting to me how even something as simple as environmental variables points out the differences between the Windows and Unix command-line philosophies. For example, instead of packing all kinds of functionality into a single command like Windows does with "set", Unix handles this by providing a toolkit of different programs that all interact with each other. For example, you use the "env" command to dump all of your current environment variable settings. If you want a specific subset, you pipe the output of "env" into "grep":

$ env | grep PATH
MANPATH=/usr/man:/usr/share/man:/usr/openwin/man:/usr/dt/man:/usr/local/man
CDPATH=.:/home/hal
LD_LIBRARY_PATH=/usr/lib:/usr/openwin/lib:/usr/dt/lib:/usr/local/lib
PATH=/bin:/usr/bin:/usr/X11R6/bin:/usr/local/bin:/sbin:/usr/sbin:...

This seems cumbersome-- you have to use two commands and a pipe instead of using just one "set" command with different parameters. But the power of this idiom is that you use the same knowledge of "grep" to search any kind of textual data in Unix, whereas under Windows you have to learn the particular idiosyncracies of a whole host of separate command line interfaces that each only deal with very specific types of data.

Anyway, returning to Ed's examples, you can display the value of a particular variable using "echo", and we typically set new values using "export" so that the variable setting will be passed along to any subshells we spawn:

$ echo $PATH
PATH=/bin:/usr/bin:/usr/X11R6/bin:/usr/local/bin:/sbin:/usr/sbin:...
$ export PATH=.:$PATH
$ echo $PATH
PATH=.:/bin:/usr/bin:/usr/X11R6/bin:/usr/local/bin:/sbin:/usr/sbin:...
$ export PATH=${PATH/\.:/}
$ echo $PATH
PATH=/bin:/usr/bin:/usr/X11R6/bin:/usr/local/bin:/sbin:/usr/sbin:...

Here I'm using the current value of $PATH in the "export" expression so that I can prepend "." (the current working directory) at the front of my search path. Obviously, as Ed points out above, this is a terrible idea from a security perspective, so I then use the same variable substitution operator we used back in Episode 26 to remove the leading dot. Again, I'm leveraging prior knowledge of basic shell building blocks to solve a new problem.

As Ed points out, Unix does have the "whoami" command, plus a number of other mechanisms for figuring out what user you are that provide different types of information:

$ whoami
hal
$ who am i
hal pts/2 2009-04-26 14:44 (:0.0)
$ id
uid=1000(hal) gid=1000(hal) groups=4(adm),20(dialout),24(cdrom),...

Also, the your login program will generally set the $LOGNAME and $HOME environment variables, and your shell may also set the $USER and/or $USERNAME variables as well.

You can change your prompt by setting the $PS1 environment variable. For example, the default on my Ubunty machine is:

$ export PS1='\u@\h:\w\$ '
hal@elk:~$

There are a whole host of different escape sequences you can use here: "\u" is your user ID, "\h" is the unqualified host name, and "\w" is the current working directory. So if we wanted to emulate the standard Windows command prompt in our Unix shell we could use:

hal@elk:~$ export PS1='\w> '
~> cd /tmp
/tmp>

Of course, it doesn't look exactly like the Windows prompt, because when you're in your home directory, the directory is listed as "~", not $HOME. However, you can use the magic $PWD variable in your prompt instead of "\w" to get a more Windows-like experience:

/tmp> export PS1='$PWD> '
/tmp> cd
/home/hal>

The emulation isn't perfect because Unix uses forward slashes in directory paths, not backslashes. I present the following for the truly psychotic:

/home/hal> export PS1='C:${PWD//\//\\\\}> '
C:\home\hal> cd /tmp
C:\tmp>

You think having a "$" prompt will confuse the Windows folks? Try putting the above recipe into your /etc/profile file next April Fool's Day and watch your Unix users freak out.

By the way, you'll notice that the variable is $PS1. There's also $PS2:

C:\home\hal> export PS1='$ '
$ export PS2='more> '
$ for i in *
more> do
more> ...

Believe it or not, there are even $PS3 (the prompt used by the "select" command) and $PS4 (usually set to "+", this is the value printed before each command in an execution trace as with "set -x").

Paul Throws His Hat In:

One of the environment variables that I've encountered in the past that has really helped me is "LD_LIBRARY_PATH". The variable stores the path that will be used by programs to find software libraries. For example, if you've got a bunch of custom libraries in /opt/local/lib you could run the following command:

$ export LD_LIBRARY_PATH="/opt/local/lib:/usr/local/lib:/usr/lib:/lib"


This comes in handy when you are using OS X and something such as MacPorts is installed in /opt and has the libraries you are looking for. Yes, these are in fact the libraries you are looking for...