【记】2021年第四届浙江省大学生网络安全技能挑战赛

文章目录

  • 前言
  • 初赛
    • RE - crackPYC
  • 决赛
    • RE - preprocess
    • RE - 最简单的逆向
    • RE - RE人三项
  • 后记

前言

坐牢就完事儿了☠
 

初赛

感觉这次的初赛难度不低…

但好歹也辉煌了一下,
【记】2021年第四届浙江省大学生网络安全技能挑战赛_第1张图片

RE - crackPYC

看到题面写着字节码 Python3.7,我心里就咯噔一声,暗道大事不妙,因为这比赛是不能联网的,下面直接上题解,具体的字节码知识,补充在了我的 Python3 字节码详解 博文中了;

  1           0 LOAD_CONST               0 (<code object keyinit at 0x0000028C1CC11D20, file "crackPYC.py", line 1>)
              2 LOAD_CONST               1 ('keyinit')
              4 MAKE_FUNCTION            0
              6 STORE_NAME               0 (keyinit)

  8           8 LOAD_NAME                1 (__name__)
             10 LOAD_CONST               2 ('__main__')
             12 COMPARE_OP               2 (==)
             14 POP_JUMP_IF_FALSE      250

  9          16 LOAD_NAME                2 (print)
             18 LOAD_CONST               3 ('Can you crack pyc?')
             20 CALL_FUNCTION            1
             22 POP_TOP

 10          24 LOAD_NAME                3 (input)
             26 LOAD_CONST               4 ('Plz give me your flag:')
             28 CALL_FUNCTION            1
             30 STORE_NAME               4 (str)

 11          32 LOAD_CONST               5 (108)
             34 LOAD_CONST               6 (17)
             36 LOAD_CONST               7 (42)
             38 LOAD_CONST               8 (226)
             40 LOAD_CONST               9 (158)
             42 LOAD_CONST              10 (180)
             44 LOAD_CONST              11 (96)
             46 LOAD_CONST              12 (115)
             48 LOAD_CONST              13 (64)
             50 LOAD_CONST              14 (24)
             52 LOAD_CONST              15 (38)
             54 LOAD_CONST              16 (236)
             56 LOAD_CONST              17 (179)
             58 LOAD_CONST              18 (173)
             60 LOAD_CONST              19 (34)
             62 LOAD_CONST              20 (22)
             64 LOAD_CONST              21 (81)
             66 LOAD_CONST              22 (113)
             68 LOAD_CONST              15 (38)
             70 LOAD_CONST              23 (215)
             72 LOAD_CONST              24 (165)
             74 LOAD_CONST              25 (135)
             76 LOAD_CONST              26 (68)
             78 LOAD_CONST              27 (7)

 12          80 LOAD_CONST              28 (119)
             82 LOAD_CONST              29 (97)
             84 LOAD_CONST              30 (45)
             86 LOAD_CONST              31 (254)
             88 LOAD_CONST              32 (250)
             90 LOAD_CONST              33 (172)
             92 LOAD_CONST              34 (43)
             94 LOAD_CONST              35 (62)
             96 BUILD_LIST              32
             98 STORE_NAME               5 (text)

 13         100 LOAD_NAME                6 (len)
            102 LOAD_NAME                4 (str)
            104 CALL_FUNCTION            1
            106 LOAD_CONST              36 (32)
            108 COMPARE_OP               3 (!=)
            110 POP_JUMP_IF_TRUE       140
            112 LOAD_NAME                4 (str)
            114 LOAD_CONST              37 (0)
            116 LOAD_CONST              27 (7)
            118 BUILD_SLICE              2
            120 BINARY_SUBSCR
            122 LOAD_CONST              38 ('DASCTF{')
            124 COMPARE_OP               3 (!=)
            126 POP_JUMP_IF_TRUE       140
            128 LOAD_NAME                4 (str)
            130 LOAD_CONST              39 (31)
            132 BINARY_SUBSCR
            134 LOAD_CONST              40 ('}')
            136 COMPARE_OP               3 (!=)
            138 POP_JUMP_IF_FALSE      154

 14     >>  140 LOAD_NAME                2 (print)
            142 LOAD_CONST              41 ('Bye bye~~')
            144 CALL_FUNCTION            1
            146 POP_TOP

 15         148 LOAD_NAME                7 (exit)
            150 CALL_FUNCTION            0
            152 POP_TOP

 16     >>  154 LOAD_NAME                8 (list)
            156 LOAD_NAME                4 (str)
            158 CALL_FUNCTION            1
            160 STORE_NAME               9 (st)

 17         162 BUILD_LIST               0
            164 STORE_NAME              10 (key)

 18         166 LOAD_NAME                0 (keyinit)
            168 LOAD_NAME               10 (key)
            170 CALL_FUNCTION            1
            172 POP_TOP

 19         174 SETUP_LOOP              48 (to 224)
            176 LOAD_NAME               11 (range)
            178 LOAD_CONST              36 (32)
            180 CALL_FUNCTION            1
            182 GET_ITER
        >>  184 FOR_ITER                36 (to 222)
            186 STORE_NAME              12 (i)

 20         188 LOAD_NAME               13 (ord)
            190 LOAD_NAME                4 (str)
            192 LOAD_NAME               12 (i)
            194 BINARY_SUBSCR
            196 CALL_FUNCTION            1
            198 LOAD_NAME               10 (key)
            200 LOAD_NAME               12 (i)
            202 LOAD_NAME                6 (len)
            204 LOAD_NAME               10 (key)
            206 CALL_FUNCTION            1
            208 BINARY_MODULO
            210 BINARY_SUBSCR
            212 BINARY_XOR
            214 LOAD_NAME                9 (st)
            216 LOAD_NAME               12 (i)
            218 STORE_SUBSCR
            220 JUMP_ABSOLUTE          184
        >>  222 POP_BLOCK

 21     >>  224 LOAD_NAME                9 (st)
            226 LOAD_NAME                5 (text)
            228 COMPARE_OP               2 (==)
            230 POP_JUMP_IF_FALSE      242

 22         232 LOAD_NAME                2 (print)
            234 LOAD_CONST              42 ('Congratulations and you are good at PYC!')
            236 CALL_FUNCTION            1
            238 POP_TOP
            240 JUMP_FORWARD             8 (to 250)

 24     >>  242 LOAD_NAME                2 (print)
            244 LOAD_CONST              43 ('Sorry,plz learn more about pyc.')
            246 CALL_FUNCTION            1
            248 POP_TOP
        >>  250 LOAD_CONST              44 (None)
            252 RETURN_VALUE

