2025 KCTF 2025-08-25 17:59 上海
本题只有3支战队成功提交flag
2025 KCTF 于8月15日中午12点正式开赛!比赛设置了多维度的评分体系,包括难度值、火力值和精致度积分。今天中午12点,第五题《智破幻阵》已截止答题。
*注意:签到题《废柴少年觉醒》持续开放,整个比赛期间均可提交答案获得积分
本题只有3支战队成功提交flag,看来难度不小呀~他们分别是:【tacesrever】、【1023】、【雨落星沉】
KCTF评委团队点评:
本题通过 mov 完备性与异常分发机制 实现复杂混淆,结合 IOCP 模拟虚拟机指令执行,考察选手对内存数据流、异常处理及自定义指令逆向的理解。算法设计简洁却颇具趣味,解题思路在分析数据变换关系后逐步清晰,兼具学习与挑战价值。
一起来看看本题的设计思路和解题思路吧~
一、
设计思路
出题者:n00bzx
来自【newbiezx 战队】
公开用户名:59A35804E4F4C235
公开序列号:7FF3675E036335E65E5D29D121FC149197556E6EA39F2E1A1A05437A9609EBC2
答案用户名:KCTF
答案序列号:AC1999741568E0A6B7CA93FD53FD900AE8EB599B8AE49E0797E91B106BE5DA53
题目名:FZREU考试系统登录器
错误提示:
正确提示:(在我的机器上运行1~2s即可输出结果)
混淆设计思路
由于网上常见的mov混淆会使用4字节加法表,导致程序文件空间过大。所以我做了优化,使用2字节加法表,配合进位实现mov加法,类似的方法用于其他表,大大减少了表数据的体积,进而减少了程序大小。但是代码较为复杂,内联同样会文件大小巨大,所以与传统mov混淆的内联运算符不同,所以我使用了”调用码”方式执行。就是输入一个fs或gs段的地址,跳转到对应运算符的mov指令实现.如:
事先安装好veh,由于该地址的访问必定会产生异常,所以可以根据异常发生地址读取指令操作数头部的调用码(图中为0x12),进入分发器,分发到指定运算符的mov指令实现去执行。
分发器分为主分发器,api分发器和调用分发器,主分发器中实现了5个调用,这几个调用的调用码(图中为0x3)紧跟着magic(0x66)。如图:
00:一般调用分发器
01:winapi分发器
02:绝对跳转
03:虚拟栈push
04:虚拟栈pop
一般调用分发器:准备一个表,分发器查表跳转。
winapi分发器:将iat地址提取,写入表,查表跳转。
虚拟栈push:将需要push的内容写入虚拟栈操作寄存器,然后移动栈指针写入栈顶。
虚拟栈pop:pop对应内容到虚拟栈操作寄存器。
调用号码表(从0开始enum):
虚拟栈主要用于mov代码中寄存器的保存和一些绝对跳转。
跳转分为两种,一种为调用分发器中的跳转调用,使用跳转表中的跳转偏移id进行跳转,另一种在虚拟栈上,根据压栈的绝对地址跳转。条件跳转为第一种,mov函数调用的调用和返回为第二种。
不是所有的栈操作都在虚拟栈上,未被混淆函数和api的返回地址在原栈上,因为要响应未混淆的ret指令。
设置的虚拟寄存器如下:
reg0-reg16 通用寄存器
reg17,reg18 参数寄存器
reg19,reg20 返回值寄存器
21,22,23,24 OF,SF,ZF,CF (标志寄存器)
reg25-reg60 通用寄存器
reg61 虚拟栈顶寄存器
reg62 虚拟栈操作寄存器
reg63 循环计数器
为了省时间(技术差),标志寄存器没有全部实现,仅仅实现了常见的那4个。通用寄存器用于mov调用,参数寄存器用于传递参数到mov调用,返回地址寄存器用于暂存mov调用的返回值。
reg25-reg60用处繁多,用于选择器和一些寄存器的备份(比如当虚拟寄存器被用来存储程序基址的时候,需要先备份被使用的虚拟寄存器)。
使用简单的几条中间指令,再由中间指令转化为mov指令,中间指令如下:
中间指令的使用详见mov_il.code,到mov指令的转换详见Stockholm.h/.cpp,mov代码详见程序文件。
混淆是以函数为单位的,所以有部分函数没混淆(由于我水平太低,多线程支持没搞,带锁的函数没混淆,以后会慢慢搞),还有部分(其实是一大堆)指令没支持的,以及一些可优化的,残余的设定部分,以后再慢慢搞。
题目设计思路(源码见原帖附件):
使(lan)用了win的iocp模型,取其vm特性,以控制码为opcode
输入用户名和序列号,序列号长度为64.转成数值后,分成8个dword
使用PostQueuedCompletionStatus发送完成数据包连接opcode,使用GetQueuedCompletionStatus阻塞接收opcode,根据每个opcode,对包中id对应的dword进行一次opcode对应的加密操作。
opcode 2333为按钮单击事件,opcode 6666为结束,0,1,2,3都为计算指令,每个指令均满足交换律并且可逆。
将用户名进行sha256 hash,将结果每2 bit转化为128位opcode,应用于8个dword。
最后,如果八个dword的结果均为0则正确,其他为错误,8个dword均可乱序执行。
输入64个大写hex字符,验证输入合法并转换分割后,将id乱序,起到迷惑性。混淆了线程函数(单线程,无锁)和sha256的几个函数.
题目概览:
ida打开,定位到start
打开入口点,动态获取api,设置veh,分配内存。
winapi实现的窗口创建
iocp初始化
线程函数反编译失败
函数stub,目的是从未被混淆的函数调用一个被混淆的函数。
所谓混淆大概看过去是这样的。
解题参考过程:
首先安装了veh,然后发现程序一直发生异常,看到iocp后,应该要去找线程函数,找到线程函数后,按c识别代码,会发现全是mov指令。
这种模式出现得很多,往6088和6090写入的东西,然后触发异常。
第一次触发异常之前会传入一个地址,这个地址为第二次异常发生地址的后一条,跟进第一次异常,动态调试,会发现第二次异常后会跳回到该地址。
同时会发现回到该地址之后,总会从6098取东西,动态调试可发现为返回结果。
多次黑盒即可猜测该异常为运算符调用,6088,6090为参数,6098为返回,根据返回结果,判断该调用为用于替换运算符的mov代码,并得出对应运算符。
往下翻,发现一类形式不同的异常,动调跟进发现为api函数。
发现初始化了iocp,从窗体函数还能发现发送了0x91d完成请求,又调用了获取请求的函数,推断题目使用了iocp做了一些操作。
然后在GetQueuedCompletionStatus上下断点,返回后在返回位置下断点,拦截接收到的完成请求包。
找到输入内容,发现宽字节转单字节,再由16进制字符串被转成字节数据。
在其上面下写入断点,每次改变的时候都会进入调用。
离开调用后,观察每次调用的结果。
在发送完成请求的函数(PostQueuedCompletionStatus)上下断点。
会发现只有4个handler.(4个opcode,为完成请求发送参数)
向上翻代码,并浏览内存即可获得栈中的opcode数据。根据每一个mov调用的含义和opcode推出每一个handler的含义。
写出每一个handler,模拟虚拟机代码(具体见keygen源码),进一步逆向后,发现6666 opcode的handler,会判断加密结果并输出正误判断信息多次。
输入给出的序列号和结果,发送6666号opcode后,在接收处下断。
通过动调获得接收到的结果:
接收随意输入的序列号产生的结果。可得出结论,正确的加密结果为全0(每个dword均为0).写出模拟虚拟机算法,从0倒推即可得出正确序列号,具体脚本见keygen。
附件里有原版的抽风报告,其实这就是一个简单的指令替换,指令结构和去年一样都没混淆,也没有表达式混淆,也没有反调试(有异常了,就没加)。本来就是尽量为了趣味(感谢公司老大教我的,ctf题不是越难越好,而是要有趣味性),展示下mov混淆的思路,所以算法很简单。出题时初步估计5解左右,明年会加上一些奇奇怪怪的混淆。
混淆源码请到原帖下载:https://bbs.kanxue.com/thread-287463.htm
二、
赛题解析
该解析由论坛会员ID:【HHHso】提供
该题定义四种变换,通过对用户名进行sha256,对256位hash值每两位构成变换选择子,构成一组128个变换选择子构成的变换序列,对32位0开始逆变换得到用户密码,用户密码正变换得到32位0则正确。题目利用mov的完备性和异常分发机制对原控制流进行混淆,但这里我们不考虑混淆代码控制流和相关数据流,直接分析内存数据变换情况着手。
Step 1
一眼32字节长password,测试是否几种常见的hash,如下图,不是直接hash结果,也可以考虑多迭代几次试试。
un='59A35804E4F4C235'
pw='7FF3675E036335E65E5D29D121FC149197556E6EA39F2E1A1A05437A9609EBC2'
import hashlib
for n in dir(hashlib):
if n.startswith(('md5','sha')):
try:
hf = getattr(hashlib,n)
hv = hf(un.encode()).hexdigest().upper()
print(f"{n.ljust(8)} {len(hv)//2} {hv}")
except Exception as er:
pass
Step 2
但在登录成功后,我们检索内存,可以看到有疑似有sha256(user_name)的存在,如下图:
Step 3
xdbg64中,在GetWindowTextW下断点,输入登录断下,在dump中追踪获取username或password的初步存放内存及其附近,如下图:
Step 4
在内存变化分析中,我们得到几个关键内存位置,8字(32字节)每字计算结果中间存放位置,字序位置、变换选择子位置、变换次序位置;
这些位置的值,也可以在输入username和password点击登录后进行观察:
Step 5
在计算结果存放位置设置硬件写断点,通过计算结果的变换,得到变换关系,如下是结果值变换情况样例:
x0=t0(xi) #00
E6356303 19CA9CFC F8339539
5E67F37F A1980C80 01433019
D1295D5E 2ED6A2A1 425DAD45
9114FC21 6EEB03DE BCDDD607
6E6E5597 9191AA68 D1232354
1A2E9FA3 E5D1605C B9CBA2C0
7A43051A 85BCFAE5 CB0B79F5
C2EB0996 3D14F669 D27A29EC
x1=t0(x0) #01
F8339539 07CC6AC6 8C0F98D5
01433019 FEBCCFE6 CDFD799F
425DAD45 BDA252BA 757B44A5
BCDDD607 432229F8 F0864453
D1232354 2EDCDCAB 565DB9B9
B9CBA2C0 46345D3F 7E8C68BA
CB0B79F5 34F4860A 1469E90C
D27A29EC 2D85D613 265B0BAC
x2=t2(x1) #02
8C0F98D5 AC607CC6 3C6D8CCB
CDFD799F FE6FEBCC 6E621BC1
757B44A5 2BABDA25 BBA62A28
F0864453 9F843222 0F89C22F
565DB9B9 CAB2EDCD 5ABF1DC0
7E8C68BA D3F46345 43F99348
1469E90C 60A34F48 F0AEBF45
265B0BAC 6132D85D F13F2850
x3=t1(x2) #03
3C6D8CCB 86C03675 06CEB0D8 F9314F27
6E621BC1 D4CFA17F F42FFA99 0BD00566
BBA62A28 010B9096 7212C021 8DED3FDE
0F89C22F B5247891 8F1236A4 70EDC95B
5ABF1DC0 E012A77E 54EFDC02 AB1023FD
43F99348 F95429F6 853EDF2A 7AC120D5
F0AEBF45 4A0305FB 60BF6940 9F4096BF
F13F2850 4B9292EE 525DC972 ADA2368D
x4=t1(x3) #04
F9314F27 439CF599 9EB32873 614CD78C
0BD00566 B17DBFD8 B7FB162F 4804E9D0
8DED3FDE 37408560 10AC06E8 EF53F917
70EDC95B CA4073E5 0E7CB948 F18346B7
AB1023FD 11BD9943 B3286237 4CD79DC8
7AC120D5 C06C9A6B 934D780D 6CB287F2
9F4096BF 25ED2C01 A58024BD 5A7FDB42
ADA2368D 170F8C33 F18662E1 0E799D1E
x5=t1(x4) #05
614CD78C DBE16D32 2DA65B7C D259A483
4804E9D0 F2A9536E 2A6DDE55 D59221AA
EF53F917 55FE43A9 C8752ABF 378AD540
F18346B7 4B2EFC09 DF812965 207ED69A
4CD79DC8 F67A2776 44EEDECF BB112130
6CB287F2 D61F3D4C E7A99AC3 1856653C
5A7FDB42 E0D261FC 4C3F9C1A B3C063E5
0E799D1E B4D427A0 84F4169A 7B0BE965
x6=t0(x5) #06
D259A483 2DA65B7C F85B4CB6
D59221AA 2A6DDE55 AA54DBBC
378AD540 C8752ABF 7F90EA55
207ED69A DF812965 CBBF0252
BB112130 44EEDECF 9E89DDBD
1856653C E7A99AC3 87CF5335
B3C063E5 4C3F9C1A 34987F38
7B0BE965 84F4169A 3509E82D
x7=t3(x6) #07
F85B4CB6 1:C2DA65B7 2:16D32DBE
AA54DBBC 1:52A6DDE5
7F90EA55 1:FC8752AB 2:E43A955F 3:21D4AAFF
CBBF0252 1:5DF81296 2:EFC094B2 3:7E04A597 4:F0252CBB
9E89DDBD 1:F44EEDEC 2:A2776F67 3:13BB7B3D 4:9DDBD9E8 5:EEDECF44
87CF5335 1:3E7A99AC 2:F3D4CD61 3:9EA66B0F 4:F533587C 5:A99AC3E7 6:4CD61F3D
34987F38 1:A4C3F9C1 2:261FCE0D 3:30FE7069 4:87F38349 5:3F9C1A4C 6:FCE0D261 7:E706930F
3509E82D 1:A84F4169 2:427A0B4D 3:13D05A6A 4:9E82D350 5:F4169A84 6:A0B4D427 7:05A6A13D 8:2D3509E8
x8=t3(x7) #08
16D32DBE 1:B6996DF0 2:B4CB6F85
52A6DDE5 1:9536EF2A
21D4AAFF 1:0EA557F9 2:752ABFC8 3:A955FE43
F0252CBB 1:812965DF 2:094B2EFC 3:4A5977E0 4:52CBBF02
EEDECF44 1:76F67A27 2:B7B3D13B 3:BD9E89DD 4:ECF44EED 5:67A2776F
4CD61F3D 1:66B0F9EA 2:3587CF53 3:AC3E7A99 4:61F3D4CD 5:0F9EA66B 6:7CF53358
E706930F 1:3834987F 2:C1A4C3F9 3:0D261FCE 4:6930FE70 5:4987F383 6:4C3F9C1A 7:61FCE0D2
2D3509E8 1:69A84F41 2:4D427A0B 3:6A13D05A 4:509E82D3 5:84F4169A 6:27A0B4D4 7:3D05A6A1 8:E82D3509
x9=t3(x8) #09
B4CB6F85 1:A65B7C2D 2:32DBE16D
9536EF2A 1:A9B77954
A955FE43 1:4AAFF21D 2:557F90EA 3:ABFC8752
52CBBF02 1:965DF812 2:B2EFC094 3:977E04A5 4:BBF0252C
67A2776F 1:3D13BB7B 2:E89DDBD9 3:44EEDECF 4:2776F67A 5:3BB7B3D1
7CF53358 1:E7A99AC3 2:3D4CD61F 3:EA66B0F9 4:533587CF 5:99AC3E7A 6:CD61F3D4
61FCE0D2 1:0FE70693 2:7F383498 3:F9C1A4C3 4:CE0D261F 5:706930FE 6:834987F3 7:1A4C3F9C
E82D3509 1:4169A84F 2:0B4D427A 3:5A6A13D0 4:D3509E82 5:9A84F416 6:D427A0B4 7:A13D05A6 8:09E82D35
x10=t2(x9) #0A
32DBE16D 6996DF0B F99B2F06
A9B77954 A54DBBCA 35404BC7
ABFC8752 955FE43A 05521437
BBF0252C 65DF8129 F5D27124
3BB7B3D1 89DDBD9E 19D04D93
CD61F3D4 A66B0F9E 3666FF93
1A4C3F9C E0D261FC 70DF91F1
09E82D35 A84F4169 3842B164
Step 6
通过分析,我们得到四种变换,及其逆变换,python复现如下,其中rorx_w和one_count用于发现计算结果之间的计算关系,如果a和b通过one_count得到其中为1的位数相同,则考虑用rorx_w发现是否循环移动及移动位数;如果和位32,则优先考虑取反等。
import struct
from ctypes import *
def rorx_w(w):
for i in range(0x20):
print(f'{i:2} {ror32(w,i):08X}')
def one_count(s):
if isinstance(s,int):
return bin(s).count('1')
return bin(int(bytes.fromhex(s)[::-1].hex(),0x10)).count('1')
def notw(w):
return c_ulong(~c_ulong(w).value).value
def rorw(w,s):
s=s%32
return ((w>>s)|(w<<(32-s)))&0xFFFFFFFF
def rorwc(w,s,c):
for i in range(c):
w=rorw(w,s)
return w
def pws(ws,file=sys.stdout):
wstr = ",".join([f"{w:08X}" for w in ws])
print(f"{wstr}",file=file)
def dt0(xws,file=sys.stdout):
yws = [ror32(notw(w),7) for w in xws]
pws(yws,file)
return yws
def et0(xws,file=sys.stdout):
yws = [notw(ror32(w,32-7)) for w in xws]
pws(yws,file)
return yws
def dt1(xws,file=sys.stdout):
yws = [notw(ror32(w^0xbaadbabe,19)) for w in xws]
pws(yws,file)
return yws
def et1(xws,file=sys.stdout):
yws = [c_ulong(0xbaadbabe^ror32(notw(w),32-19)).value for w in xws]
pws(yws,file)
return yws
def dt2(xws,file=sys.stdout):
yws = [c_ulong(0x900df00d^ror32(w,5)).value for w in xws]
pws(yws,file)
return yws
def et2(xws,file=sys.stdout):
yws = [ror32(0x900df00d^w,32-5) for w in xws]
pws(yws,file)
return yws
def dt3(xws,file=sys.stdout):
sc=[2,1,3,4,5,6,7,8]
yws = [rorwc(w,29,c) for w,c in zip(xws,sc)]
pws(yws,file)
return yws
def et3(xws,file=sys.stdout):
sc=[2,1,3,4,5,6,7,8]
yws = [rorwc(w,32-29,c) for w,c in zip(xws,sc)]
pws(yws,file)
return yws
dts=[dt0,dt1,dt2,dt3]
ets=[et0,et1,et2,et3]
def loadfbs(file):
with open(file,'rb') as fin:
return fin.read()
def load_trs(file):
fbs = loadfbs(file)
trs = list(struct.unpack('128L',fbs))
return trs
Step 7
实测中,我们发现128次(0x80)的变换序列就在内存中,如下图,
可通过savedata "D:\ctf05\trs.bin",0x68CFBA0,0x200 命令保存
通过加载变换序列,我们可以观察password验证计算过程,如下:
trs1=load_trs(r'D:\ctf05\trs.bin')
rp='7FF3675E036335E65E5D29D121FC149197556E6EA39F2E1A1A05437A9609EBC2'
rws=list(struct.unpack('8L',bytes.fromhex(rp)))
xi = [rws[1],rws[0]]+rws[2:]
x = xi
for i,t in enumerate(trs1):
print(f"{i:02X}: ",end='')
x = dts[t](x)
00: F8339539,01433019,425DAD45,BCDDD607,D1232354,B9CBA2C0,CB0B79F5,D27A29EC
01: 8C0F98D5,CDFD799F,757B44A5,F0864453,565DB9B9,7E8C68BA,1469E90C,265B0BAC
02: 3C6D8CCB,6E621BC1,BBA62A28,0F89C22F,5ABF1DC0,43F99348,F0AEBF45,F13F2850
03: F9314F27,0BD00566,8DED3FDE,70EDC95B,AB1023FD,7AC120D5,9F4096BF,ADA2368D
04: 614CD78C,4804E9D0,EF53F917,F18346B7,4CD79DC8,6CB287F2,5A7FDB42,0E799D1E
05: D259A483,D59221AA,378AD540,207ED69A,BB112130,1856653C,B3C063E5,7B0BE965
...
7B: 8AA48A82,55245414,51549150,0A2A922A,41455245,A828AA48,15051549,22A0A2A9
7C: A922A0A2,A922A0A2,A922A0A2,A922A0A2,A922A0A2,A922A0A2,A922A0A2,A922A0A2
7D: BAADBABE,BAADBABE,BAADBABE,BAADBABE,BAADBABE,BAADBABE,BAADBABE,BAADBABE
7E: FFFFFFFF,FFFFFFFF,FFFFFFFF,FFFFFFFF,FFFFFFFF,FFFFFFFF,FFFFFFFF,FFFFFFFF
7F: 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000
逆变换过来就可以得到password:
yi = [0]*8
y = yi
for i,t in enumerate(trs1[::-1]):
print(f"{i:02X}: ",end='')
y = ets[t](y)
yws = [y[1],y[0]]+y[2:]
yp=struct.pack('8L',*yws).hex().upper()
print(f"password: {yp}")
00: FFFFFFFF,FFFFFFFF,FFFFFFFF,FFFFFFFF,FFFFFFFF,FFFFFFFF,FFFFFFFF,FFFFFFFF
01: BAADBABE,BAADBABE,BAADBABE,BAADBABE,BAADBABE,BAADBABE,BAADBABE,BAADBABE
02: A922A0A2,A922A0A2,A922A0A2,A922A0A2,A922A0A2,A922A0A2,A922A0A2,A922A0A2
03: 8AA48A82,55245414,51549150,0A2A922A,41455245,A828AA48,15051549,22A0A2A9
04: ADBABEBA,6DD5F5D5,55B757D7,EAB6EAFA,5D56DD5F,EBAADBAB,7D755B75,AFAEAB6E
05: 22A0A2A9,15051549,24541455,A48A828A,54915051,2A922A0A,45524541,28AA48A8
...
7B: F9314F27,0BD00566,8DED3FDE,70EDC95B,AB1023FD,7AC120D5,9F4096BF,ADA2368D
7C: 3C6D8CCB,6E621BC1,BBA62A28,0F89C22F,5ABF1DC0,43F99348,F0AEBF45,F13F2850
7D: 8C0F98D5,CDFD799F,757B44A5,F0864453,565DB9B9,7E8C68BA,1469E90C,265B0BAC
7E: F8339539,01433019,425DAD45,BCDDD607,D1232354,B9CBA2C0,CB0B79F5,D27A29EC
7F: E6356303,5E67F37F,D1295D5E,9114FC21,6E6E5597,1A2E9FA3,7A43051A,C2EB0996
password: 7FF3675E036335E65E5D29D121FC149197556E6EA39F2E1A1A05437A9609EBC2
Step 8
同理,我们输入KCTF,登录,然后通过savedata命令,dump处变换序列,加载,进行逆变换,即可得到【KCTF】的password【AC1999741568E0A6B7CA93FD53FD900AE8EB599B8AE49E0797E91B106BE5DA53】
trs2=load_trs(r'D:\ctf05\trs_kctf.bin')
yi = [0]*8
y = yi
for i,t in enumerate(trs2[::-1]):
print(f"{i:02X}: ",end='')
y = ets[t](y)
yws = [y[1],y[0]]+y[2:]
yp=struct.pack('8L',*yws).hex().upper()
print(f"password: {yp}")
Step 9
实际分析128次(0x80)变换序列,我们可以发现,其实际就是sha256(user_name)的256位值中,每两位两两组成的变换选择子(从四种变换中选一种),于是我们可以写出相应的keygen:
import hashlib
def key_from(trs):
yi = [0]*8
y = yi
for i,t in enumerate(trs[::-1]):
y = ets[t](y)
#
yws = [y[1],y[0]]+y[2:]
yp=struct.pack('8L',*yws).hex().upper()
return yp
def keygen(uname='KCTF'):
if isinstance(uname,str):
uname=uname.encode()
elif isinstance(uname,bytes):
pass
else:
assert 0,f'uname should be bytes for str'
#
int256 = int(hashlib.sha256(uname).digest()[::-1].hex(),0x10)
tbit=2
tmsk=(1<<tbit)-1
tcnt=256//2
trs = [0]*tcnt
for i in range(tcnt):
trs[i]=int256&tmsk
int256>>=tbit
#
return key_from(trs)
Step 10
以下参考AI问答
1
扫码参赛
第六题《秘辛揭露》火热挑战中
关于KCTF
看雪CTF(简称KCTF)是圈内知名度最高的技术竞技,从原CrackMe攻防大赛中发展而来,采取线上PK的方式,规则设置严格周全,题目涵盖Windows、Android、iOS、Pwn、智能设备、Web等众多领域。
扫码进入2025 KCTF
主办方
支持单位
看雪CTF比赛分为两个阶段,所有论坛会员均可参与,第一阶段是防守篇,防守方根据比赛要求制作题目,根据题目被破解的时间排名,被破解时间长者胜出。第二阶段为攻击篇,攻击第一阶段的题目,根据攻击成功的时间与题目排名,破解时间短且破解题目数多者胜。既给了防守方足够的施展空间,也避免过度浪费攻击方的时间。从攻防两个角度看,都是个难得的竞技和学习机会。
看雪CTF比赛历史悠久、影响广泛。自2007年以来,看雪已经举办十多个比赛,与包括金山、360、腾讯、阿里等在内的各大公司共同合作举办赛事。比赛吸引了国内一大批安全人士的广泛关注,历年来CTF中人才辈出,汇聚了来自国内众多安全人才,高手对决,精彩异常,成为安全圈的一次比赛盛宴,突出了看雪论坛复合型人才多的优势,成为企业挑选人才的重要途径,在社会安全事业发展中产生了巨大的影响力。
- End -
球分享
球点赞
球在看
混淆源码,请点击“阅读原文”,查看原帖附件!
