【CTF】2024.11&12

这学期摸鱼的时候把[PolarCTF]平台的RE easy题做完了,遂发上来
(除了一个附件不太对的题)

Week-1

[NSSCTF][SWPUCTF 2021 新生赛]re1

image

exeinfo看一眼,64位。
拖进IDA打开,F5反编译
image

把里面的ascii都换成字符(按R),再理一下大概逻辑:
image

至于str2是什么,可以看到最开始str2和{34sy_r3v3rs3}​进行了一次比较

逆向即:把{34sy_r3v3rs3}​中的3​换成e​,4​换成a

可得flag:NSSCTF{easy_reverse}

11.30

[ctfshow][逆向签到题]

直接IDA打开就能看见flag

[ctfshow][re2]

运行简单理解一下该程序:大概是用于加密文件的

IDA打开,shift+F12看看string,发现flag.txt。点进flag.txt,在ctrl+x看引用

image

找到主函数,F5(截图时,部分内容已被我重命名):重点是红框内的函数

image

sub_401069​:str xor 0x1F​ 后要 == "DH~mqqvqxB^||zll@Jq~jkwpmvez{"​ => 异或特性可知,str == "DH~mqqvqxB^||zll@Jq~jkwpmvez{" xor 0x1F

image

核心是sub_401028这个函数,跟进去看看(截图时,部分内容已被我重命名)

image

挨个看吧

  • sub_4010F0:用 key循环填充256位的数组
    image
    ​​
  • sub_4010C8s[i] = i
    image
    ​​
  • sub_4018E0:用k_box对s_box进行置换
    image
    ​​
  • sub_4015E0:rc4加密
    image

这么理下来就很清楚了!