Disassembly of <code object keyinit at 0x0000028C1CC11D20, file "crackPYC.py", line 1>:
  2           0 LOAD_CONST               1 (0)
              2 STORE_FAST               1 (num)

  3           4 SETUP_LOOP              42 (to 48)
              6 LOAD_GLOBAL              0 (range)
              8 LOAD_CONST               2 (8)
             10 CALL_FUNCTION            1
             12 GET_ITER
        >>   14 FOR_ITER                30 (to 46)
             16 STORE_FAST               2 (i)

  4          18 LOAD_FAST                1 (num)
             20 LOAD_CONST               3 (7508399208111569251)
             22 BINARY_SUBTRACT
             24 LOAD_CONST               4 (4294967295)
             26 BINARY_MODULO
             28 STORE_FAST               1 (num)

  5          30 LOAD_FAST                0 (key)
             32 LOAD_METHOD              1 (append)
             34 LOAD_FAST                1 (num)
             36 LOAD_CONST               5 (24)
             38 BINARY_RSHIFT
             40 CALL_METHOD              1
             42 POP_TOP
             44 JUMP_ABSOLUTE           14
        >>   46 POP_BLOCK
        >>   48 LOAD_CONST               0 (None)
             50 RETURN_VALUE

上边字节码的大致内容就是输入一串字符串 str,然后与 key 进行异或,最后与 text 中的内容逐个比较,其中 key 是通过函数 keyinit 生成,直接上 poc 脚本:

