BCACTF 3.0

BCACTF 3.0

麻了,之前的没保存全没了…

这个比赛给的提示是真的多。难度不打,很适合我 😃。

MISC

Sequence

1
2
3
4
5
6
7
8
9
10
11
12
13
sequence = [0, 1, 3, 6, 2]
numbers = [774, 5842, 4294, 9433, 5232, 1871, 3292, 4213, 2752, 5521, 4581, 3829, 2812, 2244, 3312, 7059, 2959, 8297, 7497, 1272, 2288, 160, 594, 158, 4833, 7140, 5352, 142, 3018, 9468, 5625, 4848, 2051, 3008, 4298, 6250, 144]
validPass = "ABCFEDFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz123457890{}_"

def gensequence():
for i in range(10000):
# TODO write sequence generator for one of the most famous sequences and add it to sequence
pass

gensequence()

for i in numbers:
print(validPass[sequence[i]%len(validPass)], end="")

提示是著名的数列之一。google看了一下应该是雷卡曼数列,前面几项也能对的上。完成生成数列函数即可。

1
2
3
4
5
6
7
8
def gensequence():
for _ in range(10000):
if sequence[-1]-len(sequence) > 0 and sequence[-1]-len(sequence) not in sequence:
sequence.append(sequence[-1]-len(sequence))
else :
sequence.append(sequence[-1]+len(sequence))

# bcactf{Cr4cKInG_Th3_R3C4MaN_S3qu3NcE}

Blender Creation

下载下来是一张图片,二进制查看可以看到末尾有一段python代码。dump出来看看。

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
import bpy
from base64 import b64decode

bpy.ops.object.select_all(action="SELECT")
bpy.context.scene.cursor.location = (0, 0, 0)
bpy.ops.object.delete(use_global=False, confirm=False)
bpy.ops.object.camera_add(
enter_editmode=False,
align="VIEW",
location=(0, 0, 0),
rotation=(1.1169, 0.01420, 0.8269),
scale=(1, 1, 1),
)
bpy.ops.transform.translate(
value=(4.58569, -4.20269, 3.1699),
orient_type="GLOBAL",
orient_matrix=((1, 0, 0), (0, 1, 0), (0, 0, 1)),
)
bpy.ops.mesh.primitive_monkey_add(
size=2, enter_editmode=False, align="WORLD", location=(0, 0, 0), scale=(1, 1, 1)
)
u = "__"[1:] + 'x_N3r0f__'[2:-2][::-1]
yrsth = "b" + str(len(bpy.context.object.data.polygons[0].vertices) - 3) + str(len(bpy.context.object.data.polygons[2].vertices) - 1)+ "NdR__" + "Xp_R3"[1::-1] + chr(len(bpy.context.object.data.polygons[3].vertices) + int(42.5*2)) + "YtH0"[1:-1] + str(len(bpy.context.object.data.polygons[5].vertices) ** 0 - 1) + "N_4ND" + u
bpy.ops.object.light_add(
type="POINT", radius=1, align="WORLD", location=(0, -2.5, 0), scale=(1, 1, 1)
)
x = (
int(
0x0000000000000080
+ 0x0000000000000240
+ 0x0000000000000840
- 0x0000000000000AC0
)
- 2
)
bpy.context.object.data.energy = 50
bpy.context.object.data.color = (1, 1, 0.69420)

