Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What are the basics of Pwn In Kernel

2025-02-28 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article introduces the relevant knowledge of "what are the basic knowledge of Pwn In Kernel". In the operation of actual cases, many people will encounter such a dilemma. Then let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!

Briefly analyze the form of CTF Kernel Pwn questions, taking 2017 CISCN babydrive as an example.

Decompress the file package first

➜example ls babydriver.tar➜ example file babydriver.tar babydriver.tar: POSIX tar archive ➜example tar-xvf babydriver.tar boot.sh bzImage rootfs.cpio➜ example ls babydriver.tar boot.sh bzImage rootfs.cpio

Get three files of boot.sh,bzImage,rootfs.cpio

Boot.sh ➜example cat-n boot.sh 1 #! / bin/bash 2 qemu-system-x86_64\ 3-initrd rootfs.cpio\ 4-kernel bzImage\ 5-append 'console=ttyS0 root=/dev/ram oops=panic panic=1'\ 6-enable-kvm\ 7-monitor / dev/null\ 8-m 64m\ 9-nographic\ 10-smp cores=1,threads=1\ 11-cpu kvm64,+smep

The boot.sh file is used to start the program. Call qemu to load rootfs.cpio and run with bzImage.

The above parameters are all parameters of qemu.

-initrd rootfs.cpio, using rootfs.cpio as the kernel boot file system-kernel bzImage, using bzImage as the kernel image-cpu kvm64,+smep, setting the security option for CPU. Here, smep-m 64m is enabled, and the virtual RAM is set to 64m. The default is 128MbzImage ➜example file bzImage bzImage: Linux kernel x86 boot executable bzImage, version 4.4.72 (atum@ubuntu) # 1 SMP Thu Jun 15 19:52:50 PDT 2017, RO-rootFS, swap_dev 0x6, Normal VGA

BzImage is a compressed linux kernel file

Rootfs.cpio ➜example file rootfs.cpio rootfs.cpio: gzip compressed data, last modified: Tue Jul 4 08:39:15 2017, max compression, from Unix

This is a linux kernel file system compression package, which we can unzip and recompress to modify the files of this system.

Create a new folder to extract

➜example mkdir fs & & cd fs➜ fs cp.. / rootfs.cpio. / rootfs.cpio.gz ➜fs gunzip. / rootfs.cpio.gz➜ fs cpio-idmv

< rootfs.cpio . etc etc/init.d etc/passwd etc/group bin ...... linuxrc home home/ctf 5556 blocks ➜ fs ll total 2.8M drwxrwxr-x 2 mask mask 4.0K 1 月 20 12:16 bin drwxrwxr-x 3 mask mask 4.0K 1 月 20 12:16 etc drwxrwxr-x 3 mask mask 4.0K 1 月 20 12:16 home -rwxrwxr-x 1 mask mask 396 6 月 16 2017 init drwxr-xr-x 3 mask mask 4.0K 1 月 20 12:16 lib lrwxrwxrwx 1 mask mask 11 1 月 20 12:16 linuxrc ->

Bin/busybox drwxrwxr-x 2 mask mask 4.0K June 15 2017 proc-rwxrwxr-x 1 mask mask 2.8m January 20 12:15 rootfs.cpio drwxrwxr-x 2 mask mask 4.0K January 20 12:16 sbin drwxrwxr-x 2 mask mask 4.0K June 15 2017 sys drwxrwxr-x 2 mask mask 4.0K June 15 2017 tmp drwxrwxr-x 4 mask mask 4.0K January 20 12:16 usr

These are the files that the system has when it is running. Look at the init file.

➜fs cat-n. / init 1 #! / bin/sh 2 3 mount-t proc none / proc 4 mount-t sysfs none / sys 5 mount-t devtmpfs devtmpfs / dev 6 chown root:root flag 7 chmod 400 flag 8 exec 0/dev/console 10 exec 2 > / dev/console 11 12 insmod / lib/modules/4.4.72/babydriver.ko 13 chmod 777 / dev / babydev 14 echo-e "\ nBoot took $(cut-d'- F1 / proc/uptime) seconds\ n" 15 setsid cttyhack setuidgid 1000 sh 16 17 umount / proc 18 umount / sys 19 poweroff-d 0-f