num = 0
key = []
text = [108,17,42,226,158,180,96,115,64,24,38,236,179,173,34,22,81,113,38,215,165,135,68,7,119,97,45,254,250,172,43,62]
flag = ''

for i in range(8):
    num = (num - 7508399208111569251) % 4294967295
    key.append((num >> 24))

for i in range(len(text)):
    flag += chr(text[i] ^ key[i % len(key)])

print(flag)

# DASCTF{0hH_My_9Uy!_vou_D_1T_0^0}

 

决赛

【记】2021年第四届浙江省大学生网络安全技能挑战赛_第2张图片

 

RE - preprocess

直接抄大佬的 WP:

原题应该来自于今年 GoogleCTF reverse 的 CPP,考点是 C++ 的宏定义:

clang-format --style='{IndentPPDirectives: AfterHash}' preprocess.c > loveCTF.c

宏定义处:

#define _COM(a0, a1, a2) (a0<<2 | a1<<1 | a2)
#define COM(a0, a1, a2, a3, a4, a5) (_COM(a3, a1, a5) << 3 | _COM(a0, a4, a2)) #define A COM(A7, A6, A5, A4, A3, A2)
#define B COM(A1, A0, B7, B6, B5, B4)
#define C COM(B3, B2, B1, B0, C7, C6)
#define D COM(C5, C4, C3, C2, C1, C0)
#define _CP(x, y) INPUT_ ## x ## _ ## y
#define CP(x, y) _CP(x, y) #define _LK(l0, l1, l2, l3, l4, l5, l6, l7) l0 ## l1 ## l2 ## l3 ## l4 ## l5 ## l6 ## l7
#define LK(l0, l1, l2, l3, l4, l5, l6, l7) _LK(l0, l1, l2, l3, l4, l5, l6, l7)
#define L LK(l0, l1, l2, l3, l4, l5, l6, l7)
#define SUM (S0 | S1 | S2 | S3) // 0
#define F (R0 | R1 | R2 | R3 | R4 | R5 | R6 | R7 | R8 | R9) // 0

这边的 10~17 其实是索引:

#ifdefl0
	#undefl0
#endif
#definel00
#ifdefl1
	#undefl1 
#endif
#definel10 
#ifdefl2
	#undefl2 
#endif
#definel20
#ifdefl3
	#undefl3
#endif
#definel30
#ifdefl4
	#undefl4
#endif
#definel40
#ifdefl5
	#undefl5
#endif
#definel50
#ifdefl6
	#undefl6
#endif
#definel60
#ifdefl7
	#undefl7
#endif
#definel70
#ifdefA0
	#undefA0
#endif

通过 CP(L, 0) 得到 INPUT_00000000_0 ,如果值为 1 则定义 A0 为 0 ,其实就是一个取反的过程,照此处理3个字节得到24位,再使用了 A,B,C,D 宏定义处理了二进制位即 4*6,简单位移之后与对应数异或;

数值归零算作成功,结尾使用 F 宏定义check,意味着10组24位二进制字串经处理后都为0;

#if F
	#error Failed to execute program
#else
	#warning Check completed #endif

先用脚本跑出异或表:

text = """
// Please fill in your flag below
// run `gcc preprocess.c -o preprocess.out`
// Have fun~
#define FLAG_0 CHAR_Z
#define FLAG_1 CHAR_J
#define FLAG_2 CHAR_C
#define FLAG_3 CHAR_T
……省略了太长了,就是源文件内容
"""
data = text.splitlines()
arrs = []
tm = 0
ts = []
for i, v in enumerate(data):
	index = data[i].find(" ^ ")
	if index != -1:
	ts.append(eval(data[i][index + 2:]))

	if data[i].startswith("#if D ^ "):
		arrs.append(ts.copy())
		ts = []

print(arrs)

