Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

这个Course里有很大一部分都是关于RSA加密的。关于RSA的基本原理以及基本的攻击方法可以看我的另一篇博客:RSA加解密以及攻击方法

Modular Exponentiation

image-20250603203113226

1
2
print(pow(101,17,22663))
# 19906

Public Keys

image-20250603203242869

1
2
print(pow(12,65537,17*23))
# 301

Euler’s Totient

image-20250603203534493

1
2
3
4
5
p = 857504083339712752489993810777
q = 1029224947942998075080348647219
phi = (p-1)*(q-1)
print(phi)
# 882564595536224140639625987657529300394956519977044270821168

Private Keys

image-20250603204109019

1
2
3
4
5
6
7
p = 857504083339712752489993810777
q = 1029224947942998075080348647219
phi = (p-1)*(q-1)
e = 65537
d = pow(e,-1,phi)
print(d)
# 121832886702415731577073962957377780195510499965398469843281

RSA Decryption

image-20250603204310596

不难发现这个N就是前几道题给的p,q的乘积。

1
2
3
4
5
6
7
8
9
10
11
p = 857504083339712752489993810777
q = 1029224947942998075080348647219
N = 882564595536224140639625987659416029426239230804614613279163
assert N == p*q
phi = (p-1)*(q-1)
e = 65537
d = pow(e,-1,phi)
c = 77578995801157823671636298847186723593814843845525223303932
m = pow(c,d,N)
print(m)
# 13371337

RSA Signatures

image-20250603204620258

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from Crypto.Hash import SHA256
from Crypto.Util.number import bytes_to_long

N = 15216583654836731327639981224133918855895948374072384050848479908982286890731769486609085918857664046075375253168955058743185664390273058074450390236774324903305663479046566232967297765731625328029814055635316002591227570271271445226094919864475407884459980489638001092788574811554149774028950310695112688723853763743238753349782508121985338746755237819373178699343135091783992299561827389745132880022259873387524273298850340648779897909381979714026837172003953221052431217940632552930880000919436507245150726543040714721553361063311954285289857582079880295199632757829525723874753306371990452491305564061051059885803
d = 11175901210643014262548222473449533091378848269490518850474399681690547281665059317155831692300453197335735728459259392366823302405685389586883670043744683993709123180805154631088513521456979317628012721881537154107239389466063136007337120599915456659758559300673444689263854921332185562706707573660658164991098457874495054854491474065039621922972671588299315846306069845169959451250821044417886630346229021305410340100401530146135418806544340908355106582089082980533651095594192031411679866134256418292249592135441145384466261279428795408721990564658703903787956958168449841491667690491585550160457893350536334242689

message = b"crypto{Immut4ble_m3ssag1ng}"

h = SHA256.new(message).digest()

h_int = bytes_to_long(h)

signature = pow(h_int, d, N)

print(signature)
# 13480738404590090803339831649238454376183189744970683129909766078877706583282422686710545217275797376709672358894231550335007974983458408620258478729775647818876610072903021235573923300070103666940534047644900475773318682585772698155617451477448441198150710420818995347235921111812068656782998168064960965451719491072569057636701190429760047193261886092862024118487826452766513533860734724124228305158914225250488399673645732882077575252662461860972889771112594906884441454355959482925283992539925713424132009768721389828848907099772040836383856524605008942907083490383109757406940540866978237471686296661685839083475

Factoring

image-20250603211340033

使用

http://www.factordb.com/index.php

得到p,q

1
2
p = 19704762736204164635843
q = 25889363174021185185929

Monoprime

image-20250603211604925

1
2
3
4
n = 171731371218065444125482536302245915415603318380280392385291836472299752747934607246477508507827284075763910264995326010251268493630501989810855418416643352631102434317900028697993224868629935657273062472544675693365930943308086634291936846505861203914449338007760990051788980485462592823446469606824421932591                                                                  
e = 65537
ct = 161367550346730604451454756189028938964941280347662098798775466019463375610700074840105776873791605070092554650190486030367121011578171525759600774739890458414593857709994072516290998135846956596662071379067305011746842247628316996977338024343628757374524136260758515864509435302781735938531030576289086798942

1
2
3
4
5
6
7
8
9
10
from Crypto.Util.number import long_to_bytes, inverse

