2020 ROARCTF

W&M办的比赛,质量真不错,学到不少

1.Crypto_System

# These three are constants
p =
12039102490128509125925019010000012423515617235219127649182470182570195018265927223
g =
10729072579307052184848302322451332192456229619044181105063011741516558110216720725

# random generation
m1 = "test1"
m2 = "test2"

# Initialization
r1, s1 = sign(m1)
# r1 R1 will be provided to player

def int2str(data, mode="big"):
	if mode == "little":
		return sum([ord(data[_]) * 2 ** (8 * _) for _ in range(len(data))])
	elif mode == "big":
		return sum([ord(data[::-1][_]) * 2 ** (8 * _) for _ in range(len(data))])

def get_parameter(m):
	x = int2str(m, 'little')
	y = powmod(g, x, p)
	a = bytes_to_long(hashlib.sha256(long_to_bytes(y).rjust(128, "\0")).digest())
	b = powmod(a, a, p - 1)
	h = powmod(g, b, p)
	
	return y, h, b

def sign(m):
	y, h, b = get_parameter(m)
	r = getStrongPrime(512)
	s = (y * powmod(h, r, p)) % p
	
	return str(r),str(s)

def verify(m, r, s):
	y, h, b = get_parameter(m)
	if s == ((y * powmod(h, r, p)) % p):
		return True
	else:
		return False

# Give me the (r2,s2)
if r2 != r1 and s2 == s1 and verify(m2, r2, s2):
	print("Congratulation!Here is your flag: %s" % flag)

