# MISC
# LSD#4
这道题直接看提示

这里用 Py 写个脚本,从 1000x1000 的位置。类似 LSB 隐写,读取红色通道,然后输出即可。
给一个 ai 写的 exp:
from PIL import Image | |
def decode_red_channel_lsb(image_path, start_x=1000, start_y=1000, size=100): | |
# 打开图像 | |
im = Image.open(image_path) | |
pixels = im.load() | |
# 提取红色通道 LSB | |
red_bits = [] | |
for y in range(start_y, start_y + size): | |
for x in range(start_x, start_x + size): | |
red_value = pixels[x, y][0] # R 通道 | |
red_bits.append(red_value & 1) # 取最低位 | |
print("\n=== 搜索Flag ===") | |
search_flag_pattern(red_bits) | |
def search_flag_pattern(bits): | |
# 将比特转换为字符串便于搜索 | |
bit_str = ''.join(str(b) for b in bits) | |
# Hero { 的 ASCII 二进制模式 | |
hero_patterns = { | |
'H': '01001000', | |
'e': '01100101', | |
'r': '01110010', | |
'o': '01101111', | |
'{': '01111011' | |
} | |
# 搜索连续的 flag 起始模式 | |
target_start = ''.join(hero_patterns[char] for char in 'Hero{') | |
if target_start in bit_str: | |
idx = bit_str.index(target_start) | |
# 提取从该位置开始的比特 | |
flag_bits = bit_str[idx:] | |
flag_bytes = bytearray() | |
for i in range(0, len(flag_bits) - 7, 8): | |
byte_bits = flag_bits[i:i + 8] | |
if len(byte_bits) == 8: | |
byte_val = int(byte_bits, 2) | |
flag_bytes.append(byte_val) | |
if byte_val == ord('}'): # 遇到结束符 | |
break | |
flag_text = flag_bytes.decode('ascii') | |
print(f"🎯 提取到Flag: {flag_text}") | |
image_path = "secret.png" # 修改为你的图像路径 | |
decode_red_channel_lsb(image_path) |
# Neverland
这题是登录上去直接试着输出 flag,发现权限不足
首先尝试 sudo 提权:

就一个可以用的,显然就是这里
然后看看内容:
TEMP_DIR="/home/peter/git-review-$$" | |
... | |
mkdir -p "$TEMP_DIR" | |
tar -xzf "$USER_ARCHIVE" -C "$TEMP_DIR" | |
EXTRACTED_DIR=$(find "$TEMP_DIR" -mindepth 1 -maxdepth 1 -type d) | |
cd "$EXTRACTED_DIR" |
这里创建了个临时目录来解压用户提交的 tar.gz
并且没有过滤解压出来的内容,并且自动 cd 到解压出来的内容中的一个目录,此后脚本里的所有 git 命令都会在这个提交的 repo 中运行:

而在执行 commit 命令时,会自动执行 hook,而我们刚好可以控制其中的内容,以 peter 的身份执行任意命令
而检查的部分只是检查了.git/config 是否和 Admin 提交的一致,这就要求我们不能改变 config 文件,也就不能改变其中的内容。
这个文件的作用:
其存储配置按小节划分,包括远程仓库地址,以及拉取推送规则等:
[remote "origin"] url=/app#可以是本地路径或者 URL fetch=+refs/heads/*:refs/remotes/origin#拉取时的分支映射规则[branch "master"] remote=origin#默认是关联的远程仓库 merge=refs/heads/master#拉取时默认合并规则[user] name=Admin email=admin@localhost[core] editor=vim hooksPath=.git/hooks#默认存放的路径,这决定了我们恶意 hook 应该放在哪里。 autocrlf=false
所以当我们复用了 Admin 原先的 config,然后构造一个 tar 包结构类似:
exploit/ <-待会被打开的目录,所有git命令将在这执行
├── .git/
│ ├── config
│ └── hooks/
│ └── pre-commit ← 恶意脚本
├── README.md
└── config-tool.py
随后脚本后面执行 commit 时就会自动执行我们的恶意脚本
将 flagcp 到 /tmp 目录下,然后自行读取
# WEB
# Revoked
首先发现有个 SQL 注入:

甚至还存储了现有的 JWT

我的天,看我一把梭出 admin:


好的好的:
然后才发现这玩意儿是废弃的,坏
通过看后面一题 rev,发现说是有测试账户没有删,但是查询数据库时会发现那个账户是同样具有 admin 权限的 admin1。但就题目而言,与 admin 本身没看出有什么区别。
PS: 在结束后在网上找到了 wp。居然是去爆破 admin1 密码的 hash,蚌埠住
# Tomcat
两次执行同一个东西按理来说是不可能得到不同的结果,而且强行将两个不同的 web 程序的 session 放在一个文件夹来实现共用。此外 compose 提到 bp,盒异味。
# SYSTEM
# Movie Night
还是一题提权,绷不住:
首先看一眼 sudo 除了没什么用的自己提权自己以外没有任何东西
然后稍微尝试一下发现几乎没法访问任何 dev 用户的文件,所以哪里肯定有权限接口,看一下程序:
find / -user dev -ls 2>/dev/null |
输出了一大堆,看不懂没关系,但是要注意到在一大堆 proc 中,有一个:

在 tmp 目录下,显然不是正常会有的东西,而且我们是可读可写的。
搜一下什么是 tmux

尝试连接一下:
tmux -S /tmp/tmux-1002 attach |
这个语法在教程中似乎并没有,但是问问 ai 应该就行了
得到 shell,获取 flag
