SadServers 通关记录
本文最后更新于 2023年3月26日 凌晨
“Like LeetCode for Linux”
SadServers 通关记录
关于 SadServers
-
SadServers 是一个 SaaS,用户可以在真正的 Linux 服务器上以类似“CTF”的方式测试他们的 Linux 运维技能。
-
为了减少地球二氧化碳排放,节省作者的 AWS 账单,一旦完成题目,建议使用
sudo shotdown -h now关闭服务器。
Troubleshoot and make a sad server happy!
通关记录
“Saint John”: what is writing to this log file?
-
题目描述:某个测试程序连续写入日志文件
/var/log/bad.log并填充磁盘。找到并终止它。 -
解答
# 查找占用 `/var/log/bad.log` 进程的 pid
lsof |grep /var/log/bad.log
# 终止进程
kill -9 [pid]
- 检测
# 检测终止进程后是否在 6 秒内被修改过
find /var/log/bad.log -mmin -0.1
“Saskatoon”: counting IPs
-
题目描述:根据Web服务器访问日志
/home/admin/access.log找出请求最多的 IP 地址,并将其写入/home/admin/highestip.txt -
解答
# 取出文件第一列
awk '{print $1}' /home/admin/access.log
# 排序
awk '{print $1}' /home/admin/access.log |sort
# 计数(次数在第一列)
awk '{print $1}' /home/admin/access.log |sort |uniq -c
# 对计数排列
awk '{print $1}' /home/admin/access.log |sort |uniq -c |sort -r
# 取第二列第一行
awk '{print $1}' /home/admin/access.log |sort |uniq -c |sort -r |head -1 |awk '{print $1}'
# 输出到指定文件
awk '{print $1}' /home/admin/access.log |sort |uniq -c |sort -r |head -1 |awk '{print $1}' > /home/admin/highestip.txt
- 检测
# 检验 hash 值
sha1sum /home/admin/highestip.txt
“Santiago”: Find the secret combination
-
题目描述:
- 找到
/home/admin目录中字符串Alice在*.txt文件中的出现次数 - 在字符串
Alice仅出现一次的文件中在此之后一行中的数字 - 将这两个数字写入
/home/admin/solution
- 找到
-
解答:
# 找字符串出现次数(-type f 指普通文件),返回各文件中字符串出现次数
find /home/admin -type f -name "*.txt" |xargs grep -c 'Alice'
# 写入结果(无换行符)
echo -n 411 > /home/admin/solution
# 对仅出现一次的文件 1342-0.txt 查找 alice 出现后的一行
cat /home/admin/1342-0.txt| grep 'Alice' -A 1
# 写入结果(追加一行)
echo 156 >> /home/admin/solution
- 检测
# 检验 hash 值
md5sum /home/admin/solution
“Manhattan”: can’t write data into database
-
题目描述:现有 Postgres 数据库中无法插入,解决该问题。
- Postgres 监听 5432 端口,data_directory 在
/opt/pgdata/main,由 systemd 作为一个名为 postgresql 的单元进行管理
- Postgres 监听 5432 端口,data_directory 在
-
解答:
# 重启服务
sudo systemctl restart postgresql
# 查看服务错误日志,postgresql cluster 启动失败
journalctl -p err
# 查看系统日志,发现空间不足
cat /var/log/syslog
# 查看磁盘空间,/opt/pgdata/ 占用满
df -h
# 检查 data_directory 目录大小
du -sh /opt/pgdata/main
# 删除 /opt/pgdata/ 中所有 *.bk 文件并重启
rm /opt/pgdata/*.bk
sudo systemctl restart postgresql
- 检测
# 插入数据
sudo -u postgres psql -c "insert into persons(name) values ('jane smith');" -d dt
“Tokyo”: can’t serve web file
-
题目描述:配置好的 Web 服务器,代理
/var/www/html/index.html时异常 -
解答:
# 测试 curl 命令未中止且无回显,说明网阻塞
# 查看防火墙规则,http 阻塞
iptables -L
# 清空防火墙
iptables -F
# 测试 curl 命令有回显,显示 403 Forbbiden
# 查看权限
ls -l /var/www/html/index.html
# 修改权限
chmod 777 /var/www/html/index.html
- 检测
curl 127.0.0.1:80
“Cape Town”: Borked Nginx
-
问题描述:执行
curl -I 127.0.0.1:80时回显curl -I 127.0.0.1:80 returns curl: (7) Failed to connect to localhost port 80: Connection refuse。解决该异常。Nginx 由 systemd 管理。 -
解答:
# 重启 Nginx,失败
systemctl restart nginx
# 检查配置文件,报错
nginx -t
# 重新加载配置并重启 nginx,检测报错 500 Internal Server Error
# 查看 Nginx 日志,发现 24: Too many open files
cat /var/log/nginx/error.log
# 增加 systemd 中在 `/etc/systemd/system/nginx.service` 的打开文件上限 LimitNOFILE
# 重新加载 systemd 配置并重启 nginx
systemctl daemon-reload
systemctl restart nginx
- 检测
curl -Is 127.0.0.1:80| head -1
“Salta”: Docker container won’t start
-
问题描述:在 8888 端口上启动一个用于 Node.js 应用的容器,容器镜像目录在
/home/admin/app -
解答:
# 查看列表容器
docker ps -a
# 查看启动日志,server.js 缺失
docker logs 124a4fb17a1c
# 修改 Dockerfile
cd /home/admin/app
vim Dockerfile
# 重新构建镜像
docker build -t app .
# 启动容器,发现端口占用
docker run -d -p 8888:8888 app
# 查看端口占用(lsof -i:[port] 无法使用,并解除占用后启动成功
netstat -tunlp| grep 8888
kill -9 620
- 检测
curl localhost:8888
“Venice”: Am I in a container
-
问题描述:判断是在容器中还是在宿主机中
-
解答:
# 查看 PID = 1 进程的环境变量,有 container=youlooked
cat /proc/1/environ|tr "\0" "\n"
# 查看根目录信息 inode 编号(宿主机的根目录的 inode 编号一般为 2,与平台有关)
ls -ali
- 检测:无
“Oaxaca”: Close an Open File
-
问题描述:文件
/home/admin/somefile已打开以供某些进程写入。在不终止进程的情况下关闭此文件。 -
解答:
# 获取文件描述符编号,77
lsof /home/admin/somefile
# 关闭文件描述符编号 77 的文件
exec 77>&-
- 检测
# 无返回
lsof /home/admin/somefile
“Melbourne”: WSGI with Gunicorn
-
问题描述:
/home/admin/WSGI.py是一个Python WSGI web应用程序文件,其目的是提供字符串“Hello,world!”。- 该文件由 Gunicorn 服务器提供,该服务器由 nginx 服务器前置(两个服务器均由 systemd管理)。
- 因此,HTTP请求的流程是:
Web Client(curl)->Nginx->Gunicorn->wsgi.py。 - 目标是配置服务器使得
curl -s http://localhost时返回“Hello,world!”。
-
解答:
# 返回 Connection refused
curl localhost
# nginx 代理 /run/gunicorn.socket
cat /etc/nginx/sites-enabled/default
# gunicorn 使用的 /run/gunicorn.sock,修改 nginx
cat /etc/systemd/system/gunicorn.service
# 无回显
curl localhost
# 返回 Content-Length: 0,修改 wsgi.py(使用等于或大于消息所需的13个字节数,或完全去掉Content-Length 标头)
curl -i localhost
# 重启
systecm restart gunicorn
- 检测
curl -s http://localhost
“Lisbon”: etcd SSL cert troubles
-
问题描述:在
https:// localhost:2379上运行了一个 etcd 服务器,获取键“foo”的值 -
解答:
# certificate has expired or is not yet valid(系统时间超前一年)
etcdctl get foo
# 设置系统时间到一年前
date -s "last year"
# 查看防火墙
sudo /usr/sbin/iptables -t nat -L
# 删除规则
sudo /usr/sbin/iptables -t nat -F
- 检测
etcdctl get foo
“Jakarta”: it’s always DNS
-
问题描述:在
ping google.com时返回ping: google.com: Name or service not known -
解答:
# 配置解析顺序
# 把 hosts: files 修改为 hosts: files dns
# 代表先 files(/etc/hosts)解析,再从 dns(/etc/resolv.conf)解析
vim /etc/nsswitch.conf
- 检测
ping google.com
“Bern”: Docker web container can’t connect to db container
-
问题描述:一个正常的 Wordpress Docker 无法了解到 MariaDB Docker,
curl -s localhost:80 |tail -4时显示Error establishing a database connection -
解答:
# 查看 Wordpress 容器与 WORDPRESS_DB 相关的配置
docker exec wordpress env | grep "WORDPRESS_DB"
# 查看 MariaDB 容器相关的配置
docker inspect mariadb
# 比较 wp-config.php,username 和 password 正确,但是 WORDPRESS_DB_HOST 未定义
docker exec wordpress grep WORDPRESS_DB_ /var/www/html/wp-config.php
# 能够正常访问
docker exec wordpress mysqladmin -h mysql -u root -ppassword -h 172.17.0.2
# 利用 --link 重建 docker
docker stop wordpress ; \
docker rm wordpress ; \
docker run -d \
--name wordpress \
-v html:/var/www/html \
--link mariadb:mysql \
-p 80:80 \
-e WORDPRESS_DB_HOST=mysql \
-e WORDPRESS_DB_NAME=wordpress \
-e WORDPRESS_DB_USER=root \
-e WORDPRESS_DB_PASSWORD=password \
wordpress:sad
- 检测
# 返回 mysqld is alive
sudo docker exec wordpress mysqladmin -h mysql -u root -ppassword ping
“Karakorum”: WTFIT – What The Fun Is This?
-
问题描述:一个二进制文件
/home/admin/wtfit没法正常启动,试修复之 -
解答:
# Permission denied
/home/admin/wtfit
# /usr/bin/chmod: Permission denied
chmod +x /home/admin/wtfit
# 在无法使用 chmod 的情况下授予执行权限
# 通过 perl 脚本调用
perl -e 'chmod 0755, "/usr/bin/chmod"'
# 通过 ld-linux 库调用
/lib64/ld-linux-x86-64.so.2 /usr/bin/chmod +x /usr/bin/chmod
chmod +x /home/admin/wtfit
# ERROR: can't open config file
/home/admin/wtfit
# strace 检查调用,发现打开 /home/admin/wtfitconfig.conf
strace /home/admin/wtfit
# 创建 /home/admin/wtfitconfig.conf
touch /home/admin/wtfitconfig.conf
# ERROR: can't connect to server
/home/admin/wtfit
# 再次检查调用,发现使用 127.0.0.1:7777
strace /home/admin/wtfit
# 使用 netcat 监听端口,接收到一个 HTTP GET 包
nc -l -p 7777
# 启动 HTTP 服务器
python3 -m http.server --bind 127.0.0.1 7777
- 检测
# 返回 OK
/home/admin/wtfit
“Singara”: Docker and Kubernetes web app not working
-
问题描述:从主机访问部署的“webapp”网络服务器并找到它服务的消息
-
解答:
# 获取所有 pod 状态,web 状态为 ImagePullBackOff
kubectl get -A pod
# 尝试 pull webapp 镜像失败
docker pull webapp
# 查看所有镜像,有 register
docker images
# 启动 register 镜像仓库
docker run -d -p 5000:5000 registry:2
# 提交镜像
docker tag webapp localhost:5000/webapp
docker push localhost:5000/webapp
# 删除 webapp-deployment 的 Deployment 对象
kubectl delete deploy webapp-deployment -n web
# 修改 deployment.yaml,需要改 image 为 localhost:5000/webapp 以及 port 为 8888
vim /home/admin/deployment.yml
# 应用修改
kubectl apply -f /home/admin/deployment.yml
# 开放端口
kubectl port-forward deployments/webapp-deployment 8888 -n web
- 检测
curl localhost:8888
“Hong-Kong”: can’t write data into database
-
问题描述:类似于 “Manhattan” 问题,需要插入一行到 Postgres 数据库中
-
解答:
# 查看服务错误日志,显示 Timed out waiting for device /dev/xvdb
# postgres 的目录在 /opt/pgdata/ 但没数据,可能有未挂载的磁盘卷
journalctl -p err
# 查看磁盘分区状态,/dev/nvme0n1 未挂载
lsblk -f
# 尝试挂载,失败
mount /dev/nvme0n1 /opt/pgdata
# 查看日志,显示 Unit is bound to inactive unit dev-xvdb.dev
journalctl|tail
# 修改 /etc/fstab,把 /dev/xvdb 改成 /dev/nvme0n1
vim /etc/fstab
# 重启,挂载成功
systemctl daemon-reload
mount /dev/nvme0n1 /opt/pgdata
# 执行仍失败,日志显示 No space left on device
# 检查磁盘空间,/opt/pgdata/ 占用满
df -h
# 计算 Postgres 数据目录大小
du -sh /opt/pgdata/main
# 删除 /opt/pgdata/ 中所有 *.bk 文件并重启
rm /opt/pgdata/*.bk
sudo systemctl restart postgresql
- 检测
# 返回 insert 0 1
sudo -u postgres psql -c "insert into persons(name) values ('jane smith');" -d dt
“Pokhara”: SSH and other sshenanigans
-
问题描述:一个用户 client 和它的 SSH 公钥被添加到服务器。目标是能够作为该用户使用它的 SSH 密钥在本地进行 SSH(只有一台服务器)。
-
解答:
# 直接运行,报 “man-in-the-middle” 警告
sudo -u client ssh client@localhost 'pwd'
# 清空 known_hosts 配置
ssh-keygen -f "/home/client/.ssh/known_hosts" -R "localhost"
# 再次运行,显示 client@localhost: Permission denied (publickey).
sudo -u client ssh client@localhost 'pwd'
# 删除 ssh 错误配置并重启服务
rm /etc/ssh/sshd_config.d/sad.conf
systemctl restart ssh
# 再次运行,显示 WARNING: UNPROTECTED PRIVATE KEY FILE! Permissions 0644 for '/home/client/.ssh/id_rsa' are too open.
sudo -u client ssh client@localhost 'pwd'
# 修改 /home/client/.ssh/id_rsa 权限
chmod 600 /home/client/.ssh/id_rsa
# 再次运行,显示 Your account has expired; please contact your system administrator.
sudo -u client ssh client@localhost 'pwd'
# 查看 client 的账户有效期,被设置到 0
lslogins client
# 或
grep client /etc/shadow
# 修改有效期
chage -E-1 client
# 再次运行,显示 exec request failed on channel 0,系统线程有限制
sudo -u client ssh client@localhost 'pwd'
# 查看文件描述符配置(/etc/pam.d/sshd 中引用),删除 client hard nproc 0
vim /etc/security/limits.conf
# 再次运行,显示 This account is currently not available.
sudo -u client ssh client@localhost 'pwd'
# 查看用户登录信息,shell 显示 /usr/sbin/nologin
lslogins client
# 查看所有可用 shell
cat /etc/shells
# 设置用户登录 shell 为 /bin/bash
usermod --shell /bin/bash client
- 检测
# 返回 /home/client
sudo -u client ssh client@localhost 'pwd'
“Roseau”: Hack a Web Server
-
问题描述:说明:本地 Apache Web 服务器可以提供的文件中存储了一个 secret。 找到这个 secret 并将其保存为
/home/admin/secret.txt文件。- 密码破解程序 Hashcat 和 Hydra 是从软件包安装的,而 John the Ripper 二进制文件是从
/home/admin/john/run中的源代码构建的
- 密码破解程序 Hashcat 和 Hydra 是从软件包安装的,而 John the Ripper 二进制文件是从
-
解答:
# 有 webfile 文件,权限不够无法打开
ls /var/www/html/
# 401 Unauthorized,需要正确的 credentials
curl localhost
# 查看 credentials 位置,在 /etc/apache2/.htpasswd
vim /etc/apache2/sites-enabled/000-default.conf
# 用 John the Ripper 破解,得到账户:密码为 carlos:chalet
cd ~ ; john/run/john /etc/apache2/.htpasswd
# 查看 webfile,并输出到 secret
curl localhost/webfile -u "carlos:chalet" --output secret
# 查看 secret 文件类型,是 zip
file secret
# 解压,但是有密码保护
unzip secret
# zip2john 提取 hash
john/run/zip2john secret > zip.hash
# 用 John the Ripper 破解,得到密码 andes
john/run/john zip.hash
# 解压,成功得到 secret.txt
unzip secret
- 检测
# 返回 cc2c322fbcac56923048d083b465901aac0fe8f8
sha1sum /home/admin/secret.txt |awk '{print $1}'