bugku题目

# 大小写转换工具

while True:

print("\n=====大小写转换器=====")

print("1. 大写 → 小写")

print("2. 小写 → 大写")

print("3. 退出程序")

choice = input("请输入选项(1/2/3): ")

if choice == "1":

text = input("请输入要转小写的大写文本:")

result = text.lower()

print("转换结果:", result)

elif choice == "2":

text = input("请输入要转大写的小写文本:")

result = text.upper()

print("转换结果:", result)

elif choice == "3":

print("程序退出")

break

else:

print("输入错误,请选择1‑3")

1.备份是个好习惯

漏洞原理(备份文件泄露)

Web 开发人员经常修改index.php,备份时会生成备份文件,常见备份后缀:

复制代码
index.php.bak
index.php~
index.php.swp
index.php.bak~

.bak 是 Windows 记事本 / 编辑器最经典的备份后缀!

解题步骤

1、访问备份文件地址

在浏览器地址栏输入:

复制代码
http://160.202.254.160:10418/index.php.bak

回车,浏览器就会下载 index.php.bak 的源码备份文件。

复制代码
include_once "flag.php";
ini_set("display_errors", 0);
// 取出url ? 后面所有参数
$str = strstr($_SERVER['REQUEST_URI'], '?');
// 去掉问号,拿到参数字符串
$str = substr($str,1);
// 把字符串里面所有的 key 字样,替换成空(删除)
$str = str_replace('key','',$str);
// 将字符串解析成变量
parse_str($str);

echo md5($key1);
echo md5($key2);
// 判断条件
if(md5($key1) == md5($key2) && $key1 !== $key2){
    echo $flag."取得flag";
}

必须同时满足 2 个条件

  1. md5($key1) == md5($key2) 弱相等,哈希值相同
  2. $key1 !== $key2 强不等,两个变量本身不能完全一样

关键坑点:str_replace('key','',$str)

它会把参数字符串里面 所有 "key" 文字删掉 举个例子:如果你写 ?key1=QNKCDZO&key2=240610708 原始字符串:key1=QNKCDZO&key2=240610708 经过 str_replace('key','') 删除 key 之后 变成:1=QNKCDZO&2=240610708 👉 parse_str 就识别不出key1 key2,直接失败!

绕过思路:双写 key!

kkeyey → 里面包含 key,str‑replace 删掉中间的key kkeyey 去掉 key → key

  • kkeyey1 → 删除 key → key1
  • kkeyey2 → 删除 key → key2

最终 Payload(直接复制访问)

复制代码
?kkeyey1=QNKCDZO&kkeyey2=240610708

原理验证

  1. 原始参数串:kkeyey1=QNKCDZO&kkeyey2=240610708
  2. str_replace('key',''):把里面的key删掉 kkeyey1 → k + (key) + ey1 → key1 kkeyey2 → k + (key) + ey2 → key2
  3. parse_str 解析后得到 $key1 = QNKCDZO $key2 = 240610708
  4. MD5 弱碰撞: md5 ('QNKCDZO') = 0e830400459932425248873780520603 md5 ('240610708') = 0e462097431906509019562988736854 PHP 中 0e数字 == 0e数字 → 当作科学计数法,都等于 0,相等成立
  5. $key1 !== $key2:字符串 "QNKCDZO" 和 "240610708" 完全不一样,条件通过 → 输出 flag

备用可用 payload(其他 0e 碰撞字符串)

复制代码
?kkeyey1=s878926199a&kkeyey2=a155964671a

完整 URL 例子

复制代码
http://你的ip:端口/?kkeyey1=QNKCDZO&kkeyey2=240610708

#读取output文件将每一个字符加密后的md5解密

import hashlib

生成单个字符→md5的字典表

def get_md5(s):

return hashlib.md5(s.encode()).hexdigest()

枚举所有有可能出现在flag里的字符

charset = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ{}_"

lookup = {}

for c in charset:

lookupget_md5(c) = c

读取题目给的output文件

res = ""

with open("output","r") as f:

lines = f.readlines()

for line in lines:

md5_hash = line.strip()

res += lookupmd5_hash

print(res)

2.变量1

完整源码分析

复制代码
error_reporting(0);
include "flag1.php";
highlight_file(__file__);
if(isset($_GET['args'])){
    $args = $_GET['args'];
    if(!preg_match("/^\w+$/",$args)){
        die("args error!");
    }
    eval("var_dump($$args);");
}
?>

1. 逐段解析漏洞原理

  1. preg_match("/^\w+$/",$args) 正则 ^\w+$\w = 只能是字母、数字、下划线 ,不能包含. `

[ ( -等符号。 你传 flag1.php,里面带了 .→ 正则不通过 → 直接输出args error!`。

  1. 危险代码:eval("var_dump($$args);"); $$args 是 PHP可变变量