一个陌生的签名方案,后来看la佬的博客后有所了解,具有同态性质,但是并不影响做题 (相关链接: https://zhuanlan.zhihu.com/p/108659500 )

题目所要求的就是找到两不同信息在不同的r的情况下达到签名结果相同的目的,这其实就是让你找到一个碰撞的方案,将签名底数化一致后就相当于解一个同余方程

最后一步幂次的同余式建立在g在modp的阶下,否则直接mod(p-1)会存在无逆的情况

代码如下:

p =12039102490128509125925019010000012423515617235219127649182470182570195018265927223
g =10729072579307052184848302322451332192456229619044181105063011741516558110216720725
G=GF(p)
g=G(g)
print(g.multiplicative_order())
import hashlib
import gmpy2
from Crypto.Util.number import *
import string
from signal import alarm
from Crypto.Util.number import *
from string import digits, ascii_letters
from pwn import *
io=remote('pwn.challenge.ctf.show',28073)
table = digits+ascii_letters
def proof_of_work():
	rev = io.recvuntil("sha256(XXXX+")
	suffix = io.recv(16).decode()
	io.recvuntil(" == ")
	res = io.recv(64).decode()
	def f(x):
		hashresult = hashlib.sha256((x+suffix).encode()).hexdigest()
		if hashresult == res:
			return 1
		else:
			return 0
	prefix = util.iters.mbruteforce(f,table,4,'upto')
	io.sendline(str(prefix))
def int2str(data, mode="big"):
    if mode == "little":
        return sum([ord(data[_]) * 2 ** (8 * _) for _ in range(len(data))])
    elif mode == "big":
        return sum([ord(data[::-1][_]) * 2 ** (8 * _) for _ in range(len(data))])
def get_parameter(m):
    x = int2str(m, 'little')
    y = pow(g, x, p)
    a = bytes_to_long(hashlib.sha256(long_to_bytes(y).rjust(128, b"\0")).digest())
    b = pow(a, a, p - 1)
    h = pow(g, b, p)
    return [x,y, h, b,a]
def verify(m, r, s):
    y=get_parameter(m)[1]
    h=get_parameter(m)[2]
    if s == (y * pow(h, r, p)) % p:
        return True
    else:
        return False
def sign(m,r):
    y= get_parameter(m)[1]
    h=get_parameter(m)[2]
    s = (y * pow(h, r, p)) % p
    return s
proof_of_work()    
p=12039102490128509125925019010000012423515617235219127649182470182570195018265927223
g=10729072579307052184848302322451332192456229619044181105063011741516558110216720725
q=1039300813886545966418005631983853921163721828798787466771912919828750891
io.recvuntil('Here is the frist message(64 bytes):')
m1=str(io.recvuntil('\n')[:-1])[2:-1]
m1=str(long_to_bytes(int(m1,16)))[2:-1]
io.recvuntil('Here is the second message(64 bytes):')
m2=str(io.recvuntil('\n')[:-1])[2:-1]
m2=str(long_to_bytes(int(m2,16)))[2:-1]
io.recvuntil(':')
a=io.recvuntil('\n')[:-1]
r1=int(a)
b1=get_parameter(m1)[3]
s1=sign(m1,r1)
x1=get_parameter(m1)[0]
b2=get_parameter(m2)[3]
x2=get_parameter(m2)[0]
r2=(b1*r1+x1-x2)*gmpy2.invert(b2,q)%q
s2=sign(m2,r2)
io.recvuntil('Please choice your options:')
io.sendline('3')
io.sendline('('+str(r2)+','+str(s1)+')')
io.interactive()

2.EASYRSA

from Crypto.Util.number import *
from gmpy2 import *
from secret import *

assert(flag.startwith('flag{')) and (flag.endwith('}'))
assert(is_prime(beta) and len(bin(beta)[2:]) == 512) 
assert(len(bin(x)[2:]) == len(bin(y)[2:]))
# This is tip!!!
assert(tip == 2*x*y*beta + x + y)

p = 2*x*beta + 1
q = 2*y*beta + 1

assert(is_prime(p) and is_prime(q))

n = p*q
e = 65537
m = bytes_to_long(flag)
enc = powmod(m,e,n)
#n=17986052241518124152579698727005505088573670763293762110375836247355612011054569717338676781772224186355540833136105641118789391002684013237464006860953174190278718294774874590936823847040556879723368745745863499521381501281961534965719063185861101706333863256855553691578381034302217163536137697146370869852180388385732050177505306982196493799420954022912860262710497234529008765582379823928557307038782793649826879316617865012433973899266322533955187594070215597700782682186705964842947435512183808651329554499897644733096933800570431036589775974437965028894251544530715336418443795864241340792616415926241778326529055663
#e=65537
#enc=10760807485718247466823893305767047250503197383143218026814141719093776781403513881079114556890534223832352132446445237573389249010880862460738448945011264928270648357652595432015646424427464523486856294998582949173459779764873664665361437483861277508734208729366952221351049574873831620714889674755106545281174797387906705765430764314845841490492038801926675266705606453163826755694482549401843247482172026764635778484644547733877083368527255145572732954216461334217963127783632702980064435718785556011795841651015143521512315148320334442235923393757396733821710592667519724592789856065414299022191871582955584644441117223
#beta=11864389277042761216996641604675717452843530574016671576684180662096506094587545173005905433938758559675517932481818900399893444422743930613073261450555599

p-1与q-1有较大公约数,一开始考虑rho算法但没跑出来,原因不知

∵p = 2x*beta + 1 q = 2y*beta + 1 =>n=4xy*beta^2+2beta(x+y)+1

=>n/4beta^2=xy+(x+y)/2beta+1/4beta^2

利用bit信息估计x,y大致为521bits

beta为512bits

基于此等式我们采取爆破的方式获取xy的取值随后利用此数据计算phi=4xy*beta^2

import gmpy2
from Crypto.Util.number import *
n=17986052241518124152579698727005505088573670763293762110375836247355612011054569717338676781772224186355540833136105641118789391002684013237464006860953174190278718294774874590936823847040556879723368745745863499521381501281961534965719063185861101706333863256855553691578381034302217163536137697146370869852180388385732050177505306982196493799420954022912860262710497234529008765582379823928557307038782793649826879316617865012433973899266322533955187594070215597700782682186705964842947435512183808651329554499897644733096933800570431036589775974437965028894251544530715336418443795864241340792616415926241778326529055663
e=65537
enc=10760807485718247466823893305767047250503197383143218026814141719093776781403513881079114556890534223832352132446445237573389249010880862460738448945011264928270648357652595432015646424427464523486856294998582949173459779764873664665361437483861277508734208729366952221351049574873831620714889674755106545281174797387906705765430764314845841490492038801926675266705606453163826755694482549401843247482172026764635778484644547733877083368527255145572732954216461334217963127783632702980064435718785556011795841651015143521512315148320334442235923393757396733821710592667519724592789856065414299022191871582955584644441117223
beta=11864389277042761216996641604675717452843530574016671576684180662096506094587545173005905433938758559675517932481818900399893444422743930613073261450555599
xy1=n//(4*(beta**2))
for i in range(2000):
    a=xy1-i
    phi=a*(beta**2)
    try:
        d=gmpy2.invert(e,phi)
        m=long_to_bytes(pow(enc,d,n))
        if 'flag{' in str(m):
            print(m)
    except:
        continue

3.Reverse

from Crypto.Util.number import *
from gmpy2 import *
from secret import *

assert(flag.decode().startswith('flag{')) and (flag.decode().endswith('}'))
def reverse(x):
	y = 0
	while x != 0:
		y = y*2 + x%2
		x = x // 2
	return y


while True:
	p = getStrongPrime(512)
	q = reverse(p)
	if is_prime(q):
		break

n = p*q
e = 65537
m = bytes_to_long(flag)
enc = powmod(m,e,n)
#n = 158985980192501034004997692253209315116841431063210516613522548452327355222295231366801286879768949611058043390843949610463241574886852164907094966008463721486557469253652940169060186477803255769516068561042756903927308078335838348784208212701919950712557406983012026654876481867000537670622886437968839524889
#enc = 103728452309804750381455306214814700768557462686461157761076359181984554990431665209165298725569861567865645228742739676539208228770740802323555281253638825837621845841771677911598039696705908004858472132222470347720085501572979109563593281375095145984000628623881592799662103680478967594601571867412886606745

这个题目p,q的构造很有意思,仔细琢磨会发现q的二进制与p的二进制表示刚好相反
这样的数有专门的名词emirp数,目前暂时没有证明出emirp数有无穷多个,是一个很有趣的问题了 (相关链接:https://en.wikipedia.org/wiki/Emirp )

相似的一道题: https://kt.gy/blog/2015/10/asis-2015-finals-rsasr/ (不同的是此题是十进制的反素数,而本题是在二进制下的)

关键:逐位爆破,同时设置判断条件,减少不必要的计算过程

代码如下:

n=158985980192501034004997692253209315116841431063210516613522548452327355222295231366801286879768949611058043390843949610463241574886852164907094966008463721486557469253652940169060186477803255769516068561042756903927308078335838348784208212701919950712557406983012026654876481867000537670622886437968839524889
def factor(a,b,k):
    if k==256:
        if a*b==n:
            print([a,b])
            return a,b
    else:
        for i in range(2):
            for j in range(2):
                a1=a+i*(2**k)+j*(2**(511-k))
                b1=b+j*(2**k)+i*(2**(511-k))
                if a1*b1>n:
                    continue
                if (a1+2**(511-k))*(b1+2**(511-k))<n :
                    continue
                if (a1*b1)%(2**(k+1))!=n%(2**(k+1)):
                    continue
                factor(a1,b1,k+1)
factor(0,0,0)

from Crypto.Util.number import *
import gmpy2
p=13299413764048930133302138749466137829470129709829516069778014310838093114516400589047888072065037035007023741009041669893387899867083575829855377403280423
q=11954360020159164180709939019047385560179850436770100207193049651260543609501871575909448998378290922795824941066935928157032997160163537467165365731882943
c=103728452309804750381455306214814700768557462686461157761076359181984554990431665209165298725569861567865645228742739676539208228770740802323555281253638825837621845841771677911598039696705908004858472132222470347720085501572979109563593281375095145984000628623881592799662103680478967594601571867412886606745
e=65537
n=p*q
phi=(p-1)*(q-1)
d=gmpy2.invert(e,phi)
m=pow(c,d,n)
print(long_to_bytes(m))
posted @ 2022-01-13 21:56  hash_hash  阅读(170)  评论(0)    收藏  举报