美文网首页CTF Re&&Pwn
【RCTF2018】部分Writeup

【RCTF2018】部分Writeup

作者: Kirin_say | 来源:发表于2018-05-25 20:09 被阅读14次

    0x01 Sign

    签到题
    载入ida
    Alt+T查找RCTF即得flag

    0x02 git

    签到题
    查看commit信息:

    Revert
    # 请为您的变更输入提交说明。以 '#' 开始的行将被忽略,而一个空的提交
    # 说明将会终止提交。
    #
    # 位于分支 rctf
    # 要提交的变更:
    #   删除:     flag.txt
    #
    

    需要利用git revert来恢复flag.txt
    git bash 下打开:

    git reflog
    

    看到有一次合并:

    f671986 HEAD@{5}: checkout: moving from master to develop
    

    而后:

    git revert f671986
    

    即可恢复txt文件,得到flag

    0x03 cpushop

    hash长度扩展攻击
    我们需要flag的价格:price<money
    利用hashdump附加请求信息:&price=0
    而后根据正常的sign值得到附加信息后的sign
    发送新的请求即得flag

    0x04 Number Game

    第一关直接碰撞即可
    而后可以看到number game是很早的一个猜数游戏
    github上可以找到一种生成树策略:

    https://github.com/AustinGuo/GessNumber
    

    直接套入脚本,过关即得flag

    0x05 babyre

    调试后发现堆中几个参数不可控
    直接运行发现每个字节依次运算,与位置无关
    找到对应关系根据密文破解
    或者直接pwntools按位爆破也可以:

    key = [0xb8a6ee10,0xb986234f,0xf1b1602,0x2571a420,0x805feee3,0x958b0534,0x8a0ad7,0xf3a32248,0x45c66c5a,0xcda47499,0xee152dad,0x77591917,0xb118982f,0x7386bd6a,0xdf1708d2,0x67d38af2,0xc567b6b6,0x526ba076,0xae4c822d,0xa1e10430,0xc3f2de73,0x7f08e077,0x7240b7ba,0x20067e4b,0x28def57e,0x545c15ad,0xb02881cf,0x15d71041,0x9f9e33a3,0x6958d9df,0x51a1924f,0x299fa574,0x3e968078,0x6e7b9de9,0x3e5daef6,0x70573efe,0x94bec810,0xde26ea93,0x7f7a8193,0x7147adb7,0xe554cf78,0xf0dc5e15,0x730a451b,0x90347c6c,0x8699b5f,0x834c762a,0x97e8bb26,0xc1ca6398,0x6aed0d44,0xe498e228,0xb80c91fe,0x9935e5ee,0xbeed92ae,0x5067d2a7,0x239b768c,0x3b6eb4ce,0x354689e2,0x8028bcb,0x86447eef,0x86c95e28,0x8a0ad7,0xe887091c,0xa8f27e12,0x7d8aa463,0xc15dfd82,0x9c513266,0x30a3769a,0xaa8afbba,0x1edc3864,0xaa7a15df,0x6c1194bf,0xeade7bf1,0x115f3801,0x42bafa35,0xa5a30516,0x4e032f9f,0x121ee8ab,0xe75d55e4,0x7f543d62,0x153f1a32,0x6d076b18,0xf3857621,0x6d7df3e1,0xfbcb7aa0,0x36b897bd,0x82c974fc,0xf5650025,0x90f77ba1,0xf9b8d92b,0x9323bc07,0xa5c88e2,0x7390c17b,0x760e65f9,0xb13ad888,0x1667aba8]
    crypto = [0xb80c91fe,0x70573efe,0xbeed92ae,0x7f7a8193,0x7390c17b,0x90347c6c,0xaa7a15df,0xaa7a15df,0x526ba076,0x153f1a32,0x545c15ad,0x7d8aa463,0x526ba076,0xfbcb7aa0,0x7d8aa463,0x9c513266,0x526ba076,0x6d7df3e1,0xaa7a15df,0x9c513266,0x1edc3864,0x9323bc07,0x7d8aa463,0xfbcb7aa0,0x153f1a32,0x526ba076,0xf5650025,0xaa7a15df,0x1edc3864,0xb13ad888]
    flag=""
    for i in crypto:
         j=0
         for k in range(32,127):
              if key[k]==i:
                 flag+=chr(k)
                 break
              k+=1
         print flag
    

    0x06 babyre2

    载入ida调试,看到这里:

    mov     rax, 20656D6F636C6557h
    mov     qword ptr [rsp+198h+s], rax
    mov     rax, 2046544352206F74h
    mov     [rsp+198h+var_D0], 0FFFFFFFFFFFFFFFFh
    mov     [rsp+198h+var_110], rax
    mov     rax, 6548202138313032h
    mov     [rsp+198h+var_C8], 0FFFFFFFFFFFFFFFFh
    mov     [rsp+198h+var_108], rax
    mov     rax, 2061207369206572h
    mov     [rsp+198h+var_C0], 0FFFFFFFFFFFFFFFFh
    mov     [rsp+198h+var_100], rax
    mov     rax, 6320455279626142h
    mov     [rsp+198h+var_B8], 0FFFFFFFFFFFFFFFFh
    mov     [rsp+198h+var_B0], 0FFFFFFFFFFFFFFFFh
    mov     [rsp+198h+var_A8], 0FFFFFFFFFFFFFFFFh
    mov     [rsp+198h+var_A0], 0FFFFFFFFFFFFFFFFh
    mov     [rsp+198h+var_F8], rax
    mov     rax, 65676E656C6C6168h
    mov     [rsp+198h+var_F0], rax
    mov     rax, 756F7920726F6620h
    mov     [rsp+198h+var_E8], rax
    

    这些数据依照顺序依次参与:

    mov     rax, qword ptr [rsp+198h+s]
    xor     ecx, ecx
    mul     [rsp+198h+var_198]
    mov     rsi, rdx
    mov     rdi, rax
    mov     rdx, 0FFFFFFFFFFFFFFC5h
    call    sub_400BA0
    

    这里可以看到几个参数:

    我们输入字符与上文数据的乘积
    乘积高16位存于rsi寄存器
    乘积低16位存于rdi寄存器
    参数0FFFFFFFFFFFFFFC5h存于rdx中
    

    看一下sub_400BA0的伪代码:
    很显然进行运算的只有:

    else
      {
        if ( a2 <= *((_QWORD *)&a1 + 1) )
        {
          if ( !a2 )
            v3 = 1 / 0uLL;
          *(_QWORD *)&v17 = a1;
          *((_QWORD *)&v17 + 1) = *((_QWORD *)&a1 + 1) % v3;
          v5 = v17 % v3;
        }
        else
        {
          v5 = a1 % a2;
        }
        result = v5;
      }
      return result;
    

    很显然,这里的高16位与低16位都需要对0FFFFFFFFFFFFFFC5h取模,而后return
    继续看数次调用sub_400BA0并retn后的运算:

    movdqa  xmm1, [rsp+198h+var_98]
    mov     qword ptr [rsp+198h+var_28+8], rax
    movdqa  xmm0, cs:xmmword_602070
    pxor    xmm1, cs:xmmword_602060
    movdqa  xmm4, [rsp+198h+var_78]
    pxor    xmm0, [rsp+198h+var_88]
    movdqa  xmm3, [rsp+198h+var_68]
    pxor    xmm4, cs:xmmword_602080
    movdqa  xmm2, [rsp+198h+var_58]
    pxor    xmm3, cs:xmmword_602090
    por     xmm1, xmm0
    pxor    xmm2, cs:xmmword_6020A0
    movdqa  xmm0, [rsp+198h+var_38]
    por     xmm4, xmm1
    movdqa  xmm1, [rsp+198h+var_48]
    pxor    xmm0, cs:xmmword_6020C0
    por     xmm3, xmm4
    pxor    xmm1, cs:xmmword_6020B0
    por     xmm2, xmm3
    movdqa  xmm3, xmm2
    movdqa  xmm2, xmm1
    movdqa  xmm1, xmm0
    movdqa  xmm0, cs:xmmword_6020D0
    por     xmm2, xmm3
    pxor    xmm0, xmmword ptr [rsp+198h+var_28]
    por     xmm1, xmm2
    por     xmm0, xmm1
    movdqa  xmm1, xmm0
    psrldq  xmm1, 8
    por     xmm0, xmm1
    movq    rax, xmm0
    test    rax, rax
    jz      short loc_400A86
    jz      short loc_400A86
    mov     edi, offset s   ; "Incorrect."
    call    _puts
    loc_400A68:                             ; CODE XREF: main+520↓j
    xor     eax, eax
    mov     rcx, [rsp+198h+var_10]
    xor     rcx, fs:28h
    jnz     short loc_400A92
    add     rsp, 190h
    pop     rbp
     loc_400A86:                             ; CODE XREF: main+4EC↑j
    mov     edi, offset aCorrectCongrat ; "Correct. Congratulations!"
    call    _puts
    jmp     short loc_400A68
    

    对应伪代码(实际汇编的运算逻辑更清晰一些):

    5 = _mm_or_si128(
             _mm_xor_si128(_mm_load_si128((const __m128i *)&xmmword_6020D0), v46),
             _mm_or_si128(
               _mm_xor_si128(_mm_load_si128((const __m128i *)&v45), (__m128i)xmmword_6020C0),
               _mm_or_si128(
                 _mm_xor_si128(_mm_load_si128((const __m128i *)&v44), (__m128i)xmmword_6020B0),
                 _mm_or_si128(
                   _mm_xor_si128(_mm_load_si128((const __m128i *)&v43), (__m128i)xmmword_6020A0),
                   _mm_or_si128(
                     _mm_xor_si128(_mm_load_si128((const __m128i *)&v42), (__m128i)xmmword_602090),
                     _mm_or_si128(
                       _mm_xor_si128(_mm_load_si128((const __m128i *)&v41), (__m128i)xmmword_602080),
                       _mm_or_si128(
                         _mm_xor_si128(v4, (__m128i)xmmword_602060),
                         _mm_xor_si128(_mm_load_si128((const __m128i *)&xmmword_602070), v40))))))));
      if ( (unsigned __int64)*(_OWORD *)&_mm_or_si128(v5, _mm_srli_si128(v5, 8)) )
        puts("Incorrect.");
      else
        puts("Correct. Congratulations!");
      return 0LL;
    

    很显然,这里只是对应比较运算后的数据与内存中固定的数据:

    .data:0000000000602060 xmmword_602060  xmmword 7BA58F82BD8980352B7192452905E8FBh
    .data:0000000000602060                                         ; DATA XREF: main+438↑r
    .data:0000000000602070 xmmword_602070  xmmword 163F756FCC221AB0A3112746582E1434h
    .data:0000000000602070                                         ; DATA XREF: main+430↑r
    .data:0000000000602080 xmmword_602080  xmmword 0DCDD8B49EA5D7E14ECC78E6FB9CBA1FEh
    .data:0000000000602080                                         ; DATA XREF: main+45B↑r
    .data:0000000000602090 xmmword_602090  xmmword 0AAAAAAAAAA975D1CA2845FE0B3096F8Eh
    .data:0000000000602090                                         ; DATA XREF: main+46C↑r
    .data:00000000006020A0 xmmword_6020A0  xmmword 55555555555559A355555555555559A3h
    .data:00000000006020A0                                         ; DATA XREF: main+478↑r
    .data:00000000006020B0 xmmword_6020B0  xmmword 55555555555559A355555555555559A3h
    .data:00000000006020B0                                         ; DATA XREF: main+4A2↑r
    .data:00000000006020C0 xmmword_6020C0  xmmword 55555555555559A355555555555559A3h
    .data:00000000006020C0                                         ; DATA XREF: main+496↑r
    .data:00000000006020D0 xmmword_6020D0  xmmword 55555555555559A355555555555559A3h
    .data:00000000006020D0                                         ; DATA XREF: main+4BA↑r
    

    shift+E提取数据
    我们需要求出对应的x满足:

    x:所要求的的flag
    y:内存中的比较数据(已知)
    k:最开始的参与乘积的数据(已知)
    x需要满足:
    kx ≡ y mod 0FFFFFFFFFFFFFFC5h
    

    实际上,我们只需要求k关于0FFFFFFFFFFFFFFC5h的乘法逆元,即X满足:

    kX  ≡ 1 mod 0FFFFFFFFFFFFFFC5h
    

    而后kXy即满足:

    kXy ≡ y mod 0FFFFFFFFFFFFFFC5h
    

    故而:

    所求:x=Xy
    

    这里直接利用PyCrypto库中的inverse函数(求乘法逆元)即可:
    逐位运算即得flag:

    from pwn import *
    from Crypto.Util.number import *
    
    key1 =[0x20656D6F636C6557,0x2046544352206F74,0x6548202138313032,0x2061207369206572,0x6320455279626142,0x65676E656C6C6168,0x756F7920726F6620,0xFFFFFFFFFFFF002E,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF]
    key2 =[0x2B7192452905E8FB,0x7BA58F82BD898035,0xA3112746582E1434,0x163F756FCC221AB0,0xECC78E6FB9CBA1FE,0x0DCDD8B49EA5D7E14,0xA2845FE0B3096F8E,0x0AAAAAAAAAA975D1C,0x55555555555559A3,0x55555555555559A3,0x55555555555559A3,0x55555555555559A3,0x55555555555559A3,0x55555555555559A3,0x55555555555559A3,0x55555555555559A3]
    key3 = 0xFFFFFFFFFFFFFFC5
    flag=""
    for i in range(len(key1)):
       flag+=p64(key2[i] * inverse(key1[i],key3)%key3)
    print flag
    

    相关文章

      网友评论

        本文标题:【RCTF2018】部分Writeup

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