0%

downwardAPI存储卷

– 摘自 《kubernetes进阶实战》

很多时候,应⽤程序需要基于其所在的环境信息设定运⾏特性等,这类环境信息包括节点及集群的部分详细属性信息等,例如,Nginx进程可根据节点的CPU核⼼数量⾃动设定要启动的worker进程数,JVM虚拟机可根据节点内存资源⾃动设定其堆内存⼤⼩。类似地,托管运⾏于Kubernetes的Pod对象中的容器化应⽤偶尔也需要获取其所属Pod对象的IP、主机名、标签、注解、UID、请求的CPU及内存资源量及其限额,甚⾄是Pod所在的节点名称等,容器可以通过环境变量或downwardAPI存储卷访问此类信息,不过,标签和注解仅⽀持通过存储卷暴露给容器。

环境变量式元数据注⼊

引⽤downwardAPI元数据信息的常⽤⽅式之⼀是使⽤容器的环境变量,它通过在valueFrom字段中嵌套fieldRef或resourceFieldRef字段来引⽤相应的数据源。不过,通常只有常量类的属性才能够通过环境变量注⼊到容器中,毕竟,在进程启动完成后将⽆法再向其告知变量值的变动,于是,环境变量也就不⽀持中途的更新操作。

可通过fieldRef字段引⽤的信息具体如下。

·spec.nodeName:节点名称。
·status.hostIP:节点IP地址。
·metadata.name:Pod对象的名称。
·metadata.namespace:Pod对象⾪属的名称空间。
·status.podIP:Pod对象的IP地址。
·spec.serviceAccountName:Pod对象使⽤的ServiceAccount资源的名称。
·metadata.uid:Pod对象的UID。
·metadata.labels[‘‘] :Pod对象标签中的指定键的值,例如
metadata.labels[‘mylabel’],仅Kubernetes 1.9及之后的版本才⽀持。
·metadata.annotations[‘‘] :Pod对象注解信息中的指定键的值,仅Kubernetes 1.9及之后的版本才⽀持。

另外,可通过resourceFieldRef字段引⽤的信息是指当前容器的资源请求及资源限额的定义,因此它们包括requests.cpu、limits.cpu、requests.memory和limits.memory四项。

下⾯的资源配置清单⽰例(downwardAPI-env.yaml)中定义的Pod对象通过环境变量向容器env-test-container中注⼊了Pod对象的名称、⾪属的名称空间、标签app的值以及容器⾃⾝的CPU资源限额和内存资源请求等信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
apiVersion: v1
kind: Pod
metadata:
name: env-test-pod
labels:
app: env-test-pod
spec:
containers:
- name: env-test-container
image: busybox
command: [ "/bin/sh", "-c", "env" ]
resources:
requests:
memory: "32Mi"
cpu: "125m"
limits:
memory: "64Mi"
cpu: "250m"
env:
- name: MY_POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: MY_POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: MY_APP_LABEL
valueFrom:
fieldRef:
fieldPath: metadata.labels['app']
- name: MY_CPU_LIMIT
valueFrom:
resourceFieldRef:
resource: limits.cpu
- name: MY_MEM_REQUEST
valueFrom:
resourceFieldRef:
resource: requests.memory
divisor: 1Mi
restartPolicy: Never

此Pod对象创建完成后,向控制台打印所有的环境变量即可终⽌运⾏,它仅⽤于测试通过环境变量注⼊信息到容器的使⽤效果:

1
2
3
4
5
~]$	kubectl	create	-f	downwardAPI-env.yaml
pod "env-test-pod" created
$ kubectl get pods -l app=env-test-pod
NAME READY STATUS RESTARTS AGE
env-test-pod 0/1 Completed 0 1m

⽽后即可通过控制台⽇志获取注⼊的环境变量:

1
2
3
4
5
6
~]$	kubectl logs env-test-pod | grep "^MY_"
MY_POD_NAMESPACE=default
MY_CPU_LIMIT=1
MY_APP_LABEL=env-test-pod
MY_MEM_REQUEST=32
MY_POD_NAME=env-test-pod

如⽰例中的最后⼀个环境变量所⽰,在定义资源请求或资源限制时还可额外指定⼀个“divisor”字段,⽤于为引⽤的值指定⼀个除数以实现所引⽤的相关值的单位换算。CPU资源的divisor字段其默认值为1,表⽰为1个核⼼,相除的结果不⾜1个单位时则向上圆整(例如,0.25向上圆整的结果为1),它的另⼀个可⽤单位为1m,即表⽰1个微核⼼。内存资源的divisor字段其默认值为也是1,不过,它意指1个字节,此时,32Mi的内存资源则要换算为33554432的结果予以输出。其他可⽤的单位还有1Ki、1Mi、1Gi等,于是,在将divisor字段的值设置为1Mi时,32Mi的内存资源的换算结果即为32。

