<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    CTF 中如何欺騙 AI

    VSole2021-08-25 18:00:00

    近年來,筆者在國內外 CTF 競賽中見到不少與 AI 相關的題目。有一些是需要選手自行實現一個 AI,來自動化某些操作;有些是給出了一個目標 AI 模型,要求選手進行破解。本文主要談論后者——在 CTF 競賽中,我們如何欺騙題目給出的 AI?

    CTF 中的欺騙 AI 問題一般分成兩類:基于神經網絡的和基于統計模型的。如果題目要求選手欺騙神經網絡,一般會給出白盒的模型(往往是圖像分類任務);如果是要求選手欺騙統計學習模型,有些題目會給出白盒的模型參數,也有的提供訓練數據集。

    我們先從一道很簡單的欺騙統計學習模型看起,來體驗這類問題的主要求解過程。

    任務目標

    有一個 AI 模型,要求選手上傳一張圖片,與 dear.png 的差異很小,但被 AI 判別為馬。

    import numpy as npfrom PIL import Imageimport mathimport operatorimport osimport timeimport base64import 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 = 0    for x in range(length):        distance += pow((instance1[x] - instance2[x]), 2)    return math.sqrt(distance)
    
    def getNeighbors(trainingSet, testInstance, k):    distances = []    length = len(testInstance) - 1    for 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] += 1        else:            classVotes[response] = 1    sortedVotes = sorted(classVotes.items(), key=operator.itemgetter(1), reverse=True)    return sortedVotes[0][0]
    
    def getAccuracy(testSet, predictions):    correct = 0    for x in range(len(testSet)):        if testSet[x][-1] == predictions[x]:            correct += 1    return (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 = 0    a, b = source_p.size    if 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('''      ____       __            _          _   _                _                              _   _            _                              |  __ \     / _|          | |        | | | |              | |                            | | | |          | |                             | |__) |___| |_ ___ _ __  | |_ ___   | |_| |__   ___    __| | ___  ___ _ __    __ _ ___  | |_| |__   ___  | |__   ___  _ __ ___  ___      |  _  // _ \  _/ _ \ '__| | __/ _ \  | __| '_ \ / _ \  / _` |/ _ \/ _ \ '__|  / _` / __| | __| '_ \ / _ \ | '_ \ / _ \| '__/ __|/ _ \\     | | \ \  __/ ||  __/ |    | || (_) | | |_| | | |  __/ | (_| |  __/  __/ |    | (_| \__ \ | |_| | | |  __/ | | | | (_) | |  \__ \  __/     |_|  \_\___|_| \___|_|     \__\___/   \__|_| |_|\___|  \__,_|\___|\___|_|     \__,_|___/  \__|_| |_|\___| |_| |_|\___/|_|  |___/\___|    ''')        print('-'*134)        print('\t1.show source code')        print('\t2.give me the source pictures')        print('\t3.upload picture')        print('\t4.exit')        choose = input('>')        if choose == '1':            w = open('run.py','r')            print(w.read())            continue        elif choose == '2':            print('this is horse`s picture:')            h = base64.b64encode(open('horse.png','rb').read())            print(h.decode())            print('-'*134)            print('this is deer`s picture:')            d = base64.b64encode(open('deer.png', 'rb').read())            print(d.decode())            continue        elif choose == '4':            break        elif choose == '3':            print('Please input your deer picture`s base64(Preferably in png format)')            pic = input('>')            try:                pic = base64.b64decode(pic)            except:                exit()            if b" in pic or b'eval' in pic:                print("Hacker!!This is not WEB,It`s Just a misc!!!")                exit()            salt = str(random.getrandbits(15))            pic_name = 'tmp_'+salt+'.png'            tmp_pic = open(pic_name,'wb')            tmp_pic.write(pic)            tmp_pic.close()            if check(pic_name)>=100000:                print('Don`t give me the horse source picture!!!')                os.remove(pic_name)                break            ma = load_horse()            lu = load_deer()            k = 1            trainingSet = np.append(ma, lu).reshape(2, 5185)            testSet = load_test(pic_name)            neighbors = getNeighbors(trainingSet, testSet[0], k)            result = getResponse(neighbors)            if repr(result) == '0':                os.system('clear')                print('Yes,I want this horse like deer,here is your flag encoded by base64')                flag = base64.b64encode(open('flag','rb').read())                print(flag.decode())                os.remove(pic_name)                break            else:                print('I want horse but not deer!!!')                os.remove(pic_name)                break        else:            print('wrong choose!!!')            break    exit()
    if __name__=='__main__':    main()
    

    我們詳細看一遍代碼,發現這個 AI 模型是 k-鄰近(k-Nearest Neighbor, KNN),而且還是個 k=1 的情形,且訓練集中,鹿和馬各只有一張圖片。題目將選手的圖片讀進去,做的事情如下:

    1. 檢查選手上傳的圖片與 deer 的像素差是否小于 100000。如果超過限制,則報告錯誤。
    2. 求選手圖片與 deer 和 horse 的歐幾里得距離。離誰更近,就判定為哪個分類。
    3. 如果選手圖片被判定為馬,則選手獲勝。

    deer 和 horse 都是灰度圖,如下:

    筆者建議在做機器學習類 CTF 題的時候,采用 jupyter notebook 或者 jupyter lab,并用好 matplotlib 來可視化當前的結果。這會大大提升工作效率。

    我們現在的目標就是在 deer 的基礎上進行小幅度修改,使得它與 horse 之間的的歐氏距離小于其與 deer 的。

    嘗試:隨機噪聲

    為了構造出合法的圖片,我們需要回去看「修改幅度」的衡量方式。其代碼如下:

    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
    

    它衡量的是圖片 A 與 B 之間每個像素點的距離之和。換句話講,這是曼哈頓距離。筆者遇到的大部分 CTF 欺騙 AI 題目,衡量修改幅度都是采用曼哈頓距離。

    這張圖片共有 5184 個像素點,也就是說,平均下來,每個像素點允許 19 的偏差。事實上,這是非常寬松的值,我們隨便演示一個合法的修改:

    輸出的圖片就像老式電視一樣。那么它能否騙過 AI 呢?

    很遺憾,其與鹿之間的歐氏距離,小于其與馬之間的歐氏距離。我們現在要開始反思一個問題:把 100000 個差異值隨機平攤到每個像素上,是最好的解法嗎?

    解法:修改差異大的像素

    在二維平面上考慮這個問題。假設我們想讓一個點在歐氏距離的衡量下遠離 (0, 0),但要保持曼哈頓距離不超過 2。如果選擇 (1, 1),則歐氏距離為 sqrt(2);如果選擇 (0,2),則歐氏距離可以達到 2,這是更優的選擇。

    那么,我們相應地猜測:對于本題,我們應該把一些像素點直接改到與 horse 的對應像素相等;其他的像素點可以放棄。而那些應當修改的點,是 deer 與 horse 像素差異最大的點。

    生成了一張很怪的圖。來驗證一下是否滿足要求:

    可見與鹿的距離是 4003,與馬的距離是 2538,騙過了 AI。像素差異是 99999,我們成功完成了題目指定的目標。

    數學上的證據

    我們剛剛基于「差異越大的像素越應該修改」這個猜測,成功地解決了問題。這里給出為什么 it works 的證明。不愛看證明的讀者可以跳過。

    所以,我們從數學上證明了為什么「差異越大的像素點,越值得更改」。并且從數學推導中,我們還可以發現另一個結論:將像素點改成馬的對應像素值,并非最優解。要改就改徹底:要么改成 0,要么改成 255。不過本題的像素差異限制 100000 是一個很松的界,所以我們之前不那么優秀的算法也可以成功。

    總結

    回顧我們的做題過程,我們從一個原圖片 X 出發,施加一個很小的擾動向量,獲得樣本 Y,且 AI 對 Y 的表現與對 X 的表現非常不同。這樣的樣本被稱為「對抗樣本」,如何構造高質量的對抗樣本、利用對抗樣本來改進模型的魯棒性,是機器學習研究中逐步受到重視的一個方向。

    需要注意的是,攻擊統計學習 AI 模型,往往需要進行一些數學推導。如果讀者有興趣,筆者推薦了解一下 kNN、kmeans、混合高斯模型等經典的統計學習方法。

    欺騙白盒神經網絡

    概述

    神經網絡能解決大量傳統模型難以解決的問題,近年經歷了飛速發展。神經網絡一般是由多層神經元構成的,每個神經元有自己的參數。下圖是一個簡單的神經網絡模型(多層感知機):

    圖源 IBM。本文假定讀者已經對神經網絡有一些了解;如果從零學起的話,筆者推薦看一看 3Blue1Brown 的機器學習教程、PyTorch 的官方教程。

    以上圖描述的神經網絡為例。在圖像分類任務中,圖像的每個像素點被輸入到第一層,然后傳導到第二層、第三層……直到最后一層。最后一層的每個神經元代表一個分類,其輸出是「圖像是否屬于本類」的打分。我們一般取打分最高的那一類,作為分類結果。

    CTF 中的欺騙神經網絡題一般如下:給定一個預訓練好的分類模型(PyTorch 或者 TensorFlow),再給定一張原圖。要求小幅度修改原圖,使得神經網絡將其誤分類為另一個類別。

    攻擊手段

    我們訓練神經網絡時,一般采用梯度下降的方法。每一輪迭代可以理解為下面的過程:首先輸入 X,然后運行 net(X) 獲取輸出,根據網絡輸出與期望輸出的不同,來反向傳播,修改網絡模型的參數。

    那么,我們現在要攻擊這個網絡,可以采取什么辦法呢?首先還是給網絡提供原圖 X,得到輸出 net(X),接下來,我們根據「網絡分類的結果」與「我們想要誤導的結果」的差異計算 loss 值,進行反向傳播。但是需要注意,我們不修改網絡參數,而是將原圖減去其梯度。這樣迭代若干次,直到成功誤導 AI 為止。

    下面,我們以識別手寫數字(MNIST數據集)的任務為例,從訓練網絡開始,演示一下攻擊方法。

    實踐:訓練神經網絡

    這里采用 PyTorch 來實現神經網絡。首先是導入數據集:

    import torchimport torchvisionimport torch.nn as nnimport torchvision.transforms as transformsimport torch.nn.functional as Fimport numpy as np
    import matplotlib.pyplot as plt
    trans_to_tensor = transforms.Compose([    transforms.ToTensor()])
    data_train = torchvision.datasets.MNIST(    './data',     train=True,     transform=trans_to_tensor,     download=True)
    data_test = torchvision.datasets.MNIST(    './data',     train=False,     transform=trans_to_tensor,     download=True)
    data_train, data_test
    

    實現一個 DataLoader,作用是生成隨機打亂的 mini batch 用于訓練:

    train_loader = torch.utils.data.DataLoader(    data_train,     batch_size=100,     shuffle=True)
    

    來看一個 mini batch。

    接下來定義網絡。我們采用一個很原始的模型:將輸入的 28*28 的灰度圖展開為一維數組,然后經過 100 個神經元的全連接層,激活函數為 ReLu。接下來再通過 10 個神經元的全連接層,激活函數為 sigmoid,作為預測值輸出。

    class MyNet(nn.Module):
        def __init__(self):        super().__init__()        self.fc1 = nn.Linear(28*28, 100)        self.fc2 = nn.Linear(100, 10)
        def forward(self, x):        x = x.view(-1, 28*28)        x = self.fc1(x)        x = F.relu(x)        x = self.fc2(x)        x = torch.sigmoid(x)
            return x
    net = MyNet()
    

    如果圖像中的數字是 c,我們希望輸出的 10 維向量中僅有第 c 位是 1,其余都是 0。所以我們采用交叉熵損失函數以及 Adam 優化器:

    criterion = nn.CrossEntropyLoss()optimizer = torch.optim.Adam(net.parameters())
    

    接下來就是訓練這個網絡。

    def fit(net, epoch=1):    net.train()    run_loss = 0
        for num_epoch in range(epoch):        print(f'epoch {num_epoch}')
            for i, data in enumerate(train_loader):            x, y = data[0], data[1]
                outputs = net(x)            loss = criterion(outputs, y)
                optimizer.zero_grad()            loss.backward()            optimizer.step()
                run_loss += loss.item()
                if i % 100 == 99:                print(f'[{i+1} / 600] loss={run_loss / 100}')                run_loss = 0
                    test(net)
    def test(net):    net.eval()
        test_loader = torch.utils.data.DataLoader(data_train, batch_size=10000, shuffle=False)    test_data = next(iter(test_loader))
        with torch.no_grad():        x, y = test_data[0], test_data[1]
            outputs = net(x)
            pred = torch.max(outputs, 1)[1]        print(f'test acc: {sum(pred == y)} / {y.shape[0]}')
        net.train()
    

    來看 5 個 epoch 之后的結果:

    我們訓練出了測試準確率 97.89% 的網絡。接下來,我們開始針對網絡進行攻擊。

    實踐:欺騙白盒多層感知機

    目前網絡的所有參數我們都是知道的。在 CTF 中,一般會提供訓練網絡的代碼,以及通過 torch.save() 導出的預訓練模型,選手通過 model.load_state_dict() 即可導入模型參數。

    我們隨便選擇一個數據,作為原圖:

    我們的模型以很強的信心,將其分類為 2。接下來,我們篡改原圖,使得網絡將其誤分類為 3。過程如下:

    1. 將圖片輸入網絡,得到網絡輸出。
    2. 將網絡輸出與期望輸出求 loss 值(這里采用交叉熵)。
    3. 將圖片像素減去自己的梯度 * alpha,不改變網絡參數。

    重復以上過程,直到誤導成功為止。代碼如下:

    def play(epoch):    net.requires_grad_(False)     # 凍結網絡參數    img.requires_grad_(True)      # 追蹤輸入數據的梯度
        loss_fn = nn.CrossEntropyLoss()   # 交叉熵損失函數
        for num_epoch in range(epoch):        output = net(img)        target = torch.tensor([3])    # 誤導網絡,使之分類為 3        loss = loss_fn(output, target)
            loss.backward()               # 計算梯度        img.data.sub_(img.grad * .05) # 梯度下降        img.grad.zero_()
            if num_epoch % 10 == 9:            print(f'[{num_epoch + 1} / {epoch}] loss: {loss} pred: {torch.max(output, 1)[1].item()}')
            if torch.max(output, 1)[1].item() == 3:            print(f'done in round {num_epoch + 1}')            return
    img = origin.view(1, 28, 28)
    play(100)
    

    我們成功地構造出了一個對抗樣本,我們人類看顯然還是 2,但模型將其識別為 3。至此成功完成任務。對比圖如下:

    總結

    很多 CTF 欺騙神經網絡題目,都可以采用上面這一套代碼。訓練網絡的代碼選手不用自己寫,只需要導入預訓練好的模型即可。在迭代時,選手應該選取合適的學習率 alpha(筆者的代碼中是 0.05)、添加一些特殊約束(例如對每個像素的修改距離不能超過特定值)。無論如何,欺騙白盒神經網絡的主要思想,往往都是「固定網絡參數、通過梯度下降修改原圖」。

    更進一步的討論

    我們已經一步步完成了對白盒神經網絡的欺騙。但日常生活中,很少有神經網絡會把自己的參數廣而告之,這使得我們不能采用上面的套路去攻擊。此外,我們上面生成的那張圖片很不「自然」,有大量的背景噪聲,而這是正常的數字圖片中不會存在的。

    關于這些問題,ICLR2018 的一篇論文 Generating natural adversarial examples 可以提供一些啟發。該論文提出的方法不要求預先知道網絡參數,甚至不要求知道網絡模型。而且該方案能生成比較自然的對抗樣本,如下所示:

    那么,他們是如何做到的呢?下面簡要描述一下原理。首先,通過類似于 CycleGAN 的思路,訓練一個從 latent space 到圖片的生成器、一個從圖片反推 z 的編碼器。接下來,把原圖編碼成向量 z,并在 z 的附近隨機選擇很多的 z’,利用生成器從這些 z’ 生成圖片,然后交給目標模型去判斷。如果有圖片成功誤導了模型,則報告成功。

    論文作者給出了該方法用于 CV 和 NLP 兩個領域的成效,并成功地攻擊了谷歌翻譯。他們的代碼開源在 Github 上。

    這是一個適用范圍比較廣的方案,不過筆者認為可能不適合用于 CTF 出題。這是因為訓練 GAN 是一件費時費力、且需要機器學習技巧的工作,已經超出了 CTF 一般的考察范疇;且由于出題人模型是黑盒的,可能訓練模型技巧較好、使用的判別模型與出題人差異較大的選手反而難以成功。

    總而言之,對抗樣本是一條很有趣的研究方向。筆者今天介紹了 CTF 競賽中欺騙 AI 的一般步驟,希望對 CTF 選手有所幫助。

    神經網絡模型ctf
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    CTF 中如何欺騙 AI
    2021-08-25 18:00:00
    近年來,筆者在國內外 CTF 競賽中見到不少與 AI 相關的題目。有一些是需要選手自行實現一個 AI,來自動化某些操作;有些是給出了一個目標 AI 模型,要求選手進行破解。本文主要談論后者——在 CTF 競賽中,我們如何欺騙題目給出的 AI?
    所以在最壞的安全假設下,噪聲成為降低攻擊效率的主要條件。GE表示正確密鑰的位置排名。每條能量跡有25萬個樣本點,對其中1400個特征點進行分析。漢明重量泄露模型下特征點數量和PI的關系在高信噪比的情況下,神經網絡顯示出優于高斯模板攻擊的性能。圖中顯示了每個單獨的密鑰字節達到猜測熵為1 時所需的攻擊軌跡數。
    這凸顯了開發檢測惡意 PowerShell 命令的有效方法的迫切需要。在這項工作中,我們通過實施幾個新穎的惡意 PowerShell 命令檢測器并評估它們的性能來應對這一挑戰。在這項工作中,我們使用 AMSI 提供的信息對惡意 PowerShell 代碼檢測進行了首次研究。
    研究人員zhi Wang、Chaoge Liu 和Xiang Cui 提出了一種通過神經網絡模型傳遞惡意軟件的技術,以在不影響網絡性能的情況下逃避檢測。
    模型量化攻擊
    2022-01-12 16:34:14
    隨著深度神經網絡模型的性能增加,神經網絡的深度越來越深
    針對現有的靜態代碼分析工具有較高的誤報率與漏報率,提出一種基于切片依賴圖(Slice Dependency Graph,SDG)的自動化漏洞檢測方法,將程序源代碼解析為包含數據依賴和控制依賴信息的切片依賴圖,然后使用圖神經網絡對切片依賴圖的結構進行表征學習,最后使用訓練的神經網絡模型預測待測程序源代碼中的漏洞。在 5 類常見缺陷分類(Common Weakness Enumeration,CWE)
    針對當前的入侵檢測方法普遍存在準確率與泛化性較低的問題,提出了一種基于卷積神經網絡(Convolutional Neural Network,CNN)和權重縮減門控循環單元(Weight Reduction Gated Recurrent Unit,WRGRU)的網絡入侵檢測模型(CNN-WRGRU)。該模型首先利用 CNN 進行入侵檢測數據集的特征提取,其次利用 WRGRU 來學習數據特征之間的
    深度神經網絡(DNNs)缺乏透明性使得它們容易受到后門攻擊,其中隱藏的關聯或觸發器會覆蓋正常的分類以產生意想不到的結果。例如,如果輸入中存在特定符號,則具有后門的模型總是將人臉識別為比爾蓋茨。后門可以無限期地隱藏,直到被輸入激活,并給許多與安全或安全相關的應用帶來嚴重的安全風險,例如,生物識別系統或汽車自動駕駛。
    同時購買這兩種食品的消費者將會在墨西哥食品和亞洲食品集群之間形成一種嵌入。商店和客戶的行為定期訓練這類嵌入,以便在推薦和其他個性化應用程序中使用。
    STRIDE是一個流行的威脅建模框架,目前已被廣泛用來幫助組織主動發現那些可能對其應用系統造成影響的威脅、攻擊、漏洞和對策。
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类