看雪ctf晋级赛第六题wp

查看导出表,就一个main函数

在这里插入图片描述

打开strings窗口,查看strings,可以看到下面是有很多字符串的

在这里插入图片描述

程序运行,输出结果如下所示,所以我们需要去定位到这个字符串,看看是哪里调用的

在这里插入图片描述

在我们的sub_4014C0当中被用到了

在这里插入图片描述

查看伪代码如下所示

在这里插入图片描述

scanf以后是sub_004012F0这个函数验证,验证从第8位开始之后的12位字符,要全部相等,然后以及我们输入的字符串a1+20个字节要等于H

在这里插入图片描述

然后我们od动态调试

在这里插入图片描述

然后我们f8一步一步的运行,可以运行到下面,就可以看到有相应的字符串了,总共验证了12个字符串,X1Y0uN3tG00d

在这里插入图片描述

接下来看其他的,接下来我们来看sub_401460

在这里插入图片描述

下面的这个函数,判断了我们输入的是不是等于24个字符

在这里插入图片描述

然后去调用了sub_4013B0,然后又去调用了sub_401380

在这里插入图片描述

sub_401380

在这里插入图片描述

前8位字符的转换

void sub_401380(char *str)      //参数是我的输入
{
    int v1=0; 
    int c[8]={0};
    while ( v1 <= 7 )
        c[v1] = str[v1++] - 48;
}

然后再就是sub_4013B0

int sub_4013B0(int a1)                      //参数是我的输入
{
    int v1; // ebx
    int v2; // ecx
    int v3; // esi
    int result; // eax

    sub_401380(a1);                         //408020 存前8位验证码整数
    /*
    int i=0; 
    int c[8]={0};
    while ( i <= 7 )
        c[i] = str[i++] - 48;
    */

    v1 = c[4] + 1000 * c[1] + 100 * c[2] + 10 * c[3];
    v2 = c[6] + 10 * c[5];
    v3 = c[8] + 10 * c[7];
 
    if ( 2 * (v1 + v2) != 4040 || 3 * v2 / 2 + 100 * v3 != 115 )
goto LABEL_2;
    result = 1;
    if ( v1 - 110 * v3 != 1900 )
    {
        printf("Key_Is_Wrong,Please_Input_Again!");
LABEL_2:
        result = 0;
    } 
    return result;
}

所以我们要让其不满足这个条件2 * (v1 + v2) != 4040 || 3 * v2 / 2 + 100 * v3 != 115以及v1 - 110 * v3 != 1900,假设我们让其的解等变成相等,那么条件其实就是
2*(v1+v2) =4040
3v2/2 + 100v3=115
v1-110*v3=1900
设v3=1,v2=10,那么v1=2010,三条式子就都成立了

所以带回到上面
2010 = c[3] + 1000 * c[0] + 100 * c[1] + 10 * c[2];
10 = c[5] + 10 * c[4];
1 = c[7] + 10 * c[6];
c[0]=0或1或2
c[3]=10或0
c[6]=0
c[7]=1
c[4]=0或1
c[5]=0或10
c[1]=0-20
c[2]=0-74

所以这里c的范围我们知道了,我们就可以逆推原先的符号了,算出68个解,感觉应该是不带符号的

