Kernel Pwn In CTF

简单分析一下 CTF Kernel Pwn 题目的形式,以 2017 CISCN babydrive 为例。

先对文件包解压➜ 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

得到 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

boot.sh 文件是用来启动这个程序的,调用 qemu 来加载 rootfs.cpio 与 bzImage 运行起来

上面的参数都是 qemu 的参数-initrd rootfs.cpio,使用 rootfs.cpio 作为内核启动的文件系统

-kernel bzImage,使用 bzImage 作为 kernel 映像

-cpu kvm64,+smep,设置 CPU 的安全选项,这里开启了 smep

-m 64M,设置虚拟 RAM 为 64M,默认为 128M

bzImage➜ 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 是经压缩过的 linux 内核文件

rootfs.cpio➜ example file rootfs.cpio

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

这是一个 linux 内核文件系统压缩包,我们可以对其解压并重新压缩,从而修改这个系统的文件

新建一个文件夹来解压➜ 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 6 月 15 2017 proc

-rwxrwxr-x 1 mask mask 2.8M 1 月 20 12:15 rootfs.cpio

drwxrwxr-x 2 mask mask 4.0K 1 月 20 12:16 sbin

drwxrwxr-x 2 mask mask 4.0K 6 月 15 2017 sys

drwxrwxr-x 2 mask mask 4.0K 6 月 15 2017 tmp

drwxrwxr-x 4 mask mask 4.0K 1 月 20 12:16 usr

这些就是运行起来后这个系统拥有的文件,查看这个 init 文件➜ 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

9 exec 1>/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

看到第 12 行的 insmod /lib/modules/4.4.72/babydriver.ko,意味着要调试这个 ko 文件,使用 IDA 对其进行分析,利用漏洞

对此文件系统进行打包也是要在这个目录下进行➜ fs find . | cpio -o --format=newc > rootfs.cpio

cpio: File ./rootfs.cpio grew, 43008 new bytes not copied

5640 blocks

vmlinux

有些题目会给 vmlinux 这个文件,这是编译出来的最原始的内核文件,未压缩的,是个 ELF 形式,方便找 gadget

可以使用一个工具来从 bzImage 中导出 vmlinux,extract-vmlinux➜ 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, stripped

exploit

Kernel Pwn 就是找出内核模块中的漏洞,然后写一个 C 语言程序,放入文件系统中打包,重新运行取来,此时用户一般都是普通用户,运行程序调用此模块的功能利用漏洞,从而提升权限到 root 用户,读取 flag/ $ ls

bin exp lib root sys

dev home linuxrc rootfs.cpio tmp

etc init proc sbin usr

/ $ whoami

ctf

/ $ ./exp

[ 18.277799] device open

[ 18.278768] device open

[ 18.279760] alloc done

[ 18.280706] device release

/ # whoami

root

比赛时一般是上传 C 语言程序的 base64 编码到服务器,然后运行

Kernel Pwn Debug

要对内核模块进行调试,在启动脚本中加入-gdb tcp::1234

然后使用 gdb 连接gdb -q -ex "target remote localhost:1234"

如果显示 Remote 'g' packet reply is too long 一长串数字,要设置一下架构gdb -q -ex "set architecture i386:x86-64:intel" -ex "target remote localhost:1234"

要调试内核模块,可以先查看内核加载地址,在/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

获取 babydrive 模块的加载地址/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

在 gdb 中载入符号信息,就可以对内核模块进行下断调试pwndbg> add-symbol-file ./fs/lib/modules/4.4.72/babydriver.ko 0xffffffffc00000

00

add symbol table from file "./fs/lib/modules/4.4.72/babydriver.ko" at

.text_addr = 0xffffffffc0000000

Reading symbols from ./fs/lib/modules/4.4.72/babydriver.ko...done.

pwndbg> b*babyopen

Breakpoint 1 at 0xffffffffc0000030: file /home/atum/PWN/my/babydriver/kernelmo

dule/babydriver.c, line 28.

Basic Knowledge

Kernel

Kernel 是一个程序,是操作系统底层用来管理上层软件发出的各种请求的程序,Kernel 将各种请求转换为指令,交给硬件去处理,简而言之,Kernel 是连接软件与硬件的中间层

Kernel 主要提供两个功能,与硬件交互,提供应用运行环境

