目录
题目先需要先爆破一个4字节的sha256再求40次 模二多项式,成功以后就直接给flag
- 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()
-
运算式子很简单,已知r,a,c求b,其实有个除法就行了
r = pa*pb+pc
题目给定了一个 模二多项式环的运算 的类(有删减),里边用到除的部分被删掉了,从网上找原版,发现原版被删了,只有搜索引擎的缓存,但python程序在缓存时压缩了空格并删掉了回车换行这样的程序基本无法读。并且把 [0] 也丢掉。拿到程序根据意思理解也很难,然后用搜狗搜了一下发现一个正常版的。搜狗平常啥都搜不到,但偶尔还会有点用。
- def div(self,other):
- r,b = self.param[::-1],other.param[::-1]
- if len(r) < len(b):
- return Polynomial2(),self
- q= [0]*(len(r) - len(b) + 1)
- for i in range(len(q)):
- if len(r)>=len(b):
- index = len(r) - len(b) + 1 # 确定所得商是商式的第index位
- q[-index] = int(r[0] / b[0]) # 更新被除多项式
- b_=b.copy()
- b_.extend([0]*(len(r) - len(b)))
- b_ = [t*q[i] for t in b_]
- r = [(r[t] - b_[t])%2 for t in range(len(r))]
- for j in range(len(r)): #除去列表最左端无意义的0
- if r[0]==0:
- r.remove(0)
- else:
- break
- else:
- break
- return Polynomial2(q),Polynomial2(r)
同时由于给出的数据是多项式,需要改为可处理的方式(第三种)
- def p3(s):
- return eval( b'['+s.replace(b'+', b',').replace(b', 1', b', 0').replace(b'x^', b'').replace(b'x', b'1')+ b']' )
然后就可以连后台了
- from pwn import *
- import string
- from hashlib import sha256
- from poly2 import *
-
- def get_proof(last, shav):
- s = string.ascii_letters+string.digits
- for v1 in s:
- for v2 in s:
- for v3 in s:
- for v4 in s:
- t = (v1+v2+v3+v4).encode() + last
- #print(t, sha256(t).hexdigest(), shav)
- #return
- if sha256(t).hexdigest() == shav:
- return (v1+v2+v3+v4).encode()
-
- context.log_level = 'debug'
-
- p = remote('59.110.212.61', 26882)
-
- #爆破sha256
- p.recvuntil(b'sha256(XXXX+')
- last = p.recvuntil(b') == ', drop=True)
- shav = p.recvline()[:-1]
- print('last:', last)
- print('sha256:', shav)
- found = get_proof(last, shav.decode())
- p.sendlineafter(b'Give me XXXX: ', found)
-
- #计算guess
- for i in range(40):
- p.recvuntil(b'(x) = ')
- pr = Poly(p3(p.recvline()[:-1]))
- p.recvuntil(b'(x) = ')
- pa = Poly(p3(p.recvline()[:-1]))
- p.recvuntil(b'(x) = ')
- pc = Poly(p3(p.recvline()[:-1]))
- pb = (pr - pc).div(pa)
-
- p.sendlineafter(b'> b(x) = ', str(pb[0]))
- p.recvuntil(b'Success!\n')
-
- p.recv()
- p.recv()
- p.recv()
- p.recv()
-
- pause()
这是个逆向题,结了一个.net写和游戏和一个gamemessage文件
用dnSpy打开找到以下几段
1,BlackjackConsole Program.Main() 里将gamemessage读入memory变量
- FileStream fileStream = File.OpenRead("gamemessage");
- int num = (int)fileStream.Length;
- Program.memory = new byte[num];
- fileStream.Position = 0L;
- fileStream.Read(Program.memory, 0, num);
2,BlackjackConsole Game.goldFunc 567 将memory的内容按字节与34异或
- for (int i = 0; i < Program.memory.Length; i++)
- {
- byte[] array = Program.memory;
- int num = i;
- array[num] ^= 34;
- }
3,BlackjackConsole Game.goldFunc() 538 将memory 用AES,ECB 解密生成ExploitClass.dll
- byte[] key = new byte[]
- {
- 66,
- 114,
- 97,
- 105,
- 110,
- 115,
- 116,
- 111,
- 114,
- 109,
- 105,
- 110,
- 103,
- 33,
- 33,
- 33
- };
- ICryptoTransform cryptoTransform = new RijndaelManaged
- {
- Key = key,
- Mode = CipherMode.ECB,
- Padding = PaddingMode.Zeros
- }.CreateDecryptor();
- Program.m = cryptoTransform.TransformFinalBlock(Program.memory, 0, Program.memory.Length);
这样就可以恢复这个动态库了
- data = open('gamemessage', 'rb').read()
- data = bytes([v^0x22 for v in data])
-
- from Crypto.Cipher import AES
-
- key = bytes([0x42, 0x72, 0x61, 0x69, 110, 0x73, 0x74, 0x6f, 0x72, 0x6d, 0x69, 110, 0x67, 0x21, 0x21, 0x21])
- aes = AES.new(key,AES.MODE_ECB)
- m = aes.decrypt(data)
-
- pos = 0x13eb
- m = m[pos:]+m[:pos]
- open('temp.dll', 'wb').write(m)
然后用dnSpy再打开这个动态库就可以找到加密部分了
主要函数是check1 在程序中会对3个数字赋值(当然不知道是多少了),然后进行检查,查检通过后把这3个数作成12字节的key与密文异或就是flag
check1把这3个数向左移位并填充尾位(用其它位运算得到)共320次循环,最终这320个1位结果作成40个字节去校验。
- private static void Check1(ulong x, ulong y, ulong z, byte[] KeyStream)
- {
- int num = -1;
- for (int i = 0; i < 320; i++)
- {
- x = (((x >> 29 ^ x >> 28 ^ x >> 25 ^ x >> 23) & 1UL) | x << 1);
- y = (((y >> 30 ^ y >> 27) & 1UL) | y << 1);
- z = (((z >> 31 ^ z >> 30 ^ z >> 29 ^ z >> 28 ^ z >> 26 ^ z >> 24) & 1UL) | z << 1);
- bool flag = i % 8 == 0;
- if (flag)
- {
- num++;
- }
- KeyStream[num] = (byte)((long)((long)KeyStream[num] << 1) | (long)((ulong)((uint)((z >> 32 & 1UL & (x >> 30 & 1UL)) ^ (((z >> 32 & 1UL) ^ 1UL) & (y >> 31 & 1UL))))));
- }
- }
解法想来想去最后想到z3,1000多个变量,不过运算比较快1分钟之内就解决。
- from z3 import *
-
- first = [101,5,80,213,163,26,59,38,19,6,173,189,198,166,140,183,42,247,223,24,106,20,145,37,24,7,22,191,110,179,227,5,62,9,13,17,65,22,37,5]
- array5 = [60,100,36,86,51,251,167,108,116,245,207,223,40,103,34,62,22,251,227]
-
- sec = [0]*320
- for i in range(40):
- for j in range(8):
- sec[i*8+j] = (first[i] >>(7-j))&1
-
- x = [BitVec(f'x{i}',1) for i in range(360+30)]
- y = [BitVec(f'y{i}',1) for i in range(360+31)]
- z = [BitVec(f'z{i}',1) for i in range(320+32)]
- s = Solver()
- s.add([x[0]==0,x[1]==0,y[0]==0])
- for i in range(320):
- x[i+32] = x[i+2]^x[i+3]^x[i+6]^x[i+8]
- y[i+32] = y[i+1]^y[i+4]
- z[i+32] = z[i]^z[i+1]^z[i+2]^z[i+3]^z[i+5]^z[i+7]
- s.add(sec[i] == (z[i]&x[i+2])^((z[i]^1)&y[i+1]))
-
- if s.check() == sat:
- d = s.model()
- print('x=', end='')
- for i in range(32):
- print(str(d[x[i]]), end='')
- print('\ny=', end='')
- for i in range(32):
- print(str(d[y[i]]), end='')
- print('\nz=', end='')
- for i in range(32):
- print(str(d[z[i]]), end='')
-
- #x=00001001010100010101010001100101
- #y=00110011110000101000100101110011
- #z=10111010101000101100011000110011
- #156324965,868387187,3131229747
最后通过这3个数字得到flag
- n1 = 156324965
- n2 = 868387187
- n3 = 3131229747
-
- from pwn import p32
- key = (p32(n1)+p32(n2)+p32(n3))*2
- array5 = [60,100,36,86,51,251,167,108,116,245,207,223,40,103,34,62,22,251,227]
-
- for i,v in enumerate(array5):
- print(chr(v^key[i]), end='')
-
- #Y0u_@re_G3meM3s7er!