sub_4014E0​:将flagFile​文件里的内容,用rc4加密后放入enflagFile​里,key是DH~mqqvqxB^||zll@Jq~jkwpmvez{​与 0x1F 异或的结果

image

那么解密则需要:

  1. getKey:DH~mqqvqxB^||zll@Jq~jkwpmvez{​与 0x1F 异或
  2. getFlag:key + enflag.txt =rc4=> flag.txt

/*
    401A70: str xor 1f == DH~mqqvqxB^||zll@Jq~jkwpmvez{
*/
#include<stdio.h>
int main() {
    char x[] = {"DH~mqqvqxB^||zll@Jq~jkwpmvez{"};

    for (int i = 0; i < 30; i++) {
        x[i] = x[i] ^ 0x1F;
        printf("%c", x[i]);
    }

    //output: [Warnning]Access_Unauthorized
    return 0;
}

rc4找在线解密即可:flag{RC4&->ENc0d3F1le}

image

12.2

[ctfshow][re3]

题目描述: 提交最小解即可,4位值

Die打开发现是64bit+linux

丢进IDA打开,shift+F12​看到字符串

image

Ctrl+x​跟进去,再F5​反编译

image

重命名+分析一下:

image

关键在于,我们通过阅读变量声明可以发现:因为输入时并未控制长度,因此我们可以对v19进行赋值

image

这个变换很复杂,但是都是固定数值没什么好分析的,因此我们直接转换成c语言,让电脑自己处理:

(我自己加了几个打印,方便查看)

#include<stdio.h>
int main() {
    int v15 = 0;
    unsigned __int64 v16 = 0LL;
    int v17[7] = { 80, 64227, 226312059, -1540056586, 20496, 3833, 0 };     // 看看没赋值的情况

    for (int i = 0; i <= 6; ++i) {
        for (v16 += (unsigned int)v17[i]; v16 > 0xFFFF; v16 = v15 + (unsigned int)(unsigned __int16)v16) {
            v15 = v16 >> 16;
        }
        printf("v16=%xn", v16);
        printf("i=%dn", i);
    }

    printf("need = %xn",0xFFFF - v16);

    if (v16 == 0xFFFF)
        puts("OK");
    else
        puts("Error");

    return 0;
}

image

因为最后效验需要v16 == 0xFFFF​,而v16+=v17[6] == 0xFFFF​时不会进入超级复杂的内层for​循环

所以我这里敢直接写0xFFFF - v16

v17[6]​赋值为0x1a9f​确认一下:

image

12.16

[PolarCTF][ezpack]

image

发现是Aspack壳,用工具脱壳:

image

32位:用IDA打开。直接shift+f12发现关键字符“Enter password:”

image

直接跟进函数看看:

image

关键函数:sub_401738​。继续跟进去看看:

  • 大概逻辑就是:input​逐个和0xC​进行异或,然后和Str2​进行比较
  • 所以input = Str2 ^ 0xC

image

查看一下Str2 = >4i44oo4?i=n>:m;8m4=oo4i;>?4>h9m

image
image

编写解密脚本:

#include<stdio.h>

int main() {
    char str[] = ">4i44oo4?i=n>:m;8m4=oo4i;>?4>h9m";
    for (int i = 0; i < 32; i++) {
        str[i] ^= 0xC;
    }
    printf("%s", str);
    return 0;
}
// 28e88cc83e1b26a74a81cc8e72382d5a

[PolarCTF][L00k_at_h3r3]

image

查壳发现是NsPack,用工具脱壳:

image

32位,用IDA打开。直接搜索函数,找到main​函数:

image

很长,但实际上很简单,步骤大概是:

  • 和几个数组逐个进行比较,且异或不同的数
  • 例如第一个for​循环,input[i]​和 aNqt[i] ^ 0xBu​的结果进行比较
  • 第二个for​循环,input[i+len(aNqt)]​和 aKixs[i] ^ 0xCu​的结果进行比较
  • ...

image

  • aNqt = nqT
  • aKixs = kixS
  • aKa9jr = ka9jR
  • aHCq = h|>cQ
  • aG = g<}<

编写解密脚本:

#include<stdio.h>

int main() {
    char str1[] = "nqT";
    char str2[] = "kixS";
    char str3[] = "ka9jR";
    char str4[] = "h|>cQ";
    char str5[] = "g<}<";

    for (int i = 0; i < sizeof(str1)-1; i++) {
        str1[i] ^= 0xBu;
    }
    printf("%s", str1);
    for (int i = 0; i < sizeof(str2) - 1; i++) {
        str2[i] ^= 0xCu;
    }
    printf("%s", str2);
    for (int i = 0; i < sizeof(str3) - 1; i++) {
        str3[i] ^= 0xDu;
    }
    printf("%s", str3);
    for (int i = 0; i < sizeof(str4) - 1; i++) {
        str4[i] ^= 0xEu;
    }
    printf("%s", str4);
    for (int i = 0; i < sizeof(str5) - 1; i++) {
        str5[i] ^= 0xFu;
    }
    printf("%s", str5);

    return 0;
}
//ez_get_fl4g_fr0m_h3r3
// 需要md5 32位小写加密后再提交

[ctfshow][re4]

DIE查看,发现是64位的

image

IDA64打开

12.18

[PolarCTF][shell]

查壳发现是upx

image

工具脱壳:upx -d [FilePath]

image
image

32位,IDA打开,shitf+F12​发现关键字符串。跟进去看看

image

F5反编译直接看到!

image

[PolarCTF][PE结构]

image

不是PE文件?根据题目,大概可以猜到,是想让我们修复PE结构。

winhex打开看看

image

上来就发现不是MZ!notepad++修改一下(别问为什么不是winhex,notepad用起来顺手一点QAQ)

image

再打开,发现OK了。

image

直接运行试试:

image

[PolarCTF][拼接]

image

32位,直接用IDA打开,发现脸上就是main函数,手直接就挪F5上了啊!

image

嗯······这拼接在,嗯。哈哈。

[PolarCTF][加加减减]

image

32位,IDA打开。main函数又在脸上,直接F5:

image

看眼逻辑:input​每位都--​,然后与str2​进行比较。

所以str2​每位都++​,就是flag

int main() {
    char str2[] = "ekfz5123086/ce7ac7/4a816/87bb28a5|";

    for (int i = 0; i < strlen(str2); i++) {
        str2[i]++;
    }
    printf("%s", str2);

    return 0;
}

image

[PolarCTF][HowTo_Login]

image

upx壳,工具脱掉:

image

32位,因为是注册机,所以先运行看看:

image
image

OK,上IDA,搜索字符串看看:

image

跟进去发现关键:

image

pawd会被打印,所以可以x64嗯调到打印的地方?

哦不行,试了一下发现,只会打印输入的东西,还是得自己对照QAQ

复制下来试试:

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

int main() {
    char v11[20];
    v11[0] = 'C';
    v11[15] = 'X';
    v11[1] = 'Z';
    v11[14] = 'A';
    v11[2] = '9';
    v11[13] = 'b';
    v11[3] = 'd';
    v11[12] = '7';
    v11[4] = 'm';
    v11[11] = 'G';
    v11[5] = 'q';
    v11[10] = '9';
    v11[6] = '4';
    v11[9] = 'g';
    v11[7] = 'c';
    v11[8] = '8';
    v11[16] = '�';

    if (strlen(v11) == 0x10) {printf("%s", v11);}
    return 0;
}
// CZ9dmq4c8g9G7bAX

image

运行检验一下:

image

哦对,邮箱要有@​,且@​后面有字符,有.​,且.​后面要有字符。反正写规范一点,直接123会被拦截

tip:最终密码要进行32位md5加密哦

丢到网页里32位小写md5一下即可:flag{c3ec13a01b07ad218dbd5f4bbab592b9}

12.19

[PolarCTF][box]

image

64位ELF。进kali看看:

image

程序入口是key2。IDA,启动!

image

跟进去发现,key2=str1​,str1 = that_ok = key2

image
image

接着找谁调用了key2()​,找到main​函数:

image

image
image

直接复制下来,运行一下发现:key1 = 11694441

key3 = NNSXS===

image

拼起来:flag{11694441that_okNNSXS===}

啊?不对。

草,key3需要base32解密,结果为:key

所以:flag{11694441that_okkey}​,再进行md5,32位小写加密即可

[PolarCTF][crc]

image

64位ELF,进kali看看:发现没有任何输出,直接等你输入。

好吧,那IDA启动!

image

简单分析一下strmncpy​函数:

image

简单分析一下magic​函数:

image

查找发现,python的binascii库和zlib库有crc32

因为flag的前4位包是flag,所以可以试试:flag​加密后是否和0xd1f4eb9a​相等,看看python库里的crc32的实现是否和这题的实现一致。

image

OK!可以开始爆破了

import binascii

for i in range(128):
    str2 = chr(i)
    crc2 = binascii.crc32(str2.encode())
    if crc2 == 0x15d54739:
        print("str2 = ", str2)

    if crc2 == 0xfcb6e20c:
        print("str6 = ", str2)

    for j in range(128):
        str4 = chr(i)+chr(j)
        if binascii.crc32(str4.encode()) == 0x3fcbd242:
            print("str4 = ", str4)

        for k in range(128):
            for l in range(128):
                str1 = chr(i)+chr(j)+chr(k)+chr(l)
                crc1 = binascii.crc32(str1.encode())
                if crc1 == 0xd1f4eb9a:
                    print("str1 = ",str1)

                if crc1 == 0x540bbb08:
                    print("str3 = ", str1)

                if crc1 == 0x2479c623:
                    print("str5 = ", str1)

print("end")

image

拼起来:flag{ezrebyzhsh}

[PolarCTF][EasyCPP2]

image

64位ELF。直接运行发现:没有任何输出,直接等你输入。

IDA启动:

image

看了眼flag = qisngksofhuivvmg

再看眼encode()​:+=3​再^=1u

image

所以对flag = qisngksofhuivvmg​进行encode()​就是我们的input

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

int main() {
    char flag[] = "qisngksofhuivvmg";

    for (int i = 0; i <= 15; i++) {
        flag[i] += 3;
        flag[i] ^= 0x1u;
    }

    printf("%s", flag);

    return 0;
}
//umwpkowshjymxxqk

[PolarCTF][一个flag劈三瓣儿]

image

64位ELF,直接运行:flag{HaiZI233N145wuD!le112@666}

image

啊?真这么简单wow!

[PolarCTF][C^]

image

64位ELF,直接运行:关键字符串“Please enter flag”

image

IDA启动!

image

fun1()​:a1[i] ^= 1u

image

check()​用于判断a1​是否和s​相等:s = shfiu777

image

所以flag = shfiu777 ^ 1u

#include<stdio.h>

int main() {
    char flag[] = "shfiu777";
    for (int i = 0; i <8; i++) {
        flag[i] ^= 0x1u;
    }
    printf("%s", flag);

    return 0;
}
//right666

再md5,32位小写加密即可

[PolarCTF][babyRE]

image

64位exe。运行以后发现,随便输入会输出“Err"

image

看眼endoce()​:对flag​的每位+2

image

那flag是啥嘞:shift+f12​里有一串诡异字符。可以试试

image

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

int main() {
    char flag[] = "asdfgcvbnmjgtlop";
    for (int i = 0; i <strlen(flag); i++) {
        flag[i] +=2;
    }
    printf("%s", flag);

    return 0;
}
//cufhiexdpolivnqr

[PolarCTF][easyre1]

image

64位ELF。运行发现:会输出”no no no"

image

IDA启动!

image

挨个看吧。

enkey()​:循环32次,134520896 + 96 = 134520992

image

看看这俩内容都是啥:

134520896: key = 5055045045055045055045055045055

image

134520992: flag​的位置

image

所以enkey()​就是让flag​和key​按位异或。

reduce()​:循环31次,flag​每位都-1

image

check()​:对比flag​和d^XSAozQPU^WOBU[VQOATZSE@AZZVOF

image

反过来就是:

  • d^XSAozQPU^WOBU[VQOATZSE@AZZVOF​每位都+1
  • 然后和key​按位异或
#include<stdio.h>
#include<string>

int main() {
    char flag[] = "d^XSAozQPU^WOBU[VQOATZSE@AZZVOF";
    char key[] = "5055045045055045055045055045055";
    for (int i = 0; i <strlen(flag); i++) {
        flag[i]++;
        flag[i] ^= key[i];
    }
    printf("%s", flag);

    return 0;
}
//PolarDNbecomesbiggerandstronger

[PolarCTF][Sign Up]

image

64位exe。直接运行发现关键字符串。

image

IDA启动!

image

image

非常eazy啊,key_num[i]-1 = name; key_password[i]-2 = password

key_num = 192168109; key_password = root

image

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

int main() {
    char key_num[] = "192168109";
    char key_password[] = "root";
    for (int i = 0; i <strlen(key_num); i++) {
        key_num[i]--;
    }
    for (int i = 0; i < strlen(key_password); i++) {
        key_password[i] -= 2;
    }
    printf("name = %sn", key_num);
    printf("password = %sn", key_password);

    return 0;
}
//name = 0810570/8
//password = pmmr
//0810570/8pmmr

检验一下:

image

拼接起来md5即可。

等等,不对?

原来是眼睛不好使,没注意人家只替换了7个数

image

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

int main() {
    char key_num[] = "192168109";
    char key_password[] = "root";
    for (int i = 0; i <=6; i++) {
        key_num[i]--;
    }
    for (int i = 0; i <=3; i++) {
        key_password[i] -= 2;
    }
    printf("name = %sn", key_num);
    printf("password = %sn", key_password);

    return 0;
}
//name = 081057009
//password = pmmr

这下对了!

[PolarCTF][?64]

image

64位可执行。

image

这,我猜是base64,直接在线解密试试:

image

赢!但是还是看看程序

image

image

遗憾!并不是base64的加密程序QAQ。收工

[PolarCTF][Why32]

image

64位exe

image
image

image
image

这几个函数连起来的意思就是:input.len == 32

继续看Do()​函数:input = cAry[i]-2; cAry = "2gfe8c8c4cde574f7:c6c;:;3;7;2gf:"

image

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

int main() {
    char key_num[] = "2gfe8c8c4cde574f7:c6c;:;3;7;2gf:";
    for (int i = 0; i <=31; i++) {
        key_num[i]-=2;
    }
    printf("%sn", key_num);
    return 0;
}
//0edc6a6a2abc352d58a4a98919590ed8

这个half right是什么意思呢?

不管了先直接包裹上flag提交试试,比较这个看起来很像md5加密之后的值。

豪德,不对。

解密试试呢?

image

F1laig​。这下对了!

12.20

[PolarCTF][康师傅]

image

32位exe。IDA直接跟进main​函数

image

input[i] ^= 9u == str1[i]

太简单了哇!直接str1[i] ^= 9u​就是flag了

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

int main() {
    char flag[] = "oehnr8>?;<?:9k>09;hj00o>:<o?8lh;8h9l;t";
    for (int i = 0; i < strlen(flag); i++) {
        flag[i] ^= 9u;
    }
    printf("%sn", flag);
    return 0;
}
//flag{17625630b7902ac99f735f61ea21a0e2}

[PolarCTF][re2]

image

64位ELF,IDA直接启动。

image

12.21

[NewStar CTF 2024][base64]

image

64位exe。IDA启动!

image

g84Gg6m2ATtVeYqUZ9xRnaBpBvOVZYtj+Tc=

关键函数是sub_1400014E0​,跟进去看看:

image

发现是BASE64的变形。只有索引表变了。

新的索引表在aWhydo3sthis7ab​里,具体是:WHydo3sThiS7ABLElO0k5trange+CZfVIGRvup81NKQbjmPzU4MDc9Y6q2XwFxJ/

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

#define LOSU_BASE64_CODE_TABLE "WHydo3sThiS7ABLElO0k5trange+CZfVIGRvup81NKQbjmPzU4MDc9Y6q2XwFxJ/"   //只有索引表改变,因此修改这里就行
#define LOSU_BASE64_CODE_PADDING (uint8_t)'='

int _decode(uint8_t x)
{
    /*
        该函数用于从编码表(LOSU_BASE64_CODE_TABLE)中查找对应字符的序号
        在Base64Decode函数中,这大概率是性能制约部分
        如需优化,可考虑使用二叉查找树进行优化
    */
    for (int i = 0; i < strlen(LOSU_BASE64_CODE_TABLE); i++)
        if (LOSU_BASE64_CODE_TABLE[i] == (char)x)
            return i;
    return -1;
}

uint8_t* Base64Decode(uint8_t* content, int length)
{
    //创建缓冲区
    int buffersize = (length / 4) * 3;
    uint8_t* buffer = (uint8_t*)malloc(buffersize + sizeof(char));
    memset(buffer, 0, buffersize + sizeof(char));

    //计算填充字符个数
    int left = 0;
    if (content[length - 1] == LOSU_BASE64_CODE_PADDING){
        left++;
    } else if (content[length - 2] == LOSU_BASE64_CODE_PADDING) {
        left++;
    }

    //解码
    int i, j, i_max;
    i_max = (left == 0 ? length : length - 4);

    for (i = j = 0; i < i_max; i += 4, j += 3)
    {
        buffer[j] = ((_decode(content[i]) & 0x3f) << 2) + ((_decode(content[i + 1]) & 0x30) >> 4);  //第一个byte的后6bit和第二个byte的第3到第4bit
        buffer[j + 1] = ((_decode(content[i + 1]) & 0xf) << 4) + ((_decode(content[i + 2]) & 0x3c) >> 2); //第二个byte的第5到第8bit和第三个byte的第3到第6bit
        buffer[j + 2] = ((_decode(content[i + 2]) & 0x3) << 6) + ((_decode(content[i + 3]) & 0x3f));       //第三个byte的第7到第8个bit和第四个byte的第3到第8bit
    }

    //处理填充的区块
    switch (left)
    {
    case 0:
    {
        *((char*)&buffer[j]) = '�';
        break;
    }
    case 1:
    {
        buffer[j] = ((_decode(content[i]) & 0x3f) << 2) + ((_decode(content[i + 1]) & 0x30) >> 4);  //第一个byte的后6bit和第二个byte的第3到第4bit
        buffer[j + 1] = ((_decode(content[i + 1]) & 0xf) << 4) + ((_decode(content[i + 2]) & 0x3c) >> 2); //第二个byte的第5到第8bit和第三个byte的第3到第6bit
        *((char*)&buffer[j + 2]) = '�';
        break;
    }
    case 2:
    {
        buffer[j] = ((_decode(content[i]) & 0x3f) << 2) + ((_decode(content[i + 1]) & 0x30) >> 4);  //第一个byte的后6bit和第二个byte的第3到第4bit
        buffer[j + 1] = ((_decode(content[i + 1]) & 0xf) << 4); //第二个byte的第5到第8bit
        break;
    }
    }

    return buffer;
}

int main() {
    char cipher[] = "g84Gg6m2ATtVeYqUZ9xRnaBpBvOVZYtj+Tc=";
    char* plain = (char*)Base64Decode((uint8_t*)cipher, strlen(cipher));
    printf("%s",plain);

    return 0;
}
// flag{y0u_kn0w_base64_well}

[PolarCTF][layout]

image

下载下来发现是apk。安装到雷电模拟器里看看。

image

疑似没做竖屏适配。调设置重启一下,发现还是乱码。

OK!上手段——jadx打开,直接搜索flag{

image

不对?!

好吧。回到雷电模拟器,用开发者助手提取:

image

这下对了

[PolarCTF][use_jadx_open_it]

这个名字——我听话,用 jadx 直接打开,然后搜索字符串:

image

结束

【未完成】[PolarCTF][另辟蹊径]

image

32位exe。但是注意:Section​是乱码。丢进虚拟机里运行发现果然运行不了。

拽进ida里发现会创建一个新文件,感觉不对。

然后搜了一下writeup,好像这个文件有问题。暂停解题

12.22

[PolarCTF][JunkCode]

image

32位可执行文件。IDA没看出名堂,进x64dbg试试。

根据题目名,猜测有很多无用代码,所以直接搜索字符串找到关键代码部分

image

简单分析(内容写注释里了):

image

分析认为junkcode.1F1258​是判断函数:

  • 调用该函数后,有个jump,一个会输出funny(疑似成功?),一个会输出"no"。
  • 运行测试时,发现输错 flag 就会输出"no"

image

下断点准备跟进去看,结果发现eax里就是flag~

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