如果 args=flag$$args = $flag,打印$flag变量的值!

  1. 提示:flag In the variable ! flag 保存在一个变量里面,而不是文件内容,所以不能直接传文件名。

2. 核心绕过思路 ------ GLOBALS 超全局变量

PHP 超全局变量:$GLOBALS $GLOBALS 是一个数组,存放当前脚本所有已经定义的变量(包含 include 进来的flag1.php里面的 flag 变量)

重点!GLOBALS 完全由字母组成,满足正则^\w+$,不会被拦截

payload:

复制代码
?args=GLOBALS

完整 URL:

复制代码
http://160.202.254.160:19275/?args=GLOBALS

3. 为什么这个 Payload 可行

  • args=GLOBALS → $args = "GLOBALS"
  • $$args${"GLOBALS"}$GLOBALS
  • var_dump($GLOBALS) 打印出全部全局变量,就能看到 flag1.php 加载进来存 flag 的那个变量。

4. 完整攻击链路复盘

  1. include "flag1.php",执行了 flag1.php,里面定义了存 flag 的变量,存入全局作用域
  2. 传入args=GLOBALS,正则校验放行(GLOBALS 只有字母)
  3. eval 执行var_dump($$GLOBALS),输出所有全局变量,flag 直接显示在页面。

❌错误:?args=flag1.php(带点被正则拦截) ✅正确:?args=GLOBALS

你直接访问上面这条 url 就可以拿到 flag。

3.Linux2

直接使用cat brave | grep -a KEY

grep -a "KEY" brave

4.来自宇宙的信号

nopqrst

5.请攻击这个压缩包

加密 zip 包:file.zip 压缩包内加密文件:flag.png 加密方式:ZipCrypto(传统 zip 加密,支持明文攻击 bkcrack) 最低明文长度:12 字节 PNG 文件头


第 1 部分:完整安装 bkcrack(编译版)

步骤 1:更新软件源

复制代码
sudo apt update

步骤 2:安装编译依赖包

复制代码
sudo apt install git cmake build-essential -y

步骤 3:下载源码

复制代码
git clone https://github.com/kimci86/bkcrack.git

步骤 4:进入源码文件夹,创建编译目录

复制代码
cd bkcrack
mkdir build
cd build

步骤 5:编译

复制代码
cmake ..
make

✅编译成功后,可执行程序位置:./src/cli/bkcrack


第 2 部分:把压缩包放到家目录

把下载好的 file.zip 放到 /home/lgr/(你的家目录) 检查文件是否存在

复制代码
ls ~/file.zip

第 3 部分:查看 zip 包信息(验证是 ZipCrypto 加密)

复制代码
./src/cli/bkcrack -L ~/file.zip

你之前已经成功看到输出:

复制代码
0  ZipCrypto Store  ... flag.png

ZipCrypto = 可以明文攻击。

第 4 部分:明文攻击【核心命令!直接复制】

⚠️使用 printf 输出完整 12 字节 PNG 头部明文 ,解决之前not enough plaintext字节不足报错

复制代码
./src/cli/bkcrack -C ~/file.zip -c flag.png -p <(printf '\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D')

运行等待几秒,成功会输出类似:

复制代码
Keys:  xxxxxxxx xxxxxxxx xxxxxxxx

三个密钥字符串。

第 5 部分:解密导出图片文件

把下面命令中 key1 key2 key3 替换成你刚刚得到的三组密钥

复制代码
./src/cli/bkcrack -C ~/file.zip -c flag.png -k key1 key2 key3 -d ~/flag_out.png

第 6 部分:打开图片查看 flag

复制代码
xdg-open ~/flag_out.png

图片内的内容就是 flag,格式:BugKu{xxxxxx}


备用方案:免编译 pip 安装(更简单,推荐下次用)

如果你不想再编译,可以用这条命令安装,全程一步:

复制代码
pip install bkcrack

装好之后任意目录直接调用,不用写长路径:

复制代码
bkcrack -C ~/file.zip -c flag.png -p <(printf '\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D')

常见踩坑清单

  1. 报错 not enough plaintext不要用 echo,改用 printf,必须 12 字节
  2. 找不到 ./bkcrack → 编译出来的程序路径是 ./src/cli/bkcrack,不是 build 目录下
  3. 加密类型显示 AES‑256 → bkcrack 明文攻击无效,该题目就做不了
  4. 跑完攻击没有算出密钥 → 文件不是标准 png,明文头猜错了

