1. 程式人生 > >南郵ctf-密碼學(前五題)

南郵ctf-密碼學(前五題)

寫writeup之前先來介紹一下Base編碼系列:base16,base32與base64。

1.

Base16編碼使用16個ASCII可列印字元(數字0-9和字母A-F)對任意位元組資料進行編碼。Base16先獲取輸入字串每個位元組的二進位制值(不足8位元在高位補0),然後將其串聯進來,再按照4位元一組進行切分,將每組二進位制數分別轉換成十進位制,在下述表格中找到對應的編碼串接起來就是Base16編碼。可以看到8位元資料按照4位元切分剛好是兩組,所以Base16不可能用到填充符號“=”。

Base16編碼後的資料量是原資料的兩倍:1000位元資料需要250個字元(即 250*8=2000 位元)。換句話說:Base16使用兩個ASCII字元去編碼原資料中的一個位元組資料。

Base16編碼是一個標準的十六進位制字串(注意是字串而不是數值),更易被人類和計算機使用,因為它並不包含任何控制字元,以及Base64和Base32中的“=”符號。

編碼 編碼
0 0 8 8
1 1 9 9
2 2 10 A
3 3 11 B
4 4 12 C
5 5 13 D
6 6 14 E
7 7 15 F

2.Base32編碼是使用32個可列印字元(字母A-Z和數字2-7)對任意位元組資料進行編碼的方案,編碼後的字串不用區分大小寫並排除了容易混淆的字元,可以方便地由人類使用並由計算機處理。

符號 符號 符號
0 A 8 I 16 Q 24 Y
1 B 9 J 17 R 25 Z
2 C 10 K 18 S 26 2
3 D 11 L 19 T 27 3
4 E 12 M 20 U 28 4
5 F 13 N 21 V 29 5
6 G 14 O 22 W 30 6
7 H 15 P 23 X 31 7
填充 =

Base32將任意字串按照位元組進行切分,並將每個位元組對應的二進位制值(不足8位元高位補0)串聯起來,按照5位元一組進行切分,並將每組二進位制值轉換成十進位制來對應32個可列印字元中的一個。

由於資料的二進位制傳輸是按照8位元一組進行(即一個位元組),因此Base32按5位元切分的二進位制資料必須是40位元的倍數(5和8的最小公倍數)。例如輸入單位元組字元“%”,它對應的二進位制值是“100101”,前面補兩個0變成“00100101”(二進位制值不足8位元的都要在高位加0直到8位元),從左側開始按照5位元切分成兩組:“00100”和“101”,後一組不足5位元,則在末尾填充0直到5位元,變成“00100”和“10100”,這兩組二進位制數分別轉換成十進位制數,通過上述表格即可找到其對應的可列印字元“E”和“U”,但是這裡只用到兩組共10位元,還差30位元達到40位元,按照5位元一組還需6組,則在末尾填充6個“=”。填充“=”符號的作用是方便一些程式的標準化執行,大多數情況下不新增也無關緊要,而且,在URL中使用時必須去掉“=”符號。

與Base64相比,Base32具有許多優點:

  • 適合不區分大小寫的檔案系統,更利於人類口語交流或記憶。
  • 結果可以用作檔名,因為它不包含路徑分隔符 “/”等符號。
  • 排除了視覺上容易混淆的字元,因此可以準確的人工錄入。(例如,RFC4648符號集忽略了數字“1”、“8”和“0”,因為它們可能與字母“I”,“B”和“O”混淆)。
  • 排除填充符號“=”的結果可以包含在URL中,而不編碼任何字元。

Base32也比Base16有優勢:

  • Base32比Base16佔用的空間更小。(1000位元資料Base32需要200個字元,而Base16則為250個字元)

Base32的缺點:

  • Base32比Base64多佔用大約20%的空間。因為Base32使用8個ASCII字元去編碼原資料中的5個位元組資料,而Base64是使用4個ASCII字元去編碼原資料中的3個位元組資料。

3.

Base64編碼是使用64個可列印ASCII字元(A-Z、a-z、0-9、+、/)將任意位元組序列資料編碼成ASCII字串,另有“=”符號用作字尾用途。

