强网杯-Qualifier-2022/强网先锋/polydiv writeup

1. challenge

nc 59.110.212.61 23675

附件poly2.py

▸ 点击查看代码
class Polynomial2():
    '''
    模二多项式环,定义方式有三种
    一是从高到低给出每一项的系数
        >>> Polynomial2([1,1,0,1])
        x^3 + x^2 + 1

    二是写成01字符串形式
        >>> Polynomial2('1101')
        x^3 + x^2 + 1

    三是直接给出系数为1的项的阶
        >>> Poly([3,1,4])
        x^4 + x^3 + x
        >>> Poly([]) # 加法元
        0
        >>> Poly(0) # 乘法元
        1
        >>> Poly(1,2) * Poly(2,3)
        x^5 + x^3
    '''
    def __init__(self,ll):
        
        if type(ll) ==  str:
            ll = list(map(int,ll))

        self.param = ll[::-1]
        self.ones = [i for i in range(len(self.param)) if self.param[i] == 1] # 系数为1的项的阶数列表
        self.Latex = self.latex()
        self.b = ''.join([str(i) for i in ll]) # 01串形式打印系数
        
        self.order = 0 # 最高阶
        try:self.order = max(self.ones)
        except:pass
        
    def format(self,reverse = True):
        '''
            格式化打印字符串
            默认高位在左
            reverse = False时,低位在左
            但是注意定义多项式时只能高位在右
        '''
        r = ''
        if len(self.ones) == 0:
            return '0'
        if reverse:
            return ((' + '.join(f'x^{i}' for i in self.ones[::-1])+' ').replace('x^0','1').replace('x^1 ','x ')).strip()
        return ((' + '.join(f'x^{i}' for i in self.ones)+' ').replace('x^0','1').replace('x^1 ','x ')).strip()

    def __call__(self,x):
        '''
            懒得写了,用不到
        '''
        print(f'call({x})')

    def __add__(self,other):
        '''
            多项式加法
        '''
        a,b = self.param[::-1],other.param[::-1]
        if len(a) < len(b):a,b = b,a
        for i in range(len(a)):
            try:a[-1-i] = (b[-1-i] + a[-1-i]) % 2
            except:break
        return Polynomial2(a)

    def __mul__(self,other):
        '''
            多项式乘法
        '''

        a,b = self.param[::-1],other.param[::-1]
        r = [0 for i in range(len(a) + len(b) - 1)]
        for i in range(len(b)):
            if b[-i-1] == 1:
                if i != 0:sa = a+[0]*i
                else:sa = a
                sa = [0] * (len(r)-len(sa)) + sa
                #r += np.array(sa)
                #r %= 2
                r = [(r[t] + sa[t])%2 for t in range(len(r))]
        return Polynomial2(r)

    def __sub__(self,oo):
        # 模二多项式环,加减相同
        return self + oo


    def __repr__(self) -> str:
        return self.format()
    
    def __str__(self) -> str:
        return self.format()

    def __pow__(self,a):
        # 没有大数阶乘的需求,就没写快速幂
        t = Polynomial2([1])
        for i in range(a):
            t *= self
        return t
    
    def latex(self,reverse=True):
        '''
            Latex格式打印...其实就是给两位及以上的数字加个括号{}
        '''
        def latex_pow(x):
            if len(str(x)) <= 1:
                return str(x)
            return '{'+str(x)+'}'
        
        r = ''
        if len(self.ones) == 0:
            return '0'
        if reverse:
            return (' + '.join(f'x^{latex_pow(i)}' for i in self.ones[::-1])+' ').replace('x^0','1').replace(' x^1 ',' x ').strip()
        return (' + '.join(f'x^{latex_pow(i)}' for i in self.ones)+' ').replace('x^0','1').replace(' x^1 ',' x ').strip()

    def __eq__(self,other):
        return self.ones == other.ones

    def __lt__(self,other):
        return max(self.ones) < max(other.ones)

    def __le__(self,other):
        return max(self.ones) <= max(other.ones)

def Poly(*args):
    '''
        另一种定义方式
        Poly([3,1,4]) 或 Poly(3,1,4)
    '''
    if len(args) == 1 and type(args[0]) in [list,tuple]:
        args = args[0]
        
    if len(args) == 0:
        return Polynomial2('0')
    
    ll = [0 for i in range(max(args)+1)]
    for i in args:
        ll[i] = 1
    return Polynomial2(ll[::-1])

    
PP = Polynomial2
P = Poly
# 简化名称,按长度区分 P 和 PP
if __name__ == '__main__':
    p = Polynomial2('10011')
    p3 = Polynomial2('11111')
    Q = p*p3

附件task.py

▸ 点击查看代码
import socketserver
import os, sys, signal
import string, random
from hashlib import sha256

from secret import flag
from poly2 import *

