出题报告: container/registry_misc
出题报告: container/registry_misc
hwctf202001/container/registry_misc
题目描述
请获取该镜像仓库中的flag.txt docker pull swr.cn-south-1.myhuaweicloud.com/huaweictf/registry_misc:v2
- 难度: 2/5
- 预计解题时间: 3h
出题目的
- 引导选手发现并学习registry v2 api
- 引导选手理解业界镜像仓库的实现原理
writeup
直接执行docker pull发现无法下载镜像
st0n3@yoga:~$ docker pull swr.cn-south-1.myhuaweicloud.com/huaweictf/registry_misc:v2
Error response from daemon: mediaType in manifest should be 'application/vnd.docker.distribution.manifest.v2+json' not ''
根据题目描述、报错信息,经过搜索引擎搜索一段时间后,可以发现该镜像的格式不正确,所以docker daemon无法识别。
根据docker registry v2的官方文档(https://docs.docker.com/registry/spec/api/), 可以发现registry v2的api, 根据这些api应该可以下载文件内容
经过一段时间的学习,可以发现manifest是描述一个镜像的关键文件
GET /v2/<name>/manifests/<reference>
Host: <registry host>
Authorization: <scheme> <token>
查看该镜像的manifest如下
╭─st0n3@yoga in ~
╰$ curl -s -k -H "Authorization: Bearer x" -H "Accept: application/vnd.docker.distribution.manifest.v2+json, application/vnd.docker.distribution.manifest.list.v2+json, application/vnd.oci.image.manifest.v1+json, application/vnd.oci.image.index.v1+json, */*" https://swr.cn-south-1.myhuaweicloud.com/v2/huaweictf/registry_misc/manifests/v2 | python -m json.tool
{
"config": {
"digest": "sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a",
"mediaType": "application/vnd.unknown.config.v1+json",
"size": 2
},
"layers": [
{
"annotations": {
"org.opencontainers.image.title": "flag.txt.sha256"
},
"digest": "sha256:6adb790c8a0650571d57e93b10e5d3afb1905cd89ce6d65ea69ad5025ce697b6",
"mediaType": "application/vnd.oci.image.layer.v1.tar",
"size": 75
}
],
"schemaVersion": 2
}
发现其中有一个layer名为flag.txt.sha256, 但是没有发现flag.txt ? 先使用blob api下载下来再说
GET /v2/<name>/blobs/<digest>
Host: <registry host>
Authorization: <scheme> <token>
直接访问发现会302,直接follow 即可获取flag.txt.sha256的内容
╭─st0n3@yoga in ~
╰$ curl -L -s -k -H "Authorization: Bearer x" -H "Accept: application/vnd.docker.distribution.manifest.v2+json, application/vnd.docker.distribution.manifest.list.v2+json, application/vnd.oci.image.manifest.v1+json, application/vnd.oci.image.index.v1+json, */*" https://swr.cn-south-1.myhuaweicloud.com/v2/huaweictf/registry_misc/blobs/sha256:6adb790c8a0650571d57e93b10e5d3afb1905cd89ce6d65ea69ad5025ce697b6
69bccaa2d38b8f08503667662c99113a512e46581bc003b131d06de69c0f5e0d flag.txt
看起来像是执行了sha256 flag.txt
命令的结果
难道flag.txt即使不存在于镜像文件中,我们也能下载?
╭─st0n3@yoga in ~
╰$ curl -L -s -k -H "Authorization: Bearer x" -H "Accept: application/vnd.docker.distribution.manifest.v2+json, application/vnd.docker.distribution.manifest.list.v2+json, application/vnd.oci.image.manifest.v1+json, application/vnd.oci.image.index.v1+json, */*" https://swr.cn-south-1.myhuaweicloud.com/v2/huaweictf/registry_misc/blobs/sha256:69bccaa2d38b8f08503667662c99113a512e46581bc003b131d06de69c0f5e0d
flag{ssssssssst0n3}
成功了!
我们理一下,题目大概是这样的流程
- 上传了一个flag.txt到镜像仓库huaweictf/registry_misc:v2中
- 上传了flag.txt.sha256到镜像仓库huaweictf/registry_misc:v2中
- 此时flag.txt被覆盖了,看起来,我们应该无法再获取flag.txt
而实际上,历史上传的layer,会一直存在于镜像仓库中,能下载它的前提是知道它的sha256。
exp
package main
import (
"github.com/ssst0n3/awesome_libs/awesome_error"
"github.com/ssst0n3/awesome_libs/log"
"github.com/ssst0n3/registry_v2_client/registry"
)
var (
serviceAddress = "swr.cn-south-1.myhuaweicloud.com"
repositoryName = "huaweictf/registry_misc"
reference = "v2"
r = registry.NewRegistry(serviceAddress, "", "", false)
)
func DownloadAllLayers() {
manifest, err := r.GetManifest(repositoryName, reference)
awesome_error.CheckFatal(err)
for _, layer := range manifest.Layers {
blob, err := r.FetchBlob(repositoryName, layer.Digest.String(), true)
awesome_error.CheckFatal(err)
log.Logger.Info(string(blob))
}
}
func GetFlag() {
// read from flag.txt.sha256
digest := "sha256:69bccaa2d38b8f08503667662c99113a512e46581bc003b131d06de69c0f5e0d"
blob, err := r.FetchBlob(repositoryName, digest, true)
awesome_error.CheckFatal(err)
log.Logger.Info(string(blob))
}
func main() {
// get content of file flag.txt.sha256
DownloadAllLayers()
// get content of flag.txt
GetFlag()
}