#include <stdio.h>
#include <stdlib.h>
int main(int argc, const char * argv[]) {
   
    int v1=0;
    int v2=0;
    int v3=0;
    int c[8]={0};
    c[6]=0;
    c[7]=1;
    int p=1;
    
    for (c[0] = 0; c[0] <= 2; c[0]++)
        for (c[1] = 0; c[1] <= 20; c[1]++)
            for (c[2] = 0; c[2] <= 74; c[2]++)
                for (c[3] = 0; c[3] <= 10; c[3]++)
                    for (c[4] = 0; c[4] <= 1; c[4]++)
                        for (c[5] = 0; c[5] <= 10; c[5]++)
                        {
                            if ((2010 == (c[3] + 1000 * c[0] + 100 * c[1] + 10 * c[2])) &&
                                (10 == (c[5] + 10 * c[4])) && (1 == (c[7] + 10 * c[6])))
                            {
                                char str[9] = { 0 };
                                for (int i = 0; i < 8; i++)
                                    str[i] = (c[i] + 48);
                                printf("解%-3d:%s\n",p++, str);
                            }
                        }
    
    return 0;
}
解1  :0=v:0:01
解2  :0=v:1001
解3  :0=w00:01
解4  :0=w01001
解5  :0>l:0:01
解6  :0>l:1001
解7  :0>m00:01
解8  :0>m01001
解9  :0?b:0:01
解10 :0?b:1001
解11 :0?c00:01
解12 :0?c01001
解13 :0@X:0:01
解14 :0@X:1001
解15 :0@Y00:01
解16 :0@Y01001
解17 :0AN:0:01
解18 :0AN:1001
解19 :0AO00:01
解20 :0AO01001
解21 :0BD:0:01
解22 :0BD:1001
解23 :0BE00:01
解24 :0BE01001
解25 :0C::0:01
解26 :0C::1001
解27 :0C;00:01
解28 :0C;01001
解29 :0D0:0:01
解30 :0D0:1001
解31 :0D100:01
解32 :0D101001
解33 :13v:0:01
解34 :13v:1001
解35 :13w00:01
解36 :13w01001
解37 :14l:0:01
解38 :14l:1001
解39 :14m00:01
解40 :14m01001
解41 :15b:0:01
解42 :15b:1001
解43 :15c00:01
解44 :15c01001
解45 :16X:0:01
解46 :16X:1001
解47 :16Y00:01
解48 :16Y01001
解49 :17N:0:01
解50 :17N:1001
解51 :17O00:01
解52 :17O01001
解53 :18D:0:01
解54 :18D:1001
解55 :18E00:01
解56 :18E01001
解57 :19::0:01
解58 :19::1001
解59 :19;00:01
解60 :19;01001
解61 :1:0:0:01
解62 :1:0:1001
解63 :1:100:01
解64 :1:101001
解65 :200:0:01
解66 :200:1001
解67 :20100:01
解68 :20101001

上面我们得到了可以说是21个字符串了,还有三个字符串没有拿到,八位是20101001,中间12位是 X1Y0uN3tG00d,然后第21位是H,那么还剩下最后的三位,下面就是验证最后的函数的地方

int sub_401460(char *Str)           //参数是我的输入
{
  char Dest; // [esp+8h] [ebp-10h]

  if ( strlen(Str) == 24 )                  //首先验证我的输入是否为24字节  
  {
    if ( sub_4013B0((int)Str) )
    {
      Str[20] -= 88;                        //最后4位字符的鬼操作
      Str[21] -= 70;
      Str[22] -= 3;
      Str[23] -= 107
      strcpy(&Dest, Str);
    }
  }
  else                                      //不是24字节就他退出了
  {
    printf("String Length is Wrong");
  }
  return 0;
}

在strcpy函数做完之后,还会跳转到401483处,此时esp为0022FEB0

在这里插入图片描述

然后我们跟着堆栈,发现最后要去调用隐藏函数401BF0,到这里的时候,ESP是为0022FECC了,因为上面esp + 0x14 然后再弹出了两个寄存器的值,所以说明我们这里就是要去要得到的是0022FFCC这个地址要指向我们的隐藏函数sub_401BF0

在这里插入图片描述

0x401BF0应该就是最终调用的函数了,因为它最后是有输出东西给我们的

在这里插入图片描述

为了达到这个目的,我们做了下面的操作,之所以可以做下面的操作是在于这里少申请了4个字节,所以结合上面的走到jmp 00401483的时候esp是0022FEB0,所以应该是从0022FEB0 + 0x8 = 0022FEB8开始复制

在这里插入图片描述

用od查看也可以查看的出来,只申请了20个字节

在这里插入图片描述

所以既然从b8开始复制,要复制到cc,总共是20个字节,所以最后四个字节是我们可以去溢出得到,我们只需要去关注最后三位得到的结果设置为1B 40 00,所以就应该为aCk

在这里插入图片描述

倒数第四个字符H是确定的也不需要我们管,下面可以看到它自己变成了70了

在这里插入图片描述

移入了两个寄存器的值到栈当中,然后复制就是从0022FEB9开始的了一直复制到了0022FECC,所以我们是可以控制0022FECC处的值的

在这里插入图片描述

最终得到的Flag,最后两位分别是67和107
20101001X1Y0uN3tG00dHaCk

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值