近年来,笔者在国内外 CTF 竞赛中见到不少与 AI 相关的题目。有一些是需要选手自行实现一个 AI,来自动化某些操作;有些是给出了一个目标 AI 模型,要求选手进行破解。本文主要谈论后者——在 CTF 竞赛中,我们如何欺骗题目给出的 AI?
CTF 中的欺骗 AI 问题一般分成两类:基于神经网络的和基于统计模型的。如果题目要求选手欺骗神经网络,一般会给出白盒的模型(往往是图像分类任务);如果是要求选手欺骗统计学习模型,有些题目会给出白盒的模型参数,也有的提供训练数据集。
我们先从一道很简单的欺骗统计学习模型看起,来体验这类问题的主要求解过程
欺骗 kNN:[西湖论剑2020] 指鹿为马
任务目标
有一个 AI 模型,要求选手上传一张图片,与 dear.png 的差异很小,但被 AI 判别为马。
import numpy as np
from PIL import Image
import math
import operator
import os
import time
import base64
import random
def load_horse():data = []p = Image.open('./horse.png').convert('L')p = np.array(p).reshape(-1)p = np.append(p,0)data.append(p)return np.array(data)
def load_deer():data = []p = Image.open('./deer.png').convert('L')p = np.array(p).reshape(-1)p = np.append(p,1)data.append(p)return np.array(data)
def load_test(pic):data = []p = Image.open(pic).convert('L')p = np.array(p).reshape(-1)p = np.append(p,1)data.append(p)return np.array(data)
def euclideanDistance(instance1, instance2, length):distance = 0for x in range(length):distance += pow((instance1[x] - instance2[x]), 2)return math.sqrt(distance)
def getNeighbors(trainingSet, testInstance, k):distances = []length = len(testInstance) - 1for x in range(len(trainingSet)):dist = euclideanDistance(testInstance, trainingSet[x], length)distances.append((trainingSet[x], dist))distances.sort(key=operator.itemgetter(1))neighbors = []for x in range(k):neighbors.append(distances[x][0])return neighbors
def getResponse(neighbors):classVotes = {}for x in range(len(neighbors)):response = neighbors[x][-1]if response in classVotes:classVotes[response] += 1else:classVotes[response] = 1sortedVotes = sorted(classVotes.items(), key=operator.itemgetter(1), reverse=True)return sortedVotes[0][0]
def getAccuracy(testSet, predictions):correct = 0for x in range(len(testSet)):if testSet[x][-1] == predictions[x]:correct += 1return (correct / float(len(testSet))) * 100.0
def check(pic):source_p = Image.open('deer.png')try:c_p = Image.open(pic)except:print("Please upload right picture.")exit()diff_pixel = 0a, b = source_p.sizeif c_p.size[0] != a and c_p.size[1] != b:print("Please upload right picture size("+str(a)+','+str(b)+')')exit()for y in range(b):for x in range(a):diff_pixel += abs(source_p.getpixel((x, y)) - c_p.getpixel((x, y)))return diff_pixel
def main():while 1:print('-' * 134)print('''____ ____ ___ __ |__ \ / _|| || | | || || | | || | | |__) |___| |_ ___ _ __| |_ ___ | |_| |__ _____| | ______ _ ____ _ ___| |_| |__ ___| |__ ____ __ ______ |_// _ \_/ _ \ '__| | __/ _ \| __| '_ \ / _ \/ _` |/ _