ctfshow pwn pwn02 同时也作为入门题目无比细致讲解分析 真0基础入门
栈溢出是pwn的HelloWorld!
正所谓万事开头难,打开这篇文章也将可能成为你进入pwn世界的叩门石。由于本文过于详细,会耽搁大佬很多时间,同时本人学识尚浅,如有错误请指正。
我们先打开题目
launch an instance创建容器,创建容器后就会显示相应的host与port。
stack是可以下载的附件,就是我们要寻找漏洞的程序,点击下载即可。
而我们刚入门的做题步骤就是:
- 下载附件stack,并找到漏洞。
- 利用工具,nc创建出的host与port,利用工具进行攻击,得到权限后从host得到flag。
题目做法有很多,可以使用不同工具,但由于我是菜鸡,就只讲解一种方法
- 首先,我们从附件中得到了stack文件(注意是文件)没有后缀名(关于windows后缀名),但是我们可以用exeinfope工具查询(自己百度下载,注:在各种非官方网站下载时,拖至网页最下面寻找普通下载渠道,同时注意病毒与捆绑软件)。
- exeinfope是查壳工具,关于壳=shell黑客逆向破解基础-1:壳、加壳和脱壳分别是什么?加壳的解压原理介绍
- 但由于是入门题,其实并不需要查壳(但是以后需要),但我们很浅的说一下,将stack拖入exeinfope:
Diagnose:NOT Win EXE - .o - ELF [ 32bit obj. Exe file - CPU : Intel 80386 - OS/ABI: unspecified ]
紧随其后的: -> Compiler : GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609
大意就是32位的Ubuntu下的文件
我们也可以用pwntool工具中的checksec来检测可执行文件开启的各种安全机制(checksec讲解(点击跳转))
简单的说:
Stack:No canary found没有防溢出。
NX:NX enabled不可执行的
PIE:No PIE()未使用随机地址
- 将文件拖入IDA(一款强大的反编译软件)(我写的关于其使用的小短文)中。
PS:IDA有64位与32位之分,目前不影响入门,随便拖入即可
恭喜你,你已经迈出了一大步ヽ(゚∀゚)メ(゚∀゚)ノ
打开后,看见花花绿绿的界面“我是谁,我在哪,我要去干什么”。别急,当你先会简单使用IDA就没什么问题了。
那么问题又来了,该干嘛?
- 我们先看左侧的FcuntionWindow里面的函数,不难发现存在一个main函数,众所周知main函数为是程序执行的起点。我们双击他(其实一开始IDA-View-A显示的就是),然后在IDA-View-A窗口看见汇编语言,可以按F5进行反汇编,开启pseudocode-B窗口输出伪代码。
- setvbuf()函数相当于对文件流的规定,对文件进行操作,需要将磁盘中的文件写入内存中,相应的会在内存区建立一个缓存区用于与磁盘交换数据。stdout是屏幕输出设备,stdin是键盘输入设备,在开机时自动打开,相当于将缓存区清0,可以做到及时输入输出,不会等到缓存区写满后才引入结果,对此不需要深究。详细自行搜索,puts()输出字符串,pwnme()函数,双击查看其定义
双击fgets()发现是:
意义不明,其实是调用的库函数,自行百度即可(上文的setvbuf()也是库函数)
百度得到fgets()相当于对数组s,从stdin文件中输入50个字节,但是注意char s;的长度。
按esc返回上一级,到pwnme()并双击char s;的s得到:
显然s只有9字节大小,但是却输入了50个字节,未对输入字节正确控制导致栈溢出,可通过这个漏洞干一票大的。
栈溢出漏洞(这时你可能需要一点内存知识了自行百度,多看一点集百家之言,自然会了解)(也有许多有趣的视频)
溢出溢出,字面上就是往容器里加的水超过了水的容积,简单讲,栈溢出就是向栈中某个变量中写入的字节数超过了这个变量本身所申请的字节数,造成溢出。发生栈溢出的条件:程序必须向栈上写入数据。写入的数据大小没有被良好地控制。利用方式:覆盖程序的返回地址为攻击者所控制的地址,比如该地址为执行shellcode的地址shellcode是一段用于利用软件漏洞而执行的代码,shellcode为16进制的机器码,可以让攻击者获得shell,利用pwntools可自动生成,等用到再说。
可能造成栈溢出的函数有:gets,scanf,vscanf,sprintf,strcpy,strcat,bcopy
摘自某大佬博客
- 注意在+0000004处,就是s下面有一个r,这个r就是ret(Push, Pop, call, leave 和 Ret 指令图解)我们可以通过输入9字节占满s的大小,然后+4覆盖ret,让其返回到我们想要到的地方(轻则破坏程序,重则得到shell)。
-
- 为什么能做到这一点呢,就是因为栈的性质,栈是从高地址向下的,故从-00000009开始向下+00000000(此处为相对位置)存储,由于未作出合理限制输入,故可以继续覆盖低地址中存储,ret因此被覆盖。
- 当然我们的目的不是破坏程序,是get shell。从左处FunctionWindow处可以看见还有很多没用调用的函数,我们可以通过栈溢出,跳转执行。
- 可以从StringWindows(View->open subviews->string)处看见
服务器一般架设在Linux内核之上,对于Linux来说一切都是文件的存在,而/bin存储了许多系统可执行文件目录:cat,mv,date.......
/bin/sh 就是Bourne shell
双击该处就可跳转至
在根据右边 stack+9↑o 双击后跳转至相应的stack处并反编译
看见了stack()函数调用了system("/bin/sh"),于是我们可以通过栈溢出跳转至这里并执行。
既然要跳转至stack(),我们相对应的也要知道其首地址,拉大FunctionWindows后可以看见
从而得到0804850F
接下来就是我们Linux大显身手的时候,本人用的是Kail。
我们将会使用pwntools工具(windows无法使用)
- 进行编写exp(exploit漏洞利用)
- 编写exp一般使用python3语言,相应的会使用pwn包(自行导入)进行操作
本人使用vim写py代码然后丢入py3中运行(注意缩进,由于个人问题缩进没有显现出来)。
from pwn import *
//引入pwn包所有函数
content = 1
def main():
if content = 0
p = process("./stack")
//这是连接本地文件,其实在这里没什么用不写也可以因为根本就不会执行
else:
p = remote("pwn.challenge.ctf.show",28040)
//建立一个远程连接需要相应URL/IP和port当然这就是在前面创建的容器(服务器)信息,将remote对象保存至变量p中
payload = b'a'*13
//数据打包,由于前文提到的在s处填入9+4个字节
payload += p32(0x804850F)
//同上,p32()将整数值转为32位打包
p.send(payload)
//调用对象p的方法,send()将shellcode送至服务器端
p.interactive()
//将控制权交给用户可使用打开的shell
main()
pwntools使用简介(点击跳转)
pwntools各使用模块简介(点击跳转)
exploit利器-pwntools(点击跳转)
当然官方的说明才是最好最全的,但是刚入门就简单了解一下看看文章即可(注意要博彩多家)
编辑好后执行得到:
根据显示表明我们成功入侵对方,然后用ls查看对方/中文件,我们要的flag就赫然出现在第一个位置
最后我们cat flag(以只读模式打开)flag,得到flag。
注意:连接上一段时间后会自动断掉连接,此时再次执行脚本即可,所以手脚快一点。
(づ。◕ᴗᴗ◕。)づ<(▰˘◡˘▰)✧。٩(ˊᗜˋ)و✧。♪(^∀^●)ノ☆(≧∀≦)ノ
你好啊,旅行者(〃'▽'〃)这篇有趣的文字是来自一个剑与魔法的世界(o゚▽゚)o :博客园
作者:{奇迹和魔法都是存在的},我的家是在这块呦:{https://www.cnblogs.com/connerlink/}
如果有空的话就来坐一坐吧
这块有日记,书籍推荐,茶水,还有一个孤单的小博主QAQ