Archives for the Month of August, 2005

Monad and the "First Vista Virus"

F-Secure has reported on some recent work by Second Part To Hell on a Monad scripting virus ("First Vista Virus Found"). It's a misleading title, as it's an issue that affects any vehicle for any executable code on any operating system. There's an excellent treatment of shell script viruses on Virus Bulletin that covers this issue, but predates it by 2 years: Unix Shell Scripting Malware.

The fact that MSH is used as the execution vehicle is really a side-note, as it does not exploit any vulnerabilities in Monad. The guidance on shell script viruses is the same as the guidance on all viruses and malware: protect yourself against the point of entry, and limit the amount of damage that the malicious code can do.

To protect yourself against the point of entry, follow the guidance suggested by Microsoft's Malware FAQ:

The best way to stop viruses is to use common sense. If an executable computer program is attached to your e-mail and you are unsure of the source, then it should be deleted immediately. Do not download any applications or executable files from unknown sources, and be careful when trading files with other users.

To limit the amount of damage that the malicious code can do, try to limit the amount of time you run as Administrator / root.  Aaron Margosis has an excellent blog on how to run as non-Administrator.

Now, this isn't meant to be dismissive of the very real threat of scripting viruses. In the real world, it's very hard to protect yourself against the point of entry.

To combat this, Monad has three features to help: not installing a shell association by default, configurable execution policies (along with digitally signing scripts,) and not running scripts from the current directory.

In the past, many viruses have injected themselves into a user's system when they double-click on the file. This is especially true in the case of email attachments. Windows then looks for the program that understands the file, and tells the program to run it. This is known as a shell association. Double-clicking on a .txt file opens Notepad. Double clicking on a .html page opens your browser of choice. Our installer doesn't tell Windows that it understands .msh scripts, so double-clicking on a .msh file does nothing.

We also support three execution policies to help you run scripts only from publishers that you trust.

The first execution policy, "AllSigned," checks all scripts for a digital signature. Monad asks you if you trust that publisher to run scripts on your system. If you do, Monad will run the script. If you don't, it won't. If the file doesn't have a digital signature, Monad won't run the file. Monad contains functionality to let you digitally sign your own scripts to help you run in this mode. This will be our default execution policy past beta.

The second execution policy, "RemoteSigned," checks scripts origintating from the Internet for a digital signature. If a script originates from the Internet, Monad goes through the same process that it does in the "AllSigned" mode. If the script does not originate from the Internet, it runs the script. This is the mode that our betas are configured for.

The final execution policy, "Unrestricted," does not check the digital signatures on scripts. However, if a script originates from the internet, it will warn (and prompt you) before it runs it.

As for not running scripts in the current directory, Monad follows a policy similar to that of Unix shells: we do not run them, unless you explicitly ask us to. This prevents malicious scripts (with names such as dir.msh, or get-childitem.msh) from intercepting your otherwise innocent attempt to list the files in that directory.

[Edit: Monad has now been renamed to Windows PowerShell. This script or discussion may require slight adjustments before it applies directly to newer builds.]

Reminder: Monad Technet Webcast

Just as a reminder, the first Monad technet webcast is happening today (9:30am PST to 11:00 am PST): http://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?EventID=1032277850&EventCategory=4&culture=en-US&CountryCode=US.

The next one is next week, I'll post a reminder then, as well.

I posted more about the Technet Webcasts here.

[Edit: Monad has now been renamed to Windows PowerShell. This script or discussion may require slight adjustments before it applies directly to newer builds.]

A Download Manager in MSH

I recently stumbled upon this blog entry that expanded on a piece I wrote a few days ago: Command Line Shortcut for Repetitive Operations. (Hankatsu?)'s entry is in Japanese, so I don't know what it says. In fact, for all I know, he or she could be making fun of me. In any case, the code included with the blog entry shows a quck way to download sequentially numbered files from the internet -- such as File001.jpg, File002.jpg, etc. That's a great use of the technique, and we can improve it even further with a useful script that acts as a download manager.

