# CS2022 補交 writeup
## hackmd url
https://hackmd.io/@Chtsai873/Hyiu52oKo
* Crypto
* [[HW] DH](#[HW]-DH)
* Reverse
* [[HW] dropper](#[HW]-dropper)
## [HW] DH
* 題目 Hint
:::success
**[HW] DH [200]**
nc edu-ctf.zoolab.org 10104
Something might be helpful
[Quadratic_residue](https://en.wikipedia.org/wiki/Quadratic_residue#Prime_modulus)
[is_square](https://doc.sagemath.org/html/en/reference/finite_rings/sage/rings/finite_rings/integer_mod.html#sage.rings.finite_rings.integer_mod.IntegerMod_abstract.is_square)
[sqrt](https://doc.sagemath.org/html/en/reference/finite_rings/sage/rings/finite_rings/integer_mod.html#sage.rings.finite_rings.integer_mod.IntegerMod_abstract.sqrt)
you can solve this challenge without the links above, but some of you might want to use these functions.
:::
* 題目程式碼
```python=
#! /usr/bin/python3
from Crypto.Util.number import bytes_to_long, getPrime
import random
from secret import FLAG
# nc edu-ctf.zoolab.org 10104
p = getPrime(1024)
assert bytes_to_long(FLAG) < p
print(p)
g = int(input().strip())
g %= p
if g == 1 or g == p - 1:
print("Bad :(")
exit(0)
a = random.randint(2, p - 2)
A = pow(g, a, p)
if A == 1 or A == p - 1:
print("Bad :(")
exit(0)
b = random.randint(2, p - 2)
c = pow(A, b, p) * bytes_to_long(FLAG) % p
print(c)
```
* 解題思路
1. 這題明顯是有關 Diffie_Hellman 的題目,但不同於先前的 Dlog 那題,這題的大質數 p ,是直接呼叫 getPrime(1024) 產出的,因此無法再使用先前的手法嘗試,接著繼續往下可以看到,雖然底數 g 是由我們自己輸入的,但題目有特別對可能產生的特例進行防堵,加上了 `g != 1 or g != p-1` 和 `A != 1 or A != p-1` 這兩個限制,加上這兩樣限制導致我們幾乎不太可能對 g 和 A 做手腳,剩下有辦法嘗試的點就只有 `B=pow(g, b, p)` 了。
2. 由於題目並沒有對 B 進行確認,所以我想說可以嘗試著讓`B == 1`,這樣做會導致 `c = pow(A, b, p) * bytes_to_long(FLAG) % p` 中的 `pow(A, b, p) = 1`,因為 pow(A, b, p) = A^b^ mod p = g^ab^ mod p = B^a^ mod p = 1。想著這樣在還原的時候可能可以避免大量的計算,但最後大失敗,不知道如何滿足。
3. 後來才有查到一些資訊,這種題型貌似是需要透過給定 g 來產生一個很小的 subgroup,因此解題前先限定 `p%3==1`,若沒有抽到我們想要的 p 則 exit(0) 重來。再來則是set `g = pow(3, (p - 1) // 3, p)`(前方的底數3似乎可以隨意給一個數?),這樣做則一定會符合`g != 1 or g != p-1`、但有機會剛好使`A == 1 or A == p-1`而失敗,因此需要多試幾次,總共會有兩種失敗的可能,一種是撞到`A != 1 or A != p-1`、另一種則是`p%3!=1`。
4. 最後則會產生 3個可能的模逆元,一一塞進去還原看看就可以找到對的值。
* 解題程式碼
```python=
from pwn import *
from Crypto.Util.number import long_to_bytes
if __name__=="__main__":
r = remote("edu-ctf.zoolab.org", 10104)
p = int(r.recvline().decode())
if(p%3 != 1):
print("Bad prime :(")
exit(0)
g = pow(2, (p-1)//3, p)
r.sendline(str(g).encode())
c = int(r.recvline().decode())
r.close()
for i in range(3):
flag = c * pow(g, -i, p) % p
print(long_to_bytes(flag))
# f = c % p
# print(long_to_bytes(flag))
```
* 執行結果

## [HW] dropper
* 解題思路
1. 解題首先使用 die 來查看檔案是否有被加殼過,發現似乎有被 UPX 給加殼過,查了一下發現 linux 本身就有指令可以用來解 UPX。



2. 然後使用 IDA 來查看程式碼,一點開就可以看到主程式,接下來可以看到很多重複做的事,不斷的給陣列賦值然後呼叫 function `sub140001030`,查看後發現 `sub140001030` 會將先前賦值的陣列進行 decode。


人工搬運還原

3. 實際執行的時候會失敗,用 IDA 動態分析可以看到程式甚至還沒進到 main function 就會發生 exception,在執行 _initterm_e 會報錯,貌似是給的 Last funtion pointer 有誤,但查了很久也不知道要怎麼更改,最後想到有可能是跟 packer 有關係。


4. 後來改成使用 x64dbg 來跑動態分析,跑的是沒有去殼的 dropper,發現跑到一個地方就停住了,下方有紀錄顯示已經載入了 cryptbase.dll,於是再回到 IDA 查看,發現停住的地方是因為被呼叫了一段時間很長的 sleep()。


而在 x64dbg 有功能可以跳過某段程式碼,所以我就試試讓他不執行 sleep syscall 直接 return,讓程式可以成功跑完。

5. 最後回頭來分析整理一下程式碼,大概的內容是會透過呼叫 api 來對 flag 進行加密的流程,結束後會再呼叫 RegCreateKeyA 儲存 key,名稱則是叫做 `CS_2022`,`win+R`打開 regedit 後就會看到剛剛成功執行的FLAG已經跑出來了。

* 執行結果
