Polarctf靶场做题——8字节能干什么(我觉得好详细哦)

哎~就这题我一看名字我就知道这个是栈迁移,然后ida一看果然是栈迁移

一个小白能有什么坏心思呢,只是想做题提升一下罢了   哎~

啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊(来自一个小白的无能狂吼)

那就先看看这个程序吧

32位的,没开别的东西

直接看ida有一个vuln函数。

int vuln()
{
  int buf[11]; // [esp+8h] [ebp-30h] BYREF

  memset(buf, 0, 40);
  read(0, buf, 0x38u);
  printf("%s", (const char *)buf);
  read(0, buf, 0x38u);
  return printf("%s", (const char *)buf);
}

分析一下,

1. read函数输入buf,可以溢出8个字节,然后printf函数输出buf

2. 再一次read函数输入buf,然后再输出buf

就没了。。。。

那我们应该怎么办

思路

由于题里没有'/bin/sh',所以我们就把/bin/sh写入栈里,然后通过地址去调用/bin/sh

由于可以溢出的字节太少了,所以我们就要就要换一个地方去当作我们的栈,其实按照我的理解啊,有esp的地方才是栈,所以我们要把esp的位置改以一下。

所以我们可以以ebp的地址作为基准(因为这个地址是可以获得的),然后我们可以通过ebp的地址找到buf在栈上的地址,那么我们就把栈迁移到这个位置,因为这个地方够大而且也可以容易找到。

那么我们来实际操作一下,来找ebp_addr, buf_addr


ebp

在第一次输入输出的时候,ida显示buf距离栈底是0x30字节。那我们把buf的0x30字节覆盖之后的下一个位置就是ebp(这个应该都知道吧),然后printf(“%s")输出,会把buf的整体都输出,一直输出到'\0',但是ebp是有值的,不是'\0',所以会把ebp连带着一起输出,那我们就借着这个输出把ebp输出就好了,所以我们先用'a' 填充0x2f 个字节 (距离0x30还剩一个字节),然后再输入'b'(弄个和之前输入不一样的), 因为我们printf会把0x30个数据都会输出,然后才会输出ebp,那我们先接收0x30个数据,(用b作为分割),就会方便很多

payload = b'a' * 0x2f + b'b'

io.send(payload)
io.recvuntil("b")
ebp_addr = u32(io.recv(4))

buf_addr

buf的地址咱们用gdb看

咱们下断点到read函数那里  b *0x08048545    

然后  r  运行然后  n  下一步

输入   aaaaaaaa

然后我们看栈    stack 30

在这里我们要注意一下,buf的值就是框框的地址,但是ebp的值就需要注意,ebp那一行有俩地址,其中左边第一个是ebp的位置,框框里的是我们之前泄露的地址,所以我们要使用泄露的地址去相减,所以是0xffffd108 - 0xffffd0c8 = 0x40

所以buf_addr = ebp_addr - 0x40


所以现在我们就知道了ebp_addr, buf_addr。这些都是准备工作


然后我们还需要寻找一个汇编指令 ”  leave ret   “

ROPgadget --binary pwn --only "leave|ret"

找到leave;ret的地址,那这个指令有什么用呢?

leave:分两步

        1.    mov esp, ebp           //把ebp的值给esp,,也就是让esp指向ebp的位置

         2. pop ebp                    //把esp指向的内容给ebp

ret :就一步

        pop eip                              //把esp指向的内容给eip,让程序执行


我们先构造payload

payload = (b'aaaa' + p32(system_addr) + p32(1) + p32(buf_addr + 0x10) +  b'/bin/sh')

payload = payload.ljust(0x30, b'\x00') + p32(buf_addr) + p32(leave_ret)

然后我们看栈上


这个就应该是发送payload之后栈上的内容,然后我们来还原一下这个payload是如何运行的

payload是在当前函数运行结束之后才会执行,但是看vuln函数的汇编代码能看到最后有一个leave retn.

所以函数本身的leave ret加上我们构造的leave ret,一共有两组leave ret。

leave的第一步之后就是把esp挪到ebp的位置

leave的第二步过后,是pop ebp,就是把esp指向的值给ebp,并且esp会向上移动一位

到现在为止,ebp的位置就移动了移动到了buf的位置,函数本身的leave指令结束了,开始进行函数本身的ret指令。 然后esp到了我们payload里构造的leave ret的位置

ret:pop rip,把esp指向的内容给eip,然后esp向上一个。

然后eip执行我们payload的leave ret,

leave第一步,把esp移动到ebp的位置

leave第二步:把esp指向的东西给ebp,然后esp向上一位

就变成了这样,因为之前esp指向的位置的值是aaaa,所以执行pop ebp的时候,aaaa给了ebp,所以ebp现在的位置就在0x0000aaaa那里,我也不知道是哪里,爱在哪在哪。现在已经用不上了

,因为我们的目的已经达到了,有esp的地方就是栈,ebp管他干嘛,现在我们已经成功的栈迁移了。所以到现在leave就结束了,

接下来就是ret:pop eip        把esp的内容给eip去执行,自己向上一格

现在执行eip,system函数就运行了,然后就是32位程序函数system寻找参数,32位的程序寻找参数是要隔一位的

参数就是buf_addr + 0x10的位置的值,那么这个位置是什么呢,buf_addr + 0的位置是buf本身

栈上每一个格子是4字节,那么buf_addr + 0x10就是在buf开始的第5个位置

所以buf_addr + 0x10刚好是/bin/sh的位置,那么system函数调用就是/bin/sh。

所以啊,就组成了system("/bin/sh")直接提权

听懂掌声!!!!!!!!!!!!!!!!

这道题就完事了,好像基本大概可能也许栈迁移都是这个思路,可能我写的有一点乱,各位师傅凑活凑活看哈,如果有哪里写的不对或者不足,欢迎指正

这个题在 https://www.polarctf.com/#/page/challengesPolarD&N CTF靶场是一个CTF综合练习平台,题目难易结合,简题居多,适合CTF初学者。靶场所有题目均为原创,全部免费使用。icon-default.png?t=N7T8https://www.polarctf.com/#/page/challenges 的pwn区,想要会栈迁移的话还是自己再尝试一下吧,反正我是理解了好久

加油哦~~~~

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值