GFCTF2021复盘

比赛打到中午就溜溜球去新生赛帮忙了,所以试图复盘此次比赛部分题目

因个人水平有限,复现的题目仅包括(每题提供附件):

  • misc全部题目(重生之我在A国当间谍,pikapikapika,双击开始冒险)
  • re部分题目(Wordy,easy_low)
    逆向剩余的部分题目有个师傅在52上写了,我舔!https://www.52pojie.cn/thread-1551240-1-1.html

Misc

重生之我在A国当间谍

链接:https://pan.baidu.com/s/1pkAtfcm5MI4hSBFFu-8yHQ
提取码:eqyq

拿到题目后 winhex 打开

看到 ASCII 部分很像 hex 值,于是复制出来再以 hex 的形式保存到新的文件

看到有串长得很像 base64 的字符串

base64decode 一下,得到解压密码:[1e4rl0/e

但是赛后看大佬 wp 得知这其实是 PDU 编码,一句一句解密就可以,网址:http://www.sendsms.cn/pdu/

倒数第二句解密出来是:真让人无语。我把密码告诉你,记住,这个密码不要告诉任何人。WzFlNHJsMFwvZQ==

算是非预期了吧,这题的分我本不配拿QAQ

言归正传,继续往下做题,用密码解开压缩包以后,看到是一张撕毁了的二维码,本来想着截图成一块一块拼到一起,结果显然是不行的,啥也扫不出来。于是扔给会 ps 的咸鱼舍友,才终于拼出了flag

GFCTF{ctf_Ha0_NaN_aaAaaaAaaaaAaaaaaAaa}

pikapikapika

链接:https://pan.baidu.com/s/1gcQxhrQvPRFMhQhEBTiPLA
提取码:lze7

拿到题目 binwalk 发现有个压缩包

分离出来后解压提示需要密码,看一眼皮卡丘

按照这个顺序组合出解压密码为:I_want_a_p1ka!

解压后得到 flag.wav,用 Audacity 打开看看,发现一共 2 种频率,不难想到低位对应 0,高位对应 1

不会写脚本,抱着侥幸心理想会不会有用信息就一部分,往后就都是重复的,手撸了一会后发现其实并不,于是就心安理得摆烂了(叉腰

赛后看了大佬的 wp,才得以了解此题

有一点注意的是跑脚本前需要处理一下 wav 文件,只保留其中的 data 部分,如下图所示

脚本如下(来源:套神)

f = open('flag.wav','rb').read()
flag = ''
for i in range(len(f)//2):
    if(f[i*2:i*2+2] == b'\x98:'):
        flag += '0'
    else:
        flag += '1'
s = ''
rflag = ''
for i in flag:
    s+=i
    if len(s)==8:
        rflag += chr(int(s,2))
        s=''
print(rflag)

得到一串 base64,放到 cyberchef 解密一下保存为 png,发现很明显改了图片的高,改高一点就可以发现 flag 啦

GFCTF{fe1a-17f7-a7f6-1f8f534e-ef3974-c049c5}

双击开始冒险

链接:https://pan.baidu.com/s/1Q4GrX8XGgVeQkt0JugJcSw
提取码:cgai

第一步爆破密码,四位数,上 AZPR

解压后来到第二层,打开 hint 拉到最右边,中间的地方有句话

搜索对应 QQ 号,看到签名(因为复现时时间已经是赛后两天了,所以此人只保留了签名,比赛时名字也是base64,虽然我强调这个好像也没什么必要),WW91IGxvdmUgbWUsIEkgbG92ZSB5b3U=

base64decode 得到:You love me, I love you,解压压缩包,来到第三层

看到给出了一个 usb 鼠标流量,此前只接触过键盘流量,上网搜了几篇文章对着弄但不知道为啥啥也提取不出来,于是又顺理成章摆烂了

赛后看别人 wp,发现大家都能提取出来,整个被大疑惑到,但我肯定我确实是提取不出来,又通过一中午的不懈尝试,终于发现虽然在 kali 里提取了个寂寞但是在 windows 下却可以提取出来......原因不明,但觉得自己血亏

tshark -r usb.pcapng -T fields -e usb.capdata > usbdata.txt

提取后发现有很多空行,想着用 sed 一步到位然而发现又什么都提取不出来,只得手动脚本加工来把空行去掉

file1 = open('usbdata.txt', 'r', encoding='utf-8') 
file2 = open('usbdat.txt', 'w', encoding='utf-8') 

for line in file1.readlines():    
    if line == '\n':        
       line = line.strip("\n")       
    file2.write(line) 
file1.close()
file2.close()

得到了一串 16 位的流量数据,提取第 0 2 4 6 字节来画图(说明:接下来的脚本来源均为套神博客)

f = open('usbdat.txt','r').readlines()
f1 = open('usb.txt','w')
for i in range(len(f)):
    f[i] = f[i].split(':')
for i in range(len(f)):
    tmp = ''
    for j in range(4):
        tmp += f[i][j*2]+':'
    f1.write(tmp)
    f1.write('\n')

接下来转换成坐标(y坐标需要加个负号)

nums = []
keys = open('usb.txt','r')
result=open('result.txt','w')
posx = 0
posy = 0
for line in keys:
    if len(line) != 13:
         continue
    x = int(line[3:5],16)
    y = int(line[6:8],16)
    if x > 127 :
        x -= 256
    if y >127 :
        y -=256
    posx += x
    posy += y
    btn_flag = int(line[0:2],16)  # 1 for left , 2 for right , 0 for nothing
    if btn_flag == 1:
        result.write(str(posx)+' '+str(-posy)+'\n')
keys.close()
result.close()

用 gnuplot 画图得到:

7724774CTF,解压得到

winhex 打开,flag 就在结尾

GFCTF{this_is_rea1_fllllll11ag}

RE

Wordy

链接:https://pan.baidu.com/s/1B7HFDUk1PC_d3WTYW9X6mw
提取码:mt1t

IDA 打开,看到 hex 窗口,很明显可以看到一串可疑字符

读一下,hello world! There are moments in...

bb了贼长的一段,往下拉一段距离就可以看到 flag

GFCTF{u_are2wordy}

easy_low

链接:https://pan.baidu.com/s/1bNQ1MDZZ7ucqhPR1x0rCYg
提取码:p4w8

jadx 打开,定位到 MainActivity

简单分析一下,看到点击事件 onClick,先看第一部分

这一部分输入两个字符串,用户名和密码,并且可以得知二者长度均为 16,然后进入下一部分

用户名先通过 encode 函数进行加密,查看一下 encode

函数传入输入的用户名也就是 str,以及一个已知数组,通过 for 循环进行两次变换,最后变换后的结果与其原值一致,所以可以据此写出脚本爆破出用户名

#include <bits/stdc++.h>
using namespace std;
int num_list[] = {23, 22, 26, 26, 25, 25, 25, 26, 27, 28, 30, 30, 29, 30, 32, 32};
string user_name;
inline bool check(int a, int pos) {
  int num = ((a + num_list[pos]) % 61) * 2 - pos;
  if (num == a) return true;
  else return false;
}
int main() {
  for (int i = 0; i < 16; i++)
    for (int j = 0; j < 125; j++)
      if (check(j, i)) user_name += (char)j;
  cout << user_name << endl;
  return 0;
}

得到用户名为:LOHILMNMLKHILKHI

然后继续看获取密码的部分

对用户名每一位异或 34,取前 10 位存入 str,str 再与 '_' 以及 bArr 拼接,然后将 str 与用户输入的密码作比较,因此可以逆向出密码

#include <bits/stdc++.h>
using namespace std;
int Llist[] = {64, 48, 48, 49, 49};
int num_list[] = {23, 22, 26, 26, 25, 25, 25, 26, 27, 28, 30, 30, 29, 30, 32, 32};
int num[] = {0xF2, 0xE, 0x95, 0x5D, 0xDE, 0xA2, 0xCC, 0x86, 0xF4, 0xBB, 0x39, 0xC0, 2, 0x81, 0x94, 0xC5, 0x9C, 0x5E, 0xD5, 0xAE, 0x77, 0x43, 0xF1, 0x89};
string user_name, user_pass;
inline bool check(int a, int pos) {
  int num = ((a + num_list[pos]) % 61) * 2 - pos;
  if (num == a) return true;
  else return false;
}
int main() {
  for (int i = 0; i < 16; i++)
  	for (int j = 0; j < 125; j++)
  	  if (check(j, i)) user_name += (char)j;
  for (int i = 0; i < 16; i++) 
    user_name[i] = (char)((int)user_name[i] ^ 34);
  for (int i = 0; i < 10; i++) user_pass += user_name[i];
  user_pass += '_';
  for (int i = 0; i < 5; i++) user_pass += Llist[i];
  cout << user_pass;
  return 0;
}

得到密码为:nmjknoloni_@0011

接下来可以发现该活动通过 Intent 将密码传进了 o0 这个活动里面,o0 如下

o0 类把密码又传给了 b 类,查看 b

b 类调用了一个 f 类的 oho 方法,查看 f

oho 在 native 层,总之,它就是最终的加密⽅法。它将我们的密码,用户名以及在第三个界⾯输入的内容进行了加密并做比较,返回值 boolean 正确则输出 Congratulations...

反编译 apk,把 so 文件拖入 IDA,找到 oho

这个函数先对传入的参数的长度进行比较,得知 flag 的长度应当为 24

然后看循环部分,通过分析可以发现是将密码每次 2 位传给 src,用户名则是先倒置再每次 2 位接在 src 后面,然后再与用户第三个输入的内容拼接后传入 encode 进行最终的加密,查看 encode

看不懂呜呜呜,菜鸡落泪,找了出题师傅要的脚本,才勉强看懂了

#include <bits/stdc++.h>
using namespace std;
int main() {
  char key1[]={"nNjLnHlL"};
  int count=1;
  int key[7];//nNjLnHlL
  for (int i = 0; i < 6; ++i) {
    key[i] = key1[count];
    count++;
  }
  unsigned int ks[6]={0x5d950ef2,0x86cca2de,0xc039bbf4,0xc5948102,0xaed55e9c,0x89f14377};
  unsigned int k=0,bk=0;
  unsigned int p[4];
  for(int i=5;i>=0;i--)
	if(i>0) ks[i]^=ks[i-1];
  for(int i=0;i<24;i+=4){
	k=ks[i/4];
	k=(1<<key[i/4])^k;
	k=((k>>16)) | ((~(k<<16))&0xffff0000);  //这一句还有些疑问,求会的师傅讲讲QAQ,小的定感激不尽
	k=((k<<key[i/4])) | (k>>(32-key[i/4]));
	for(int j=0; j<4; j++) printf("%c", *((char*)&k+3-j));
  }
  return 0;
}

解出:WelCOme_To_mAkaBakA!BrO!,包裹上 GFCTF{} 得到 flag

GFCTF{WelCOme_To_mAkaBakA!BrO!}

此次比赛感悟:大抵是因为题目相对简单的缘故,最起码在做题的时候能略微有些思路了,然而也暴露出了许多问题,例如脚本屁也不会写。总而言之,这次比赛是一个令我这种啥也不会的萌新参与感很高的一次比赛,虽然做出来的题不多,但每个题都能有些思路并且做几步。虽说给自己的方向的定位是逆向,但是在比赛中还是杂项做的更多一些,说到底还是人太菜了,尤其是安卓逆向最后那个 native 层的加密,不看师傅的解题脚本根本就不知道在说什么,从今往后还是要多刷题,还差得远啊qwq

posted @ 2021-11-26 10:43  Moominn  阅读(1204)  评论(0编辑  收藏  举报