PDA

View Full Version : Terminal variable set from 'defaults' command




mhoward84
Apr 6, 2012, 04:40 PM
Hi, I am trying to write the standard output of the defaults command to a variable. When I do the following
VAR1=$( defaults read ~/.MacOSX/environment/DYLD_INSERT_LIBRARIES )

then

echo $VAR1

I simply get a blank line then the command prompt. I also can't redirect the output to a document.

Is there any way to do this with this command? Thanks in advance



chown33
Apr 6, 2012, 06:27 PM
Break It Down. The problem may not be what you think it is.

First, check that your syntax is correct for the inner command:
defaults read ~/.MacOSX/environment/DYLD_INSERT_LIBRARIES

If you just paste that into a Terminal window, what is the output? Post it, please, including any error messages.

If the output isn't what you expect, please describe what you expected, and how you decided that the posted defaults command-line is what should work.

Also describe exactly what you're trying to do. If you're trying to read the environment.plist file, looking for a DYLD_INSERT_LIBRARIES entry, perhaps related to the Flashback trojan, then please say that's what you're trying to do. Because if that's what you're trying to do, your syntax is wrong. You should start by reading the man page for the defaults command (http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man1/defaults.1.html). You might also read about PListBuddy (google it).

EDIT
Article with correct examples of defaults commands:
http://arstechnica.com/apple/news/2012/04/how-to-check-forand-get-rid-ofa-mac-flashback-infection.ars

mhoward84
Apr 7, 2012, 04:12 PM
Thanks for the response chown.
I want to build a script that I can distribute to customers that will examine the results of this command and the other 2 and verify that the trojan isn't installed.

Upon further examination it appears it might just be easier to download someone else's script and distribute it or use some of their script to construct my own.

subsonix
Apr 7, 2012, 04:38 PM
Upon further examination it appears it might just be easier to download someone else's script and distribute it or use some of their script to construct my own.

defaults writes to stderr, you need to direct it to stdout. It might also make sense to pipe it to: grep -E "( does not exist)$" or something before you assign it to a variable, also use meaningful names for variables.


DYLD=$(defaults read ~/.MacOSX/environment DYLD_INSERT_LIBRARIES 2>&1 | grep -E "( does not exist)$")
# similar for the other tests

if [ -n "$DYLD" ] && [ -n "$SAFARI" ] && [ -n "$FIREFOX" ]
then
echo "ok"
else
echo "Oh noes!"
fi


Edit: I have not tested this on a machine that has this trojan, keep that in mind. It might actually be better to do it manually to be sure instead of taking the risk of a false positive or worse, a false negative.

chown33
Apr 7, 2012, 05:53 PM
defaults writes to stderr, you need to direct it to stdout.

It does write to stdout, when invoked correctly, on a plist value that exists, in a plist or domain that exists.

If invoked incorrectly, or on a plist file or domain that doesn't exist, or with a key that doesn't exist, the stdout stream contains no bytes.

It only writes error messages to stderr, like many other Unix/Posix commands. In this design, the fact that nothing is written to stdout is intended to mean "no such thing", usually coupled with a non-zero exit status (shell: $?).

For example, if the cat command is invoked to cat a file that doesn't exist, the stdout stream gets no bytes, the stderr stream gets an error message, and cat's exit status is not-success (i.e. non-zero).

Try these:
defaults read com.apple.TextEdit; echo $?
defaults read com.apple.TextEdit WidthInChars; echo $?
defaults read com.apple.TextEdit ExplodingPenguin; echo $?


----------

Upon further examination it appears it might just be easier to download someone else's script and distribute it or use some of their script to construct my own.

This seems like a good idea, especially if you're not extremely familiar with writing shell scripts that need to deal with error conditions.

subsonix
Apr 7, 2012, 06:14 PM
It does write to stdout, when invoked correctly, on a plist value that exists, in a plist or domain that exists.

If invoked incorrectly, or on a plist file or domain that doesn't exist, or with a key that doesn't exist, the stdout stream contains no bytes.

It only writes error messages to stderr, like many other Unix/Posix commands.

Right, but in this case the idea is to catch the case where a plist does not exist so stderr needs to be redirected to assign it to the variable. The non existence of these plist files is the only case we know about. Likewise for the removal, a script can't be made by the information posted by Fsecure since the exact output is not known.

subsonix
Apr 7, 2012, 06:44 PM
This seems like a good idea, especially if you're not extremely familiar with writing shell scripts that need to deal with error conditions.

Really? If you are not capable of writing it, how are you going to assess that the script you are using is correct? The best is to follow the exact instructions given by Fsecure.

chown33
Apr 7, 2012, 07:20 PM
Right, but in this case the idea is to catch the case where a plist does not exist so stderr needs to be redirected to assign it to the variable. The non existence of these plist files is the only case we know about.
I'm not following your logic.

If you didn't redirect and grep the stderr stream, the value assigned to the variable is "" (empty string). How is that not a definitive indicator that there is either no such file, or no such key?

It's conceivable that the file does exist, and the key exists with a value of "" (empty string), and this would not be a uniquely detectable condition. I'm not seeing how it's harmful, though, since it means DYLD_INSERT_LIBRARIES is defined to be the empty string. How is that harmful?


