aboutsummaryrefslogtreecommitdiffstats
path: root/ramfs
diff options
context:
space:
mode:
Diffstat (limited to 'ramfs')
-rwxr-xr-xramfs/bin/busyboxbin0 -> 1005608 bytes
-rwxr-xr-xramfs/bin/ptreebin0 -> 58940 bytes
l---------ramfs/bin/sh1
-rw-r--r--ramfs/home/.profile5
-rw-r--r--ramfs/home/README21
-rwxr-xr-xramfs/init29
-rwxr-xr-xramfs/sbin/dhcpassign.sh34
-rw-r--r--ramfs/src/linux-3.5.4-ptree.patch115
-rw-r--r--ramfs/src/ptree.c79
9 files changed, 284 insertions, 0 deletions
diff --git a/ramfs/bin/busybox b/ramfs/bin/busybox
new file mode 100755
index 0000000..e51a71e
--- /dev/null
+++ b/ramfs/bin/busybox
Binary files differ
diff --git a/ramfs/bin/ptree b/ramfs/bin/ptree
new file mode 100755
index 0000000..888c590
--- /dev/null
+++ b/ramfs/bin/ptree
Binary files differ
diff --git a/ramfs/bin/sh b/ramfs/bin/sh
new file mode 120000
index 0000000..c3fa810
--- /dev/null
+++ b/ramfs/bin/sh
@@ -0,0 +1 @@
+busybox \ No newline at end of file
diff --git a/ramfs/home/.profile b/ramfs/home/.profile
new file mode 100644
index 0000000..7a6e604
--- /dev/null
+++ b/ramfs/home/.profile
@@ -0,0 +1,5 @@
+if [ "$(id -u)" == "0" ] ; then
+ PS1='\[\033[01;31m\]hackme\[\033[01;34m\] \W #\[\033[00m\] '
+else
+ PS1='\[\033[01;32m\]not-yet-root@hackme\[\033[01;34m\] \w \$\[\033[00m\] '
+fi
diff --git a/ramfs/home/README b/ramfs/home/README
new file mode 100644
index 0000000..48f8c16
--- /dev/null
+++ b/ramfs/home/README
@@ -0,0 +1,21 @@
+=== Welcome to the ZX2C4 Kernel Challenge ===
+ by Jason A. Donenfeld <Jason@zx2c4.com>
+
+
+Pwn the kernel and pop a root shell!
+
+Source is available inside /src.
+
+
+eth0 receives an IP address via dhcp. It may be helpful to do
+development on the host and send binaries to the VM:
+
+On the VM:
+ /home $ while true; do nc -l -p 1234 > a; chmod +x a; ./a; done
+
+On the host:
+ $ gcc -static -o a vuln.c && nc 192.168.56.102 1234 < a
+
+
+More information about this project is available at:
+ <http://git.zx2c4.com/kernel-pwn-challenge/about/>
diff --git a/ramfs/init b/ramfs/init
new file mode 100755
index 0000000..cb64951
--- /dev/null
+++ b/ramfs/init
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+mkdir -p /dev /proc /sys /etc
+[ ! -e /dev/console ] && mknod /dev/console c 5 1
+[ ! -e /dev/null ] && mknod /dev/null c 1 3
+[ ! -e /dev/tty ] && mknod /dev/tty c 5 0
+[ ! -e /dev/urandom ] && mknod /dev/urandom c 1 9
+[ ! -e /dev/random ] && mknod /dev/random c 1 8
+[ ! -e /dev/zero ] && mknod /dev/zero c 1 5
+
+mount -t sysfs sysfs /sys
+mount -t proc proc /proc
+mount -t devtmpfs devtmpfs /dev
+echo 0 > /proc/sys/kernel/printk
+/bin/busybox --install -s
+ifconfig eth0 up
+udhcpc -b -i eth0 -s /sbin/dhcpassign.sh
+rm /init
+clear
+
+export HOME=/home
+export ENV=$HOME/.profile
+chown -R 1000:1000 $HOME
+cd $HOME
+while true; do
+ cat README
+ setsid sh -c 'exec sh --login -c "exec chpst -u 1000:1000 /bin/sh" </dev/tty1 >/dev/tty1 2>&1'
+ clear
+done
diff --git a/ramfs/sbin/dhcpassign.sh b/ramfs/sbin/dhcpassign.sh
new file mode 100755
index 0000000..347a37c
--- /dev/null
+++ b/ramfs/sbin/dhcpassign.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+RESOLV_CONF="/etc/resolv.conf"
+[ -n "$broadcast" ] && BROADCAST="broadcast $broadcast"
+[ -n "$subnet" ] && NETMASK="netmask $subnet"
+
+case "$1" in
+ deconfig)
+ /sbin/ifconfig $interface 0.0.0.0
+ ;;
+
+ renew|bound)
+ /sbin/ifconfig $interface $ip $BROADCAST $NETMASK
+
+ if [ -n "$router" ] ; then
+ echo "deleting routers"
+ while route del default gw 0.0.0.0 dev $interface ; do
+ :
+ done
+
+ for i in $router ; do
+ route add default gw $i dev $interface
+ done
+ fi
+
+ echo -n > $RESOLV_CONF
+ [ -n "$domain" ] && echo search $domain >> $RESOLV_CONF
+ for i in $dns ; do
+ echo nameserver $i >> $RESOLV_CONF
+ done
+ ;;
+esac
+
+exit 0
diff --git a/ramfs/src/linux-3.5.4-ptree.patch b/ramfs/src/linux-3.5.4-ptree.patch
new file mode 100644
index 0000000..ee6182d
--- /dev/null
+++ b/ramfs/src/linux-3.5.4-ptree.patch
@@ -0,0 +1,115 @@
+diff -ru linux-3.5.4/arch/x86/syscalls/syscall_64.tbl linux-3.5.4-compile/arch/x86/syscalls/syscall_64.tbl
+--- linux-3.5.4/arch/x86/syscalls/syscall_64.tbl 2012-09-15 00:28:08.000000000 +0200
++++ linux-3.5.4-compile/arch/x86/syscalls/syscall_64.tbl 2012-09-28 04:45:49.232275782 +0200
+@@ -319,6 +319,7 @@
+ 310 64 process_vm_readv sys_process_vm_readv
+ 311 64 process_vm_writev sys_process_vm_writev
+ 312 common kcmp sys_kcmp
++313 common ptree sys_ptree
+
+ #
+ # x32-specific system call numbers start at 512 to avoid cache impact
+diff -ru linux-3.5.4/include/linux/sched.h linux-3.5.4-compile/include/linux/sched.h
+--- linux-3.5.4/include/linux/sched.h 2012-09-15 00:28:08.000000000 +0200
++++ linux-3.5.4-compile/include/linux/sched.h 2012-09-28 04:45:49.273275264 +0200
+@@ -465,6 +465,16 @@
+ u32 incr_error;
+ };
+
++struct prinfo {
++ long state;
++ pid_t pid;
++ pid_t parent_pid;
++ pid_t first_child_pid;
++ pid_t next_sibling_pid;
++ long uid;
++ char comm[64];
++};
++
+ /**
+ * struct task_cputime - collected CPU time counts
+ * @utime: time spent in user mode, in &cputime_t units
+diff -ru linux-3.5.4/kernel/sched/core.c linux-3.5.4-compile/kernel/sched/core.c
+--- linux-3.5.4/kernel/sched/core.c 2012-09-15 00:28:08.000000000 +0200
++++ linux-3.5.4-compile/kernel/sched/core.c 2012-09-30 11:01:31.395166872 +0200
+@@ -4453,6 +4453,80 @@
+ return retval;
+ }
+
++/*
++ * Does a depth first search through the entire process tree.
++ * nr is a pointer to the number of entries that should be put
++ * into the address specified by buf. nr is set to the number
++ * of entries actually put into that buffer.
++ */
++SYSCALL_DEFINE2(ptree, struct prinfo *, buf, unsigned int *, nr)
++{
++ unsigned int count, max;
++ int ret, moved_up;
++ struct prinfo info;
++ struct task_struct *task, *child, *sibling;
++
++ ret = 0;
++ count = 0;
++
++ if (!nr)
++ return -EINVAL;
++ if (get_user(max, nr)) {
++ ret = -EFAULT;
++ goto out;
++ }
++ if (!buf) {
++ ret = -EINVAL;
++ goto out;
++ }
++
++ memset(&info, 0, sizeof(info));
++ task = &init_task;
++ moved_up = 0;
++ rcu_read_lock();
++ while (task && count < max) {
++ child = list_empty(&task->children) ? NULL : list_first_entry(&task->children, struct task_struct, sibling);
++ sibling = list_empty(&task->sibling) ? NULL : list_first_entry(&task->sibling, struct task_struct, sibling);
++
++ /* If we're not traversing back up the list, and we're not init_task,
++ * then this is a task we want. */
++ if (!moved_up && task->pid) {
++ info.state = task->state;
++ info.pid = task->pid;
++ info.parent_pid = task->parent->pid;
++ info.first_child_pid = child ? child->pid : 0;
++ info.next_sibling_pid = sibling ? sibling->pid : 0;
++ info.uid = task->cred->uid;
++ get_task_comm(info.comm, task);
++ if (copy_to_user(&(buf[count++]), &info, sizeof(struct prinfo))) {
++ ret = -EFAULT;
++ break;
++ }
++ }
++ /* If we have just moved back up the list, or if we're at a leaf node... */
++ if (moved_up || !child) {
++ if (!task->parent)
++ break;
++
++ /* If there are no other siblings to hang out with, move up another
++ * level to the parent. */
++ if (list_is_last(&task->sibling, &task->parent->children)) {
++ task = task->parent;
++ moved_up = 1;
++ } else { /* Otherwise, check out the sibling. */
++ task = sibling;
++ moved_up = 0;
++ }
++ } else /* Otherwise, next time examine the next child. */
++ task = child;
++ }
++ rcu_read_unlock();
++out:
++ /* nr should be the number of entries copied */
++ *nr = count;
++ return ret;
++}
++
+ /**
+ * sys_sched_setscheduler - set/change the scheduler policy and RT priority
+ * @pid: the pid in question.
diff --git a/ramfs/src/ptree.c b/ramfs/src/ptree.c
new file mode 100644
index 0000000..2773140
--- /dev/null
+++ b/ramfs/src/ptree.c
@@ -0,0 +1,79 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#define __NR_ptree 313
+
+struct prinfo {
+ long state;
+ pid_t pid;
+ pid_t parent_pid;
+ pid_t first_child_pid;
+ pid_t next_sibling_pid;
+ long uid;
+ char comm[64];
+};
+
+static inline int ptree(struct prinfo *processes, unsigned int *count)
+{
+ return syscall(__NR_ptree, processes, count);
+}
+
+static pid_t find_parent(struct prinfo *processes, unsigned int count, pid_t pid)
+{
+ int i;
+ for (i = 0; i < count; ++i) {
+ if (processes[i].pid == pid)
+ return processes[i].parent_pid;
+ }
+ return 0;
+}
+
+static int hilariously_inefficient_method_of_finding_indentation_level(struct prinfo *processes, unsigned int count, pid_t pid)
+{
+ int indentation = 0;
+ while((pid = find_parent(processes, count, pid)))
+ ++indentation;
+ return indentation;
+
+ /* Bonus points if you can find a reasonable _looking_
+ * algorithm that is even more inefficient. */
+}
+
+int main(int argc, char *argv[])
+{
+ struct prinfo *processes;
+ unsigned int count, indentation, i, j;
+ pid_t last_ppid;
+
+ indentation = 0;
+
+ count = 32768;
+ processes = malloc(sizeof(struct prinfo) * count);
+ if (!processes) {
+ perror("processes");
+ return EXIT_FAILURE;
+ }
+
+ memset(processes, 0, sizeof(struct prinfo) * count);
+
+ if (ptree(processes, &count)) {
+ perror("ptree");
+ return EXIT_FAILURE;
+ }
+
+ for (i = 0; i < count; ++i) {
+ indentation = hilariously_inefficient_method_of_finding_indentation_level(processes, count, processes[i].pid);
+ for (j = 0; j < indentation; ++j)
+ putchar('\t');
+ printf("%s,%d,%ld,%d,%d,%d,%ld\n", processes[i].comm, processes[i].pid,
+ processes[i].state, processes[i].parent_pid, processes[i].first_child_pid,
+ processes[i].next_sibling_pid, processes[i].uid);
+ }
+
+ printf("%d processes\n", count);
+
+ return EXIT_SUCCESS;
+}