pad = lambda s:s + bytes([(len(s)-1)%16+1]*((len(s)-1)%16+1))
testCases = 40

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, prompt=b'> '):
        self.send(prompt, newline=False)
        return self._recvall()

    def close(self):
        self.send(b"Bye~")
        self.request.close()

    def proof_of_work(self):
        random.seed(os.urandom(8))
        proof = ''.join([random.choice(string.ascii_letters+string.digits) for _ in range(20)])
        _hexdigest = sha256(proof.encode()).hexdigest()
        self.send(f"sha256(XXXX+{proof[4:]}) == {_hexdigest}".encode())
        x = self.recv(prompt=b'Give me XXXX: ')
        if len(x) != 4 or sha256(x+proof[4:].encode()).hexdigest() != _hexdigest:
            return False
        return True

    def guess(self):
        from Crypto.Util.number import getPrime
        a,b,c = [getPrime(i) for i in [256,256,128]]
        pa,pb,pc = [PP(bin(i)[2:]) for i in [a,b,c]]
        r = pa*pb+pc
        self.send(b'r(x) = '+str(r).encode())
        self.send(b'a(x) = '+str(pa).encode())
        self.send(b'c(x) = '+str(pc).encode())
        self.send(b'Please give me the b(x) which satisfy a(x)*b(x)+c(x)=r(x)')
        #self.send(b'b(x) = '+str(pb).encode())
        
        return self.recv(prompt=b'> b(x) = ').decode() == str(pb)


    def handle(self):
        #signal.alarm(1200)

        if not self.proof_of_work():
            return

        for turn in range(testCases):
            if not self.guess():
                self.send(b"What a pity, work harder.")
                return
            self.send(b"Success!")
        else:
            self.send(b'Congratulations, this is you reward.')
            self.send(flag)
        
        

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

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

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

nc 59.110.212.61 23675示例

▸ 点击展开
r(x) = x^510 + x^509 + x^507 + x^505 + x^504 + x^502 + x^500 + x^494 + x^492 + x^491 + x^489 + x^488 + x^485 + x^484 + x^483 + x^480 + x^479 + x^478 + x^476 + x^473 + x^472 + x^471 + x^470 + x^465 + x^464 + x^463 + x^462 + x^461 + x^457 + x^456 + x^454 + x^453 + x^448 + x^445 + x^443 + x^442 + x^441 + x^438 + x^437 + x^435 + x^434 + x^433 + x^430 + x^429 + x^426 + x^425 + x^422 + x^421 + x^418 + x^416 + x^414 + x^413 + x^410 + x^409 + x^407 + x^406 + x^405 + x^404 + x^403 + x^402 + x^400 + x^398 + x^397 + x^395 + x^392 + x^389 + x^387 + x^384 + x^381 + x^380 + x^378 + x^375 + x^374 + x^371 + x^370 + x^369 + x^366 + x^365 + x^360 + x^359 + x^358 + x^355 + x^351 + x^350 + x^349 + x^347 + x^344 + x^342 + x^341 + x^340 + x^339 + x^336 + x^335 + x^332 + x^331 + x^327 + x^324 + x^322 + x^321 + x^319 + x^317 + x^315 + x^314 + x^309 + x^308 + x^306 + x^305 + x^297 + x^296 + x^291 + x^290 + x^286 + x^284 + x^282 + x^280 + x^278 + x^277 + x^276 + x^275 + x^274 + x^272 + x^270 + x^268 + x^266 + x^264 + x^261 + x^260 + x^259 + x^258 + x^254 + x^253 + x^252 + x^249 + x^248 + x^243 + x^242 + x^239 + x^236 + x^234 + x^233 + x^232 + x^231 + x^226 + x^224 + x^219 + x^218 + x^216 + x^213 + x^209 + x^208 + x^206 + x^204 + x^202 + x^200 + x^199 + x^197 + x^195 + x^192 + x^189 + x^185 + x^184 + x^181 + x^180 + x^179 + x^178 + x^175 + x^173 + x^172 + x^168 + x^163 + x^162 + x^161 + x^158 + x^157 + x^155 + x^150 + x^149 + x^147 + x^146 + x^145 + x^144 + x^142 + x^141 + x^140 + x^139 + x^137 + x^133 + x^131 + x^128 + x^124 + x^121 + x^119 + x^118 + x^115 + x^114 + x^113 + x^112 + x^111 + x^110 + x^107 + x^103 + x^99 + x^98 + x^96 + x^93 + x^92 + x^91 + x^89 + x^88 + x^86 + x^85 + x^83 + x^80 + x^78 + x^77 + x^76 + x^75 + x^62 + x^61 + x^60 + x^59 + x^58 + x^56 + x^51 + x^50 + x^48 + x^47 + x^45 + x^41 + x^40 + x^39 + x^38 + x^36 + x^35 + x^33 + x^32 + x^29 + x^28 + x^27 + x^23 + x^22 + x^21 + x^20 + x^19 + x^17 + x^16 + x^14 + x^13 + x^12 + x^11 + x^10 + x^9 + x^8 + x^3 + x^2 + x
a(x) = x^255 + x^254 + x^253 + x^252 + x^251 + x^248 + x^244 + x^243 + x^241 + x^240 + x^238 + x^236 + x^234 + x^233 + x^232 + x^231 + x^230 + x^229 + x^227 + x^223 + x^222 + x^221 + x^216 + x^214 + x^211 + x^210 + x^204 + x^201 + x^200 + x^198 + x^197 + x^191 + x^190 + x^188 + x^186 + x^185 + x^184 + x^183 + x^182 + x^181 + x^178 + x^176 + x^174 + x^173 + x^169 + x^167 + x^164 + x^163 + x^161 + x^159 + x^158 + x^157 + x^155 + x^154 + x^151 + x^149 + x^148 + x^142 + x^141 + x^138 + x^136 + x^135 + x^134 + x^125 + x^124 + x^122 + x^120 + x^115 + x^109 + x^108 + x^99 + x^98 + x^95 + x^92 + x^90 + x^89 + x^86 + x^85 + x^84 + x^83 + x^82 + x^81 + x^80 + x^79 + x^78 + x^77 + x^75 + x^73 + x^69 + x^68 + x^64 + x^63 + x^59 + x^58 + x^56 + x^54 + x^53 + x^51 + x^50 + x^48 + x^44 + x^43 + x^42 + x^40 + x^38 + x^37 + x^36 + x^35 + x^31 + x^28 + x^27 + x^25 + x^23 + x^22 + x^20 + x^18 + x^17 + x^16 + x^13 + x^12 + x^11 + x^8 + x^7 + x^6 + x^5 + x^3 + x^2 + x + 1
c(x) = x^127 + x^126 + x^124 + x^120 + x^112 + x^111 + x^110 + x^108 + x^105 + x^104 + x^103 + x^101 + x^100 + x^99 + x^98 + x^97 + x^95 + x^93 + x^92 + x^90 + x^89 + x^85 + x^83 + x^81 + x^79 + x^75 + x^73 + x^70 + x^68 + x^66 + x^64 + x^62 + x^61 + x^60 + x^58 + x^57 + x^55 + x^52 + x^50 + x^48 + x^44 + x^41 + x^39 + x^36 + x^33 + x^30 + x^29 + x^28 + x^26 + x^25 + x^21 + x^17 + x^16 + x^14 + x^9 + x^7 + x^5 + x^4 + x^2 + 1
Please give me the b(x) which satisfy a(x)*b(x)+c(x)=r(x)
> b(x) = 

