挖edusrc,很多自动化工具扫出的ip,要揉在语句里放到kali进行验证。一个一个复制加修改很麻烦,于是萌生了写一个辅助脚本的想法,也以此学一下python使用,使学习贴于实际

这也是开始学python后写的第一段脚本

我的学习过程

先让ai写了完整脚本,然后丢到另一个ai中,让他给我逐句解释,让我对每个函数每个功能进行复现。最后开始整体的脚本复现,搜改,升级,搜改。

从中学到了很多,也不仅仅是py语法方面的,还有对安全工具开发等多维度进行了学习

脚本介绍:

从一个文档中提取纯净的ip,揉进特定语句中输出到控制台,然后输出那些被我标记通过的ip到另一个文件里

起到整理作用

源码:

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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import os
import re
def resolve_path(filename):

"""把文件名转成相对于脚本所在目录的绝对路径"""

script_dir = os.path.dirname(os.path.abspath(__file__))

return os.path.join(script_dir, filename)

def ipfind(filename):

if not filename:

​ filename = "ip.txt"

full_path = resolve_path(filename)

if not os.path.exists(full_path):

​ return None

cleaned_ips = []

with open(full_path, "r", encoding="utf-8") as f:

​ for line in f:

​ line = line.strip()

​ match = re.search(r'\d{1,3}**\.**\d{1,3}**\.**\d{1,3}**\.**\d{1,3}', line)

​ if not match:

​ continue

​ else:

​ cleaned_ips.append(match.group(0))

return list(dict.fromkeys(cleaned_ips))

def output_cons(ip):

count_confirm = 0

count_all = 0

output_filename = input("请输入结果需存入的文件名(默认 result.txt): ").strip()

if not output_filename:

​ output_filename = "result.txt"

full_output = resolve_path(output_filename)

\# 先清空文件,防止上次结果残留

with open(full_output, "w", encoding="utf-8") as f:

​ pass

for i in ip:

​ count_all += 1

​ print(f"redis-cli -h {i} -p 6379\n")

​ print(f"复制上面命令到Kali中,连上后输入info并回车,立刻截图\n")

​ if input("确认资产请按y: ").strip().lower() == 'y':

​ count_confirm += 1

​ save_result(full_output, i)

​ else:

​ continue

return count_all, count_confirm

def save_result(output_filename, output):

with open(output_filename, "a", encoding="utf-8") as o:

​ o.write(output + "\n")

def main():

try:

​ from_file = input("请输入原ip文件,默认为ip.txt: ").strip()

​ cleaned_ips = ipfind(from_file)

​ if cleaned_ips is None:

​ print("找不到文件")

​ return

​ if not cleaned_ips:

​ print("未找到可用ip")

​ return

​ count_all, count_confirm = output_cons(cleaned_ips)

​ print(f"总共收集到{count_all}个数据,有效数据{count_confirm}个")

except KeyboardInterrupt:

​ print("\n用户已停止程序")

if __name__ == "__main__":

main()

用到的功能点:

函数 功能 用到的技术点
resolve_path 路径解析 os.path.dirname、os.path.abspath、os.path.join
ipfind 读文件、清洗、去重 with open、strip、re.search、match.group(0)、dict.fromkeys(去重有序,相较于集合)
output_cons 循环展示、用户确认 input().strip().lower()、for、+=
save_result 追加写入 open(..., "a")、f.write(ip + "\n")
main 串联、异常处理 try-except KeyboardInterrupt、is None

f.write(ip + “\n”) vs f.write(“\n”.join(…)):注意循环中用前者,后者的话会输出整个列表,会把之前输出的再次输出

思维与心态收获:

蓝图设计 写代码前先想清楚目标、输入、输出、模块、数据流
求败战术 主动找错,越错越好,错误是修正认知的唯一途径
效率复盘 改代码前先列清单,每写一个函数就跑一次
工具适用 需要考虑到工具适用性,如脏数据处理,返回值清晰。

蓝图设计:

ai所教

模板:

  • 【脚本名称】
    【一句话目标】
    【输入】
    
      - 输入1:格式、来源
      - 输入2:格式、来源
        【输出】
      - 输出1:格式、去向
      - 输出2:格式、去向
        【功能模块】
    
        1. 模块A:负责什么,输入什么,输出什么
        2. 模块B:负责什么,输入什么,输出什么
        3. ...
           【数据流】
             main → 模块A → 模块B → 输出
           【异常处理】
    
      - 文件不存在怎么办?
      - 用户输入非法怎么办?
      - 网络超时怎么办?
        【待办】
      - 第一版先实现什么
      - 第二版再加什么
    