在 intel 的 CPU 中,会将 CPU 的权限分为 Ring 0,Ring 1,Ring 2,Ring 3,四个等级,权限依次递减,高权限等级可以调用低权限等级的资源

在常见的系统(Windows,Linux,MacOS)中,内核处于 Ring 0 级别,应用程序处于 Ring 3 级别

LKM

内核模块是 Linux Kernel 向外部提供的一个插口,叫做动态可加载内核模块(Loadable Kernel Module,LKM),LKM 弥补了 Linux Kernel 的可拓展性与可维护性,类似搭积木一样,可以往 Kernel 中接入各种 LKM,也可以卸载,常见的外设驱动就是一个 LKM

LKM 文件与用户态的可执行文件一样,在 Linux 中就是 ELF 文件,可以利用 IDA 进行分析

LKM 是单独编译的,但是不能单独运行,他只能作为 OS Kernel 的一部分

与 LKM 相关的指令有如下几个insmod:接入指定模块

rmmod:移除指定模块

lsmod:列出已加载模块

这些都是 shell 指令,可以在 shell 中运行查看➜ ~ lsmod

Module Size Used by

rfcomm 77824 2

vmw_vsock_vmci_transport 32768 2

vsock 36864 3 vmw_vsock_vmci_transport

......

ioctl

ioctl 是设备驱动程序中对设备的 I/O 通道进行管理的函数

所谓对 I/O 通道进行管理,就是对设备的一些特性进行控制,例如串口的传输波特率、马达的转速等等。它的调用个数如下: int ioctl(int fd, ind cmd, …);

其中 fd 是用户程序打开设备时使用 open 函数返回的文件标示符,cmd 是用户程序对设备的控制命令,至于后面的省略号,那是一些补充参数,一般最多一个,这个参数的有无和 cmd 的意义相关

ioctl 函数是文件结构中的一个属性分量,就是说如果你的驱动程序提供了对 ioctl 的支持,用户就可以在用户程序中使用 ioctl 函数来控制设备的 I/O 通道。

意思就是说如果一个 LKM 中提供了 iotcl 功能,并且实现了对应指令的操作,那么在用户态中,通过这个驱动程序,我们可以调用 ioctl 来直接调用模块中的操作

Land Switch

在程序运行时,总是会经历 user space 与 kernel space 之前的切换,因为用户态应用程序在执行某些功能时,是由 Kernel 来执行的,这就涉及到两个 space 之前的切换

user land -> kernel land

当用户态程序执行系统调用,异常处理,外设终端时,会从用户态切换到内核态,切换过程如下:1.swapgs 指令修改 GS 寄存器切换到内核态

2.将当前栈顶(sp)记录在 CPU 独占变量区域,然后将此区域里的内核栈顶赋给 sp

3.push 各寄存器的值

4.通过汇编指令判断是否为 32 位

5.通过系统调用号,利用函数表 sys_call_table 执行响应操作ENTRY(entry_SYSCALL_64)

/* SWAPGS_UNSAFE_STACK 是一个宏,x86 直接定义为 swapgs 指令 */

SWAPGS_UNSAFE_STACK

/* 保存栈值,并设置内核栈 */

movq %rsp, PER_CPU_VAR(rsp_scratch)

movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp

/* 通过 push 保存寄存器值,形成一个 pt_regs 结构 */

/* 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 $(6*8), %rsp /* pt_regs->bp, bx, r12-15 not saved */

kernel land -> user land

内核态返回用户态流程:1.swapgs 指令恢复用户态 GS 寄存器

2.sysretq 或者 iretq 恢复到用户空间

Kernel Functions

内核态与用户态的函数有一些区别printk:类似与 printf,但是内容不一定会在终端显示起来,但是会在内核缓冲区里,可以用 dmsg 命令查看

copy_from_user:实现了将用户空间的数据传送到内核空间

copy_to_user:实现了将内核空间的数据传送到用户空间

kmalloc:内核态内存分配函数

kfree:内核态内存释放函数

用来改变权限的函数:int commit_creds(struct cred *new)

struct cred prepare_kernel_cred(struct task_struct daemon)

执行 commit_creds(prepare_kernel_cred(0)) 即可获得 root 权限

Expoit Mitigations

内核态与用户态的保护方式有所区别

