さえぴ の めも

色んなアウトプットする。

google foo.bar終わりました

学校の先輩に招待いただいたfoo.bar、先日level5解き終わりました!ワーーーーーイ!

f:id:saemero:20180610181314p:plain
⬆︎頑張って逃したBunny


解き終えた後、status画面でメッセージももらった。
1人1人違うようで、どうやらユーザー名(googleアカウント名)がキーになっているっぽい。
暗号化されたメッセージをbase64でデコードし、その結果とユーザー名のXORとっていったら解読できた。
Python3でコード書きました。

import base64

txt = "NUIFEBEPBB0XCREKS0oTPAAXEVVAQUkHQV1cDgwTOwBRRUhMRgsXWlRVBggQaUlWQhcKBwEWWkIXS1dUaQwYBgAJBQcGQlQXR01TLwYeDBcaBAMBQEUXS1dUaRAYCR0PCgsACR0QTB8VLAcfEQFLQVRECUJRDQhTYkVRAx0DRk5eDhZHAgNVaRg="
key = "my username"

message = ""

m = list(base64.b64decode(txt).decode())

for i in range(len(m)):
    a = int((key[i % len(key)]).encode("utf-8").hex(),16)
    b = int(m[i].encode("utf-8").hex(),16)
    message += chr(a ^ b)
    
print(message)

いや〜本当に嬉しいです。
楽しかった!!

Python3でステガノグラフィーを作ってみた

CTFなどでよくでてくるステガノグラフィー。
データを別のデータに隠蔽する暗号的な技術のことです。


今回作るのは、RGB画像に白黒2値の画像を埋め込むタイプのステガノグラフィーです。CTFでよく画像が隠れているあれです。

RGBの各色情報(0〜255の8bit)に対して、どれか一色の下位nbitを操作することで、情報を埋め込みます。
基本的に#nnnnnnとある色情報のうち、下位bitに情報を隠すため、肉眼での確認はほぼ不可能です。

とてもわかりやすい解説:ステガノグラフィーの解析について

自分でも作ってみたいので、スクリプトを書きました。




例として、写真に2値画像を埋め込んでみたいと思います。

f:id:saemero:20180604113604p:plain

この前食べたつけ麺。メッッッッチャ美味しかった。


f:id:saemero:20180604113614p:plain

という思いを込めたFLAG画像を、つけ麺画像に埋め込みます。

つけ麺はRGBだとなんとなく赤っぽいので、Rの下位1bitを利用して埋め込むことにしました。

from PIL import Image

im = Image.open("tsukemen.png")
image = im.convert("RGB")
fl = Image.open("flag.png")
flag = fl.convert("RGB")


for x in range(600):
    for y in range(450):
        r,g,b = image.getpixel((x, y))
        r = r&0B11111110 | int(flag.getpixel((x, y))[0] > 128)<<1

        image.putpixel((x, y), (r,g,b))

image.save("steg.png")

できた画像です。

f:id:saemero:20180604115209p:plain

やっぱめっちゃ美味しそう。

見た目的には一切変わった感じがしませんが、うさみみハリケーン同梱の青い空を見上げればいつもそこに白い猫で確認してみます。


f:id:saemero:20180604115508p:plain

画像を参照して「ステガノグラフィー解析」を選択。
今回はR下位1bitを操作したので、「赤色 ビット1抽出」を選択します。

f:id:saemero:20180604115505p:plain

でてきた!
といった感じで、PILでちょちょっとやることでステガノグラフィー画像を作ることができました。

Python3でtracerouteとwhoisを一気にやるスクリプト作った

ネットワークの授業でひたすらtraceroute(winだとtracertらしい)をしました。楽しかったです。
さらに、そこで可視化されたIPアドレスwhoisドメイン/IPアドレス サーチ 【whois情報検索】)で検索して国や持ち主を調べるといったことをしました。


ネットワーク超初心者の私としては楽しかったのですが、いかんせんIPアドレスをコピペして検索して…とやるのがすんごく面倒くさい。
なのでネットワークの勉強も兼ねて、traceroute → whoisで検索して国・会社を表示までPython3で一気にできるようにしました。



環境

mac OS sierra 10.12.4



作りたいもの

コマンドラインから実行するPython3のスクリプト
・入力したアドレスまでtracerouteして、whoisで取得した国・会社名とともに表示する



traceroute

まずはPython3でtracerouteを実装してみる。
書いた:traceroute/traceroute.py at master · sae-py/traceroute · GitHub



具体的にいうと、dest_name,port,max_hopsを与えてtracerouteを行う関数です。
なんでもかんでも手動で指定すると面倒くさいので、あらかじめmain関数で

port = 33434
max_hops = 30

を宣言しておきます。
2つともUNIX系のUDPtracerouteのデフォルト値です。

Traceroute - Wikipediaによると、UDPtracerouteが使用するポート番号の範囲は

On Unix-like operating systems, traceroute sends, by default, a sequence of User Datagram Protocol (UDP) packets, with destination port numbers ranging from 33434 to 33534;

だそうなので、その辺空けておいてランダムに使ってもいいかもしれない。
dest_nameはinput()で取得します。