例子:

【脚本名称】Redis 未授权验证辅助脚本

【一句话目标】
帮安全测试人员,解决「手动输入 IP 执行 Redis 未授权验证命令时容易输错、效率低」的问题。

【输入】

  • a_ip.txt:txt,每行一个 IP(可能带 http:// 或 :6379 等多余字符)
  • 用户确认:键盘输入 y 或回车

【输出】

  • a_ips.txt:txt,每行一个确认成功的 IP

【功能模块】

  1. ipload()
    输入:无(用户交互输入文件名)
    输出:IP 列表(去重保序),或 None(文件不存在)
    职责:读文件、正则提取 IP、跳过空行、去重保序

  2. output_cons(ips)
    输入:IP 列表
    输出:确认数量(int)
    职责:清空 a_ips.txt → 循环每个 IP → 打印命令 → 问用户 → 如果 y 则立即追加写入 a_ips.txt

  3. main()
    输入:无
    输出:无
    职责:串联 ipload 和 output_cons,处理异常

【数据流】
main → ipload → 返回 ips
→ 如果 ips 为 None 或空 → 退出
→ output_cons(ips) → 边确认边写 a_ips.txt
→ 打印总结

【异常处理】(第二版加)

  • 文件不存在:ipload 返回 None
  • 用户 Ctrl+C:main 加 try-except KeyboardInterrupt
  • 写文件失败:output_cons 加 try-except

【待办】

  • 第一版:跑通基本流程
  • 第二版:加异常处理
  • 第三版:加分批(每 5 个停一下)

提高效率:

不要【写->改->写】,而是要先【抄】

先理解源代码,然后照着源代码打一遍,接着闭卷打一遍,搜,写出修改清单,改,最后复现完整,写总结

检查清单(ai生成)

以后的问题可以先自查一下,都是我在与ai交流过程中遇到的问题

一、路径与文件类

编号 坑 原因 修正 下次怎么避免
P1 相对路径找不到文件 相对路径相对于当前工作目录,不是脚本所在目录 用 resolve_path():os.path.dirname(os.path.abspath(__file__)) + os.path.join 工具里所有文件路径都过 resolve_path()
P2 文件不存在时返回 [] [] 既表示「文件不存在」,也表示「文件为空」 文件不存在返回 None,文件为空返回 [] 用 is None 区分「不存在」和「空」
P3 空行被加入列表 line.strip() 后空行变成 "",正则匹配不到,走 else 被 append 加 if not line: continue 读文件时先跳过空行
P4 f.write("\n".join(...)) 在循环里重复写 join 拼出整个列表,每次确认都把之前所有内容再写一遍 循环中用 f.write(ip + "\n") 循环里只写当前元素,一次性写才用 join
P5 结果文件只在程序结束后更新 output_file 在 output_cons 全部循环完之后才调用 用 "a" 模式边确认边写 自动工具边扫边写,防止中途 Ctrl+C 丢数据
P6 "w" 和 "a" 模式混淆 "w" 覆盖清空,"a" 追加 循环前用 "w" 清空一次,循环中用 "a" 追加 记住:w=覆盖,a=追加
P7 用户输入空文件名导致 open("") 报错 用户直接回车,output_filename 是 "" 加 if not output_filename: output_filename = "result.txt" 所有用户输入的文件名都要处理默认值
P8 从别的目录运行脚本找不到文件 相对路径依赖当前工作目录 用 resolve_path() 转成相对于脚本目录的绝对路径 工具不能依赖「你在哪个目录运行它」

二、字符串与正则类

编号 坑 原因 修正 下次怎么避免
S1 strip() 没去掉中间空格 strip() 只去首尾空白,不去中间 用 replace(" ", "") 或 "".join(line.split()) 先确认需求:去首尾还是去所有
S2 match.group(0) 不理解 不知道 match 是 Match 对象,不是字符串 group(0) 是整个匹配,group(1) 是第1个括号 正则里括号是分组,没括号只有 group(0)
S3 re.search 匹配失败后没处理 匹配不到时 match 是 None,直接 match.group(0) 会报 AttributeError 先 if match: 判断,再取 group(0) 所有 re.search 后都要判断 if match
S4 空行被 re.search 匹配后加入列表 空行 strip() 后是 "",正则匹配不到,走 else 被 append 加 if not line: continue 读文件时先跳过空行
S5 input() 拿到脏数据 用户可能输大写、带空格、带换行 .strip().lower() 所有 input() 都清洗

三、数据结构类

编号 坑 原因 修正 下次怎么避免
D1 set() 无序,每次运行顺序不一样 集合内部用哈希表,存储顺序和插入顺序无关 用 list(dict.fromkeys(...)) 去重保序 需要顺序时不用 set
D2 dict.fromkeys(match) 用错 match 是 Match 对象,不是列表 先收集到列表,循环结束后 dict.fromkeys(cleaned_ips) dict.fromkeys 的参数必须是可迭代对象
D3 return list(dict.fromkeys(match)) 放在循环里 循环只执行一次就返回 return 放在循环外面 写函数前先想清楚返回值在循环内还是循环外
D4 cleaned_ips 定义在 if 里面 如果 if 不成立,变量未定义 变量定义在函数开头 变量定义放在函数最前面

四、控制流与函数类

编号 坑 原因 修正 下次怎么避免
C1 return 写在循环里 循环只执行一次就返回 return 放循环外 写函数前先想清楚返回值
C2 else 对不上 if if 和 else 中间插了别的语句 if...else 必须紧挨着 注意缩进和结构
C3 else: continue 多余 if 不匹配时自动进入下一轮循环 删掉 else: continue continue 只在需要跳过时用
C4 count_all 和 count_confirm 没定义 直接 += 1 会报 NameError 循环前先 count_all = 0 Python 变量必须先赋值再使用
C5 main 里 count_all 可能未定义 如果 cleaned_ips 为空,count_all 没赋值就打印 加 return 提前退出 分支里提前 return,避免未定义变量
C6 if not cleaned_ips: 后面缺 return 空列表时继续往下执行 加 return 每个分支都要想清楚「然后呢」
C7 函数参数名和循环变量名冲突 for i in ip: 但里面用 ip 列表用复数 ips,单个用单数 ip 命名规范:列表复数,元素单数
C8 output_cons 说「无传出」但 output_file 需要数据 数据流断裂 output_cons 返回确认列表,或边确认边写文件 写蓝图时画出数据流

五、Python 语法类

编号 坑 原因 修正 下次怎么避免
G1 count++ Python 没有 ++ count += 1 记住 Python 语法
G2 return a and b and 返回单个值(True/False或最后一个值) return a, b 返回元组 多返回值用逗号
G3 a and b = 函数() 左边不能是表达式 a, b = 函数() 元组解包左边只能是变量
G4 == None 不规范 is None None 是单例,用 is
G5 except KeyboardInterrupt : 冒号前有空格 except KeyboardInterrupt: 注意语法规范
G6 if not filename: 后没处理默认值 用户直接回车,filename 是 "" if not filename: filename = "ip.txt" 默认值处理放在函数开头

六、效率与流程类

编号 坑 原因 修正 下次怎么避免
E1 改代码只改记得住的 没列「本次要改的问题」清单 改代码前先列清单,改一个划一个 清单是外部记忆,不依赖脑子
E2 一口气写完整脚本再跑 错误互相掩盖 每写一个函数就跑一次 错误隔离在单个函数里
E3 卡住超过10分钟还不查 自己死磕 卡住5分钟就查文档/搜/问 借鉴前人,不死磕
E4 一遍过,不做三连刷题 只做了「记忆」,没做「理解」和「运用」 第一遍抄,第二遍合上写,第三遍改功能 三连刷题法
E5 跳过最小可运行版本 直接写完整脚本 先跑最小版本,逐步加功能 每步只加一个功能,跑通再加下一个
E6 写→改→写,效率低 没有先抄 先理解源代码,照着打一遍,闭卷打一遍,搜,写修改清单,改,复现完整,写总结 先抄再改

七、工具设计类

编号 坑 原因 修正 下次怎么避免
T1 输入输出文件名前后不一致 设计时说 a_ip.txt,写代码时用 ip.txt 统一命名 蓝图里写清楚,写代码时对照
T2 output_cons 说「无传出」但 output_file 需要数据 数据流断裂 要么返回列表,要么边确认边写文件 写蓝图时画出数据流
T3 没有异常处理 文件不存在、用户Ctrl+C、写文件失败 加 try-except 工具越自动,越要处理异常
T4 没有区分「文件不存在」和「文件为空」 都返回 [] 文件不存在返回 None,文件为空返回 [] 用 is None 区分
T5 工具依赖当前工作目录 相对路径 用 resolve_path() 工具不能依赖「你在哪个目录运行它」

站内搜索

没有找到内容!