ハッカーへのマイルストーン

ハッカーになるために、日々学んだことを記し、マイルストーンとしていきたい。

サイバーセキュリティプログラミング Day 1

はじめに

早速「サイバーセキュリティプログラミング」を読み始めてみた! 基本序文から読むスタイルなので読んでみると、なんとハッカーと同じことができるという。これはと思い、まず第1章に目を通す。

python 自体は触ったことはあったので環境設定など難なくクリア、この調子で第2章からの本格的ハッキングへ入っていこう。

と思った矢先。2章は半端なく難しかった。 2章の壁は厚く、コードを読んでも全くわからない。調べても何を調べればいいのか。。。 とにかく途中で投げ出してはいけない、と思いマイルストーン、備忘録代わりにブログを書くことにした。

*ブログの書き方など気に留めていないので、読みにくさ満点になってますがご了承ください。

TCP/IPについて(知ってる人は読み飛ばしてください。かなり初歩の部分です。)

2章は「通信プログラムの作成・基礎」である。つまり通信のことがわかっていないとコードを読んでも解説を見ても何をしているのか、何を言っているのか全く頭に入ってこない。 なので、今日は通信について「マスタリングTCP/IP 入門編」を使いながら勉強する。

インターネットについて学ぶ際に100%毎回最初に出てくるのはプロトコルの話。今まで何回も見たことがあったがなかなか覚えきれなかった。 そもそもプロトコルとは、コンピュータとコンピュータがネットワークを利用して通信をするために決められた「約束ごと」であり、実際の通信プロトコルではヘッダに書き込まれる情報や、その情報をどのように処理するかを定めている。

もちろんいろんな約束ごとがあっては困るので、プロトコルは標準化され、OSIプロトコルを作った。でも、OSIはあまり普及されていないらしく、TCP/IPがよく使われているらしい。インターネット上では標準になっているので、こういうのをデファクトスタンダードっていうらしい。 まあこれによってOSとハードウェアの違いを意識せずに通信できるようになったって。

で、まあよくみるのがプロトコルの階層化。 OSI参照モデルであるように、1-7の層(レイヤ)があって物理層データリンク層ネットワーク層トランスポート層、セッション層、プレゼンテーション層、アプリケーション層に分かれている。 もちろん他の層もめっちゃ大切で後々勉強するけど、今回はTCPが使われるトランスポート層ネットワーク層に注目する。

トランスポート層は、宛先のアプリケーションにデータを確実に届ける役目。通信を行う両端のノードだけで処理され、ルーターを介さない。 後でも出てくるけど、コネクションの確立をするときはここ。当然確立があれば切断も。微妙に確立できてなかった場合は聞き返す(再送処理)も行う。

ネットワーク層は、宛先までデータを届ける役割を持つ。ルーターにも送るし、ルーターから先のネットワーク上のノードにも送る。そのためのアドレス体系決めや、どの経路を使うかなどの経路選択の役割を持つ。 これはネットワークがトランスポート層で接続されてるので、送信ホストから受信ホストまでデータを配達する役割。

ここまででなんとなく、TCPUDPの下準備完了かな?

通信方式の種類があって、本にも出てくるけど、TCPはコネクション型。UDPコネクションレス型で、TCPは先にデータが通る道を準備する(送信ホストと受信ホストの間で回線を接続)。通信の前後でコネクションの確立と切断の処理を行う。 相手の通信可否を先に判断するので、データを無駄に送らなくてもよいこと。 UDPはコネクションの確立や切断処理がない(トランスポート層は無視ってこと?)。つまり送信したければいつでもデータを送信できる。けど、受け取るほうはいつデータが来るかわからないので常に確認しなければいけない。通信速度はその分速いらしいけど、正確さはなさそう。

通信方法ではパケット交換が行われていて、パケット交換機(ルーター)によって通信回線が結ばれる。 コンピュータから送られてきたパケットを一旦ルーターのバッファに格納して、そっから転送する。 ここで、本によく出てくるキューがある。ルーターに入ってきたパケットが順番に待ち行列(キュー)を作りながらバッファに格納される。そして、先に入ってきたパケットから順番に転送される。FIFO(First In First Out)ってやつ。

パケットが大量に流れてくると、バッファオーバーフローを起こしてエラーしたり、悪意あるパケット送ったりと、いろいろできるらしい(そんな感じの攻撃があった気がする)。

ーーー小休憩ーーー

TCP/IPの基礎知識

こっからはTCP/IPの基礎知識。(今までは基礎でもなかった)

TCP/IPのことは全部仕様書RFC(Request For Comments)に書いてあるそうなのでまあいずれ読もう。

