终于打完祥云杯了,两天的比赛真的累。这是之前做的一个联合新生赛,借这个新人友好的比赛学习了一下逆向的基础题型;crypto做完了,但只记录稍微复杂的题目。misc原本是想学python jail,但是捣鼓半天也只会简单的,希望有wp可以复现。
Misc
[Week1]silly_zip
zip文件是伪加密,但是他把前后都改了,所以两边都要把1改成0;解开以后是一张bmp图片,尝试查看低位隐写,没有找到;猜测是改变了图片的宽或者高,参考链接,计算正确的高度位77h,修改即可看见flag,这里我在没计算的情况下直接把高改大是失败的,应该是高度不能改的超过原本的大小,否则文件的大小就异常了。
[Week1]开局一张图(OSINT)
首先直接去百度搜索该图片,找到胶东屋脊,苹果之都
,遂百度发现是烟台栖霞;根据栖霞地图可知湖应该是长春湖,以下信息百度很容易找到:湖的原名为庵里水库,因丘处机而得名,2010年设立旅游度假区。比较麻烦的是一和六两个问题,第六个问题必须找到该烟台政府网站上的title,其他新闻网站上的均不正确;而第一个问题很容易认为是苹果公园,因为图片里有三个苹果并且苹果公园的地标也是类似的大苹果;根据hint以及不断地搜索,找到滨湖公园
,终于正确。
所以flag为nssctf{滨湖公园-长春湖-庵里水库-丘处机-2010-环长春湖2012山东省公路自行车锦标赛}
[Week1]线下单杀出题人(OSINT)
首先用EXIF查看A原图信息,得到拍摄经纬度为30 deg 47’ 12.96” N, 120 deg 44’ 23.48” E,定位发现是在嘉兴汽车北站,因为B图看起来像是公园,所以直接找周围的公园可定位到穆湖森林公园。在汽车北站和公园附近的酒店挨个排查,通过水壶和室内装饰锁定为亚芬汀精品酒店。
1 | from hashlib import * |
[Week1]python2 input(JAIL)
1 | eval(input()) |
[Week1]calc_jail_beginner_level1
过滤了i和b以及单双引号;
做了一些尝试,比如用chr来拼接出eval(‘input()’):
1 | eval("eval(input())") |
最后采取读文件的方式绕过,简单粗暴…
1 | open(chr(102)+chr(108)+chr(97)+chr(103)).read() |
本质上eval只会执行一次,那么只需要把文件名用chr拼接即可,其他部分不能用chr拼接,否则返回的是命令的字符串。
[Week1]calc_jail_beginner_level2
payload长度不大于13,用input即可:
1 | eval(input()) |
[WEEK2]Baldi’s Basics
1000次加减乘除,存一个比较简约的脚本以后直接用。
1 | from pwn import * |
[WEEK3]看不见的代码
https://vii5ard.github.io/whitespace/解密。
[WEEK3]神秘的压缩包
crc32爆破,取可读字符拼接为:
1 | passwordisClassicalencryptionishint6 |
得到密码解压,里面是一段可见乱码,和flag
对照一下ascii码发现相差9,解密即可:
1 | c = "]cX^r:X\jXiV`jVm\ipV`ek\ijk`e^t" |
Re
[WEEK2]Easy_Android
jadx反编译整个apk,定位和flag有关的代码:
1 | public boolean checkSN(String userName, String sn) { |
这里就是把username做了个md5哈希,然后取偶数下标的字符进行拼接,和sn进行比对,若一致则返回true,那么这个sn其实也就是flag了。写个python脚本即可:
1 | from hashlib import * |
[WEEK2]Packet
upx -d脱壳,base64加密,但是它把base表的大小写字母顺序换了,所以把密文的大小写交换解密即可。
1 | import base64 |
[WEEK2]来解个方程?
解22维的矩阵方程即可,我用的sagemath,也可以用z3但是应该挺慢的。
1 | from sage.all import * |
[WEEK2]getflag
点击很多下能够出flag,所以静态patch修改条件即可,那么我们可以把条件改为点击次数大于1即出flag:
patch之后要记得apply patch to…
[WEEK2]e@sy_flower
最常见的花指令,参考链接,改为nop以后要用快捷键p创建函数,得到伪代码:
1 | int __cdecl __noreturn main(int argc, const char **argv, const char **envp) |
先异或再置换:
1 | c = 'c~scvdzKCEoDEZ[^roDICUMC' |
[WEEK2]TTTTTTTTTea
Tea加密算法。
注意整数类型内部存储:低地址存储低位,高地址存储高位。比如int a=1,则存储情况为0000(高地址) 0000 0000 0001(低地址)。所以key应该是unsigned int key1[4] = { 0x00010203,0x04050607,0x08090A0B,0x0C0D0E0F}
尝试解密:
1 |
|
Crypto
[Week1]littleprince
enc就是循环右移32位,每次enc完再右移得到的x其实就是flag的32位;并且题目的每组p和q都是质数,可以通过crt求出每轮的x;注意有几轮32位的x大于p乘q,即在crt求出结果以后要再加上一个pq才是正确结果。
1 | from Crypto.Util.number import * |
[WEEK2]Chaos
加密的第二部分时间戳t是和0x66进行异或的,所以可以还原20位时间戳,并通过预测伪随机数还原enc;拿到enc之后我通过正向爆破获得了置换群,再逆运算mix还原flag。
1 | from hashlib import md5 |
[WEEK3]Binomials
1 | from Crypto.Util.number import * |
[WEEK3]s1mple_block
爆破两字节即可
1 | from pwn import * |
[WEEK3]AnyoneIsOk
给的是100组pem格式的公钥,可以用RSA库去批量提取n e,依次取两个n来求公因子,第22组和第43组存在公因子,即成功分解模数。需要注意这里的填充方式是PKCS1_OAEP
,不能以pow(c,d,n)解密,要用Crypto.Cipher.PKCS1_OAEP
解密。exp:
1 | import Crypto.PublicKey.RSA as RSA |
[WEEK3]Base42?
本质上就是进制转换,把flag每个字符的ascii码放在256进制下,再转成42进制去对照表完成加密;所以解密就是个逆过程,把42进制放在256进制下。
1 | alphabet = "0123456789aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpP" |
[WEEK3]AES
简单的CBC漏洞,用前一组密文作为key解密。
1 | from Crypto.Cipher import AES |
[WEEK3]partialP
已知p高位攻击,coppersmith。
1 | from sage.all import * |
[WEEK3]babyCBC
cbc字节反转,理论可参考https://blog.csdn.net/qq_45698157/article/details/109746592 。
由于本题中的guest刚好是在第二个分组的起始位置,所以很容易修改,把该组和Admin及前一组明文做xor即可,给出exp:
1 | import time |
这是伪造信息加上enc_flag解密得到的返回值,data里就是flag的hex:
[WEEK4]random
mt19937预测:
1 | from Crypto.Cipher import AES |
[WEEK4]square
有限域开根:
1 | from Crypto.Util.number import * |