python - 为什么输出保持空白?
问题描述
我正在关注“Black Hat Python”一书,作者创建了一个 TCP 代理,但我似乎无法使其工作。
这是我正在使用的代码:
import sys
import socket
import threading
# this is a pretty hex dumping function directly taken from
# http://code.activestate.com/recipes/142812-hex-dumper/
def hexdump(src, length=16):
result = []
digits = 4 if isinstance(src, str) else 2
for i in range(0, len(src), length):
s = src[i:i + length]
hexa = b' '.join([b"%0*X" % (digits, ord(x)) for x in s])
text = b''.join([x if 0x20 <= ord(x) < 0x7F else b'.' for x in s])
result.append(
b"%04X %-*s %s" % (i, length * (digits + 1), hexa, text))
print(b'\n'.join(result))
def receive_from(connection):
buffer = b''
# We set a 2 second time-out. Depending on your target this may need
# to be adjusted
connection.settimeout(2)
try:
# keep reading into the buffer until there's no more data or we
# time-out
while True:
data = connection.recv(4096)
if not data:
break
buffer += data
except TimeoutError:
pass
return buffer
# modify any requests destined for the remote host
def request_handler(buffer):
# perform packet modifications
return buffer
# modify any responses destined for the local host
def response_handler(buffer):
# perform packet modifications
return buffer
def proxy_handler(client_socket, remote_host, remote_port, receive_first):
# connect to the remote host
remote_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
remote_socket.connect((remote_host, remote_port))
# receive data from the remote end if necessary
if receive_first:
remote_buffer = receive_from(remote_socket)
hexdump(remote_buffer)
# send it to our response handler
remote_buffer = response_handler(remote_buffer)
# if we have data to send to our local client send it
if len(remote_buffer):
print("[<==] Sending %d bytes to localhost." % len(remote_buffer))
client_socket.send(remote_buffer)
# now let's loop and read from local, send to remote, send to local
# rinse wash repeat
while True:
# read from local host
local_buffer = receive_from(client_socket)
if len(local_buffer):
print("[==>] Received %d bytes from localhost." % len(local_buffer))
hexdump(local_buffer)
# send it to our request handler
local_buffer = request_handler(local_buffer)
# send off the data to the remote host
remote_socket.send(local_buffer)
print("[==>] Sent to remote.")
# receive back the response
remote_buffer = receive_from(remote_socket)
if len(remote_buffer):
print("[<==] Received %d bytes from remote." % len(remote_buffer))
hexdump(remote_buffer)
# send to our response handler
remote_buffer = response_handler(remote_buffer)
# send the response to the local socket
client_socket.send(remote_buffer)
print("[<==] Sent to localhost.")
# if no more data on either side close the connections
if not len(local_buffer) or not len(remote_buffer):
client_socket.close()
remote_socket.close()
print("[*] No more data. Closing connections.")
break
def server_loop(local_host, local_port, remote_host, remote_port,
receive_first):
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
server.bind((local_host, local_port))
except socket.error as exc:
print("[!!] Failed to listen on %s:%d" % (local_host,
local_port))
print("[!!] Check for other listening sockets or correct "
"permissions.")
print(f"[!!] Caught exception error: {exc}")
sys.exit(0)
print("[*] Listening on %s:%d" % (local_host, local_port))
server.listen(5)
while True:
client_socket, addr = server.accept()
# print out the local connection information
print("[==>] Received incoming connection from %s:%d" % (
addr[0], addr[1]))
# start a thread to talk to the remote host
proxy_thread = threading.Thread(target=proxy_handler, args=(
client_socket, remote_host, remote_port, receive_first))
proxy_thread.start()
def main():
# no fancy command line parsing here
if len(sys.argv[1:]) != 5:
print("Usage: ./proxy.py [localhost] [localport] [remotehost] "
"[remoteport] [receive_first]")
print("Example: ./proxy.py 127.0.0.1 9000 10.12.132.1 9000 True")
sys.exit(0)
# setup local listening parameters
local_host = sys.argv[1]
local_port = int(sys.argv[2])
# setup remote target
remote_host = sys.argv[3]
remote_port = int(sys.argv[4])
# this tells our proxy to connect and receive data
# before sending to the remote host
receive_first = sys.argv[5]
if "True" in receive_first:
receive_first = True
else:
receive_first = False
# now spin up our listening socket
server_loop(local_host, local_port, remote_host, remote_port, receive_first)
main()
使用以下命令:
sudo ./proxy.py 127.0.0.1 21 ftp.target.ca 21 True
该程序应给出如下输出:
[*] Listening on 127.0.0.1:21
[==>] Received incoming connection from 127.0.0.1:59218
0000 32 32 30 20 50 72 6F 46 54 50 44 20 31 2E 33 2E 220 ProFTPD 1.3.
0010 33 61 20 53 65 72 76 65 72 20 28 44 65 62 69 61 3a Server (Debia
0020 6E 29 20 5B 3A 3A 66 66 66 66 3A 35 30 2E 35 37 n) [::ffff:22.22
0030 2E 31 36 38 2E 39 33 5D 0D 0A .22.22]..
[<==] Sending 58 bytes to localhost.
[==>] Received 12 bytes from localhost.
0000 55 53 45 52 20 74 65 73 74 79 0D 0A USER testy..
[==>] Sent to remote.
[<==] Received 33 bytes from remote.
0000 33 33 31 20 50 61 73 73 77 6F 72 64 20 72 65 71 331 Password req
0010 75 69 72 65 64 20 66 6F 72 20 74 65 73 74 79 0D uired for testy.
0020 0A .
[<==] Sent to localhost.
[==>] Received 13 bytes from localhost.
0000 50 41 53 53 20 74 65 73 74 65 72 0D 0A PASS tester..
[==>] Sent to remote.
[*] No more data. Closing connections.
我尝试了不同的选项,比如使用不同的 ftp 服务器(例如 ftp.dlptest.com),甚至在 Windows 7 机器(相同子网)上设置了我自己的 ftp 服务器,但我仍然无法连接。
(在不同的终端上,我可以使用命令轻松连接到指定的 ftp 服务器
ftp ftp.dlptest.com
)
我错过了什么?
谢谢
解决方案
如果你运行它127.0.0.1 21
sudo ./proxy.py 127.0.0.1 21 ftp.dlptest.com 21 True
那么您必须使用
ftp 127.0.0.1 21
然后它开始工作。
但是有一个不同的问题:它似乎hexdump
是为 Python 2 创建的,它将bytes
和str
视为相同类型的数据 - 它用于ord()
将 char 转换为其代码/数字。在 Python 3 中不需要它。
您还可以直接将其代码转换为字符串chr(x)
并连接到要显示的字符串。
def hexdump(src, length=16):
result = []
digits = 4 if isinstance(src, str) else 2
#print('[DEBUG] src:', type(src))
for i in range(0, len(src), length):
s = src[i:i+length]
data = ['%0*X' % (digits, x) for x in s]
#print('[DEBUG] data:', data)
hexa = ' '.join(data)
#print('[DEBUG] hexa:', hexa)
data = [chr(x) if 0x20 <= x < 0x7F else '.' for x in s]
#print('[DEBUG] data:', data)
text = ''.join(data)
#print('[DEBUG] text:', text)
result.append(
"%04X %-*s %s" % (i, length * (digits+1), hexa, text))
print('\n'.join(result))
其他问题:它需要socket.timeout
而不是Timeout
捕获这个异常。
其他问题:当代码等待本地数据时,它可能需要更大的价值,connection.settimeout(2)
因为人类可能需要时间来放置一些数据 - 即。FTP 连接中的登录名和密码。我对不同的连接使用不同的值。默认情况下,它使用 2 秒
def receive_from(connection, timeout=2):
connection.settimeout(timeout)
但对于本地数据,它使用 10 秒
local_buffer = receive_from(client_socket, 10)
顺便提一句:
我也抓住KeyboardInterrupt
了,所以当我停止使用Ctrl+C
.
我也加
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
解决[Errno 98] Address already in use
再次启动服务器时出现错误的问题。
代码:
import sys
import socket
import threading
# this is a pretty hex dumping function directly taken from
# http://code.activestate.com/recipes/142812-hex-dumper/
def hexdump(src, length=16):
result = []
digits = 4 if isinstance(src, str) else 2
#print('[DEBUG] src:', type(src))
for i in range(0, len(src), length):
s = src[i:i+length]
data = ['%0*X' % (digits, x) for x in s]
#print('[DEBUG] data:', data)
hexa = ' '.join(data)
#print('[DEBUG] hexa:', hexa)
data = [chr(x) if 0x20 <= x < 0x7F else '.' for x in s]
#print('[DEBUG] data:', data)
text = ''.join(data)
#print('[DEBUG] text:', text)
result.append(
"%04X %-*s %s" % (i, length * (digits+1), hexa, text))
print('\n'.join(result))
def receive_from(connection, timeout=2):
buffer = b''
# We set a 2 second time-out. Depending on your target this may need
# to be adjusted
connection.settimeout(timeout)
try:
# keep reading into the buffer until there's no more data or we
# time-out
while True:
data = connection.recv(4096)
if not data:
break
buffer += data
except socket.timeout as ex:
#print('TimeoutError:', ex)
pass
print('[DEBUG] buffer:')
print(buffer.decode())
return buffer
# modify any requests destined for the remote host
def request_handler(buffer):
# perform packet modifications
return buffer
# modify any responses destined for the local host
def response_handler(buffer):
# perform packet modifications
return buffer
def proxy_handler(client_socket, remote_host, remote_port, receive_first):
print(client_socket)
print(remote_host, remote_port)
print(receive_first)
# connect to the remote host
remote_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
remote_socket.connect((remote_host, remote_port))
# receive data from the remote end if necessary
if receive_first:
print('receive first')
remote_buffer = receive_from(remote_socket)
hexdump(remote_buffer)
# send it to our response handler
remote_buffer = response_handler(remote_buffer)
# if we have data to send to our local client send it
if len(remote_buffer):
print("[<==] Sending %d bytes to localhost." % len(remote_buffer))
client_socket.send(remote_buffer)
# now let's loop and read from local, send to remote, send to local
# rinse wash repeat
while True:
# read from local host
local_buffer = receive_from(client_socket, 10) # longer time for user response
if len(local_buffer):
print("[==>] Received %d bytes from localhost." % len(local_buffer))
hexdump(local_buffer)
# send it to our request handler
local_buffer = request_handler(local_buffer)
# send off the data to the remote host
remote_socket.send(local_buffer)
print("[==>] Sent to remote.")
# receive back the response
remote_buffer = receive_from(remote_socket)
if len(remote_buffer):
print("[<==] Received %d bytes from remote." % len(remote_buffer))
hexdump(remote_buffer)
# send to our response handler
remote_buffer = response_handler(remote_buffer)
# send the response to the local socket
client_socket.send(remote_buffer)
print("[<==] Sent to localhost.")
# if no more data on either side close the connections
if not len(local_buffer) or not len(remote_buffer):
client_socket.close()
remote_socket.close()
print("[*] No more data. Closing connections.")
break
def server_loop(local_host, local_port, remote_host, remote_port,
receive_first):
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
try:
server.bind((local_host, local_port))
except socket.error as exc:
print("[!!] Failed to listen on %s:%d" % (local_host,
local_port))
print("[!!] Check for other listening sockets or correct "
"permissions.")
print(f"[!!] Caught exception error: {exc}")
sys.exit(0)
print("[*] Listening on %s:%d" % (local_host, local_port))
server.listen(5)
try:
while True:
client_socket, addr = server.accept()
# print out the local connection information
print("[==>] Received incoming connection from %s:%d" % (
addr[0], addr[1]))
# start a thread to talk to the remote host
proxy_thread = threading.Thread(target=proxy_handler, args=(
client_socket, remote_host, remote_port, receive_first))
proxy_thread.start()
except KeyboardInterrupt:
print('KeyboardInterrupt')
server.close()
def main():
# no fancy command line parsing here
if len(sys.argv[1:]) != 5:
print("Usage: ./proxy.py [localhost] [localport] [remotehost] "
"[remoteport] [receive_first]")
print("Example: ./proxy.py 127.0.0.1 9000 10.12.132.1 9000 True")
sys.exit(0)
# setup local listening parameters
local_host = sys.argv[1]
local_port = int(sys.argv[2])
# setup remote target
remote_host = sys.argv[3]
remote_port = int(sys.argv[4])
# this tells our proxy to connect and receive data
# before sending to the remote host
receive_first = sys.argv[5]
receive_first = ("True" in receive_first)
# now spin up our listening socket
server_loop(local_host, local_port, remote_host, remote_port, receive_first)
main()
当我在一个控制台中运行时
sudo python3.7 proxy.py 127.0.0.1 5005 ftp.dlptest.com 21 True
并在第二
ftp 127.0.0.1 5005
然后我得到
$ sudo python3.7 proxy.py 127.0.0.1 5005 ftp.dlptest.com 21 True
[*] Listening on 127.0.0.1:5005
[==>] Received incoming connection from 127.0.0.1:50124
<socket.socket fd=4, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 5005), raddr=('127.0.0.1', 50124)>
ftp.dlptest.com 21
True
receive first
[DEBUG] buffer:
220-#########################################################
220-Please upload your web files to the public_html directory.
220-Note that letters are case sensitive.
220-#########################################################
220 This is a private system - No anonymous login
0000 32 32 30 2D 23 23 23 23 23 23 23 23 23 23 23 23 220-############
0010 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 ################
0020 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 ################
0030 23 23 23 23 23 23 23 23 23 23 23 23 23 0D 0A 32 #############..2
0040 32 30 2D 50 6C 65 61 73 65 20 75 70 6C 6F 61 64 20-Please upload
0050 20 79 6F 75 72 20 77 65 62 20 66 69 6C 65 73 20 your web files
0060 74 6F 20 74 68 65 20 70 75 62 6C 69 63 5F 68 74 to the public_ht
0070 6D 6C 20 64 69 72 65 63 74 6F 72 79 2E 0D 0A 32 ml directory...2
0080 32 30 2D 4E 6F 74 65 20 74 68 61 74 20 6C 65 74 20-Note that let
0090 74 65 72 73 20 61 72 65 20 63 61 73 65 20 73 65 ters are case se
00A0 6E 73 69 74 69 76 65 2E 0D 0A 32 32 30 2D 23 23 nsitive...220-##
00B0 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 ################
00C0 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 ################
00D0 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 ################
00E0 23 23 23 23 23 23 23 0D 0A 32 32 30 20 54 68 69 #######..220 Thi
00F0 73 20 69 73 20 61 20 70 72 69 76 61 74 65 20 73 s is a private s
0100 79 73 74 65 6D 20 2D 20 4E 6F 20 61 6E 6F 6E 79 ystem - No anony
0110 6D 6F 75 73 20 6C 6F 67 69 6E 0D 0A mous login..
[<==] Sending 284 bytes to localhost.
[DEBUG] buffer:
USER furas
[==>] Received 12 bytes from localhost.
0000 55 53 45 52 20 66 75 72 61 73 0D 0A USER furas..
[==>] Sent to remote.
[DEBUG] buffer:
331 User furas OK. Password required
[<==] Received 38 bytes from remote.
0000 33 33 31 20 55 73 65 72 20 66 75 72 61 73 20 4F 331 User furas O
0010 4B 2E 20 50 61 73 73 77 6F 72 64 20 72 65 71 75 K. Password requ
0020 69 72 65 64 0D 0A ired..
[<==] Sent to localhost.
[DEBUG] buffer:
PASS adasdasda
[==>] Received 16 bytes from localhost.
0000 50 41 53 53 20 61 64 61 73 64 61 73 64 61 0D 0A PASS adasdasda..
[==>] Sent to remote.
[DEBUG] buffer:
[*] No more data. Closing connections.
^CKeyboardInterrupt
和
$ ftp 127.0.0.1 5005
Connected to 127.0.0.1.
220-#########################################################
220-Please upload your web files to the public_html directory.
220-Note that letters are case sensitive.
220-#########################################################
220 This is a private system - No anonymous login
Name (127.0.0.1:furas):
331 User furas OK. Password required
Password:
421 Service not available, remote server has closed connection
Login failed.
No control connection for command: Success
ftp> quit
顺便说一句:如果你使用更大的端口1024
(就像5005
我的回答一样),那么它应该在没有sudo
.
推荐阅读
- django - 不允许的方法:POST
- ios - Firebase 身份验证问题 - 发生内部错误,打印并检查错误详细信息以获取更多信息
- javascript - React DatePicker 更改默认开始日期
- flutter - 如何使导航底部栏透明
- botframework - 有没有办法删除网络聊天中的文件附加图标?
- arm - 使用 musl-cross-make 对标准库中符号的未定义引用
- python - 如何根据查找在 Pandas 中填充 NA 值?
- vue.js - 如何使用 Google 自动完成和 Vue js 自动填写地址?
- c# - 当 C# 函数必须写入标准输出时,如何对 C# 函数进行单元测试
- r - 如何在 ggplot2 的条形图上同时显示计数和百分比?R