[祥云杯 2022] crypto部分

目录

DLP

RSA

leak_rsa 未完成

tracing

fill

fermat


有几个差一点,看了个  Arr3stY0u 的WP,豁然开朗 

DLP

原题是个DLP加密,输入g可对其加密,加密后如果是4则返回flag。

import socketserver
from time import sleep
from secret import flag
import signal
import random 

from Crypto.Util.number import *
import random

#通过快速幂的方法求幂,每次通过4的状态设置t,泄露t
#当返回值t==1时,说明这个密文经历过4
def pow_d(g, e, n):
	t, r = 0, 1
	for _ in bin(e)[2:]:
		if r == 4: t += 1
		r = pow(r, 2, n)
		if _ == '1': r = r * g % n
	return t, r

def ts(m, p):
	m = m % p
	return pow(m, (p - 1) // 2, p) == 1
class Task(socketserver.BaseRequestHandler):
    def _recvall(self):
        BUFF_SIZE = 2048
        data = b''
        while True:
            part = self.request.recv(BUFF_SIZE)
            data += part
            if len(part) < BUFF_SIZE:
                break
        return data.strip()

    def send(self, msg, newline=True):
        try:
            if newline:
                msg += b'\n'
            self.request.sendall(msg)
        except:
            pass

    def recv(self):
        return self._recvall()
        



    def handle(self):
        border = b"|"
        self.send(border*72)
        self.send(border+b"Solve a DLP challenge in some special way to get the flag", border)

        p = 2 ** 1024 - 2 ** 234 - 2 ** 267 - 2 ** 291 - 2 ** 403 - 1
        s = random.randint(2, (p - 1) // 2)

        while True:
            self.send(s)
            self.send(b"| Options: \n|\t[T]ry the magic machine \n|\t[Q]uit")
            ans = self.recv().lower()

            if ans == b't':
                self.send(border+b"please send your desired integer: ")
                g = self.recv()
                try:
                    g = int(g)
                except:
                    self.send(border+b"The given input is not integer!")
                    break 
                sleep(0.3)
                if ts(g, p):
                    t, r = pow_d(g, s, p)
                    if r == 4:
                        self.send(border+b'Great! you got the flag:'+flag)
                    else:
                        self.send(border+b"t, r = "+f"{t, r}".encode())
                else:
                    self.send(border+"The given base is NOT valid!!!")
            elif ans == b'q':
                self.send(border+"Quitting ...")
                break 
            else:
                self.send(border+"Bye bye ...") 
                break 
                
'''
DLP题由s进行加密
c = g**s %p 
可根据用户输入的g得到c, 求c=4时g
'''                







class ThreadedServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
    pass


class ForkedServer(socketserver.ForkingMixIn, socketserver.TCPServer):
    pass


if __name__ == "__main__":
    HOST, PORT = '0.0.0.0', 10001
    server = ForkedServer((HOST, PORT), Task)
    server.allow_reuse_address = True
    print(HOST, PORT)
    server.serve_forever()

这里边给了个t,r其中r是密文,t是表示在乘幂过程中是否有过结果是4的情况,一直不清楚怎么弄,看了WP才知道,正是这个t的泄露这题才能解。WP也没看大明白,先存一下,回头慢慢看

from pwn import *
from sage import *
from Crypto.Util.number import *

context.proxy = 'localhost'

class Gao: 
    def __init__(self): 
        #self.conn = process(['python3', '1_DLP_chall.py']) 
        self.conn = remote('101.201.71.136', 38476) 
        self.p = 2 ** 1024 - 2 ** 234 - 2 ** 267 - 2 ** 291 - 2 ** 403 - 1 
        self.s_high = 1 
        self.Zp = Zmod(self.p) 
    def gao_check(self): 
        self.conn.sendline('T') 
        ans = self.Zp(4).nth_root(self.s_high) 
        print('Guessing: {}'.format(ans)) 
        self.conn.sendline(str(ans)) 
        self.conn.recvuntil('integer: n') 
        a = self.conn.recvline() 
        if ('Great!' in a): 
            print(a) 
            print(ZZ(ans).nbits()) 
            return True 
        else: 
            return False 
    
    def gao_one(self): 
        self.conn.sendline('T') 
        ans = self.Zp(2).nth_root(self.s_high) #对2开s_high次幂
        self.conn.sendline(str(ans)) 
        self.conn.recvuntil('integer: n') 
        a = self.conn.recvline() 
        if ('Great!' in a): 
            print(a) 
            print(ZZ(ans).nbits()) 
            return True 
        else: 
            a = a[8:] 
            t, r = eval(a) 
            self.s_high <<= 1 
            if (t == 0): 
                self.s_high |= 1 
                self.t = 1 - t 
                print('{:b}'.format(self.s_high)) 
                return False 
    def gao(self): 
        while (True): 
            if (self.gao_one()): 
                break 
            if (self.t == 1): 
                if (self.gao_check()): 
                    break 
    def gao_2(self): 
        for i in range(1023): 
            if (self.gao_one()): 
                break 
            else: 
                for i in range(20): 
                    self.gao_check() 
                    self.s_high >>= 1
                    
if __name__ == '__main__': 
    g = Gao() 
    g.gao_2()

 

RSA

一直以来RSA的n从来没有分解成功过,这回也没有,不知道是不是yafu是不是真的。

from Crypto.Util.number import getPrime, isPrime, bytes_to_long, inverse
from math import lcm
from secret import flag

def gen(g):
    bits = 512 - g.bit_length()
    while True:
        a = getPrime(bits)
        p = 2 * a * g + 1
        if isPrime(p):
            return p

flag = bytes_to_long(flag)
g = getPrime(320)
p = gen(g)
q = gen(g)
n = p * q
d = getPrime(135)
phi = lcm(p - 1, q - 1)
e = inverse(d, phi)
c = pow(flag, e, n)
print("n = {}".format(n))
print("e = {}".format(e))
print("c = {}".format(c))

想分解n-1也没有成功,看WP说是直接分解。也就没啥说的了。

from gmpy2 import invert
from Crypto.Util.number import long_to_bytes

n = 253784908428481171520644795825628119823506176672683456544539675613895749357067944465796492899363087465652749951069021248729871498716450122759675266109104893465718371075137027806815473672093804600537277140261127375373193053173163711234309619016940818893190549811778822641165586070952778825226669497115448984409
e = 31406775715899560162787869974700016947595840438708247549520794775013609818293759112173738791912355029131497095419469938722402909767606953171285102663874040755958087885460234337741136082351825063419747360169129165
c = 97724073843199563126299138557100062208119309614175354104566795999878855851589393774478499956448658027850289531621583268783154684298592331328032682316868391120285515076911892737051842116394165423670275422243894220422196193336551382986699759756232962573336291032572968060586136317901595414796229127047082707519

#p = 2 * a * g + 1
#tn = 2*a1*a2*g**2 + (a1+a2)*g
#WP 直接分解
p=21007149684731457068332113266097775916630249079230293735684085460145700796880956996855348862572729597251282134827276249945199994121834609654781077209340587
q = n//p 
print(long_to_bytes(pow(c,invert(e,(p-1)*(q-1)),n)))

leak_rsa 未完成

这个给出了p和q的42%的位,想爆破,但也没成功

from Crypto.Util.number import getPrime, inverse, bytes_to_long
from secret import flag
from random import randint
from math import floor

def hint(p, length, upper):
    gift = {}
    pstr = bin(p)[2:].zfill(upper + 1)
    for i in range(length):
        idx = randint(1, upper)
        if idx not in gift:
            gift[idx] = pstr[idx]
    return gift

p = getPrime(512)
q = getPrime(512)
n = p * q
e = getPrime(32)
d = inverse(e, (p - 1) * (q - 1))
c = pow(bytes_to_long(flag), e, n)
hint1 = hint(p, floor(0.42 * p.bit_length()), 511)
hint2 = hint(q, floor(0.42 * q.bit_length()), 511)
hint3 = hint(d, floor(0.42 * d.bit_length()), 1023)
print("n =", n)
print("e =", e)
print("c =", c)
print("hint1 =", hint1)
print("hint2 =", hint2)
print("hint3 =", hint3)

爆破脚本,小数试过,题目不成

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'}


nbits = 511

#爆破得到p,q
def get_pq(tp,tq, idx):
    #print(idx)
    if idx<100:
        print(idx, hex(tp),hex(tq))
    if tp*tq == n:
        print('OK-------->',tp,tq)
        exit()
    
    if idx>=nbits:
        return 
    
    if ((tp*tq)^n)&((1<<idx)-1) != 0:
        return False
    
    b = nbits-idx
    if b in hint1:
        tp+= int(hint1[b])<<idx 
        #print('h1', hint1[b])
        if b in hint2:
            #print('h2', hint2[b])
            tq += int(hint2[b])<<idx 
            get_pq(tp,tq, idx+1)
        else:
            tq1 = tq 
            tq2 = tq + (1<<idx)
            get_pq(tp,tq1, idx+1)
            get_pq(tp,tq2, idx+1)
    else:
        if b in hint2:
            #print('h2', hint2[b])
            tq += int(hint2[b])<<idx 
            tp1 = tp 
            tp2 = tp + (1<<idx)
            get_pq(tp1,tq, idx+1)
            get_pq(tp2,tq, idx+1)
        else:
            tp1 = tp 
            tp2 = tp + (1<<idx)
            tq1 = tq 
            tq2 = tq + (1<<idx)
            get_pq(tp1,tq1, idx+1)
            get_pq(tp1,tq2, idx+1)  
            get_pq(tp2,tq1, idx+1)  
            get_pq(tp2,tq2, idx+1)
    return False

'''
>>> bin(865579743731)[2:].zfill(40)
'1100100110001000100100101011100111110011'
>>> bin(749495783639)[2:].zfill(40)
'1010111010000001011011100001000011010111'
  ^                 ^                ^ ^

hint1 = {12: '1', 22: '1', 2: '0', 25: '0', 29: '0', 8: '1', 36: '0', 16: '1', 5: '0', 28: '1', 11: '0', 21: '0', 18: '0', 32: '1'}
hint2 = {26: '0', 15: '1', 19: '0', 7: '0', 12: '0', 14: '0', 24: '0', 3: '0', 8: '1', 30: '0', 27: '1', 11: '0', 17: '1', 10: '0'}
n = 648748368329710642617109
nbits = 39
'''
get_pq((1<<nbits)+1,(1<<nbits)+1,1)

 

tracing

题目就是个简单的rsa,但对gcd(phi,e)进行了tracing

from secret import p, q, flag
from Crypto.Util.number import bytes_to_long

def gcd(a, b):
    s = 0
    while b != 0:
        print(a, b)
        if isOdd(a):
            if isOdd(b):
                a = a - b
                a = rshift1(a)
                if a < b:
                    a, b = b, a
            else:
                b = rshift1(b)
                if a < b:
                    a, b = b, a
        else:
            if isOdd(b):
                a = rshift1(a)
                if a < b:
                    a, b = b, a
            else:
                a = rshift1(a)     #同为偶数运行不到
                b = rshift1(b)
                s += 1
    if s:
        return lshift(a, s)
    return a

def isOdd(a):
    return a & 1 == 1

def rshift1(a):
    return a >> 1

def lshift(a, s):
    return a << s


n = p * q
e = 65537
phi = (p - 1) * (q - 1)
assert gcd(phi, e) == 1
c = pow(bytes_to_long(flag), e, n)
print(c)
print(n)

在700多行的位置有gcd的内容

task.py(30): def isOdd(a):
task.py(33): def rshift1(a):
task.py(36): def lshift(a, s):
task.py(40): n = p * q
task.py(41): e = 65537
task.py(42): phi = (p - 1) * (q - 1)
task.py(43): assert gcd(phi, e) == 1
 --- modulename: task, funcname: gcd
task.py(5):     s = 0
task.py(6):     while b != 0:
task.py(7):         if isOdd(a):
 --- modulename: task, funcname: isOdd
task.py(31):     return a & 1 == 1
task.py(18):             if isOdd(b):
 --- modulename: task, funcname: isOdd
task.py(31):     return a & 1 == 1
task.py(19):                 a = rshift1(a)
 --- modulename: task, funcname: rshift1
task.py(34):     return a >> 1
task.py(20):                 if a < b:
task.py(6):     while b != 0:
task.py(7):         if isOdd(a):

 显然它这个运行到的流程就是它作的判断过程,不过判断本身没有,执行的操作才有用。把涉及到9,10,12,14,16,19,21,28行的操作过滤出来,然后把逆向操作就能把phi,e从1,0逆回到原始状态

op = [9,10,12,14,16,19,21,28]
sop = [(str(i)+')')[:2] for i in op]
print(sop)
lines = open('4_trace.out').read().split('\n')
ostr = []
for i,line in enumerate(lines):
    if not line.startswith('task.py('):
        continue
    
    if line[8:10] in sop:
        ostr.append(line[12:].strip())

#print(ostr)

cmd = 'a,b = 1,0\n'
for o in ostr[::-1]:
    if o == 'a = a - b':
        cmd += "a +=b\n"
    elif o == 'a = rshift1(a)':
        cmd += "a <<=1\n"
    elif o == 'a, b = b, a':
        cmd += "a, b = b, a\n"
    elif o == 'b = rshift1(b)':
        cmd += "b <<=1\n"
    elif o == 'return a':
        pass 
    else:
        print('XXXX',o)

cmd+= 'print(a,b)\n'
open('a4_a.py', 'w').write(cmd)

把这些操作写成的脚本是这样的

a,b = 1,0
a, b = b, a
a <<=1
a +=b
a <<=1
a <<=1
a <<=1
a +=b
b <<=1
b <<=1
a, b = b, a
a <<=1
a +=b
a <<=1
a +=b
a <<=1
a <<=1
a +=b
b <<=1
b <<=1
a, b = b, a
a <<=1
a +=b
a, b = b, a
a <<=1
...以下略...
print(a,b)

 得到phi后就能直接操作得到flag 了

phi = 113793513490894881175568252406666081108916791207947545198428641792768110581083359318482355485724476407204679171578376741972958506284872470096498674038813744206060043230633366541996120990867169768523014939944773017185662017479011094588132516102178922759206005551241577259317764398494195585166584573218495824732
e = 65537
c = 64885875317556090558238994066256805052213864161514435285748891561779867972960805879348109302233463726130814478875296026610171472811894585459078460333131491392347346367422276701128380739598873156279173639691126814411752657279838804780550186863637510445720206103962994087507407296814662270605713097055799853102
n = 113793513490894881175568252406666081108916791207947545198428641792768110581083359318482355485724476407204679171578376741972958506284872470096498674038813765700336353715590069074081309886710425934960057225969468061891326946398492194812594219890553185043390915509200930203655022420444027841986189782168065174301
from gmpy2 import invert
d = invert(e,phi)
m = pow(c,d,n)
print(bytes.fromhex(hex(m)[2:]))

fill

这个题前边是个LCG求参数,后边是背包问题,小LCG,小背包,都比较容易。

from Crypto.Util.number import *
from random import *
from gmpy2 import gcd
from numpy import dot

nbits = 32
msg = getRandomNBitInteger(nbits)
flag = b'flag{sha256(msg)}'
tmp_m = bin(msg)[2:]
f_list = []
for i in range(len(tmp_m)):
    f_list.append(int(tmp_m[i]))

r_list =[randint(20, 50)]
for i in range(nbits - 1):
    r_list.append(randint(2 * r_list[-1], 3 * r_list[-1]))

while True:
    A = randint(2 * r_list[-1] + 1, 3 * r_list[-1])
    B = randint(2 * r_list[-1] + 1, 3 * r_list[-1])
    if gcd(A, B) == 1:
        break

M = [A * x % B for x in r_list]

S = dot(f_list, M)
print(S)

seed = getRandomNBitInteger(30)
s = [0] * nbits
s[0] = seed
m = getRandomNBitInteger(20)
c = getPrime(24)
n = 991125622
for i in range(1, nbits):
    s[i] = (s[i-1]*m+c)%n
print(s[0], s[1], s[2])
for t in range(nbits):
    M[t] = M[t] + s[t]
print(M)


'''
492226042629702
562734112 859151551 741682801
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]
'''

先求LCG的参数a,b,然后通过得到的s还原M

from gmpy2 import *

nbits = 32
S = 492226042629702
n = 991125622
s =[562734112, 859151551, 741682801]
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]

'''
for i in range(1, nbits):
    s[i] = (s[i-1]*m+c)%n
'''
#LCG求a,b
m = (s[2]-s[1])*invert((s[1]-s[0]),n) %n
c = (s[1]-s[0]*m )%n
for i in range(3,32):
    s.append(int(s[i-1]*m + c)%n)
#还原M
for t in range(nbits):
    M[t] = M[t] - s[t]

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]

 然后用sagemath求背包的解,最后作sha256