IPの仕様を決めているのはRFC791、TCPの仕様はRFC793だそうです。ありがたいね。 ここにある。 http://www.rfc-editor.org/rfc/

RFCに1回なると内容を改定しちゃいけないそう。憲法よりも厳しい。。。 新しく追加することのみオッケーってことですね。 あーでも、仕様を変更すれば古いRFCは無効になるので、実質改定みたいなもんか。。。

主要プロトコルについてはこれからも触れていくのでSTD、RFC等々でてくるよ。

インターネットの基礎知識

いろんなネットワークあるけどそれらすべて結んでインターネットっていうらしい。

それぞれのネットワークは、バックボーンと呼ばれる基幹ネットワークと、スタブと呼ばれる末端のネットワーク部分から構成される。 ネットワークとネットワークはNOC(Network Operation Center)で接続される。 で、異なる運用者や運用方針、利用方針を持つネットワークはIX(Internet Exchange)と呼ばれるポイントで接続されている。

上でOSI参照モデルが出てきたが、今回はTCP/IPの階層モデルについて触れてみたいと思う。 TCP/IPは5層でできており、アプリケーション層、トランスポート層、インターネットそう、ネットワークインタフェース層、ハードウェアである。 先ほど紹介したトランスポート層ネットワーク層に該当するのは、トランスポート層、インターネットそうである。

ネットワーク層では、IPプロトコルが使われて、IPアドレスをもとにパケットを転送する。 ルーターにはインターネット層を利用してパケットを転送する機能を実装しなければいけなくて、インターネットに接続されるすべてのホストやルーターは、必ずIPの機能を実装しなければならない。 ただ、ブリッジやリピーター、ハブはいいらしい(それぞれが何を指すのかはわからない)

以下新規単語 IP:Internet Protocol ネットワークをまたいでパケットを配送し、インターネット全体にパケットを送り届けるためのプロトコル それぞれのホストを識別するために、IPアドレスと呼ばれる識別子を使う。 パケットの再送は行わない ICMP:Internet Control Message Protocol IPパケットの配送中に何らかの異常が発生してパケットを転送できなくなった場合に、パケットの送信元に異常を知らせるために使われるプロトコル。ネットワークの診断などにも利用できる。 てことは、ペネトレーションテストで使うんかな? ARP:Address Resolution Protocol パケットの送り先の物理的なアドレス(MACアドレス)をIPアドレスから取得するプロトコル

トランスポート層の役割は、アプリケーションプログラム間の通信を実現すること。ポート番号でアプリケーションプログラムの識別をしている。

新規単語 TCP:Transmission Control Protocol 両端のホスト間でデータの到達性を保証。まあなんかほかにも素晴らしい特徴がいっぱいあってとりあえず信頼できるプロトコル。ただ、コネクションの確立/切断をするだけで制御のためのパケットを約7回もやり取りするので、転送するデータの総量が少ない場合には無駄が多くなる。ビデオ会議の音声・映像データなどの一定間隔で決められた寮のデータを転送する通信には向いてない。 UDP:User Datagram Protocol 全く信頼性のないやつ。だけど、TCPの欠点であるパケット数が少ない通信や、ブロードキャストやマルチキャストの通信、ビデオや音声などのマルチメディア通信に向いている。 通信例(一部) トランスポート層ではTCPヘッダを付加、ネットワーク層ではIPヘッダを付加(逆は解析)

TCPモジュールの処理 アプリケーションから渡されたデータの前にTCPのヘッダがつけられる。TCPのヘッダには、送信ホストと受信ホストのアプリケーションを識別するためのポート番号、そのパケットのデータが何バイト目のデータなのかを示すシーケンス番号、データが壊れていないことを保証するためのチェックサム(データのやり取りが正しく行われているかどうかを検査する方法)などが含まれる。

IPモジュールの処理 TCPヘッダ+データの前にIPヘッダを付ける。IPヘッダには、宛先のIPアドレスや送信元のIPアドレス、IPヘッダの次に続くデータがTCPなのかUDPなのかといった情報が含まれる。 IPパケットが完成したら、経路制御表(ルーティングテーブル)を参照して、IPパケットを次に受け渡すルーターやホストを決定する。

受け取るほうはちょっと違うけど、基本それぞれを解析して上のレイヤーへ渡す感じ。

マスタリングTCP/IPはここからそれぞれの層の説明に入ってくけど、今回は一気に飛ばしてメインテーマのTCPUDP

TCPUDP

おさらい

それぞれトランスポートプロトコル TCPは信頼性のある通信を提供し、UDPは同時通信や、細かい制御をアプリケーションに任せたほうがよい通信に用いられる。TCPはストリーム型の(切れ目のない)データ構造。

