• [2022强网杯] polydiv和gamemaster


    目录

    polydiv

    re_gamemaster


    polydiv

    题目先需要先爆破一个4字节的sha256再求40次 模二多项式,成功以后就直接给flag

    1. import socketserver
    2. import os, sys, signal
    3. import string, random
    4. from hashlib import sha256
    5. from secret import flag
    6. from poly2 import *
    7. pad = lambda s:s + bytes([(len(s)-1)%16+1]*((len(s)-1)%16+1))
    8. testCases = 40
    9. class Task(socketserver.BaseRequestHandler):
    10. def _recvall(self):
    11. BUFF_SIZE = 2048
    12. data = b''
    13. while True:
    14. part = self.request.recv(BUFF_SIZE)
    15. data += part
    16. if len(part) < BUFF_SIZE:
    17. break
    18. return data.strip()
    19. def send(self, msg, newline=True):
    20. try:
    21. if newline:
    22. msg += b'\n'
    23. self.request.sendall(msg)
    24. except:
    25. pass
    26. def recv(self, prompt=b'> '):
    27. self.send(prompt, newline=False)
    28. return self._recvall()
    29. def close(self):
    30. self.send(b"Bye~")
    31. self.request.close()
    32. def proof_of_work(self):
    33. random.seed(os.urandom(8))
    34. proof = ''.join([random.choice(string.ascii_letters+string.digits) for _ in range(20)])
    35. _hexdigest = sha256(proof.encode()).hexdigest()
    36. self.send(f"sha256(XXXX+{proof[4:]}) == {_hexdigest}".encode())
    37. x = self.recv(prompt=b'Give me XXXX: ')
    38. if len(x) != 4 or sha256(x+proof[4:].encode()).hexdigest() != _hexdigest:
    39. return False
    40. return True
    41. def guess(self):
    42. from Crypto.Util.number import getPrime
    43. a,b,c = [getPrime(i) for i in [256,256,128]]
    44. pa,pb,pc = [PP(bin(i)[2:]) for i in [a,b,c]]
    45. r = pa*pb+pc
    46. self.send(b'r(x) = '+str(r).encode())
    47. self.send(b'a(x) = '+str(pa).encode())
    48. self.send(b'c(x) = '+str(pc).encode())
    49. self.send(b'Please give me the b(x) which satisfy a(x)*b(x)+c(x)=r(x)')
    50. #self.send(b'b(x) = '+str(pb).encode())
    51. return self.recv(prompt=b'> b(x) = ').decode() == str(pb)
    52. def handle(self):
    53. #signal.alarm(1200)
    54. if not self.proof_of_work():
    55. return
    56. for turn in range(testCases):
    57. if not self.guess():
    58. self.send(b"What a pity, work harder.")
    59. return
    60. self.send(b"Success!")
    61. else:
    62. self.send(b'Congratulations, this is you reward.')
    63. self.send(flag)
    64. class ThreadedServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
    65. pass
    66. #class ForkedServer(socketserver.ForkingMixIn, socketserver.TCPServer):
    67. class ForkedServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
    68. pass
    69. if __name__ == "__main__":
    70. HOST, PORT = '0.0.0.0', 10000
    71. server = ForkedServer((HOST, PORT), Task)
    72. server.allow_reuse_address = True
    73. server.serve_forever()

    运算式子很简单,已知r,a,c求b,其实有个除法就行了

    r = pa*pb+pc

    题目给定了一个 模二多项式环的运算 的类(有删减),里边用到除的部分被删掉了,从网上找原版,发现原版被删了,只有搜索引擎的缓存,但python程序在缓存时压缩了空格并删掉了回车换行这样的程序基本无法读。并且把 [0] 也丢掉。拿到程序根据意思理解也很难,然后用搜狗搜了一下发现一个正常版的。搜狗平常啥都搜不到,但偶尔还会有点用。

    1. def div(self,other):
    2. r,b = self.param[::-1],other.param[::-1]
    3. if len(r) < len(b):
    4. return Polynomial2(),self
    5. q= [0]*(len(r) - len(b) + 1)
    6. for i in range(len(q)):
    7. if len(r)>=len(b):
    8. index = len(r) - len(b) + 1 # 确定所得商是商式的第index位
    9. q[-index] = int(r[0] / b[0]) # 更新被除多项式
    10. b_=b.copy()
    11. b_.extend([0]*(len(r) - len(b)))
    12. b_ = [t*q[i] for t in b_]
    13. r = [(r[t] - b_[t])%2 for t in range(len(r))]
    14. for j in range(len(r)): #除去列表最左端无意义的0
    15. if r[0]==0:
    16. r.remove(0)
    17. else:
    18. break
    19. else:
    20. break
    21. return Polynomial2(q),Polynomial2(r)

    同时由于给出的数据是多项式,需要改为可处理的方式(第三种)

    1. def p3(s):
    2. return eval( b'['+s.replace(b'+', b',').replace(b', 1', b', 0').replace(b'x^', b'').replace(b'x', b'1')+ b']' )

    然后就可以连后台了

    1. from pwn import *
    2. import string
    3. from hashlib import sha256
    4. from poly2 import *
    5. def get_proof(last, shav):
    6. s = string.ascii_letters+string.digits
    7. for v1 in s:
    8. for v2 in s:
    9. for v3 in s:
    10. for v4 in s:
    11. t = (v1+v2+v3+v4).encode() + last
    12. #print(t, sha256(t).hexdigest(), shav)
    13. #return
    14. if sha256(t).hexdigest() == shav:
    15. return (v1+v2+v3+v4).encode()
    16. context.log_level = 'debug'
    17. p = remote('59.110.212.61', 26882)
    18. #爆破sha256
    19. p.recvuntil(b'sha256(XXXX+')
    20. last = p.recvuntil(b') == ', drop=True)
    21. shav = p.recvline()[:-1]
    22. print('last:', last)
    23. print('sha256:', shav)
    24. found = get_proof(last, shav.decode())
    25. p.sendlineafter(b'Give me XXXX: ', found)
    26. #计算guess
    27. for i in range(40):
    28. p.recvuntil(b'(x) = ')
    29. pr = Poly(p3(p.recvline()[:-1]))
    30. p.recvuntil(b'(x) = ')
    31. pa = Poly(p3(p.recvline()[:-1]))
    32. p.recvuntil(b'(x) = ')
    33. pc = Poly(p3(p.recvline()[:-1]))
    34. pb = (pr - pc).div(pa)
    35. p.sendlineafter(b'> b(x) = ', str(pb[0]))
    36. p.recvuntil(b'Success!\n')
    37. p.recv()
    38. p.recv()
    39. p.recv()
    40. p.recv()
    41. pause()

    re_gamemaster

    这是个逆向题,结了一个.net写和游戏和一个gamemessage文件

    用dnSpy打开找到以下几段

    1,BlackjackConsole Program.Main() 里将gamemessage读入memory变量

    1. FileStream fileStream = File.OpenRead("gamemessage");
    2. int num = (int)fileStream.Length;
    3. Program.memory = new byte[num];
    4. fileStream.Position = 0L;
    5. fileStream.Read(Program.memory, 0, num);

    2,BlackjackConsole Game.goldFunc 567 将memory的内容按字节与34异或

    1. for (int i = 0; i < Program.memory.Length; i++)
    2. {
    3. byte[] array = Program.memory;
    4. int num = i;
    5. array[num] ^= 34;
    6. }

    3,BlackjackConsole Game.goldFunc() 538  将memory 用AES,ECB 解密生成ExploitClass.dll

    1. byte[] key = new byte[]
    2. {
    3. 66,
    4. 114,
    5. 97,
    6. 105,
    7. 110,
    8. 115,
    9. 116,
    10. 111,
    11. 114,
    12. 109,
    13. 105,
    14. 110,
    15. 103,
    16. 33,
    17. 33,
    18. 33
    19. };
    20. ICryptoTransform cryptoTransform = new RijndaelManaged
    21. {
    22. Key = key,
    23. Mode = CipherMode.ECB,
    24. Padding = PaddingMode.Zeros
    25. }.CreateDecryptor();
    26. Program.m = cryptoTransform.TransformFinalBlock(Program.memory, 0, Program.memory.Length);

    这样就可以恢复这个动态库了

    1. data = open('gamemessage', 'rb').read()
    2. data = bytes([v^0x22 for v in data])
    3. from Crypto.Cipher import AES
    4. key = bytes([0x42, 0x72, 0x61, 0x69, 110, 0x73, 0x74, 0x6f, 0x72, 0x6d, 0x69, 110, 0x67, 0x21, 0x21, 0x21])
    5. aes = AES.new(key,AES.MODE_ECB)
    6. m = aes.decrypt(data)
    7. pos = 0x13eb
    8. m = m[pos:]+m[:pos]
    9. open('temp.dll', 'wb').write(m)

    然后用dnSpy再打开这个动态库就可以找到加密部分了

    主要函数是check1 在程序中会对3个数字赋值(当然不知道是多少了),然后进行检查,查检通过后把这3个数作成12字节的key与密文异或就是flag

    check1把这3个数向左移位并填充尾位(用其它位运算得到)共320次循环,最终这320个1位结果作成40个字节去校验。

    1. private static void Check1(ulong x, ulong y, ulong z, byte[] KeyStream)
    2. {
    3. int num = -1;
    4. for (int i = 0; i < 320; i++)
    5. {
    6. x = (((x >> 29 ^ x >> 28 ^ x >> 25 ^ x >> 23) & 1UL) | x << 1);
    7. y = (((y >> 30 ^ y >> 27) & 1UL) | y << 1);
    8. z = (((z >> 31 ^ z >> 30 ^ z >> 29 ^ z >> 28 ^ z >> 26 ^ z >> 24) & 1UL) | z << 1);
    9. bool flag = i % 8 == 0;
    10. if (flag)
    11. {
    12. num++;
    13. }
    14. KeyStream[num] = (byte)((long)((long)KeyStream[num] << 1) | (long)((ulong)((uint)((z >> 32 & 1UL & (x >> 30 & 1UL)) ^ (((z >> 32 & 1UL) ^ 1UL) & (y >> 31 & 1UL))))));
    15. }
    16. }

    解法想来想去最后想到z3,1000多个变量,不过运算比较快1分钟之内就解决。

    1. from z3 import *
    2. 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]
    3. array5 = [60,100,36,86,51,251,167,108,116,245,207,223,40,103,34,62,22,251,227]
    4. sec = [0]*320
    5. for i in range(40):
    6. for j in range(8):
    7. sec[i*8+j] = (first[i] >>(7-j))&1
    8. x = [BitVec(f'x{i}',1) for i in range(360+30)]
    9. y = [BitVec(f'y{i}',1) for i in range(360+31)]
    10. z = [BitVec(f'z{i}',1) for i in range(320+32)]
    11. s = Solver()
    12. s.add([x[0]==0,x[1]==0,y[0]==0])
    13. for i in range(320):
    14. x[i+32] = x[i+2]^x[i+3]^x[i+6]^x[i+8]
    15. y[i+32] = y[i+1]^y[i+4]
    16. z[i+32] = z[i]^z[i+1]^z[i+2]^z[i+3]^z[i+5]^z[i+7]
    17. s.add(sec[i] == (z[i]&x[i+2])^((z[i]^1)&y[i+1]))
    18. if s.check() == sat:
    19. d = s.model()
    20. print('x=', end='')
    21. for i in range(32):
    22. print(str(d[x[i]]), end='')
    23. print('\ny=', end='')
    24. for i in range(32):
    25. print(str(d[y[i]]), end='')
    26. print('\nz=', end='')
    27. for i in range(32):
    28. print(str(d[z[i]]), end='')
    29. #x=00001001010100010101010001100101
    30. #y=00110011110000101000100101110011
    31. #z=10111010101000101100011000110011
    32. #156324965,868387187,3131229747

    最后通过这3个数字得到flag

    1. n1 = 156324965
    2. n2 = 868387187
    3. n3 = 3131229747
    4. from pwn import p32
    5. key = (p32(n1)+p32(n2)+p32(n3))*2
    6. array5 = [60,100,36,86,51,251,167,108,116,245,207,223,40,103,34,62,22,251,227]
    7. for i,v in enumerate(array5):
    8. print(chr(v^key[i]), end='')
    9. #Y0u_@re_G3meM3s7er!

  • 相关阅读:
    【22年】2022最新阿里Java面经,转疯了
    HBase 在统一内容平台业务的优化实践
    一文详解Docker镜像
    电影《万里归途》
    python flask框架接受axios发送的图片文件
    C++保留小数点后两位(floor&ceil&round)详解
    做了几年“斜杠青年”,我在ZStack立志做国产云计算的研发
    7-57 租用游艇问题——dp
    Python 自动化测试中最火的第三方开源测试框架 pytest
    支付宝推出AI毛发自测工具,上传照片即可自测脱发等级
  • 原文地址:https://blog.csdn.net/weixin_52640415/article/details/126090098