注意: 未为容器定义资源请求及资源限额时,downwardAPI引⽤的值即默认为节点的可分配CPU及内存资源量。

存储卷式元数据注⼊

向容器注⼊元数据信息的另⼀种⽅式是使⽤downwardAPI存储卷,它将配置的字段数据映射为⽂件并可通过容器中的挂载点进⾏访问。7.2.5节中能够通过环境变量的⽅式注⼊的元数据信息也都可以使⽤存储卷的⽅式进⾏信息暴露,除此之外,还可以在downwardAPI存储卷中使⽤fieldRef引⽤如下两个数据源。

·metadata.labels:Pod对象的所有标签信息,每⾏⼀个,格式为label-key=”escaped-label-value”。
·metadata.annotations:Pod对象的所有注解信息,每⾏⼀个,格式为annotation-key=”escaped-annotation-value”。

下⾯的资源配置清单⽰例(downwardAPI-vol.yaml)中定义的Pod对象通过downwardAPI存储卷向容器volume-test-container中注⼊了Pod对象⾪属的名称空间、标签、注解以及容器⾃⾝的CPU资源限额和内存资源请求等信息。存储卷在容器中的挂载点为/etc/podinfo⽬录,因此,注⼊的每⼀项信息均会映射为此路径下的⼀个⽂件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
kind: Pod
apiVersion: v1
metadata:
labels:
zone: east-china
rack: rack-101
app: dapi-vol-pod
name: dapi-vol-pod
annotations:
annotation1: "test-value-1"
spec:
containers:
- name: volume-test-container
image: busybox
command: ["sh", "-c", "sleep 864000"]
resources:
requests:
memory: "32Mi"
cpu: "125m"
limits:
memory: "64Mi"
cpu: "250m"
volumeMounts:
- name: podinfo
mountPath: /etc/podinfo
readOnly: false
volumes:
- name: podinfo
downwardAPI:
defaultMode: 420
items:
- fieldRef:
fieldPath: metadata.namespace
path: pod_namespace
- fieldRef:
fieldPath: metadata.labels
path: pod_labels
- fieldRef:
fieldPath: metadata.annotations
path: pod_annotations
- resourceFieldRef:
containerName: volume-test-container
resource: limits.cpu
path: "cpu_limit"
- resourceFieldRef:
containerName: volume-test-container
resource: requests.memory
divisor: "1Mi"
path: "mem_request"

创建资源配置清单中定义的Pod对象后即可测试访问由downwardAPI存储卷映射的⽂件pod_namespace、pod_labels、pod_annotations、limits_cpu和mem_request等:

1
2
~]$	kubectl	create	-f	downwardAPI-vol.yaml
pod "dapi-vol-pod" created

接下来即可测试访问上述的映射⽂件,例如,查看Pod对象的标签列表:

1
2
3
4
~]$	kubectl	exec	dapi-vol-pod	--	cat	/etc/podinfo/pod_labels
app="dapi-vol-pod"
rack="rack-101"
zone="east-china"

如命令结果所⽰,Pod对象的标签信息每⾏⼀个地映射于⾃定义的路径/etc/podinfo/pod_labels⽂件中,类似地,注解信息也以这种⽅式进⾏处理。如前⾯的章节中所述,标签和注解⽀持运⾏时修改,其改动的结果也会实时映射进downwardAPI⽣成的⽂件中。例如,为dapi-vol-pod添加新的标签:

1
2
~]$	kubectl	label	pods	dapi-vol-pod	env="test"
pod "dapi-vol-pod" labeled

⽽后再次查看容器内的pod_labels⽂件的内容,由如下的命令结果可知新的标签已经能够通过相关的⽂件获取到:

1
2
3
4
5
~]$	kubectl	exec	dapi-vol-pod	--	cat	/etc/podinfo/pod_labels
app="dapi-vol-pod"
env="test"
rack="rack-101"
zone="east-china"

downwardAPI存储卷为Kubernetes上运⾏容器化应⽤提供了获取外部环境信息的有效途径,这⼀点对那些⾮为云原⽣开发的应⽤程序在不进⾏代码重构的前提下,获取环境信息进⾏⾃⾝配置等操作时尤为有⽤。

xray辅助工具-推送消息到钉钉

1、初衷

之前使用方糖进行接收漏洞信息,在开启了分布式扫描后,推送的信息过多,导致方糖账号不能使用了,需要交保护费才给开通,于是,切换到钉钉上。