Seeing insmod / lib/modules/4.4.72/babydriver.ko on line 12 means debugging the ko file, parsing it with IDA, and exploiting the vulnerability

This file system is also packaged in this directory.

➜fs find. | | cpio-o-format=newc > rootfs.cpio cpio: File. / rootfs.cpio grew, 43008 new bytes not copied 5640 blocksvmlinux |

Some topics will be given to vmlinux this file, this is the most original compiled kernel file, uncompressed, is an ELF form, easy to find gadget

You can use a tool to export vmlinux,extract-vmlinux from bzImage

➜example. / extarct-vmlinux. / bzImage > vmlinux➜ example file bzImage bzImage: Linux kernel x86 boot executable bzImage, version 4.4.72 (atum@ubuntu) # 1 SMP Thu Jun 15 19:52:50 PDT 2017, RO-rootFS, swap_dev 0x6, Normal VGA ➜example file vmlinux vmlinux: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, BuildID [sha1] = e993ea9809ee28d059537a0d5e866794f27e33b4, strippedexploit

Kernel Pwn is to find out the loopholes in the kernel module, then write a C language program, package it in the file system, and run it again. At this time, the user is generally an ordinary user. The running program calls the function of this module to exploit the loophole, so as to enhance the authority to root users and read flag.

/ $lsbin exp lib root sysdev home linuxrc rootfs.cpio tmpetc init proc sbin usr/ $whoamictf/ $. / exp [18.277799] device open [18.278768] device open [18.279760] alloc done [18.280706] device release/ # whoamiroot

During the competition, the base64 code of the C language program is usually uploaded to the server, and then run.

Kernel Pwn Debug

To debug the kernel module, add it to the startup script

-gdb tcp::1234

Then use gdb to connect

Gdb-Q-ex "target remote localhost:1234"

If Remote 'g' packet reply is too long is displayed as a long string of numbers, set up the schema

Gdb-Q-ex "set architecture i386:x86-64:intel"-ex "target remote localhost:1234"

To debug kernel modules, you can first look at the kernel load address, which is the information of each loaded module in / sys/module/

/ $cd sys/module/ / sys/module $ls 8250 ipv6 scsi_mod acpi kdb sg acpi_cpufreq kernel spurious Acpiphp keyboard sr_mod apparmor kgdb_nmi suspend ata_generic kgdboc sysrq ata_piix libata tcp_cubic babydriver loop thermal battery md_mod Tpm block module tpm_tis core mousedev uhci_hcd cpuidle netpoll uinput debug_core pata_sis usbcore dm_mod pcc_cpufreq virtio_balloon Dns_resolver pci_hotplug virtio_blk dynamic_debug pci_slot virtio_mmio edd pcie_aspm virtio_net efivars pciehp virtio_pci ehci_hcd ppp_generic vt elants_i2c printk Workqueue ext4 processor xen_acpi_processor firmware_class pstore xen_blkfront fuse rcupdate xen_netfront i8042 rcutree xhci_hcd ima rfkill xz_dec intel_idle rng_core zswap

Get the load address of the babydrive module

/ sys/module $cd babydriver/ / sys/module/babydriver $ls coresize initsize notes sections taint holders initstate refcnt srcversion uevent / sys/module/babydriver $cd sections/ / sys/module/babydriver/sections $grep 0.text 0xffffffffc0000000

By loading symbol information in gdb, you can debug the kernel module.

Pwndbg > add-symbol-file. / fs/lib/modules/4.4.72/babydriver.ko 0xffffffffc0000000add symbol table from file ". / fs/lib/modules/4.4.72/babydriver.ko" at. Text _ addr = 0xffffffffc0000000Reading symbols from. / fs/lib/modules/4.4.72/babydriver.ko...done.pwndbg > b*babyopen Breakpoint 1 at 0xffffffffc0000030: file / home/atum/PWN/my/babydriver/kernelmodule/babydriver.c, line 28.Basic KnowledgeKernel