a = (
str(
b64decode(
(
chr(x - 0x000000000000001)
+ chr(x - 0x000000000000001 * 10 // 2 + 6 - 6 % 4)
+ ("wemR3YhNmY")
)[::-1]
)
)[:-1]
+ yrsth
+ "}"
)[2:]
bpy.data.curves.new(type="FONT", name="Font Curve").body = a
font_obj = bpy.data.objects.new(
name="Font Object", object_data=bpy.data.curves["Font Curve"]
)
bpy.context.scene.collection.objects.link(font_obj)
font_obj.location = (0, 0.8, 1.2)
font_obj.rotation_euler = (90, 0, 0)
font_obj.scale = (0.75, 0.75, 0.75)

中间的a就是我们的flag。

1
2
3
4
5
6
7
8
9
10
11
12
a = (
str(
b64decode(
(
chr(x - 0x000000000000001)
+ chr(x - 0x000000000000001 * 10 // 2 + 6 - 6 % 4)
+ ("wemR3YhNmY")
)[::-1]
)
)[:-1]
+ yrsth
+ "}"

x的值可以算,前面的base64也可以解。接出来就是bcactf{所以这里就是我们的flag。那么我们还需要得到yrsth这个部分。

1
2
3
4
5
6
7
8
9
u =  "__"[1:] + 'x_N3r0f__'[2:-2][::-1]
yrsth = "b" + str(
len(bpy.context.object.data.polygons[0].vertices) - 3) + str(len(bpy.context.object.data.polygons[2].vertices) - 1)+ "NdR__" +
"Xp_R3"[1::-1] +
chr(len(bpy.context.object.data.polygons[3].vertices) + int(42.5*2)) +
"YtH0"[1:-1] +
str(len(bpy.context.object.data.polygons[5].vertices) ** 0 - 1
) + "N_4ND" + u

u的的话相当于直接给出了。中间几段明文跑一下就能得到。可以的得到以下代码:

1
2
3
4
5
6
7
yrsth = "b" + str(
len(bpy.context.object.data.polygons[0].vertices) - 3) + str(len(bpy.context.object.data.polygons[2].vertices) - 1)+ "NdR__" +
"pX" +
chr(len(bpy.context.object.data.polygons[3].vertices) + int(42.5*2)) +
"tH" +
str(len(bpy.context.object.data.polygons[5].vertices) ** 0 - 1
) + "N_4ND" + "_f0r3N"

可以看到前面有一个blender这个单词。所以猜测缺少的一个是1一个是3。

后面有一个0次方,所以是0。

1
2
3
yrsth = "b" + str(
"1" + "3" + "NdR__" + "pX" + chr(len(bpy.context.object.data.polygons[3].vertices) + int(42.5*2)) +
"tH" + "0" ) + "N_4ND" + "_f0r3N"

你看看那个单词像不像python?后面加了85所以应该是Y。那么yrsth就是:

1
2
3
b13NdR__pXYtH0N_4ND_f0r3N

# bcacft{b13NdR__pXYtH0N_4ND_f0r3N}

Gogle Maze

是一个google文档。但是我们啥都做不了,点击下一个没用。

右键查看源代码。搜索bcactf。

找到flag。

1
# bcactf{f4rthER_th4n_m3eTS_th3_EY3_9928ef}

Crypto

New Keyboard

1
Cy ygpbo rgy ydco t.fxrape go.o yd. Ekrpat nafrgy! Cy p.annf m.oo.o gl mf mgojn. m.mrpfv Yd. unai co xjajyu?t3fx0ape{naf0g7{jdabi3gl{',.pyf+

提示说他用了一个少见的键盘格式。

猜测

1
unai co xjajyu?t3fx0ape{naf0g7{jdabi3gl{',.pyf+

是我们的flag。

找了一下应该是这个Dvorak键盘:

KB_United_States_Dvorak.png

因为unai的位置刚好就是我们正常键盘的flag。所以flag为:

1
2
3
4
xjajyu?t3fx0ape{naf0g7{jdabi3gl{',.pyf+
bcacft{k3yb0ard_lay0u7_chang3up_qwerty}

# bcacft{k3yb0ard_lay0u7_chang3up_qwerty}

Hidden Frequencies

文件是一串字符

1
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiijjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkllllllllllllllllllllllllllllllllllllllllllllllllllllmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnoooooooooooooooooooooooooooooooooooooooooooooooooooppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssstttttttttttttttttttttttttttttttttttttttttttttttttttuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333334444444444444444444444444444444444444444444444444444455555555555555555555555555555555555555555555555566666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777888888888888888888888888888888888888888888888888999999999999999999999999999999999999999999999999............................................................................................................???????????????????????????????????????????????????????????????????????????????????????????????!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#####################################################################################################$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

统计每个字符出现的次数,然后转ascii。

1
2
3
4
5
6
7
8
import string
with open(r"msg.txt", "r") as fp:
data = fp.read()
charset = string.ascii_lowercase + string.digits + ".?!<>@#$%^&"
for i in charset:
print(chr(data.count(i)), end="")

# bcactf{ch4r4ct3r_fr3qu3ncy_15_50_c00l_55aFejnb}

Really Secure Algorithm

1
2
3
4
c=2464250865277757821428965675155522992457560926961269981007162702551724392855202737838222228070453790200941338664587735699257288834514629714756168098513102225910176071493495606754285130938545761358963130345627434505300662209712223707092556796463691345274980307752267846533429807624844732139940872159965514596
p=13088210551361451568469688622513897981426518145215665452575421200429661351366918393846354939929997184772996442562042682789520346956154452065929764946443447
q=1590315075423589460616307119751698143804899237034239149886381441961338087331451452499790183510691573469327467020483209974248378007574390792001615535983477
e=65537

标准的rsa。

直接解就行了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import re
import libnum
import gmpy2

c=...
p=...
q=...
e=65537

d = int(gmpy2.invert(e, (p-1)*(q-1)))
m = pow(c,d,p*q)
print(re.sub("1?..", lambda x : chr(int(x.group())), str(m)))

# bcactf{w311_th15_15_aWkWard_Fbahu8d3}

这里输出的m就是我们的明文,只不过他不是16进制的,而是10进制的。提示里说他喜欢十进制我也是半天没理解。

如果你看m的十进制输出的话,可以看到开头是98999799这个其实就是ascii码了, b(98)c(99)a(97)c(99)。

Funky Factors

1
2
3
n=2451500972944572751067639135542724911455699735389455909239072706748572836232480252074031400797211301593443375562946962694274273077543664039604383719893091628336430360455909687693258270869995548362038438414271398400407702884883827901471304659858249570873108083356722001678236438255333957918061509916855914316124827985975637
e=65537
c=564821294757794643397264923024262896319938418162067361975239043464095797026401068770491393457675494733286339893448531140461611917094383999568438980881431718162518066997760793975381905628192846966986565357045880322008658585158406186349420366526027108151457442130148185466107727095596643126951328051023864119076639932491216

啥都没给,一般来说就是n可以直接分解。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
F:\CTFTools\yafu-1.34>yafu-x64.exe
factor(2451500972944572751067639135542724911455699735389455909239072706748572836232480252074031400797211301593443375562946962694274273077543664039604383719893091628336430360455909687693258270869995548362038438414271398400407702884883827901471304659858249570873108083356722001678236438255333957918061509916855914316124827985975637)


fac: factoring 2451500972944572751067639135542724911455699735389455909239072706748572836232480252074031400797211301593443375562946962694274273077543664039604383719893091628336430360455909687693258270869995548362038438414271398400407702884883827901471304659858249570873108083356722001678236438255333957918061509916855914316124827985975637
fac: using pretesting plan: normal
fac: no tune info: using qs/gnfs crossover of 95 digits
div: primes less than 10000
fmt: 1000000 iterations
rho: x^2 + 3, starting 1000 iterations on C322
rho: x^2 + 2, starting 1000 iterations on C322
rho: x^2 + 1, starting 1000 iterations on C322
pm1: starting B1 = 150K, B2 = gmp-ecm default on C322
Total factoring time = 4.2737 seconds


***factors found***

P14 = 25854458289211
P308 = 94819274320962195588391046032702062340347787753861707917333803643013756112498232723436129143357983211782575094016538160601055922810359418391115604418400747711916131212069247930840360588635198701990348690076607422776450913659984003956055504691820691172367804759436721489067099363705442358971393631085988763567

ans = 1

得到p,q。解rsa即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
import gmpy2
import re

p = ...
q = ...
e= 65537
c= ...

d = gmpy2.invert(e, q-1)
m = pow(c,d, q)
print(re.sub("1?..", lambda x : chr(int(x.group())), str(m)))

# bcactf{w0w_f4ct0r1ng_l3g3nd_hAUebf29}

Salty

看名字估计就是哈希了。

给的是个网站,里面的debug部分给出了一个hash和salt。题目描述是4位数字和小写字母。那么我们来爆破。

1
2
hash = "6877ac6025ecfc8d127bfb158afd4273"
salt = "NaCl-82eed"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import itertools
import string
from hashlib import md5

hash = "6877ac6025ecfc8d127bfb158afd4273"
salt = "NaCl-82eed"

char_set = [string.ascii_lowercase + string.digits for _ in range(4)]

for i in itertools.product(*char_set):
passwd = "".join(i) + salt

if md5(passwd.encode("utf-8")).hexdigest() == hash:
print("".join(i))
break

# bca4

之后使用admin登录。

1
# bcactf{1_10v3_5a1ty_h@5h_br0wn5_3749}

A Fine Line

1
2
3
4
5
6
7
I'm carefully drawing a fine line on this piece of paper, letting each portion guide the next... (Digits and letters are 0-9 and 10-35 in their usual orders, and the underscore is 36. {} are not encoded but should be added in afterwards. All letters are lowercase.)

Hint 1 of 2
This uses the affine cipher, as clued by the title and description, but with an added modification.

Hint 2 of 2
Each pair of letters decodes the next.

下载下来里面是一串字符,提示说是放射密码。然后码表也给我们了。提示二说两个字符解下一个字符。所以就可以得到解法了。

放射密码一共有三个参数,一个乘数一个加数和一个模数。模数实际上是码表的长度,所以是固定的。那么两个字符解下一个其实就是两个字符作为乘数和加数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import string
from Crypto.Util.number import *

c = list("(bc)bx6ez_unufi3bm0r0xeb".replace("(", "").replace(")", ""))
char_set = string.digits + string.ascii_lowercase + "_"

for i in range(len(c)-2) :
key = c[i:i+1]
mul = char_set.find(key[0])
add = char_set.find(key[0])
mul_ = inverse(mul, len(char_set))

c[i+2] = char_set[(mul_*(char_set.find(c[i+2]))) % len(char_set)]

print("".join(c))

# bc1c6wcfl4cdknw9030b01

嗯…好像不太对。

最后发现是我们对提示的理解错了,我以为是两个字符解下一个字符,实际上是两个字符解下两个字符…而且算法写的也有点问题,改一下。

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 string
from Crypto.Util.number import *

c = list("(bc)bx6ez_unufi3bm0r0xeb".replace("(", "").replace(")", ""))
char_set = string.digits + string.ascii_lowercase + "_"
c = [c[2*i:2*i+2] for i in range(len(c)//2)]

key = c[0]
res = ["bc"]

for i in c[1:] :
mul = char_set.index(key[0])
add = char_set.index(key[1])
mul_ = inverse(mul, len(char_set))

key = char_set[mul_*(char_set.index(i[0]) - add) % len(char_set)] + \
char_set[mul_ * (char_set.index(i[1]) - add) % len(char_set)]

res.append(key)

print("".join(res))

# bcactfg2b_npjs3p4d65k1
# bcactf{g2b_npjs3p4d65k1}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!