首页 > 其他 > 详细

BUU Dig the way

时间:2020-10-11 08:54:25      阅读:58      评论:0      收藏:0      [点我收藏+]

先检查下文件, 32位的PE,无壳

技术分享图片

 

 

主函数:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int result; // eax
  int v4; // ebx
  size_t v5; // eax
  int v6; // ebx
  char v7[20]; // [esp+1Ch] [ebp-48h]
  int v8; // [esp+30h] [ebp-34h]
  int v9; // [esp+34h] [ebp-30h]
  int v10; // [esp+38h] [ebp-2Ch]
  int v11; // [esp+3Ch] [ebp-28h]
  int v12; // [esp+40h] [ebp-24h]
  int v13; // [esp+44h] [ebp-20h]
  signed int (__cdecl *v14)(int, int, int); // [esp+48h] [ebp-1Ch]
  int (__cdecl *v15)(int, int, int); // [esp+4Ch] [ebp-18h]
  int (__cdecl *v16)(int, int, int); // [esp+50h] [ebp-14h]
  int v17; // [esp+54h] [ebp-10h]
  int v18; // [esp+58h] [ebp-Ch]
  FILE *v19; // [esp+5Ch] [ebp-8h]

  __main();
  v14 = func0;
  v15 = func1;
  v16 = func2;
  v8 = 0;
  v9 = 1;
  v10 = 2;
  v11 = 3;
  v12 = 3;
  v13 = 4;
  v19 = fopen("data", "rb");
  if ( !v19 )
    return -1;
  fseek(v19, 0, 2);
  v18 = ftell(v19);                             // 获取文件长度
  fseek(v19, 0, 0);
  v17 = ftell(v19);                             // v17 = 0
  if ( v17 )
  {
    puts("something wrong");
    result = 0;
  }
  else
  {
    for ( i = 0; i < v18; ++i )                 // 将data之中的数据写入 v7[20]数组
    {
      v4 = i;
      v7[v4] = fgetc(v19);
    }
    v5 = strlen(v7);                            // v7之中的有效字符数
    if ( v5 <= v18 )
    {
      v18 = v11;
      i = 0;
      v17 = v13;
      while ( i <= 2 )                          // 3轮  正常情况下依次调用函数 func0 、 func1 、 func2
      {
        v6 = i + 1;
        *(&v8 + v6) = (*(&v14 + i))((int)&v8, v12, v13);// 返回值依次填入 v9 v10 v11
        v12 = ++i;
        v13 = i + 1;                            // 先交换 v8[4*v12] 与 v8[4*v13] 返回值 = 1
      }                                         // 返回 abs( v8[4*v13] + v8[4*v12] ) - abs( v8[4*v13] ) - abs( v8[4*v12] ) + 2 
      if ( v11 )                                // 返回 abs(v8[4*v13]) - abs( v8[4*v13] + v8[4*v12] ) + abs( v8[4*v12] ) + 2
      {
        result = -1;                            // 因为 abs(a)+abs(b) >= abs(a+b)  所以正常情况下第三轮的返回值即 v11 永远大于零
                                                // 所以利用 func0 交换 func1 和 func2 在在栈上的地址
      }                                         // 
                                                // 第二轮开始时 v12 = 1  v13 = 2
      else                                      // 第三轮开始时 v12 = 2  v13 = 3
      {                                         // 交换之后:
        get_key(v18, v17);                      // 第二轮: abs(v9) + abs(v10) - abs( v9 + v10 ) + 2  
        system("PAUSE");                        // 第三轮: abs( v11 + v10 ) - abs( v11 )- abs( v10 ) + 2
        result = 0;
      }
    }
    else
    {
      result = -1;
    }
  }
  return result;
}

通过后面对于 while() 循环的发现可知,正常情况下,3个func走完后 v11是绝对不为 0 的。

在不对程序本身下手的情况下。我们只能把注意打到那个叫 data 的文件上。

刚好程序中 data 写入 v7[20] 这一步因为没有对写入长度进行限制,存在溢出。

而 3 个 func 函数又是通过函数指针进行间接调用,函数的地址也是都写在栈上,还都在 v7[20] 后面:

技术分享图片

 

 做过pwn的小伙伴们立刻想到:通过栈溢出改变程序的执行流:

利用 data 的写入覆盖 v12 和 v13 

使  v8[4*v12]  和  v8[4*v13]  分别指向 func1 和 func2

在 func0 执行后交换 v15 和 v16,从而改变 func1 和 func2 的执行顺序

于是我们先构造一个 44 字节的data

 技术分享图片

 

 我试过将v12覆盖为8,v13为7,到最后虽然也能触发  _get_key 但输出的flag值提交上去是错的。

然后是要构造 v9 、v10 、 v11 的值,使 v11在func2 、 func1 执行结束后为 0.

我在注释里也写得挺清楚:

 v9 = x
 v10 = y
 v11 = z
 
 y = |x| + |y| - |x + y| + 2

 z = |y + z| - |y| - |z| + 2
 
 z == 0

解不唯一,我算了两个都能用:

 v9 = 1  v10 = 0 v11 = -1
 
 v9 = -1 v10 = 1 v11 = -1

最后用 winhex 生成 data :

技术分享图片

 

 ( 前20字节可以随便写,不用客气的。 )

技术分享图片

 

 

FLAG:flag{8cda1bdb68a72a392a3968a71bdb8cda}

 

BUU Dig the way

原文:https://www.cnblogs.com/pmrPMR/p/13796012.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!