MoeCTF 2024 WriteUp 开发与运维基础(全部+详细)
MoeCTF2024 WriteUP
CTFerName:fifker
题目链接:https://ctf.xidian.edu.cn/training/10
开发与运维基础
开发与运维基础入门指北
要求主要有这几个:
在你的家目录中有一个文件夹:1
2
31.将形如 xxxxxxx.bak 的文件清理掉
2.将所有带 xml 后缀的文件重命名为 html 后缀
3.按照前缀将所有文件分类到对应的文件夹,例如 f572d396fae9206628714fb2ce00f72e94f2258f.txt 需要放在 f5/72/f572d396fae9206628714fb2ce00f72e94f2258f.txt 下。
全部整理完毕后,使用 root 用户将其移至 /var/www/html 文件夹下,然后稍等片刻,从 /var/log/nginx/access.log 里找 flag 就可以了!
使用FinalShell连接,不过操作均使用shell命令。
我们来一个一个完成:
任务一
首先,将形如 xxxxxxx.bak 的文件清理掉。那么我们就用正则表达式匹配相关文件,然后删除(使用rm)。命令如下:
1 | rm *.bak |
任务二
第二步,看到改名字,首先能想到的就是rename命令了,可惜该系统没有该命令:

不然可以使用
1 | rename 's/\.xml$/.html/' *.xml |
或者
1 | rename .xml .html *.xml |
那么就使用for循环吧:
1 | for file in *.xml; do |
来解析一下这几行shell:
for file in *.xml,就是一个简单的for循环,在当前目录下选取所有xml后缀的文件。
然后mv "$file" "${file%.xml}.html",${file%.xml}的意思是从变量file的值中,从末尾删除.xml这个后缀。最后利用.html直接拼接上去。
这样就可以用满足全部条件。
任务三
最后一步,这一步比较复杂,使用shell脚本(附上注释):
1 | for file in *.txt *.html; do |
完成任务后,登录root用户,使用su命令:

移动文件。
1 | mv /home/user/* /var/www/html |
查看flag。
1 | cat /var/log/nginx/access.log |

哦不!我的libc!
这是一题抢救glibc的题,有点吃手速(只有一次连接机会且断的很快)
题目连接方式:
1 | ssh root@127.0.0.1 -p <port> |
由于为了降低难度,只需要恢复ls和cat即可完成题目目标,无须真的恢复服务器的glibc,所以出现了一堆非预期。
题目说到:flag 文件在 /flag.txt 。因此最简单的办法就是:
1 | echo "$(< /flag.txt)" |

哦不!我的nginx!
本题模拟 glibc 被删除后的服务器救援。动态链接程序都需要动态加载器 ld-linux-x86-64.so.2 和 libc.so.6,因此 ls、cat、cp、nginx 等命令都会无法启动。
但当前 SSH 中已经运行的 Bash 不会立刻退出。它启动时所需的库已经映射到内存,因此 Bash 内建的 printf、read、变量、重定向和 /dev/tcp 仍能使用。
本题的关键,就是先利用 Bash 内建能力写入一个静态 BusyBox,再恢复 libc 和动态加载器。
注意:坏机只能使用第一次登录得到的 Bash。不要退出 SSH,也不要建立新的 root SSH 连接,否则新的 /bin/bash 无法启动。
1. 准备静态 BusyBox
BusyBox 是静态链接程序,不依赖目标机的 glibc。先在本地下载 x86_64 musl 版本:
1 | wget https://busybox.net/downloads/binaries/1.35.0-x86_64-linux-musl/busybox |
将其上传到 neighbor:
1 | scp -P <neighbor端口> ./busybox user@127.0.0.1:~/busybox |
BusyBox 是多调用程序,执行时会根据自己的文件名决定模拟哪个命令。例如文件名为 /bin/cp 时,它会自动作为 cp 工作。
2. 为什么写入 /bin/cp
坏机没有 chmod,直接新建 /tmp/busybox 后无法赋予可执行权限。
但 /bin/cp 原本已经是可执行文件。使用重定向覆盖它的内容时,文件权限不会改变:
1 | printf '内容' > /bin/cp |
因此把静态 BusyBox 写入 /bin/cp 后,/bin/cp 仍然可以执行,并且会成为 BusyBox 的 cp applet。
3. 用 neighbor 传输 BusyBox
二进制文件不能直接可靠地存入 Bash 变量,所以先将每个字节变成 \xNN 形式的可打印文本。
在 neighbor 中执行:
1 | od -v -An -tx1 ~/busybox | |
来看看这有啥用:
首先,od -An -tx1:将 BusyBox 转为十六进制字节,不输出地址。
其次,awk:把 7f 45 4c 46 转成 \x7f\x45\x4c\x46。
最后,nc -lvp 8000:监听 8000 端口,等待坏机连接。
假设 BusyBox 大小为 S 字节,转义后长度为 4*S。本题实际 BusyBox 为 1131168 字节,因此需要读取:
1 | 1131168 * 4 = 4524672 |
在坏机第一次 root SSH 会话中执行:
1 | exec 3<>/dev/tcp/127.0.0.1/8000 |
其中:
exec 3<>...:将 TCP 连接绑定到文件描述符 3。read -u 3:从描述符 3 读取数据。-N 4524672:精确读取这么多字符。-r:保留反斜杠,不把\x提前处理。printf '%b':将\xNN重新解释为真实二进制字节。
至此,/bin/cp 已经是可执行的静态 BusyBox。
4. 恢复基础命令
1 | /bin/cp /bin/cp /bin/chmod |
这样就重新获得了文件复制、修改权限、查看文件和网络传输能力。
如果只做前面那一题,到这里将 BusyBox 复制为 /bin/ls、/bin/cat 即可读取 /flag.txt:
1 | /bin/cp /bin/cp /bin/ls |
5. 恢复 libc 和动态加载器
由于本道题要求启动 Nginx,因此还需要恢复完整动态运行环境。
neighbor 发送 libc:
1 | nc -lvp 8001 < /usr/lib/x86_64-linux-gnu/libc.so.6 |
坏机接收:
1 | /bin/nc 127.0.0.1 8001 > /usr/lib/x86_64-linux-gnu/libc.so.6 |
neighbor 发送动态加载器:
1 | nc -lvp 8002 < /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 |
坏机接收:
1 | /bin/nc 127.0.0.1 8002 > /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 |
最后恢复执行权限:
1 | /bin/chmod 755 /usr/lib/x86_64-linux-gnu/libc.so.6 |
两者缺一不可:ld-linux 负责装载动态程序,libc 提供程序运行所需的基础函数。
6. 删除事故触发器并启动 Nginx
题目通过 /root/.bashrc 模拟删除 glibc 的事故,因此恢复后必须删除它:
1 | rm -f /root/.bashrc |
验证动态程序已经能运行:
1 | ls -l /usr/lib/x86_64-linux-gnu/libc.so.6 |
启动 Nginx:
1 | nginx -g 'daemon off;' & |
客户端会持续请求服务器,并将 flag 放在请求参数中。查看访问日志:
1 | cat /var/log/nginx/access.log |
可以得到flag:
1 | moectf{th@ts-NoT+vERY_H@Rd-T0_R3scUe,riGhT?1e3e4b} |