Base64隱寫
0x00: 前言
Base64編碼的作用:
- 將一些特殊的字符轉(zhuǎn)換成常見的字符。特殊的字符可能是不可見字符或者是大于ascii碼127的,將其變成常見的字符(在base64中為a~z A~Z 0~9 + /)。
- Base64特別適合在某些網(wǎng)絡(luò)協(xié)議下快速傳輸。
在學(xué)習(xí)Base64隱寫之前,得先熟悉Base64編碼與解碼的過程。
0x01: Base64的編碼過程
Base64編碼后的字符為”a~z A~Z 0~9 + /“共計(jì)64個(gè),每個(gè)需要6個(gè)比特位進(jìn)行存儲(chǔ)。原本,ASCII編碼字符每個(gè)字符占8個(gè)比特位。Base64編碼則是把原來(lái)每單位8個(gè)比特位的字符序列劃分成每單位6個(gè)比特位,然后按單位轉(zhuǎn)換成上述中的64個(gè)字符。

Base64編碼表
舉個(gè)栗子~:將字符串"tolele"進(jìn)行Base64編碼。
- 根據(jù)ASCII編碼進(jìn)行轉(zhuǎn)換:tolele <==> 01110100 01101111 01101100 01100101 01101100 01100101
- 重新按6bit進(jìn)行劃分:011101 000110 111101 101100 011001 010110 110001 100101
- 根據(jù)Base64編碼表進(jìn)行轉(zhuǎn)碼:dG9sZWxl
檢驗(yàn)一下是沒問題的:

通過這種方式編碼,當(dāng)字符數(shù)為3的倍數(shù)時(shí)才會(huì)剛好可以轉(zhuǎn)換成若干個(gè)Base64編碼字符。那當(dāng)字符數(shù)不為3的倍數(shù)時(shí),該怎么辦呢?解決方法就是往后面以8bit為單位填充0。
這時(shí),有兩種情況:
- 字符數(shù)為3n+1:此情況最后會(huì)多出2個(gè)比特位,我們可以填充2個(gè)單位的0(即16個(gè)比特位的0),這時(shí)會(huì)有多余的18個(gè)比特位。前6個(gè)比特位按表格進(jìn)行轉(zhuǎn)碼,其余的每6個(gè)bit位轉(zhuǎn)換成'='。
- 字符數(shù)為3n+2:此情況會(huì)多出4個(gè)比特位,填充1個(gè)單位的0,這樣就多余12個(gè)比特位,為6的整數(shù)倍。后續(xù)和1中類似。
圖像總是比話語(yǔ)更能說(shuō)明內(nèi)容:

檢驗(yàn)一下:

0x02: Base64的解碼過程:
很顯然,解碼過程就是編碼的逆過程。
拿上面"tole"的Base64編碼"dG9sZQ=="進(jìn)行舉例:
- 先把填充的'='去掉:dG9sZQ
- 根據(jù)Base64編碼表進(jìn)行轉(zhuǎn)碼:dG9sZQ <==> 011101 000110 111101 101100 011001 010000
- 從前往后,以每8個(gè)比特位為單位進(jìn)行ASCII轉(zhuǎn)換成字符。最后面會(huì)有4個(gè)'0'多余,直接去掉就行。
0x03: Base64隱寫原理:
可以留意一下解碼過程中的第三步,會(huì)將多余的比特位去掉(因?yàn)闇惒坏?span id="w0obha2h00" class="ne-text">8位)。那么,這說(shuō)明了:這多余的比特位即使我們隨意的改變值也不會(huì)影響解碼后的結(jié)果,因?yàn)樗鼤?huì)被丟棄掉。
測(cè)試一下:還是上面的例子,最后是Q,為010000。后面的4個(gè)0在解碼時(shí)會(huì)被丟棄掉的,那我們使其變成010101,變成了V。解碼后的結(jié)果會(huì)改變嗎?

可見,這個(gè)改變并不會(huì)對(duì)解碼結(jié)果造成影響。
這樣,為了隱寫某些數(shù)據(jù),我們就可以將數(shù)據(jù)寫入這里。但每個(gè)Base64編碼最多多余4個(gè)比特位,為了隱藏較大的數(shù)據(jù),我們常常需要多個(gè)比特位。提取時(shí),我們可以將每個(gè)多余的比特位截取出來(lái),按一定的順序組合,從而得到我們的隱藏?cái)?shù)據(jù)。
0x04: 例題實(shí)踐
Buuctf的base64隱寫:
https://buuoj.cn/challenges#[ACTF%E6%96%B0%E7%94%9F%E8%B5%9B2020]base64%E9%9A%90%E5%86%99
打開關(guān)鍵的txt文件一看,大量的base64編碼,base64隱寫跑不了了:

這里直接用大佬的腳本了,python2執(zhí)行是沒問題的,至于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

浙公網(wǎng)安備 33010602011771號(hào)