前言
很多同学都知道,我们常见的CTF赛事除了解题赛之外,还有一种赛制叫AWD赛制。在这种赛制下,我们战队会拿到一个或多个服务器。服务器的连接方式通常是SSH链接,并且可能一个战队可能会同时有多个服务器。
本期文章,我们来详细讲述一下如何使用Python绝地反击、逆风翻盘。
万能的Python
Python作为一个解释型语言,拥有高集成性。虽然高并发、执行效率有些勉强,但是不免是一个好用的语言。
Python几乎可以涵盖在AWD中的多种操作,我们在下面对部分可能用到的和已经用到的功能给大家写一些例子,方便文章后续的综合。
Python的SSH操作
我们想要链接容器,有很多方式,最最最正常的方式,当然是通过SSH操作了。
我们可以通过用户名和密码去连接靶机,然后执行命令,并取得结果。
相信聪明的人已经知道了,我们可以这样操作SSH之后别提有多方便了!
首先,我们需要一个Python库:“paramiko”
pip3 install paramiko
给出示例代码:
import paramiko
def execute_ssh_command(host, username, password, command):
# 创建SSH客户端对象
ssh_client = paramiko.SSHClient()
# 自动添加主机密钥(慎用,可能会有安全风险)
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
# 连接SSH服务器
ssh_client.connect(hostname=host, username=username, password=password)
# 执行命令
stdin, stdout, stderr = ssh_client.exec_command(command)
# 获取命令执行结果
result = stdout.read().decode().strip()
# 关闭SSH连接
ssh_client.close()
return result
except Exception as e:
return str(e)
if __name__ == "__main__":
host = "ip" # 替换为SSH主机地址
username = "root" # 替换为SSH主机用户名
password = "password" # 替换为SSH主机用户的密码
command = "ls /"
result = execute_ssh_command(host, username, password, command)
print(result)
我们根据上面的代码,是不是也可以根据一些基础Python知识进行完善,填补更多的内容?
Python SSH 后一些小技巧
上面这个例子,是通过SSH获取容器ID的例子,代码如下:
import paramiko
def get_remote_all_container_ids(host, username, password):
try:
# 创建SSH客户端对象
ssh_client = paramiko.SSHClient()
# 自动添加主机密钥(慎用,可能会有安全风险)
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 连接SSH服务器
ssh_client.connect(hostname=host, username=username, password=password)
# 执行docker ps -aq命令并捕获输出
stdin, stdout, stderr = ssh_client.exec_command('docker ps -aq')
# 获取命令执行结果,即所有容器的ID
container_ids = stdout.read().decode().strip().split()
# 关闭SSH连接
ssh_client.close()
return container_ids
except Exception as e:
print(f"Error: {str(e)}")
return []
if __name__ == "__main__":
host = "192.168.31.161" # 替换为远程主机的IP地址或主机名
username = "root" # 替换为登录用户名
password = "password" # 替换为登录密码
container_ids_list = get_remote_all_container_ids(host, username, password)
print(container_ids_list)
我们额外注意获取结果那一行的命令:container_ids = stdout.read().decode().strip().split()
这一行的代码是读取执行后输出的结果,解码,然后分割。
事实上我们很多地方都可以根据这样去写,并取回我们想要的东西。
如果我们获取了结果,那么重启docker容器、进入容器执行命令是不是也轻而易举了。
防守篇
在防守篇中,我们着重对SSH后一些操作进行举例。
SSH后快速查看容器和当前目录
适用:AWD中开赛迅速熟悉自身靶机容器。
import paramiko
import sys
import select
class InteractiveShell:
def __init__(self, ssh_client):
self.ssh_client = ssh_client
self.channel = ssh_client.invoke_shell()
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
self.ssh_client.close()
def execute_command(self, command):
self.channel.send(command + "\n")
while not self.channel.recv_ready():
continue
output = self.channel.recv(4096).decode()
return output
def interactive_shell(self):
try:
while True:
# 监听标准输入和远程终端输出
inputs, _, _ = select.select([sys.stdin, self.channel], [], [])
for src in inputs:
if src is sys.stdin:
# 从标准输入读取输入,并发送到远程终端
user_input = sys.stdin.readline()
self.channel.sendall(user_input.encode())
sys.stdout.flush() # 用于刷新终端,防止不输出或输出不完整命令提示符
else:
# 从远程终端读取输出,并显示在本地终端
output = self.channel.recv(1024).decode()
sys.stdout.write(output)
sys.stdout.flush