0x00序言
Pwn是CTF中黑客常见的俚语,意为爆炸时发出的声音”砰”,代表的是你的电脑已被黑了,目前在CTF中是五大方向里入门门槛最高的方向。一旦入门,深入理解Pwn的难度就会降低许多,比较容易成为二进制大牛。
0x01Pwn历史
有关Pwn的CTF比赛起源于1986年第一次全球黑客大会,
有关著名赛事
活动的主要目的是希望安全研究人员、开发人员、以及黑客们通过某些此前未知的漏洞来侵入各种移动设备,然后将之汇报给相应的设备制造商,以便它们对这些漏洞进行修补和修复。
GeekPwn
堪称全球最大规模的智能设备破解挑战赛在北京举行。在这次中国顶级黑客的“华山论剑”中,特斯拉无人驾驶被Keen Team全球首次实现,此外,一次性攻破七十款主流智能手机,借助未公开网络基础协议设计漏洞攻破网络银行等展示均为活动最大亮点,各大安全路由器、智能家居、电视盒子、手环等主流智能硬件产品悉数被攻破 。
0x02栈&堆
先了解下,什么叫堆、栈?
堆、栈均是一个特定的存储区,一端是固定的,另一端是动态的,属于动态内存
栈
栈是一种数据结构,是由操作系统自动在内存中分配的一段空间,特点是”先进后出”。即把栈比作一个半封闭的圆筒,从栈中插入一个元素,我们称为压入栈底,在汇编中用”PUSH”指令代表。从栈中取出一个元素,称它为弹出栈顶,在汇编中用”POP”指令代表。
栈一般分为实现形式
1、顺序栈,顺序栈的底层实现是数组形式
2、链栈,链栈的底层实现是链表形式
栈是从高地址到低地址,栈顶指针(SP)指向栈顶,栈顶地址最低,栈底地址最高。这里用一幅图来简单表示进栈和出栈的过程。
栈区
栈区中一般存储的是局部变量,函数定义的参数值。
堆
堆是一种经过排序的树形数据结构,每一个节点都有一个值,通常所说堆的数据结构是二叉树,堆的存取是随意的。所以堆在数据结构中通常可以被看做是一棵树的数组对象。而且堆需要满足一下两个性质:
(1)堆中某个节点的值总是不大于或不小于其父节点的值;
(2)堆总是一棵完全二叉树。
堆区
堆区一般由程序员创建和释放,若没有主动释放堆区内存,程序结束后操作系统会释放内存
在C语言中分配内存使用malloc函数,使用free释放内存,在C++或java使用的是new关键字,分配的方式类似于链表结构
栈、堆区别
1、申请方式
栈:由系统自动分配。例如在声明函数的一个局部变量int b,系统自动在栈中为b开辟空间。
堆:需要程序员申请,并指明大小
2、申请后系统的响应
栈:只要栈的剩余空间大于所申请的空间,系统将为程序提供内存,否则将报异常提示栈溢出。
堆:操作系统有一个记录空间内存地址的链表,当系统收到程序的申请时,会遍历链表,寻找第一个空间大于所申请空间的堆节点,然后将节点从内存空闲节点链表中删除,并将该节点的空间分配给程序。对于大多数操作系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的对节点的大小不一定正好等于申请的大小,系统会自动地将多余的那部分重新放入到链表中。
0x03栈溢出
栈溢出指的是程序向栈中某个变量中写入的字节数超过了这个变量本身所申请的字节数,因而导致与其相邻的栈中的变量的值被改变。
最为常见的就是递归,无限递归的时候会不断把新的数据压入原来的栈中
造成栈溢出的函数常见的有gets()、scanf()、vscanf()、sprintf()、strcpy()、strcat()、bcopy()
一般流程
1、ida反汇编程序
2、找危险函数
3、寻找并确认执行目的函数的地址
4、计算危险操作地址与危险函数的差值
5、传数据到危险函数,其中格式为:差值*某个字符 +执行目的函数的地址(填充长度)
6、常见的pwntool代码
1 | ##coding=utf8 |
0x04堆溢出
堆溢出是指程序向某个堆块中写入字节数超过堆块自身可使用的字节数
造成堆溢出的函数常见的有gets()、scanf()、vscanf()、sprintf()、strcpy()、strcat()、bcopy()
一般流程
1、ida反汇编程序
2、寻找分配函数
堆会调用glibc函数malloc分配内存,其他情况下会调用calloc函数。两者函数的区别为calloc在分配内存后会自动清空。此外还可以选择realloc,该函数可以同时发挥malloc和free函数作用。
3、找危险函数
4、填充长度
计算写入地址和覆盖地址之间的距离,python脚本写法可参考下栈溢出
0x05区别
栈溢出攻击的原理是将危险操作函数的地址覆盖到程序正常执行的地址,导致溢出后可执行危险操作函数里的功能。
堆溢出不会返回地址可以直接执行控制流程,也就无法直接控制EIP。
一般操作的方法就是覆盖物理相邻的下一个chunk内容,改变程序执行流
或者是利用堆中的机制实现任意地址写入控制堆块中的内容,劫持程序流
0x06总结
栈溢出和堆溢出是目前pwn系列中最为常见的两种溢出攻击方法。
栈溢出相比于堆溢出是较为容易,因为可以泄露一些敏感函数的地址可以让攻击者直接覆盖调用,而堆则无法返回地址,从而不能控制EIP,需要改写堆块中的内容或覆盖chunk内容才能进行溢出攻击。