feat: finish xiaosai

This commit is contained in:
2023-10-15 19:42:16 +08:00
parent 7fe37b52eb
commit c2de294d1c
13 changed files with 571 additions and 0 deletions

View 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

View 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的编码也就是循环冗余校验
根据题目描述我们需要构造一个157循环码也就是15bit的编码数7bit的有效信息数
"""
# 首先定义伽罗瓦域
R.<x> = PolynomialRing(GF(2))
"""
然后寻找生成元g
根据定理nk循环码的生成元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和1271和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()

View 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

View 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()

View File

@@ -0,0 +1,37 @@
from pwn import *
from flag import flag
from Crypto.Cipher import AES
from hashlib import sha256
import base64
flag = b''
first_flag = b''
wordlist = b'123456789qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM{}_'
for i in range(16):
for j in wordlist:
r = remote("127.0.0.1", 10002)
payload = b'0'*(16-5) + b'0' * (15 - i)\
+ first_flag + j.to_bytes() + \
b'0' * (15 - i)
r.sendline(payload)
cipher = r.recvline()
cipher = base64.b64decode(cipher)
if cipher[16:32] == cipher[32:48]:
first_flag = first_flag + j.to_bytes()
break
last_flag = b''
for i in range(21-16):
for j in wordlist:
r = remote("127.0.0.1", 10002)
payload = b'0' * 11 + j.to_bytes() + \
last_flag + b'0' * 27
r.sendline(payload)
cipher = r.recvline()
cipher= base64.b64decode(cipher)
if cipher[16:32] == cipher[64:80]:
last_flag = j.to_bytes() + last_flag
break
print(first_flag + last_flag)

View File

@@ -0,0 +1 @@
flag = b'flag{eCb_is_not_SafE}'

View File

@@ -0,0 +1,73 @@
from hashlib import sha256
import socketserver
import signal
from flag import flag
from Crypto.Cipher import AES
import base64
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 task(self):
key = sha256(flag).digest()
key = key[:16]
aes = AES.new(key, AES.MODE_ECB)
data = self.recv(prompt=b'')
data = b'cqupt'+ data + flag
# len(flag) == 21
# wordlist = b'123456789qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM{}_'
if len(data)%16 != 0:
pad = b'0' * (16 - len(data)%16)
data = data + pad
cipher = aes.encrypt(data)
print(aes.decrypt(cipher))
cipher = base64.b64encode(cipher)
self.send(cipher)
def handle(self):
signal.alarm(60)
self.task()
return
class ThreadedServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
pass
class ForkedServer(socketserver.ForkingMixIn, socketserver.TCPServer):
pass
if __name__ == "__main__":
#flag = bytes(os.getenv("FLAG"),"utf-8")
HOST, PORT = '0.0.0.0', 10002
server = ForkedServer((HOST, PORT), Task)
server.allow_reuse_address = True
print(HOST, PORT)
server.serve_forever()

View File

@@ -0,0 +1,11 @@
from Crypto.Util.number import *
p = 170021659067442061523756541191993539248601165314725269340063885026090819928194021233489114706002869522375199940625136026822330472394573193982550217044532146962203411567638298486561460035048451998397915884861905155825573014911356931131393751111816934458614898785910805905358218404703141056982153504282962094549
q = 156289115230564684236869282390677373336412812898135298853785374595122098483952732832928286906302804608150589957073534308140034369315958525768786913022949461790625449368299077456798653080889386800523502656112132648850626018430482876211766660346216029055456596647573751654709671998718949348538504201995353414849
n = p * q
cipher = 15315994859113745140937150782850225701835894977924847828178261709106790713756481438851906169833437205680746393379892960895453635059199072504132009117455118252801524117640663250753749247480223306967637814097656959416506419849108127590869410005001001319682678605925584319221815990695423909010895701674831442387195906671891136861712786777889185580869108974742614564867198257449323144696618681193168712805318310217437715668293800077584570491524233826384775049353844578873853868493454822838612576965182892687235411858595304846022012252673457313575555164210208501163855569260816910756715565420825070869972114502924134935227
phi = (p - 1) * (q - 1)
e = 65537
d = inverse(e, phi)
plaintext = pow(cipher, d, n)
print(long2str(plaintext))