ipwhois

ipwhois · PyPI こちらを使って、IPアドレスの管理者情報を取得するコードを書きます。
書いた:traceroute/whois.py at master · sae-py/traceroute · GitHub


ipwhoisは

pip install ipwhois

で入れられますが、私の環境の場合これでインストールすると

AttributeError: 'IPWhois' object has no attribute 'lookup'

のエラーが出てしまったので

pip install ipwhois==0.10.3

でインストールし直しました。ピタッとエラーなくなりました。
参考:[SOLVED] Cannot use python IPWhois: IPWhois instance has no attribute &#39;lookup_rws&#39;

whoisの情報は辞書型で返ってきますが、

{'query': '24.24.24.24', 'nets': [{'cidr': '24.24.0.0/14, 24.28.0.0/15', 'name': 'ROAD-RUNNER-1', 'handle': 'NET-24-24-0-0-1', 'range': '24.24.0.0 - 24.29.255.255', 'description': 'Time Warner Cable Internet LLC', 'country': 'US', 'state': 'CO', 'city': 'Greenwood Village', 'address': '6399 S Fiddlers Green Circle', 'postal_code': '80111', 'abuse_emails': 'abuse@rr.com', 'tech_emails': 'ipaddressing@chartercom.com', 'misc_emails': None, 'created': '2000-06-08T00:00:00', 'updated': '2011-07-06T00:00:00'}], 'raw': None, 'referral': None, 'raw_referral': None, 'asn_registry': 'arin', 'asn': '11351', 'asn_cidr': '24.24.0.0/18', 'asn_country_code': 'US', 'asn_date': '2000-06-09'}

こんな感じで、返ってきた辞書型whoの中にさらに辞書型の要素['nets']が入っています。
なので、who['nets']をnetsに代入し、netsの要素['description']['country']を取り出しています。


合わせてみた

上記2つを合わせたスクリプトを書きます。
書いた:traceroute/trace_whois.py at master · sae-py/traceroute · GitHub


tracerouteは自分のローカル環境から任意のアドレスまでの道筋を追ってくれますが、whoisローカルアドレスを取得できないため、エラーとなります。

なので

from ipwhois.ipwhois import IPDefinedError

try:
	obj = IPWhois(curr_addr)
except IPDefinedError as e:
	print("local host")
else:
	who = obj.lookup()
	nets = who['nets']
	country = nets[0]['country']
	company = nets[0]['description']
	print("country:{0} company:{1}\n".format(country,company))

でエラーをキャッチするようにしました。

参考:IPDefinedError import is missing · Issue #9 · ChrisTruncer/Just-Metadata · GitHub

あとは素直にtracerouteのループの中にwhoisをぶち込めば完成です。わーい。



参考

PythonでUDPトレースルート(traceroute)〜ネットワーク経路調査 - ServersMan@VPS(CentOS)でお気楽サーバー運営 (^^♪ (忘れっぽいので個人メモ用)
TracerouteをPython3で実装
whoisの情報から必要なところだけを抜き出してくれるようにしてみた。 - KITA Eng.

Python3でスタック&キュー

タイトルママです。
アルゴリズムの勉強も兼ねて、10分くらいで書いてみました。


スタック

class Stack:
	def __init__(self):
		self.stack = [0,0,0,0,0]
		self.p = 0

	def push(self,obj):
		self.stack[self.p] = obj
		self.p += 1

	def pop(self):
		del self.stack[self.p-1]
		self.p -= 1

	def disp(self):
		print(self.stack)

if __name__ == "__main__":
	stack = Stack()
	data = [2,4,6,8,10]
	for i in range(len(data)):
		stack.push(data[i])
	stack.disp()
	for i in range(len(data)):
		stack.pop()
		stack.disp()

キュー

class Queue:
	def __init__(self):
		self.queue = [0,0,0,0,0]
		self.p = 0

	def enqueue(self,obj):
		self.queue[self.p] = obj
		self.p += 1

	def dequeue(self):
		del self.queue[0]
		self.p -= 1

	def disp(self):
		print(self.queue)

if __name__ == "__main__":
	queue = Queue()
	data = [2,4,6,8,10]
	for i in range(len(data)):
		queue.enqueue(data[i])
	queue.disp()
	for i in range(len(data)):
		queue.dequeue()
		queue.disp()

オーバーしちゃった時の処理などを入れていないので、まだ色々手直ししないといけないです。
githubGitHub - sae-py/stack_and_queue

Python3でハッシュ探索

前回の記事(Python3で構造体っぽいことをしてみる - さえぴ の めも)にて、Python3で構造体っぽいものを作り、さらにその要素をリニアサーチ&バイナリサーチで探索するという課題のコードを載せました。

今週の授業ではさらにハッシュ探索の実装が追加されたので、Python3でのハッシュ探索を書きました。というわけでこまめにアウトプットします(あんまりできてない)

ハッシュ探索とは

  • 配列の要素を一定の規則でハッシュ化し、そのハッシュ値を使って探索を行う。
  • ハッシュ値に従っての格納さえ済んでいれば、探索の計算量は常にO(1)

というウルトラスーパー早い探索アルゴリズムです。
ただ格納の際に時間がかかるので、探索したいデータが小さい場合はかえって効率が悪いこともあります。


簡単なコードを書くと、

import hashlib

# ハッシュ関数
def get_hash(n):
	hash = hashlib.md5(n.encode('utf-8')).hexdigest()
	hash = int(hash,16) % 61
	return hash

# ハッシュ探索
def hash_search(list,target):
	index = get_hash(target)
	if list[index] == "":
		print("見つかりませんでした")
	else:
		print("見つかりました")

# 探索したいリスト
ary = ["あ","い","う","え","お","か"]
# 格納先のリスト
hash_list = []
for i in range(61):
	hash_list.append("")

# ハッシュに基づいて格納
for i in range(len(ary)):
	index = get_hash(ary[i])
	hash_list[index] = ary[i]

# あを探す
hash_search(hash_list,"あ")
# きを探す
hash_search(hash_list,"き")

こんな感じになります。

探索したい配列aryの中身をハッシュ関数でハッシュ化し、格納先のリストの要素数素数、この場合は61)で割って格納します。
今回は簡単なハッシュかですが、衝突を考えなければいけないので実際は対策が必要です。

