2018上海CTF“骇极杯” What’s_it

从这道题中学到了很多东西--------

我当时和一个朋友抱怨 有没有有难度的题 而且还有wp的  因为 没有wp 做了好多天都没有结果 还没有答案是一件非常难受的事 

本来这个题 我想用ida的idc 或者 python来解题的 但是 后来发现。。。。。 不会

很尴尬 还拿了书 结果 看是能看懂 但是根本就没有办法 怎么说 让问题简单化  用python 我百度了一下 发现还是要调用c语言的api函数 (那我不如直接用c语言的) 但是这又背离了我的初衷 所以  我就直接粘贴复制简单暴力。。。

先说说这道题 一开始这道题并没有显示出来是exe文件 我拖入llinux 然后发现竟然是个32位 PE文件????   然后后缀改成exe 然后直接就能运行了  然后这道题 看起来也没有那么难 

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v4; // [esp+1Ch] [ebp-48h]
  int v5; // [esp+20h] [ebp-44h]
  char v6[32]; // [esp+24h] [ebp-40h]
  char v7; // [esp+44h] [ebp-20h]
  int v8; // [esp+45h] [ebp-1Fh]
  __int16 v9; // [esp+49h] [ebp-1Bh]
  char v10; // [esp+4Bh] [ebp-19h]
  int k; // [esp+4Ch] [ebp-18h]
  int j; // [esp+50h] [ebp-14h]
  int i; // [esp+54h] [ebp-10h]
  int v14; // [esp+58h] [ebp-Ch]
  int v15; // [esp+5Ch] [ebp-8h]

  __main();
  v8 = 0;
  v9 = 0;
  v10 = 0;
  memset(v6, 0, sizeof(v6));
  v7 = 0;
  v5 = 0;
  v4 = 0;
  v15 = 0;
  v14 = 0;
  printf("Please input your luck string:");     // 让输入值
                                                // 
  scanf("%s", &v8);
  if ( strlen((const char *)&v8) != 6 )         // 长度为6
    return 0;
  for ( i = 0; i <= 5; ++i )
  {
    if ( *((_BYTE *)&v8 + i) <= 96 || *((_BYTE *)&v8 + i) > 122 )// a~z
      return 0;
  }
  getMD5((char *)&v8, v6);                      // md5加密
  for ( j = 0; j <= 31; ++j )
  {
    if ( v6[j] == 48 )
    {
      ++v15;
      v14 += j;
    }
  }
  if ( 10 * v15 + v14 == 403 )                  // 这里就可以 暴力求我们输入的值
  {
    for ( k = 0; k <= 3; ++k )
    {
      *((_BYTE *)&v5 + k) = v6[k];
      *((_BYTE *)&v4 + k) = v6[k + 28];
    }
    decode((unsigned __int8 *)&v4);             // 这里穿的是 后四位
  }
  check((unsigned __int8 *)&v5);                // 这里传的是前四位
  return 0;
}

看到这我的想法就是直接爆破输入就ok了 6个for循环加上 a~z的数据范围  然后这是我爆破的脚本

import hashlib
import string
m=hashlib.md5()
def encrypt_md5(str):
    md = hashlib.md5()  # 创建md5对象
    md.update(str.encode(encoding='utf-8'))  # 这里必须用encode()函数对字符串进行编码,不然会报 TypeError: Unicode-objects must be encoded before hashing
    return md.hexdigest()  # 加密
sign=''
for i in range(97,123):
    for j in range(97,123):
        for k in range(97,123):
            for l in range(97,123):
                for s in range(97,123):
                    for a in range(97,123):
                        g=0
                        gg=0
                        sign=''
                        ss=''
                        sign=chr(i)+chr(j)+chr(k)+chr(l)+chr(s)+chr(a)
                        ss=encrypt_md5(sign)
                        for xx in range(0,32):
                            if ss[xx]=="0":
                                g=g+1
                                gg=gg+xx
                        if gg+g*10==403:
                            print (sign)
                            break

然后这是我爆破的密码

爆破的字符串:ozulmt 然后我们 我们再往下看 

看着后面 它传入的是我们后面爆破的字符串 md5加密后的 前四位 和后四位 那我们再写出脚本

import hashlib
import string
m=hashlib.md5()
def encrypt_md5(str):
    md = hashlib.md5()  # 创建md5对象
    md.update(str.encode(encoding='utf-8'))  # 这里必须用encode()函数对字符串进行编码,不然会报 TypeError: Unicode-objects must be encoded before hashing
    return md.hexdigest()  # 加密

string_s=encrypt_md5("ozulmt")
s=[""]*4
ss=[""]*4
for x in range(4):
    s[x]=string_s[x]
    ss[x]=string_s[x+28]
print (s)
print (ss)

啊咧? check 是个函数 异或函数? 然后点开check 发现函数f5不行 也就是说这个函数 是被异或加密的  异或的字节 也很好能看出来 就是305 这里就是上面我说的那个 用脚本可以直接异或。。可惜我不怎么会  然后还看了很多书 也请教了很多学长 还是感觉不怎么会 然后我就直接 再od里面查找我们  地址是402626 然后 305的字节是

5589E5575383C480C745F400000000C745F000000000837DF0037F178B55F08B450801D00FB6000FB6C00145F48345F001EBE38B45F4890424E8C6FDFFFF8D4595B921000000BB000000008918895C08FC8D500483E2FC29D001C183E1FCC1E90289D789D8F3ABC7042401000000E832FDFFFF8D45B6890424E8ADFDFFFF8D45B6890424E8BEFDFFFFC745EC00000000837DEC1F7F25C7042410000000E876FDFFFF0FB6806060400089C18D55958B45EC01D088088345EC01EBD5C745F400000000C745E8000000008D45B6890424E8BEFCFFFF3B45E80F9FC084C0742A8D55B68B45E801D00FB6108D4D958B45E801C80FB60038C275068345F401EB048345F4648345E801EBC1837DF4207509C745F402000000EB07C745F4030000008B45F4890424E87CFCFFFF9083EC805B5F5DC3

然后我们就很简单的能够得到check 

为什么printfs 的2是正解  我们看一下printfs

然后  我在上面发现了一个检查我们输入flag值的地方 我们点进去看看

这里应该还是解释的挺清楚的 也就是说 flag的格式 是flag{xxx-xxx-xxx-xxx-xxx} 然后 到后面  输入的值变成了 xxxxxxxxxxxxxx 去掉了 - 和flag { } 然后

然后我们发现种子就是我们上面得出来的数组和 然后我们可以写个程序

#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<iostream>
using namespace std;
char s[]={"0123456789abcdef"};
char ss[]={"0ec4"};
char ans[32];
int seed;
int main()
{
     int sum=0;
     for(int i=0;i<4;i++)
         seed+=ss[i];
     srand(seed);
     for(int i=0;i<32;i++)
     {
          ans[i]=s[rand()%16];
     }
     printf("flag{");
     for(int i=0;i<36;i++)
     {
         if(i==8||i==13||i==18||i==23)
         {
             printf("%c",45);
             sum++;
             continue;
         }
         printf("%c",ans[i-sum]);
     }
     printf("}");
     return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值