MISC Questionaire 叮~ 您有一份调查问卷~ 请查收~ https://forms.gle/Vmzt99LazrtXsRLM9
谷歌问卷调查,FQ打开,北京知识,每回答对一个空得flag片段。
直接F12看源码大法,有答案,有结果,拼接得flag。
/bin/cat 2 [CAUTION] cats as numerous as stars are coming… 解出的答案经md5后提交~
远看可现一张二维码,没用脚本,直接stegesolve.jar,取Red plane得明显的黑白图片,上扫码工具得flag。
testyournc Test your nc
hint1: /f1a9.bak 你看到了嘛?
hint2: 用df命令看看硬盘总共多大,再看看flag多大。
nc交互题。
ls
发现目录下有flag和readme,cat flag
发现打开卡死,ls -al
查看发现flag文件很大(15T+)。
在根目录找到可读文件f1a9.bak,是生成flag文件的源码:
发现是每个字符都随机偏移 $1024\times1024\times1024\times k\quad (\rm offset\mit \leq k\leq \rm offset+2048 )$ 后写入,$\rm offset$ 本身也在不断递增,中间填满空字符,无法按固定位置读取。
试过很多shell命令的结合,cat,tr,sed,grep,hexdump
都各种花样卡死…
受大佬提示此类文件是稀疏文件 ,非空数据块存入磁盘,空数据库不占用磁盘空间。
尝试将文件移到本地处理,使用tar
命令将flag文件打包到某个可写位置,比如/var/tmp,注意到tar有个参数可高效处理稀疏文件:
-S或—sparse 倘若一个文件内含大量的连续0字节,则将此文件存成稀疏文件。
上命令:tar -zcvfS /var/tmp/flag.tar.gz flag
这时查看flag.tar.gz文件大小就很小了(0.3KB+)
在nc环境运行
cat flag.tar.gz | base64
再在本地运行
echo -n "H4sIAAAAAAAAA+3RTUrDQBgG4AgK/oBnqDfImCbpUty78gRptQURAlpXIvQIXkDEK3gBPZJHMK2iRasbGWfzPBBm5pu/N8n4vJlkkeWdqp8v2s68DXX5Pg7zJ2ShqKpQ1aHO6yzf75YXWe84drC5q8tpc9HrZRdtO/1t3Wg6jhMg//TeD4t++KE+W+xae5h97F2urz8dfKmvvU3sHnXt1rfb3yY37rKVp20+rr5l+/B5ZX3ncvU5i8s/37T738uhlr8A/+vl/naWOgMAAAAQ1/i8mVynDgEAAABEVVb9qqiLInUOAAAAIJ5BHU5TZwAAAADi6udFkzoDAAAAENegnzoBAAAAENvJMHUCAAAAILaiLJrRKB8My3L/JnUYAAAAIIpJ2570ztrhXuogAAAAAAAAwJ+9AsKEhXoAoAAA" | base64 -d
把得到的base64字符串存储到本地。
本地解压出原始flag文件(15T+):
tar -zxvfS flag.tar.gz
再使用
tar -cvfS flag-new flag
得到稀疏处理过的flag稀疏文件。
PS :写到最后发现,不用在本地处理,直接 tar -cvfS /var/tmp/flag.tar.gz flag
应该也成。
CRYPTO bbcrypto its so simple
给定脚本:
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 import A,SALTfrom itertools import *def encrypt (m, a, si ): c="" for i in range (len (m)): c+=hex (((ord (m[i])) * a + ord (next (si))) % 128 )[2 :].zfill(2 ) return c if __name__ == "__main__" : m = 'flag{********************************}' a = A salt = SALT assert (len (salt)==3 ) assert (salt.isalpha()) si = cycle(salt.lower()) print ("明文内容为:" ) print (m) print ("加密后的密文为:" ) c=encrypt(m, a, si) print (c)
salt长度为3,又知明文m的前5位和后1位字符,有对应关系:
('f'*a+salt[0])%128 = 0x17
('l'*a+salt[1])%128 = 0x74
('a'*a+salt[2])%128 = 0x01
('g'*a+salt[0])%128 = 0x50
('{'*a+salt[1])%128 = 0x4b
('}'*a+salt[1])%128 = 0x3d
可用脚本爆破:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import stringlower = string.printable[10 :36 ] for a in range (1001 ): for s0 in lower: if hex ((102 *a+ord (s0)) % 128 ) == '0x17' and hex ((103 *a+ord (s0)) % 128 ) == '0x50' : print (a, s0) for a in range (1001 ): for s1 in lower: if hex ((108 *a+ord (s1)) % 128 ) == '0x74' and hex ((123 *a+ord (s1)) % 128 ) == '0x4b' and hex ((125 *a+ord (s1)) % 128 ) == '0x3d' : print (a, s1) for a in range (1001 ): for s2 in lower: if hex ((97 *a+ord (s2)) % 128 ) == '0x1' : print (a, s2)
容易得到符合条件的最小a=57
及对应salt='ahh'
在用脚本逆向求出flag{}中间字符:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 a = 57 si0 = 97 si1 = 104 si2 = 104 c = [0x17 , 0x74 , 0x01 , 0x50 , 0x4b , 0x01 , 0x25 , 0x27 , 0x2c , 0x12 , 0x27 , 0x43 , 0x17 , 0x1e , 0x2c , 0x25 , 0x0a , 0x60 , 0x2e , 0x3a , 0x7c , 0x20 , 0x6e , 0x01 , 0x4a , 0x01 , 0x27 , 0x03 , 0x27 , 0x3a , 0x3c , 0x01 , 0x60 , 0x17 , 0x3a , 0x73 , 0x75 , 0x3d ] flag='' for i in range (len (c)): if i%3 ==0 : for m in range (0 ,127 ): if (m*57 +si0)%128 == c[i]: flag+=chr (m) else : for m in range (0 ,127 ): if (m*57 +si1)%128 == c[i]: flag+=chr (m) print (flag)
得到flag~
easyLCG easy LCG
线性同余生成器(LCG)
线性同余生成器是个产生伪随机数的方法,它是根据递归公式:
$N_{j+1}=(A\times N_j+B)\pmod M$
其中$A,B,M$是生成器设定的常数,$A$为乘数,$B$为增量,$M$为模数。
已知初始$seed_0$在生成器运行一次得到:
$seed_1=(a\times seed_0+b) \% m$
$state_1=seed_1\gt\gt16$,即 $seed_1=(state_1\lt\lt16)+k_1$
同样:
$seed_2=(a\times seed_1+b) \% m$
$state_2=seed_2\gt\gt16$,即 $seed_2=(state_2\lt\lt16)+k_2$
联立有:
$state_2=(a \times ((state_1 \lt\lt 16)+ k_1 ) + b) \% m \gt\gt16 $
已知 $a$,$b$,$m$,$state_1$,$state_2$,可以爆破得$k_1$:
1 2 3 4 5 6 7 8 9 10 11 12 a = 3844066521 b = 3316005024 m = 2249804527 state1 = 16269 state2 = 4249 for k in range (2 **32 ): seed1 = (state1<<16 )+k res = ((a*seed1+b)%m)>>16 if res==state2: print (seed1) break
而后续的gen_AB()
是在以上面迭代两次后的$seed_2$为初始seed的,根据得到的$seed_1$计算$seed_2=278490266$,带入后续步骤即可。
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 from Crypto.Util.number import *a = 3844066521 b = 3316005024 m = 2249804527 state1 = 16269 state2 = 4249 class LCG : def __init__ (self ): self.a = 3844066521 self.b = 3316005024 self.m = 2249804527 self.seed = 278490266 def next (self ): self.seed = (self.a*self.seed+self.b) % self.m return self.seed >> 16 class DH : def __init__ (self ): self.lcg = LCG() self.g = 183096451267674849541594370111199688704 self.m = 102752586316294557951738800745394456033378966059875498971396396583576430992701 self.A, self.a = self.gen_AB() self.B, self.b = self.gen_AB() self.key = pow (self.A, self.b, self.m) def gen_AB (self ): x = '' for _ in range (64 ): x += '1' if self.lcg.next () % 2 else '0' return pow (self.g, int (x, 2 ), self.m), int (x, 2 ) Cipher = 13040004482819935755130996285494678592830702618071750116744173145400949521388647864913527703 DH = DH() print ("flag = {}" .format (long_to_bytes(Cipher ^ DH.key)))
PWN TaQiniOj-0 nc交互题。
用C语言写语句,读取flag.txt的内容。
测试发现禁用了关键字home|ctf|flag,直接字符串分割绕过:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #include <stdio.h> #include <string.h> void main () { FILE *fp; char str[100 ]; char path[50 ] ="/ho" ; char path2[50 ]="me/ct" ; char path3[50 ]="f/fl" ; char path4[50 ]="ag" ; strcat (path3,path4); strcat (path2,path3); strcat (path,path2); fp = fopen(path, "r" ); fgets(str,100 ,fp); printf ("%s\n" ,str); }