0x01 题目

题目大意:规定时间内通过解决数个数独问题来获得flag。

image-20230611010421239

image-20230611005056289

一共需要120分。

0x02 解题思路

先分析交互命令行的输入输出:

image-20230611005149286

首先输入1开始游戏,题目给出三种难度,难度越高分值越大。

输入3/4/5选择游戏难度,然后题目给出数独题目内容,其中数字0表示需要填入的内容。

数独游戏规则:

每一行、每一列、每一个粗线宫内的数字不重复,其中粗线宫的划分如下所示:

数独题目

将解出的答案以题目要求的格式输入即可,得到120分时可以获得flag(实际上是得到shell)。

首先上网搜一段解决数独的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
from pprint import pprint


def find_next_empty(puzzle):
# finds the next row, col on the puzzle that's not filled yet --> rep with 0
# return row, col tuple (or (None, None) if there is none)

# keep in mind that we are using 0-8 for our indices
for r in range(9):
for c in range(9): # range(9) is 0, 1, 2, ... 8
if puzzle[r][c] == 0:
return r, c

return None, None # if no spaces in the puzzle are empty (0)

def is_valid(puzzle, guess, row, col):
# figures out whether the guess at the row/col of the puzzle is a valid guess
# returns True or False

# for a guess to be valid, then we need to follow the sudoku rules
# that number must not be repeated in the row, column, or 3x3 square that it appears in

# let's start with the row
row_vals = puzzle[row]
if guess in row_vals:
return False # if we've repeated, then our guess is not valid!

# now the column
# col_vals = []
# for i in range(9):
# col_vals.append(puzzle[i][col])
col_vals = [puzzle[i][col] for i in range(9)]
if guess in col_vals:
return False

# and then the square
row_start = (row // 3) * 3 # 10 // 3 = 3, 5 // 3 = 1, 1 // 3 = 0
col_start = (col // 3) * 3

for r in range(row_start, row_start + 3):
for c in range(col_start, col_start + 3):
if puzzle[r][c] == guess:
return False

return True

def solve_sudoku(puzzle):
# solve sudoku using backtracking!
# our puzzle is a list of lists, where each inner list is a row in our sudoku puzzle
# return whether a solution exists
# mutates puzzle to be the solution (if solution exists)

# step 1: choose somewhere on the puzzle to make a guess
row, col = find_next_empty(puzzle)

# step 1.1: if there's nowhere left, then we're done because we only allowed valid inputs
if row is None: # this is true if our find_next_empty function returns None, None
return True

# step 2: if there is a place to put a number, then make a guess between 1 and 9
for guess in range(1, 10): # range(1, 10) is 1, 2, 3, ... 9
# step 3: check if this is a valid guess
if is_valid(puzzle, guess, row, col):
# step 3.1: if this is a valid guess, then place it at that spot on the puzzle
puzzle[row][col] = guess
# step 4: then we recursively call our solver!
if solve_sudoku(puzzle):
return True

# step 5: it not valid or if nothing gets returned true, then we need to backtrack and try a new number
puzzle[row][col] = 0

# step 6: if none of the numbers that we try work, then this puzzle is UNSOLVABLE!!
return False

example_board = [
[3, 9, 0, 0, 5, 0, 0, 0, 0],
[0, 0, 0, 2, 0, 0, 0, 0, 5],
[0, 0, 0, 7, 1, 9, 0, 8, 0],

[0, 5, 0, 0, 6, 8, 0, 0, 0],
[2, 0, 6, 0, 0, 3, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 4],

[5, 0, 0, 0, 0, 0, 0, 0, 0],
[6, 7, 0, 1, 0, 5, 0, 4, 0],
[1, 0, 9, 0, 0, 0, 2, 0, 0]
]
print(solve_sudoku(example_board))
pprint(example_board)

其次根据nc内容编写pwntools脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from pwn import *
r = remote("47.108.165.60",41572)
context.log_level = 'debug'
# r.interactive()
for k in range(25):
r.recvuntil(b'Please input:')
r.send(b'1\n')
r.recvuntil(b'Please select the level:')
r.send(b'5\n')
r.recvuntil(b'---------------------\n')
board = []
for _ in range(9):
line1 = str(r.recvline()).replace("b\'","").replace("\\n\'","")
print(f"line1= {line1}")
list1 = []
for i in line1:
list1.append(int(i))
print(list1)
board.append(list1)
pprint(board)
print(solve_sudoku(board))
pprint(board)
r.recvuntil(b'now give me you solve:')
for b in board:
line1 = ''
for l in b:
line1 += str(l)
r.sendline(line1.encode("utf-8"))
print(f"现在是第{k}轮")
r.recvline()
r.recvline()
if k == 6:
r.interactive()

将两段代码合并起来,实测下来只需要解决7轮hard难度的数独就可以拿到flag了

image-20230611010153434

本文章仅做记录和参考使用,如有错误希望师傅们在评论区指出🙏