如果你运行完明文攻击命令后得到了三组密钥,可以把输出截图发给我,我帮你生成好可以直接复制的解密命令。

6.宽带信息泄露

搜索一下.bin文件可能是什么文件

TP‑LINK 路由器备份配置文件这是最出名的conf.bin场景:路由器网页后台导出的备份配置,内部加密 / 压缩保存 WiFi 密码、宽带 PPPoE 账号密码CSDN博...。

特征:不能直接文本打开,乱码;不是 ELF 可执行。 Windows 工具:RouterPassView,直接加载 conf.bin,搜索username拿 flag。 TP‑LINK 加密 bin,也可以用开源 python 脚本tpconf‑bin‑xml.py解密导出 xml 配置文件。

下载链接:

b4190/routerpassview186.zip-代码预览-RouterPassView-路由密码恢复工具:基于实用工具技术的路由密码恢复项目 - AtomGit

ctrl+f搜索username:

得到flag{053700357621}

7.闪的好快

方案一:Kali ffmpeg 抽帧(最推荐,CTF 标准解法)

原理:ffmpeg 可以把视频,每隔一小段时间导出一张图片。闪得快就设置高帧率抽帧,保证不会漏掉二维码画面。

步骤

  1. 把下载好的视频文件放到 kali 桌面,打开终端,进入文件所在目录

    cd ~/Desktop

  2. 新建文件夹,存放导出的帧图片

    mkdir frames

  3. 执行抽帧命令,每秒提取 20 帧图片(足够抓住一闪而过的二维码)

    ffmpeg -i test.mp4 -vf fps=20 ./frames/frame_%04d.png

参数解释:

  • -i test.mp4:输入视频,把test.mp4替换成你的附件文件名
  • -vf fps=20:每秒导出 20 张图片;闪的越快 fps 数值就要越大
  • ./frames/frame_%04d.png:输出图片保存在 frames 文件夹,自动命名
  1. 进入 frames 文件夹浏览所有图片

    cd frames
    xdg-open .

一张张浏览图片,找到二维码画面。 5. 二维码图片保存,扫码。

  • Kali 扫码工具:zbarimg

    zbarimg frame_0035.png
    批量扫描全部图片
    for pic in *.png;do echo "==== pic ===="; zbarimg "pic";done

直接把扫码输出全部保存进日志文件,之后直接搜 SYC 就行,一步到位。

执行这条命令(在 frames 文件夹内运行)

复制代码
for pic in *.png;do echo "==== $pic ====" >> scan_result.txt; zbarimg -q --qr "$pic" >> scan_result.txt 2>/dev/null;done

解释:

  • 所有扫码结果写入 scan_result.txt
  • 2>/dev/null:屏蔽掉那些 "找不到二维码" 的警告垃圾信息

2、扫描完成后,直接搜索 SYC

复制代码
grep "SYC" scan_result.txt

输出内容就是 flag,格式SYC{xxxx}

方案二:Windows 播放器手动定格(新手最简单)

原理

用播放器逐帧前进,当二维码闪现的时候立刻暂停。

步骤

  1. 使用播放器 PotPlayer / VLC 打开视频
  2. 快捷键逐帧播放:
    • PotPlayer 快捷键: 单帧前进
  3. 一点点往后逐帧挪,直到二维码出现,立刻截图
  4. 微信 / QQ 扫描截图里的二维码,读取 flag

为什么可行:视频是连续画面,逐帧前进不会跳过一闪而过的二维码。

方案三:OpenCV‑Python 脚本自动抽帧(进阶自动化)

适合不想手动翻几百张图片,脚本自动导出所有帧

复制代码
import cv2
vidcap = cv2.VideoCapture('test.mp4')
success,image = vidcap.read()
count = 0
while success:
  cv2.imwrite("frame%d.png" % count, image)
  success,image.read()
  count += 1

运行之后,视频每一帧都会被保存成图片文件,绝对不会漏掉二维码画面。 然后扫码找到的二维码图片。

方案四:在线视频拆帧网站(零安装,懒人方案)

原理:上传视频到在线帧提取网站,网站自动把视频切成图片包下载。 流程:

  1. 浏览器打开视频转帧在线工具
  2. 上传附件视频,设置高帧率提取(15‑25fps)
  3. 下载打包好的所有帧图片,解压,找到二维码截图扫码

