Python socket.accept() 没有收到任何连接请求
Python socket.accept() not receiving any connection requests
我最近买了 Justin Seitz 的 Black Hat Python 一书,因为我对进入 Python 和网络安全感兴趣.
我在 Kali Linux 工作,书中的示例之一是一个简单的 TCP 代理。我已经编写了一些通过端口连接的脚本,但现在我在尝试创建到远程服务器的连接时遇到了麻烦,例如 Google.
现在,我承认我对 Python 只是一个完全的新手。我主要用 C++ 编程。作为披露,我确实将 main() 函数移到了代码的顶部,以便按执行顺序进行组织。在实际源代码中,它位于最底部。
import sys
import socket
import threading
import time
import os
def main():
if len(sys.argv[1:]) != 5:
print "Usage: nproxy.py [localhost] [localport] [remotehost] [remoteport] [receive_first]"
print "Example: nproxy.py 127.0.0.1 5555 ftp.example.com 5555 True"
sys.exit(0)
#setup listening parameters
local_host = sys.argv[1]
local_port = sys.argv[2]
#setup remote target
remote_host = sys.argv[3]
remote_port = 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
从这里开始的一切都只是 main() 函数,用于解析和设置所有参数和变量。
#spin listening socket
server_loop(local_host, local_port, remote_host, remote_port, receive_first)
#status class for my timeout function to stop the socket.accept()
class status:
connected = False
server_loop() 函数是我的问题的源函数。它包含将客户端连接到服务器的所有代码。
第一部分只是设置我的服务器套接字以及为我自己创建一些执行快捷方式。
def server_loop(local_host, local_port, remote_host, remote_port, receive_first):
#setup server socket
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if "@" in local_host:
local_host = "127.0.0.1"
if "@" in local_port:
local_port = remote_port
local_addr = (local_host, int(local_port))
remote_addr = (remote_host, int(remote_port))
将服务器绑定到我的本地地址就可以了。我认为问题是在 while 循环期间开始的。
try:
server.bind(local_addr)
except:
print "[!!] Failed to listen on %s:%d" % local_addr
print "[!!] Check for other listening sockets or correct permissions."
sys.exit(0)
print "[*] Listening on %s:%d" % local_addr
server.listen(5)
此处启动 while 循环以保持程序打开以处理传入连接。 tout 线程包含超时和关闭服务器套接字的代码。
while True:
tout = threading.Thread(target=timeout, args=(local_host, local_port))
tout.start()
print "[*] Connecting..."
这似乎是我的程序挂起的地方。你看,我不是 100% 确定这应该如何处理。在书中,代码对他来说工作得很好,并且会从 server.accept() 成功 return 并将 client_socket 连接到正确的地址。
然而,在我的执行过程中,程序在 accept() 函数处停止并且从不 return 发送任何套接字或地址数据。除非我对 accept() 函数的理解是错误的,并且代码在设计时没有考虑到远程服务器。
我什至不完全确定 accept() 函数是如何工作的。它是向主机发送 SYN 数据包以发起连接请求,还是功能只是坐在那里等待,认为主机将发送 SYN-ACK return,而实际上根本没有发送 SYN ?
client_socket, addr = server.accept()
#The timeout function is designed to close the server by feeding
#it the localhost address. If this happens, the statement below catches the
#program and calls that the server request has timed out.
if "127.0.0.1" in addr[0]:
print "[!!] Server connection has timed out."
sys.exit(0)
#print out the local connection information
status.connected = True
print "[==>] Received incoming connection from %s:%d" % (addr[0], addr[1])
#start a thread to talk to the remote host
如果 server.accept() 正常 return,client_socket 将连接到主机并初始化代理的其余部分,因为它正常发送和接收数据。其余代码用于完成,以防我错过了实际上是失败原因的关键内容。
proxy_thread = threading.Thread(target=proxy_handler, args=(client_socket, remote_addr, receive_first))
proxy_thread.start()
def timeout(local_host, local_port):
t = 5
while True:
if status.connected is True:
break
if t <= 0:
wake = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
wake.connect((local_host, int(local_port)))
break
time.sleep(0.1)
t-=0.1
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_addr)
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 and repeat
while True:
#read from localhost
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 a 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 connection
if not len(local_buffer) or not len(remote_buffer):
client_socket.close()
remote_socket.close()
print "[*] No more data. Closing connections..."
break
def hexdump(src, length=16):
result = []
digits = 4 if isinstance(src, unicode) else 2
for i in xrange(0, len(src), length):
s = src[i:i+length]
hexa = b' '.join(["%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 = ""
#we set a 2 second timeout; 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:
pass
return buffer
#modify any requests destined for remote host
def request_handler(buffer):
#perform packet modifications
return buffer
#modify any responses destined for the localhost
def response_handler(buffer):
#perform packet modification
return buffer
main()
当我运行程序时,我使用:sudo python ./nproxy.py @ @ www.google.com 21 True
按顺序,它调用我的程序,前两个参数是自动连接到本地主机地址的快捷方式以及我们尝试连接到的主机的端口。在本例中,它是 21,但我也在端口 80 上尝试过,结果相同。我也尝试了十几个不同的网站,none 似乎在 return 发送我的连接请求。
非常感谢您提供的任何建议或帮助。
尽管 hexdump
中的格式化字符串无效且 proxy_handler
应为 proxy_handler(client_socket, remote_addr, receive_first)
,但您的程序按预期运行。我还禁用了超时,因为我在本地使用代理,所以我不想请求关闭它。按照以下方式使用它对我有用:
# Start proxy on local port 12345 and route to google
$ python @ 12345 www.google.com 80 True
# In another terminal, request from the server
# This should print the same as `curl www.google.com`
$ curl 127.0.0.1:1235
我认为您误解了这应该做什么。这句话是主要原因。
In my execution, however, the program stops at the accept() function and never returns any socket or address data. Unless my understanding of the accept() function is wrong and the code wasn't designed with remote servers in mind.
我首先要说套接字上的方法基本上是相应 C 函数的薄包装,使用 man 2 socket
或 man 2 accept
比 python 文档可能提供的更多细节.
不过要回答您的问题,accept()
正在阻塞,因为没有客户端。它正在等待另一个程序将 SYN 数据包发送到它打开的套接字,它将用 SYN|ACK 响应。这部分都是和客户端连接代理相关的,你好像以为是涉及到远程主机。
我最近买了 Justin Seitz 的 Black Hat Python 一书,因为我对进入 Python 和网络安全感兴趣.
我在 Kali Linux 工作,书中的示例之一是一个简单的 TCP 代理。我已经编写了一些通过端口连接的脚本,但现在我在尝试创建到远程服务器的连接时遇到了麻烦,例如 Google.
现在,我承认我对 Python 只是一个完全的新手。我主要用 C++ 编程。作为披露,我确实将 main() 函数移到了代码的顶部,以便按执行顺序进行组织。在实际源代码中,它位于最底部。
import sys
import socket
import threading
import time
import os
def main():
if len(sys.argv[1:]) != 5:
print "Usage: nproxy.py [localhost] [localport] [remotehost] [remoteport] [receive_first]"
print "Example: nproxy.py 127.0.0.1 5555 ftp.example.com 5555 True"
sys.exit(0)
#setup listening parameters
local_host = sys.argv[1]
local_port = sys.argv[2]
#setup remote target
remote_host = sys.argv[3]
remote_port = 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
从这里开始的一切都只是 main() 函数,用于解析和设置所有参数和变量。
#spin listening socket
server_loop(local_host, local_port, remote_host, remote_port, receive_first)
#status class for my timeout function to stop the socket.accept()
class status:
connected = False
server_loop() 函数是我的问题的源函数。它包含将客户端连接到服务器的所有代码。
第一部分只是设置我的服务器套接字以及为我自己创建一些执行快捷方式。
def server_loop(local_host, local_port, remote_host, remote_port, receive_first):
#setup server socket
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if "@" in local_host:
local_host = "127.0.0.1"
if "@" in local_port:
local_port = remote_port
local_addr = (local_host, int(local_port))
remote_addr = (remote_host, int(remote_port))
将服务器绑定到我的本地地址就可以了。我认为问题是在 while 循环期间开始的。
try:
server.bind(local_addr)
except:
print "[!!] Failed to listen on %s:%d" % local_addr
print "[!!] Check for other listening sockets or correct permissions."
sys.exit(0)
print "[*] Listening on %s:%d" % local_addr
server.listen(5)
此处启动 while 循环以保持程序打开以处理传入连接。 tout 线程包含超时和关闭服务器套接字的代码。
while True:
tout = threading.Thread(target=timeout, args=(local_host, local_port))
tout.start()
print "[*] Connecting..."
这似乎是我的程序挂起的地方。你看,我不是 100% 确定这应该如何处理。在书中,代码对他来说工作得很好,并且会从 server.accept() 成功 return 并将 client_socket 连接到正确的地址。
然而,在我的执行过程中,程序在 accept() 函数处停止并且从不 return 发送任何套接字或地址数据。除非我对 accept() 函数的理解是错误的,并且代码在设计时没有考虑到远程服务器。
我什至不完全确定 accept() 函数是如何工作的。它是向主机发送 SYN 数据包以发起连接请求,还是功能只是坐在那里等待,认为主机将发送 SYN-ACK return,而实际上根本没有发送 SYN ?
client_socket, addr = server.accept()
#The timeout function is designed to close the server by feeding
#it the localhost address. If this happens, the statement below catches the
#program and calls that the server request has timed out.
if "127.0.0.1" in addr[0]:
print "[!!] Server connection has timed out."
sys.exit(0)
#print out the local connection information
status.connected = True
print "[==>] Received incoming connection from %s:%d" % (addr[0], addr[1])
#start a thread to talk to the remote host
如果 server.accept() 正常 return,client_socket 将连接到主机并初始化代理的其余部分,因为它正常发送和接收数据。其余代码用于完成,以防我错过了实际上是失败原因的关键内容。
proxy_thread = threading.Thread(target=proxy_handler, args=(client_socket, remote_addr, receive_first))
proxy_thread.start()
def timeout(local_host, local_port):
t = 5
while True:
if status.connected is True:
break
if t <= 0:
wake = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
wake.connect((local_host, int(local_port)))
break
time.sleep(0.1)
t-=0.1
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_addr)
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 and repeat
while True:
#read from localhost
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 a 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 connection
if not len(local_buffer) or not len(remote_buffer):
client_socket.close()
remote_socket.close()
print "[*] No more data. Closing connections..."
break
def hexdump(src, length=16):
result = []
digits = 4 if isinstance(src, unicode) else 2
for i in xrange(0, len(src), length):
s = src[i:i+length]
hexa = b' '.join(["%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 = ""
#we set a 2 second timeout; 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:
pass
return buffer
#modify any requests destined for remote host
def request_handler(buffer):
#perform packet modifications
return buffer
#modify any responses destined for the localhost
def response_handler(buffer):
#perform packet modification
return buffer
main()
当我运行程序时,我使用:sudo python ./nproxy.py @ @ www.google.com 21 True
按顺序,它调用我的程序,前两个参数是自动连接到本地主机地址的快捷方式以及我们尝试连接到的主机的端口。在本例中,它是 21,但我也在端口 80 上尝试过,结果相同。我也尝试了十几个不同的网站,none 似乎在 return 发送我的连接请求。
非常感谢您提供的任何建议或帮助。
尽管 hexdump
中的格式化字符串无效且 proxy_handler
应为 proxy_handler(client_socket, remote_addr, receive_first)
,但您的程序按预期运行。我还禁用了超时,因为我在本地使用代理,所以我不想请求关闭它。按照以下方式使用它对我有用:
# Start proxy on local port 12345 and route to google
$ python @ 12345 www.google.com 80 True
# In another terminal, request from the server
# This should print the same as `curl www.google.com`
$ curl 127.0.0.1:1235
我认为您误解了这应该做什么。这句话是主要原因。
In my execution, however, the program stops at the accept() function and never returns any socket or address data. Unless my understanding of the accept() function is wrong and the code wasn't designed with remote servers in mind.
我首先要说套接字上的方法基本上是相应 C 函数的薄包装,使用 man 2 socket
或 man 2 accept
比 python 文档可能提供的更多细节.
不过要回答您的问题,accept()
正在阻塞,因为没有客户端。它正在等待另一个程序将 SYN 数据包发送到它打开的套接字,它将用 SYN|ACK 响应。这部分都是和客户端连接代理相关的,你好像以为是涉及到远程主机。