n = 171731371218065444125482536302245915415603318380280392385291836472299752747934607246477508507827284075763910264995326010251268493630501989810855418416643352631102434317900028697993224868629935657273062472544675693365930943308086634291936846505861203914449338007760990051788980485462592823446469606824421932591
e = 65537
ct = 161367550346730604451454756189028938964941280347662098798775466019463375610700074840105776873791605070092554650190486030367121011578171525759600774739890458414593857709994072516290998135846956596662071379067305011746842247628316996977338024343628757374524136260758515864509435302781735938531030576289086798942

d = inverse(e, n-1)
m = pow(ct, d, n)
print(long_to_bytes(m))
# b'crypto{0n3_pr1m3_41n7_pr1m3_l0l}'

Manyprime

image-20250603212339988

可以使用sageecm.factor()函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from Crypto.Util.number import long_to_bytes
from sage.all import *

n = 580642391898843192929563856870897799650883152718761762932292482252152591279871421569162037190419036435041797739880389529593674485555792234900969402019055601781662044515999210032698275981631376651117318677368742867687180140048715627160641771118040372573575479330830092989800730105573700557717146251860588802509310534792310748898504394966263819959963273509119791037525504422606634640173277598774814099540555569257179715908642917355365791447508751401889724095964924513196281345665480688029639999472649549163147599540142367575413885729653166517595719991872223011969856259344396899748662101941230745601719730556631637
e = 65537
ct = 320721490534624434149993723527322977960556510750628354856260732098109692581338409999983376131354918370047625150454728718467998870322344980985635149656977787964380651868131740312053755501594999166365821315043312308622388016666802478485476059625888033017198083472976011719998333985531756978678758897472845358167730221506573817798467100023754709109274265835201757369829744113233607359526441007577850111228850004361838028842815813724076511058179239339760639518034583306154826603816927757236549096339501503316601078891287408682099750164720032975016814187899399273719181407940397071512493967454225665490162619270814464

factors = ecm.factor(n)

phi = prod([f - 1 for f in factors])

d = inverse_mod(e, phi)

m = pow(ct, d, n)

flag = long_to_bytes(m)
print(flag.decode())

# crypto{700_m4ny_5m4ll_f4c70r5}

Salty

image-20250603213426668

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/usr/bin/env python3

from Crypto.Util.number import getPrime, inverse, bytes_to_long, long_to_bytes

e = 1
d = -1

while d == -1:
p = getPrime(512)
q = getPrime(512)
phi = (p - 1) * (q - 1)
d = inverse(e, phi)

n = p * q

flag = b"XXXXXXXXXXXXXXXXXXXXXXX"
pt = bytes_to_long(flag)
ct = pow(pt, e, n)

print(f"n = {n}")
print(f"e = {e}")
print(f"ct = {ct}")

pt = pow(ct, d, n)
decrypted = long_to_bytes(pt)
assert decrypted == flag
1
2
3
n = 110581795715958566206600392161360212579669637391437097703685154237017351570464767725324182051199901920318211290404777259728923614917211291562555864753005179326101890427669819834642007924406862482343614488768256951616086287044725034412802176312273081322195866046098595306261781788276570920467840172004530873767                                                                  
e = 1
ct = 44981230718212183604274785925793145442655465025264554046028251311164494127485

e选的是1,根本没有起到任何加密的效果。

1
2
3
4
5
6
7
from Crypto.Util.number import long_to_bytes
n = 110581795715958566206600392161360212579669637391437097703685154237017351570464767725324182051199901920318211290404777259728923614917211291562555864753005179326101890427669819834642007924406862482343614488768256951616086287044725034412802176312273081322195866046098595306261781788276570920467840172004530873767
e = 1
ct = 44981230718212183604274785925793145442655465025264554046028251311164494127485
flag = long_to_bytes(ct)
print(flag)
# b'crypto{saltstack_fell_for_this!}'

Modulus Inutilis

image-20250603213653670

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/usr/bin/env python3

from Crypto.Util.number import getPrime, inverse, bytes_to_long, long_to_bytes

e = 3
d = -1

while d == -1:
p = getPrime(1024)
q = getPrime(1024)
phi = (p - 1) * (q - 1)
d = inverse(e, phi)

n = p * q

flag = b"XXXXXXXXXXXXXXXXXXXXXXX"
pt = bytes_to_long(flag)
ct = pow(pt, e, n)

print(f"n = {n}")
print(f"e = {e}")
print(f"ct = {ct}")

