写好一个脚本

闲言

作为一名信息安全学习者,编写脚本能力应该是基础能力之一。或许有很多人不注重编写脚本能力,想着自身常备一些脚本即可,然而这样的思维是非常鼠目寸光的,脚本的存在有其必要性,事实上,是不可替代性。

闲言少叙,言归正传。

目标

如何写好一个脚本呢?一个好的脚本有如下特征:

  • 脚本效率高
  • 编写省时力
  • 分工精而简
  • 信息反馈足

下面我们会从MoeCTF2024·Web方向的勇闯铜人阵一题讲解一个不错的脚本是如何一步步写出来的。

题目

题目入口:

image-20240818164801810

只给玩家三秒的时间,笔者的手速是做不到的,同样如果只是靠手速解决这道题,那么笔者也觉得索然无味。这题并没有过多地涉及漏洞知识,我们只要了解题目机制再编写脚本即可。

这就是写脚本的第一个要求:先明白自己要写的脚本的工作原理、有什么需要注意的

我们首先要知道参数:

image-20240818165238832

本题有设置Session,这就是我们需要注意的。

我们还要猜想如果成功了会发生什么。因为新生赛不会很难,所以笔者猜想成功后会出现flagmoectf{,如此我们就有了停止标志。

让我们理理题目机制,这样有利于我们编写脚本:

题目会发送五次数字,我们必须爬取数字并返回对应的答案,五次以后会得到flag,我们同样要爬取flag。在这期间,我们要保证Session一直存在,不然会失败。

既然明白了,那么开始写脚本吧!

编写

分析

写之前肯定要分析细节,也就是解决问题:

  1. 怎么保存Session
  2. 怎么爬取数字
  3. 怎么构造答案
  4. 怎么编写main.py

第一个问题读者自行看我脚本即可;中间两个问题我们单开两个文件再导入即可,方便调试;最后一个问题才是重点。

对于大多数比较灵活的脚本,main.py的逻辑是很重要的。当我们不知道main.py具体逻辑如何时,不妨先上手编写,边写边想。

main.py

但是本篇是进阶文章,所以就不再赘述基础的脚本编写,笔者直接给出main.py脚本:

image-20240818170735215

细节的读者会发现我第一行代码的特殊,还有发包方式的不同:

1
session = requests.Session()
1
response = session.post(url, data=data)

如此完美就可以接受并保存第一个响应包的Set-Cookie: session=balabala,也就是解决了第一个问题。

通观main.py代码,笔者只采用了一个while循环。事实上,笔者刚开始写main.py时并没有采用循环,连写好几段过程,这样不仅耗时耗力,还容易出错,于是笔者毅然决然选择while循环函数封装。其实题目明面上表示第一次发包和后面几次发包的功能是不同的、参数是不同的,但是细心观察发现这两种请求包的原理几乎一模一样,只有POST参数不同而已,该处不同完全可以用灵活的python语法解决:

image-20240818172117574

综上所述,我们目前解决了两个问题:

  • 怎么保存Session

  • 怎么编写main.py

还剩两个问题:

  • 怎么爬取数字
  • 怎么构造答案

不妨细细思考,这两个问题都依赖于响应包,并且每个阶段的工作原理近乎一致,所以不妨编写一个函数,在响应包下来后多次利用该函数,这样不仅省时省空间,还利于调试,笔者于此还会得到一种美感。

fun_request.py

我们在fun_request.py编写函数request()

image-20240818173043019

读者可以看到我添加了很多调试语句,这些语句没有直接的作用,但是在脚本出问题时可以快速地、有针对性地解决问题,这何尝不是一种高效性的体现呢?

本函数还利用了另外一个函数,函数层层套用也是方便调试和寻找问题的一个优点!

fun_solve.py

image-20240818173704878

该函数只接受题目并返回答案,如果有其他错误就不是该函数的问题,这就大大方便了定位错误。

思考

三个文件的代码,特别是两个函数,笔者很难自己想出来。但是笔者可以问GPT,这就是写好脚本的一个比较实用的方法:自己想好逻辑,具体代码可以由人工智能代劳。当然别全部交给GPT就不管了,自己还是要调试的。

所以,写好一个脚本有以下一些方法:

  • 理解工作机制和注意事项
  • 明确脚本主体逻辑,明确分工和封装
  • 多加注释和调试语句
  • 不会的部分可以询问人工智能

最后,熟能生巧,勇于创新!