base64隱寫

tolele發表於2022-05-14

 

0x00: 前言

Base64編碼的作用:

  • 將一些特殊的字元轉換成常見的字元。特殊的字元可能是不可見字元或者是大於ascii127的,將其變成常見的字元(在base64中為a~z A~Z 0~9 + /)。
  • Base64特別適合在某些網路協議下快速傳輸。

在學習Base64隱寫之前,得先熟悉Base64編碼與解碼的過程。

 

0x01: Base64的編碼過程

       Base64編碼後的字元為”a~z A~Z 0~9 + /共計64個,每個需要6個位元位進行儲存。原本,ASCII編碼字元每個字元佔8個位元位。Base64編碼則是把原來每單位8個位元位的字元序列劃分成每單位6個位元位,然後按單位轉換成上述中的64個字元。

 

Base64編碼表

 

舉個例子~:將字串"tolele"進行Base64編碼。

  1. 根據ASCII編碼進行轉換:tolele <==> 01110100 01101111 01101100 01100101 01101100 01100101
  2. 重新按6bit進行劃分:011101 000110 111101 101100 011001 010110 110001 100101
  3. 根據Base64編碼表進行轉碼:dG9sZWxl

 

檢驗一下是沒問題的:

 

 

      通過這種方式編碼,當字元數為3的倍數時才會剛好可以轉換成若干個Base64編碼字元。那當字元數不為3的倍數時,該怎麼辦呢?解決方法就是往後面以8bit為單位填充0

這時,有兩種情況:

  1. 字元數為3n+1:此情況最後會多出2個位元位,我們可以填充2個單位的0(即16個位元位的0),這時會有多餘的18個位元位。前6個位元位按表格進行轉碼,其餘的每6bit位轉換成'='
  2. 字元數為3n+2:此情況會多出4個位元位,填充1個單位的0,這樣就多餘12個位元位,為6的整數倍。後續和1中類似。

 

影像總是比話語更能說明內容:

 

檢驗一下:

 

 

 

0x02: Base64的解碼過程:

很顯然,解碼過程就是編碼的逆過程。

拿上面"tole"Base64編碼"dG9sZQ=="進行舉例:

  1. 先把填充的'='去掉:dG9sZQ
  2. 根據Base64編碼表進行轉碼:dG9sZQ <==> 011101 000110 111101 101100 011001 010000
  3. 從前往後,以每8個位元位為單位進行ASCII轉換成字元。最後面會有4'0'多餘,直接去掉就行。

 

0x03: Base64隱寫原理:

       可以留意一下解碼過程中的第三步,會將多餘的位元位去掉(因為湊不到8位)。那麼,這說明了:這多餘的位元位即使我們隨意的改變值也不會影響解碼後的結果,因為它會被丟棄掉。

       測試一下:還是上面的例子,最後是Q,為010000。後面的40在解碼時會被丟棄掉的,那我們使其變成010101,變成了V。解碼後的結果會改變嗎?

可見,這個改變並不會對解碼結果造成影響。

 

       這樣,為了隱寫某些資料,我們就可以將資料寫入這裡。但每個Base64編碼最多多餘4個位元位,為了隱藏較大的資料,我們常常需要多個位元位。提取時,我們可以將每個多餘的位元位擷取出來,按一定的順序組合,從而得到我們的隱藏資料。

 

0x04: 例題實踐

Buuctfbase64隱寫:

https://buuoj.cn/challenges#[ACTF%E6%96%B0%E7%94%9F%E8%B5%9B2020]base64%E9%9A%90%E5%86%99

 

開啟關鍵的txt檔案一看,大量的base64編碼,base64隱寫跑不了了:

 

這裡直接用大佬的指令碼了,python2執行是沒問題的,至於python3的話……


# -*- coding: cp936 -*-

b64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'

with open('1.txt', 'rb') as f:
bin_str = ''
for line in f.readlines():
stegb64 = ''.join(line.split())
rowb64 = ''.join(stegb64.decode('base64').encode('base64').split())

offset = abs(b64chars.index(stegb64.replace('=','')[-1])-b64chars.index(rowb64.replace('=','')[-1]))
equalnum = stegb64.count('=') #no equalnum no offset

if equalnum:
bin_str += bin(offset)[2:].zfill(equalnum * 2)

print ''.join([chr(int(bin_str[i:i + 8], 2)) for i in xrange(0, len(bin_str), 8)]) #8 位一組

 

0x05: 感慨

       “您這flag挺能藏的呀~”


tolele

2022-05-14

 

相關文章