启动
看下 ReadMe.md 里面有了几个要执行的命令:
- 安装 Docker
docker build -t fr1end .
docker run --name=fr1end -p1337:80 -p4000:4000 fr1end
这样在宿主机的 1337 和 4000 端口就启动了,这里提醒下不要改端口,系统写死了访问路径,改了之后跑起来有问题。
其实我还习惯加一下 -rm (运行完自己清理) -d(不用占着一个终端,不过要自己 stop),变成:docker run --rm --name=fr1end -p1337:80 -p4000:4000 -d fr1end
除了自己折腾,题目也有./build_docker.sh 把刚才的命令打包了。直接执行也行。
玩好了也有对应的清理命令:
docker rm fr1end -f
删容器,如果加了–rm 就不用执行这一步。docker rmi fr1end
删镜像
按照题目设计,系统运行在 http://localhost:1337/ 但是我们已经知道还有一个 4000 端口。
信息收集
打开 http://localhost:1337/ 瞅一眼,是个登陆界面,错误的账号密码提示是
Username or password incorrect. I said Friend, Gandalf.
。看 Title 是 React App,前端应该是 React 写的。
看起来 nginx 运行在 1337 端口,而后端是 4000 端口
登陆的头信息中看到后端是 Express 框架
渗透
暂时没有其他信息,先尝试爆破登陆界面。假设用户名就是 Gandalfwfuzz -w /usr/share/wordlists/rockyou.txt -d "username=Gandalf&password=FUZZ" -u http://localhost:1337/login -H "Content-Type: application/x-www-form-urlencoded" --hc 405
跑一半的时候,突然想起来这个台词,Speak Friend and Enter!
那么用户名应该是 Gandalf 密码就是 Mellon 了。果然登陆成功。
获取了一个 accessToken , 去 jwt.io 解密一下:
然后看到有一个 url 出错了 :http://0.0.0.0:4000/validate
手动请求下:
1 | curl -X POST http://localhost:4000/validate -d '{"accessToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ii4va2V5cy9wdWJsaWNrZXkuY3J0In0.eyJ1c2VybmFtZSI6IkdhbmRhbGYiLCJyb2xlIjoiYWRtaW4iLCJpYXQiOjE3MTI2Mjg5NzV9.M2UJAmoWs9NVCaj9hJGi1e-picg7TtUw_auzr19QF5Y"}' -H "Content-Type:application/json" |
看到 k 读出来了。回想起刚才的 jwt 的头 Kid 的头:
1 | { |
然后我偷偷看了下 flag.txt 的位置,就和 publickey.crt 放在一起,那么剩下的就简单了。
1 | # 现在已知 publickey , 需要伪造一个 jwt, header 里的 kid 改成 ./keys/flag.txt |
最后释放资源
1 | docker rm fr1end -f |
完结撒花。🎉