[WUSTCTF 2020](病假回归)

发布时间 2023-12-08 21:39:45作者: kelec0ka

[WUSTCTF 2020]level1

下载下来后有俩文件,先看level1

查壳,无壳64位,拖入IDA中

image

看到其中的i&1,为按位与运算,取2进制整数 i 的最低位,如果最低位是1 则得1,如果最低位是0 则得0。 奇数 i 的最低位 是1,偶数i 的最低位 是0。

再看到output文件,里面有

198,232,816,200,1536,300,6144,984,51200,570,92160,1200,565248,756,1474560,800,6291456,1782,65536000

那么就可以编写脚本了

flag = [0,198,232,816,200,1536,300,6144,984,51200,570,92160,1200,565248,756,1474560,800,6291456,1782,65536000]
for i in range(1,20):
    if(i & 1) != 0:
        flag[i] = flag[i] >> i
    else:
        flag[i] = flag[i] // i
print(''.join([chr(i)for(i)in(flag)]))

image

[WUSTCTF 2020]level2

根据题目叙述,有UPX壳,查壳看看,UPX壳32位

image

脱个壳玩玩,一定要注意文件位置的命名不能带有'[]'这个东西!

image

打开看看

image

[WUSTCTF 2020]level3

查壳,拖入IDA中

image
image

看到了加密后的码,再找找码表,shift12看看

但发现只有63个字母少了,前面应该还有A

因为它提示换表且有交叉引用的考点,所以点进base函数看看,交叉引用base64_table

image

看到了LookAtYou,跟进

image

是个换表题,编写脚本

#include<stdio.h>
#include<stdlib.h>
int main() {
    char v1;
    int i;
    int result;
    char base[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    for (i = 0; i <= 9; ++i)
    {
        v1 = base[i];
        base[i] = base[19 - i];
        result = 19 - i;
        base[result] = v1;
    }
    printf("%s", base);
    return 0;
}

image

放到赛博橱子里看看

image

[WUSTCTF 2020]level4

查壳,无壳64位

image

拖进IDA中

image

有init(),type1(),type2()这三个函数值得查看

init()

image

有个赋值操作,字符串为'I{_}Af2700ih_secTS2Et_wr'

type1()

image

type2()

image

下面两个是递归函数,但我不能更好地理解...

查看wp后发现要动态调试,也可以拖入kali中运行,因为这个文件是ELF文件

image

根据wp和运行可知,这是在考察二叉树的前、中、后序遍历

所以说init函数里的就是总的字符串,为'I{_}Af2700ih_secTS2Et_wr'

type1为中序,type2为后序,而中后序遍历的结果就为上图所示

至于如何判断的前中后序:
前序:根左右
中序:左根右
后序:左右根

所以脚本为(以后遇到二叉树可以套模)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
struct TreeNode 
{
    char val;
    struct TreeNode* left;//左子树
    struct TreeNode* right;//右子树
};
 
struct TreeNode* buildTree(char* inorder, int inStart, int inEnd, char* postorder, int postStart, int postEnd) 
{
    if (inStart > inEnd || postStart > postEnd) //如果大于最大长度就结束
    {
        return NULL;
    }
 
    struct TreeNode* root = (struct TreeNode*)malloc(sizeof(struct TreeNode));//创建一个动态结构体数组
    root->val = postorder[postEnd];//指向后序中的根字符
 
    int i;
    for (i = inStart; i <= inEnd; i++) //计算中序的左子树长度
    {
        if (inorder[i] == postorder[postEnd]) //如果中序的字符与后序最后一个字符相等就结束计算,也就是最终的根
        {
            break;
        }
    }
    //开始构建树
    root->left = buildTree(inorder, inStart, i - 1, postorder, postStart, postStart + i - inStart - 1);
    root->right = buildTree(inorder, i + 1, inEnd, postorder, postStart + i - inStart, postEnd - 1);
 
    return root;
}
 
void preOrder(struct TreeNode* root) 
{
    if (!root) 
    {
        return;
    }
 
    printf("%c", root->val);
    preOrder(root->left);
    preOrder(root->right);
}
 
int main()
{
    char inorderStr[] = "2f0t02T{hcsiI_SwA__r7Ee}";//已知中序
    char postorderStr[] = "20f0Th{2tsIS_icArE}e7__w";//已知后序
    int n = strlen(inorderStr);
 
    struct TreeNode* root = buildTree(inorderStr, 0, n - 1, postorderStr, 0, n - 1);
    printf("前序遍历结果为: ");
    preOrder(root);
 
    return 0;
}

image

此题还有一种解法,那就是画图

image

这个遍历顺序问题画图解决最直观,但要注意别找错了,要不烦死

当然,你也可以在线工具直接一波带走

image

[WUSTCTF 2020]Cr0ssfun

查壳,无壳64位

image

拖进IDA中查看

image

应该是check函数进行了加密,点进去看看,一路跟进

image
image
image
image
image
image
image

跟进完后,发现是明文flag,直接脚本操作

#include<stdio.h>
int main()
{
	char a1[33];
	a1[10] = 'p'; 
	a1[13] = '@';
	a1[3] = 'f';
	a1[26] = 'r'; 
	a1[20] = 'e';
	a1[7] = '0';
	a1[16] = '_'; 
	a1[11] = 'p'; 
	a1[23] = 'e';
	a1[30] = 'u';
	a1[0] = 'w';
	a1[6] = '2'; 
	a1[22] = 's';
	a1[31] = 'n';
	a1[12] = '_';
	a1[15] = 'd'; 
	a1[8] = '{';
	a1[18] = '3';
	a1[28] = '_'; 
	a1[21] = 'r';
	a1[2] = 't';
	a1[9] = 'c';
	a1[32] = '}';
	a1[19] = 'v';
	a1[5] = '0';
	a1[14] = 'n';
	a1[4] = '2'; 
	a1[17] = 'r'; 
	a1[29] = 'f'; 
	a1[17] = 'r'; 
	a1[24] = '_';
	a1[1] = 'c';
	a1[25] = '@';
	a1[27] = 'e';
	printf("%s", a1);
}

image

很烫