祥云杯网络安全大赛初赛 2022
怎么说呢,这比赛简单题又太简单,难题的paper实践又太难,只会套轮子,就随便记录一下。
trace
给了gcd函数的整个debug流程,并且该算法是可逆的,所以逆回去计算phi就行。
from Crypto.Util.number import long_to_bytes
from gmpy2 import invert
c = 64885875317556090558238994066256805052213864161514435285748891561779867972960805879348109302233463726130814478875296026610171472811894585459078460333131491392347346367422276701128380739598873156279173639691126814411752657279838804780550186863637510445720206103962994087507407296814662270605713097055799853102
n = 113793513490894881175568252406666081108916791207947545198428641792768110581083359318482355485724476407204679171578376741972958506284872470096498674038813765700336353715590069074081309886710425934960057225969468061891326946398492194812594219890553185043390915509200930203655022420444027841986189782168065174301
e = 65537
f = open('trace.txt','r')
data = f.read().split('\n')[::-1]
def attack_phi(c):
a = 1
b = 0
for word in c:
if 'a, b =' in word:
b ,a = a,b
if 'rshift1(a)' in word:
a<<=1
if 'rshift1(b)' in word:
b<<=1
if 'a = a - b' in word:
a=a+b
return a
# 最后的a就是phi
phi = attack_phi(data)
d = invert(e,phi)
print(long_to_bytes(pow(c,d,n)))
little little fermat
费马分解得到p,q;x为p-1的倍数,就取p-1就对了。
from Crypto.Util.number import *
from gmpy2 import *
n = 141321067325716426375483506915224930097246865960474155069040176356860707435540270911081589751471783519639996589589495877214497196498978453005154272785048418715013714419926299248566038773669282170912502161620702945933984680880287757862837880474184004082619880793733517191297469980246315623924571332042031367393
c = 81368762831358980348757303940178994718818656679774450300533215016117959412236853310026456227434535301960147956843664862777300751319650636299943068620007067063945453310992828498083556205352025638600643137849563080996797888503027153527315524658003251767187427382796451974118362546507788854349086917112114926883
# 费马分解n
def fermat(num):
x = iroot(num, 2)[0]
if x * x < num:
x += 1
# y^2 = x^2 - num
while (True):
y2 = x * x - num
y = iroot(y2, 2)[0]
if y * y == y2:
break
x += 1
result = [int(x + y), int(x - y)]
return result
l = fermat(n)
p = l[0]
q = l[1]
x = p-1
e = 65537
d = invert(e,(p-1)*(q-1))
tmp = pow(c,d,n)
print(long_to_bytes(tmp^(x**2)))
fill
lcg逆一下,然后背包格。
# sage
M = [19620578458228, 39616682530092, 3004204909088, 6231457508054, 3702963666023, 48859283851499, 4385984544187, 11027662187202, 18637179189873, 29985033726663, 20689315151593, 20060155940897, 46908062454518, 8848251127828, 28637097081675, 35930247189963, 20695167327567, 36659598017280, 10923228050453, 29810039803392, 4443991557077, 31801732862419, 23368424737916, 15178683835989, 34641771567914, 44824471397533, 31243260877608, 27158599500744, 2219939459559, 20255089091807, 24667494760808, 46915118179747]
S = 492226042629702
n = len(M)
L = matrix.zero(n + 1)
for row, x in enumerate(M):
L[row, row] = 2
L[row, -1] = x
L[-1, :] = 1
L[-1, -1] = S
res = L.LLL()
print(res)
from Crypto.Util.number import *
from hashlib import *
nbits = 32
M = [19621141192340, 39617541681643, 3004946591889, 6231471734951, 3703341368174, 48859912097514, 4386411556216, 11028070476391, 18637548953150, 29985057892414, 20689980879644, 20060557946852, 46908191806199, 8849137870273, 28637782510640, 35930273563752, 20695924342882, 36660291028583, 10923264012354, 29810154308143, 4444597606142, 31802472725414, 23368528779283, 15179021971456, 34642073901253, 44824809996134, 31243873675161, 27159321498211, 2220647072602, 20255746235462, 24667528459211, 46916059974372]
s0,s1,s2 = 562734112,859151551,741682801
n = 991125622
m = (s2-s1)*inverse(s1-s0,n)%n
c = (s1-s0*m)%n
s = [0] * nbits
s[0] = s0
for i in range(1, nbits):
s[i] = (s[i-1]*m+c)%n
print(s)
for t in range(nbits):
M[t] = M[t] - s[t]
print(M)
# 注意是反向量
short = '00101000011000010001000010011011'
short2 = ''
for i in short:
if i == '0':
short2 = short2 + '1'
else:
short2 = short2 +'0'
print(short2)
print(len(short2))
num = int(short2,2)
print(sha256(str(num).encode()).hexdigest())
babyDLP
CryptoCTF-sidestep,改一两个地方就能打成功了。
common_rsa
轮子1
轮子2
两个都行但是都得改改\(\delta\)和某些位置的代码写法。
leak_rsa
k的确定可以用背包,然后用branch_and_prune,把check k的函数范围改为背包得到的最优k周围搜索。
import logging
import os
import sys
from itertools import product
from Crypto.Util.number import *
from gmpy2 import powmod
import tqdm
from sage.all import Zmod
path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(os.path.abspath(__file__)))))
if sys.path[1] != path:
sys.path.insert(1, path)
from shared import bits_to_int_le
from shared import int_to_bits_le
from shared.partial_integer import PartialInteger
# Section 3.
def _tau(x):
i = 0
while x % 2 == 0:
x //= 2
i += 1
return i
# Section 2.
def _find_k(N, e, d_bits):
best_match_count = 0
best_k = None
best_d__bits = None
# Enumerate every possible k value.
for k in range(1972411342-50, 1972411342+50):
d_ = (k * (N + 1) + 1) // e
d__bits = int_to_bits_le(d_, len(d_bits))
match_count = 0
# Only check the most significant half.
for i in range(len(d_bits) // 2 + 2, len(d_bits)):
if d_bits[i] == d__bits[i]:
match_count += 1
# Update the best match for d.
if match_count > best_match_count:
best_match_count = match_count
best_k = k
best_d__bits = d__bits
return best_k, best_d__bits
# Section 2.
def _correct_msb(d_bits, d__bits):
# Correcting the most significant half of d.
for i in range(len(d_bits) // 2 + 2, len(d_bits)):
d_bits[i] = d__bits[i]
# Section 3.
def _correct_lsb(e, d_bits, exp):
# Correcting the least significant bits of d.
# Also works for dp and dq, just with a different exponent.
inv = powmod(e, -1, 2 ** exp)
for i in range(exp):
d_bits[i] = (inv >> i) & 1
# Branch and prune for the case with p, q, and d bits known.
def _branch_and_prune_pqd(N, e, k, tk, p, q, d, p_, q_, i):
if i == len(p) or i == len(q):
yield p_, q_
else:
d_ = bits_to_int_le(d, i)
c1 = ((N - p_ * q_) >> i) & 1
c2 = ((k * (N + 1) + 1 - k * (p_ + q_) - e * d_) >> (i + tk)) & 1
p_prev = p[i]
q_prev = q[i]
d_prev = 0 if i + tk >= len(d) else d[i + tk]
p_possible = [0, 1] if p_prev is None else [p_prev]
q_possible = [0, 1] if q_prev is None else [q_prev]
d_possible = [0, 1] if d_prev is None else [d_prev]
for p_bit, q_bit, d_bit in product(p_possible, q_possible, d_possible):
# Addition modulo 2 is just xor.
if p_bit ^ q_bit == c1 and d_bit ^ p_bit ^ q_bit == c2:
p[i] = p_bit
q[i] = q_bit
if i + tk < len(d):
d[i + tk] = d_bit
yield from _branch_and_prune_pqd(N, e, k, tk, p, q, d, p_ | (p_bit << i), q_ | (q_bit << i), i + 1)
p[i] = p_prev
q[i] = q_prev
if i + tk < len(d):
d[i + tk] = d_prev
def factorize_pqd(N, e, p, q, d):
"""
Factorizes n when some bits of p, q, and d are known.
If at least 42% of the bits are known, this attack should be polynomial time, however, smaller percentages might still work.
More information: Heninger N., Shacham H., "Reconstructing RSA Private Keys from Random Key Bits"
:param N: the modulus
:param e: the public exponent
:param p: partial p (PartialInteger)
:param q: partial q (PartialInteger)
:param d: partial d (PartialInteger)
:return: a tuple containing the prime factors
"""
assert p.bit_length == q.bit_length, "p and q should be of equal bit length."
# p_bits = p
p_bits = p.to_bits_le()
for i, b in enumerate(p_bits):
p_bits[i] = None if b == '?' else int(b, 2)
# q_bits = q
q_bits = q.to_bits_le()
for i, b in enumerate(q_bits):
q_bits[i] = None if b == '?' else int(b, 2)
# p and q are prime, odd.
p_bits[0] = 1
q_bits[0] = 1
d_bits = d.to_bits_le()
for i, b in enumerate(d_bits):
d_bits[i] = None if b == '?' else int(b, 2)
# Because e is small, k can be found by brute force.
# logging.info("Brute forcing k...")
print("Brute forcing k...")
k, d__bits = _find_k(N, e, d_bits)
# logging.info(f"Found k = {k}")
print(f"Found k = {k}")
_correct_msb(d_bits, d__bits)
tk = _tau(k)
_correct_lsb(e, d_bits, 2 + tk)
# logging.info("Starting branch and prune algorithm...")
print("Starting branch and prune algorithm...")
for p, q in _branch_and_prune_pqd(N, e, k, tk, p_bits, q_bits, d_bits, p_bits[0], q_bits[0], 1):
if p * q == N:
return int(p), int(q)
n = 73380160475470842653695210816683702314062827937540324056880543809752271506601290265975543542548117392788987830919581511428492717214125296973338501980504384307279414528799452106399062576988406269897425829853390463840834798274139351938197666753546672052277640048588091137812362810008344723302886421059831149393
e = 3116872133
c = 69574121902821459446683688068339366486115223765903849266663001038736496551168104587683366853482649748413400537793260948337629422998336301256862519087984048032673577462034223842650399943613576577927825123830629917138007035313624847266208032195071033675853881447717750353382112841885318776240405314057286867952
hint1 = {120: '0', 401: '0', 58: '1', 420: '0', 192: '1', 164: '0', 100: '0', 425: '1', 227: '0', 497: '0', 284: '0',
110: '1', 257: '0', 31: '1', 68: '0', 2: '1', 206: '0', 174: '1', 326: '0', 320: '0', 498: '1', 50: '1',
7: '0', 128: '1', 54: '1', 15: '1', 222: '0', 166: '1', 496: '1', 151: '1', 317: '0', 449: '1', 181: '1',
288: '1', 311: '1', 80: '1', 69: '1', 410: '1', 127: '1', 308: '1', 39: '0', 435: '0', 258: '0', 235: '1',
94: '1', 93: '1', 412: '0', 427: '0', 352: '1', 123: '0', 25: '0', 316: '1', 3: '0', 88: '1', 390: '0',
72: '1', 450: '1', 397: '0', 309: '1', 487: '1', 207: '0', 234: '0', 144: '1', 229: '1', 48: '1', 506: '0',
253: '1', 86: '0', 384: '0', 428: '0', 359: '1', 104: '0', 339: '0', 142: '0', 452: '1', 480: '0', 224: '1',
310: '1', 98: '1', 508: '0', 133: '0', 90: '1', 170: '0', 146: '0', 101: '1', 416: '1', 460: '1', 387: '0',
67: '0', 285: '0', 213: '1', 162: '1', 14: '0', 485: '1', 413: '1', 312: '1', 458: '0', 75: '0', 242: '1',
177: '1', 30: '1', 501: '0', 434: '1', 456: '0', 264: '0', 407: '0', 135: '1', 84: '0', 476: '0', 471: '1',
430: '1', 191: '0', 176: '0', 29: '1', 156: '0', 26: '0', 322: '1', 388: '1', 364: '1', 321: '1', 351: '0',
230: '1', 345: '0', 432: '1', 36: '0', 296: '1', 79: '0', 23: '0', 290: '1', 117: '0', 507: '1', 421: '0',
274: '0', 6: '1', 327: '1', 204: '1', 383: '0', 305: '1', 113: '0', 334: '0', 85: '1', 511: '1', 464: '1',
491: '0', 370: '0', 92: '0', 495: '0', 279: '1', 346: '1', 16: '1', 44: '1', 24: '0', 466: '1', 87: '0',
243: '0', 461: '0', 379: '0', 256: '0', 473: '1', 17: '0', 276: '1', 147: '1', 187: '0', 112: '1', 218: '1',
78: '1', 411: '1', 343: '0', 10: '1', 271: '1', 378: '0', 492: '0', 269: '1', 291: '0', 289: '0', 132: '1',
9: '1', 408: '0', 398: '1', 468: '1', 124: '1', 236: '0', 377: '1', 83: '0'}
hint2 = {125: '0', 86: '1', 8: '0', 498: '1', 311: '0', 93: '0', 385: '0', 315: '1', 300: '1', 454: '0', 152: '0',
205: '0', 400: '1', 348: '1', 18: '1', 154: '0', 51: '1', 435: '0', 25: '1', 430: '0', 72: '1', 136: '0',
294: '0', 466: '0', 388: '0', 428: '0', 440: '1', 250: '1', 506: '0', 48: '0', 270: '1', 318: '0', 107: '0',
327: '1', 474: '0', 325: '0', 281: '0', 392: '0', 473: '1', 13: '1', 90: '0', 278: '0', 425: '0', 109: '1',
423: '1', 412: '1', 190: '1', 171: '0', 475: '1', 441: '1', 336: '0', 371: '0', 323: '0', 22: '1', 469: '0',
451: '0', 438: '0', 203: '1', 121: '0', 52: '1', 494: '1', 399: '0', 314: '0', 24: '1', 183: '0', 492: '1',
246: '1', 108: '1', 379: '0', 460: '1', 56: '0', 372: '1', 313: '1', 44: '0', 237: '1', 12: '0', 6: '0',
204: '1', 80: '1', 339: '1', 296: '0', 483: '0', 402: '0', 67: '0', 338: '1', 116: '0', 406: '1', 218: '0',
115: '0', 301: '0', 490: '1', 502: '0', 343: '1', 46: '1', 321: '0', 231: '1', 88: '0', 404: '1', 426: '0',
344: '0', 123: '1', 463: '0', 45: '1', 461: '1', 1: '0', 229: '0', 28: '1', 274: '1', 134: '1', 104: '1',
21: '0', 256: '0', 471: '1', 157: '0', 217: '1', 158: '0', 307: '1', 26: '0', 255: '0', 386: '1', 373: '0',
114: '1', 360: '0', 148: '1', 383: '1', 63: '0', 19: '1', 472: '0', 201: '1', 262: '1', 47: '0', 221: '0',
310: '0', 352: '1', 224: '1', 185: '0', 214: '1', 285: '1', 410: '0', 455: '0', 445: '0', 464: '0', 284: '1',
503: '1', 298: '1', 449: '0', 477: '0', 376: '0', 16: '0', 133: '0', 177: '1', 210: '0', 364: '1', 163: '1',
213: '1', 295: '1', 111: '1', 458: '0', 146: '0', 244: '0', 261: '1', 508: '1', 106: '0', 112: '1', 120: '0',
156: '1', 303: '0', 259: '1', 35: '0', 444: '0', 215: '1', 304: '0', 140: '0', 351: '0', 443: '0'}
hint3 = {891: '0', 74: '0', 129: '0', 477: '0', 880: '1', 57: '0', 473: '0', 289: '1', 361: '1', 1012: '0', 529: '0',
294: '1', 174: '1', 500: '0', 257: '1', 392: '1', 405: '1', 11: '0', 763: '1', 637: '1', 564: '0', 941: '1',
923: '1', 1014: '1', 670: '1', 558: '0', 304: '1', 444: '1', 716: '0', 208: '0', 130: '1', 634: '1', 661: '0',
862: '0', 412: '1', 796: '1', 761: '1', 113: '1', 752: '0', 818: '0', 797: '1', 390: '1', 337: '0', 133: '1',
367: '1', 470: '1', 345: '1', 170: '1', 312: '0', 624: '1', 53: '1', 75: '1', 281: '1', 522: '1', 100: '0',
554: '1', 583: '1', 16: '1', 836: '0', 715: '1', 450: '0', 484: '0', 876: '0', 165: '0', 842: '0', 62: '0',
442: '1', 927: '0', 586: '1', 399: '1', 227: '0', 886: '1', 663: '0', 947: '0', 906: '1', 377: '0', 246: '1',
365: '0', 177: '1', 59: '1', 63: '0', 936: '1', 144: '0', 416: '1', 228: '1', 366: '0', 117: '0', 78: '0',
717: '1', 14: '0', 800: '1', 47: '0', 80: '0', 34: '0', 662: '1', 970: '0', 986: '1', 287: '1', 597: '0',
783: '0', 805: '1', 112: '1', 671: '1', 540: '1', 153: '1', 577: '1', 543: '0', 414: '0', 123: '1', 626: '1',
452: '1', 810: '1', 30: '0', 905: '0', 602: '1', 537: '1', 374: '0', 408: '1', 434: '0', 137: '1', 532: '0',
397: '0', 333: '1', 258: '1', 359: '1', 134: '1', 322: '1', 653: '0', 1018: '0', 639: '1', 40: '1', 826: '1',
489: '0', 5: '0', 858: '0', 44: '1', 516: '0', 149: '0', 945: '0', 106: '1', 694: '0', 221: '0', 207: '0',
186: '1', 316: '0', 449: '1', 297: '1', 276: '0', 103: '0', 437: '0', 802: '0', 108: '1', 921: '1', 427: '0',
728: '1', 879: '0', 953: '0', 51: '1', 459: '0', 37: '0', 559: '0', 610: '1', 341: '0', 299: '0', 952: '0',
201: '0', 327: '0', 741: '1', 253: '1', 310: '1', 946: '1', 696: '0', 398: '1', 266: '1', 829: '0', 908: '0',
469: '0', 873: '1', 658: '0', 798: '1', 54: '0', 621: '0', 238: '0', 654: '1', 205: '0', 925: '0', 391: '1',
480: '0', 4: '0', 598: '0', 677: '0', 142: '1', 606: '0', 118: '0', 164: '0', 973: '1', 347: '0', 159: '1',
307: '1', 83: '1', 668: '1', 675: '0', 924: '1', 191: '1', 890: '0', 352: '1', 965: '1', 692: '1', 782: '1',
817: '1', 889: '1', 515: '1', 433: '0', 356: '0', 845: '1', 104: '0', 18: '0', 979: '0', 426: '0', 785: '1',
546: '0', 52: '0', 55: '0', 824: '1', 704: '1', 510: '1', 710: '0', 1022: '0', 647: '0', 465: '1', 245: '0',
850: '1', 657: '0', 1007: '0', 807: '1', 158: '1', 328: '0', 292: '1', 355: '1', 596: '0', 275: '1', 371: '0',
1004: '0', 594: '0', 384: '1', 446: '1', 7: '0', 994: '1', 616: '1', 317: '0', 305: '0', 151: '1', 400: '0',
900: '1', 203: '0', 563: '1', 745: '1', 536: '1', 726: '0', 751: '1', 402: '1', 116: '0', 781: '1', 988: '0',
768: '1', 688: '1', 954: '1', 976: '1', 868: '1', 723: '1', 131: '1', 794: '0', 513: '0', 914: '1', 641: '1',
319: '0', 629: '1', 620: '1', 711: '0', 601: '0', 531: '0', 393: '0', 168: '0', 132: '0', 17: '0', 950: '0',
488: '0', 679: '0', 568: '0', 43: '1', 545: '1', 217: '0', 680: '1', 501: '1', 1008: '0', 514: '0', 746: '0',
187: '0', 436: '1', 336: '1', 139: '1', 338: '0', 695: '1', 300: '0', 584: '1', 152: '0', 828: '1', 251: '0',
691: '1', 296: '1', 128: '0', 394: '1', 655: '1', 544: '1', 58: '0', 313: '1', 565: '1', 685: '1', 720: '0',
178: '1', 667: '0', 403: '1', 697: '1', 138: '1', 659: '0', 960: '0', 454: '0', 271: '0', 33: '0', 295: '0',
600: '0', 579: '1', 68: '1', 211: '1', 82: '1', 114: '1', 209: '0', 226: '0', 753: '0', 874: '0', 903: '1',
358: '0', 141: '0', 236: '1'}
p = list('?' * 512)
q = list('?' * 512)
d = list('?' * 1024)
print(len(hint1), len(hint2), len(hint3))
for i in hint1:
p[i] = hint1[i]
for i in hint2:
q[i] = hint2[i]
for i in hint3:
d[i] = hint3[i]
p_bits = ''.join(p)
q_bits = ''.join(q)
d_bits = ''.join(d)
p_bits = PartialInteger.from_bits_be(p_bits)
q_bits = PartialInteger.from_bits_be(q_bits)
d_bits = PartialInteger.from_bits_be(d_bits)
p, q = factorize_pqd(n, e, p_bits, q_bits, d_bits)
phi = (p - 1) * (q - 1)
d = inverse(e, phi)
print(long_to_bytes(pow(c, d, n)))