創作內容

1 GP

Pwn2Win androids_encryption

作者:OKHand│2020-07-07 06:03:46│巴幣:2│人氣:128
Androids_encryption:
我們先看它有3個選項可以選並且都是做不同的動作(廢話XD) 我們直接看它的程式碼
上面這段是共用的部分
import sys
import base64
from Crypto.Cipher import AES
from secrets import flag, key1, iv1

def to_blocks(txt):
    return [txt[i*BLOCK_SIZE:(i+1)*BLOCK_SIZE] for i in range(len(txt)//BLOCK_SIZE)]

def xor(b1, b2=None):
    if isinstance(b1, list) and b2 is None:
        assert len(set([len(b) for b in b1])) == 1, 'xor() - Invalid input size'
        assert all([isinstance(b, bytes) for b in b1]), 'xor() - Invalid input type'
        x = [len(b) for b in b1][0]*b'\x00'
        for b in b1:
            x = xor(x, b)
        return x
    assert isinstance(b1, bytes) and isinstance(b2, bytes), 'xor() - Invalid input type'
    return bytes([a ^ b for a, b in zip(b1, b2)])

BUFF = 256
BLOCK_SIZE = 16
iv2 = AES.new(key1, AES.MODE_ECB).decrypt(iv1)
key2 = xor(to_blocks(flag))

然後下面選擇後程式碼跑的部分
選擇1時跳到這然後要你輸入input(16bite)

def enc_plaintext():
    print('Plaintext: ', end='')
    txt = base64.b64decode(input().rstrip())
    print(encrypt(txt, key1, iv1))
跳到->
def encrypt(txt, key1, iv1):
    global key2, iv2
    assert len(key1) == BLOCK_SIZE, f'Invalid key1 size'
    assert len(iv1) == BLOCK_SIZE, 'Invalid IV size'
    assert len(txt) % BLOCK_SIZE == 0, 'Invalid plaintext size'
    bs = len(key1)
    blocks = to_blocks(txt)
    ctxt = b''
    aes = AES.new(key1, AES.MODE_ECB)
    curr = iv1
    for block in blocks:
        ctxt += aes.encrypt(xor(block, curr))
        curr = xor(ctxt[-bs:], block)
    iv2 = AES.new(key2, AES.MODE_ECB).decrypt(iv2)
    key2 = xor(to_blocks(ctxt))
    return str(base64.b64encode(iv1+ctxt), encoding='utf8')

這邊可以注意到的是key2 = xor(to_blocks(ctxt))這段
Ps. a[0] xor \x00 *len(a[0]) 因為任何數 xor 00 都是自己不會變
最後回傳一個iv1+ctxt的值並且要注意到的是它回傳的值都是用base64去加密過的

選擇2時跳到這然後會回傳一個enc_flag(這是一個用key2,iv2去加密過的flag)
def enc_flag():
    print(encrypt(flag, key2, iv2))
跳到->
def encrypt(txt, key, iv):
    global key2, iv2
    assert len(key) == BLOCK_SIZE, f'Invalid key size'
    assert len(iv) == BLOCK_SIZE, 'Invalid IV size'
    assert len(txt) % BLOCK_SIZE == 0, 'Invalid plaintext size'
    bs = len(key)
    blocks = to_blocks(txt)
    ctxt = b''
    aes = AES.new(key, AES.MODE_ECB)
    curr = iv
    for block in blocks:
        ctxt += aes.encrypt(xor(block, curr))
        curr = xor(ctxt[-bs:], block)
    iv2 = AES.new(key2, AES.MODE_ECB).decrypt(iv2)
    key2 = xor(to_blocks(ctxt))
    return str(base64.b64encode(iv+ctxt), encoding='utf8')

一樣注意到的是 xor 和 輸入值和回傳值是用base64加密的部分
Ps.key2的部分會因為之前講的xor特性所以key2=cipher
Ps.全部的 inputs和outputs都是做base64加密
跑2的時候會複寫一次iv2,key2然後會收到command給的iv2+flag_cipher我們這邊接收到回傳後可以用第一步的key2和新的iv2去做使用去解Flag

解題方法:
我取用下面某一篇的範例去跟著做並且去解說
1.enc_plaintext()
我們先send一個隨便的payload(16bit)我們可以收到iv1+cipher,從密碼我們可以知道新的key2因為xor特性所以
key2 = a[0] 所以key2就是first block 的密碼

response1 = 'qal7b3mi7fEvSccj+NcaYtqU4i4io4qT1g88K9wY2nQ='
iv_plus_ctext = base64.b64decode(response1)
iv= enc_m[:BLOCK_SIZE]    #BLOCK_SIZE==16
ctxt = enc_m[BLOCK_SIZE:] # IV is 16 bytes long
key2 = xor(to_blocks(ctext))

2. enc_flag()
接下來我們送2 給command我們會收到iv2+flag_cipher我們這邊接收到的回傳可以用第一步的key2去拿到新的iv2因為它執行的
iv2 = AES.new(key2, AES.MODE_ECB).decrypt(iv2) 所以我們可以更新key2現在的值所以我們現在有key2,iv2了可以用他們去解密flag了

enc_flag = '36X0Ug8ZEIvrRDeus6c3GBynEY7La36H0/A1Bqoy87go8FyYOeRQOuN7b0fXJXMYqWZ9lo9MWkS8EaN9/8Tl7A=='
enc_flag = base64.b64decode(enc_flag)
iv2  = enc_flag[:BLOCK_SIZE]   #BLOCK_SIZE==  0 to 16
ctxt = enc_flag[BLOCK_SIZE:]   #BLOCK_SIZE==16 to end

3.解出Flag並合併
這邊要講道AES PCBC加解碼特性請看下圖 ※這張圖非常重要可以搭程式碼先看一遍,不過一定要看的懂因為這是解出Flag的關鍵請一定要看懂不然下面的解題程式碼一定看不懂QQ
我們可以看到它是用以下方法做的
aes = AES.new(key2, AES.MODE_ECB)
加密運作:
它運作是cipher1(=C1) = aes(text1(=P1) xor iv) , 然後接下來每個區塊是
cipher2(=C2) = aes(text2(=P2) xor (text1(=P1) xor cipher1(=C1) ))這樣下去運作加密
解密運作:
所以我們解密可以這樣下去做
text1(=P1) = iv xor aes.decrypt( cipher1(=C1) ) ,然後接下來每個區塊是
textI(=PI) = xor(aes.decrypt( cipherI(=CI) ) xor ( cipherJ(=CJ),textJ(=PJ) ) )
I是當前的位置J=I-1 EX:I=2 , J=1
所以我們得出
from Crypto.Cipher import AES

iv2 = enc_flag[:16]
c1 = enc_flag[16:32]
c2 = enc_flag[32:48]
c3 = enc_flag[48:64]

aes = AES.new(key2, AES.MODE_ECB)

p1 = xor(aes.decrypt(c1),iv2)
p2 = xor(aes.decrypt(c2),xor(c1,p1))
p3 = xor(aes.decrypt(c3),xor(c2,p2))

print(p1+p2+p3)

最後可以解出CTF-BR{kn3W_7h4T_7hEr3_4r3_Pc8C_r3pe471ti0ns?!?}


我記得當初在解的時候看得出來是AES加密可是卡在AES的知識不足,不知道整麼解就卡住了QQ
如果有錯或是觀念不對 歡迎糾正^^
兩個網頁的解法程式碼都在下面
推這兩個比較容易看懂 第2個有範例可以跟著做
基本詳細觀念看這個

圖片來源:


#https://qiita.com/takdcloose/items/fe9b9cac417676103b17 程式碼跑範例
import base64
from Crypto.Cipher import AES

BUFF = 256
BLOCK_SIZE = 16

def to_blocks(txt):
    return [txt[i*BLOCK_SIZE:(i+1)*BLOCK_SIZE] for i in range(len(txt)//BLOCK_SIZE)]


def xor(b1, b2=None):
    if isinstance(b1, list) and b2 is None:
        assert len(set([len(b) for b in b1])) == 1, 'xor() - Invalid input size'
        assert all([isinstance(b, bytes) for b in b1]), 'xor() - Invalid input type'
        x = [len(b) for b in b1][0]*b'\x00'
        for b in b1:
            x = xor(x, b)
        return x
    assert isinstance(b1, bytes) and isinstance(b2, bytes), 'xor() - Invalid input type'
    return bytes([a ^ b for a, b in zip(b1, b2)])



# firstly, i'll make an arbitrary key2
enc_m = 'qal7b3mi7fEvSccj+NcaYtqU4i4io4qT1g88K9wY2nQ='
enc_m = base64.b64decode(enc_m)
iv= enc_m[:BLOCK_SIZE]
ctxt = enc_m[BLOCK_SIZE:]
key2 = xor(to_blocks(ctxt))

# Secondly, get iv2
enc_flag = '36X0Ug8ZEIvrRDeus6c3GBynEY7La36H0/A1Bqoy87go8FyYOeRQOuN7b0fXJXMYqWZ9lo9MWkS8EaN9/8Tl7A=='
enc_flag = base64.b64decode(enc_flag)
iv2= enc_flag[:BLOCK_SIZE]
#ctxt = enc_flag[BLOCK_SIZE:]

# Next, culculate newly iv2,key2 using ctxt, key2 and iv2 above
#iv2 = AES.new(key2, AES.MODE_ECB).decrypt(iv2)
key2 = xor(to_blocks(ctxt))

# Now we have iv2 and key2. let's decrypt the flag
enc_flag = '36X0Ug8ZEIvrRDeus6c3GBynEY7La36H0/A1Bqoy87go8FyYOeRQOuN7b0fXJXMYqWZ9lo9MWkS8EaN9/8Tl7A=='
enc_flag = base64.b64decode(enc_flag)
ctxt = enc_flag[BLOCK_SIZE:]
b1 = xor(AES.new(key2, AES.MODE_ECB).decrypt(ctxt[:BLOCK_SIZE]) , iv2)

curr = xor(b1, ctxt[:BLOCK_SIZE])
b2 = xor(AES.new(key2, AES.MODE_ECB).decrypt(ctxt[BLOCK_SIZE:BLOCK_SIZE*2]) , curr)

curr = xor(b2, ctxt[BLOCK_SIZE:BLOCK_SIZE*2])
b3 = xor(AES.new(key2, AES.MODE_ECB).decrypt(ctxt[BLOCK_SIZE*2:BLOCK_SIZE*3]) , curr)

print(b1+b2+b3)



#https://reveng-ctf.com/crypto/pwn2win-androids-encryption.html#step-by-step 程式碼跑範例
import base64
from Crypto.Cipher import AES

BUFF = 256
BLOCK_SIZE = 16

def to_blocks(txt):
    return [txt[i*BLOCK_SIZE:(i+1)*BLOCK_SIZE] for i in range(len(txt)//BLOCK_SIZE)]


def xor(b1, b2=None):
    if isinstance(b1, list) and b2 is None:
        assert len(set([len(b) for b in b1])) == 1, 'xor() - Invalid input size'
        assert all([isinstance(b, bytes) for b in b1]), 'xor() - Invalid input type'
        x = [len(b) for b in b1][0]*b'\x00'
        for b in b1:
            x = xor(x, b)
        return x
    assert isinstance(b1, bytes) and isinstance(b2, bytes), 'xor() - Invalid input type'
    return bytes([a ^ b for a, b in zip(b1, b2)])

def encrypt(txt, key, iv):
    global key2, iv2
    assert len(key) == BLOCK_SIZE, f'Invalid key size'
    assert len(iv) == BLOCK_SIZE, 'Invalid IV size'
    assert len(txt) % BLOCK_SIZE == 0, 'Invalid plaintext size'
    bs = len(key)
    blocks = to_blocks(txt)
    ctxt = b''
    aes = AES.new(key, AES.MODE_ECB)
    curr = iv
    for block in blocks:
        ctxt += aes.encrypt(xor(block, curr))
        curr = xor(ctxt[-bs:], block)
    iv2 = AES.new(key2, AES.MODE_ECB).decrypt(iv2)
    key2 = xor(to_blocks(ctxt))
    return str(base64.b64encode(iv+ctxt), encoding='utf8')


response1 = 'qal7b3mi7fEvSccj+NcaYtqU4i4io4qT1g88K9wY2nQ='
iv_plus_ctext = base64.b64decode(response1)
ctext = iv_plus_ctext[16:] # IV is 16 bytes long
key2 = xor(to_blocks(ctext))

enc_flag = '36X0Ug8ZEIvrRDeus6c3GBynEY7La36H0/A1Bqoy87go8FyYOeRQOuN7b0fXJXMYqWZ9lo9MWkS8EaN9/8Tl7A=='
enc_flag = base64.b64decode(enc_flag)

iv2 = enc_flag[:16]
c1 = enc_flag[16:32]
c2 = enc_flag[32:48]
c3 = enc_flag[48:64]

aes = AES.new(key2, AES.MODE_ECB)

p1 = xor(aes.decrypt(c1),iv2)
p2 = xor(aes.decrypt(c2),xor(c1,p1))
p3 = xor(aes.decrypt(c3),xor(c2,p2))

print(p1+p2+p3)
引用網址:https://home.gamer.com.tw/TrackBack.php?sn=4841052
All rights reserved. 版權所有,保留一切權利

相關創作

同標籤作品搜尋:#CTF|#Crypto

留言共 0 篇留言

我要留言提醒:您尚未登入,請先登入再留言

1喜歡★az7899603 可決定是否刪除您的留言,請勿發表違反站規文字。

前一篇:專題製作-找輪廓畫線... 後一篇:AIS3 2020 pr...

追蹤私訊切換新版閱覽

作品資料夾

colanncolann
【繪圖創作】【科嵐實驗室】九週年! 2024/4/1 https://home.gamer.com.tw/creationDetail.php?sn=5909407看更多我要大聲說昨天23:46


face基於日前微軟官方表示 Internet Explorer 不再支援新的網路標準,可能無法使用新的應用程式來呈現網站內容,在瀏覽器支援度及網站安全性的雙重考量下,為了讓巴友們有更好的使用體驗,巴哈姆特即將於 2019年9月2日 停止支援 Internet Explorer 瀏覽器的頁面呈現和功能。
屆時建議您使用下述瀏覽器來瀏覽巴哈姆特:
。Google Chrome(推薦)
。Mozilla Firefox
。Microsoft Edge(Windows10以上的作業系統版本才可使用)

face我們了解您不想看到廣告的心情⋯ 若您願意支持巴哈姆特永續經營,請將 gamer.com.tw 加入廣告阻擋工具的白名單中,謝謝 !【教學】