TSCTF-J2024 密码向WP(5/8)
ezRSA
part 1
#part1
p = getPrime(512)
q = getPrime(512)
n = p * q
phi = (p-1) * (q-1)
d = getPrime(250)
e = inverse(d, phi)
c = pow(bytes_to_long(parts[0]), e, n)
print(f'n = {n}')
print(f'e = {e}')
print(f'c = {c}')
# n = 124695452995031270645183837267530422032624508784074534979189655228220709056309638648794696369835930482818980808128467814617220810217534821336503942838791498456112882717378013827550680516551959078234339477401303759763506487676709408813412867364414651706461400252466842182365340612883444737530603407481042520627
# e = 38587713366842463962841747677614707312145479235042165803103947138237921458583509748629042842505955223421671992698976799249425980974893271454942323501453571320592126625468760278770909411858284131095166550317734018153286242950401311537208914820833671566620645882329390747892971373265592565291598852744678229891
# c = 75650426098322108299742769179799276679353245586432433359812352366165787480762021753671012472067826915659840541954505167382050569833945309043431554352347482992118091659840982421987700648585142917347916194810259117115753813661282178558428786374835684668840019166776178494086580424196110694158066034697988927644
容易发现
\]
\]
因此采用 \(\text{Wiener's Attack}\)。
part 2
#part2
p = getPrime(80)
q = getPrime(80)
n = p * q
e = 2
c = pow(bytes_to_long(parts[1]), e, n)
print(f'n = {n}')
print(f'c = {c}')
print(f'p,q = {p,q}')
# n = 649329048322675374317593820985753646586809799201
# c = 283668420132846011615755415362202578109404366325
# p,q = (647260709632957671018359, 1003195526406802286444839)
发现 \(e = 2\) 且 \(p, q\) 较小,采用 \(\text{Rabin}\) 算法。
part 3
#part3
p = getPrime(512)
q = getPrime(512)
n = p * q
e = 65537
c = pow(bytes_to_long(parts[2]), e, n)
print(f'n = {n}')
print(f'c = {c}')
print(f'p^q = {p^q}')
# n = 85836893651204560884454211125508692415276042143801480450535044733242333318334455339451808653755272841343378345709375676280488068099971805717946097641116078266013229365158341178806480395974457905053516603153056936745020102883744430977333247681929718298626185526512756702624513738698825219177049538628421559753
# c = 75578834548096799626696300881096262997184146142305165096930004492293642496308047534319034721187289042138332386120962890635270628767192988167590315544321566944902760623837249074921079890026503778053466720161607743010204269544291059577848021218234039433294700788160167294093796603060247381385159054508170520277
# p^q = 5068548570505625142069285468439450186210992627026138517591800598908379828953823253346928574075223127205617451260708785889033493211347183583859669806824864
\(p \oplus q\) 已知,考虑从低到高搜索 \(p, q\) 的每一位,对于当前为 \(i\) 满足异或后第 \(i\) 位与 \(p \oplus q\) 相等,且 \(p \times q \le n\),实现剪枝。
part 4
#part4
p = getPrime(512)
q = getPrime(512)
n = p * q
e = 3
m = bytes_to_long(os.urandom(32)+parts[3])
c = pow(m, e, n)
print(f'n = {n}')
print(f'c = {c}')
print(f'mleak = {m>>128}')
# n = 136909292741753142871542219643510188168311518562065789353531367466023357011784735447560466352669948897633633920102617017949126915203615330337196942328793619163571419292670395849251337340787480297972818664454785647844715189207055430597030032696044932960884594660634280475822683286430432169515120767378120972393
# c = 14763067643592454478187771324072634160297758439803081056226124797870386993054732731754324146768654813122274647054179017048620683751626439261028839186682159969656271385676822426489416369402998625865982105676257668946313225156476831065481561281126267398712822218497384996243578386630794573662378684549962709522
# mleak = 287621732882458207416007037901690948810437972193283953524078189541847647258
明文 \(m\) 的高 \(\text{bit}\) 位已知,低 \(128\) 位未知,根据 \(\text{Coppersmith}\) 定理可求。
ezNumberTheory
part 1
p = getPrime(512)
q = getPrime(512)
n = p * q
e = 65537
gift = pow(p+q,q,n)-p
m = bytes_to_long(flag[:part_len])
c = pow(m,e,n)
print("n =",n)
print("gift =",gift)
print("c =",c)
已知
\]
\]
考虑二项式展开得到
\]
化简得
\]
不妨考虑拆分模数 \(pq\),得到两个式子。
\]
\]
由于 \(p, q\) 为质数,由费马小定理可得
\]
\]
对 \(gift\) 因式分解得到 \(q\),进而 \(p = \frac{n}{q}\)。
已知 \(e,p,q\),可求出密文 \(m\)。
part 2
p = getPrime(512)
q = getPrime(512)
n = p * q
e = 65537
m = bytes_to_long(flag[part_len:2*part_len])
gift = pow(n-1,m,n**2)
c = pow(m,e,n)
print("n =",n)
print("gift =",gift)
print("c =",c)
# n = 101825028937892274755066568298675753051915211984336844010001051946487425488926444636462308770518438066690807207349397829434761111870976777194195377994066094978667372161712559828354279213717904934626695765400184018995342438568172381388749973725572499090794995578069624189552411881722996041605959223833931977161
# gift = 10368336518202599155478611962986419931032852827247241544520944151147424100095888793813818133261771295138537638975002709013348196763698154979511238402220870231916534915445557931918512473116396709289462544729254616655147690181935999744990349056920271954901882532521970967307761055252723712876050094383313331140406445004997917905258680326374893836686879404331037481540004243801858344196072242572121743245711481444665694028492376994909442739868671793792049626000877294534619734785195159330183197692177383792865340479971388526007871832995878259364333594949083550807440342049213394072558604884076160696389453987350453566282
# c = 6206002756473719752481539026703107851866702754011241324450943403363532188346664095512595594879972008741307201868011790850666619709952602312346601585431717191460826191100496612662950423560204126590072745286069584415447406165328489464592884522745095517397118876988652114937810284710552486235169949976593170616
已知
\]
不妨先考虑
\]
同上,有
\]
带入 \(gift, n\) 可得
\]
于是 \(m\) 为偶数。
直接展开原式有
\]
化简得
\]
即
\]
求得
\]
根据第一部分 \(m\) 的大小推断 \(m,n\) 大小接近,试除后发现 \(m = \frac{n^2 - gift + 1}{n}\) 恰为整数,故 \(m\) 为所求值。
part 3
p = getPrime(512)
q = next_prime(p)
r = getPrime(512)
n = p * q
e = 65537
m = bytes_to_long(flag[2*part_len:])
gift = (pow(1+m*n,1,n**2)*pow(r,n,n**2))%(n**2)
print("n =",n)
print("gift =",gift)
print("p =",p)
print("q =",q)
# n = 120085278656547434097495160698983440086977117014813250068332400723955573086081539793659925690983763612644098938270646361630753175121916904514302168476109276991065963359696653413330575343172587757112308794397643577457876878076258704713342584783867357600427211623403743168388707834963362860793081706620920977197
# gift = 755365096368274234067764643236574524026724653923904235465391689910808113641191521577417355583242717443863451427293486428108305560959934240539916731737071269870765365812729624798503913486014927177398814766178335408644263304959990001131184599054858122656321624816269434361664736002888774514548687701448375859895656340630928111228145226768972365422917506757004452665088879334351527814068349598913876771933729841797767944898598495453091334481416909244894797229851139025287531257727280929467263018600829848751441007477417666581057493947789435287529403836954674188989033519154270698877075630430517874818318137411379414838
已知
\]
考虑
\]
有
\]
再考虑将 \(n\) 分解有
\]
\]
由费马小定理有
\]
即
\]
考虑欧拉定理 \(a^n \equiv a^{n \text{ mod } \varphi(p)} (\text{mod p})\) 有
\]
\]
记 \(q^{-1}\) 为 \(q\) 模 \(p - 1\) 的逆元,可知
\]
\]
即
\]
由于 \(r\) 与 \(p\) 大小相近,可解出唯一 \(r\)。
回到原式,记 $ ( r^n ) ^ {-1} $ 为 \(r^n\) 模 \(n^2\) 的逆元,有
\]
\]
依旧有 $ m = \frac{(gift \times (r ^ n) ^ {-1} - 1) \text{ mod } n ^ 2 }{n} $,此题完。
ezPwntools
挺过了前面的分P狂魔,单题可以开始轻松了不少。
import random
from Crypto.Util.number import *
from typing import Callable
with open("flag.txt", "r") as f:
flag = f.read().strip()
length = 128
class LCG:
def __init__(self, length=128):
self.length = length
self.setparam()
def setparam(self):
self.m = getPrime(length+1)
self.a = getPrime(length)
self.b = getPrime(length)
self.seed = random.randint(0, self.m - 1)
self.begin = self.seed
def generate(self):
for i in range(10):
self.seed = (self.a * self.seed + self.b) % self.m
seed_list = []
for i in range(5):
self.seed = (self.a * self.seed + self.b) % self.m
seed_list.append(self.seed)
return seed_list
def __call__(self):
return self.begin
def challenge(input:Callable[[str],None], print:Callable[[str],None]):
print("Welcome to TSCTF-J! If you can recover the seed, you will get the flag!")
for i in range(512):
lcg = LCG()
print("Here is your gift:{}".format(lcg.generate()))
i = input(f"Give me the seed: ")
if int(i) != lcg():
print(f"Oh, you are wrong!")
return
print(f"Congurations!{flag}")
观察到 generate 函数每次做 \(15\) 次线性同余变换并返回最后 \(5\) 次结果,可以列出方程。
\]
考虑相邻两项相减消去 \(b\) 有
\]
\]
则对于 \(a\) 有
\]
交叉相乘可得
\]
不难发现
\]
取出上式的最大质因子即可得到 \(m\),接着易于得到 \(a, b\) 的值。
然后解 \(10\) 次一元线性同余方程
\]
对于 \(512\) 次操作,求出 \(m, a, b\),并解出其初值,用 pwntools 与交互库交互即可。
如下是一份代码
from pwn import *
from gmpy2 import *
from sympy import *
con = remote('challenges.hazmat.buptmerak.cn', 21747)
t = con.recvline()
for _ in range(512):
t = con.recvline()
t = t[19:len(t)-1]
ls = t.split()
xi = []
for i in ls:
xi.append(int(i[:len(i)-1]))
x1, x2, x3, x4, x5 = xi
m = gmpy2.gcd((x5-x4)*(x3-x2)-(x4-x3)**2, (x4-x3)*(x2-x1)-(x3-x2)**2)
while is_prime(m) == False:
div = primefactors(m)
m //= div[0]
a = (x5 - x4) * gmpy2.invert(x4 - x3, m) % m
b = (x5 - a * x4) % m
x = x1
for i in range (10, -1, -1):
x = (x - b) * gmpy2.invert(a, m) % m
t = con.recv()
print(_ + 1)
con.sendline(str(x))
t = con.recv()
print(t)
ezECC
#sage
from Crypto.Util.number import *
from sage.all import *
msg = b'???'
flag = b'TSCTF-J{'+msg+b'}'
m = bytes_to_long(flag)
(p,a,b) = (getPrime(len(bin(bytes_to_long(flag)))) for i in range(3))
E = EllipticCurve(GF(p),[a,b])
for i in range(4):
print(E.random_point())
e = 114514
K = E.lift_x(m+1)
eK = e*K
print(f"eK={eK}")
# (121542556343240612458886464797113519174471159973947349739843570016310276547868092596053087152046638137671892191449161589255393370014868931365353180578227117593735, 98840327394835055943257602264613388284774639725847294267402852043945104193135363216749971927532657727021952911622427228151863672295675502233797082353097959401869)
(99873546068894326234875062311058443230105529641172112880280159410919160848811689840010700811925066814781044568587853533466146854172381759747204462070834544581290, 54021704113721739503680080012966661376438637715420865450114718929076757346120207862947548620569435334895396324086781218017455445315421875871714429627637052871264)
(157617948261622464254152314994703598559915540865514420750304511730242939622181332932412360735409968696715108030369878546783001121709970056186086411214753185288604, 172554749510163658517336910991986476106096485848063383199885085041705448141288872247307505628175707155625972718684398442883637022240936050198926361252214588735919 )
(35601692031837010013294196210817440996871532774395053520652383520080490377765688796593595849840043210266473831404618732851470643297944496494254634489110294026906, 83109137089012676168973029782730032714034653700896174331183408691033951856596721848482516578501834370646437639802694578133409539742068584938899820955422945845189 )
# eK=(148943471114336569351357302344843611917995236697008317506292328720097140911033713257363114040728547610446354966023690433690295644571622343830380563979394775174929, 5570936030363753742907439216925560949272269404612411400083981446597152991432704283038752432067099389895408182978262946903003923985122728700021027170168725851130 )
构式题,椭圆曲线密码,做法与 ezNumberTheory 和 ezPwntools 完全一样。
给定域 \(GF(p)\),椭圆曲线 \(E_p: y^2 = x^3 + ax + b\) 上任意 \(4\) 点 \(A_1,A_2,A_3,A_4\),与 \(e\) 倍基点 \(K(m+1, y_{lift\_x})\),\(eK\) 的坐标,求 \(m\)。
对于点 \(A_i(x_i, y_i)\) 有
\]
一样是先消去 \(b\),用 \(a\) 联立两个方程得到 \(p\),然后解出 \(a, b\)。
利用 sage 自带的求椭圆曲线阶的函数 E.order(),求得阶为 \(P\),这个题就转化为了:
\(K\) 为椭圆曲线 \(E_p\) 上一点,已知 \(eK\),\(e\),求 \(K\)。
求出 \(e\) 关于阶 \(P\) 的逆元即可。
ezFakekey
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
from typing import Callable
with open("flag.txt", "r") as f:
flag = f.read().strip()
def pad(data):
pad_len = 16 - len(data) % 16
return data + bytes([pad_len] * pad_len)
def unpad(data):
pad_len = data[-1]
return data[:-pad_len]
def generate_key():
return get_random_bytes(32)
def generate_iv():
return get_random_bytes(16)
def encrypt(message, key, iv):
assert len(key) == 32
assert len(iv) == 16
cipher = AES.new(key, AES.MODE_CBC, iv)
ciphertext = cipher.encrypt(pad(message))
return ciphertext
def decrypt(ciphertext, key, iv):
assert len(key) == 32
assert len(iv) == 16
cipher = AES.new(key, AES.MODE_CBC, iv)
plaintext = unpad(cipher.decrypt(ciphertext))
return plaintext
def challenge(input:Callable[[str],None], print:Callable[[str],None]):
print("Welcome to TSCTF-J! If you are Administrator, I will give you a flag!")
key = generate_key()
iv = generate_iv()
while True:
print('[E]ncrypt the message')
print('[D]ecrypt the message')
print('[G]et the flag')
print('[Q]uit')
option = input('> ').upper()
if option == 'E':
input_message = input('Plz input your message: ')
m = input_message.encode()
if b'Administrator' in m:
print('Permission denied!')
return
ciphertext = encrypt(m, key, iv)
print(f'Your ciphertext: {ciphertext.hex()}')
elif option == 'D':
ciphertext = bytes.fromhex(input('Plz input the ciphertext: '))
m = ciphertext
plaintext = decrypt(m, key, iv)
print(f'Your plaintext: {plaintext}')
elif option == 'G':
ciphertext = bytes.fromhex(input('Plz input the ciphertext: '))
m = ciphertext
plaintext = decrypt(m, key, iv)
if b'Administrator' in plaintext:
print(f'Congurations!Here is flag:{flag}')
return
else:
print('Permission denied!')
elif option == 'Q':
return
else:
print('Unknown option:', option)
又是我们的交互题,这是一道 AES-CBC 的已知文本攻击题目,我们需要构造一条密文,使得密文经过解密后出现一条子串 Administrator。
由于 CBC 加密只有相邻的两个块有异或关系,我们可以先通过加密得到含有 administrator 的循环密文,其循环节为 \(16\)(CBC加密的块大小),找到对应字节所在块的位置,进行遍历搜索解密。
考虑 AES 编码只存在十六进制数,因此找到一个十六进制两位数对其做替换解密,直到出现子串 Administrator,即是我们所需要的密文,最后发现替换第 \(72,73\) 位可以做到。
代码如下(非预期解)
from pwn import *
from gmpy2 import *
from sympy import *
con = remote('challenges.hazmat.buptmerak.cn', 21815)
ls = [b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'a', b'b', b'c', b'd', b'e', b'f']
t = con.recvline()
t = con.recvline()
t = con.recvline()
t = con.recvline()
t = con.recvline()
t = con.recv()
con.sendline("E")
t = con.recv()
t = b'administrator' + b'\x03' * 3 + b'administrator'+ b'\x03' * 3 + b'administrator'
con.sendline(str(t))
t = con.recv()
Administ = t[17:]
Administ = Administ[:len(Administ) - 1]
for i in ls:
for j in ls:
A = Administ
ad = A[:72] + i + j + A[74:]
t = con.recvline()
t = con.recvline()
t = con.recvline()
t = con.recvline()
t = con.recv()
con.sendline("D")
t = con.recv()
c = str(ad, "utf-8")
con.sendline(c)
t = con.recvline()
ans = t[20:]
if (b'Administrator' in ans):
t = con.recvline()
t = con.recvline()
t = con.recvline()
t = con.recvline()
t = con.recv()
con.sendline("G")
t = con.recv()
con.sendline(str(c))
t = con.recv()
print(t)
break
Conclusion
对于新生赛而言,题目难度是比较高的,\(8\) 题里面我只做了 \(5\) 题(在此期间和 ACM 队友去集训了一天,不然可能还能做一道题),甚至不乏有 ezECC 这种题目解法与其他题目完全重合的这种题,同时也见识到了各种密码题的解题思路,收益还是比较大的,虽然我想学密码学的原因有一部分是数学,但我希望不要所有的密码题都是数学,ezRSA 中对搜索的考察就是很不错的一点。
成就:在比赛期间快把 Nanachi 和 PYthok 烦死了(不会做题导致的),现在其实也是什么都不会呐,还是任重而道远啊。
TSCTF-J2024 密码向WP(5/8)的更多相关文章
- WordPress用户导入Drupal7并登录
用户导入比较简单.使用Feeds模块中的Feeds Import工具就行. 不过有个不好地方的,导入前密码是明文,导入后该模块会自动转换为Drupal加密后的密码. 这需要导入后原wp的用户也能登录d ...
- hackthebox通关手记(持续更新)
简介: 花了点时间弄了几道题目.以前我是用windows渗透居多,在kali linux下渗透测试一直不怎么习惯.通过这几天做这些题目感觉顺手多了.有些题目脑洞也比较大,感觉很多也不适合于实际的环境 ...
- WP 手机Lumia 820 锁屏密码的破解研究
Windows Phone lumia 手机锁屏密码的破解研究 大家好今天给大家分享一个最新研究案例, 近日笔者接Nokia Lumia 820, 由于客户密码失误太多,导致锁屏23000余分 ...
- 实验吧—密码学——WP之 古典密码
首先我们研究题目 1.古典密码 2.key值的固定结构 3.加密方式就在谜面里 首先看到这些数字我们就能想到ASCII,而且做题多了就能看出123是{:125是},所以得到字符串如下 OCU{CFTE ...
- 实验吧—密码学——WP之 传统知识+古典密码
仔细读题,发现有价值的信息: 几个不同的年份:“+甲子”:key值结构 首先我们并不知道这些年份在这里代表着什么,那么我们就去百度一下发现了如下所示的六十甲子顺序表 而在表中每个年份前都有数字,将他们 ...
- Bugku-不可破译的密码[wp]
一 题目分析 flag.txt cipher.txt (1)密码表形式和维吉尼亚密码一样 (2)看到504Q0304 很容易想到 504B0304 Zip文件头. 二 解题步骤 2.1 解密密文 根据 ...
- Android,ios,WP三大手机系统对比
从前,我以为.一个手机系统只是一个系统的UI风格,没什么不同的.然而,在我混合使用这三个手机系统之后,才明白,一个手机系统远不只一个UI那么简单,而真的是可以称之为一个“生态”. 首先祭出三台经典设备 ...
- 【WP开发】加密篇:双向加密
说起双向加密,如果以前在.NET开发中弄过加/解密的朋友都不会陌生,常用的算法有DES.AES等.在RT应用程序中,也提供了加密相关的API,算法自然是一样的,只是API的封装方式不同罢了,因为RT不 ...
- wp手机 htc x310e
入手htc x310e 手机不错,用着流畅 不习惯,已升到wp7.8,系统限制还是有些需要的功能没有,比如说短信拦截什么的 我需要的常用软件少 转手了 1 注销windows live? 设置--应用 ...
- MySQL数据库忘记root密码解决办法
MySQL数据库忘记root密码解决办法 1.在运行输入services.msc打开服务窗体,找到MYSQL服务.右键停止将其关闭.如图:
随机推荐
- 海康威视测速&闪速测速
海康威视64g 闪速128g
- 使用 SpanMetrics Connector 将 OpenTelemetry 跟踪转换为指标
原文:https://last9.io/blog/convert-opentelemetry-traces-to-metrics-using-spanconnector/ 如果您已经实施了跟踪但缺乏强 ...
- 【Jmeter】之批量处理多接口压力测试
一.需求前提 1.有以下三个步骤: ①创建单据 ②审核单据 ③确认单据 让三个相关接口进行一连串批量请求操作,直到所有批量数据确认单据成功. 二.测试计划 需要说明的是,因为每个接口可能处理的不太一样 ...
- 日志与追踪的完美融合:OpenTelemetry MDC 实践指南
前言 在前面两篇实战文章中: OpenTelemetry 实战:从零实现分布式链路追踪 OpenTelemetry 实战:从零实现应用指标监控 覆盖了可观测中的指标追踪和 metrics 监控,下面理 ...
- 深度学习批次(batch)、迭代(iteration)、周期(epoch)、前向传播(forward propagation)、反向传播(backward propagation)、学习率(learning rate)概念解释
虽然现在应该是已经熟练掌握这些基础概念的时候,但是我是鱼的记忆,上一秒的事情,下一秒就忘了,除非是重要的人的重要的事情,呜呜呜呜,我这个破脑子. 还是写一下吧,直接GPT出来的(人类之光,欢呼~). ...
- SQL Server – 执行计划和各种 join 方式 (Execution plan & Join Pattern)
前言 我几乎从来没有遇到过性能问题, 毕竟项目真的太小了. 一般上只要用常识去建 index 就可以了. 但是这并不阻碍我对知识的追求. 这篇是关于一些性能优化和原理的内容. 纯属学习, 希望未来有机 ...
- Figma 学习笔记 – Frame
Frame = <div> Frame 就类似 HTML 中的 div, 它和形状 rectangle 特性上蛮相识的, 但是使用场景其实差很多, 所以不要搞错哦. (除了图片很少会用到 ...
- 基于DPAPI+RDP技术实现本地打开远程程序,并映射到本地机器桌面上
本教程使用工具所使用的环境说明: 启动器开发工具:VS2022 启动器所用客户端技术:.NET 8 + WPF 启动器其他技术:DPAPI 启动器发布的可执行程序,系统要求:Windows 7以及以上 ...
- Resource Acquisition Is Initialization
在 C++ 中,资源获取即初始化(RAII, Resource Acquisition Is Initialization)是一种管理资源的编程惯用法.其核心思想是将资源的获取和释放绑定到对象的生命周 ...
- Java日期时间API系列35-----Jdk8中java.time包中的新的日期时间API类应用,微秒和纳秒等更精确的时间格式化和解析。
通过Java日期时间API系列1-----Jdk7及以前的日期时间类中得知,Java8以前除了java.sql.Timestamp扩充纳秒,其他类最大只精确到毫秒:Java8 time包所有相关类都支 ...