Base64 索引表
數值 字元 數值 字元 數值 字元 數值 字元
0 A 16 Q 32 g 48 w
1 B 17 R 33 h 49 x
2 C 18 S 34 i 50 y
3 D 19 T 35 j 51 z
4 E 20 U 36 k 52 0
5 F 21 V 37 l 53 1
6 G 22 W 38 m 54 2
7 H 23 X 39 n 55 3
8 I 24 Y 40 o 56 4
9 J 25 Z 41 p 57 5
10 K 26 a 42 q 58 6
11 L 27 b 43 r 59 7
12 M 28 c 44 s 60 8
13 N 29 d 45 t 61 9
14 O 30 e 46 u 62 +
15 P 31 f 47 v 63 /

Base64將輸入字串按位元組切分,取得每個位元組對應的二進位制值(若不足8位元則高位補0),然後將這些二進位制數值串聯起來,再按照6位元一組進行切分(因為2^6=64),最後一組若不足6位元則末尾補0。將每組二進位制值轉換成十進位制,然後在上述表格中找到對應的符號並串聯起來就是Base64編碼結果。

由於二進位制資料是按照8位元一組進行傳輸,因此Base64按照6位元一組切分的二進位制資料必須是24位元的倍數(6和8的最小公倍數)。24位元就是3個位元組,若原位元組序列資料長度不是3的倍數時且剩下1個輸入資料,則在編碼結果後加2個=;若剩下2個輸入資料,則在編碼結果後加1個=。

完整的Base64定義可見RFC1421和RFC2045。因為Base64演算法是將3個位元組原資料編碼為4個位元組新資料,所以Base64編碼後的資料比原始資料略長,為原來的4/3。在電子郵件中,根據RFC822規定,每76個字元,還需要加上一個回車換行。可以估算編碼後資料長度大約為原長的135.1%。

Base64可用於任意資料的底層二進位制資料編碼,以應用於只能傳輸ASCII字元的場合。不過最常用於文字資料的處理傳輸,例如在MIME格式的電子郵件中,Base64可以用來編碼郵件內容,方便在不同語言計算機間傳輸而不亂碼,注意是傳輸而不是顯示,例如在西歐地區計算機上使用utf-8編碼即可正常顯示中文(安裝有對應字型檔),但是它未必能正常傳輸中文,這時轉換為Base64便無此顧慮。

1.easy!

可以看到密文中含有小寫字母,八成斷定是base64編碼。將其放入base線上編碼轉換中解碼得到flag。

2.KeyBoard

可以畫出每個字串在鍵盤上的軌跡。

nctf{areuhack}

3.base64全家桶

base線上編碼轉換按base64、base32、base16順序解碼即可。

nctf{base64_base32_and_base16}

4.n次base64

點選密文地址,看到密文很長。python解吧!!將密文複製下來,以base.txt命名,將base.txt文件和下面程式碼放到同一檔案下。

import base64

content = open("base.txt")
try:
    flag = content.read()
finally:
    content.close()
while 1:
    try:
        flag = base64.b64decode(flag)
    except:
        print(flag);
        break;

執行可得flag。

5.騷年來一發嗎

密文:iEJqak3pjIaZ0NzLiITLwWTqzqGAtW2oyOTq1A3pzqas

根據提示明文字串經過加密函式(先反轉明文字串得到$_o,再將$_o字串裡的每個字元(從第一個字元開始)加一,再base64編碼,再反轉再rot13,最後返回加密後的字串)後得到密文:iEJqak3pjIaZ0NzLiITLwWTqzqGAtW2oyOTq1A3pzqas

那就寫解密函式就行了。

<?php
$c='iEJqak3pjIaZ0NzLiITLwWTqzqGAtW2oyOTq1A3pzqas';
function decode($str)
{
	$re=base64_decode(strrev(str_rot13($str)));
	$m='';
	for($i=0;$i<strlen($re);$i++) 
		{
			$m.=chr(ord(substr($re,$i,1))-1);
		}
		return strrev($m);
}
echo decode($c);
?>

解密函式先將密文rot13,再反轉,再base64,得到字串$re,再將字串$re,從第一個字元開始取對應字元的ASCII 值,然後減一,再取ASCII 值對應的字元,將得到的字串接到$m,再將$m反轉即可。