说在前面python
这是一套Linux Pwn入门教程系列,做者依据Atum师傅在i春秋上的Pwn入门课程中的技术分类,并结合近几年赛事中出现的一些题目和文章整理出一份相对完整的Linux Pwn教程。linux
问:为何要花费精力去整理这套系统的Linux Pwn教程?docker
答:网上关于Pwn的资料比较零散;常常会碰到解题过程略的Writeup和没有注释;存在大量硬编码偏移的脚本;练习题目难找;调试环境难搭建;GDB没有IDA好操做等等问题。shell
问:这个Linux Pwn教程适合新手学习吗?ubuntu
答:本套课程很是适合萌新们进行入门学习,内容通俗易懂,化繁为简,同时结合历年赛题,实操性强,对于快速提高技能可起到很大的帮助。bash
问:关于Linux Pwn教程是否有视频讲解?服务器
答:在i春秋官网的课程库中有不少关于Pwn的视频课程,当即去学习!https://www.ichunqiu.com/courses/pwn?from=weixintcp
本系列教程仅针对i386/amd64下的Linux Pwn常见的Pwn手法,如栈,堆,整数溢出,格式化字符串,条件竞争等进行介绍,全部环境都会封装在Docker镜像当中,并提供调试用的教学程序,来自历年赛事的原题和带有注释的python脚本。函数
教程中的题目和脚本如有使用不妥之处,欢迎各位大佬批评指正。布局
今天是Linux Pwn入门教程第一章:环境配置,阅读用时约7分钟。
1、Docker容器的使用与简单操做
在搭建环境以前咱们须要准备一个装有Docker的64位Linux系统,内核版本高于3.10(能够经过uname -r查看),能够运行在实体机或者是虚拟机中。关于Docker的安装与启动此处再也不赘述,读者能够根据本身的Linux发行版本自行搜索。
在成功安装了Docker并验证其可用性后,咱们就能够定制本身的实验用容器了。这部份内容能够在各个地方找到教程,且与Pwn的学习不相关,此处再也不赘述。为了方便实验,我把实验环境打包成了几个容器快照,能够直接导入成镜像使用。
以ubuntu.17.04.amd64为例,导入的命令为:
cat ubuntu.17.04.amd64 | docker import - ubuntu/17.04.amd64
导入成功后使用命令docker images会看到镜像仓库中出现了一个新的镜像。
运行docker run -it -p 23946:23946 ubuntu/17.04.amd64 /bin/bash
就能够以这个镜像建立一个容器,开启一个shell,而且将IDA调试服务器监听的23946端口转发到本地的23946端口。
经过命令docker container ls -a 咱们发现容器列表里多了一个刚刚建立的容器,而且被赋予了一个随机的名字,在个人实验中它是nostalgic_raman。
咱们能够经过命令docker container rename nostalgic_raman ubuntu.17.04.amd64把这个容器重命名为ubuntu.17.04.amd64或者其余你认为合适的名字。
使用docker exec -it ubuntu.17.04.amd64 /bin/bash 咱们能够打开目标容器的一个新的bash shell。这使得咱们在后续的调试中能够在容器中启动IDA调试服务器并用socat部署Pwn题目。
此外,可使用docker container cp命令在docker容器内外双向传输文件等等。须要注意的是,对容器的各类操做须要在容器运行时进行,若容器还没有运行(运行docker container ls未显示对应容器),需使用命令docker start运行对应容器。此外,若同时运行多个容器,为了不端口冲突,在启动容器时,能够将命令docker run -it -p 23946:23946 ubuntu/17.04.amd64 /bin/bash 中的第一个端口号23946改成其余数字。
2、IDA的简单使用及远程调试配置
成功搭建了Docker环境以后,咱们接下来熟悉一下IDA和IDA的远程调试环境搭建。首先咱们在IDA所在的文件夹的dbgsrv文件夹下找到须要的调试服务器Linux_server(32位)和Linux_serverx64(64位)并复制到kali中。
而后使用命令:
docker container cp linux_server ubuntu.17.04.i386:/root/linux_server
将linux_server复制到32位容器中的/root目录下。此时咱们登陆容器能够看到linux_server,运行该server会提示正在监听23946端口。
接着咱们打开32位的ida,载入一个后面会用于演示堆漏洞的程序heapTest_x86,在左侧的Functions window中找到main函数,随便挑一行代码按F2下一个断点。而后经过Debugger->Process options...打开选项窗口设置远程调试选项。
在弹出的选项窗口中配置Hostname为kali的ip地址,Port为容器映射到kali中的端口。
填好后点击OK,按快捷键F9运行程序。若链接正常可能提示Input file is missing:xxxxx,一路OK就行,IDA会将被调试的文件复制到服务器所在目录下,而后汇编代码所在窗口背景会变成浅蓝色而且窗口布局发生变化。若IDA僵死一段时间后跳出Warning窗口,则须要检查IDA所在机器与kali是否能ping通,容器对应端口是否映射,参数是否填错等问题。
调试器链接成功后咱们就可使用各类快捷键对目标程序进行调试,经常使用的快捷键有如下断点/取消断点F2,运行程序F9,单步跨过函数F8,单步进入函数F7,运行到选中位置F4等等。在调试模式下主要使用到的窗口有汇编窗口IDA View-EIP,寄存器窗口General registers,栈窗口Stack view,内存窗口Hex View,系统日志窗口Output window等。
切回到kali,咱们会看到随着程序运行,运行调试服务器的shell窗口会显示出新的内容:
当IDA中的程序执行完call ___isoc99_scanf或者相似的等待输入的指令后会陷入阻塞状态,F4,F7,F8,F9等和运行相关的快捷键都不生效。此时咱们能够在shell中输入内容,IDA中的程序便可恢复执行。
3、使用Pwntools和IDA调试程序
在上一节中咱们尝试了使用IDA配置远程调试,可是在调试中咱们可能会有一些特殊的需求,好比自动化完成一些操做或者向程序传递一些包含不可见字符的地址,如\x50\x83\x04\x08(0x08048350)。这个时候咱们就须要使用脚原本完成此类操做。咱们选用的是著名的python库pwntools。pwntools库可使用pip进行安装,其官方文档地址为http://docs.pwntools.com/en/stable/ 。在本节中咱们将使用pwntools和IDA配合调试程序。
首先咱们在kali中安装pwntools,安装完成后输入python进入python环境,使用from pwn import * 导入pwntools库。
使用docker exec在32位的容器中新开一个bash shell,跳转到heapTest_x86所在目录/root,查看容器的IP地址,而后执行命令socat tcp-listen:10001,reuseaddr,fork EXEC:./heapTest_x86,pty,raw,echo=0
将heapTest_x86的IO转发到10001端口上。
咱们能够看到个人容器中的IP地址是172.17.0.2。回到python中,使用io = remote("172.17.0.2", 10001)打开与heapTest_x86的链接。
这个时候咱们返回到IDA中设置断点。须要注意的是此时heapTest_x86已经开始运行,咱们的目标是附加到其运行的进程上,因此咱们须要把断点设置在call ___isoc99_scanf等等待输入的指令运行顺序以后,不然因为计算机的运行速度,咱们的断点将会由于目标指令已经执行完而失效,达不到断下来的效果。
选择Debugger->Attach to process...,附加到./heapTest_x86的进程上。
此时EIP将指向vdso中的pop ebp指令上。
这几行指令其实是执行完sys_read后的指令,此处咱们不须要关心它,直接按F9,选中标志会消失。
回到python窗口,咱们使用pwntools的recv/send函数族来与运行中的heapTest_x86进行交互。首先输入io.recv( ),咱们发现原先会在shell窗口出现的菜单被读出到python窗口里了。
一样的,咱们经过io.send( )也能够向这个进程传递输入。咱们使用io.send('1')告诉这个进程咱们要选择选项1。这个时候咱们切换到IDA窗口,发现IDA仍是处于挂起状态,这是为何呢?
回想一下咱们经过shell与这个进程交互的时候,输入选项后须要按回车键以“告诉”这个进程咱们的输入结束了。那么在这里咱们一样须要再发送一个回车,因此咱们再执行io.send(' '),切换到IDA窗口就会发现EIP停在了熟悉的程序领空。这时候咱们再使用IDA的快捷键就能够进行调试,为所欲为地观察进程的内存,栈,寄存器等的状态了。固然,咱们也能够直接使用io.sendline( ),就能够直接在输入的结尾自动加上' '了。
在上图的状态中,咱们在python中再次输入io.recv( ),发现并无读取到输出,而且python处于阻塞状态。这是由于程序此时没有输出可读取。咱们在IDA中按F8到call mallocChunk一行,此时按F7进入函数,在函数中运行到call _fflush的下一行,就会发现python的阻塞状态解除了。
当咱们但愿结束调试时,应该使用io.close( )关闭掉这个io。不然下一次试图attach时会发现有两个./heapTest_x86进程。在IDA中按Ctrl+F2便可退出调试模式。
配置实验环境打包以下:
连接:https://pan.baidu.com/s/1xr9n9EBs2dALOkmIFaIdcQ
密码:bcd6
以上是今天的内容,你们看懂了吗?后面咱们将持续更新Linux Pwn入门教程的相关章节,但愿你们及时关注。