IPヘッダにはプロトコルフィールドが定義されており、どのトランスポートプロトコルにデータを渡すかが番号で示されている。(説明省略) TCPUDPも自分が運んでいるデータを次にどのアプリケーションに渡せばよいかを識別するための番号が定義されている。

本題

TCP/IPのアプリケーションプロトコルの多くは、一般にクライアント/サーバーモデルと呼ばれる形式で作られている。クライアントはサーバーに対してサービスの要求を行い、サーバーはクライアントからの要求を処理してサービスを提供する。サーバープログラムが先に起動されてクライアントプログラムの要求を待つ必要がある(感覚的にわかると思う)。 TCPヘッダには送信元ポート番号、宛先ポート番号、接続要求フラグが含まれていて、宛先ポート番号により、使うサーバーの種類?(サービス)が違う。TCP接続要求パケット(SYNセグメント)を作って送信開始。SYNセグメントはwiresharkで見たことあるし、今思えばTCPだった気がする。

これらのサーバープログラムはデーモンと呼ばれ、HTTPのサーバープログラムはhttpd(HTTPデーモン)、sshのサーバーはsshdSSHデーモン)と呼ばれる。また、デーモンを動かすのにも、代表としてクライアントからの要求を待つ、inetd(インターネットデーモン)というスーパーデーモンがいる。(xinetdもある) なんかおもしろいな。

スーパーデーモンはサービスの要求を受けると分身(fork)して、sshdなどのデーモンに変身(exec)する。

そろそろ飽きてきたのでコード

コード書いて解説しつつ学んでくスタイルに急遽変更

クライアント

tcp_client.py

# -*- config: utf-8 -*-

import socket

#ホストを今回はグーグルとする
target_host = "www.google.com"
#ポート番号は80なのでhttpd使用
target_port = 80

#(後述)
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#ここで、ホスト名、ポート名を確認して接続を開始
client.connect((target_host, target_port))
#googleのHTTPサーバにGETリクエストを送る
client.send("GET / HTTP/1.1\r\nHost: google.com\r\n\r\n")
#データの受信 ソケットからメッセージを受け取るのに使用 4096は一度に受信するデータの最大量
response = client.recv(4096)

print reponse

後述の部分 AF_INET:アドレス (およびプロトコル) ファミリーを示す定数で、 socket() の 最初の引数に指定することができる。IPv4のアドレスやホスト名を使用するための設定。 SOCK_STREAM:ソケットタイプを示す定数で、 socket() の2番目の引数に指定することができる。TCPを用いるための設定。

ソケットドメインはほかにもいっぱいあって予想やけど、これって他のドメイン指定すれば例えばアマチュア無線と通信できるってことなんやろうなー。ここが詳しいかも。とにかく今回はIPを使用するドメインを指定。

http://d.hatena.ne.jp/miyako_hechima/20091020/p4

ここにきて気づいたけどドキュメントめっちゃ参考になる。(人としてスタートラインにも立ててない悔しさ)

https://docs.python.jp/3/library/socket.html

流れとしては、ソケットオブジェクトの作成(ここでTCPヘッダの作成)→サーバーへ接続→データを送信→データの受信でデータを画面に表示。なんとなくTCP/IPモデルっぽい!

次はUDPクライアントのコードだ。 TCPと正反対のような通信を行うが、コードはどう変わるのだろうか。

udp_client.py

#-*- config: utf-8 -*-

import socket

target_host = "127.0.0.1"
target_port = 80

#socketオブジェクトの作成
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

#データの送信
client.sendto("AAABBBCCC", (target_host, target_port))

#データの受信
data, addr = client.recvfrom(4096)

print(data)

TCPクライアントのコードを比べてみてわかると思うが、ほぼ一緒。 でもちょっと違うのが、SOCK_DGRAM。これはUDPを使用することを宣言。 あとはsendto。これはソケットにデータを送信する。このメソッドでは接続先を address で指定するので、接続済みではいけないそう。でもUDPってコネクションレス型なので接続済みかっていうと微妙?? まあ接続済みなんでしょう。

最後にUDPは戻り値としてデータに加え、接続先のホストアドレスとポート番号が返ってきている。結果はタプル(bytes, address)で返ってくる。bytesは受信データのbytesオブジェクト。addressは送信元アドレス

終了

今日は寝るのでここまで。明日はTCP,UDPサーバーの実装からやっていきたいと思います。(実はもう明日) 微妙なとこで切り上げとはなりましたが、まあ基礎知識に時間割いたのでよしとしよう。圧倒的に勉強時間少ないけど。。。

以上。