feat: finish xiaosai
This commit is contained in:
46
xiaosai/Claude_Shannon/crack.py
Normal file
46
xiaosai/Claude_Shannon/crack.py
Normal file
@@ -0,0 +1,46 @@
|
||||
from pwn import * # type: ignore
|
||||
# context.log_level = 'debug'
|
||||
|
||||
"""
|
||||
(这题小小的放了水)
|
||||
因为只有一轮,而最终的答案有128种情况,那我们不妨直接猜一个答案
|
||||
根据条件概率公式算一下
|
||||
|
||||
for i in range(0,1000,100):
|
||||
print(i,":", 1 - (127/128) ** i)
|
||||
|
||||
0 : 0.0
|
||||
100 : 0.5435690025908804
|
||||
200 : 0.7916707446041162
|
||||
300 : 0.9049120701701576
|
||||
400 : 0.9565989213461966
|
||||
500 : 0.9801904023814129
|
||||
600 : 0.990958285600675
|
||||
700 : 0.9958730812784277
|
||||
800 : 0.9981163463716863
|
||||
900 : 0.9991402420956556
|
||||
大概300次以内都出结果了
|
||||
"""
|
||||
|
||||
|
||||
|
||||
for i in range(300):
|
||||
try:
|
||||
r = remote("localhost", 10011)
|
||||
# r = process(['python3', 'main.py'])
|
||||
for i in range(15):
|
||||
r.sendlineafter(b":", b"1")
|
||||
r.recvuntil(b"!")
|
||||
|
||||
r.sendlineafter(b"chests:", b"0 0 1 0 0 1 0")
|
||||
r.recvline()
|
||||
flag = r.recvline()
|
||||
if b"flag" in flag:
|
||||
end_time = time.time()
|
||||
print(flag)
|
||||
break
|
||||
else:
|
||||
r.close()
|
||||
|
||||
except EOFError:
|
||||
pass
|
||||
195
xiaosai/Claude_Shannon/crack.sage
Normal file
195
xiaosai/Claude_Shannon/crack.sage
Normal file
@@ -0,0 +1,195 @@
|
||||
"""
|
||||
前置知识(建议要看,非常自信可以不看)
|
||||
https://zhuanlan.zhihu.com/p/448198789
|
||||
|
||||
信息论的一些基础
|
||||
可以结合这份ppt来看
|
||||
https://web.xidian.edu.cn/jwliu/files/20190521_003040.pdf
|
||||
|
||||
同时b站上的国防科技大学-信息论与编码基础也可以学习一下
|
||||
https://www.bilibili.com/video/BV1pJ411U7G8?p=61
|
||||
|
||||
|
||||
读题可知,我们需要获取一个7bit的有效信息,每次返回的信息可以看作1bit,共15bit。
|
||||
而其中1-2次的说谎我们可以视为1-2bit的传输错误。
|
||||
因此我们需要一种最少可以纠正2bit的编码,也就是循环冗余校验
|
||||
|
||||
根据题目描述,我们需要构造一个(15,7)循环码,也就是15bit的编码数,7bit的有效信息数
|
||||
"""
|
||||
# 首先定义伽罗瓦域
|
||||
R.<x> = PolynomialRing(GF(2))
|
||||
|
||||
"""
|
||||
然后寻找生成元g
|
||||
根据定理,(n,k)循环码的生成元g一定是x^n+1的n-k次因子
|
||||
(ppt中说是x^n-1,这里因为是GF(2),所以+1和-1是等价的)
|
||||
带入计算得知,g应当为x^15+1的8次因子
|
||||
"""
|
||||
ff = x^15+1
|
||||
g = factor(ff)
|
||||
# (x + 1) * (x^2 + x + 1) * (x^4 + x + 1) * (x^4 + x^3 + 1) * (x^4 + x^3 + x^2 + x + 1)
|
||||
factors = []
|
||||
for i in range(len(g)):
|
||||
factors.append(g[i][0])
|
||||
|
||||
possible_g = []
|
||||
|
||||
# x + 2 * y + 4 * z == 8
|
||||
# root = [(8,0,0),(6,1,0),(4,2,0),(4,0,1),(2,3,0),(2,1,1),(0,4,0),(0,2,1),(0,0,2)]
|
||||
|
||||
|
||||
possible_g.append(factors[0]^8)
|
||||
|
||||
possible_g.append(factors[0]^6 * factors[1])
|
||||
|
||||
possible_g.append(factors[0]^4 * factors[1]^2)
|
||||
|
||||
possible_g.append(factors[0]^4 * factors[2])
|
||||
possible_g.append(factors[0]^4 * factors[3])
|
||||
possible_g.append(factors[0]^4 * factors[4])
|
||||
|
||||
possible_g.append(factors[0]^2 * factors[1]^3)
|
||||
|
||||
possible_g.append(factors[0]^2 * factors[1] * factors[2])
|
||||
possible_g.append(factors[0]^2 * factors[1] * factors[3])
|
||||
possible_g.append(factors[0]^2 * factors[1] * factors[4])
|
||||
|
||||
possible_g.append(factors[1]^4)
|
||||
|
||||
possible_g.append(factors[1]^2 * factors[2])
|
||||
possible_g.append(factors[1]^2 * factors[3])
|
||||
possible_g.append(factors[1]^2 * factors[4])
|
||||
|
||||
possible_g.append(factors[2] * factors[2])
|
||||
possible_g.append(factors[2] * factors[3])
|
||||
possible_g.append(factors[2] * factors[4])
|
||||
possible_g.append(factors[3] * factors[3])
|
||||
possible_g.append(factors[3] * factors[4])
|
||||
possible_g.append(factors[4] * factors[4])
|
||||
|
||||
"""
|
||||
至此我们已经找出所有的生成元了,但是不要忘了还有纠错的要求。
|
||||
纠正2bit的要求则是: 假设用d表示码组的最小汉明距离,纠正错误时,设可纠正t位的错误,则d >= 2t+1
|
||||
(也就是保证任一点A的错误状态不落到其余点B,并且A的错误状态离A更近)
|
||||
带入公式则是d >= 5
|
||||
"""
|
||||
|
||||
# 定义函数 n2p,将二进制数转换为多项式的形式
|
||||
def n2p(a):
|
||||
a = bin(a)[2:]
|
||||
p = 0
|
||||
for i in range(len(a)):
|
||||
if a[len(a) - i - 1] == '1':
|
||||
p += x^i
|
||||
return p
|
||||
|
||||
# 定义函数enc,将7bit的信息编码成循环码
|
||||
def enc(i):
|
||||
m = n2p(i)
|
||||
c = (x^8) * m + (((x^8) * m) % g)
|
||||
return "".join([str(int(i in c.exponents())) for i in range(15)])[::-1]
|
||||
|
||||
# 定义函数dif,计算ab之间的汉明距离
|
||||
def dif(a, b):
|
||||
cnt = 0
|
||||
for i in range(len(a)):
|
||||
if a[i] != b[i]:
|
||||
cnt += 1
|
||||
return cnt
|
||||
|
||||
"""
|
||||
通过构造校验表来检查所有的生成元是否满足条件
|
||||
"""
|
||||
for g in possible_g:
|
||||
# 创建一个列表 dic,存储不同输入值的编码
|
||||
dic = []
|
||||
|
||||
for i in range(2**7):
|
||||
dic.append(enc(i))
|
||||
|
||||
minHD = 15
|
||||
for i in dic:
|
||||
for j in dic:
|
||||
if i == j:
|
||||
continue
|
||||
if dif(i,j) <= minHD:
|
||||
minHD = dif(i,j)
|
||||
|
||||
#if minHD >= 5:
|
||||
#print(g)
|
||||
# x^8 + x^7 + x^6 + x^4 + 1
|
||||
# x^8 + x^4 + x^2 + x + 1
|
||||
|
||||
|
||||
# 下面两个随便挑一个作为生成元就好了
|
||||
# g = x^8 + x^7 + x^6 + x^4 + 1
|
||||
g = x^8 + x^4 + x^2 + x + 1
|
||||
dic = []
|
||||
|
||||
for i in range(2^7):
|
||||
dic.append(enc(i))
|
||||
|
||||
"""
|
||||
构造问题这个地方有点巧妙。
|
||||
我们可以发现系统码是一个对称互补的码,也就是说0和127,1和126的系统码每一位都相反。
|
||||
|
||||
那么对于所有系统码来说0和1就是平均分布的。(因为成对来看,30个bit中必有15bit的0和15bit的1)
|
||||
对于系统码的任意一位为0的概率就是0.5,为1的概率也是0.5
|
||||
|
||||
因此我们可以把questions[i]和j[i]等价来看,
|
||||
我们可以找出所有令j[i]==1的信息码情况,共64种,把这些进行or运算。
|
||||
把这个问题发送出去,如果返回true,那么证明j[i]就是1。
|
||||
以此类推,我们就可以得到一串15bit的返回值。
|
||||
|
||||
但是因为存在最多2bit的错误,我们需要跟码表进行对比,找出汉明距离小于等于2的系统码。
|
||||
然后这个系统码对应的信息码就是正确的信息码
|
||||
"""
|
||||
|
||||
# 定义字符串模板 part,用于后面构造问题
|
||||
part = "( C0 == {} and C1 == {} and C2 == {} and C3 == {} and C4 == {} and C5 == {} and C6 == {} ) "
|
||||
|
||||
# 创建问题列表 questions,用于存储构造的问题模板
|
||||
questions = []
|
||||
for i in range(15):
|
||||
question = ""
|
||||
nums = [j[:7] for j in dic if j[i] == '1']
|
||||
for j in range(64):
|
||||
n = nums[j]
|
||||
question += part.format(n[0], n[1], n[2], n[3], n[4], n[5], n[6]) + "or "
|
||||
questions.append(question[:-4])
|
||||
|
||||
|
||||
|
||||
# 导入 pwn 模块,用于与远程或本地进程进行交互
|
||||
from pwn import *
|
||||
|
||||
# 设置日志级别为 debug,以便在执行过程中输出详细日志信息
|
||||
#context.log_level = 'debug'
|
||||
|
||||
r = process(['python3', 'main_local.py'])
|
||||
#r = remote("localhost", "10011")
|
||||
|
||||
for i in range(1):
|
||||
msg = ''
|
||||
# 逐个发送问题并接收答案
|
||||
for j in range(15):
|
||||
r.sendlineafter(b"Shannon:", questions[j].encode())
|
||||
r.recvuntil(b"answers:")
|
||||
if b'True' in r.recvuntil(b"!"):
|
||||
msg += '1'
|
||||
else:
|
||||
msg += '0'
|
||||
# 查找与收到的答案最接近的编码,这里答案肯定只会有一个
|
||||
for j in range(128):
|
||||
if (dif(msg, dic[j]) <= 2):
|
||||
break
|
||||
ans = ""
|
||||
for k in dic[j][:7]:
|
||||
ans += k + " "
|
||||
# 发送解码后的答案
|
||||
r.sendlineafter(b"chests:", ans.encode())
|
||||
|
||||
flag = r.recvall()
|
||||
print(flag)
|
||||
r.close()
|
||||
|
||||
57
xiaosai/Claude_Shannon/main_local.py
Normal file
57
xiaosai/Claude_Shannon/main_local.py
Normal file
@@ -0,0 +1,57 @@
|
||||
from random import choice as c
|
||||
from random import randint, shuffle
|
||||
from Crypto.Util.number import * # type: ignore
|
||||
|
||||
flag = b"flag{this_is_a_test_flag}"
|
||||
|
||||
# 白名单列表,包含允许在问题中使用的关键词和符号
|
||||
white_list = ['==', '(', ')', 'C0', 'C1', 'C2', 'C3', 'C4', 'C5', 'C6', '0', '1', 'and', 'or', 'not']
|
||||
|
||||
# 定义一个函数 calc,用于计算问题的结果
|
||||
def calc(ans, chests, expr):
|
||||
try:
|
||||
C0, C1, C2, C3, C4, C5, C6 = chests
|
||||
r = eval(expr)
|
||||
except Exception as e:
|
||||
print("Shannon fails to understand your words.\n", e)
|
||||
exit(0)
|
||||
return ans(r)
|
||||
|
||||
# 定义一个游戏回合函数 do_round
|
||||
def do_round():
|
||||
# 定义两个函数 truth 和 lie,用于判断 Shannon 的回答是否为真或假
|
||||
truth = lambda r: not not r
|
||||
lie = lambda r: not r
|
||||
chests = []
|
||||
for i in range(7):
|
||||
# 随机生成 7 个 True 或 False,表示每个箱子是宝藏还是怪物
|
||||
chests.append(c((True, False)))
|
||||
print("Seven chests lie here, with mimics or treasure hidden inside.\nBut don't worry. Trusty Shannon knows what to do.")
|
||||
# 随机选择 Shannon 的回答策略,包括多少次 lie
|
||||
lie_count = c((1, 2))
|
||||
Shannon = [truth] * (15 - lie_count) + [lie] * lie_count
|
||||
# 猜猜第几次是在说谎 :-)
|
||||
shuffle(Shannon)
|
||||
for i in range(15):
|
||||
print("Ask Shannon:")
|
||||
question = input().strip() # 输入问题
|
||||
for word in question.split(" "):
|
||||
if word not in white_list: # 检查问题中是否包含白名单以外的关键词或符号
|
||||
print("({}) No treasure for dirty hacker!".format(word))
|
||||
exit(0)
|
||||
res = str(calc(Shannon[i], chests, question)) # 计算问题的结果
|
||||
print('Shannon answers: {}!\n'.format(res))
|
||||
print("Now open the chests:")
|
||||
# 输入0或1表示每个宝箱的真假,用空格隔开
|
||||
chests_string = input()
|
||||
return chests == list(map(int, chests_string.strip().split(" ")))
|
||||
|
||||
# 游戏开始
|
||||
print("The Unbreakable Shannon has returned, with some suspicious chests and a far more complicated strategy -- he MAY LIE ONCE OR TWICE! Can you still get all the treasure without losing your head?")
|
||||
|
||||
for i in range(50):
|
||||
if not do_round(): # 执行游戏回合
|
||||
print("A chest suddenly comes alive and BITE YOUR HEAD OFF.\n")
|
||||
exit(0)
|
||||
print("You've found all the treasure! {}\n".format(flag)) # 赢得游戏,获得flag
|
||||
|
||||
100
xiaosai/Claude_Shannon/main_remote.py
Normal file
100
xiaosai/Claude_Shannon/main_remote.py
Normal file
@@ -0,0 +1,100 @@
|
||||
from random import choice as c
|
||||
from random import randint, shuffle
|
||||
import socketserver
|
||||
import signal
|
||||
import string
|
||||
import random
|
||||
import os
|
||||
|
||||
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()
|
||||
|
||||
# 定义一个函数 calc,用于计算问题的结果
|
||||
def calc(self, ans, chests, expr):
|
||||
try:
|
||||
C0, C1, C2, C3, C4, C5, C6 = chests
|
||||
r = eval(expr)
|
||||
except Exception as e:
|
||||
self.send(b"Shannon fails to understand your words.\n")
|
||||
self.send(e)
|
||||
exit(0)
|
||||
return ans(r)
|
||||
|
||||
# 定义一个游戏回合函数 do_round
|
||||
def do_round(self):
|
||||
# 定义两个函数 truth 和 lie,用于判断 Shannon 的回答是否为真或假
|
||||
truth = lambda r: not not r
|
||||
lie = lambda r: not r
|
||||
chests = []
|
||||
for i in range(7):
|
||||
# 随机生成 7 个 True 或 False,表示每个箱子是宝藏还是怪物
|
||||
chests.append(c((True, False)))
|
||||
self.send(b"Seven chests lie here, with mimics or treasure hidden inside.\nBut don't worry. Trusty Shannon knows what to do.")
|
||||
# 随机选择 Shannon 的回答策略,包括多少次 lie
|
||||
lie_count = c((1, 2))
|
||||
Shannon = [truth] * (15 - lie_count) + [lie] * lie_count
|
||||
# 猜猜第几次是在说谎 :-)
|
||||
shuffle(Shannon)
|
||||
for i in range(15):
|
||||
self.send(b"Ask Shannon:")
|
||||
question = self.recv().decode().strip() # 输入问题
|
||||
for word in question.split(" "):
|
||||
if word not in white_list: # 检查问题中是否包含白名单以外的关键词或符号
|
||||
self.send("({}) No treasure for dirty hacker!".format(word).encode())
|
||||
exit(0)
|
||||
res = str(self.calc(Shannon[i], chests, question)) # 计算问题的结果
|
||||
self.send('Shannon answers: {}!\n'.format(res).encode())
|
||||
self.send(b"Now open the chests:")
|
||||
# 输入0或1表示每个宝箱的真假,用空格隔开
|
||||
chests_string = self.recv().decode()
|
||||
return chests == list(map(int, chests_string.strip().split(" ")))
|
||||
|
||||
def handle(self):
|
||||
signal.alarm(60)
|
||||
|
||||
# 游戏开始
|
||||
self.send(b"The Unbreakable Shannon has returned, with some suspicious chests and a far more complicated strategy -- he MAY LIE ONCE OR TWICE! Can you still get all the treasure without losing your head?")
|
||||
for i in range(50):
|
||||
if not self.do_round(): # 执行游戏回合
|
||||
self.send(b"A chest suddenly comes alive and BITE YOUR HEAD OFF.\n")
|
||||
return
|
||||
self.send("You've found all the treasure! {}\n".format(flag).encode()) # 赢得游戏,获得flag
|
||||
|
||||
|
||||
class ThreadedServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
|
||||
pass
|
||||
|
||||
|
||||
class ForkedServer(socketserver.ForkingMixIn, socketserver.TCPServer):
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
flag = bytes(os.getenv("FLAG"),"utf-8") # type: ignore
|
||||
# 白名单列表,包含允许在问题中使用的关键词和符号
|
||||
white_list = ['==', '(', ')', 'C0', 'C1', 'C2', 'C3', 'C4', 'C5', 'C6', '0', '1', 'and', 'or', 'not']
|
||||
HOST, PORT = '0.0.0.0', 10011
|
||||
server = ForkedServer((HOST, PORT), Task)
|
||||
server.allow_reuse_address = True
|
||||
print(HOST, PORT)
|
||||
server.serve_forever()
|
||||
Reference in New Issue
Block a user