2、申请钉钉机器人

登录钉钉后,点击自己的图像–>机器人管理–>自定义–>添加,创建自己的机器人。

定义一个推送关键字,我定义的是xray

前提需要创建一个至少3人的聊天群组。

如下所示:

1

以上,机器人的申请完成了。

3、编写推送程序

推送消息的程序已经编写好了,源代码如下:

python版本是python3

需要填写自己的机器人token

包含xray的扫描队列信息,URL:/getStatus

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# -*-coding: utf-8 -*-
from flask import Flask, request
import requests
import datetime
import logging
import json

app = Flask(__name__)

ding_Token = 'xxxxxxxx'

xrayStatus = {}
allUrls = 0
scannedUrls = 0
avgRspTime = 0

def getDetail(detail={}):
detailInfo = ''
try:
for key in detail.keys():
detailInfo = detailInfo + str(key) + ": " + str(detail.get(key)) + "\n\t"
return detailInfo
except Exception as e:
logging.exception(e)
finally:
return detailInfo

@app.route('/webhook', methods=['POST', 'GET'])
def xray_webhook():
if request.method == 'POST':
vuln = request.json
clientip = request.remote_addr
if "vuln_class" not in vuln:
'''
xrayStatus={'1.2.3.4':{"allUrls": 0, "scannedUrls": 0, "avgRspTime": 0}
'''
allUrls = vuln["num_found_urls"]
scannedUrls = vuln["num_scanned_urls"]
avgRspTime = vuln["average_response_time"]
xrayStatus[clientip] = {"allUrls": allUrls, "scannedUrls": scannedUrls, "avgRspTime": avgRspTime}
return "ok"
# vuln = json.loads(vuln, strict=False)

vuln_class = vuln["vuln_class"] or "Default"
vuln_plugin = vuln["plugin"]

content = """## xray_{plugin}_{vuln_class}

> url: {url}

> 插件: {plugin}

> 漏洞类型: {vuln_class}

> 发现时间: {create_time}

> 来源: {clientip}

### 详情:
​```{detail}
    """.format(url=vuln["target"]["url"],
               plugin=vuln_plugin,
               vuln_class=vuln_class,
               create_time=str(datetime.datetime.fromtimestamp(vuln["create_time"] / 1000)),
               clientip=clientip,
               detail=getDetail(vuln["detail"]))
    try:
        push_dingding_group(content, f"{vuln_plugin}_{vuln_class}")
    except Exception as e:
        logging.exception(e)
    return 'ok'
elif request.method == "GET":
    return 400, "<h1>Not Found!</h1>"
else:
    return "error"

@app.route(‘/getStatus’, methods=[‘GET’])
def getstatus():
clientip = request.remote_addr
try:
return xrayStatus[clientip]
except Exception as e:
return {clientip: {“allUrls”: 0, “scannedUrls”: 0, “avgRspTime”: 0}}

def push_dingding_group(content, vulnType):
headers = {“Content-Type”: “application/json”}
# 消息类型和数据格式参照钉钉开发文档
# URL: https://ding-doc.dingtalk.com/doc#/serverapi2/qf2nxq
data = {“msgtype”: “markdown”, “markdown”: {“title”: f”xray_{vulnType}”}}
data[‘markdown’][‘text’] = content

r = requests.post(f"https://oapi.dingtalk.com/robot/send?access_token={ding_Token}", data=json.dumps(data),
                  headers=headers)
print(r.text)

if name == ‘main‘:
app.run(host=’0.0.0.0’, port=10086)

1
2
3
4

## 4、部署消息推送程序

运行命令:

pip3 install flask
python3 Flask_send_vuln_msg_to_dingding.py

1
2
3
4
5
6



## 5、运行xray

运行xray需要增加`--webhook-output`参数

xray_windows_amd64.exe webscan –listen 0.0.0.0:1337 –html-output report__datetime__.html –webhook-output http://xxxxx/webhook