2. 分析

模2的多项式除法,直接用sagemath即可。

3. exp

from pwn import *
from hashlib import sha256

# context.log_level = 'debug'

host = "172.17.0.1"
port = 10000
# host = "123.56.105.22" 
# port = 18627

conn = remote(host, port)

def pow(suffix, sha):
    def random_string(length = 4):
        characters = string.ascii_letters + string.digits
        return ''.join(random.choice(characters) for _ in range(length))
    i = 0
    while True:
        i += 1
        # if i % 1000000 == 0:
        #     print(i)
        chal = random_string()
        h = sha256((chal+suffix.decode()).encode()).hexdigest().encode()
        if h == sha:
            return chal

conn.recvuntil(b"sha256(XXXX+")
suffix = conn.recvuntil(b")")[:-1]
conn.recvuntil(b"== ")
sha = conn.recvuntil(b"\n")[:-1]
chal = pow(suffix, sha)
conn.recvuntil(b"Give me XXXX: ")
conn.send(chal)

for i in range(40):
    r_msg = conn.recvline().strip()[7:]
    a_msg = conn.recvline().strip()[7:]
    c_msg = conn.recvline().strip()[7:]
    P.<x> = PolynomialRing(Zmod(2),implementation='NTL')
    r = sage_eval(r_msg.decode(), locals={'x':x})
    a = sage_eval(a_msg.decode(), locals={'x':x})
    c = sage_eval(c_msg.decode(), locals={'x':x})
    b = (r-c)/a
    conn.recvline()
    conn.send(str(b).encode())
    conn.recvline()

print(conn.recvline())
print(conn.recvline())
[x] Opening connection to 172.17.0.1 on port 10000
[x] Opening connection to 172.17.0.1 on port 10000: Trying 172.17.0.1
[+] Opening connection to 172.17.0.1 on port 10000: Done


/tmp/ipykernel_14327/2121973283.py:33: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
  conn.send(chal)


b'Congratulations, this is you reward.\n'
b'flag{b64325f6-f60e-4bc5-a2b7-c684be337822}\n'