要写脚本,编程不好不要紧--浅谈CTF中脚本的编写方法

1. 脚本在CTF比赛中的作用

CTF夺旗赛中往往分为杂项(MISC)、密码(CRYPTO)、WEB、逆向(REVERSE)和PWN。

在目前的比赛中,各种工具起到的作用在不断下降,一击必杀拿到flag很少见了。往往需要根据题目临时编制脚本,进行调试、爆破、破解算法才能顺利解题。
多以参加CTF比赛一定要有自己写脚本的能力。

2. 编程技术不好,怎么办

往往很多同学会说编程技术不好是不是要重新学开发才可以。其实大可不必,脚本不是web开发或是网络编程,不需要那么高的要求。
就像你英语不好,但置身国外怎么办,你要拿英语书从头学吗?当然不是,想尽办法,只要能让对方get到你的意思就行。努力去说去沟通,慢慢就会了。脚本编制也依然,需要用到什么,就搞懂哪里,多写多练,慢慢就能上手。到那时再系统学编程也为时不晚。

下面我就简单举例介绍下脚本是怎么一步步根据题目写出来的。 有编程基础的同学,可能一看就会,基础薄弱的同学,不要紧,get到思路勤加练习是最重要的。CTF中根据线索和源码找到解题思路和实操能力才是最重要的。

主要以python脚本为主

代码中的函数不认识怎么办,百度搜索看下很快就能掌握这个函数的用法,仅此而已,学以致用是脚本的关键。

3. 脚本编制简单举例

3.1杂项题目:一个充满0、1的TXT文件

拿到题目,是个txt文件,里面写满了0和1。
请添加图片描述

有点想法了是不是,杂项中经常考二维码,大家已经习惯了使用工具去分析。难道此题另辟蹊径,不直接提供二维码,反而需要自行构建?以CTF各种反人类的出题方式,可能性很高呢。可如何构建,下面就来一步步分析,分析完脚本也就出来了。

  1. 首先,构建二维码就要知道二维码的边长(正方形哦),所以python脚本就要读取txt文件,获取文件的大小,再开方不就得到了边长吗?
import math

# 1.判断二维码数据是否可用
f = open('txt文件路径', 'r')
s = f.read()
print(len(s))
# 开平方根,如果二进制大小能整除,证明是正方形,得出宽、高  x=y=260
print(math.sqrt(len(s)))

# 结果是260,解题思路正确的概率飙升到80%
  1. 不管题目,绘制二维码本质上就是要在边长为260的画布上画图 吗?这就要用上python大名鼎鼎的库PIL了。

记住PIL库创建画布的代码套路,永远都这样,就记住下面几行代码就行,套路都一样的。

from PIL import Image
x = 260
y = 260
image_new = Image.new('RGB', (x,y), (0,0,0)) # RGB模式,边长均为260,黑色(0,0,0)\白色(255,255,255)
image_new.show()

在这里插入图片描述
3. 那下一步是什么,结合题目 线索就是0,1。那简单啊,(反正复杂的也不会,哈哈)二维码就两个颜色白色和黑色,随机吧核心逻辑就是判断是0还是1, 0就将该橡塑上黑色(0,0,0),1就上白色(255,255,255)

还是老样子,PIL库如何对不同像素上色呢,使用函数putpixel,代码记套路。哪里不会就百度哪里。循环语句和文件读取语法,如果真是小白,这个可以百度学习python相关内容,自学时间3h吧。不要学太深,能看懂脚本的程度就可以。

# 3. 区分0或1分别上色黑或白,修复完整二维码
idx = 0    # idx表示txt文件中数据序号,第一个数据为0号,对应坐标点(0,0)  下一个1号对用坐标点(1,0)
for y in range(0, 260):   # 就是平面坐标(x,y)初中几何的知识,只不过用代码写出来
    for x in range(0, 260):
        data = s[idx]  
        if data == '0': # 假如txt中第一个数据为0,对应坐标点(0,0),就给他上黑丝(黑色)
            img_new.putpixel((x,y),(0,0,0)) 
        elif data == '1':
            img_new.putpixel((x,y),(255,255,255))
        idx += 1
img_new.show()
  1. 汇总以上3个步骤,完整脚本和结果如下。
import math
from PIL import Image

# 1.判断二维码数据是否可用
f = open('txt文件路径', 'r')
s = f.read()
print(len(s))
# 开平方根,如果二进制大小能整除,证明是长方形,得出宽、高  x=y=260
print(math.sqrt(len(s)))

