CTF逆向-Dig the way Interesting Pointer-通过栈溢出方式覆盖变量以达到修改执行流程的目的

CTF逆向-Dig the way Interesting Pointer-通过栈溢出方式覆盖变量以达到修改执行流程的目的

来源:https://buuoj.cn/

内容:dig the way(to get the key)!

附件:链接:https://pan.baidu.com/s/1ohai-S1epbYp2O-hzH8CRQ?pwd=rhz5 提取码:rhz5

答案:8cda1bdb68a72a392a3968a71bdb8cda

总体思路

发现流程正常执行的话无法获得flag

尝试通过栈溢出的方法修改正常的流程

推导出在该流程下能够使得flag输出的条件,并通过栈溢出满足该条件

详细步骤

  • 查看文件内容

    • image-20220428210124532
  • 发现有三个方法是明显要被轮流调用的,点进去查看每个方法

    • func0 是交换下标为 a2和a3的值,随后返回1

      • int __cdecl func0(int a1, int a2, int a3)
        {
          int v4; // [esp+Ch] [ebp-4h]
        
          v4 = *(_DWORD *)(4 * a2 + a1);
          *(_DWORD *)(a1 + 4 * a2) = *(_DWORD *)(4 * a3 + a1);
          *(_DWORD *)(a1 + 4 * a3) = v4;
          return 1;
        }
        
    • **func1 **是返回 |a[x]+a[y]| - |a[x]| - |a[y]| + 2

      • unsigned int __cdecl func1(int a1, int a2, int a3)
        {
          return abs32(*(_DWORD *)(4 * a2 + a1) + *(_DWORD *)(4 * a3 + a1))
               - abs32(*(_DWORD *)(4 * a3 + a1))
               - abs32(*(_DWORD *)(4 * a2 + a1))
               + 2;
        }
        
    • func2 是返回 |a[x]| + |a[y]| - |a[x]+a[y]| + 2

      • unsigned int __cdecl func2(int a1, int a2, int a3)
        {
          return abs32(*(_DWORD *)(4 * a3 + a1))
               - abs32(*(_DWORD *)(4 * a3 + a1) + *(_DWORD *)(4 * a2 + a1))
               + abs32(*(_DWORD *)(4 * a2 + a1))
               + 2;
        }
        
  • 整理得到流程

    • image-20220428204459919
  • 发现只有当v_temp[3] == 0的时候,才会调用get_key输出flag。

  • 根据绝对值的性质,发现只有v_funcs[1]可以返回0,且当a=1,b=-1的时候,|a|+|b|-|a+b| + 2 = 0

  • 再观察计算流程,发现会逐个执行v_funcs方法。故可以是通过func0交换掉func1和func2的执行顺序,使得func1成为最后被调用的

  • while ( i <= 2 )
    {
        v5 = i + 1;
        v_temp[v5] = ((int (__cdecl *)(_DWORD *, _DWORD, _DWORD))v_funcs[i])(v_temp, v_temp[4], v_temp[5]);
        v_temp[4] = ++i;
        v_temp[5] = i + 1;
    }
    
  • 模拟流程

    • i=0

      • v_temp[1] = v_funcs[0](v_temp,v_temp[4],v_temp[5]) = 1
      • v_temp[4] = 1 , v_temp[5] = 2
    • i=1

      • v_temp[2] = v_funcs[2](v_temp,1,2) = |1| + |v_temp[2]| - |1+v_temp[2]| + 2

        • 如果 v_temp[2] > 0 则 原式 = 1 + v_temp[2] - 1 - v_temp[2] + 2 = 2
        • 如果 v_temp[2] > -1 && v_temp[2] < 0 , 无v_temp[2]符合,不成立
        • 覆盖 v_temp[2] < -1 则 原式 = 1 - v_temp[2] + v_temp[2] - 1 + 2 = 2
        • 故该式恒等于 2 ,即 v_temp[2] = 2
      • v_temp[4] = 2 , v_temp[5] = 3

    • i=2

      • v_temp[3] = v_funcs[1](v_temp,2,3)

        = |v_temp[2] + v_temp[3]| - |v_temp[2]| - |v_temp[3]| + 2

        = |2 + v_temp[3]| - 2 - |v_temp[3]| + 2

        = |2 + v_temp[3]| - |v_temp[3]|

        当v_temp[3]>0时,原式恒等于2

        当v_temp[3]>-2 && v_temp[3]<0时,原式 = 2 + 2 * v_temp[3] ,即 v_temp[3] = -1时原式为0

        当v_temp[3]<-2时,原式=-2 - v_temp[3] + v_temp[3] = -2 不满足

      综上所述,使得v_temp[3]=-1即可

  • 最终,即v_temp[3] = -1 ,v_temp[4] = 7 ,v_temp[5] = 8,生成data的脚本如下

    • import struct
      single_word_len = 4
      data = b''
      data += b'a'*20  # 以字符a填充满v_input
      
      # 以字符a填充 v_temp[0] v_temp[1] v_temp[2]
      data += b'a'*3*single_word_len
      
      data += struct.pack('<i', -1) # 覆盖v_temp[3] = -1
      data += struct.pack('<i', 7)  # 覆盖v_temp[4] v_func[0] 等效于 v_input[7]
      data += struct.pack('<i', 8)  # 覆盖v_temp[5] v_func[1] 等效于 v_input[8]
      with open('data', 'wb') as f:
          f.write(data)  # 保存数据到文件
      
      
  • 运行得到flag 8cda1bdb68a72a392a3968a71bdb8cda

其他文档

更多CTF逆向题通用性做法和常用工具下载参考该博文内容:CTF逆向Reverse题的玩法

相关逆向CTF题

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值