This was one of the first Monad scripts I wrote (about 2.5 years ago,) and I've faithfully ported it through every one of the many breaking changes that have happened since then 🙂 It originally relied heavily on the Windows port of wget, but I was able to finally remove that a few weeks ago when I noticed that the .Net framework now supports the WebClient.DownloadFile() method.

It's one of my most heavily used scripts -- it's not very complex, but sure is useful.

## download-queue.msh
## Acts as a download manager, to download batches of files.
##
## 1) Create a directory, and place "download-queue.msh" in it.
## 2) Create a subdirectory, called "Queue"
## 3) Inside the "Queue" directory, place .txt files that contain only URLs in them.
##
## Download-queue.msh will use the name of the text file to create a new subdirectory.
## It will place the downloaded files inside that subdirectory.

## Ensure the System.Net and System.Web DLLs are loaded
[void] [Reflection.Assembly]::LoadWithPartialName("System.Net")
[void] [Reflection.Assembly]::LoadWithPartialName("System.Web")

## Keep on processing the queue directory, while there are batches
## remaining
while($(get-childitem Queue\*.txt).Length -gt 0)
{
 ## Get all of the .txt files in the queue directory
 foreach($file in $(get-childitem Queue\*.txt))
 {
  write-host "Processing: $file"

  ## Create a directory, based on the filename (minus extension)
  ## of the text file
  $name = $file.Name.Replace(".txt", "")
  $null = new-item -name $name -type Directory
  set-location $name

  ## Download each item in the file
  foreach($url in (get-content $file))
  {
   ## Strip the filename out of the URL
   if($url -match ".*/(?<file>.*)")
   {
    $filename = $matches["file"]
    $filename = combine-path "$(get-location)" "$([System.Web.HttpUtility]::URlDecode($filename))"

    write-host " Downloading: $url"
    $webClient = new-object System.Net.WebClient
    $webClient.DownloadFile($url, $filename)
   }
   else
   {
    write-host "$url is not a valid URI."
   }
  }

  ## Move the file list into the directory, also
  move-item (combine-path "..\Queue" ($file.Name)) .

  set-location ..
 }
}

For now, you're on your own for generating the queue files. Right-clicking "Copy Shortcut" in your browser is a great way to get URLs. Batching them this way is many times faster than downloading each file individually.

Here it is in action:

MSH:297 C:\Temp >md Queue

    Directory: FileSystem::C:\Temp

Mode    LastWriteTime            Length Name
----    -------------            ------ ----
d----   Aug 02 21:10                    Queue

MSH:299 C:\Temp >echo "https://www.leeholmes.com/blog/images/rssButton.gif" > Queue\LeeHolmes.com.txt
MSH:300 C:\Temp >echo "
https://www.leeholmes.com/blog/images/xmlCoffeeMug.gif" >> Queue\LeeHolmes.com.txt
MSH:301 C:\Temp >download-queue
Processing: C:\Temp\Queue\LeeHolmes.com.txt
 Downloading:
https://www.leeholmes.com/blog/images/rssButton.gif
 Downloading: https://www.leeholmes.com/blog/images/xmlCoffeeMug.gif
MSH:302 C:\Temp >dir LeeHolmes.com

    Directory: FileSystem::C:\Temp\LeeHolmes.com

Mode    LastWriteTime            Length Name
----    -------------            ------ ----
-a---   Aug 02 21:12                107 LeeHolmes.com.txt
-a---   Aug 02 21:12               1025 rssButton.gif
-a---   Aug 02 21:12               1486 xmlCoffeeMug.gif

Stay tuned -- in the near future, I'll write a post that shows how to parse all of the URLs out of a web page.

[Edit: I've updated the script, to make it a little less sensitive to URLs with funky characters.]
[Edit: I've now posted my link parser script, so you don't have to generate these files manually anymore.]

[Edit: Monad has now been renamed to Windows PowerShell. This script or discussion may require slight adjustments before it applies directly to newer builds.]