If it were strictly necessary to detect "no such file or no such key", then checking the exit status of 'defaults' is simpler:
example=$(defaults read ~/.MacOSX/environment DYLD_INSERT_LIBRARIES 2>/dev/null || echo "###")

If defaults has any non-zero exit status (i.e. no such file or no such key), then example will be assigned the string "###" (any other distinctive string would suffice). It's not necessary to parse the stderr messages looking for a grep pattern. Using the exit status of defaults is sufficient in this case.

I also see that your example is still using the wrong syntax for defaults [1]. So it will behave as if the file and/or key doesn't exist, producing a false negative.


Likewise for the removal, a script can't be made by the information posted by Fsecure since the exact output is not known.
It is entirely possible to script the "use the path retrieved from the plist" procedure using PListBuddy. It's also possible using defaults and awk. I'm not going to suggest it's trivial, or even simple (as such scripts go). It is, however, quite possible to get the value assigned to DYLD_INSERT_LIBRARIES and do something with that pathname.

I surmise that Fsecure simply isn't interested in producing a free solution, since they explicitly say that non-advanced users should contact their support.

There may even be a better choice of scripting language than bash. Perhaps python or perl.

Personally, I'm not going to spend a lot of time on it, because none of the Mac users I know personally have this infection, and the ones I talked to recently are well aware of how to avoid it.


[1] according to this Fsecure web page (http://www.f-secure.com/weblog/archives/00002336.html) and this one (http://www.f-secure.com/v-descs/trojan-downloader_osx_flashback_i.shtml).

----------

Really? If you are not capable of writing it, how are you going to assess that the script you are using is correct? The best is to follow the exact instructions given by Fsecure.

You're right, I rescind my suggestion.

The best strategy is to not compound one mistake with another, and to not trust scripts posted from unknown sources, no matter how good they might look at first glance.

subsonix
Apr 7, 2012, 07:33 PM
I'm not following your logic.

If you didn't redirect and grep the stderr stream, the value assigned to the variable is "" (empty string). How is that not a definitive indicator that there is either no such file, or no such key?

It's conceivable that the file does exist, and the key exists with a value of "" (empty string), and this would not be a uniquely detectable condition. I'm not seeing how it's harmful, though, since it means DYLD_INSERT_LIBRARIES is defined to be the empty string. How is that harmful?


Calm down, I'm using an example that fits the code in post 1 and explicitly test the condition posted by Fsecure.


If it were strictly necessary to detect "no such file or no such key", then checking the exit status of 'defaults' is simpler:
example=$(defaults read ~/.MacOSX/environment DYLD_INSERT_LIBRARIES 2>/dev/null || echo "###")

If defaults has any non-zero exit status (i.e. no such file or no such key), then example will be assigned the string "###" (any other distinctive string would suffice). It's not necessary to parse the stderr messages looking for a grep pattern. Using the exit status of defaults is sufficient in this case.


Technically correct, and you could come up with 5 or more different ways of doing it, the point was to replicate what was known exactly.


I also see that your example is still using the wrong syntax for defaults [1]. So it will behave as if the file and/or key doesn't exist, producing a false negative.


Yeah that's correct I simply copy pasted it from the first post.


It is entirely possible to script the "use the path retrieved from the plist" procedure using PListBuddy. It's also possible using defaults and awk. I'm not going to suggest it's trivial, or even simple (as such scripts go). It is, however, quite possible to get the value assigned to DYLD_INSERT_LIBRARIES and do something with that pathname.

I surmise that Fsecure simply isn't interested in producing a free solution, since they explicitly say that non-advanced users should contact their support.

There may even be a better choice of scripting language than bash. Perhaps python or perl.

Personally, I'm not going to spend a lot of time on it, because none of the Mac users I know personally have this infection, and the ones I talked to recently are well aware of how to avoid it.

Golf clap.

chown33
Apr 7, 2012, 07:57 PM
Yeah that's correct I simply copy pasted it from the first post.

Except you lost the ~.

OP:
VAR1=$( defaults read ~/.MacOSX/environment/DYLD_INSERT_LIBRARIES )

Your revised code:
DYLD=$(defaults read /.MacOSX/environment DYLD_INSERT_LIBRARIES 2>&1 | grep -E "( does not exist)$")

subsonix
Apr 7, 2012, 08:05 PM
Except you lost the ~.

Thanks.

You almost never post code.

chown33
Apr 9, 2012, 01:16 PM
Source for an Objective-C app that checks for infection:
https://github.com/jils/FlashbackChecker
(For OS version 10.5 and up)

Via this article on Ars Technica (http://arstechnica.com/apple/news/2012/04/checking-for-mac-flashback-infestation-theres-an-app-for-that.ars).


I wonder how many of the affected Macs are running an OS and Java version so old they can't be updated? Or on hardware so old they can't be updated?

If they're not updatable, this malware is a persistent threat (http://en.wikipedia.org/wiki/Advanced_persistent_threat) to those machines. The only easy prevention mechanism would be the "disable Java" checkbox in Safari's security preferences window.

subsonix
Apr 9, 2012, 02:25 PM
I wonder how many of the affected Macs are running an OS and Java version so old they can't be updated? Or on hardware so old they can't be updated?


Turning off Java in the browser should take care of that. I have had it turned off for several years without noticing any difference, I can probably count the instances on one hand where it had to be turned on explicitly for some reason.