相同的保护措施:DEP,Canary,ASLR,PIE,RELRO

不同的保护措施:MMAP_MIN_ADDR,KALLSYMS,RANDSTACK,STACKLEAK,SMEP,SMAP

MMAP_MIN_ADDR

MMAP_MIN_ADDR 保护机制不允许程序分配低内存地址,可以用来防御 null pointer dereferences

如果没有这个保护,可以进行如下的攻击行为:1.函数指针指针为 0,程序可以分配内存到 0x000000 处。

2.程序在内存 0x000000 写入恶意代码。

3.程序触发 kernel BUG()。这里说的 BUG() 其实是 linux kernel 中用于拦截内核程序超出预期的行为,属于软件主动汇报异常的一种机制。

4.内核执行恶意代码。

KALLSYMS

/proc/kallsyms 给出内核中所有 symbol 的地址,通过 grep /proc/kallsyms 就可以得到对应函数的地址,我们需要这个信息来写可靠的 exploit,否则需要自己去泄露这个信息。在低版本的内核中所有用户都可读取其中的内容,高版本的内核中缺少权限的用户读取时会返回 0。

SMEP

管理模式执行保护,保护内核是其不允许执行用户空间代码。在 SMEP 保护关闭的情况下,若存在 kernel stack overfolw,可以将内核栈的返回地址覆盖为用户空间的代码片段执行。在开启了 SMEP 保护下,当前 cpu 处于 ring 0 模式,当返回到用户态执行时会触发页错误。

操作系统是通过 CR4 寄存器的第 20 位的值来判断 SMEP 是否开启,1 开启,0 关闭,检查 SMEP 是否开启cat /proc/cpuinfo | grep smep

可通过 mov 指令给 CR4 寄存器赋值从而达到关闭 SMEP 的目的,相关的 mov 指令可以通过 ropper,ROPgadget 等工具查找

SMAP

管理模式访问保护,禁止内核访问用户空间的数据

KASLR

内核地址空间布局随机化,并不默认开启,需要在内核命令行中添加指定指令。

qemu 增加启动参数 -append "kaslr" 即可开启

Privilege Escalation

提取,越狱,就是要以 root 用户拿到 shell,获取 root 的方式有几种

在内核态调用 commit_creds(prepare_kernel_cred(0)),返回用户态执行起 shellvoid 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 防预这种类型的攻击的方法是:如果处理器处于 ring0 模式,并试图执行有 user 数据的内存时,就会触发一个页错误。

也可以修改 cred 结构体,cred 结构体记录了进程的权限,每个进程都有一个 cred 结构体,保存了进程的权限等信息(uid,gid),如果修改某个进程的 cred 结构体(uid = gid = 0),就得到了 root 权限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 Kernel

Source Code

先下载一份 Kernel 源码,我用的是 2.6.32,由于我的机子是 ubuntu 16.04,预装的 make 与 gcc 版本过高,编译 2.6 的 kernel 会失败,所以需要降级# 4.7 gcc

sudo apt install gcc-4.7 g++-4.7

sudo rm /usr/bin/gcc /usr/bin/g++

sudo ln -s /usr/bin/gcc-4.7 /usr/bin/gcc

sudo ln -s /usr/bin/g++-4.7 /usr/bin/g++

# 3.80 make

wget https://mirrors.tuna.tsinghua.edu.cn/gnu/make/make-3.80.tar.gz

tar -xvf make-3.80.tar.gz

cd make-3.80/

./configure

make

sudo make install

3.80 的 make 生成在源码目录里,稍后需要用这个 make 文件

修改三处 2.6 源码文件1.arch/x86/vdso/Makefile 中第 28 行的 -m elf_x86_64 改成 -m64,第 72 行的-m elf_i386 改成-m32

2.drivers/net/igbvf/igbvf.h 中注释第 128 行

3.kernel/timeconst.pl 中第 373 行 defined(@val) 改成 @val

4.(可选)关闭 canary 保护需要编辑源码中的.config 文件 349 行,注释掉 CONFIG_CC_STACKPROTECTOR=y 这一项

bzImage

安装必备依赖sudo apt-get install build-essential libncurses5-dev

解压后进入源码目录,使用刚安装的 make~/MAKE/make-3.80/make menuconfig

