TSCCTF write up (賽後解)

Mike Lv99

REV

目錄
  • Reverse
    • What_Happened
    • Chill Checker
    • Gateway to the Reverse
    • Meoware

What_Happened

雖然題目說不用用靜態分析直接用動態,但我還是稍微用了ida一下,以下是靜態完的結果

What_Happened 2

What_Happened 2

這裡是我覺得的重點,所以我接下來就直接去看了encdec兩個函式

Chill_Checker

先打開ida 做逆向分析,可知他會先輸入長度為8的Input ,再經過7次complex_function 加密,要等於”SGZIYIHW”(要顛倒,原因是此執行檔是little-endian 所以儲存順序會顛倒

Chill 3

以下可以有兩種方式逆向

靜態逆向

Chill 4

透過觀察main 可知輸入的Input 每個字元都會逐一經過complex_function加密,所以可以得到以下示意圖:

1
Input -> complex_function -> ”SGZIYIHW”

再觀察complex_function 可得到以下重點

alt text

綠色:Input 要在’A’(65) ~ ’Z’(89)之間

藍色:為加密演算法,所以可得以下公式

((a1 - 65 + 31 * a2) % 26 + 65) = [SGZIYIHW]
做逆向求 a1:
(a1 - 65 + 31 * a2) % 26 = [SGZIYIHW] - 65
a1 - 65 + 31 * a2 = [SGZIYIHW] - 65 + 26k
a1 = [SGZIYIHW] - 65 + 26
k + 65 - 31 * a2
a1 = [SGZIYIHW] + 26*k - 31 * a2

以他做一個exploit.py

1
2
3
4
5
6
7
8
9
10
Output = "SGZIYIHW"
Input = ""

def dec_func(a1 , a2):
return chr((ord(a1)-65-a2*31)%26+65)

for i in range(8):
Input += dec_func(Output[i] , (i+8))

print(Input)

即可得到真正要輸入的字串:

1
2
TSCCTF\REV> python exploit.py"
ENBFQVPZ

再重新啟動elf檔並輸入”ENBFQVPZ”即可得到flag

1
2
3
4
5
┌──(kali㉿kali)-[~/Downloads]
└─$ ./chill
Whisper your code: ENBFQVPZ
Man, you're really on fire!
Your flag is: TSC{t4k3_1t_3a$y}

動態逆向

ida 觀察main可知他會將原始字串加密後由strcmp去進行比較,所以只要隨便輸入東西在比較時把暫存器內的值進行更動即可

1
gef➤  disas main

alt text

紅色範圍:complex_function 加密,結束後到藍色strcmp做比較

藍色範圍:比較函式。對他做斷點,以便後續竄改加密結果

1
2
gef➤  b *0x000055555555544f
# 在0x000055555555544f <+187>: call 0x555555555070 <strcmp@plt>這行做斷點

並開始程式,輸入範圍在A~Z之間且為長度為8個字元即可

1
2
3
gef➤ r
Whisper your code:
gef➤ ABCDABCD

此時會看到strcmp@plt的參數會傳入的值,並對其進行修改

alt text

我們要改的值是$rdi的值 ( by calling convention, 呼叫慣例,修改完後繼續執行程式即可通過檢查並成功取得flag

1
2
3
gef➤ set {char[9]} 0x00007fffffffdc90 = "SGZIYIHW"
gef➤ c
Your flag is: TSC{t4k3_1t_3a$y}

Gateway_to_the_Reverse

方法一 ( gdb-gef

先用ida打開並觀察發現(看不懂s2 是單獨計算的,與輸入是多少無關,所以只要在strcmp 時,設個斷點,觀察s2即可看到輸入要等於什麼

1
2
3
4
gef➤ b strcmp@plt
gef➤ r
Enter the access key:
gef➤ ABCDABCD

alt text

即可得知flag

方法二 ( ltrace

alt text

因為它會把函式之間的關係都顯示得很清楚,自然也能看到傳入的參數為何

Meoware

經過觀察後重點在於它會有一段,所以只要rand() == 0 即可結束迴圈

alt text

alt text

1
2
3
4
5
6
v3 = time(0LL);
srand(v3);
while ( rand() )
{
show pic
}

再來結束迴圈後出現了std::operator<<<std::char_traits<char>>(&_bss_start, "flag is:"); ,所以很明顯我們要先結束迴圈並繼續執行到最後

所以到gef裡面進行動態分析:

1
2
3
4
5
6
7
8
gef➤  starti
gef➤ i func
...
main
...
gef➤ b main
gef➤ c
gef➤ disas [main]

alt text

alt text

由此可知他迴圈是先跳到<main+593> 接著進行比較,test eax,eax ,如果不為 0,則回到迴圈裡,所以在此設斷點,再把eax設為0即可跳出迴圈並執行程式。

1
2
3
4
5
gef➤ b *main+598
gef➤ c # 這時看到 eax 並不等於 0
gef➤ set $eax = 0 # 即可使迴圈不符合條件
gef➤ c
flag is:TSC{Bobo_milk-tea_black-carbon}
  • Title: TSCCTF write up (賽後解)
  • Author: Mike
  • Created at : 2025-01-22 17:40:45
  • Updated at : 2025-04-30 12:18:13
  • Link: https://happymike0103.github.io/2025/01/22/2025-1-22-TSCCTF/
  • License: This work is licensed under CC BY-NC-SA 4.0.