#sage
#背包加密
A = Matrix(ZZ, nbits + 1, nbits + 1)
for i in range(nbits):
    A[i, i] = 1
    A[i, nbits] = M[i]
A[nbits,nbits] = -int(S)

res = A.LLL()
for i in range(0, nbits + 1):
    # print solution
    M = res.row(i).list()
    flag = True
    for m in M:
        if m != 0 and m != 1:
            flag = False
            break
    if flag:
        print(i, M)
        M = ''.join(str(j) for j in M)
        # remove the last bit
        M = M[:-1]             #矩阵是n+1行,结果是n+1个值,最后一个去掉
        m = int(M, 2)
        print(m)

m = 3617517412   
#flag = b'flag{sha256(msg)}'
#flag{8f504aee71626212f275117326722b6c0ccc94f4039ed31fbcfde08e026352c4}

fermat

最后一题名字叫费马,一开始是q=p+A说明两数相差很小,可以分解,分解得到p和q之后作了个异或加密,异或的x有114514**x %p == 1 虽然说费马定理不能证明必要性但这里也没什么别的方法了,只能相信x=p-1,然后就出多半个flag和一堆乱码,百思不得其解。

from Crypto.Util.number import *
from random import *
from libnum import *
import gmpy2
from secret import x

flag = b'?????????'
m = bytes_to_long(flag)
def obfuscate(p, k):
    nbit = p.bit_length()
    while True:
        l1 = [getRandomRange(-1, 1) for _ in '_' * k]
        l2 = [getRandomRange(100, nbit) for _ in '_' * k]
        l3 = [getRandomRange(10, nbit//4) for _ in '_' * k]
        l4 = [getRandomRange(2, 6) for _ in '_' *k]
        A = sum([l1[_] * 2 ** ((l2[_]+l3[_])//l4[_]) for _ in range(0, k)])
        q = p + A
        if isPrime(q) * A != 0:
            return q

p = getPrime(512)
q = obfuscate(p, 5)
e = 65537
n = p*q
print(f'n = {n}')

assert 114514 ** x % p == 1
m = m ^ (x**2)
c = pow(m, e, n)
print(f'c = {c}')

'''
n = 141321067325716426375483506915224930097246865960474155069040176356860707435540270911081589751471783519639996589589495877214497196498978453005154272785048418715013714419926299248566038773669282170912502161620702945933984680880287757862837880474184004082619880793733517191297469980246315623924571332042031367393
c = 81368762831358980348757303940178994718818656679774450300533215016117959412236853310026456227434535301960147956843664862777300751319650636299943068620007067063945453310992828498083556205352025638600643137849563080996797888503027153527315524658003251767187427382796451974118362546507788854349086917112114926883
'''

其实这里的p,q可以通过大小来确定的(q=p+sum(...)),而题目说的确实是p,后来发现题目第1个参数是个正负号,sum之后确实会出现负数,是我脑子不走了。

'''
yafu
***factors found***

P155 = 11887853772894265642834649929578157180848240939084164222334476057487485972806971092902627112665734648016476153593841839977704512156756634066593725142934001
P155 = 11887853772894265642834649929578157180848240939084164222334476057487485972806971092902627112665734646483980612727952939084061619889139517526028673988305393
'''
#p<q
p = 11887853772894265642834649929578157180848240939084164222334476057487485972806971092902627112665734646483980612727952939084061619889139517526028673988305393
q = 11887853772894265642834649929578157180848240939084164222334476057487485972806971092902627112665734648016476153593841839977704512156756634066593725142934001

n = 141321067325716426375483506915224930097246865960474155069040176356860707435540270911081589751471783519639996589589495877214497196498978453005154272785048418715013714419926299248566038773669282170912502161620702945933984680880287757862837880474184004082619880793733517191297469980246315623924571332042031367393
e = 65537
c = 81368762831358980348757303940178994718818656679774450300533215016117959412236853310026456227434535301960147956843664862777300751319650636299943068620007067063945453310992828498083556205352025638600643137849563080996797888503027153527315524658003251767187427382796451974118362546507788854349086917112114926883

from gmpy2 import *
from Crypto.Util.number import long_to_bytes
d = invert(e, (p-1)*(q-1))
m = pow(c,d,n)

print(long_to_bytes(int(m)))  #x != 0
#114514 ** x % p == 1  => x = p-1
m ^= (q-1)**2

print(long_to_bytes(int(m)))
#b'flag{I~ju5t_w@nt_30_te11_y0u_how_I_@m_f3ll1ng~}45108#@7++3@79?3328?!!@08#712/+963-60#9-/83#+/1@@=59!/84@?3#4!4=-9542/##'

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值