Kernel is a program, which is used at the bottom of the operating system to manage various requests issued by the upper software. Kernel converts various requests into instructions and gives them to the hardware to process. In short, Kernel is the middle layer that connects the software and the hardware.

Kernel mainly provides two functions, which interact with hardware and provide application running environment.

In the CPU of intel, the permissions of CPU are divided into Ring 0, Ring 1, Ring 2, Ring 3, and four levels, with decreasing permissions in turn, and resources with low permission levels can be called with high permission levels.

In a common system (Windows,Linux,MacOS), the kernel is at Ring 0 level and the application is at Ring 3 level

LKM

The kernel module is a socket provided by Linux Kernel to the outside, called dynamically loadable kernel module (Loadable Kernel Module,LKM). LKM makes up for the expandability and maintainability of Linux Kernel. Like building blocks, you can connect all kinds of LKM to Kernel or uninstall it. A common peripheral driver is a LKM.

LKM files, like executable files in user mode, are ELF files in Linux, which can be analyzed by IDA.

LKM is compiled separately, but cannot be run alone, it can only be used as part of OS Kernel

There are several instructions related to LKM

Insmod: access the designated module

Rmmod: remove specified module

Lsmod: lists loaded modules

These are shell instructions that can be run in shell to view

➜~ lsmod Module Size Used byrfcomm 77824 2vmw_vsock_vmci_transport 32768 2vsock 36864 3 vmw_vsock_vmci_transport.ioctl

Ioctl is a function in the device driver to manage the device's I _ max O channel.

The so-called management of the Icano channel is to control some characteristics of the equipment, such as the transmission baud rate of the serial port, the speed of the motor and so on. The number of its calls is as follows: int ioctl (int fd, ind cmd,...)

Fd is the file identifier returned by the user program when opening the device using the open function, and cmd is the control command of the user program to the device. As for the following ellipsis, it is some supplementary parameter, generally at most one. Whether this parameter is related to the meaning of cmd or not.

The ioctl function is an attribute component of the file structure, that is, if your driver provides support for ioctl, the user can use the ioctl function in the user program to control the device's Imax O channel.

It means that if the iotcl function is provided in a LKM and the operation of the corresponding instruction is implemented, then in the user mode, through this driver, we can call ioctl to invoke the operation in the module directly.

Land Switch

When the program is running, it always goes through the switch before user space and kernel space, because when the user-mode application performs some functions, it is performed by Kernel, which involves the switching before the two space.

User land-> kernel land

When the user mode program executes system calls, exception handling, and peripheral terminals, it will switch from user mode to kernel mode. The switching process is as follows:

1.swapgs instruction modifies the GS register to switch to kernel state

two。 Record the current top of the stack (sp) in the CPU exclusive variable area, and then assign the top of the kernel stack in this area to sp

The value of each register of 3.push

4. Judge whether it is 32-bit or not by assembling instructions

5. Through the system call number, the response operation is performed by using the function table sys_call_table.