```

6、开心収洞

SRC逻辑漏洞挖掘浅谈

[前言]

​ 距离最近挖src到今天刚好一个月了,最近比较忙吧。具体应该算是5月份了,上一个月挖src的同时也被拉去参加《西安互联网安全城市巡回赛》了,还算比较幸运,通过几个逻辑漏洞,线下赛获得还算不错的结果。这个月的逻辑漏洞也相对集中。于是想写篇文章针对逻辑漏洞稍微总结一下。并且包括js静态文件信息泄漏的利用,在这篇文章做一个引入,具体更新在下一篇文章中。对于这一的出发点点也是因为在这次比赛中通过js静态文件找到了一个相对不错的高危。

1.资产收集

1.1业务范围

巧用搜索引擎首推谷歌查看了解SRC旗下涉及到的业务,收集其对应的业务下的域名,再进一步进行挖掘,如:

1

2

整理,再进行常规资产收集

3

1.2常规性质资产收集

基本的资产收集方式:子域名枚举、端口扫描、路径扫描、旁站c段查询

  • 子域名

    子域名爆破:

    sublist3r、subdomainsBurte、DiscoverSubdomain、layer子域名挖掘机

    7

    子域名枚举

    通过网络空间安全搜索引擎

    云悉资产、FOFA、Virustotal、Dnsdumpster、Threatcrowd

    5

    4

  • 路径扫描

    dirsearch 、御剑、

    6

  • 旁站C段查询

    在线旁站C段查询:www.webscan.cc、www.5kik.com、phpinfo.me

1.3信息泄漏

  • 敏感目录/文件

猪猪侠weakfilescancansinasensitivefilescan、FileSensor

Screenshot-banner-filesensor

  • 网页源码/js/json泄漏敏感接口

    1)接口泄漏

8

​ 2)json敏感信息泄漏

12

13

目前发现关于这部分没有发现比较好的收集工具或脚本,因此打算写一个,目前还正在编写中,主要基于chrom协议、pyppeteer框架动态触发爬取包含ajax以尽可能的收集到url、接口、域名:

a)网站源码涉及到的子域名ur接口资产爬取

b)网站源码js中包含的请求或拼接的访问接口

c高级功能)url接口中json信息泄漏识别

备注:该部分的具体内容将在下一篇文章【谈js静态文件在漏洞挖掘中的利用】继续更新

1.4其他业务查找

微信公众号绑定接口、app、老旧的登陆接口、版本迭代

2.越权

  • 改识别用户参数
  • 改cookie
  • 越权访问
  • 登陆后,修改密码 未校验id与用户 修改id 即可该其他人密码
  • 修改个人数据时 页面源代码有用户标识符id 抓包修改或添加id
  • 直接访问后台链接禁用js则不会跳转登录界面,直接登陆
  • 登陆分为账号和游客登陆,游客功能有限,app端只前端检测,模拟发包即可
  • 越权订单查看打印下载、越权操作他人收货地址、增删改查等。

3.逻辑漏洞

任意用户注册、密码重置、密码找回、

3.1本地验证、修改返回包

1)获取验证码后任意输入一个验证码。

图片9

2)抓包放行,得到的返回包如下

图片10

3)抓包改返回包修改为正确的返回包覆盖错误的返回包,如下

{“code”:1,”data”:”目标用户手机号”,”msg”:”绑定成功Ÿ”}

图片12

4)放行,修改成功

图片13

3.2手机号、验证码、用户未统一验证问题

未对原绑定手机号、验证码、用户未统一验证,或验证码未绑定 只验证验证码正确,没判断用户id 或手机号,修改想改的id 正确手机验证码即可

如密码找回重置时未对原绑定手机号验证进行任意账号密码重置

9

10

150\73账号被重置

11

3.3密码重置类其他逻辑问题

  1. 以重置成功的token覆盖最后一步错误的token和1类似。
  2. 密码重置时删除mobilephone参数值修改email参数值
  3. 假如找回需要4部,最后一部有user参数,用自己账号正常到第三部,第四部修改user实现

4.支付逻辑漏洞

5.步骤,可跳过步骤

酒店..

6.爆破、枚举

  1. 撞库,登陆时无验证码且可无限被尝试,用户名验证时有无用户名错误回显、密码可被爆破

  2. 无验证码,验证码不刷新,验证码4位过于简单无尝试次数限制可被爆破、

  3. 枚举注册用户 输入用户名,发送请求验证用户名是否正确(若返回次数限制,可测试服务端未限制高频访问)

  4. 登陆失败有次数限制,若包中有限制参数可更改或删除参数

  5. 邮箱轰炸,短信轰炸,burp Repeate,短信轰炸验证码有60秒限制时,有的参数修改后可绕过 如

    1)isVerfi参数 这里是1 回包 3 手机没收到信息 存在验证码限制

    逻辑1

改为0 回显2 绕过了验证码限制

逻辑2

7.其他

  • cookie一直有效,(修改密码后)

第三方账户登录绕过(拦截微博授权成功的请求地址: https://api.weibo.com/oauth2/sso_authorize?sflag=1 修改response中uid,服务端没有校验客户端提交的uid与授权成功的uid相同)

8.总结

在挖洞的过程中还是比较注重有耐心,细心测试更多参数、同时也需要我们不断的交流学习新思路,才会有更进一步的收获。另外也需要1>注重安全开发2>知识积累当然、关键还是得看自己。

简介

在k8s环境下,集群由很多node组成,一般情况下,一个集群会配置一个HA形式的镜像仓库(如Harbor),但是在分发镜像时,是每台node,逐次从镜像仓库拉取,一个1G的image分发给100台主机,会生成100G的网络流量,这些突发的流量对网络会造成一个非常大的压力。 于是,基于P2P的镜像分发方案应运而生。

dragonfly是有阿里巴巴主导开发的一款基于p2p分发镜像的方案. gayhub链接为:https://github.com/dragonflyoss/Dragonfly

架构

基本的架构如下:

架构图

部署

  • 角色分为2种, supernode和dfclient
  • 需要在每台node上配置docker的镜像仓库的镜像地址(registry-mirrors).
  • 端口,默认情况下supernode使用8001和8002, dfclient使用65001, 可根据实际情况修改

supernode部署

可以将master或者harbor主机当成supernode, 启动命令如下(截至2019-11-18,稳定版为0.4.3):

1
docker run -d --name supernode --restart=always -p 8001:8001 -p 8002:8002 -v /home/admin/supernode:/home/admin/supernode dragonflyoss/supernode:0.4.3 --download-port=8001

本测试环境supernode的ip为 “192.168.88.190”

上述命令运行完成后, supernode已经部署完成.

dfclient部署

  • 修改node的docker镜像地址配置:

    增加"registry-mirrors": ["http://127.0.0.1:65001"]

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    [root@node01 ~]# cat /etc/docker/daemon.json 
    {
    "registry-mirrors": ["http://127.0.0.1:65001"],
    "insecure-registries": ["127.0.0.1/8"],
    "max-concurrent-downloads": 10,
    "log-driver": "json-file",
    "log-level": "warn",
    "log-opts": {
    "max-size": "10m",
    "max-file": "3"
    },
    "data-root": "/var/lib/docker"
    }
  • 编写dfclient配置文件(192.168.88.190为supernode的地址),

    1
    2
    3
    4
    5
    mkdir -p /etc/dragonfly/
    cat <<EOF > /etc/dragonfly/dfget.yml
    nodes:
    - 192.168.88.190
    EOF
  • 运行dfclient

    1
    2
    3
    4
    docker run -d --name dfclient --restart=always --net=host \
    -v /etc/dragonfly:/etc/dragonfly \
    -v $HOME/.small-dragonfly:/root/.small-dragonfly \
    dragonflyoss/dfclient:0.4.3 --registry https://index.docker.io

    这里非常建议,一定要将net配置为host, 如果不是host,则注册在supernode上的地址为容器的ip, 其他主机无法直接访问.

    另外需要说明--registry参数,该参数是需要代理的镜像仓库地址, 在企业环境下,改成镜像仓库的地址即可.

测试

上面的操作完成后, 进行测试

部署2台client. 分为c1 和c2

在c1上pull nginx

在c2上pull nginx, 并tailf /root/.small-dragonfly/logs/dfclient.log, 可以看到通过dragonfly从其他node节点上获取image块.

上面日志表明, 该p2p分发环境部署成功.

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

1、安装Git bash

在windows下可以使用git Bash来执行git操作.

下载链接:https://git-for-windows.github.io/

2、 安装nodejs

hexo是基于nodejs环境的静态博客,需要nodejs执行环境,并需要npm来安装各种依赖。

npm下载链接: https://nodejs.org/en/

确认安装成功,使用node -v

3、 安装Hexo

上面两步操作完成后,开始安装hexo

  • 创建一个文件夹,用于存储blog数据,cd进入该文件夹

  • 使用npm i -g hexo安装hexo

  • 使用hexo -v 确定安装是否成功

  • 使用hexo init 初始化hexo

    image-20191117184950935

  • 解释一下:

    • node_modules:是依赖包
    • public:存放的是生成的页面
    • scaffolds:命令生成文章等的模板
    • source:用命令创建的各种文章
    • themes:主题
    • _config.yml:整个博客的配置
    • db.json:source解析所得到的
    • package.json:项目所需模块项目的配置信息

4、创建github blog

github的blog,repo名字必须为[github昵称].github.io, 创建完成后,可以通过https://[github昵称].github.io访问。

5、修改_config.yml

编辑_config.yml, 添加

1
2
3
4
deploy:
type: 'git'
repository: 'https://github.com/j4ckzh0u/j4ckzh0u.github.io'# 为自己的github repo
branch: 'master'

修改完毕后,使用下面命令推送hexo到GitHub repo

1
2
3
hexo clean
hexo generate
hexo deploy