pt = pow(ct, d, n)
decrypted = long_to_bytes(pt)
assert decrypted == flag
1
2
3
n = 17258212916191948536348548470938004244269544560039009244721959293554822498047075403658429865201816363311805874117705688359853941515579440852166618074161313773416434156467811969628473425365608002907061241714688204565170146117869742910273064909154666642642308154422770994836108669814632309362483307560217924183202838588431342622551598499747369771295105890359290073146330677383341121242366368309126850094371525078749496850520075015636716490087482193603562501577348571256210991732071282478547626856068209192987351212490642903450263288650415552403935705444809043563866466823492258216747445926536608548665086042098252335883
e = 3
ct = 243251053617903760309941844835411292373350655973075480264001352919865180151222189820473358411037759381328642957324889519192337152355302808400638052620580409813222660643570085177957

e选的太小了,且ct也比n小很多,所以直接开3次根就好。

1
2
3
4
5
6
7
8
9
from sympy import root
from Crypto.Util.number import long_to_bytes
n = 17258212916191948536348548470938004244269544560039009244721959293554822498047075403658429865201816363311805874117705688359853941515579440852166618074161313773416434156467811969628473425365608002907061241714688204565170146117869742910273064909154666642642308154422770994836108669814632309362483307560217924183202838588431342622551598499747369771295105890359290073146330677383341121242366368309126850094371525078749496850520075015636716490087482193603562501577348571256210991732071282478547626856068209192987351212490642903450263288650415552403935705444809043563866466823492258216747445926536608548665086042098252335883
e = 3
ct = 243251053617903760309941844835411292373350655973075480264001352919865180151222189820473358411037759381328642957324889519192337152355302808400638052620580409813222660643570085177957

flag = root(ct, e)
print(long_to_bytes(flag))
# b'crypto{N33d_m04R_p4dd1ng}'

Working with Fields

image-20250603215356617

1
2
3
4
p=991
g=209
print(pow(g,-1,p))
# 569

Generators of Groups

image-20250603215534883

设g为$\mathbb{F}_p$的 primitive element,则有

并且

实际上因为费马小定理,所有的元素都满足第一个等式,并且根据拉格朗日定理可以得到所有元素的order都是$p-1$的因数。所以有

利用这个办法我们可以快速判断一个元素是否是primitive element。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from sympy import isprime, factorint

def find_primitive_root(p):
assert isprime(p)
phi = p - 1
factors = factorint(phi).keys()