进入 kernel hacking,勾选 Kernel debugging,Compile-time checks and compiler options-->Compile the kernel with debug info,Compile the kernel with frame pointers 和 KGDB,然后开始编译~/MAKE/make-3.80/make bzImage

大概 10 分钟的样子,出现这个信息就说明编译成功了Setup is 15036 bytes (padded to 15360 bytes).

System is 3754 kB

CRC 4505d1c3

Kernel: arch/x86/boot/bzImage is ready (#1)

vmlinux 在源码根目录下,bzImage 在/arch/x86/boot/里

rootfs.cpio

编译 busyboxwget https://busybox.net/downloads/busybox-1.27.2.tar.bz2

tar -jxvf busybox-1.27.2.tar.bz2

cd busybox-1.27.2

make menuconfig

勾选 Busybox Settings -> Build Options -> Build Busybox as a static binarymake install

编译完成后源码目录下会有一个_install 文件夹,进入mkdir -pv {bin,sbin,etc,proc,sys,usr/{bin,sbin}}

mkdir etc/init.d

touch etc/init.d/init

编辑 etc/inittab 文件,加入以下内容(貌似这一步可以省略)::sysinit:/etc/init.d/rcS

::askfirst:/bin/ash

::ctrlaltdel:/sbin/reboot

::shutdown:/sbin/swapoff -a

::shutdown:/bin/umount -a -r

::restart:/sbin/init

编辑 etc/init.d/init 文件,加入以下内容#!/bin/sh

mount -t proc none /proc

mount -t sys none /sys

/bin/mount -n -t sysfs none /sys

/bin/mount -t ramfs none /dev

/sbin/mdev -s

接着就可以打包成 rootfs.cpiochmod +x ./etc/init.d/rcS

find . | cpio -o --format=newc > ../rootfs.cpio

boot

得到三个文件后,可以利用 qemu 运行起来,启动脚本 boot.sh#!/bin/sh

qemu-system-x86_64 \

-initrd rootfs.cpio \

-kernel bzImage \

-nographic \

-append "console=ttyS0 root=/dev/ram rdinit=/sbin/init" \

-m 64M \

-monitor /dev/null \/ # uname -a

Linux (none) 2.6.32 #1 SMP Sun Jan 26 21:51:02 CST 2020 x86_64 GNU/Linux

Run LKM

build

简单写一个 hello 的程序,hello.c 内容如下#include

#include

#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);

Makefile 内容如下,注意 xxx.c 与 xxx.o 文件名一致,KERNELDR 目录是内核源代码obj-m := hello.o

KERNELDR := /home/mask/kernel/linux-2.6.32

PWD := $(shell pwd)

modules:

$(MAKE) -C $(KERNELDR) M=$(PWD) modules

modules_install:

$(MAKE) -C $(KERNELDR) M=$(PWD) modules_install

clean:

$(MAKE) -C $(KERNELDR) M=$(PWD) clean

make 出来后得到.ko 文件➜ helloworld ls

helloc.c helloc.mod.c helloc.o modules.order

helloc.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]=08aaa94df43f8333c14

9073cddf3043e52b28107, 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)

再写一个调用程序 call.c#include

#include

#include

#include

#include

#include

#include

int main()

{

int fd = open("/proc/hello", O_WRONLY);

write(fd, "Mask", 4);

return 0;

}

run

将 helloc.ko 文件与 call 文件复制.

进文件系统,也就是 busybox 目录里的_install 文件夹,重新打包 rootfs.cpio,运行起来即可看见模块/ # insmod hello.ko

[ 11.743066] hello driver init!

/ # ./call

[ 25.860294] You write something.

Reference

*本文作者:Mask6asok,转载请注明来自FreeBuf.COM

