pwn(栈-buu、ctfshow)

1:题目:warmup_csaw_2016

下载附件得到一份64位ELF文件

checksec检查都开启了哪些防护措施

然后拖进IDA64分析:

shift+f12查看字符串,发现cat flag.txt字眼。双击,发现其压栈的地址为0x40060D,call system调用 cat flag.txt

接着查看main函数

sprintf函数(该函数用法详情在该题末尾)将数字或者其他数据格式化成字符串保存到一个字符串变量中,在这里的作用是将地址0x40060D中的cat flag.txt保存到s中,然而s是可以造成溢出进而覆盖返回地址触发调用cat flag.txt的,

查看s,发现其距离返回地址为0x40+8

故可编写exp拿到flag

本题所涉及的sprintf知识点


上代码:

2:题目:ciscn_2019_n_1

下载附件,一个64位的ELF文件。

checksec检查开启哪些防护措施

没有开启栈保护。

拖进IDA分析,shift+f12查看字符串发现cat flag字眼。

双击此cat flag 找到其压栈位置地址0x4006BE

然后查看main函数

发现没什么可利用的,双击func进入查看详情。发现gets函数,可以利用栈溢出覆盖返回地址

思路一:栈溢出覆盖返回地址。

双击v1发现其距离返回地址位0x30+8

所以exp编写如下,运行拿到flag。

思路二:覆盖局部变量

我们也可以让v2的值等于11.28125来调用system,gets(v1)是能输入字符的,即利用gets函数的溢出来控制v2的值,通过IDA知v1距离v2为0x30-0x4,显示的11.28125要先转化成16进制,于是先十进制11.2825转化为十六进制0x41348000。

编写exp拿到flag。

3:题目:pwn1_sctf_2016

拿到附件,先查看文件类型,为32位ELF文件,checksec 检查保护措施,没有开启栈保护措施。

拖进IDA32分析,shift+f12查看字符串寻找敏感字眼,找到敏感字眼cat flag。

双击找寻其地址,并记住其地址。

找到main函数,分析可以利用的漏洞,发现调用了vuln函数。

双击vuln函数。
发现fgets函数(详细用法在本题末尾),但可惜这个函数比gets函数安全的多,无法利用溢出漏洞,该函数限制我们输入32个字符,然而s距离ebp为0x3c(也就是60)的距离,明显无法造成溢出,但下方的代码似乎是能replace一下输进去的字符,大胆推测是把I 转换成you,输进去20个字符刚好不超过s的限制范围,经过replace成you再加上任意四个字符即可完成溢出。

尝试编写exp

运行果然拿到flag。

本题涉及的知识点:

fgets函数的原型为

include <stdio.h>
char *fgets(char *s, int size, FILE *stream)

fgets函数相比gets更安全,但也比gets函数更麻烦,其有三个参数,功能是从 stream 流中读取 size 个字符存储到字符指针变量 s 所指向的内存空间。它的返回值是一个指针,指向字符串中第一个字符的地址。s 代表要保存到的内存空间的首地址,可以是字符数组名,也可以是指向字符数组的字符指针变量名。size 代表的是读取字符串的长度。stream 表示从何种流中读取,可以是标准输入流 stdin,也可以是文件流,即从某个文件中读取,这个在后面讲文件的时候再详细介绍。标准输入流就是前面讲的输入缓冲区。所以如果是从键盘读取数据的话就是从输入缓冲区中读取数据,即从标准输入流 stdin 中读取数据,所以第三个参数为 stdin。

如代码:

若输入的字符长度大于fgets函数限制的长度,则会被截取,若不足则会用"\0"补充。

4:题目:jarvisoj_level0

下载附件,die检查为ELF64位文件,checksec检查开启了哪些保护

没有开启栈保护,可以利用程序溢出漏洞。

拖进IDA分析,shift+f12查看敏感字眼,看见bin/sh后门函数

双击跟进查看其压栈地址0x0400596

接着查看main函数查找漏洞函数,可以看出调用了vulnerable_function函数,

双击跟进,看到read函数读取了0x200长度的数据到buf缓冲区。
但buf距离ebp仅80的距离,完全可以造成溢出。

于是编写exp,运行拿到flag