for g in range(2, p):
is_primitive = True
for q in factors:
if pow(g, phi // q, p) == 1:
is_primitive = False
break
if is_primitive:
return g

p = 28151
primitive = find_primitive_root(p)
print(primitive)
# 7

Computing Public Values

image-20250604125806688

1
2
3
4
5
6
g=2
p=2410312426921032588552076022197566074856950548502459942654116941958108831682612228890093858261341614673227141477904012196503648957050582631942730706805009223062734745341073406696246014589361659774041027169249453200378729434170325843778659198143763193776859869524088940195577346119843545301547043747207749969763750084308926339295559968882457872412993810129130294592999947926365264059284647209730384947211681434464714438488520940127459844288859336526896320919633919
a=972107443837033796245864316200458246846904598488981605856765890478853088246897345487328491037710219222038930943365848626194109830309179393018216763327572120124760140018038673999837643377590434413866611132403979547150659053897355593394492586978400044375465657296027592948349589216415363722668361328689588996541370097559090335137676411595949335857341797148926151694299575970292809805314431447043469447485957669949989090202320234337890323293401862304986599884732815
A=pow(g,a,p)
print(A)
# 1806857697840726523322586721820911358489420128129248078673933653533930681676181753849411715714173604352323556558783759252661061186320274214883104886050164368129191719707402291577330485499513522368289395359523901406138025022522412429238971591272160519144672389532393673832265070057319485399793101182682177465364396277424717543434017666343807276970864475830391776403957550678362368319776566025118492062196941451265638054400177248572271342548616103967411990437357924

Computing Shared Secrets

image-20250604125955514

image-20250604130008091

1
2
3
4
5
6
7
8
9
10
11
g=2
p=2410312426921032588552076022197566074856950548502459942654116941958108831682612228890093858261341614673227141477904012196503648957050582631942730706805009223062734745341073406696246014589361659774041027169249453200378729434170325843778659198143763193776859869524088940195577346119843545301547043747207749969763750084308926339295559968882457872412993810129130294592999947926365264059284647209730384947211681434464714438488520940127459844288859336526896320919633919

A=70249943217595468278554541264975482909289174351516133994495821400710625291840101960595720462672604202133493023241393916394629829526272643847352371534839862030410331485087487331809285533195024369287293217083414424096866925845838641840923193480821332056735592483730921055532222505605661664236182285229504265881752580410194731633895345823963910901731715743835775619780738974844840425579683385344491015955892106904647602049559477279345982530488299847663103078045601

b=12019233252903990344598522535774963020395770409445296724034378433497976840167805970589960962221948290951873387728102115996831454482299243226839490999713763440412177965861508773420532266484619126710566414914227560103715336696193210379850575047730388378348266180934946139100479831339835896583443691529372703954589071507717917136906770122077739814262298488662138085608736103418601750861698417340264213867753834679359191427098195887112064503104510489610448294420720
B=518386956790041579928056815914221837599234551655144585133414727838977145777213383018096662516814302583841858901021822273505120728451788412967971809038854090670743265187138208169355155411883063541881209288967735684152473260687799664130956969450297407027926009182761627800181901721840557870828019840218548188487260441829333603432714023447029942863076979487889569452186257333512355724725941390498966546682790608125613166744820307691068563387354936732643569654017172

shared_secret = pow(A,b,p)
print(shared_secret)
# 1174130740413820656533832746034841985877302086316388380165984436672307692443711310285014138545204369495478725102882673427892104539120952393788961051992901649694063179853598311473820341215879965343136351436410522850717408445802043003164658348006577408558693502220285700893404674592567626297571222027902631157072143330043118418467094237965591198440803970726604537807146703763571606861448354607502654664700390453794493176794678917352634029713320615865940720837909466

Deriving Symmetric Keys

image-20250604130537851

image-20250604130603716

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
import hashlib
import os
from secret import shared_secret

FLAG = b'crypto{????????????????????????????}'


def encrypt_flag(shared_secret: int):
# Derive AES key from shared secret
sha1 = hashlib.sha1()
sha1.update(str(shared_secret).encode('ascii'))
key = sha1.digest()[:16]
# Encrypt flag
iv = os.urandom(16)
cipher = AES.new(key, AES.MODE_CBC, iv)
ciphertext = cipher.encrypt(pad(FLAG, 16))
# Prepare data to send
data = {}
data['iv'] = iv.hex()
data['encrypted_flag'] = ciphertext.hex()
return data


print(encrypt_flag(shared_secret))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
import hashlib


def is_pkcs7_padded(message):
padding = message[-message[-1]:]
return all(padding[i] == len(padding) for i in range(0, len(padding)))


def decrypt_flag(shared_secret: int, iv: str, ciphertext: str):
# Derive AES key from shared secret
sha1 = hashlib.sha1()
sha1.update(str(shared_secret).encode('ascii'))
key = sha1.digest()[:16]
# Decrypt flag
ciphertext = bytes.fromhex(ciphertext)
iv = bytes.fromhex(iv)
cipher = AES.new(key, AES.MODE_CBC, iv)
plaintext = cipher.decrypt(ciphertext)

if is_pkcs7_padded(plaintext):
return unpad(plaintext, 16).decode('ascii')
else:
return plaintext.decode('ascii')


shared_secret = ?
iv = ?
ciphertext = ?

print(decrypt_flag(shared_secret, iv, ciphertext))

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
import hashlib


def is_pkcs7_padded(message):
padding = message[-message[-1]:]
return all(padding[i] == len(padding) for i in range(0, len(padding)))


def decrypt_flag(shared_secret: int, iv: str, ciphertext: str):
# Derive AES key from shared secret
sha1 = hashlib.sha1()
sha1.update(str(shared_secret).encode('ascii'))
key = sha1.digest()[:16]
# Decrypt flag
ciphertext = bytes.fromhex(ciphertext)
iv = bytes.fromhex(iv)
cipher = AES.new(key, AES.MODE_CBC, iv)
plaintext = cipher.decrypt(ciphertext)

if is_pkcs7_padded(plaintext):
return unpad(plaintext, 16).decode('ascii')
else:
return plaintext.decode('ascii')

g=2
p=2410312426921032588552076022197566074856950548502459942654116941958108831682612228890093858261341614673227141477904012196503648957050582631942730706805009223062734745341073406696246014589361659774041027169249453200378729434170325843778659198143763193776859869524088940195577346119843545301547043747207749969763750084308926339295559968882457872412993810129130294592999947926365264059284647209730384947211681434464714438488520940127459844288859336526896320919633919

A=112218739139542908880564359534373424013016249772931962692237907571990334483528877513809272625610512061159061737608547288558662879685086684299624481742865016924065000555267977830144740364467977206555914781236397216033805882207640219686011643468275165718132888489024688846101943642459655423609111976363316080620471928236879737944217503462265615774774318986375878440978819238346077908864116156831874695817477772477121232820827728424890845769152726027520772901423784

b=197395083814907028991785772714920885908249341925650951555219049411298436217190605190824934787336279228785809783531814507661385111220639329358048196339626065676869119737979175531770768861808581110311903548567424039264485661330995221907803300824165469977099494284722831845653985392791480264712091293580274947132480402319812110462641143884577706335859190668240694680261160210609506891842793868297672619625924001403035676872189455767944077542198064499486164431451944
B=1241972460522075344783337556660700537760331108332735677863862813666578639518899293226399921252049655031563612905395145236854443334774555982204857895716383215705498970395379526698761468932147200650513626028263449605755661189525521343142979265044068409405667549241125597387173006460145379759986272191990675988873894208956851773331039747840312455221354589910726982819203421992729738296452820365553759182547255998984882158393688119629609067647494762616719047466973581

shared_secret = pow(A,b,p)

iv = "737561146ff8194f45290f5766ed6aba"
ciphertext = "39c99bf2f0c14678d6a5416faef954b5893c316fc3c48622ba1fd6a9fe85f3dc72a29c394cf4bc8aff6a7b21cae8e12c"

print(decrypt_flag(shared_secret, iv, ciphertext))
# crypto{sh4r1ng_s3cret5_w1th_fr13nd5}

Parameter Injection

image-20250604131824055

我们会先收到Alice发送的公钥以及参数(p,g,A),可以选择不进行修改将其发送给Bob。而后收到了Bob的公钥B之后我们将其修改为g发送给Alice。这时对A来说,他们的共享密钥为:

,是我们已知的,所以最后用其解密收到AES加密后的信息即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
from pwn import *
import json
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
import hashlib


def is_pkcs7_padded(message):
padding = message[-message[-1]:]
return all(p == len(padding) for p in padding)

def decrypt_flag(shared_secret: int, iv: str, ciphertext: str):
# Derive AES key from shared secret
sha1 = hashlib.sha1()
sha1.update(str(shared_secret).encode('ascii'))
key = sha1.digest()[:16]
# Decrypt flag
ciphertext = bytes.fromhex(ciphertext)
iv = bytes.fromhex(iv)
cipher = AES.new(key, AES.MODE_CBC, iv)
plaintext = cipher.decrypt(ciphertext)

if is_pkcs7_padded(plaintext):
return unpad(plaintext, 16).decode('ascii')
else:
return plaintext.decode('ascii')

r = remote("socket.cryptohack.org", 13371)


alice_raw = r.recvline().decode()
# print(alice_raw)
# Intercepted from Alice: {"p": "0xffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca237327ffffffffffffffff", "g": "0x02", "A": "0x66dfba3758f569f2e8555b078f0ab97cebee5d95e0952156442dad855a6fa4b83f46706864009e5f4a675ac9805a62c98bfdb11257c093f709e665dedce2b5e2d1fac06abc6f20ee542359062a0cbfef4c34e82d1ca6ed7e005d42d1b1101bf17ee19e1dba12cfbb7cd13b2754c224a0e1200f1c28780ee117b8779be01af187a69bbba2bf7429370775cf34611ff93e90b3851d927ae7c41e4a83866ed5df76edb3c9f36fa5fb955887ccec964a773240d7b24df13f5cc0d9ffcc7fc3c9d19d"}
alice_data = json.loads(alice_raw.split("Intercepted from Alice: ")[1])
r.sendafter(b"Send to Bob:", json.dumps(alice_data).encode())

# 拦截 Bob 的数据并修改 B=g
bob_raw = r.recvline().decode()
# print(bob_raw)
# Intercepted from Bob: {"B": "0x4b3506e067f1e4c2cb9a481efe7df6300cc39cfa71e93468afd35d7bdccc95d479f6711672ec1c1c2ca2bc7e69ebc66e548323efebcccb6b6f1cf5e313aecf2b8e31a382481a867fd1f37623ba69224f5d51788df06f4f579f0cc4bc301977ec442332dc370a5e30e701dce36df6cc16b4a9f4f85a39a1ac98431fc3af5726f506f22b7947f2c555af0d2d3135b74ba9d19851c0aac1ab6bc672878edb26a4838593a023ede0074e4e013a33f373406751563cdf6a1a8015345b47d2f4ee67ca"}
bob_data = json.loads(bob_raw.split("Intercepted from Bob: ")[1])
bob_data['B'] = alice_data['g']
r.sendafter(b"Send to Alice:", json.dumps(bob_data).encode())

# 接收加密数据
final_response = r.recvall()
# print(final_response)
# b' Intercepted from Alice: {"iv": "43650888bb6facc1200aa3ddbf103cb4", "encrypted_flag": "4d9ec31387929a23395dd382d0b5fc62b377a4daa95f168d17cdd4c2630a5b69"}\n'
final_data = json.loads(final_response.decode().split("Intercepted from Alice: ")[1])
iv = final_data['iv']
ciphertext = final_data['encrypted_flag']

shared_secret = int(alice_data['A'], 16)

print(decrypt_flag(shared_secret, iv, ciphertext))
# crypto{n1c3_0n3_m4ll0ry!!!!!!!!}

Export-grade

image-20250604164146879

与服务器进行交互大概会收到这些内容:

1
2
3
4
5
6
7
8
9
Intercepted from Alice: {"supported": ["DH1536", "DH1024", "DH512", "DH256", "DH128", "DH64"]}
Send to Bob:

Send to Bob: Intercepted from Bob: {"chosen": "DH1024"}
Send to Alice:

Intercepted from Alice: {"p": "0xde26ab651b92a129", "g": "0x2", "A": "0xab480cafdb6037a9"}
Intercepted from Bob: {"B": "0x2edc404ff934cbbb"}
Intercepted from Alice: {"iv": "de3c285b773c7f37920800f8292b5604", "encrypted_flag": "dfd4221ad3ec8788d6410213adae297b5076179df27885ea0fa9d76ea0748a32"}

我们需要做的就是拦截选择算法的那一步,让他们选择DH64,这样就可以直接用sympy库的discrete_log计算出密钥。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
from pwn import *
import json
import re
from hashlib import sha1
from Crypto.Cipher import AES
from sympy import discrete_log

# 将消息中的JSON部分提取出来
def recv_until_jsons(raw_data: str):
json_objects = re.findall(r'\{.*?\}', raw_data)
parsed = []
for js in json_objects:
try:
parsed.append(json.loads(js))
except json.JSONDecodeError:
continue
return parsed

r = remote("socket.cryptohack.org", 13379)

line = r.recvline().decode().strip()
json_str = re.search(r'\{.*\}', line).group()
msg = json.loads(json_str)
msg['supported'] = ["DH64"]
r.sendline(json.dumps(msg).encode())

line = r.recvline().decode().strip()
json_str = re.search(r'\{.*\}', line).group()
r.sendline(json_str.encode())

data = r.recvall().decode()

params = {}
for obj in recv_until_jsons(data):
if 'p' in obj and 'g' in obj and 'A' in obj:
params['p'] = int(obj['p'], 16)
params['g'] = int(obj['g'], 16)
params['A'] = int(obj['A'], 16)
elif 'B' in obj:
params['B'] = int(obj['B'], 16)
elif 'iv' in obj and 'encrypted_flag' in obj:
params['iv'] = bytes.fromhex(obj['iv'])
params['ct'] = bytes.fromhex(obj['encrypted_flag'])

# === 计算私钥 a, 共享密钥 s, 派生 AES 密钥并解密 ===
p, g, A, B = params['p'], params['g'], params['A'], params['B']
iv, ct = params['iv'], params['ct']

a = discrete_log(p, A, g)
s = pow(B, a, p)
key = sha1(str(s).encode()).digest()[:16]
pt = AES.new(key, AES.MODE_CBC, iv).decrypt(ct)

print(pt.decode())
# crypto{d0wn6r4d35_4r3_d4n63r0u5}