# 2. 测试每个像素点上色(全白、全黑)
x = 260
y = 260
img_new = Image.new('RGB', (x,y), (0,0,0)) # RGB模式,边长均为260,黑色(0,0,0)\白色(255,255,255)
# image_new.show()

# 3. 区分0或1分别上色黑或白,修复完整二维码
idx = 0
for y in range(0, 260):
    for x in range(0, 260):
        data = s[idx]
        if data == '0':
            img_new.putpixel((x,y),(0,0,0))
        elif data == '1':
            img_new.putpixel((x,y),(255,255,255))
        idx += 1
img_new.show()

请添加图片描述
大家放心扫码吧,不是我的收款码~

3.2 加密题目:标准凯撒爆破脚本

基础知识:凯撒密码是一种最简单且最广为人知的加密 技术,它属于替代加密,明文中的所有字母都在字母表上向后(或 向前)按照一个固定数目进行偏移后被替换成密文。
举例如下:
原始字母表 ABCDEFGHIGKLMNOPQRSTUVWXYZ key=3 每个字母右移3位
新的字母表 DEFGHIGKLMNOPQRSTUVWXYZABC
若明文M=“HEASON”
则密文C = “KHDVRQ” 解密同理左移3位即可
所谓的密钥就是上面的key,他只有25中可能(key=1就是自己去掉这个)。所以写个脚本遍历出所有结果,看到那个字段有意义,其实就完成破解了。

from string import ascii_letters
str1 = 'ComeChina'
str2 = str1.lower()
num = 1
table = ascii_letters
for i in range(26):
    print("{}:  ".format(num), end='')
    for temp in str2:
        if temp not in table:
            print(chr(ord(temp)), end="")
        elif ((ord(temp)+num)>ord('z')):
            print(chr((ord(temp)+num)-26), end='')
        else:
            print(chr((ord(temp)+num)), end='')
    num += 1
    print("")
# 结果会输出26种全部结果,其中有个flag

如果你看不懂这段代码,我想不是脚本多难,而是

  1. 你可能不知道ascii码的相关知识 就是脚本中的ord函数。本质上就是将一个字符转换成唯一的十进制数,方便运算。每个字符均会对应一个十进制数。后面chr就是反过来,将十进制数转换为对应字符。动手网上搜下ascii就能了解了,自学时长20min吧
  2. 前文说了循环结构需要学下。不会的函数百度下,瞬间就会明了。

3.3 加密题目:变异凯撒脚本

有了上面一题的铺垫,此题就好理解了。变异凯撒不是固定key,而是key有规律变化,如本例题,第一个字符,key=5加密。后面每个字符,key都增加1再进行加密,依次类推。
脚本如下,设置个初始key=5,然后在循环中,处理完一个字符,就增加1即可。

key = 5  # 初始key值
result = ""
content = "afZ_r9VYfScOeO_UL^RWUc"  # 密文
for i in range(len(content)):
    ori = ord(content[i]) + key
    result += chr(ori)
    key += 1
print(result)

# 输出结果 flag{Caesar_variation}

3.4 逆向题目

本文不关心逆向解题方法,只关注脚本。所以逆向的脚本反而最简单,原伪代码中算法都写好了,脚本反着写就行。
省略掉逆向题目的前期分析,直接上伪代码
在这里插入图片描述
注意第32行,是伪代码的算法。我们编制的脚本很简单,既然要破解,那就把算法反过来运算,不就行了?

# 1.原始24位字符串
key1 = 'xIrCj~<r|2tWsv3PtIzndka'
flag = ""

# 2. 获取每位的ascii值,(x^6)-1  注意异或运算优先级低于加减
for i in range(0, len(key1)):
    flag += chr((ord(key1[i])^6) - 1) # 注意:异或运算优先级低于加减,所以要写成(ord()^6)-1

#3. 倒序输出
print(flag)
print(flag[::-1]) # 逆序输出

# }NsDkw9sy3qPto4UqNx{galf
# flag{xNqU4otPq3ys9wkDsN}

脚本很简单吧,简单到令人发指。

4. 总结

所以,CTF比赛中脚本的编制,没有大家想象的那么难。真正难得地方是思路,是找到破题点。

如果基础较弱,在日常CTF学习中,遇到不明白的函数,随遇随学,多记套路用法即可。不断练习已经理解的脚本,不断重温新学的函数,写的多,自然就入门了。等真正有时间,再系统学习一门编程语言即可。
个人经验,为了学习而学习,永远学不好。为了一个目标,用“偷懒”的办法,学以致用,不断巩固练习,效果反而好。

猜你喜欢

转载自blog.csdn.net/eason612/article/details/126202413
今日推荐