pt-slot.php,Pwn In Kernel(一):基础知识相关推荐

  1. pwn学习总结(二) —— 基础知识(持续更新)

    pwn学习总结(二) -- 基础知识(持续更新) Canary PLT表&GOT表 格式化字符串漏洞 GCC编译参数 ASLR 危险函数 输入流 syscall条件 shellcode 其它 ...

  2. pwn学习总结(四)—— 堆基础知识(持续更新)

    pwn学习总结(四)-- 堆基础知识(持续更新) 前言 chunk 使用中(分配后) 空闲中(释放后) 堆块大小 空间复用 bins fastbin unsorted bin small bin 前言 ...

  3. windows pwn 基础知识

    环境搭建 checksec winchecksec winchecksec 是 windows 版的 checksec ,不过有时候结果不太准确. checksec(x64dbg) x64dbg 的插 ...

  4. 【网络通信】【电信运营商实战工程师】思科设备篇-网络工程师必备基础知识

    电信运营商实战工程师系列文章. 思科设备篇-网络工程师必备基础知识. 文章目录 1. 电信运营商网络设备机房 2. 认识并管理运营商网络设备 3. GNS3 安装与配置 4. IPv4地址及子网划分 ...

  5. opencv-python基础知识学习笔记

    opencv-python基础知识学习笔记 原博地址:https://www.cnblogs.com/silence-cho/p/10926248.html 目录: opencv-python基础知识 ...

  6. Python计算机视觉编程第十章——OpenCV基础知识

    Python计算机视觉编程 (一)OpenCV 的 Python 接口 (二)OpenCV 基础知识 2.1 读取和写入图像 2.2 颜色空间 2.3 显示图像及结果 (三)处理视频 3.1 视频输入 ...

  7. 【ASM】ASM基础知识

    [ASM]ASM基础知识 市场占有率 ASM自动存储管理技术已经面世10多个年头,目前已经广泛使用于各个领域的数据库存储解决方案. 到2014年为止,ASM在RAC上的采用率接近60%,在单机环境中也 ...

  8. 【通信系统】移动通信系统基础知识

    移动通信系统基础知识 一.移动通信的基本术语 二.移动通信电波传播和预测模型 三.信源编码和调制解调 四.抗衰落技术 五.蜂窝组网技术 六.GSM及其增强移动系统 一.移动通信的基本术语 移动通信: ...

  9. 总结Linux基础知识和常用渗透命令!!!

    作为Web渗透的初学者,Linux基础知识和常用命令是我们的必备技能,本文详细讲解了Linux相关知识点及Web渗透免了高龄.如果想玩好Kali或渗透,你需要学好Linux及相关命令,以及端口扫描.漏 ...

  10. shell基础知识总结

    1. shell 对于一台计算机而言,其硬件受系统内核的控制,使用者想要控制计算机,就必须有与系统内核进行通讯的手段.而shell就是使用者与计算机进行通讯的手段之一.从命名上看,shell其实是相对 ...

最新文章

  1. Confluence 6 SQL Server 测试你的数据库连接
  2. 对异步脉冲信号的处理——不归0翻转电路
  3. Ubentu编译Android源码(AOSP)
  4. nodejs http.get 方法可以 request 不行
  5. java web开发中Filter使用Annotation配置 (转载)
  6. 模块化是数据中心设计的未来
  7. linux read01,Linux内置命令之read
  8. Linux云服务器安装Redis并设置远程连接设置开机自启
  9. doxygen问题集锦
  10. 洛谷-P1903 数颜色 分块 bitset
  11. 七大排序的个人总结(二) 归并排序(Merge
  12. java代理机制简单实现
  13. python中的pip是什么_python中的pip
  14. C语言中可变参函数介绍与示例
  15. wireshark未响应
  16. 三种内存虚拟化技术(内存全虚拟化、内存半虚拟化、内存硬件辅助虚拟化),以及查看linux对ETP和VPID的支持情况
  17. cyclone小知识(二)——cyclone加载扫描工程的数据
  18. Flink web ui面板功能简述
  19. 读书笔记(第五周)之魔方的创新
  20. 对项目经理而言,PMP是否对职业生涯的发展有帮助?

热门文章

  1. 浅读《构建之法:现代软件工程》有感
  2. 外部SRAM实验,让STM32的外部SRAM操作跟内部SRAM一样(转)
  3. 经常使用的正則表達式归纳—JavaScript正則表達式
  4. CC学iOS杂记 001_Device
  5. error LNK2019: unresolve d external symbol _DriverEntry@8 referenced in function _GsDriverEntry@8
  6. fastdfs 报错 err: TrackerTask RecvHeader recv resp status 28 != 0
  7. 基于Python-turtle库绘制皮卡丘、多边形、星空
  8. init.rc语法与解析
  9. Gstreamer1.16.2与Glib2 signals关键字冲突解决(十一)
  10. Android报错:No resource found that matches the given name 'Theme.AppCompat.Light.NoActionBar'