2024VishwaCTF
记录近期做的一些赛题,包括VishwaCTF,osu,GHCTF,pearlCTF
VishwaCTF
poly fun
题目描述:
Its a simple symmetric key encryption, I am sure you will be able to solve it (what do you mean the key looks weird)
task.py
1 | import numpy as np |
enc_key
1 | ☞➭⥄⫣Ⲋ⸹⿰ㆯ㍶☞⒗☞☞☞➭☞⥄☞⫣☞Ⲋ☞⸹☞⿰☞ㆯ☞㍶➭⒗➭ |
enc_flag
1 | u5FUKxDUxH9y8yxvfaaU+GSXDwvJS6QxlN/3udOEzpU6fIVUExjDLsB3LKqUTz/x |
花近一小时琢磨后发现这个transform函数并无作用,就是说transform(number) = number
key的每位字符进行了多项式运算:
$enckey_i = 4\times key^2 + 3\times key + 7$
解这个方程即可获得key的每位字符
解出来后key = 12345678910111213141516171819202
根据题目描述的,这是个简单的对称加密,于是找了个AES的解密网站AES在线加密解密工具 - MKLab在线工具

Intellectual Heir
task.py
1 | # my secret to hide the combination of my safe in fornt of all without anyone getting a clue what it is ;) |
file.txt
1 | 4400037514278889258479265625258024039636437755883377709505596356049534358755375772484057042989024750972247184288820831886430459963472328358741858934783775986591400972020736548834642094922678189447202173710409868474198821576627330424767999152339702779346380 |
file1.txt
1 | 5.403023058681397650e-01 |
file2.txt
1 | 8.414709848078965049e-01 |
file1.txt和file2.txt内容蛮多的,就不贴全了
str_to_ass()函数的作用就是把输入的字符变成ASCII码,再转成str,eg:输入A,则str_to_ass('A') = 65
a,z其实不用管,看了后面encrypted知道这大概是RSA加密,然后猜f应该就是模,e说了是最常用的,所以是65537
然后下面给了两组三角函数的值,分别放在了两个文件里面。
只需要知道np.sin()这个函数的作用就是算bin_arr里面每个元素的正弦值,比如bin_arr = [1 0],那么返回的就是[sin 1, 0]
不知道也没关系,自己跑一下脚本也可以看出规律
同理np,cos()也就明白了
file.txt放的就是c,file1.txt放的是np.cos(),file2.txt放的是np.sin()
这时候我们只需要根据两个文件的内容来恢复number
拿file1.txt来说,如果此时的值是0,就说明当前二进制的值是0,否则当前二进制为1
file2.txt同理,此时的值为1的时候,当前二进制的值是0,否则当前二进制的值是1
通过两个文件,可以得到两个素数,而且都是426bit,再根据c的大小是850bit,说明思路并没有问题,然后解密即可
不过需要注意的是最后得到的m应该做一个对str_to_ass()的逆向
exp
1 | from Crypto.Util.number import * |
BitBane
task.cpp
1 |
|
这道题有点逆向的感觉
先看主函数,先把flag进行了加密,然后用applyKey对密文进行处理,然后再用extraSecurity对密文再次处理
在看extraSecurity这个函数之前,先看一下checkValidity(x)这个函数,作用就是判断x是否是素数
然后就很好理解extraSecurity(encryption)这个函数的作用就是,是根据目前索引值i再加2的值,即i+2是否是素数,决定是否对encryption[i]取反。这个我们很容易就可以逆回去。
再看完applyKey这个函数,具体细节我就不说了,说不太清楚。总之可以发现,既然我们有了key,完全可以把原来的encryption恢复,(可以自己测试一下)。
最后就是encode()函数,看了很久发现没什么可以利用的点
最后想了想,因为有了key,完全可以通过爆破的方式来求解flag,前面的理解完全都不用看了。
exp.py
1 | def create_topping(curr, idx): |
爆破的时候出了点小问题,慢慢调试了之后找到问题在于enc[23]和enc[47]没取反,所以对enc[23],enc[47]进行了手动取反
Lets smother the King!
题目描述:
In my friend circle, Mr. Olmstead and Mr. Ben always communicate with each other through a secret code language that they created, which we never understand. Here is one of the messages Mr. Ben sent to Mr. Olmstead, which I somehow managed to hack and extract it from Ben’s PC. However, it’s encrypted, and I don’t comprehend their programming language. Besides being proficient programmers, they are also professional chess players. It appears that this is a forced mate in a 4-move chess puzzle, but the information needs to be decrypted to solve it. Help me out here to solve the chess puzzle and get the flag.
Flag format: VishwaCTF{move1ofWhite_move1ofBlack_move2ofWhite_move2ofBlack_move3ofWhite_move3ofBlack_move4ofWhite}.
Note: Please use proper chess notations while writing any move.
code.txt
1 | D'`A_9!7};|jE7TBRdQbqM(n&JlGGE3feB@!x=v<)\r8YXtsl2Sonmf,jLKa'edFEa`_X|?UTx;WPUTMqKPONGFjJ,HG@d'=BA@?>7[;4z21U54ts10/.'K+$j(!Efe#z@a}vut:[Zvutsrqj0ngOe+Lbg`edc\"CBXW{[TSRvP8TMq4JONGFj-IBGF?c=a$@9]=6|:3W10543,P*/.'&%$Hi'&%${z@a}vut:xqp6nVrqpoh.fedcb(IHdcba`_X|V[ZYXWPOsMLKJINGkKJI+G@dDCBA#"8=6Z4z21U5ut,P0)(-&J*)"!E}e#"!x>|uzs9qvo5srkpingf,Mchg`_%cbaZBXW{>=YXWPOs65KPImMLEDIBf)(D=a$:?>7<54X210/43,Pqp(',+*#G'gf|B"y?}v^tsr8vuWsrqpi/POkdibgf_%]b[Z_X|?>TYRQu8TMqQPIHGkEJIBA@dD&B;@?8\<5{3W70/.-Q10/on,%Ij('~}|B"!~}_u;y[Zponm3qpoQg-kjihgfeG]#aCBXW{[ZYX:Pt7SRQJONMLEiIHA@?cCB$@9]~<;:921U543,10/.-&J*j('~}${A!~}vuzs9Zponm3qpihmf,jihgfeG]#n |
密文很怪,没什么线索。根据题目描述搜了下Ben和Olmstead,分开搜也没有线索,合起来搜以后了解到Malbolge这个编程语言

然后找个在线网站运行一下malbolge在线运行,在线工具,在线编译IDE_w3cschool
得到结果

再结合一下GPT得知,这是一个残局,这些符号的信息如下:

然后再找个网站分析一下残局,寻找白棋4步绝杀的方法
使用的时候把在线计算关了,会快一点。

得到解法之后拼接flag即可
VishwaCTF{Nc7+_Kb8_Na6+_Ka8_Qb8+_Rxb8_Nc7#}
GHCTF
2024九省联考
task.py
1 | from Crypto.Util.number import * |
$$
\because key \equiv g^{a\times (p-1)} \mod n
$$
可以推出
$$
key \equiv g^{a\times (p-1)} \mod p
$$
$$
key \equiv g^{a\times (p-1)} \mod q
$$
通过费马小定理可以知道
$$
key \equiv g^{a\times (p-1)}\equiv 1 \mod p
$$
$$
\therefore key - 1 = kp
$$
则gcd(key-1,p) = p
$$
c \equiv key^b \times m\mod n
$$
同理可推出
$$
c \equiv key^b \times m\mod p
$$
$$
c \equiv key^b \times m\mod q
$$
在mod p下,我们有
$$
c \equiv key^b \times m \equiv 1 \times m \mod p
$$
$$
\therefore m \equiv c \mod p
$$
exp
1 | from Crypto.Util.number import * |
2023四省联考
task.py
1 | from Crypto.Util.number import * |
抓住关键即可
$$
\because c_1 = m + r\times K = m + r\times k \times G
$$
$$
c_2 = r\times G
$$
$$
\therefore m= c_1 - k\times c_2
$$
exp
1 | from Crypto.Util.number import * |
Crypto1921
task.py
1 | .---- ...-- .---- .---- -..-. ----- -.... .---- ..... -..-. ----- ...-- ...-- ---.. -..-. ...-- .---- ..--- --... -..-. ....- ....- ...-- -.... -..-. ----- ..--- ...-- ....- -..-. ..--- ..... ----. ---.. -..-. .---- ---.. ----- --... -..-. -.... ....- ..--- ....- -..-. .---- -.... ...-- ...-- -..-. ...-- .---- ..... ----. -..-. ----- ...-- -.... ..--- -..-. ..... --... .---- ....- -..-. ...-- ----. ----. ..--- -..-. ----- .---- ...-- ---.. -..-. ..--- ..... ---.. ----. -..-. --... ....- ..... -.... -..-. ----- ....- ....- .---- -..-. ----- ....- ...-- ...-- -..-. .---- ...-- .---- .---- -..-. -.... .---- ..... ...-- -..-. ----- ....- -.... --... -..-. ----- -.... ...-- --... -..-. ..--- ..--- ...-- ..--- -..-. ..--- -.... ---.. -.... -..-. ----- ----. --... -.... -..-. ..--- ---.. --... .---- -..-. ..--- -.... ...-- ----. -..-. ....- ---.. ....- ..--- -..-. .---- -.... ...-- ...-- -..-. ----- ----- ..... ----. -..-. .---- -.... ...-- ...-- -..-. .---- -.... ..... ...-- -..-. ----- ----- ..... ----. -..-. ----- ...-- -.... ----- -..-. ----- ....- ...-- ...-- -..-. .---- -.... ...-- ...-- -..-. ----- ...-- -.... ..--- -..-. ....- ....- ...-- ..--- -..-. ----- ..... ..... ....- -..-. ....- ---.. ---.. ..... -..-. ----- ----- ----- ..... -..-. .---- -.... ...-- ...-- -..-. .---- -.... ..... ...-- -..-. .---- -.... ...-- ...-- -..-. ----- ----- ----- ..... -..-. ----- ....- ...-- ...-- -..-. ----- ...-- -.... ..--- -..-. ....- ....- ...-- ..--- |
摩斯解码得到
1 | 1311/0615/0338/3127/4436/0234/2598/1807/6424/1633/3159/0362/5714/3992/0138/2589/7456/0441/0433/1311/6153/0467/0637/2232/2686/0976/2871/2639/4842/1633/0059/1633/1653/0059/0360/0433/1633/0362/4432/0554/4885/0005/1633/1653/1633/0005/0433/0362/4432 |
中文电码查询得到
1 | 1311:子 |
压缩包密码即121.471E,31.218N
打开得到信息
1 | 這次會議遭到破壞,恐怕是存在著敵特的監視。請你幫助我們擬一封電報,發送給XXX,內容為: |
将上海已不安全,請即刻前往嘉興。进行编码

转为0006/3189/1571/0008/1344/0356/6153/0613/0466/0467/1766/0857/5281
进行摩斯编码得到
1 | ----- ----- ----- -.... -..-. ...-- .---- ---.. ----. -..-. .---- ..... --... .---- -..-. ----- ----- ----- ---.. -..-. .---- ...-- ....- ....- -..-. ----- ...-- ..... -.... -..-. -.... .---- ..... ...-- -..-. ----- -.... .---- ...-- -..-. ----- ....- -.... -.... -..-. ----- ....- -.... --... -..-. .---- --... -.... -.... -..-. ----- ---.. ..... --... -..-. ..... ..--- ---.. .---- |
再md5得到43f756680ebbcc619bc7b9a4c69e18ab,即为压缩包密码
flag:NSSCTF{Wh3Re_7herE_1s_OppreSsi0n_Ther3_iS_REs1st4nce!}
Crypto1939
cipher.txt
1 | Che-chil-be-tah-ola |
密文是Navajo
网上找码表即可
1 | Che-chil-be-tah-ola -> major |
压缩包密码为major_transport_blinker_regiment_section
NSSCTF{W0Rds_SomeTimes_N3ec1_L1vEs_To_DeFend!}
Crypto2042
给出c = 2280855825153079369164514405327170396436620371664464526496429415733055203155893358484242996086505609777681080427906338470140692619928813296029361848636902023401977358243759630394370381376771421271028169492126347929997983519619222735581769019133156193638407197605823449074124544232663174637158818370904094998560600412703805652546502801423946150024740398302185572802694514470006408627417645654400501165391976205173956917696904810606259304153658230235808250378495226246727449749944446621780268923502478344984402162063011322533642498211989023200258638304752854056875616723925602248635708248865548095231743243612632966212
以及破损私钥文件
1 | -----BEGIN BREAK PEM PRIVATE----- |
能提取出n,e,dp,dq,inv,关于提取数据可以参考NSSCTF Round16 | DexterJie’Blog
然后用dp泄露的思路进行求解
Exp
1 | from Crypto.Util.number import * |
osu
第一道题
task.py
1 | from Crypto.Util.number import isPrime,bytes_to_long |
从低位往高位爆破即可,因为题目生成的素数只含7,2,所以每次爆破只需要2个数字,爆破起来蛮快的
exp
1 | from Crypto.Util.number import * |
第二道题
task.py
1 | from Crypto.Util.number import getPrime # https://pypi.org/project/pycryptodome/ |
由$X_{n+1} \equiv aX_n + b \mod p$
拆成高低位来写,则有
$$
H_{n+1}\times 100 + L_{n+1} \equiv a(H_n\times 100 + L_n) +b \mod p
$$
化简得
$$
H_{n+1} \equiv aH_n + (aL_n + b -L_{n+1})\times 100^{-1} \mod p
$$
于是有
$$
H_2 \equiv aH_1 + (aL_1 + b - L_2)\times 100^{-1} \mod p
$$
$$
H_3 \equiv aH_2 + (aL_2+b-L_3) \times 100^{-1} \mod p
$$
即
$$
H_3 \equiv a^2H_1 + (a(aL_1+b-L_2) + (aL_2+b-L_3)) \times 100^{-1} \mod p
$$
写到这里是为了后面更好理解$B_i$如何计算
回到题目,简单来写就是
$$
H_{n+1} \equiv A_nH_1 + B_n \mod p
$$
即$H_{n+1} = A_mH_1 + B_n +k_np$
构造格

exp
1 | from Crypto.Cipher import AES |
pearlCTF
3 pies
task.py
1 | #!/usr/bin/env python3 |
exp
1 | from Crypto.Util.number import * |
进入这个网站得到一串信息:
1 | You think this is Gibbrish, but it's something different... |
放入CyberChef

Baby’s Message Out
task.py
1 | #!/usr/bin/env python3 |
将$q,r,s,t$暂且设为
$q = 17p+1,r = 29p\times q,s = q\times r + p,t = r\times s\times q$
可以得到
$$
n = 4933820698627921p^{13} + 2321797975824904p^{12} + 479194612657574p^{11} + 56652867922228p^{10} + 4196277199301p^9 + 199402260580p^8 + 5936228776p^7 + 101222760p^6 + 756900p^5
$$
把n的系数化为1,然后开13次方,可以得到一个在实际的p附近波动的值,然后再进行爆破即可恢复p
爆破范围的选定可以自己生成数据进行测试。
exp
1 | from Crypto.Util.number import * |
Bit War
task.c
1 |
|
output
1 | output:01001000 11010111 11010001 11001011 01011010 01000110 11011101 01001110 01001010 01110000 11010001 01110000 01011010 11010101 01001010 11001011 11000011 |
代码实现的是一个LFSR的作用,至于具体过程,我不太说的明白,值得注意的是,我们输入的数据得是2进制。
不过题目给出output,根据output的长度可以判断flag的长度并不长,于是想到了爆破的方法
exp.py
1 | from tqdm import * |
syntelestis
task.py
1 | from Crypto.Util.number import getPrime, inverse |
首先进行推导
$$
e \equiv (c^{-1}+d^{-1})^2 \mod p
$$
$$
f \equiv m^2c^{-1}n^2d^{-1} \mod p
$$
$$
f^{-1} \equiv m^{-2}cn^{-2}d \mod p
$$
$$
h \equiv ef^{-1} \equiv (c^{-2}+d^{-2}+2c^{-1}d^{-1})(m^{-2}cn^{-2}d) \equiv m^{-2}c^{-1}n^{-2}d + m^{-2}cn^{-2}d^{-1} +2m^{-2}n^{-2}
$$
把c,d用a,b表示,即可得到h关于a,b的式子
$$
h \equiv m^{-3}a^{-1}n^{-1}b + m^{-1}an^{-3}b^{-1} + 2m^{-2}n^{-2} \mod p
$$
再写成g和a,b的式子

题目一共给出54组这样的数据,于是想到用格来做,不过这里存在$a^{-1},b^{-1}$,比较麻烦。
在鸡块师傅的指导下,我们引入$t = ord(‘0’)\times ord(‘1’)\times … \times ord(‘f’)$,然后两边同时乘上t可以得到

即

首先尝试用一组数据构造格:

结果不出所料,没有规约成功
进行优化,把$\sum_{i=1}^{37}2m_i^{-2}n_i^{-2}t$记为一个变量R,此时格为

不过还是没有规约成功,把所有数据利用上,此时格为

利用这个格便可规约成功。有个值得注意的点是,最后两行的$R_i$和$g_i$可以合并为1个变量,这样可以把格的规模从$130\times 130$变为$129\times 129$
1 | #sage |
得到一系列$\frac{tb_i}{a_i},\frac{ta_i}{b_i}$以后,采取枚举的方式即可求得flag的16进制形式,再进行转化即可
1 | from gmpy2 import invert |
得到的结果是pearl{a_5ymPh0nY_oF_bRu7\x00_c0mpl\x00x1tY}
进行猜测:
1 | pearl{a_5ymph0nY_oF_bRu7e_c0mplex1tY} |
正确的结果是pearl{a_5ymPh0nY_oF_bRu73_c0mpl3x1tY}
在鸡块师傅的指正下,得到pearl{a_5ymPh0nY_oF_bRu7\x00_c0mpl\x00x1tY}这个结果后正确的思路如下:
出现\x00,说明改组$\frac{ta_i}{b_i} = \frac{tb_i}{a_i}$,满足这个情况的a,b有$a = ord(‘0’),b=ord(‘0’)$…$a=ord(‘f’),b=ord(‘f’)$
也就是说,\x00的位置只可能是\x00,\x11,",3,D,U,f,w,\x88,\x99,\xaa,\xbb,\xcc,\xdd,\xee,\xff
这样的话,很明显结果就是pearl{a_5ymPh0nY_oF_bRu73_c0mpl3x1tY}
Security++
secure.py
1 | from flag import flag, key |
enc.py
1 | from copy import copy |
靶机:dyn.ctf.pearlctf.in 30015
花了很长时间看代码,后来在鸡块师傅指导下,可以用逐字节爆破的方式进行求解,具体过程如下:
先输入空,可知flag长度为32
然后输入000000000000000,即15个0。
此时明文分块为
$$
000000000000000m_1 \quad m_2m_3…m_{17} \quad m_{18}…m_{32}.
$$
最后那个点是填充
我们再输入000000000000000 + X,X为我们要爆破的字符
此时明文分块为
$$
000000000000000X \quad m_1m_2…m_{16} \quad m_{17}…m_{32}
$$
只需要对比第一块密文是否相同,我们就可以知道X是什么字符,也就是flag的第一个字符
接下来,我们爆破第二位
这个时候输入00000000000000,即14个0
此时明文分块为:
$$
00000000000000m_1m_2 \quad m_3m_4…m_{18} \quad m_{19}…m_{32}..
$$
最后两个点是填充
我们再输入00000000000000m1 + X,上一步已经把m1求出来了
此时明文分块为
$$
00000000000000m_1X \quad m_1m_2 …m_{16} \quad m_{17}…m_{32}
$$
还是对比第一块密文即可判断出flag的字符,依次爆破出flag的前16位
接下来爆破第17位
此时我们需要输入0000000000000000000000000000000,即31个0
此时明文分块为
$$
0000000000000000 \quad 00000000000000m_1 \quad m_2…m_{17} \quad m_{18}…m_{32}.
$$
再输入flag[-15:] + X + 000000000000000,就是flag倒数15个,X是要爆破的字符
$$
m_2…m_{16}X \quad 000000000000000m_1 \quad m_2…m_{17} \quad m_{18}…m_{32}.
$$
这个时候我们只需要把第一块密文和第三块密文进行对比,即可依次爆出所有字符
exp.py
1 | from pwn import * |