adversarial_ml_ctf靶场攻击(明文)

攻击流程

有代码

注意ai会给模型文件以及部分代码用来调用接口

题目:

在check接口接收post的图片(256*256)

返回的json为similarity、access、text

目标:让access变成granted

题目是使用的ResNet50 模型

我们需要拿出预设图片

复制代码
sudo docker exec ai-ctf find /app -type f \( -name "*.jpg" -o -name "*.png" -o -name "*.jpeg" \) 2>/dev/null
复制代码
sudo docker exec ai-ctf cat /app/app/model.py

from torchvision import transforms
from torchvision import models
import torch


class Model():
    def __init__(self):
        self.resnet50 = models.resnet50(pretrained=True)
        self.resnet50.eval()

        self.transform = transforms.Compose([transforms.Resize(256),
                                             transforms.CenterCrop(224),
                                             transforms.ToTensor(),
                                             transforms.Normalize(
                                             mean=[0.485, 0.456, 0.406],
                                             std=[0.229, 0.224, 0.225])])

    def check_similarity(self, image):
        image_tensor = torch.unsqueeze(self.transform(image), 0)
        out = self.resnet50(image_tensor)
        similarity = torch.nn.functional.softmax(out, dim=1)[0] * 100
        goldfish_similarity = similarity[1].item() # [1] is the goldfish class

        return goldfish_similarity
     
sudo docker exec ai-ctf cat /app/app/views.py

import base64
from io import BytesIO

import flask
from PIL import Image
import numpy as np

from app import app, model


@app.route('/')
def home():
    return flask.render_template('index.html')


random_number = ''.join([str(value) for value in np.random.randint(10, size=30)])
@app.route('/hidden_page_' + random_number)
def hidden_page():
    return flask.render_template('hidden_page.html')


@app.route('/check', methods=['POST'])
def check():
    data = flask.request.get_data()
    image = decode_image(data)
    similarity = model.check_similarity(image)
    response = create_response(similarity)
    return response


def decode_image(data):
    starter = data.find(b',')
    image_data = data[starter+1:]
    image = Image.open(BytesIO(base64.b64decode(image_data))).convert('RGB')
    return image


def create_response(similarity):
    if similarity > 80.0:
        data = flask.redirect(flask.url_for('hidden_page'))
        return data
    elif similarity > 50.0:
        data = {'similarity': similarity, 'access': 'denied', 'text': 'The AI is unsure...'}
    elif similarity > 10.0:
        data = {'similarity': similarity, 'access': 'denied', 'text': 'The AI is confident, that you have no access rights.'}
    else:
        data = {'similarity': similarity, 'access': 'denied', 'text': 'The AI is very confident, that you have no access rights.'}
    return flask.jsonify(data) 

要similarity>80,目标是ImageNet → 1 = goldfish

查询代码

复制代码
# 方法1: 用 torchvision 自带的标签
from torchvision.models import ResNet50_Weights
weights = ResNet50_Weights.IMAGENET1K_V1
print(weights.meta["categories"][1])  # → 'goldfish'

# 方法2: 直接查公开的标签文件
import requests
labels = requests.get("https://raw.githubusercontent.com/anishathalye/imagenet-simple-labels/master/imagenet-simple-labels.json").json()
print(labels[1])  # → 'goldfish'

攻击脚本

复制代码
import base64
import io
import requests
from PIL import Image

# 1. 准备金鱼图
img = Image.open('goldfish.jpg').convert('RGB')

# 2. 转 base64
buf = io.BytesIO()
img.save(buf, format='PNG')
body = "data:image/png;base64," + base64.b64encode(buf.getvalue()).decode()

# 3. 发到靶场
r = requests.post(
    'http://192.168.21.137:5000/check',
    data=body,
    headers={'Content-Type': 'image/png'},
    allow_redirects=True
)

print(r.text)