GDOUCTF 2023 CTF Writeup

警告
本文最后更新于 2023-04-20,文中内容可能已过时。

rank: 27

misc完整wp

以及取证题不适用取证软件的手工做法

MISC

pixelart

提取像素点

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
from PIL import Image


im = Image.open('arcaea.png')
# print(im.height)
img_new = Image.new('RGB',(320,180))

for i in range(0,im.width,12):
    for j in range(0,im.height,12):

        rgb = im.getpixel((i,j))
        img_new.putpixel((i//12,j//12),rgb)

# img_new.show()
img_new.save('fake_flag.png')

fake_flag

然后在lsb隐写里

image-20230417083848924

Matryoshka

压缩包套娃,不过密码要解算式

最麻烦的地方是从左向右计算,

然后两个坑是十进制不能以0开头和答案是负数要去掉符号

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import os
# 去掉十进制数字开头的0
def not_start_zero(tmp):
    while True:
        if tmp.startswith("0"):
            tmp = tmp[1:]
        else:
            break
    return tmp
# 从左到右计算算式
def Calculate(calc:str)->str:
    tmp = ""
    f = []
    for index,i in enumerate(calc):
        if i.isdigit():
            tmp += i
        if i.isdigit()==False:
            f.append(not_start_zero(tmp))
            f.append(i)
            tmp = ""
        if index == (len(calc)-1):
            
            f.append(not_start_zero(tmp))

    result = int("".join(f[:1]))
    for i in range(1,len(f),2):
        result = eval(str(result)+"".join(f[i:i+2]))

    return str(result)
# 循环解压缩
while True:
    zip_name = "".join([i for i in os.listdir() if i.endswith('.zip')])
    if zip_name == "":
        break
    print(zip_name)
    

    pwdtxt="".join([i for i in os.listdir() if i.endswith('txt')])
    passwd =open(pwdtxt,'r').read()
    passwd=passwd.replace('zero','0').replace('one','1').replace('two','2').replace('three','3').replace('four','4').replace('five','5').replace('six','6').replace('seven','7').replace('eight','8').replace('nine','9')
    passwd = passwd.replace('plus','+').replace('times','*').replace('mod','%').replace('minus','-')
    print(passwd)
    # 答案中如果有符号 也要去掉
    cal_passwd = Calculate(passwd).replace('-','')
    print(cal_passwd)
    # zipfile模块太慢了 
    os.system(f'unzip -P {cal_passwd} {zip_name}')

    os.remove(zip_name)
    os.remove(pwdtxt)

zipfile太慢了,这里用的unzip命令解压

getnopwd

明文攻击,攻击流量包

1
bkcrack -C getnopwd.zip -c final.pcapng  -x 8 4D3C2B1A01000000FFFFFFFFFFFFFFFF

解压得到一个流量包,另一个文件是doc

在document.xml中可以看到

image-20230417084850207

流量包根据品牌可以知道是数位板流量

image-20230417084914236

用knm提取USB流量

然后处理流量,Z为0的时候为没有下笔

参考B神脚本

https://byxs20.github.io/posts/43085.html#4-getnopwd

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import binascii
import matplotlib.pyplot as plt


with open("./out.data", "r") as f:
    data = f.read().splitlines()

def big_to_small(data):
    return binascii.hexlify(binascii.unhexlify(data)[::-1]).decode()

x_lis, y_lis = [], []
for line in data:
    x,y,z = int((big_to_small(line[4:8])),16),-int((big_to_small(line[8:12])),16),int((big_to_small(line[12:16])),16)

    if z == 0:
        continue
    
    x_lis.append(x)
    y_lis.append(y)


plt.scatter(x_lis, y_lis)
plt.show()

image-20230417091219935

t3stify

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import scipy.io.wavfile as wav
import numpy as np 
import matplotlib.pyplot as plt

sample_rate, data = wav.read('flagg.wav')

left = data[:, 0::2] 
right = data[:, 1::2]

diff = np.abs(left - right)

plt.plot(diff)
plt.show()

左右声道差分

image-20230417101619718

中间明显有不同,放大细看可以看出摩斯

image-20230417101542770

1
.- .-. -.-. .- . .- .---- ..-. .---- . ...-- ...--
1
ARCAEA1F1E33

是deepsound的密码

解得flag

Ez Forensics

数据库版本+字符集格式+最长列名 示例:NSSCTF{v0.0.1+GBK+1}

diskgenius挂载,可以找到1,2,4三个zip,还有个看着是exe实际上是zip的MySQL.exe

image-20230417102458510

3.zip就在里面

image-20230417102607822

1234ZIP里面三个文件刚好是数据表的数据

image-20230417112711664

file命令可以发现分别的frm MYD MYI文件

50726对应MySQL 5.7.26版本

新建一个数据库导入

image-20230417112805244

image-20230417112825624

这个数据库不是UTF8的,但是表数据是utf8的默认,所以字符集格式是UTF8

image-20230417112854424

image-20230417112956374

image-20230417113010100

image-20230417113018688

image-20230417113024507

比较发现 最长的列名是表2的listen

1
NSSCTF{v5.7.26+UTF-8+listen}

image-20230417111556150

crypto

Absolute_Baby_Encrytpion

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
let messagetoEncrypt = prompt("Enter a string: ").toLowerCase();
let charArray = messagetoEncrypt.split("");
let encryptedString = "";
let hasInvalidCharacter = false;

for (let i = 0; i < charArray.length; i++) {
    switch (charArray[i]) {
        case '!':
            encryptedString = encryptedString.concat('a')
            break;
        case '1':
            encryptedString = encryptedString.concat('b')
            break;
        case ')':
            encryptedString = encryptedString.concat('c')
            break;
        case 'v':
            encryptedString = encryptedString.concat('d')
            break;
        case 'm':
            encryptedString = encryptedString.concat('e')
            break;
        case '+':
            encryptedString = encryptedString.concat('f')
            break;
        case 'q':
            encryptedString = encryptedString.concat('g')
            break;
        case '0':
            encryptedString = encryptedString.concat('h')
            break;
        case 'c':
            encryptedString = encryptedString.concat('i')
            break;
        case ']':
            encryptedString = encryptedString.concat('j')
            break;
        case '(':
            encryptedString = encryptedString.concat('k')
            break;
        case '}':
            encryptedString = encryptedString.concat('l')
            break;
        case '[':
            encryptedString = encryptedString.concat('m')
            break;
        case '8':
            encryptedString = encryptedString.concat('n')
            break;
        case '5':
            encryptedString = encryptedString.concat('o')
            break;
        case '$':
            encryptedString = encryptedString.concat('p')
            break;
        case '*':
            encryptedString = encryptedString.concat('q')
            break;
        case 'i':
            encryptedString = encryptedString.concat('r')
            break;
        case '>':
            encryptedString = encryptedString.concat('s')
            break;
        case '#':
            encryptedString = encryptedString.concat('t')
            break;
        case '<':
            encryptedString = encryptedString.concat('u')
            break;
        case '?':
            encryptedString = encryptedString.concat('v')
            break;
        case 'o':
            encryptedString = encryptedString.concat('w')
            break;
        case '^':
            encryptedString = encryptedString.concat('x')
            break;
        case '-':
            encryptedString = encryptedString.concat('y')
            break;
        case '_':
            encryptedString = encryptedString.concat('z')
            break;
        case 'h':
            encryptedString = encryptedString.concat('0')
            break;
        case 'w':
            encryptedString = encryptedString.concat('1')
            break;
        case 'e':
            encryptedString = encryptedString.concat('2')
            break;
        case '9':
            encryptedString = encryptedString.concat('3')
            break;
        case 'g':
            encryptedString = encryptedString.concat('4')
            break;
        case 'z':
            encryptedString = encryptedString.concat('5')
            break;
        case 'd':
            encryptedString = encryptedString.concat('6')
            break;
        case '~':
            encryptedString = encryptedString.concat('7')
            break;
        case '=':
            encryptedString = encryptedString.concat('8')
            break;
        case 'x':
            encryptedString = encryptedString.concat('9')
            break;
        case 'j':
            encryptedString = encryptedString.concat('!')
            break;
        case ':':
            encryptedString = encryptedString.concat('@')
            break;
        case '4':
            encryptedString = encryptedString.concat('#')
            break;
        case 'b':
            encryptedString = encryptedString.concat('$')
            break;
        case '`':
            encryptedString = encryptedString.concat('~')
            break;
        case 'l':
            encryptedString = encryptedString.concat('^')
            break;
        case '3':
            encryptedString = encryptedString.concat('&')
            break;
        case 't':
            encryptedString = encryptedString.concat('*')
            break;
        case '6':
            encryptedString = encryptedString.concat('(')
            break;
        case 's':
            encryptedString = encryptedString.concat(')')
            break;
        case 'n':
            encryptedString = encryptedString.concat('_')
            break;
        case ';':
            encryptedString = encryptedString.concat('+')
            break;

        case '\'':
            encryptedString = encryptedString.concat('-')
            break;
        case 'r':
            encryptedString = encryptedString.concat('=')
            break;
        case 'k':
            encryptedString = encryptedString.concat('`')
            break;
        case 'p':
            encryptedString = encryptedString.concat('~')
            break;
        case '\"':
            encryptedString = encryptedString.concat('{')
            break;
        case '&':
            encryptedString = encryptedString.concat('}')
            break;
        case '/':
            encryptedString = encryptedString.concat('[')
            break;
        case '\\':
            encryptedString = encryptedString.concat(']')
            break;
        case '2':
            encryptedString = encryptedString.concat('|')
            break;
        case '.':
            encryptedString = encryptedString.concat(':;')
            break;
        case '%':
            encryptedString = encryptedString.concat(';')
            break;
        case '|':
            encryptedString = encryptedString.concat('\"')
            break;
        case ',':
            encryptedString = encryptedString.concat('\'')
            break;
        case '@':
            encryptedString = encryptedString.concat('<')
            break;
        case '{':
            encryptedString = encryptedString.concat('>')
            break;
        case 'u':
            encryptedString = encryptedString.concat(',')
            break;
        case '7':
            encryptedString = encryptedString.concat('.')
            break;
        case 'y':
            encryptedString = encryptedString.concat('?')
            break;
        case 'a':
            encryptedString = encryptedString.concat('/')
            break;

        default:
            hasInvalidCharacter = true;
    }
}

if (hasInvalidCharacter) {
    encryptedString = "Invalid String!";
} else {
    console.log(`Your encoded string is ${encryptedString}`);
}

image-20230417092108350

babylua

这段代码实现了一个简单的加密算法。它的工作流程如下:

  1. 它首先生成一个4位的随机种子seed,然后使用md5算法计算key = md5(md5(seed))。它打印key的前10位,在例子中是b5e62abe84。

  2. 它将要加密的字符串flag转换为字符的ASCII码,存储在secret数组中。

  3. 它将key中的每个字符的ASCII码和flag中的对应字符的ASCII码相加,得到加密后的ASCII码,存储回secret数组。

  4. 它将secret数组中的值打印出来,这些值就是加密后的字符串。

所以为了解密,我们需要:

  1. 拿到key的前10位,在例子中是b5e62abe84。

  2. 拿到加密后的字符串,在例子中是200 161 198 157 173 169 199 150 105 163 193 175 173 194 135 131 135 225。

  3. 对每个值减去key中的对应字符的ASCII码,就可以得到flag的ASCII码。

  4. 将ASCII码转换回字符,拼接起来就是flag。

这是ai答的

有一点不对,就是key需要通过爆破还原完整的key

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from hashlib import md5 
import itertools
import string

def md5_(string):
    return md5(string.encode()).hexdigest()

for i in itertools.product(string.ascii_letters,repeat=4):
    seed = "%s%s%s%s"%i
    # print(key)
    if "b5e62abe84" in md5_(md5_(seed)):
        print(seed)
        key=md5_(md5_(seed))
        print(key)
        break


encrypted = [200, 161, 198, 157, 173, 169, 199, 150, 105, 163, 193, 175, 173, 194, 135, 131, 135, 225]

flag = ''
for i in range(len(encrypted)):
    ascii_code = encrypted[i] - ord(key[i])
    flag += chr(ascii_code)

print(flag)
# flag{He11o_Lua!!!}

Magic of Encoding

数据清洗

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import base64
import zipfile
confuse_flags = ["flag{Xd_fake_flag_xD}", "find_me_if_you_can", "flag{not_the_correct_flag_lol}","\nflag{not_the_correct_flag_lol}\nflag{not_the_correct_flag_lol}\n"]
base64_lis = [base64.b64encode(i.encode()).decode() for i in confuse_flags]

data = open("Magic_Of_Encoding.txt", "r").read()

for i in base64_lis:
    data = data.replace(i, "")

print(data)

with open("flag.zip", "wb") as f:
    f.write(base64.b64decode(data))


# zipfile.ZipFile

zip_load = zipfile.ZipFile('flag.zip')
zip_load.extractall()
zip_load.close()
print(open('Magic of Encoding.txt').read())

# flag{h0p3_y0u_lik3d_the_M4gic_7rick}

Math Problem

已知ecc的a,b和基点的y轴

椭圆曲线的p就是rsa的p

所以求出p的值就可以解出flag

用sage在有理数环上带入椭圆曲线的函数表达式$x^3+a*x+b-y^2$求解x

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
from Crypto.Util.number import *
from sage.all import *

e = 65537
n = 79239019133008902130006198964639844798771408211660544649405418249108104979283858140199725213927656792578582828912684320882248828512464244641351915288069266378046829511827542801945752252863425605946379775869602719406340271702260307900825314967696531175183205977973427572862807386846990514994510850414958255877
c = 45457869965165575324534408050513326739799864850578881475341543330291990558135968254698676312246850389922318827771380881195754151389802803398367341521544667542828862543407738361578535730524976113729406101764290984943061582342991118766322793847422471903811686775249409300301726906738475446634950949059180072008
a = 9303981927028382051386918702900550228062240363697933771286553052631411452412621158116514735706670764224584958899184294505751247393129887316131576567242619
b = 9007779281398842447745292673398186664639261529076471011805234554666556577498532370235883716552696783469143334088312327338274844469338982242193952226631913
y = 970090448249525757357772770885678889252473675418473052487452323704761315577270362842929142427322075233537587085124672615901229826477368779145818623466854

R.<x> = PolynomialRing(Zmod(n))
f = x^3+a*x+b-y^2
ans = f.monic().small_roots(X=2^64, beta=0.4, epsilon=0.02)

p = gcd(n, ZZ(f(ans[0])))
q = n//p
d = inverse(e, (p-1)*(q-1))
m = pow(c, d, n)
print(long_to_bytes(int(m)).decode())

# flag{c4edd6d0-d1b3-cbda-95e3-a323edc35be5}

epsilon取0.02算的比较快

0%