そして、ハッシュはユニークなものなので、格納先リストのハッシュ番目をのぞけば探したい数字があるかないかわかるという寸法です。


このハッシュ探索を前回のコード(空クラスを使用した構造体もどき)に盛り込んでみました。
github.com

Python3で構造体っぽいことをしてみる

授業で出た課題をこなすにあたって、構造体を利用できる言語を使うことになったのですが、どうしてもPythonで乗り切りたかったので調べたメモ。
テキストデータを読み込んで構造体に格納し、そのデータに対して探索をかけるという課題でした。


Pythonにはそのまま構造体というものがないので、データを統合する目的としての構造体を使用した場合、空クラスを使用するらしい。

テストの点数を取りまとめる場合の簡単な例。

class score():
	pass

suzuki = score()
suzuki.kokugo = 88
suzuki.rika = 67

honda = score()
honda.kokugo = 75
honda.rika = 72

テキストデータを読み込んでループの中で動的にデータを追加することもできます。便利!

読み込みたいデータ(番号、名前、都道府県が記載)

1,山田 一郎,北海道
2,山田 次郎,青森県
3,山田 三郎,秋田県
4,山田 四郎,岩手県
5,山田 五郎,宮城県


以上のデータを読み取り、それぞれno,name,addrに格納していくプログラムです。

# coding: utf-8

# 空クラス作成
class Hum():
	pass

def get_info(txt):
	man = []
	with open(txt, 'r') as f:
		line = f.readlines()
	for i in range(len(line)):
		man.append(Hum())
		info = line[i].split(',')
		man[i].no = int(info[0])
		man[i].name = info[1]
		man[i].addr = info[2]
	return man

def main():
	man = get_info("info.txt")
	print(man[1].name)

if __name__ == '__main__':
    main()

これで2番目の人の名前を表示するので、出力は「山田 次郎」です。
readlines()使ってるので都道府県名の最後に¥n入っちゃってるのでそこだけ直したい。


構造体のデータにバイナリサーチとか色々できるようにしたコード(そっくりそのまま課題の解答)はgithubにあげました
github.com

ksnctf C92 #E1 「Mysterious Light」

お久しぶりです。
イギリスでインターンの機会をいただき、先日無事日本に帰って来ましたのでまた更新を再開しようと思います。

今回は2017年夏に開催されていた ksnctf C92 のwrite-upです。

全ての設問に対して表・裏が用意されており、表面を全答すると裏面が現れるという仕組みです。


問題【表】

f:id:saemero:20180131111653p:plain

QRコードに関する問題です。


解答までの道

向き読み取りの部分が煙で隠されています。
自分で補修してあげます。

⬇︎こんな感じ⬇︎
f:id:saemero:20180131113154p:plain

読み取ったらflagゲット。


問題【裏】

f:id:saemero:20180131113328p:plain


解答までの道

隠されている部分は誤り訂正レベルやマスクなどのQRコードのフォーマット情報が書かれている部分です。
QRの仕様についてはこちらが詳しく、参考にしました。

肉眼でも読める!QRコード入門 | quizknock

あとはQRを復号します。
QR decoder」とかでググるstrong-qr-decoder という超強力そうなデコーダーが出てくるのでそちらを使います。

strong-qr-decoderはQRコードを.txtデータで読み込むため、まずは問題のQRコードをテキスト化。

from PIL import Image

img = Image.open('flag2.png')

qr = ""

for y in range(177):
    for x in range(177):
        r,g,b = img.getpixel((x*8+36,y*8+36))
        if r < 255/2:
            qr += "#"
        else:
            qr += " "
        
    qr += "\n"

f = open('flag.txt', 'w')
f.write(qr)
f.close()

これで問題のQRコードをテキストファイルとして出力できます。

これをパラメータを変えながらstrong-qr-decoderに与えることで、flag(1237文字!)が出て来ます。
成功したのは誤り訂正レベル2、マスクパターン3の場合でした。