我最近刚买了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..."
这似乎是我的程序挂起的地方。你看,我不是百分之百确定应该如何处理。在本书中,代码对他来说效果很好,并且将成功从server.accept()返回并将client_socket连接到正确的地址。
然而,在我的执行中,程序在accept()函数处停止,并且永远不会返回任何套接字或地址数据。除非我对accept()函数的理解是错误的,并且代码的设计并未考虑远程服务器。
我不完全确定accept()函数是如何工作的。它是否向主机发送SYN数据包以发起连接请求,或者是只是坐在那里等待的功能,认为主机在首先没有发送SYN的情况下将发送SYN-ACK返回?
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()要正常返回,则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
按顺序调用我的程序,前两个参数是自动连接到localhost地址的快捷方式,以及我们尝试连接的主机端口。在这种情况下,它是21,但我也尝试了80端口,结果相同。我也试过了十几个不同的网站,似乎都没有回复我的连接请求。
如果您有任何建议或帮助,请提前感谢您。
答案 0 :(得分:1)
您的程序按预期工作,但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
我认为你误解了应该做的事情。这句话是主要原因。
然而,在我的执行中,程序在accept()函数处停止,并且永远不会返回任何套接字或地址数据。除非我对accept()函数的理解是错误的,并且代码的设计并未考虑远程服务器。
我首先要说套接字上的方法基本上是相应C函数的瘦包装,使用man 2 socket
或man 2 accept
获取比python文档可能提供的更多细节。
要回答您的问题,accept()
正在阻止,因为没有客户端。它正在等待另一个程序将SYN数据包发送到它的开放套接字,它将用SYN | ACK响应。这部分都与连接到代理的客户端有关,你似乎认为它涉及远程主机。