ENTRY (entry_SYSCALL_64) / * SWAPGS_UNSAFE_STACK is a macro. X86 is directly defined as the swapgs instruction * / SWAPGS_UNSAFE_STACK / * to save stack values and set kernel stack * / movq% rsp, PER_CPU_VAR (rsp_scratch) movq PER_CPU_VAR (cpu_current_top_of_stack), and% rsp/* saves register values through push Form a pt_regs structure * / / * Construct struct pt_regs on stack * / pushq $_ _ USER_DS / * pt_regs- > ss * / pushq PER_CPU_VAR (rsp_scratch) / * pt_regs- > sp * / pushq% R11 / * pt_regs- > flags * / pushq $_ USER_CS / * pt_regs- > cs * / pushq% rcx / * pt_regs- > ip * / Pushq% rax / * pt_regs- > orig_ax * / pushq% rdi / * pt_regs- > di * / pushq% rsi / * pt_regs- > si * / pushq% rdx / * pt_regs- > dx * / pushq% rcx tuichu / * pt_regs- > cx * / pushq $- ENOSYS / * pt_regs- > ax * / pushq% R8 / * pt_regs- > R8 * / pushq% R9 / * pt_regs- > R9 * / pushq% R10 / * pt_regs- > R10 * / pushq% R11 / * pt_regs- > R11 * / sub $(6x8) % rsp / * pt_regs- > bp, bx, R12-15 not saved * /

Kernel land-> user land

Kernel state returns user state flow:

1.swapgs instruction recovery user mode GS register

2.sysretq or iretq restore to user space

Kernel Functions

There are some differences in functions between kernel state and user state.

Printk: similar to printf, but the content may not necessarily be displayed on the terminal, but it will be in the kernel buffer, which can be viewed with the dmsg command

Copy_from_user: implements the transfer of user space data to kernel space

Copy_to_user: implements the transfer of kernel space data to user space

Kmalloc: kernel state memory allocation function

Kfree: kernel state memory release function

The function used to change permissions:

Int commit_creds (struct cred * new)

Struct cred prepare_kernel_cred (struct task_struct daemon)

Execute commit_creds (prepare_kernel_cred (0)) to get root permission

Expoit Mitigations

The protection mode of kernel mode is different from that of user mode.

The same protective measure: DEP,Canary,ASLR,PIE,RELRO

Different protective measures: MMAP_MIN_ADDR,KALLSYMS,RANDSTACK,STACKLEAK,SMEP,SMAP

MMAP_MIN_ADDR

The MMAP_MIN_ADDR protection mechanism does not allow programs to allocate low memory addresses and can be used to defend against null pointer dereferences.

Without this protection, the following attacks can be carried out:

1. The function pointer is 0, and the program can allocate memory to 0x000000.

two。 The program writes malicious code in memory 0x000000.

3. The program triggers kernel BUG (). The BUG () mentioned here is actually used in linux kernel to intercept the behavior of kernel programs that exceed expectations, and it belongs to a mechanism for software to actively report exceptions.

4. The kernel executes malicious code.

KALLSYMS

/ proc/kallsyms gives the addresses of all symbol in the kernel, and you can get the addresses of the corresponding functions through grep / proc/kallsyms. We need this information to write reliable exploit, otherwise we need to leak this information ourselves. The contents can be read by all users in the lower version of the kernel, and 0 is returned when the user lacks permissions in the higher version of the kernel.

SMEP

Administrative mode performs protection, which protects the kernel from allowing user-space code to be executed. With SMEP protection off, if there is a kernel stack overfolw, the return address of the kernel stack can be overwritten as a snippet of code in user space. When SMEP protection is enabled, cpu is currently in ring 0 mode, and a page error will be triggered when returning to user mode execution.

The operating system determines whether SMEP is enabled by the value of the 20th bit of the CR4 register, 1 on, 0 off, and checks whether SMEP is enabled.

Cat / proc/cpuinfo | grep smep

You can use mov instructions to assign values to CR4 registers to achieve the purpose of closing SMEP, and related mov instructions can be found through tools such as ropper,ROPgadget.

SMAP

Administrative mode access protection, which prevents the kernel from accessing data in user space

KASLR

Kernel address space layout randomization, which is not turned on by default, needs to add specified instructions to the kernel command line.

Qemu can be enabled by adding startup parameter-append "kaslr".

Privilege Escalation

To extract and jailbreak is to get shell and root by root users.

Call commit_creds (prepare_kernel_cred (0)) in kernel mode, and return to user mode to execute shell.

Void get_r00t () {commit_creds (prepare_kernel_cred (0));} int main (int argc, char * argv) {... Trigger_fp_overwrite (& get_r00t); / / trigger fp use trigger_vuln_fp (); / / Kernel Executes get_r00t ()... / / Now we have root system ("/ bin/sh");}

SMEP protects against this type of attack by triggering a page error if the processor is in ring0 mode and tries to execute memory with user data.

You can also modify the cred structure. The cred structure records the permissions of the process. Each process has a cred structure, which stores the process's permissions and other information (uid,gid). If you modify the cred structure of a process (uid = gid = 0), you get the root permission.

Struct cred {atomic_t usage;#ifdef CONFIG_DEBUG_CREDENTIALS atomic_t subscribers; / * number of processes subscribed * / void * put_addr; unsigned magic;#define CRED_MAGIC 0x43736564#define CRED_MAGIC_DEAD 0x44656144#endif kuid_t uid; / * real UID of the task * / kgid_t gid; / * real GID of the task * / kuid_t suid / * saved UID of the task * / kgid_t sgid; / * saved GID of the task * / kuid_t euid; / * effective UID of the task * / kgid_t egid; / * effective GID of the task * / kuid_t fsuid; / * UID for VFS ops * / kgid_t fsgid; / * GID for VFS ops * / unsigned securebits / * SUID-less security management * / kernel_cap_t cap_inheritable; / * caps our children can inherit * / kernel_cap_t cap_permitted; / * caps we're permitted * / kernel_cap_t cap_effective; / * caps we can actually use * / kernel_cap_t cap_bset; / * capability bounding set * / kernel_cap_t cap_ambient / * Ambient capability set * / # ifdef CONFIG_KEYS unsigned char jit_keyring; / * default keyring to attach requested * keys to * / struct key_ _ rcu * session_keyring; / * keyring inherited over fork * / struct key * process_keyring; / * keyring private to this process * / struct key * thread_keyring; / * keyring private to this thread * / struct key * request_key_auth / * assumed request_key authority * / # endif#ifdef CONFIG_SECURITY void * security; / * subjective LSM security * / # endif struct user_struct * user; / * real user ID subscription * / struct user_namespace * user_ns; / * user_ns the caps and keyrings are relative to. * / struct group_info * group_info; / * supplementary groups for euid/fsgid * / struct rcu_head rcu; / * RCU deletion hook * /} _ _ randomize_layout;Build Linux KernelSource Code

First download a copy of the Kernel source code, I use 2.6.32, because my machine is ubuntu 16.04, the pre-installed make and gcc version is too high, the compilation of 2.6kernel will fail, so I need to downgrade

# 4.7 gccsudo apt install gcc-4.7 g++-4.7sudo rm / usr/bin/gcc / usr/bin/g++sudo ln-s / usr/bin/gcc-4.7 / usr/bin/gccsudo ln-s / usr/bin/g++-4.7 / usr/bin/g++# 3.80 makewget https://mirrors.tuna.tsinghua.edu.cn/gnu/make/make-3.80.tar.gztar-xvf make-3.80.tar.gzcd make-3.80/./configuremakesudo make install

3.80 make is generated in the source directory. You need to use this make file later.

Modify three 2.6 source files

In 1.arch/x86/vdso/Makefile,-m elf_x86_64 in line 28 is changed to-M64, and-m elf_i386 in line 72 is changed to-M32

Line 128 of comments in 2.drivers/net/igbvf/igbvf.h

Change line 373 of 3.kernel/timeconst.pl defined (@ val) to @ val

4. (optional) turning off canary protection requires editing line 349 of the. config file in the source code and commenting out the item CONFIG_CC_STACKPROTECTOR=y

BzImage

Installation prerequisite dependencies

Sudo apt-get install build-essential libncurses5-dev

After decompressing, enter the source directory and use the newly installed make

~ / MAKE/make-3.80/make menuconfig

Enter kernel hacking, check Kernel debugging,Compile-time checks and compiler options-- > Compile the kernel with debug info,Compile the kernel with frame pointers and KGDB, and then start compiling

~ / MAKE/make-3.80/make bzImage

In about 10 minutes, the appearance of this message indicates that the compilation is successful.

Setup is 15036 bytes (padded to 15360 bytes) System is 3754 kBCRC 4505d1c3Kernel: arch/x86/boot/bzImage is ready (# 1)

Vmlinux is in the source root directory, and bzImage is in / arch/x86/boot/.

Rootfs.cpio

Compile busybox

Wget https://busybox.net/downloads/busybox-1.27.2.tar.bz2tar-jxvf busybox-1.27.2.tar.bz2cd busybox-1.27.2make menuconfig

Check Busybox Settings-> Build Options-> Build Busybox as a static binary

Make install

After the compilation is completed, there will be a _ install folder in the source directory, enter the

Mkdir-pv {bin,sbin,etc,proc,sys,usr/ {bin,sbin}} mkdir etc/init.dtouch etc/init.d/init

Edit the etc/inittab file and add the following (it seems that this step can be omitted)

: sysinit:/etc/init.d/rcS::askfirst:/bin/ash::ctrlaltdel:/sbin/reboot::shutdown:/sbin/swapoff-a::shutdown:/bin/umount-a-r::restart:/sbin/init

Edit the etc/init.d/init file and add the following

#! / bin/shmount-t proc none / procmount-t sys none / sys/bin/mount-n-t sysfs none / sys/bin/mount-t ramfs none / dev/sbin/mdev-s

Then it can be packed into rootfs.cpio.

Chmod + x. / etc/init.d/rcSfind. | | cpio-o-format=newc >.. / rootfs.cpioboot |

After you have three files, you can use qemu to run it and start the script boot.sh

#! / bin/shqemu-system-x86_64\-initrd rootfs.cpio\-kernel bzImage\-nographic\-append "console=ttyS0 root=/dev/ram rdinit=/sbin/init"\-m 64m\-monitor / dev/null\ / # uname-aLinux (none) 2.6.32 # 1 SMP Sun Jan 26 21:51:02 CST 2020 x 86 million 64 GNU/LinuxRun LKMbuild

Simply write a hello program, the hello.c content is as follows

# include # include int hello_write (struct file * file, const char * buf, unsigned long len) {printk ("You write something."); return len;} static int _ init hello_init (void) {printk (KERN_ALERT "hello driver init!\ n"); create_proc_entry ("hello", 0666, 0)-> write_proc = hello_write; return 0 } static void _ exit hello_exit (void) {printk (KERN_ALERT "hello driver exit\ n");} module_init (hello_init); module_exit (hello_exit)

The Makefile content is as follows. Note that the xxx.c file name is the same as the xxx.o file name, and the KERNELDR directory is the kernel source code

Obj-m: = hello.oKERNELDR: = / home/mask/kernel/linux-2.6.32PWD: = $(shell pwd) modules: $(MAKE)-C $(KERNELDR) MIMO $(PWD) modulesmodules_install: $(MAKE)-C $(KERNELDR) MNO $(PWD) modules_installclean: $(MAKE)-C $(KERNELDR) MNO $(PWD) clean

Make came out to get the .ko file.

➜helloworld lshelloc.c helloc.mod.c helloc.o modules.orderhelloc.ko helloc.mod.o Makefile Module.symvers➜ helloworld file helloc.ko helloc.ko: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), BuildID [sha1] = 08aaa94df43f8333c149073cddf3043e52b28107 Not stripped ➜helloworld checksec helloc.ko [*]'/ home/mask/kernel/test/linux4.4/module/helloworld/helloc.ko' Arch: amd64-64-little RELRO: No RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x0)

Write another calling program call.c

# include # include int main () {int fd = open ("/ proc/hello", O_WRONLY); write (fd, "Mask", 4); return 0;} run

Copy helloc.ko file and call file.

Enter the file system, that is, the _ install folder in the busybox directory, repackage rootfs.cpio, and you can see the module when you run it.

/ # insmod hello.ko [11.743066] hello driver initations / #. / call [25.860294] You write something. This is the end of the introduction of "what are the basics of Pwn In Kernel". Thank you for reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report