pwn入门-1-初识
学pwn有一段时间了,反反复复捣鼓一些东西,还是觉得以博客记录比较好,梳理自己的思路,会以第一人称来写,来记录学习的过程和结局思路(不是那种我是老师,教你学, 而是自己在探索.所以可能有时候会比较傻) 基础知识总有书和博客比我写得好,我觉得没有必要造轮子,所以有些基础知识可能会不会写的太细….反之,有一些博客上漏掉的细节,以及解题的关键会重点写(不会吧不会吧,真有人看你博客吗)
自己曾经说网上99%的博客都是垃圾(包括自己的),希望自己换了新博客后写的能质量高一点(至少越来越有长进)。(笑,不会真有人看你博客吧?)
第一篇文章首先来简单说一下自己目前认知的pwn
什么是pwn?
简单来说就是二进制漏洞的利用,什么是二进制呢? 这里的二进制指的是二进制程序,也就是我们平常用高级语言编写的程序被编译链接后成为的01010101, 它们在操作系统中运行的时候,会因为操作系统和cpu等设计的问题,以及程序员的问题,出现各种bug,导致漏洞利用.
最常见的就是溢出类型的漏洞,在CTF中也是最常考察的,栈溢出,堆溢出等,在这之后会有虚拟化逃逸,内核漏洞等.
“万物皆可pwn”,尤其是现在iot的发展,多种设备都联入网络,像汽车,智能家居,安保系统等,都可能被“pwn“掉
如何入门?
这个问题我没法回答,因为我现在正在入门……….我只能说一些我目前正在做的事情,仅供参考
1.系统地打好计算机基础
pwn和web不一样,是比较底层的,需要的计算机知识很多,基础不牢地动山摇,所以要有较好的计算机基础.
包括但不限于 操作系统、汇编语言、体系结构、编译原理、C语言等
作者目前研一,还有一段时间用来打基础,建议大家在本科期间就好好打基础呀 (半路出家的痛)
目前选了学校的一些课程,同时在看一些书和视频等
(一)计算机体系结构
或者说计算机组成原理,是非常非常基础和重要的(本科时候学的太烂的),国科大的胡伟武老师讲这门课(放弃申报院士,为国家做芯片,龙芯董事长,首席科学家!!!! 超级牛的老师)
这门课能让你懂计算机的运行原理,CPU的原理,计算机是如何工作的,从电路、元器件的原理上去深入理解计算机
推荐书籍:
《计算机体系结构基础 第三版》 胡伟武 这是给国科大的本科生看的,但我觉得不论什么水平看一看都有收获
《计算机体系结构 第二版》胡伟武 这是给研究生推荐的教材,可以作为进阶看
《深入理解计算机系统》 经典黑书..
(二)操作系统
操作系统可以说
从最简单的一个栈溢出开始了解pwn
什么是栈?
栈是用来存储用户输入,函数变量,寄存器的值等的一块内存空间,它从高地址向低地址生长
什么是缓冲区溢出?
在上图中, buffer是用户能够可控的,用户能够可控的事实上便不安全,如果没有对buffer的大小进行正确的控制,buffer超过了128字节,则会产生溢出.
那么产生了溢出又会怎样呢? 先看最直接的效果,buffer的地址是从低地址向高地址生长的,那么它往上溢出,就会覆盖ebp和返回地址,以及等等.
那么覆盖了又会怎样呢?? 这里就需要了解函数调用的基础了(基础知识很重要!),这里先简单的说,在我们当前这个函数被调用完成,进行return的时候,它会return到哪呢? 就是我们存储的返回地址(return address),所以,答案就来了,如果我们把返回地址修改为恶意代码的地址,是不是就能够对它进行劫持? 是的,这种手法就叫劫持控制流
一个简单的例子, ret2backdoor/ret2text
题目来源于bamboofox中的ret2text
题目链接:
一般我们拿到的都是二进制文件,没有源代码,但我们不能直接读01吧,读汇编也很难吧(大佬除外),所以我们需要工具来帮我们反编译反汇编,反汇编是把01那些转换成汇编代码,反编译是把汇编转换成高级语言(如c语言)
这时候我们需要借助一个工具, ida pro, 别的工具也可以,不过ida确实是非常好用啊
动态调试
啥是动态调试呢? 静态分析是看源程序的汇编代码,程序是死的,动态调试就是让程序跑起来,在程序运行的时候,在某个节点断下来,查看程序的运行时状态,如栈的布局,寄存器等等,来寻找漏洞和探索利用方式,这里同样我们要用一些工具,首先是gdb,gdb本身不是为了漏洞利用而生的,而是给程序员来调试程序用的.
(这里还需要安装一个插件, gef ,具体安装可以google,有很多安装教程,或者直接看github仓库) 不过,为啥要安插件呢? 因为没插件不好用,插件能够帮你提取重要信息,以及给你增加很多方便漏洞调试的命令.
我们用 gdb 文件名 来启动调试
start 从第一条指令开始运行
ni 一步一步往下执行(遇到函数时不进入,直接执行完)
这里我们执行到了gets函数,它就是用来读取我们用户输入的,我们先来随便输入一串a
telescope 查看栈的情况 连续按回车可以一直往下展示栈(其实是重复当前命令)
能够看到 esp提示你 0xffffd56c这个位置存储的是这一串a,往下看,确实是,
当我们继续往下看的时候,我们看到了ebp
根据我们上面对栈的理解,buf之后是ebp然后是返回地址 (实际上实际情况可能比这还要复杂,暂且这样)
所以我们也可以从这里算覆盖地址,用ebp的地址 - 字符串开头,也就是buffer的地址, 就可以算出来要填充的字节数
0xffffd5d8 - 0xffffd56c = 108 这是到ebp的, 再加上ebp 4个字节,于是就是 112 字节, 然后就是返回地址了
那么返回地址我们返回到哪呢? 我们刚才在静态分析的时候已经分析到了存在后门函数,地址是0x804863a,所以我们返回这个后门的地址就可以了!
ctfwiki里解释的太粗了,为什么eax的位置就是字符串开始读取的位置呢?????????
构造payload与exp
1 | payload = b"a" * 108 + b"a" * 4 + retaddress |
1 | from pwn import * |
1 | root@VM-24-10-ubuntu:/home/ubuntu/zhan# python3 exp.py |
关于和pwntools的联动问题
sh.send(payload)
pause()
想达到在刚发送完这条payload,查看之后的效果,如果这样的话,是不行的,这样的话估计是执行了很多条之后的了,为什么呢?
如果想达到上述效果,需要下断点. 先调试找到断点,然后在gdb.attach的时候下断点
1 | 0xf7e4c624 <gets+292> call __uflow <__uflow> |
下断点下到0xf7e4c629就可以了
1 | from pwn import * |
运行的时候感觉不是到断点那里了,差了一些,但是可以一直往下n,还是差不多的
需要输入的时候 切换到左边按一下回车,就发送过去了