转载请备注来源
sudoku_easy
简单的数独交互,几个小注意点,每次发送level之后sleep5秒才会返回题目
-
将形如
---------------------
800103720
023840650
410006008
300001062
000052407
072060090
160000375
205019846
000030000
---------------------
转换成二维数组进行解数独,并将返回结果重新转换成多行字符串形式
def parse_input(input_list):
board = []
for row in input_list:
nums = list(map(int, row))
board.append(nums)
return board
def format_output(board):
formatted = ""
for row in board:
formatted += "".join(map(str, row)) + "\n"
return formatted.strip()
-
一开始以为每次获得5分,要拿到120分,range了24次,一直出问题,后来发现获得分数是递增的,同时调试了一下发现拿到120分会返回一个getshell,因此修改一下range7次
最终脚本:
def find_empty(board):
for row in range(9):
for col in range(9):
if board[row][col] == 0:
return row, col
return None
def is_valid(board, num, pos):
row, col = pos
for i in range(9):
if board[row][i] == num and col != i:
return False
if board[i][col] == num and row != i:
return False
box_row = row // 3
box_col = col // 3
for i in range(box_row * 3, box_row * 3 + 3):
for j in range(box_col * 3, box_col * 3 + 3):
if board[i][j] == num and (i, j) != pos:
return False
return True
def solve(board):
find = find_empty(board)
if not find:
return True
else:
row, col = find
for i in range(1, 10):
if is_valid(board, i, (row, col)):
board[row][col] = i
if solve(board):
return True
board[row][col] = 0
return False
def parse_input(input_list):
board = []
for row in input_list:
nums = list(map(int, row))
board.append(nums)
return board
def format_output(board):
formatted = ""
for row in board:
formatted += "".join(map(str, row)) + "\n"
return formatted.strip()
# input_string = '''---------------------
# 800103720
# 023840650
# 410006008
# 300001062
# 000052407
# 072060090
# 160000375
# 205019846
# 000030000
# ---------------------
# now give me you solve:'''
# lists=input_string.split('\n')[1:10]
# board = parse_input(lists)
# print(board)
# solve(board)
# print(board)
from pwn import *
# 创建连接
conn = remote('47.108.165.60',27539)
# 接收欢迎信息
for i in range(7):
msg = conn.recvuntil("Please input:").strip().decode("utf-8")
print(msg)
# 发送选择
conn.sendline('1'.encode())
# 接收下一步提示
msg = conn.recvuntil("Please select the level:").strip().decode("utf-8")
print(msg)
conn.sendline('5'.encode())
msg = conn.recvuntil("clock start").strip().decode("utf-8")
print(msg)
time.sleep(5)
msg = conn.recvuntil("now give me you solve:").strip().decode("utf-8")
print(msg)
lists = msg.split('\n')[1:10]
board = parse_input(lists)
solve(board)
solved = format_output(board)
conn.sendline(solved.encode())
conn.interactive()
getflag
烦人的压缩包
爆破
jpg文件尾压缩包
提取出来直接解压提示crc报错
观察后发现store算法却有着极高的压缩率明显不合理
改一下压缩方式和解压方式为default(单单改解压方式也够了)
解开后ook解密
sudoku_speedrun
小小升级版数独,telnet交互
kali :: ~ 127 » telnet 47.108.165.60 37569
Trying 47.108.165.60...
Connected to 47.108.165.60.
Escape character is '^]'.
Ubuntu 22.04.2 LTS
Welcome to Play Sudoku Game!
Play(1)
Exit(2)
Please input
> 1
Tips:
R to replay
Q to exit
WASD to move
You have 10000ms to solve it :)
Please select the level
easy(5)
normal(6)
hard(7)
>5
这次需要解出之后通过移动光标将数独还原
其实大差不差,这里主要几个点
-
题目用了ANSI转义码,读取数据时会有大量的乱码,需要replace掉
response=response.replace(b'\x1b[7;32m',b'').replace(b'\x1b[0m',b'').replace(b'\x1b[1;32m',b'').replace(b'\x1b[H\x1b[2J',b'')
-
这里我为方便采用了在每一行右移填补到最后之后,往下再重新左移到最左边,再开始下一行的右移填补,而不是用左移填补导致需要倒着索引,略微增加了时间复杂度
def solve(input_string): original_board = parse_input(input_string)# 创建原始数组的副本 board_copy = [row[:] for row in original_board] solution = solve_sudoku(original_board) # print(board_copy) # print(solution) lists=[] for i in range(9): for j in range(9): if board_copy[i][j] == 0: lists.append(str(solution[i][j])) if j != 8: lists.append('d') lists.extend('saaaaaaaa') # print(f"索引为 ({i}, {j}) 的位置,填入数字 {solution[i][j]}") return lists
-
读取到形如
‘’’
-------------------------
| 4 3 0 | 0 0 6 | 2 0 0 |
| 8 0 0 | 0 7 0 | 0 0 3 |
| 2 0 7 | 0 5 0 | 1 4 6 |
-------------------------
| 0 0 0 | 0 0 0 | 0 7 5 |
| 7 5 0 | 8 0 0 | 6 2 0 |
| 0 2 9 | 7 3 5 | 0 1 0 |
-------------------------
| 5 6 0 | 4 0 3 | 0 9 0 |
| 0 0 2 | 5 0 0 | 8 0 0 |
| 3 0 1 | 0 8 2 | 0 6 4 |
-------------------------’’’
转二维数组
def parse_input(input_string): rows = input_string.strip().split('\n') board = [] for row in rows: row = row.replace('-', '').replace('|', '').split() nums = [int(num) if num != '0' else 0 for num in row] if nums!=[]: board.append(nums) return board
-
经过尝试后发现只要发送数组服务器便会执行移动与填充操作,例如发送[‘d’,‘d’,‘1’]光标会右移两个单位并填入1
最终脚本:
import telnetlib
def solve_sudoku(board):
if is_complete(board):
return board
row, col = find_empty_cell(board)
for num in range(1, 10):
if is_valid(board, row, col, num):
board[row][col] = num
if solve_sudoku(board):
return board
board[row][col] = 0
return None
def is_complete(board):
for row in board:
if 0 in row:
return False
return True
def find_empty_cell(board):
for i in range(9):
for j in range(9):
if board[i][j] == 0:
return i, j
return None, None
def is_valid(board, row, col, num):
# Check row
if num in board[row]:
return False
# Check column
for i in range(9):
if board[i][col] == num:
return False
# Check 3x3 box
box_row = (row // 3) * 3
box_col = (col // 3) * 3
for i in range(box_row, box_row + 3):
for j in range(box_col, box_col + 3):
if board[i][j] == num:
return False
return True
def parse_input(input_string):
rows = input_string.strip().split('\n')
board = []
for row in rows:
row = row.replace('-', '').replace('|', '').split()
nums = [int(num) if num != '0' else 0 for num in row]
if nums!=[]:
board.append(nums)
return board
def solve(input_string):
original_board = parse_input(input_string)# 创建原始数组的副本
board_copy = [row[:] for row in original_board]
solution = solve_sudoku(original_board)
# print(board_copy)
# print(solution)
lists = []
for i in range(9):
for j in range(9):
if board_copy[i][j] == 0:
lists.append(str(solution[i][j]))
if j != 8:
lists.append('d')
lists.extend('saaaaaaaa')
# print(f"索引为 ({i}, {j}) 的位置,填入数字 {solution[i][j]}")
return lists
tn = telnetlib.Telnet('47.108.165.60',36697)
welcome_msg = tn.read_until(b"Please input")
print(welcome_msg.decode("utf-8"))
# 发送返回值到服务器
tn.write("1".encode("utf-8") + b"\n")
msg = tn.read_until(b"hard(7)")
print(msg.decode("utf-8"))
tn.write("5".encode("utf-8") + b"\n")
msg = ''
for i in range(15):
response = tn.read_until(b"\n")
# print((response))
response = response.replace(b'\x1b[7;32m',b'').replace(b'\x1b[0m',b'').replace(b'\x1b[1;32m',b'').replace(b'\x1b[H\x1b[2J',b'')
msg += response.decode().strip('> 5')
tn.write(str(solve(msg)).encode("utf-8") + b"\n")
tn.interact()
cancellation
浅恰了个三血还行
题目得到noise.mp4,意外的发现用windows media player播放可以读到一串sstv
结合file用Matroska打包猜测应该是mkv文件
用mkvtool发现确实有多个音频轨道
mkvextract.exe提取出来两个音频(轨道是从0开始的,mkvtool里的轨道编号从1开始的)
轨道3可以读到一张图
轨道2可以读到一个模糊无法识别的二维码,仔细观察可以发现背景图似乎就是轨道3读到的图
在测试过程中发现在一定位置挂上notch之后,可以读到很清晰的后半边的二维码,左半边变得更加模糊了,但却更加清晰的显示出背景图,明显就是轨道3的图
再结合题目名,大胆猜测轨道2的sstv做了一个叠加处理,尝试几次后2*轨道2-轨道3
可以扫描出正确的图像(这里放完整二维码图片会被csdnban掉)
import librosa
import soundfile as sf
import numpy as np
audio1, sr1 = librosa.load('2.wav', sr=None)
audio2, sr2 = librosa.load('3.wav', sr=None)
result = 2*audio1-audio2
sf.write('result.wav', result, sr1)
扫描的结果解base64得到图片
拿到flag