使用 z3 进行条件约束,求解:

# -*- coding:utf-8 -*-
import z3

def com(a0, a1, a2, a3, a4, a5):
	return (a3 << 2 | a1 << 1 | a5) << 3 | (a0 << 2 | a4 << 1 | a2)

# 01011010 01001010 01000011
# 101001
# 010110

arr = [[13, 27, 50, 53], [7, 31, 38, 32], [14, 9, 35, 50], [38, 9, 51, 11], [36, 21, 19, 4], [46, 13, 35, 11], [38, 5, 54, 19], [38, 23, 2, 61], [46, 5, 22, 19], [22, 49, 39, 2]]

tflag = ""

for i in range(0, 30, 3):
	flag = [z3.BitVec("f" + str(i), 8) for i in range(3)]
	slo = z3.Solver()
	tmp = arr[i // 3]
	a7 = flag[0] >> 7 & 1
	a6 = flag[0] >> 6 & 1
	a5 = flag[0] >> 5 & 1
	a4 = flag[0] >> 4 & 1
	a3 = flag[0] >> 3 & 1
	a2 = flag[0] >> 2 & 1
	a1 = flag[0] >> 1 & 1
	a0 = flag[0] >> 0 & 1
	slo.add(com(a7 ^ 1, a6 ^ 1, a5 ^ 1, a4 ^ 1, a3 ^ 1, a2 ^ 1) ^ tmp[0] == 0)

	b7 = flag[1] >> 7 & 1
	b6 = flag[1] >> 6 & 1
	b5 = flag[1] >> 5 & 1
	b4 = flag[1] >> 4 & 1
	b3 = flag[1] >> 3 & 1
	b2 = flag[1] >> 2 & 1
	b1 = flag[1] >> 1 & 1
	b0 = flag[1] >> 0 & 1
	slo.add(com(a1 ^ 1, a0 ^ 1, b7 ^ 1, b6 ^ 1, b5 ^ 1, b4 ^ 1) ^ tmp[1] == 0)
	c7 = flag[2 ] >> 7 & 1
	c6 = flag[2 ] >> 6 & 1
	c5 = flag[2 ] >> 5 & 1
	c4 = flag[2] >> 4 & 1
	c3 = flag[2] >> 3 & 1
	c2 = flag[2] >> 2 & 1
	c1 = flag[2] >> 1 & 1
	c0 = flag[2] >> 0 & 1
	slo.add(com(b3 ^ 1, b2 ^ 1, b1 ^ 1, b0 ^ 1, c7 ^ 1, c6 ^ 1) ^ tmp[2] == 0)
	slo.add(com(c5 ^ 1, c4 ^ 1, c3 ^ 1, c2 ^ 1, c1 ^ 1, c0 ^ 1) ^ tmp[3] == 0)

	# slo.add(122 >= flag[0])
	# slo.add(122 >= flag[1])
	# slo.add(122 >= flag[2])

	assert slo.check() == z3.sat
	solov = slo.model()
	tflag += "".join([chr(solov.eval(flag[i]).as_long()) for i in range(3)]) 

print(tflag)

print(((0 << 2 | 0 << 1 | 1) << 3 | (1 << 2 | 0 << 1 | 1)))
com(1, 0, 1, 0, 0, 1)
# ((0 << 2 | 0 << 1 | 1) << 3 | (1 << 2 | 0 << 1 | 1))

 

RE - 最简单的逆向

真·最简单逆向

str = [118, 115, 133, 117, 134, 120, 173, 107, 151, 104, 
152, 103, 100, 100,  98, 151, 104, 152, 107, 107, 
150, 103,  98, 105, 149, 150, 101, 150, 106, 105, 
105, 101, 102, 151, 104, 152, 106, 149, 104, 175]
 
 
for i in str:
  print(chr(i-50),end="")

 

RE - RE人三项

三段加密,以 _ 分隔:

第一段是简单的字符 ASCII 变换;
第二段就是标准 sm4;
第三段是个迷宫;

# -*- coding:utf-8 -*-

import pysm4

flag1 = [i for i in "E0gy3"]
maps = "NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm"
for i, v in enumerate(flag1):
	if ord("A") <= ord(v) <= ord("Z"):
		flag1[i] = chr(maps.index(v) + 0x41)
	elif ord("a") <= ord(v) <= ord("z"):
		flag1[i] = chr(maps.index(v) + 0x47)
	else:pass
flag1 = "".join(flag1)

encdata = int.from_bytes(bytes.fromhex("F27352FB8DF41D6DC233B5A5EEC160DA"), 'big') 
key = 0x0123456789abcdeffedcba9876543210
flag2 = pysm4.decrypt(encdata, key)
flag2 = flag2.to_bytes(16, 'big')
print(flag2)

arrs = [
[0x0077DF9E, 0x0077DFB1, 0x0077DF84, 0x0077DF84, 0x0077E2D6, 0x0077DF84, 0x0077DFAD],
[0x0077DF84, 0x0077DFB2, 0x0077DF84, 0x0077DF84, 0x0077DF84, 0x0077DF98, 0x0077DF84],
[0x0077DF84, 0x0077DFBC, 0x0077DF84, 0x0077DF84, 0x0077E06A, 0x0077DF84, 0x0077DF84],
[0x0077DF84, 0x0077DFE4, 0x0077E017, 0x0077E066, 0x0077E069, 0x0077DF84, 0x0077DF84],
[0x0077E06B, 0x0077DF84, 0x0077DF84, 0x0077DF84, 0x0077E0D9, 0x0077DF84, 0x0077DF84],
[0x0077DF84, 0x0077DF84, 0x0077DFE8, 0x0077DF84, 0x0077E1B5, 0x0077E21A, 0x0077E291],
[0x0077DF84, 0x0077DF84, 0x0077DF84, 0x0077DF84, 0x0077DF84, 0x0077DF84, 0x0077E36C]
]
mik = arrs.copy()
for i, v in enumerate(arrs):
	for j, v2 in enumerate(v):
		if v2 <= 0x0077DF9E:
			mik[i][j] = 1
		else:
			mik[i][j] = 0
print(mik)
# [s, 0, 1, 1, 0, 1, 0],
# [1, 0, 1, 1, 1, 1, 1],
# [1, 0, 1, 1, 0, 1, 1],
# [1, 0, 0, 0, 0, 1, 1],
# [0, 1, 1, 1, 0, 1, 1],
# [1, 1, 0, 1, 0, 0, 0],
# [1, 1, 1, 1, 1, 1, e]

flag3 = ""
awsd = [1, 7, -1, -7]
adds = -127
for i in "dsssdddssdds":
	if i == "d":
		adds = awsd.index(1)
	elif i == 'a':
		adds = awsd.index(-1)
	elif i == 's':
		adds = awsd.index(7)
	elif i == "w":
		adds = awsd.index(-7)
	flag3 += chr(adds + ord('a'))
print(flag3)

print(flag1+flag2+flag3)
# ZJCTF{R0tl3_Sm34@and_abbbaaabbaab}

有一说一,首尾都解出来了,中间有思路,但不会操作,纯手爆,笑死;
 

后记

我的方便面没有调料包

二等奖

【记】2021年第四届浙江省大学生网络安全技能挑战赛_第3张图片

只能说很幸运,但也挺可惜的,跟上一个就差5分,就是手速慢了点,不然就是省一了;

【记】2021年第四届浙江省大学生网络安全技能挑战赛_第4张图片

不过我的重心还是在开发上,双修还是时间太少了,没法精通,又或者说关于安全的资源太少了,没有成型的体系,自己摸索太消耗时间了,到头来一事无成就得不偿失了,所以打 CTF 也就是图一乐吧;

衷心感谢我的队友 y3s woodwhale,么么哒!!!

你可能感兴趣的:(#,CTF,日记,比赛,CTF,逆向,安全,1024程序员节)