1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
| import re import string import sys import os import subprocess from pwn import *
TARGET_BINARY = os.path.abspath('./hyperjump') FLAG_LEN = 24
FLAG_PREFIX = "flag{" FLAG_SUFFIX = "}"
START_INDEX = len(FLAG_PREFIX)
PIN_ROOT = '/home/kali/Desktop/pintools/pin-external-4.0-linux' PIN_TOOL_PATH = os.path.abspath(os.path.join(PIN_ROOT, 'source/tools/ManualExamples/obj-intel64/inscount0.so'))
PIN_CMD_LIST = [os.path.join(PIN_ROOT, 'pin'), '-t', PIN_TOOL_PATH, '--', TARGET_BINARY]
CHARSET = string.ascii_lowercase + string.digits + "_@{}"
context.log_level = 'info'
dates = ['inscount.out', 'inscount.txt', 'pin.out'] for name in candidates: path = os.path.join(workdir if workdir else '.', name) if os.path.exists(path): try: with open(path, 'r', encoding='utf-8', errors='ignore') as f: data = f.read() m = re.search(r'(\d+)\s+instructions', data) if m: return int(m.group(1)), data m2 = re.search(r'(\d+)', data) if m2: return int(m2.group(1)), data except Exception: pass return None, None
def get_inscount(payload: bytes) -> int: IO_TIMEOUT = 5 log.info(f"Testing payload: {payload.decode('latin-1')[:START_INDEX+1]}...")
try: proc = subprocess.run( PIN_CMD_LIST, input=payload.decode('latin-1') + '\n', capture_output=True, timeout=IO_TIMEOUT, text=True, cwd='.' )
stdout = proc.stdout or "" stderr = proc.stderr or "" exitcode = proc.returncode
sys.stderr.write(f"\n--- Pin Tool 完整输出 (Exit Code {exitcode}): ---\n") if stdout.strip(): sys.stderr.write("[stdout]\n" + stdout.strip() + "\n") if stderr.strip(): sys.stderr.write("[stderr]\n" + stderr.strip() + "\n") sys.stderr.write("--------------------------------------------------\n")
combined = stdout + "\n" + stderr
match_re = re.search(r'(\d+)\s+instructions', combined, re.IGNORECASE) if match_re: return int(match_re.group(1))
lines = combined.strip().splitlines() for line in reversed(lines): s = line.strip() if s.isdigit(): return int(s)
file_count, file_content = read_inscount_outfile(workdir='.') if file_count is not None: try: os.remove('inscount.out') except Exception: pass return file_count
low = combined.lower() if exitcode is not None and exitcode != 0: if any(k in low for k in ['nope', 'try again', 'wrong', 'incorrect']): return 0 if stderr.strip(): return 0
if exitcode == 0 and any(k in low for k in ['flag', 'correct', 'congrats', 'success']): return 10**9
log.warning("无法从 Pin 输出或文件中解析到指令数(stdout/stderr/file 均无数字)。") return 0
except subprocess.TimeoutExpired as te: sys.stderr.write(f"[TIMEOUT] Pin 运行超时: {te}\n") return 0 except FileNotFoundError as fe: sys.stderr.write(f"[FATAL] 找不到 pin 可执行文件或路径错误: {fe}\n") return 0 except Exception as e: sys.stderr.write(f"[FATAL ERROR] get_inscount 发生错误: {e}\n") return 0
def main(): if FLAG_LEN < len(FLAG_PREFIX) + len(FLAG_SUFFIX): log.critical("FLAG_LEN 太短,不能容纳 prefix 和 suffix") return
known_flag = list("A" * FLAG_LEN) for i, ch in enumerate(FLAG_PREFIX): known_flag[i] = ch known_flag[-1] = FLAG_SUFFIX
fixed_positions = set(range(0, len(FLAG_PREFIX))) | {FLAG_LEN - 1} try_positions = [i for i in range(0, FLAG_LEN) if i not in fixed_positions and i >= START_INDEX]
log.info(f"开始爆破,长度 {FLAG_LEN},字符集大小 {len(CHARSET)},从索引 {START_INDEX} 开始。") log.info(f"固定前缀: '{FLAG_PREFIX}',固定后缀: '{FLAG_SUFFIX}'。将尝试位置: {try_positions}")
if not os.path.exists(TARGET_BINARY): log.critical(f"目标文件不存在: {TARGET_BINARY}") return if not os.path.exists(PIN_TOOL_PATH): log.critical(f"Pin Tool 不存在: {PIN_TOOL_PATH}") return if not os.path.exists(PIN_CMD_LIST[0]): log.critical(f"Pin 可执行文件不存在: {PIN_CMD_LIST[0]}") return
for i in try_positions: log.info(f"\n>>>> 正在爆破第 {i} 位...")
max_count = 0 best_char = None
for char in CHARSET: current_test = known_flag[:] current_test[i] = char payload = "".join(current_test).encode('latin-1')
count = get_inscount(payload)
if count == 0: continue
if count > max_count: max_count = count best_char = char log.info(f"发现新的最大值: 字符 '{best_char}' -> {max_count} 条指令")
if best_char: known_flag[i] = best_char log.success(f"第 {i} 位确定为: '{best_char}'") log.success(f"当前 Flag: {''.join(known_flag)}") else: log.warning(f"第 {i} 位爆破失败。所有字符返回 0。") break
known_flag[-1] = FLAG_SUFFIX
log.success(f"\n--- 爆破完成 ---") log.success(f"最终 Flag: {''.join(known_flag)}")
if __name__ == '__main__': main()
|