5:题目:[第五空间2019 决赛]PWN5 (格式化字符串漏洞)

下载附件,die查看,是一个ELF32位文件。

checksec查看都开启了哪些保护措施。

好家伙,开启了NX,Stack,一部分RELRO。拖进IDA看main函数有什么可利用的没有,可以看到main函数读取了4字节长度的随机数到dword_804c044缓冲区,而能调用system(“bin/sh")的前提是输入的passwd与读入的随机数一样。
看到了read和printf,并且已经知道开启了Stack,想到格式化字符串漏洞,nc上端口,利用“AAAA %p %p %p %p %p %p %p %p %p %p %p %p..."这样的字符串来试探自己输入的参数会被写在栈上的哪个位置,(别的师傅称之为首地址偏移量)
可以看到0x41414141,是第十个位置,后面可以直接利用 %10$ (%$定位参数符)定位到这个位置,再用%n修改这这个地址里的内容,由于修改了一个地址的内容,一个地址四个字节,而%10$n(具体用法在本题末尾)把该地址对应的随机数替换成了其对应字符数,此时passwd为4,所以我们输入4即可。
故可编写exp运行拿到flag

6:题目:rop_test (典型栈溢出--基础ROP之ret2text 32位ELF文件)

拿到附件,die查看为ELF32文件。(第7道题是64位文件,可以对比这俩题目EXP有何不同)

checksec检查下都开启了哪些保护。

没有开启Stack保护,可以考虑栈溢出。拖进IDA分析,直接查看敏感字眼,找到了bin/sh。
双击跟进,先记下此时的bin/sh函数地址0x0804a024
接着查看main函数,确实存在溢出,buf缓冲区只有0x88大小的空间,但read函数读入0x100长度的数据。
发现程序并没有system调用bin/sh后门函数,所以没法直接利用溢出覆盖返回地址来获取flag,所以有了解题思路:劫持程序执行流,到system()函数,更改参数为"/bin/sh",查看system的地址0x804849e。
所以payload构造思路如下
首先 我们首先需要填充缓存区0x88(因为溢出)
之后 我们需要在覆盖4个字符来覆盖ebp
然后 我们要函数返回值为system函数
紧接着 我们要填充函数调用的返回地址(‘c’ * 4)如果你需要 可以一直执行main函数
最后 我们只需要调整system函数的参数为bin/sh 就结束了

试着编写exp,运行获取flag

[栈溢出--基础ROP相关文章]((27条消息) ret2xx----- Pwn中常见的CTF模板命题_Greeety的博客-CSDN博客_pwn中常见的ctf模板命题) ((27条消息) 栈溢出----基础rop_xiaoyuyulala的博客-CSDN博客

7:题目:[HarekazeCTF2019]baby_rop (典型栈溢出 ROP之ret2text 64位文件)

拿到文件,检查为ELF64位文件。(第6道题是32位文件,可以对比这俩题目EXP有何不同)

checksec检查开启了哪些保护措施。

没有开启canary保护,考虑栈溢出。拖进IDA分析。
有system函数,但是没有直接调用binsh;scanf函数能造成栈溢出。查找字符串找寻binsh与system地址

查找pop rdi ;ret的地址

构造ROP链:p=b'a'*(0x10+8)+p64(pop_rdi_ret)+p64(binsh)+p64(sysadd) ; (为何如此构造,请参考前边发的文章ROP之ret2xx)

exp如下:

flag藏得很深,打通之后输入命令 find / -name "flag"来定位之后一个一个cd。

8:题目:pwn_string (格式化字符串漏洞之ret2shellcode)

拿到附件,die查看为ELF64位文件。

checksec检查开启了哪些保护。

开启了Canary,NX,全部的RELRO。

拖进IDA,查看敏感字眼,并未发现什么,但不难看出该程序是个小游戏

直接在main函数中分析代码:

代码都是指引的,没什么用,直接看printf,printf泄露了v4的地址,v4的值传入函数sub_400D72(),然后点击sub_400D72()进入该函数。
a1的值就是v4。分析该段代码,要求我们输入一个字符串,长度不超过0xc,就进入游戏;若超过,则进不了游戏。先点击sub_400A7D进入看代码。
代码的大意就是你必须输入east,否则程序就会发出”hei!i am secious"的警告并且一直循环,输入east就退出该函数,然后点击sub_400BB9()
要求你输入一个address和一个wish,下方的printf(format)是格式化字符串漏洞可以利用。再点击sub_400CA6(a1),这里的a1的值就是v4的。
不难发现,这段函数就是可以把shellcode读入的,前提是a1==a1[1],但我们知道a1就是v4,而v4=68,v4[1]=85,a1不等于a1[1],此时就是利用格式话字符串漏洞来修改a1[1]的值,使他们相等。if里mma是p一种内存映射文件的方法,通过read函数读入一串机器码,然后运行。

在printf(有格式化字符串漏洞)测试字符串偏移位置,可以看出是第八位0x6161616161616161,但前边还有输入v2的值,占了一个偏移,所以wish是print的第八个参数,格式化字符串的第七个参数。

编写exp

9:题目:ciscn_2019_n_8 (覆盖局部变量)

下载附件,检查为ELF32位文件,再检查开启了哪些保护。

可以看出开启了Canary保护,不能利用栈溢出覆盖返回地址直接获取shell了,拖进ida分析。
审计代码,发现var数组的第13位,第14位被初始化为0,scanf函数向var数组内输入数据。if判断如果var数组的第13位等于0x11的话,就能调用system函数得到shell了,点进var
发现var数组大小为15,所以我们可以利用覆盖局部变量的方法,将var数组每一位都填上0x11,这样就能成功通过if判断了。

exp如下

10:题目 :bjdctf_2020_babystack

拿到附件,die检查为64位ELF,checksec检查开启了哪些保护措施。

只开启了NX保护。

拖进ida分析,先查看字符串有无敏感字眼。

双击跟进查看压栈地址:0x04006E6
接着查看main函数:
审计代码,定义了一个buf变量和一个nbytes变量,scanf向变量nbytes的地址输入内容,然后read把nbytes的内容读入buf里面。注意read里面的nbytes类型为unsigned int,会出现整数溢出,可以先sendline一个-1;

点击buf

可以看出距离r为0x10+8的距离,利用scanf函数的无限制参数输入即可造成溢出。

exp

11:题目:pwn04 (栈溢出之Carry绕过)

拿到附件,检查为ELF32位文件,再检查开启了哪些保护,

开启了NX,Canary,不能直接利用栈溢出了。拖进ida继续分析,进入main中的vuln函数中
发现存在溢出,并且printf泄露了buf的地址,存在格式化字符串漏洞,但是该题好像没有能利用格式化字符串漏洞的函数,只存在了一个read读入,因此只能栈溢出了,但是检查出开启了Canary保护,不能直接溢出,所以我们首先要做的就是让程序泄露出Canary值。我们得找一下Canary的偏移位置。
算出Canary偏移位置为31,用%31$x来泄露,
buf距离canary的空间为0x64,用垃圾数据填充,然后再填充canary的值,最后填充ebp,覆盖返回地址为system
地址为0x804859B.

exp如下:

12:题目:pwn03(ret2libc -32)

下载附件,检查为32ELF文件,checksec检查开启哪些保护

拖进ida分析,没有system与binsh,这就涉及plt表和got表了,典型的ret2libc。程序还未执行时,got表里是plt表的地址,程序执行后,plt表里是got表的地址,got表是函数的真实地址,所以思路就是利用第一次溢出把已经执行过的puts函数的plt表放置ret处,泄露出got表里的真实地址,然后返回地址填的main,再执行程序,再通过溢出将返回地址覆盖成泄露出来的 system 的地址 getshell

exp如下

13:题目:get_started_3dsctf_2016 (无ebp寻址)

拿到附件,检查为32位ELF文件,checksec,

拖进ida分析
printf泄露v4地址,而恰好v4就是能溢出的地方,第一就想到ret2shellcode,但是前边检查出开启了NX保护,于是放弃,
但是看到了有get_flag字样的函数,点进去,发现只要满足两个参数就能得到flag,于是payload = ‘a’ * 垃圾数据 + ‘junk’ + get_flag的地址 + ‘junk’ + get_flag的第一个参数 + get_flag的第二个参数就好('junk’就是四个字节,第一个是代替main的ebp,第二个代替get_flag的返回地址)

但是发现若没有flag返回地址的话程序就没法正常打印flag,于是改payload,payload = ‘a’ * 垃圾数据 + get_flag的地址 + exit_addr + get_flag的第一个参数 + get_flag的第二个参数,

exp如下:

14:BJDCTF2020 题目: babyrouter(ret2libc-64)

检查附件,64位elf,checksec开启哪些保护措施

可以构造栈溢出

拖进ida分析,查看字符串表无binsh,无system,

查找一下gadgets

有可以利用的gadgets,判断该题位ret2libc,需要我们构造ROP链

点击main函数

代码很简单,调用了一个vuln函数,点击vuln
read可以栈溢出,因为buf长度为0x20,而read要向buf缓冲区读入0x64长度的数据。

先构造ROP链利用putsplt表泄露readgot表的地址然后根据readgot表的真实地址计算出system与binsh的地址,第一个payload为p=flat(b'a'*(0x20+8),poprdi,readgot,putsplt,main,word_size=64)。

然后利用计算出的system,binsh构造第二个payload,p2=flat(b'a'*(0x20+8),ret,poprdi,bin,system,word_size=64)。

exp如下:

15: 1024杯 题目 1024_happy_checkin(ret2libc 64)

拿到附件,die检查为64位elf文件,checksec检查

没有开启栈保护

拖进ida分析

无system无binsh,

查看main函数

有puts,并且存在gets危险函数,典型的ret2libc题,需要我们自己构造ROP链通过puts函数plt表来泄露got表的真实地址,接着计算出system与binsh的地址。

s缓冲区的溢出大小为0x370+8,

ROPgadget找我们需要用到的gadgets

开始构造第一个payload来泄露libc,p=flat(b'a'*(0x370+8),rdi,putsgot,putsplt,main,word_size=64)

泄露之后先recvline接收程序puts的s,再接收泄露的libc地址,addr=u64(r.recv(6).ljust(8,b'\x00'),然后计算system与binsh

的地址,接着利用计算得到的system与binsh构造第二个payload来getshell,p2=flat(b'a'(0x370+8),ret,rdi,bin,system,word_size=64)

exp如下:

16:题目:ciscn_2019_n_5 (法1:ret2libc-64) 17题为本题的ret2shellcode解法

拿到附件,die检查为64位程序,checksec检查保护措施

无保护措施。

拖进ida分析,可以看到没有system,没有binsh,

再查看main函数,

有puts函数有read函数,还有gets危险函数,ret2libc类型题,查看text缓冲区溢出长度为0x20+8,

查找我们需要的gadgets

先构造一个payload通过read函数,这个payload随便都可以,主要目的就是传进去一个name好让程序继续执行。p1=flat(b'aaaa') ,然后构造第二个payload,利用puts函数的plt表泄露read函数got表的真实地址,然后计算system与binsh的地址,p2=flat(b'a'*(0x20+8),poprdi,readgot,putsplt,main,word_size=64),接收泄露的libc ,addr=u64(r.recv(6).ljust(8,b'\x00')),因为p2的返回地址填的是main函数,程序会再次执行,需要再构造payload通过read函数,p3=flat(b'aaaa') ,然后根据计算出的system与binsh构造payload来getshell,p4=flat(b'a'*(0x20+8),ret,poprdi,bin,system,word_size=64)

exp如下:

17:题目:ciscn_2019_n_5 (法2 ret2shellcode)
前面已检查并未开启NX保护,read函数会读取用户输入的东西,那推测我们可以把shellcode读取到read里,然后再利用下边gets函数栈溢出,把返回地址覆盖为read函数的地址,程序会执行read函数里的shellcode,然后我们就getshell了,比上面的解法1简单多了。

exp如下

18:题目:ciscn_2019_ne_5(ret2text-32)

拿到附件,die检查为32位elf文件,checksec检查开启哪些保护。

未开启栈保护

拖进ida分析,未直接给出binsh,但程序有system函数。

查看main函数

分析整个代码逻辑,先让第一个scanf输入paswd :administrator,让程序继续执行,构造第一个payload p=b'administrator',switch根据第二个scanf输入的数字选择执行对应的功能。发现switch里有getflag字样,点进去
发现会把src复制到dest中,dest是目标溢出函数,而src是中间传递的工具,The flag is your log 提示我们入口处在case 1处 Addlog函数,点进Addlog
发现会把scanf输入a1的内容返回给src,于是思路就是把payload通过此处的scanf写入src,再选择4执行getflag函数,经过getflag函数里的strcpy传给dest,故dest是目标溢出函数。查看dest函数溢出大小为0x48+4,构造payload,system程序中有,但是没有binsh,使用ROPgadget查找下binsh,构造payload,p1=flat(b"a"*(0x48+4),system,b"aaaa",sh),

exp如下:

19:题目:ciscn_2019_c_1(ret2libc-64)

拿到附件,检查为64位elf文件。

checksec检查开启哪些保护

拖进ida分析。

没有binsh没有system函数,需要自己构造ROP链了。

查看main函数

分析代码逻辑,经过一串puts欢迎后,调用begin函数,查看begin函数
让你选择,然后程序执行
while循环里,若选择2选项,则会puts(“I think you can do it by yourself"),并且又进入选择;若选择3,程序puts("Bye"),并且程序结束,看来只能选择1,调用encrypt函数。点进去
发现是对你输入的东西进行加密,并且gets就是溢出点,payload的入口,但是我们不能让传进去的payload被程序加密,strlen是计算长度的函数,我之前的文章c各类函数原理以及使用介绍过,可以用'\0' 截断使其返回 0。使if判断为真,进入break,不执行下方加密程序。s的溢出大小为0x50+8,但要在第一位加一个'\x00',故只需再填充0x57长度的垃圾数据即可。但这题还需自己构造ROP链泄露libc,计算sytem与binsh的地址,查找需要用到的gadgets

分析完毕,开始构造第一个payload泄露libc,p=flat(b'\x00',b'a'*(0x50+7),rdi,putsgot,putsplt,main,word_size=64),计算system与binsh地址,再构造第二个payload获得shell,p1=flat(b'\x00',b'a'*(0x50+7),ret,rdi,bin,system,word_size=64),

exp如下:

20:题目:[HarekazeCTF2019]baby_rop2(ret2libc-64加设置printf参数)

checksec 检查

64位小端序,无栈保护

ida分析。

无system无binsh,需构造ROP链。

利用printf泄露函数地址,参数类型为printf(“%s”,address),由于64位程序前六个参数不直接使用栈,先使用寄存器RDI、RSI、RDX、RCX、R8、R9,传递,其余参数才通过栈传递。

第一个参数我们利用程序自带的’Welcome …,%s’字符串

第二个参数我们选择打印read函数的真正地址来泄露libc

查找用到的gadgets

不存在单独利用rsi的指令,但是随意设置r15就可以,此题没用到r15设置参数。

构造payload1:

rdi,str:设置寄存器rdi的内容为str,为printf的第一个参数。

rsi,readgot:设置寄存器rsi的内容为readgot,printf的第二个参数,r15因为没用到,随意设置。

printfplt:执行ret指令后,返回到printf在plt表中的地址,相当于执行printf函数

main:printf函数的返回地址,得到read真正地址后返回程序开始,重新执行

打通后发现没有flag

那就查找:
exp如下:

21:题目:repeater

checksec

64位小端序ELF程序

没有敏感字眼

main函数:

由于程序开启了pie保护,地址只剩下了后三位,我们需要先找到基地址才能继续解题。所以先要满足if判断来打印出main函数真实地址。

我们需要先第一次溢出使if判断相等打印出main函数地址,构造第一个payload来覆盖局部变量:p=flat(b'a'*(0x20),0x321321,word_size=64),然后接收main地址。

r.recvuntil("But there is gift for you :\n")

mainaddr=int(r.recvuntil("\n"),16)

然后mainaddr减去随机化的main后三位即为基地址

然后0x202040加上基地址即为真实地址,

这个地址可以读入shellcode,然后在溢出点的时候把返回地址覆盖为读入shellcode的地址即可getshell。构造第二个payload:p= b'a'*(0x30+8)+ p64(base + 0x202040)

exp如下: