什么是docker镜像?
首先,docker的英文含义是码头工人,搬运工人,百科里的定义它是一个开源的应用容器引擎,它能让linux开发者快速打包应用和依赖包到一个容器里,方便移植。所以这里的理解应该是它专门用于应用的跨平台搬运。它基于64为linux系统使用,不支持32位,它的跨平台实际上并不是说它可适用所有应用场景,而是只能虚拟基于Linux的服务运行。
docker分为四个部分:
- DockerClient客户端(docker是C/S架构,Daemon作为服务端接收用户请求并处理,客户端服务端既可运行到一个机器上,也可以运行到多个上用网络通信)
- Docker Daemon守护进程
- Docker Image镜像
- DockerContainer容器
docker镜像(image)相当于ubuntu里的root文件系统,镜像和容器的区别是,镜像相当于是静态的,而容器是镜像的运行实例,容器可以被创建,启动、停止、删除、暂停等。
仓库(Repository):仓库可看成一个代码控制中心,用来保存镜像。
docker命令导图
zsh,bash是什么?
有时候在运行linux命令的时候会遇到如下情况,zsh:command not found:某命令。其实zsh都是(shell shell相当于包裹于系统内核的一层壳,用于输入命令行运行内核调用内存等,shell就是命令解释器) 命令解释器的一种,命令解释器是一个单独的软件程序,它可在用户和操作系统之间提供直接的通讯。命令行解释器是解释器的一种,用于对命令行进行解释执行。
shell与基础命令行:
相同点:
①基础命令行和Shell都可以操作Linux系统
不同点:
①基础命令行(ls、cd等),是一种单一的操作。
②Shell可以比基础命令行更复杂,是一种组合型的操作。相比基础命令拥有了面向过程的概念。
常见的命令解释器有
Sh
Bash
Zsh
Csh
Ash
Fish
函数调用栈:
程序运行时内存一段连续的区域,用来保存函数运行时的状态信息,调用函数时被调用函数压入栈顶,栈地址由高地址向低地址生长。函数状态主要涉及三个寄存器--esp,ebp,eip。esp 用来存储函数调用栈的栈顶地址,在压栈和退栈时发生变化。ebp 用来存储当前函数状态的基地址,在函数运行时不变,可以用来索引确定函数参数或局部变量的位置。eip 用来存储即将执行的程序指令的地址,cpu 依照 eip 的存储内容读取指令并执行,eip 随之指向相邻的下一条指令,如此反复,程序就得以连续执行指令。
参考:https://zhuanlan.zhihu.com/p/25816426
1.函数调用时,首先将参数逆序压入栈中,但参数仍旧保存在调用函数的状态内,之后压入栈中的数据都会当作被调用函数的函数状态处理。
被调用函数的参数压入栈中。
2.参数压完之后压入返回地址,return address这里的返回地址实际上是调用函数调用完被调用函数之后,要执行的下一条指令地址,这样做使得调用函数eip(指令)信息得以保存。
3.将当前的ebp寄存器内值(值为调用函数的基地址)压入栈内,并将其更新为当前栈顶的地址。这样调用函数的基地址得以保存,且ebp也被改变成被调用函数的基地址。
4.被调用函数局部变量等数据压入栈中,esp内地址下移,变低地址。
调用参数以外的数据共同构成了被调用函数(callee)的状态。
发生调用时,被调用函数的指令地址存到了eip寄存器中,这样程序就可以依次执行被调用函数的指令了。这就是函数的调用,理解这个,那么调用状态的恢复也就不难理解了。
函数调用状态的变化,给了攻击者可乘之机,只要让eip寄存器指向攻击指令的地址,eip执行攻击指令,就可以达到目的。
具体操作是:
在调用函数的时候,存入的返回地址实际上是调用完成之后要执行的下一条指令的地址,它是要传给eip寄存器的,所以我们需要让溢出数据用攻击地址的地址覆盖返回地址即可攻击。
我们可以在溢出数据内包含一段攻击指令,也可以在内存其他位置寻找可用的攻击指令。
关于eip覆盖技术
可分为四类:
- 修改返回地址,让其指向溢出数据中的一段指令(shellcode)
- 修改返回地址,让其指向内存中已有的某个函数(return2libc)
- 修改返回地址,让其指向内存中已有的一段指令(ROP)
- 修改某个被调用函数的地址,让其指向另一个函数(hijack GOT)
1.修改返回地址,让其指向溢出数据中的一段指令(shellcode)
溢出数据组成
shellcode所用溢出数据的构造
address of shellcode 是后面 shellcode 起始处的地址,用来覆盖返回地址。
溢出数据不要包含”\x00“,否则会造成截断。\x00 == 0x00。对应于ASCII码的NULL。它在字符串中作为结束标志使用。
根据上边的构造,需要去解决两个问题,padding1有多长,shellcode起始地址在哪里?
padding1长度可以运行程序试探或者用调试工具从汇编查看。
shellcode起始地址我们有时候只能得到大概位置,所以可以在padding2填充若干长度“\x90”,意思是NOP指令,不进行任何操作进入下一条。只要返回地址命中这一段任意位置,都能到shellcode起始地址。
这个方案执行的前提是对方关闭地址随机化,否则每次程序运行地址都不同,无法确定地址,另外shellcode也要有可执行的权限。所以就引出了调用程序内部函数和指令的方法:return2libc和ROP
2.修改返回地址,让其指向内存中已有的某个函数(return2libc)
在内存中确认某个函数的地址,并用其覆盖返回地址。之所以叫return2libc,是因为libc动态链接库中的函数大概率会被用到并且在内存中找到,此外该库还包含了一些系统级函数,可用以取得当前进程的控制权。要执行的函数可能需要参数,所以要把需用到的参数写入溢出数据中。
同一理,这个构造中需要解决的问题为padding1的长度,以及system()函数的起始地址在哪?这里同理,只有在关闭地址随机化的前提下才能用调试工具找出system()函数起始地址(也可找到动态库的起始地址,加上动态库内的相对偏移量就是system函数绝对地址)。padding1任意填充,填充长度可用调试工具或运行程序不断试探输入长度得到。此外还需搜索字符串“/bin/sh”在链接库中的位置,如果这个位置在动态库中找不到,可以将其添加到环境变量里,再通过getenv() 等函数来确定地址。如果对方打开了地址随机化,以上两种方法都会失效,下面介绍两种不需此前提的方法。
3.修改返回地址,让其指向内存中已有的一段指令(ROP)
包含多个gadget的溢出数据,gadget为某段指令地址,这里只是这样命名为英文小工具。
现在任务可以分解为:针对程序栈溢出所要实现的效果,找到若干段以 ret 作为结束的指令片段,按照上述的构造将它们的地址填充到溢出数据中。
要解决问题如下:
栈溢出要实现的效果---------------常见的效果是实现一次系统调用
如何寻找对应的指令片段---------有许多可借助的开源工具可实现搜索以ret为结尾的指令片段
如何传入系统调用参数------------使用pop指令写入后再弹出相对简单一点,对于单个 gadget,pop 所传输的数据应该在 gadget 地址之后
4.修改某个被调用函数的地址,让其指向另一个函数(hijack GOT)
这个方法是要在内存中修改某个函数的地址,使其指向另一个函数。 比如原来要调用printf函数,现在通过修改,变成了执行system函数。
关于程序如何实现外部函数调用:静态链接和动态链接。动态链接在发送调用的时候去链接库定位所需函数,这个过程需要用到全局偏移量表GOT和程序链接表PLT。
GOT存储外部函数在内存的确切地址,存储于数据段中,在程序运行的时候可修改。
PLT存储外部函数的入口点,程序运行时会来这里寻找外部函数地址。它存在于代码段,运行前确定不可被修改,它的入口点就是GOT表中对应的地址。
之所以不直接使用GOT表其实是为了效率考虑。从PLT表找寻GOT表中函数地址第一次如果没有,则会回到PLT运行地址解析函数,并写入GOT表,如果已经有了,会直接从GOT表跳转到代码段。
这个过程不是一次全部实现的,而是在调用的时候才会发生,这就给了我们函数伪装的可能。修改GOT表中函数A的地址变为函数B,这样每次调用函数A都会变成调用B。
以上可分为三步,确定A在GOT表中位置,找到B函数位置,替换
1.找A:可通过PLT的入口点找到GOT表中具体条目。如call 0x08048430 <printf@plt>,说明 printf 在 PLT 表中的入口点是在 0x08048430,所以 0x08048430 处存储的就是 GOT 表中 printf 的条目地址。
2.找函数B:如果关闭地址随机化,那方法与前面一样,但这还不够,为了能够在打开地址随机化的情况下使用,可以借助链接库中相对位置不变这一特点,知道函数A的地址,借助其与函数B在链接库内的相对位置可找到函数B运行时地址。
3.替换:对方肯定不会用提供合适的函数,所以可借助ROP。只要找到若干条gadget,就不难改写GOT表中数据。
pop eax; ret; # printf@plt -> eax
mov ebx [eax]; ret; # printf@got -> ebx
pop ecx; ret; # addr_diff = system - printf -> ecx
add [ebx] ecx; ret; # printf@got += addr_diff
学好ROP还是很重要的,它可在一定程度上绕开地址随机化。