View File

@@ -0,0 +1 @@
flag = b'flag{W0W_you_cAn_factor_2048bits_prime}'

View File

@@ -0,0 +1,19 @@
from flag import flag
from Crypto.Util.number import *
# Is it possible to factor 2048 bits RSA????
p = getStrongPrime(1024)
q = getStrongPrime(1024)
n = p * q
e = 65537
message = bytes_to_long(flag)
cipher = pow(message, e, n)
print(p)
print(q)
print('n = ', n)
print('cipher = ', cipher)
'''
n = 26572534665683235245636883276068606612246011683144885473463339711820331993493357279285848391008791322234296406608539840620252625886064149394162998948970494176467317183311068211754639508369506106626167584042532674048767021259563143175030276397301094824563794971045331643148544039656526615133318494601670688100830427083371422333448416345157657081894568628680132969792458721329931299527818220689347292610785587787837487603664368727957712489422350366840751269348100479824826707549651813948243868760028344290958809882314383956517334878930614926458454637703779278161529934602431923391507121553686269628353968327172758558101
cipher = 15315994859113745140937150782850225701835894977924847828178261709106790713756481438851906169833437205680746393379892960895453635059199072504132009117455118252801524117640663250753749247480223306967637814097656959416506419849108127590869410005001001319682678605925584319221815990695423909010895701674831442387195906671891136861712786777889185580869108974742614564867198257449323144696618681193168712805318310217437715668293800077584570491524233826384775049353844578873853868493454822838612576965182892687235411858595304846022012252673457313575555164210208501163855569260816910756715565420825070869972114502924134935227
'''

14
xiaosai/factor_n/crack.py Normal file
View File

@@ -0,0 +1,14 @@
import gmpy2
from sympy import nextprime
from Crypto.Util.number import *
n = 119089874014927074688341672884508166875005676500322264758691717600758737133958853429775347698400246542956663932584349274109281162512900740554148968627493442686180696496512753102593837838697028745592258709705875168834908314583594102947493349091661801379830005354833653565157987808629144151353148601181998243399
cipher = 117095409962662175082351896808794751507022710425611245694723238077959955609489552866653772250169627679450018400780468195080203740614508425379908667955368095074633690882446901510961333353751345467769557765781287285368700648236247094896521401160296460446518097963846290488354458277094831166588801569124630935182
e = 65537
root = gmpy2.iroot(n,2)[0]
q = nextprime(root)
print(n % q)
p = n // q
phi = (p - 1) * (q - 1)
d = inverse(e, phi)
plaintext = pow(cipher, d, n)
print(long2str(plaintext))

1
xiaosai/factor_n/flag.py Normal file
View File

@@ -0,0 +1 @@
flag = b'flag{You_can_do_this}'

16
xiaosai/factor_n/main.py Normal file
View File

@@ -0,0 +1,16 @@
from flag import flag
from Crypto.Util.number import *
from sympy import nextprime
p = getStrongPrime(512)
q = nextprime(p)
n = p * q
e = 65537
message = bytes_to_long(flag)
cipher = pow(message, e, n)
print('n = ', n)
print('cipher = ', cipher)
'''
n = 119089874014927074688341672884508166875005676500322264758691717600758737133958853429775347698400246542956663932584349274109281162512900740554148968627493442686180696496512753102593837838697028745592258709705875168834908314583594102947493349091661801379830005354833653565157987808629144151353148601181998243399
cipher = 117095409962662175082351896808794751507022710425611245694723238077959955609489552866653772250169627679450018400780468195080203740614508425379908667955368095074633690882446901510961333353751345467769557765781287285368700648236247094896521401160296460446518097963846290488354458277094831166588801569124630935182
'''