🔍踩坑避坑 & 思考复盘

  1. 为什么不能直接播放视频? 二维码画面持续时间极短,人眼反应速度跟不上,等你看到的时候画面已经消失,必须定格 / 拆帧。
  2. fps 参数怎么选?
  • 一闪而过:fps=20~30
  • 画面停留半秒:fps=5 就足够 fps 越高,生成图片数量越多,越不容易漏掉,但图片文件也越多。
  1. zbarimg 扫码失败怎么办
    • 图片模糊:可以用画图工具放大二维码再扫码
    • 二维码不全:回到帧文件夹,找相邻的下一帧图片

零代码懒人终极方案(最省事,不用写任何 python)

关掉 vscode 脚本,直接打开在线 GIF 拆帧网站,上传 masterGO.gif,一键下载全部图片,直接扫码即可。 或者如果你电脑有 ffmpeg,cmd 一行命令搞定:

复制代码
ffmpeg -i masterGO.gif frame_%02d.png

wps可以一帧一帧看图片,直接微信扫描。

本题最终 flag

S Y C { F 1 a S h _ s o _ f 4 s T }

8.简单加密

末尾AA结束,想到可能是base64中的结尾:== 偏移过来的,先使用ASCII偏移转换找到两个==,再使用base64解码。

key{68743000650173230e4a58ee153c68e8}

9.告诉你个秘密

第1步:所有字符只包含:0‑9、大写字母A‑F

这是十六进制 (hex/base16) 最标志性的特征,属于 CTF 密码题第一优先级检查项。

排除其他可能性

MD5:固定 32 位,这里长度明显更长;

SHA1:40 位,长度也不匹配;

不是直接密文:一堆数字 + A‑F 几乎不会是明文加密结果;

base16解码结果:

cjV5RyBscDlJIEJqTSB0RmhC

VDZ1aCB5N2lKIFFzWiBiaE0g

第 2 步:解码后为什么立刻想到 Base64?

看到的线索

hex 解码出来的文本:cjV5RyBscDlJIEJqTSB0RmhCVDZ1aCB5N2lKIFFzWiBiaE0g 字符全部落在 Base64 合法字符集:A‑Z a‑z 0‑9 + / =

base64解码结果:

r5yG lp9I BjM tFhB

T6uh y7iJ QsZ bhM

键盘包围密码」(键盘围栏密码)固定规则: 每 4 个字符,代表键盘上一个字母的上下左右 4 个方向按键,四个点包围住中间目标字母。 格式永远是:XXXX XXXX XXXX,4 字符 = 1 组,一组解密出1 个明文字母。

TONGYUAN

flag{TONGYUAN}

10.game1

打开网页源代码看到

  1. 三条箭头分别讲解

var ppp='112.96.211.89';

定义了一个 ip 参数,写死的固定值,提交请求时必须带上。

var sign = Base64.encode(score.toString());

sign 才是经过 Base64 加密的值!!!

score = 你的游戏分数(例如 100000),先转字符串,再 base64 加密,结果存进变量sign

一直把加密后的密文当成num参数,根本就没有 num 这个参数!

xmlhttp.open("GET","score.php?score="+score+"&ip="+ppp+"&sign="+sign, true);

最最关键:它是 GET 请求!!不是 POST!!! 访问的页面不是 / 而是 score.php 携带 3 个参数:

score:明文分数(100000)

ip:固定 ip 112.96.211.89

sign:分数经过 base64 加密之后的值

完整的正确请求 URL

明文分数:100000 base64 加密 100000 → zMMTAwMDAw==

拼接完整 url:

http://160.202.254.160:14156/score.php?score=100000\&ip=112.96.211.89\&sign=zMMTAwMDAw==

直接复制这条链接丢进浏览器地址栏访问,立刻就能拿到 flag!

方法二:抓包更改分数。

相关推荐
新网企兴40 分钟前
2026西安GEO推广选哪家?新网企兴帮您精准获客
人工智能·python
西西小飞龙43 分钟前
npm vs pnpm
前端·npm·node.js
zh_xuan44 分钟前
c++ string_view
开发语言·c++
阿里嘎多学长1 小时前
2026-09-05 GitHub 热点项目精选
开发语言·程序员·github·代码托管
天天进步20151 小时前
Pixelle-Video 源码解析 #17:TTS 语音生成:Edge-TTS、Index-TTS 如何接入?
前端·数据库
古少侠1 小时前
用 DS随心转 把 AI 画的 Mermaid 流程图转成 Word 里的高清图
开发语言·c#·word
2601_962297481 小时前
一、Python GUI 的十字路口:免费凑活还是付费破局
python·gui·tkinter·customtkinter·bravurasdk
晴天161 小时前
Tsup:TypeScript库打包的“零配置极速方案”
前端·javascript·typescript
万年咸鱼1 小时前
Java BufferedOutputStream 详解:原理、用法与性能优化
java·开发语言·性能优化