第五届红明谷-异常行为溯源-WP
字数统计:
1.1k字
|
阅读时长:
4分
在刷题时,遇到了这个题,感觉适合写python脚本(AI打工雾)和练习bash命令的。所以记下。
题目说明
某企业网络安全部门人员正在对企业网络资产受到的攻击行为进行溯源分析,该工作人员发现攻击者删除了一段时间内的访问日志数据,但是攻击者曾传输过已被删除的访问日志数据并且被流量监控设备捕获,工作人员对流量数据进行了初步过滤并提取出了相应数据包。已知该攻击者在开始时曾尝试低密度的攻击,发现未被相关安全人员及时发现后进行了连续多日的攻击,请协助企业排查并定位攻击者IP,flag格式为:flag{md5(IP)}
分析题目压缩包发现,tcp流量里被base64编码。
1
| eyJtc2ciOiJPVEF1T1RjdU1qUXlMakk0TFNBdElGc3dPQzlLWVc0dk1qQXlOVG95TWpvMU56b3pOeUFyTURBd01GMGdJbEJQVTFRZ0wyMWhhVzR2YzJWaGNtTm9MbkJvY0NCSVZGUlFMekV1TVNJZ01qQXdJREl6T0RBZ0lpMGlJQ0pOYjNwcGJHeGhMelV1TUNBb1kyOXRjR0YwYVdKc1pUc2dUVk5KUlNBNUxqQTdJRmRwYm1SdmQzTWdUbFFnTmk0eE95QlVjbWxrWlc1MEx6VXVNU2tpQ2c9PSIsInR5cGUiOiJMb2ctRGF0YSJ9
|
解密后,发现是一个json数据里面msg里有包含一个base64数据。
1
| {"msg":"OTAuOTcuMjQyLjI4LSAtIFswOC9KYW4vMjAyNToyMjo1NzozNyArMDAwMF0gIlBPU1QgL21haW4vc2VhcmNoLnBocCBIVFRQLzEuMSIgMjAwIDIzODAgIi0iICJNb3ppbGxhLzUuMCAoY29tcGF0aWJsZTsgTVNJRSA5LjA7IFdpbmRvd3MgTlQgNi4xOyBUcmlkZW50LzUuMSkiCg==","type":"Log-Data"}
|
解密msg里的base64编码数据,发现是一个日志数据。
1
| 90.97.242.28- - [08/Jan/2025:22:57:37 +0000] "POST /main/search.php HTTP/1.1" 200 2380 "-" "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.1)"
|
发现这个规律后,我们可以先编写python将文件里的base64提起处理,再去分析base64数据。
python脚本编写
我们分析了tcp流量发现里面的base64有鲜明的特征,我们可以编写脚本来判断base64启始位置,再同时提取出来进行解码。于是得到以下脚本。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
| import base64 import re import argparse from pathlib import Path
def is_valid_base64(s): """检查字符串是否是有效的Base64""" try: padding = len(s) % 4 if padding: s += '=' * (4 - padding) base64.b64decode(s) return True except: return False
def extract_and_decode_base64(input_file, output_file=None, min_length=8): """ 从文件中提取Base64字符串并解密 参数: input_file: 输入文件路径 output_file: 输出文件路径(可选) min_length: 最小Base64字符串长度(默认8) """ try: content = Path(input_file).read_text(encoding='utf-8', errors='ignore') base64_pattern = r'(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?' print(f"正在分析文件: {input_file}") print(f"找到的Base64字符串:\n{'='*40}") results = [] unique_strings = set() for match in re.finditer(base64_pattern, content): base64_str = match.group() if (len(base64_str) >= min_length and is_valid_base64(base64_str) and base64_str not in unique_strings): unique_strings.add(base64_str) try: decoded_bytes = base64.b64decode(base64_str) try: decoded_str = decoded_bytes.decode('utf-8') result = f"Base64: {base64_str}\n解码(UTF-8): {decoded_str}\n" except UnicodeDecodeError: hex_str = decoded_bytes.hex() result = f"Base64: {base64_str}\n解码(HEX): {hex_str}\n" print(result) results.append(result) except Exception as e: error_msg = f"Base64: {base64_str}\n解码失败: {str(e)}\n" print(error_msg) results.append(error_msg) if not results: print("没有找到有效的Base64字符串") return if output_file: with open(output_file, 'w', encoding='utf-8') as f: f.write('\n'.join(results)) print(f"\n结果已保存到: {output_file}") except Exception as e: print(f"处理文件时出错: {str(e)}")
if __name__ == "__main__": parser = argparse.ArgumentParser(description='从文件中提取Base64字符串并解密') parser.add_argument('-i', '--input', required=True, help='输入文件路径') parser.add_argument('-o', '--output', help='输出文件路径(可选)') parser.add_argument('-l', '--min-length', type=int, default=8, help='最小Base64字符串长度(默认8)') args = parser.parse_args() extract_and_decode_base64( input_file=args.input, output_file=args.output, min_length=args.min_length )
|
bash命令配合
我们执行python脚本两次,第一次提取出json数据到1.txt。
1
| python3 1.py -i ./network_traffic.pcap -o 1.txt
|
再从1.txt里提取出日志信息到2.txt
1
| python3 1.py -i ./1.txt -o 2.txt
|
再利用bash命令行的grep命令,把日志信息里的POST信息分离
1
| cat 2.txt | grep "POST" >3.txt
|
通过awk 把ip 匹配出,再通过sort和uniq 找出出现次数最多的IP。
1
| cat 3.txt| awk '{print $2}'| sort | uniq -c | sort
|
找点一个次数异常的ip:
1 2 3 4 5 6 7 8 9
| 4 220.90.115.241 4 222.124.84.168 4 30.74.60.8 4 33.218.233.40 4 69.144.190.184 4 73.96.151.224 4 89.195.144.147 5 153.148.53.46 67 35.127.46.111
|
将 35.127.46.111 md5后就是flag。