两个主题:躲避execve与分析/proc/目录
- 2020 年 4 月 7 日
- 筆記
今天比较特别,讲两个主题,主要是为了承上启下,进行补充和过渡。
躲避execve,是在原来的文章的基础上补充一个小思路,分析/proc/目录 是为了下一篇讲解内存中修改函数做准备,要让大家提前知道这回事。
本公众号以原创干货为主,原创不易,大家如果喜欢本篇文章的话,记得点在看和转发朋友圈。
1. 躲避execve的小思路
在之前文章中,我讲解过各种躲避execve监控的方法,如果有朋友没看到过,可以点下面文章链接熟悉一下:
无"命令"反弹shell-逃逸基于execve的命令监控(上)
本文的思路,类似文件复制重命名,躲避execve监控的关键点在于创建软链接,通过创建软链接的方式来混淆命令执行的路径。下面以whoami命令为例:
ln -s /bin/whoami /tmp/whoami_tmp
接着使用strace调试执行/tmp/whoami_tmp,看一下execve的系统调用:
strace -f /tmp/whoami_tmp

由于execve执行软链接,会自动执行目标文件,不会对软链接进行转换,从而实现了隐藏。
不要以为这就结束了!!!
虽然最后执行的时候混淆了,但是在执行ln命令的时候,还是暴露了命令路径,暴露了关键字。
可以对目录下的文件进行批量创建软连接:
cp -s /bin/* /tmp/
然后对 /tmp下的软链接批量添加后缀名即可,就不会暴露命令了。
之前有朋友说很简单,直接将bash复制一份,重命名即可,就算执行命令也无所谓呀,反正不知道是bash执行的。
下面我来说一下,这种方式按我的猜想该怎么监控:
- 复制一份的bash,bash的MD5是不会变的,在安全基线中有进程文件哈希库:一个名字不是bash的文件哈希 和bash一样,你觉得可不可疑呢?其实这种监控方式也会对付软链接。
- 在之前讲的内容中,我们讲到patch命令解释器的方式,即使你改了bash名字,只要执行命令,还是会被HIDS知道是从bash解释器执行的。
2. 分析/proc/目录
接下来的文章中,我要讲解一下从linux进程内存中修改函数,需要给大家提前预习一下基础知识。
proc文件系统是一个伪文件系统,它提供内核数据结构的接口。通常安装在/过程。通常,它是由系统自动安装的,但是也可以使用以下命令手动安装:
mount -t proc proc /proc
proc文件系统中的大多数文件都是只读的,但是有些文件是可写的,允许更改内核变量。/proc目录下的文件很多,我们主要讲解如下文件/文件夹,其中pid是进程号,如果是想查看自身进程中的内容,可以将pid换成self。
/proc/[pid]/auxv /proc/[pid]/cmdline /proc/[pid]/comm /proc/[pid]/cwd /proc/[pid]/environ /proc/[pid]/exe /proc/[pid]/fd /proc/[pid]/limits /proc/[pid]/maps /proc/[pid]/root /proc/[pid]/stack /proc/[pid]/statm /proc/[pid]/status /proc/[pid]/syscall /proc/[pid]/wchan
auxv
/proc/[pid]/auxv
包含传递给进程的 ELF
解释器信息,格式是每一项都是一个 unsignedlong
长度的 ID
加上一个 unsignedlong
长度的值。最后一项以连续的两个 0x00
开头。举例如下:
[root@VM_0_13_centos ~]# hexdump -x /proc/28858/auxv 0000000 0021 0000 0000 0000 e000 90bf 7ffc 0000 0000010 0010 0000 0000 0000 fbff 1f8b 0000 0000 0000020 0006 0000 0000 0000 1000 0000 0000 0000 0000030 0011 0000 0000 0000 0064 0000 0000 0000 0000040 0003 0000 0000 0000 f040 6206 7f48 0000 0000050 0004 0000 0000 0000 0038 0000 0000 0000 0000060 0005 0000 0000 0000 0009 0000 0000 0000 0000070 0007 0000 0000 0000 b000 61e4 7f48 0000 0000080 0008 0000 0000 0000 0000 0000 0000 0000 0000090 0009 0000 0000 0000 2004 6207 7f48 0000 00000a0 000b 0000 0000 0000 0000 0000 0000 0000 00000b0 000c 0000 0000 0000 0000 0000 0000 0000 00000c0 000d 0000 0000 0000 0000 0000 0000 0000 00000d0 000e 0000 0000 0000 0000 0000 0000 0000 00000e0 0017 0000 0000 0000 0000 0000 0000 0000 00000f0 0019 0000 0000 0000 4269 90bd 7ffc 0000 0000100 001f 0000 0000 0000 4fea 90bd 7ffc 0000 0000110 000f 0000 0000 0000 4279 90bd 7ffc 0000 0000120 0000 0000 0000 0000 0000 0000 0000 0000 0000130
解析这个文件可以参考这段代码(https://www.wienand.org/junkcode/linux/read-auxv.c)。
cmdline
/proc/[pid]/cmdline
是一个只读文件,包含进程的完整命令行信息。举例如下:
[root@VM_0_13_centos ~]# ps -ef | grep 28858 root 28858 28568 0 22:56 pts/2 00:00:00 ping www.baidu.com root 29047 2548 0 22:57 pts/4 00:00:00 grep --color=auto 28858 [root@VM_0_13_centos ~]# cat /proc/28858/cmdline pingwww.baidu.com
comm
/proc/[pid]/comm
包含进程的命令名。举例如下:
[root@VM_0_13_centos ~]# cat /proc/28858/comm ping
cwd
/proc/[pid]/cwd
是进程当前工作目录的符号链接。举例如下:
[root@VM_0_13_centos ~]# ls -lt /proc/28858/cwd lrwxrwxrwx 1 root root 0 Mar 29 22:58 /proc/28858/cwd -> /root
environ
/proc/[pid]/environ
显示进程的环境变量。举例如下:
[root@VM_0_13_centos ~]# strings /proc/28858/environ XDG_SESSION_ID=212367 rvm_bin_path=/usr/local/rvm/bin HOSTNAME=VM_0_13_centos PYENV_ROOT=/root/.pyenv GEM_HOME=/usr/local/rvm/gems/ruby-2.5.5 TERM=xterm SHELL=/bin/bash HISTSIZE=3000 IRBRC=/usr/local/rvm/rubies/ruby-2.5.5/.irbrc SSH_CLIENT=113.97.33.208 58836 22 MY_RUBY_HOME=/usr/local/rvm/rubies/ruby-2.5.5 SSH_TTY=/dev/pts/2 USER=root
exe
/proc/[pid]/exe
为实际运行程序的符号链接。举例如下:
[root@VM_0_13_centos ~]# ls -lt /proc/28858/exe lrwxrwxrwx 1 root root 0 Mar 29 22:56 /proc/28858/exe -> /usr/bin/ping
fd
/proc/[pid]/fd
是一个目录,包含进程打开文件的情况。举例如下:
[root@VM_0_13_centos ~]# ls -lt /proc/28858/fd total 0 lrwx------ 1 root root 64 Mar 29 23:01 0 -> /dev/pts/2 lrwx------ 1 root root 64 Mar 29 23:01 1 -> /dev/pts/2 lrwx------ 1 root root 64 Mar 29 23:01 3 -> socket:[153313413] lrwx------ 1 root root 64 Mar 29 23:01 6 -> /dev/pts/2 lrwx------ 1 root root 64 Mar 29 22:56 2 -> /dev/pts/2
目录中的每一项都是一个符号链接,指向打开的文件,数字则代表文件描述符。
limits
/proc/[pid]/limits
显示当前进程的资源限制。举例如下:
[root@VM_0_13_centos ~]# cat /proc/28858/limits Limit Soft Limit Hard Limit Units Max cpu time unlimited unlimited seconds Max file size unlimited unlimited bytes Max data size unlimited unlimited bytes Max stack size 8388608 unlimited bytes Max core file size 0 unlimited bytes Max resident set unlimited unlimited bytes Max processes 7282 7282 processes Max open files 100001 100002 files Max locked memory 65536 65536 bytes Max address space unlimited unlimited bytes Max file locks unlimited unlimited locks Max pending signals 7282 7282 signals Max msgqueue size 819200 819200 bytes Max nice priority 0 0 Max realtime priority 0 0 Max realtime timeout unlimited unlimited us
SoftLimit
表示 kernel
设置给资源的值, HardLimit
表示 SoftLimit
的上限,而 Units
则为计量单元。
maps
/proc/[pid]/maps
显示进程的内存区域映射信息。举例如下:
[root@VM_0_13_centos ~]# cat /proc/28858/maps ...... 7f4862059000-7f486205d000 rw-p 00000000 00:00 0 7f486206a000-7f486206c000 rw-p 00000000 00:00 0 7f486206c000-7f486206d000 r--p 00021000 fd:01 139988 /usr/lib64/ld-2.17.so 7f486206d000-7f486206e000 rw-p 00022000 fd:01 139988 /usr/lib64/ld-2.17.so 7f486206e000-7f486206f000 rw-p 00000000 00:00 0 7f486206f000-7f4862079000 r-xp 00000000 fd:01 143369 /usr/bin/ping 7f4862278000-7f4862279000 r--p 00009000 fd:01 143369 /usr/bin/ping 7f4862279000-7f486227a000 rw-p 0000a000 fd:01 143369 /usr/bin/ping 7f486227a000-7f486228d000 rw-p 00000000 00:00 0 7f4863ec6000-7f4863ee7000 rw-p 00000000 00:00 0 [heap] 7ffc90bb4000-7ffc90bd5000 rw-p 00000000 00:00 0 [stack] 7ffc90bfe000-7ffc90c00000 r-xp 00000000 00:00 0 [vdso] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
其中注意的一点是 [stack:<tid>]
是线程的堆栈信息,对应于 /proc/[pid]/task/[tid]/
路径。
root
/proc/[pid]/root
是进程根目录的符号链接。举例如下:
[root@VM_0_13_centos ~]# ls -lt /proc/28858/root lrwxrwxrwx 1 root root 0 Mar 29 22:58 /proc/28858/root -> /
stack
/proc/[pid]/stack
显示当前进程的内核调用栈信息,只有内核编译时打开了 CONFIG_STACKTRACE
编译选项,才会生成这个文件。举例如下:
[root@VM_0_13_centos ~]# cat /proc/28858/stack [<ffffffff81213465>] poll_schedule_timeout+0x55/0xb0 [<ffffffff812149ed>] do_sys_poll+0x4cd/0x580 [<ffffffff81214ba4>] SyS_poll+0x74/0x110 [<ffffffff81697809>] system_call_fastpath+0x16/0x1b [<ffffffffffffffff>] 0xffffffffffffffff
statm
/proc/[pid]/statm
显示进程所占用内存大小的统计信息,包含七个值,度量单位是 page
( page
大小可通过 getconf PAGESIZE
得到)。举例如下:
[root@VM_0_13_centos ~]# cat /proc/28858/statm 36867 404 315 10 0 111 0
各个值含义: a)进程占用的总的内存; b)进程当前时刻占用的物理内存; c)同其它进程共享的内存; d)进程的代码段; e)共享库(从 2.6
版本起,这个值为 0
); f)进程的堆栈; g) dirty pages
(从 2.6
版本起,这个值为 0
)。
status
/proc/[pid]/status
包含进程的状态信息。其很多内容与 /proc/[pid]/stat
和 /proc/[pid]/statm
,但是却是以一种更清晰地方式展现出来。举例如下:
[root@VM_0_13_centos ~]# cat /proc/28858/status Name: ping State: S (sleeping) Tgid: 28858 Ngid: 0 Pid: 28858 PPid: 28568 TracerPid: 0 Uid: 0 0 0 0 Gid: 0 0 0 0 FDSize: 256 Groups: 0 VmPeak: 147524 kB VmSize: 147468 kB VmLck: 0 kB VmPin: 0 kB VmHWM: 1616 kB VmRSS: 1616 kB RssAnon: 356 kB RssFile: 1260 kB RssShmem: 0 kB VmData: 312 kB VmStk: 132 kB VmExe: 40 kB VmLib: 4348 kB VmPTE: 104 kB VmSwap: 0 kB Threads: 1 SigQ: 0/7282 SigPnd: 0000000000000000 ShdPnd: 0000000000000000 SigBlk: 0000000000000000 SigIgn: 0000000000000000 SigCgt: 0000000180002006 CapInh: 0000000000000000 CapPrm: 0000000000003000 CapEff: 0000000000000000 CapBnd: 0000001fffffffff CapAmb: 0000000000000000 Seccomp: 0 Cpus_allowed: 1 Cpus_allowed_list: 0 Mems_allowed: 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000001 Mems_allowed_list: 0 voluntary_ctxt_switches: 1881 nonvoluntary_ctxt_switches: 0
关于信号( signal
)的信息: SigQ
分为两部分(例如 0/7282
),前面表示当前处在队列中的信号( 0
),后面则表示队列一共可以存储多少信号( 7282
); SigPnd
表示当前线程 pending
的信号,而 ShdPnd
则表示整个进程 pending
的信号; SigBlk
、 SigIgn
和 SigCgt
分别表示对信号的处理是阻塞,忽略,还是捕获。(关于 Unix
信号的相关知识,可以参考Unix: Dealing with signals)。
syscall
/proc/[pid]/syscall
显示当前进程正在执行的系统调用。举例如下:
[root@VM_0_13_centos ~]# cat /proc/28858/syscall 7 0x7ffc90bd2d00 0x1 0x3e3 0x5e80b9e6 0x0 0x0 0x7ffc90bd28d8 0x7f4861738bd0
第一个值是系统调用号( 7
代表 poll
),后面跟着 6
个系统调用的参数值(位于寄存器中),最后两个值依次是堆栈指针和指令计数器的值。如果当前进程虽然阻塞,但阻塞函数并不是系统调用,则系统调用号的值为 -1
,后面只有堆栈指针和指令计数器的值。如果进程没有阻塞,则这个文件只有一个“ running
”的字符串。
内核编译时打开了 CONFIG_HAVE_ARCH_TRACEHOOK
编译选项,才会生成这个文件。
wchan
/proc/[pid]/wchan
显示当进程 sleep
时, kernel
当前运行的函数。举例如下:
[root@VM_0_13_centos ~]# cat /proc/28858/wchan poll_schedule_timeout
参考:http://man7.org/linux/man-pages/man5/proc.5.html https://github.com/NanXiao/gnu-linux-proc-pid-intro