kasayanus diary

後で思い出したいことを書く

いかに「マリオストーリー」が"神ゲー"であるかについて

最近ネット配信にて久しぶりに「マリオストーリー」にふれる機会があり、小学生のときこのゲームをやっていたことを思い出し、懐かしくなった。

それと同時に、いかにこのゲームが神ゲーなのかについて語りたくなったので記事にしたいと思う。

 

1. 概説

まず「マリオストーリー」とはニンテンドー64で2000年8月11日発売されたアクションRPGである。

f:id:kasayanus:20181118011317j:plain

バトルは、ターン制で味方側と敵側の行動を交互に繰り返すシンプルなコマンド戦闘だ。FFやドラクエとほとんど同じ形式である。

 

ストーリーは、マリオシリーズ定番の"いつもどおり"ピーチ姫がクッパによってさらわれてしまい、マリオがクッパ城に乗り込んでピーチ姫を救い出す、というものだ。

 

この神ゲーが今までのRPGゲームの中でも革新的である理由について以下で大きく2つの焦点に絞って紹介したいと思う。

 

2. 物語はラスボス「クッパ」にボコボコにされるところから始まる

RPGゲームといえば戦闘である。多くのゲームでは戦闘システムのチュートリアルとして弱い敵をはじめに用意する。例えば、ドラクエなら最初の戦闘はスライムだし、FFでも弱い敵がはじめに出てきて、そこでプレイヤーは基本的な戦い方を学ぶ。

しかしマリオストーリーは違う。

はじめて戦う相手が大魔王クッパなのだ。このときマリオ側には戦闘コマンドの選択肢は一つしかなく、プレイヤーはAボタンを押し続ける以外選択肢がない。本来ラスボスであるクッパの攻撃に耐えきれるわけもなく、圧倒的な絶望感とともにマリオは敗北してしまう。いわゆる負けイベントである。

f:id:kasayanus:20181118011706p:plain

↓ マリオがクッパにボコボコにされるシーン

f:id:kasayanus:20181118011731j:plain

そしてマリオは無残に天空のクッパ城から放り出されてしまうのである。

 

マリオストーリーの物語はここから始まる。”

 

クッパ城から投げ捨てられるマリオ

f:id:kasayanus:20181118035517p:plain

f:id:kasayanus:20181118035538p:plain

 

この演出がとても新鮮で、物語の最後のラスボス戦においてより深みを出していると思う。

最終的にマリオは冒険の中で成長し、クッパにリベンジを果たすのだが、はじめにクッパにボコボコにされることで、昔クッパに手も足も出なかったマリオがどれだけ強くなったのかということをプレイヤーに印象付けられるのである。

多くのRPGゲームのラスボス戦では、悪の元凶を倒し、世界に平和が戻ってハッピーエンド、という流れが定番だが、マリオストーリーはさらにそれに加えて、冒険の中でどれだけマリオとプレイヤーが成長してきたのかということを2度のクッパ戦の手応えの違いを通して、実感することができるのだ。

 

3. 最終ダンジョン「クッパ城」は"世界遺産"

2つ目の神ゲーたる所以について話したい。これはどういうことだ、と思うかも知れない。話は脱線するが、なぜ世界遺産を生で見ると感動するのかを考えてほしい。その理由は、その世界遺産のことを"知っているからである"。例えばエッフェル塔はテレビや本などで何度も見かけたことがあるしその名前も生きているうちに何度も聞くだろう。だからこそ、その既知感がエッフェル塔に行ったときの感動に結びつくのである。

話は脱線したが、それと同じ理屈がマリオストーリーのラストダンジョン「クッパ城」についても言えるのである。つまり、ゲームの"ある演出"によってクッパ城に乗り込んだとき、まるで世界遺産に訪れたかのような感動を呼び起こす効果を引き出しているのである。

 

その演出とは、ピーチ視点である。

 

このゲームは基本的にはプレイヤーはマリオを操作する。しかし、一つのダンジョンをクリアするという物語の節目ごとに、「その頃ピーチは‥」という演出とともに、同じ時間軸のクッパ城で監禁されているピーチ視点に切り替わり、ピーチ姫を操作してクッパ城からの脱出を試みるのである。(当然、脱出することはできない。)

このピーチ視点は短く、戦闘もないし、アクションもない。回収するフラグも少ないとてもシンプルなものだ。

f:id:kasayanus:20181118012109j:plain

f:id:kasayanus:20181118012125j:plain

しかし、このクッパ城でのピーチ視点をゲームの節目節目に取り入れることで、プレイヤーはラストダンジョン「クッパ城」を文字通り"知る"ことになる。

これは多くのRPGゲームとの相違点だろう。多くのRPGゲームのラストダンジョンはプレイヤーにとってはじめて訪れる場所になることが多いと思う。だからこそ、プレイヤーに未知の場所として衝撃を与えることができるだろう。しかし、あえてマリオストーリーではラストダンジョンを何度もピーチ視点によってプレイヤーに見せることで、マリオがクッパ城に訪れたときの感動を何倍にも膨らませているのである。

つまり、ピーチ視点によってクッパ城を見知った世界遺産のように演出することによって、マリオで訪れたときの高揚感をより大きなものにするのである。

 

4. まとめ

ということで、マリオストーリーが以下に神ゲーであるかについて語ってきたわけであるが、上記の2つの点で似たゲームがもう一つある。FFXである。やったことがある人ならわかると思うが、このゲームでもまずラスボス「シン」を相手にプレイヤーは絶望感を味わわされる。さらに物語上重要な場所であるザナルカンドは物語の中で何度も登場させることで"世界遺産化"している。このような演出もFFX神ゲーと言われる理由の一つだと思う。

話は脱線したが、マリオシリーズでは、RPGで一番秘密にしておきたいラスボスという最重要ポジションがクッパだということがプレイヤーにすでに知られているという大きなハンディキャップを背負っている。にもかかわらず、これだけ演出の力で面白いゲームにできるというこのゲームの奥深さに10年以上たってはじめて気付かされたのだった。

 

 

おわり

 

大学ポータルサイトに自動ログインするスクリプト作ってみた【Python】

大学の成績管理や講義の履修申告をするためには毎回パスワードや学生証のマトリックスコードを打ち込んでログインしなければいけません。

これがかなりめんどくさかったので今回、この認証を自動化するPythonスクリプトを作りました。

もちろんポータルサイトは大学ごとに異なるので、他の大学のポータルサイトでこのスクリプトを使うことはできませんが、アイディア自体は難しくないので、自分の大学用の自動ログインスクリプトも簡単に作れると思います。

今回は自分の大学のポータル自動ログインスクリプトを紹介します。



1. 大学ポータルサイトの認証の仕組み
自分の大学のポータルサイトへのログインの仕組みについて簡単に説明します。

まず、ポータルサイトのURLを開いたら同意(マトリクス/OTP認証)をクリックします。

f:id:kasayanus:20181027113214p:plain


次の画面で学籍番号とパスワードを入力して"OK"をクリックします

f:id:kasayanus:20181027113320p:plain


最後に学生証の裏にかかれているマトリックスコードからサイトで指定された要素を3つ入力して"OK"を押したら認証完了です

f:id:kasayanus:20181027120627p:plain




2. 自動ログインスクリプトの仕組み

使うのはseleniumというライブラリです。これは、ブラウザをプログラムで操作するための機能がまとめられたものです。

(seleniumは使いこなせればブラウザでの操作はすべて自動化することができるので夢が広がります。)

1. seleniumの関数を使ってブラウザオブジェクトを生成する。

2. ブラウザオブジェクトにサイトのURLを入力する。

3. サイトのソースコードを解析してパスワード入力部分やマトリックス認証で必要な文字(上の画像のA4,C7,D1)を含むDOM要素をCSSセレクターで見つける.

4. ブラウザオブジェクトにパスワードやマトリックスの要素を指定したDOM要素に入力するように指示したあと、"OK"ボタンをクリックさせる。

以下は実際のコードになります。


from selenium import webdriver
from selenium.webdriver.firefox.options import Options

USER="学籍番号"
PASS="パスワード"

matrix={'A':{},'B':{},'C':{},'D':{},'E':{},'F':{},'G':{},'H':{},'I':{},'J':{}}
'''
マトリックスコードの各要素はここで具体的に入力する
'''

def send_matrix_key(i):
	text=browser.find_element_by_css_selector("body > center:nth-child(5) > form > table > tbody > tr > td > table > tbody > tr:nth-child("+i+") > th:nth-child(1)").text
	key_alphabet=text[1]
	key_number=text[3]
	e=browser.find_element_by_css_selector("body > center:nth-child(5) > form > table > tbody > tr > td > table > tbody > tr:nth-child("+i+") > td > div > div > input")
	e.send_keys(matrix[key_alphabet][int(key_number)-1])


browser=webdriver.Chrome()#ブラウザオブジェクトを生成


url_login="https://portal.titech.ac.jp/"
browser.get(url_login)

e=browser.find_element_by_css_selector("input[value='同意(マトリクス/OTP認証)']")
e.click()

e=browser.find_element_by_css_selector("input[name='usr_name']")
e.send_keys(USER)

e=browser.find_element_by_css_selector("input[name='usr_password']")
e.send_keys(PASS)

e=browser.find_element_by_css_selector("input[name='OK']")
e.click()

#マトリックス認証を行う
send_matrix_key("5")
send_matrix_key("6")
send_matrix_key("7")

e=browser.find_element_by_css_selector("input[name='OK']")
e.click()

情報処理安全確保支援士試験受けてきました。

こんにちはまさです!

先日21日にIPAの情報処理安全確保支援士の資格試験を八王子の中央大学多摩キャンパスで受験してきました。

今回は受けてきた感想をまとめようと思います。

 

0. 試験概要

情報処理安全確保支援士試験(SC)は以下の4つの区分の試験で全て60%以上の点数がとれると合格になります。

午前Ⅰ   50分 (高度共通試験)4択マーク式全30問←範囲は応用情報と同じ

午前Ⅱ   40分 4択マーク式25問←セキュリティ分野から出題される

午後Ⅰ   90分  論述試験←大問3つから2つ選んで解答

午後Ⅱ  120分  論述試験←大問2つから1つ選んで解答

 

 

1. 受験しようと思った動機

 

IPA情報処理試験は一年に春季と秋季の二回あるのですが、春季に応用情報試験(AP)を受けた友達がいたことが動機です。

当初は友達と同じAPを受けるつもりでしたが、「どうせならAPとは別の試験を受けたい」と思いたち、高度試験の中で最も興味があったセキュリティに関する本試験を受けることにしました。

 

 

2. 受験に向けての勉強の流れ

 

6月に秋季の試験を受けることを決めたのですが、当初はAPを受けるつもりだったのでAPの合格教本を買って勉強していました。

(TAC出版 ニューベックテキスト)

f:id:kasayanus:20181023204800j:plain

 

しかし、7月に気が変わり、安全確保支援士(SC)の勉強をはじめました。

主に下の本を買って、通学中の電車の中や家でとにかく読むという感じでした。

色ペンで線を引いたりはせず、"読み物"として楽しむ感覚で勉強しました。

(技術評論社出版 情報処理安全確保支援士 合格教本)

f:id:kasayanus:20181023205415j:plain

 

順調に勉強はしていたのですが、9月中は勉強の調子が出ず一度も教本を読むことなく、ブランクとなってしまいました。

 

実際に問題演習や過去問に取り組んだのは10月になってからでした。

それまで一度も午後試験(論述問題)について演習していなかったので問題演習の本を買って勉強しました。

これについても演習問題をペンを使って"解く"というより、解説や問題を"読む"というふうにしました。

これは紙とペンを使って午後問題を解こうとしても経験値が足りないため、全く解けずに自身を失い勉強のモチベが下がると思ったからです。

なので、あくまで午後問題の演習も"読み物"として電車の中や家でひたすら読み解くということに徹しました。

 

(TAC出版情報処理安全確保支援士合格トレーニング)

f:id:kasayanus:20181023213930j:plain

 

(TAC出版共通午前ⅠALL IN ONE)

f:id:kasayanus:20181023213956j:plain

午前試験(4択マーク試験)はほとんど過去問から出題されるので(実際8割近く過去問のまんま出題されたと思う)、

最後に前日の土曜日に午前試験の過去問を解きまくりました。

 

 

3.  振り返ってみて

 

IPA情報処理試験は2年以上前から受けたいと考えていましたが、なかなか行動に移せず、今回はじめて受けることになりました。

自分の場合は、本試験について「就職に有利だから取りたい!」というような気張った気持ちはなく、勉強についても興味のある内容だったため半分趣味のような感覚で楽しんで進めることができました。

セキュリティに関してはほぼ知識0からのスタートでしたが、楽しんで勉強できたからこそ、今回勉強した内容は当分忘れることのない長期記憶になったと思います。

 

特に午後問題のシナリオ問題は読んでいても非常に興味深い内容なので、ぜひ少しでもセキュリティに興味がある方はぜひ過去問などを読んでみるとおもしろいと思います! 

↓平成30年秋季午後Ⅰ過去問(IPAより)

https://www.jitec.ipa.go.jp/1_04hanni_sukiru/mondai_kaitou_2018h30_2/2018h30a_sc_pm1_qs.pdf

 

【C言語】ARPキャッシュポイズニングを実装する

こんにちは、まさです!

前回までで、実際にC言語のpcapライブラリを使って生のパケットを送信する方法について紹介しました。
生のパケットは、unsigned char型の配列で表されており、パケットの送信先などの情報もOSI参照モデルで決まった書式でパケットに書き込まなければいけません。


今回は実際に下の画像のような偽のARPパケットを生成する方法を紹介します。
つまり、IPアドレス192.168.0.1、MACアドレス11:22:33:44:55:66のPCに対して、自分がIPアドレス192.168.0.2であると”偽った”ARPパケットを生成します。

f:id:kasayanus:20180724213021p:plain

まず最初に言っておきますが、ARPパケットは必ず42バイトのデータにすることが決まっています。
なので、送信するパケットを表すunsigned char配列の要素数は42になります。
以下では具体的に、このこの配列の要素にはどのようなデータが入るのか説明していきます。

次の画像を見てください
f:id:kasayanus:20180802174845j:plain

パケットは必ずこのような階層構造になっており、
今回送りたいARPパケットは第三層ネットワーク層に位置していることがわかります。

つまり今回は
①第二層データリンク層のイーサヘッダ
②第三層ネットワーク層ARPヘッダ

この2つを配列のデータとして記述することになります。

①イーサヘッダ
f:id:kasayanus:20180802175703p:plain
第二層で使うイーサネットのヘッダはこのような14バイトのデータの並びになっています。

1〜6バイトまで→宛先のMACアドレス(今回の場合11:22:33:44:55:66)
7〜12バイトまで→送信元のMACアドレス(今回の場合12:34:56:78:9a:bc)
13〜14バイトまで→パケットのデータのタイプ(今回はARPのタイプを表す8,6の配列)


ARPヘッダ
f:id:kasayanus:20180802172945g:plain
データリンク層のデータが確定したので次はARPヘッダを続いて書き込んでいきます。ARPヘッダは28バイトのデータの並びになっています。

1〜2バイト→ハードウェア識別番号(今回は0,1の配列)
3〜4バイト→プロトコルのタイプ番号(今回は8,0の配列)
5バイト→ハードウェアのサイズ番号(今回は6)
6バイト→プロトコルのサイズ番号(今回は4)
7〜8バイト→オプコード(今回は0,2の配列)
9〜14バイト→ARPリプライの送信元のMACアドレス(今回は12:34:56:78:9a:bc)
15〜18バイト→ARPリプライの送信元のIPアドレス
(今回は192.168.0.2を偽る)→ココ重要!

19〜24バイト→ARPリプライの宛先MACアドレス(今回は11:22:33:44:55:66)
25〜28バイト→ARPリプライの宛先IPアドレス(今回は192.168.0.1)

以上のことをまとめると、今回送るパケットの配列の中身は

unsigned char packet[42]={
    11,22,33,44,55,66,12,34,56,78,0x9a,0xbc,8,6,
    0,1,8,0,6,4,0,2,12,34,56,78,0x9a,0xbc,192,168,0,2,
    11,22,33,44,55,66,192,168,0,1
};

この配列を前回紹介したsend_packet関数で送信すればARPキャッシュポイズニングに成功するわけです。

これで具体的な偽のパケットの作り方の紹介はおしまいですが、実際には今回生成したイーサネットヘッダ、ARPヘッダは構造体として定義したほうが後々便利でしょう。例えば次のような構造体を定義しておきます。

#define ETHER_ADDR_LEN 6
#define ETHER_HDR_LEN 14

struct ether_hdr{
	unsigned char ether_dest_addr[ETHER_ADDR_LEN];
	unsigned char ether_src_addr[ETHER_ADDR_LEN];
	unsigned short ether_type;
};

struct arp_hdr{
	unsigned short hardware_type;
	unsigned short protocol_type;
	unsigned char hardware_size;
	unsigned char protocol_size;
	unsigned short opcode;
	unsigned char sender_mac[6];
	unsigned char sender_ip[4];
	unsigned char target_mac[6];
	unsigned char target_ip[4];
};

またヘッダの各部分の意味については今回省略しましたが次のサイトに詳細が載っていますので参考にしてください。
www.atmarkit.co.jp

C言語で"生"のパケットを送信する!その2【ARPキャッシュポイズニング】

こんにちは!まさです。

前回ARPキャッシュポイズニングについて大まかに説明しました。

f:id:kasayanus:20180724213214p:plain

その中で、この攻撃を成立させるためにはニセのARPリプライを送る必要があることを述べました。

今回は具体的なARPパケットの作り方と送信のプログラムについて説明します。

今回はC言語のpcapライブラリというものを使っていきます。

C言語を使う理由としては、

ARPプロトコルOSI参照モデルネットワーク層(第三層)に位置する非常に低レイヤーなプロトコルである。

MACアドレスを詐称するためデータリンク層(第二層)のヘッダー情報を書き換える必要がある。

以上の2つが主な理由です。

では実際にパケットを送信するまでのプログラムを以下に示します。
数字をのせた行については後で説明します。

#include <pcap.h>//pcapライブラリインクルード

char* device="イーサネットデバイス名を入力";//①
pcap_t *pcap_handle; //パケット送信用ハンドラー
char errbuf[PCAP_ERRBUF_SIZE];//エラーメッセージ格納用の変数

int main(int argc,char** argv)
{
  u_char* packet={0x00};//②送信するパケットの内容(16進数)
  pcap_handle=pcap_open_live(device,8192,1,0,errbuf);//③ハンドルのオープン
  pcap_sendpacket(pcap_handle,packet,100);//④パケットを送信

}

コードの①〜④を説明します。
① PCが使っているイーサネットバイスを入力します。これはipconfigやifconfig、ip aなどのコマンドによって確認してください。

② pcapライブラリで送信するパケットは16進数の配列で表される"生"のパケットです。ここではサンプルでは{0x00}を送信していますが、
宛先の情報も書かれていないのでこのパケットには意味がありません。
(u_char型はunsigned charの略です。)

pcap_t* pcap_open_live(char* device , int snaplen ,int promisc ,int to_ms,char* errbuf)
パケット送信用のハンドルをオープンします。引数は、デバイス名、取得したいパケットの最大長、デバイスをプロミスキャスモードにするかどうかのフラグ、読み込みタイムアウト時間(0を永遠に待ち続ける。)、エラーメッセージ格納バッファ


int pcap_sendpacket(pcap_handle* handle,u_char* packet,int size)

これが一番重要なパケット送信関数です。引数はハンドル、送信パケット、送信パケットサイズです。
注意してほしいのは、引数に宛先やポートを指定していないことです。
ここが他の言語に備わっているようなソケット通信とは違うところです。
pcapライブラリは生のパケットを送ります。つまりパケットそのものに宛先などの情報を書かなければならないのです。


生のパケットには、ヘッダーと言われるパケットそのものの種類や宛先、送信元などの情報を記載するための各プロトコルごとに決まった書式があります。
もちろんARPプロトコルにも独自のARPヘッダーというものが存在します。

今回はpcapライブラリの関数を使ったパケットの送信の仕方について説明しました。
次回は実際に送信する偽のパケットのARPヘッダを生成していきたいと思います。


ARPキャッシュポイズニングを実装その1
ARPキャッシュポイズニングを実装その3

C言語で通信を盗聴する !? その1【ARPキャッシュポイズニング】

こんにちは!まさです。

今日では有線より無線で通信する機会が多くなっています。それに伴い、ますます盗聴のリスクは高まっていると思います。具体的に盗聴はどのようにしてなされるのでしょうか。

今回は2つの通信機器同士の通信の盗聴の具体的な仕組みについて紹介したいと思います。

 

通信機器同士が通信をする場合その2つをつなぐ通信経路ができます。この通信経路の間に第三者が入り込み、通信路を流れるパケットを盗み見る攻撃のことを総称して"中間者攻撃(MITM攻撃)"といいます。

この攻撃を成功させるためには通信経路を攻撃者の都合のいいように変更できなければなりません。一体どのようにして通信の向きを変更するのでしょうか?

今回は"ARPキャッシュポイズニング"という手法について紹介したいと思います。

f:id:kasayanus:20180724210852p:plain

 

 

簡単のため、今回は攻撃者と被害者はすべて同一のネットワーク(LAN)にいることを想定してください。

この攻撃を理解するためにはまず、ARPについて理解する必要があります。

 

★ ARP(Address Resolution Protocol)

ARPは通信相手のMACアドレスIPアドレスの対応づけのためのプロトコルです。

f:id:kasayanus:20180724211518p:plain

ここでは、IPアドレスは通信したい相手の名前だと思ってください。

スマホを使って誰かに電話したいとき、相手の名前(IPアドレス)を知っているだけでは通話できません。電話番号が必要です。この電話番号の役割をするのがここではMACアドレスだと思ってください。

つまり通信機器が通信するためにはIPアドレス(名前)とMACアドレス(電話番号)の対応づけが必要なのです。これを担うのがARPです。

 

具体的なARPによるやり取りはARPリクエストとARPリプライで成立します。

f:id:kasayanus:20180724212143p:plain

まず通信したい機器はARPリクエストを送ります。このとき、通信したい相手のIPアドレスは知っていますが、そのMACアドレスを知りません。そのため、"LAN全体にブロードキャスト"でリクエストを送ります。

 

f:id:kasayanus:20180724212155p:plain

リクエストを受け取った機器の中で、該当するIPアドレスの機器"だけ"がリクエストに応答して、自分のMACアドレスARPリプライとして送信します。

 

f:id:kasayanus:20180724212456p:plain

これにより、二者の間のIPアドレスMACアドレスの対応が取れたので通信が開始できるわけです。

これがARPの仕組みです。

 

さて、ここでもし再び同じ相手と通信したい場合はどうすればいいでしょうか?

もう一度ブロードキャストでリクエストを送るのでしょうか?

それでは効率が悪いのでPCには一度通信した相手のMACアドレスIPアドレスを記憶するための"ARPキャッシュ"というものが存在します。

 

f:id:kasayanus:20180724212741p:plain

ARPキャッシュはARPリプライをもとに生成されます。

(ちなみに"arp"コマンドでARPキャッシュは確認することができます。)

PCはこのARPキャッシュを参照して通信相手にパケットを送るわけです。

 

ここからが "ARPキャッシュポイズニング" の話になります。

もし悪意を持った者が偽りのARPリプライを送ったらどうなるでしょうか?

f:id:kasayanus:20180724213021p:plain

つまり、攻撃者が自分と異なるIPアドレスを以てして、自分自身のMACアドレスを付与したARPリプライを送りつけるとどうなるか。

被害者はニセのARPリプライの情報をもとにARPキャッシュを上書きしてしまいます。

f:id:kasayanus:20180724213152p:plain

被害者は上書きされたARPキャッシュを参照してパケットを送信します。

これによって、中間者攻撃が成立するのです。

f:id:kasayanus:20180724213214p:plain

 

ここまでの話は2つのPCの間の通信を例に説明しましたが、MACアドレスIPアドレスを持っている機器であればPCかどうかを問いません。

つまり、"スマホ"や"ルータ"に対してARPキャッシュポイズニングを行えば、スマホからインターネットに流れるパケットを盗聴することができます。

f:id:kasayanus:20180724213504p:plain

ではどうやってこの攻撃を防ぐことができるのでしょうか。

具体的な対策として考えられるのは以下の2つだと考えています。

 

f:id:kasayanus:20180724213544p:plain

今ではほとんどのウェブサイトがhttpsでの通信を行っており、パケットが暗号化されているので、この攻撃を受けてもデータを盗み見ることはできません。

しかし、httpではパケットが平文のまま送信されるため、もしウェブサイトがログインフォームでクレジット情報やパスワードの入力を求めてきた場合はすべて筒抜けになります。

2つ目にFreeWifiなどホストが不明なアクセスポイントに接続してしまうと、そのホストが悪意ある者だった場合、この攻撃を受ける危険性があります。

 

今回は中間者攻撃の仕組みについて説明しました。

次回は実際にプログラムで偽のARPリプライを生成する方法について説明したいと思います。



ARPキャッシュポイズニングの実装その2

 

 

 

 

 

【ハッキングの気持ち】パスワード"AAAAAAAAAAAAAAAAAAAAAAAAAAAAA"でログインする

こんにちは!まさです

今回はプログラムのIF文を不正にパスするハッキングの方法を紹介したいと思います。
この方法を使ってIF文をパスできてしまうと、不正な文字列でのログインや、Linuxなどの場合、管理者権限を奪われてしまうという恐ろしい危険性が
あります。
そんな攻撃の中でも最も簡単な方法を紹介したいと思います。

今回攻撃するのは"auth_overflow"というプログラムです。
(下にC言語のコードを載せています)
このプログラムは、ユーザが入力した文字列が、あらかじめ決まったパスワードと一致しているか判定し、その結果を出力するというものです。
今回は"brillig"または"outgrabe"という文字列が入力されるとパスするようにしています。




★ auth_overflowの挙動

1. gccを使ってauth_overflow.cをコンパイルし、実行ファイル(a.out)を作ります。
今回はオプションで"-fno-stack-protector"を付け加えます。
このオプションは、"メモリへの不正な上書きを許す"という意味だと思ってください。

gcc auth_overflow.c -fno-stack-protector

2. パスワード以外の文字列を入力するとアクセス拒否します。
f:id:kasayanus:20180712170650p:plain



3. パスワード文字列を入力するとアクセス許可されます。
f:id:kasayanus:20180712170701p:plain


このプログラムの動きはこれだけです。


以下は"auth_overflow.c"のソースコードです。

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h>

int check_authentication(char *password) { 
   char password_buffer[16];
   int auth_flag = 0; 

   strcpy(password_buffer, password);

   if(strcmp(password_buffer, "brillig") == 0) 
      auth_flag = 1;
   if(strcmp(password_buffer, "outgrabe") == 0) 
      auth_flag = 1;

   return auth_flag;
}

int main(int argc, char *argv[]) { 
   if(argc < 2) {
      printf("使用方法: %s <パスワード>\n", argv[0]); 
      exit(0);
   }
   if(check_authentication(argv[1])) {
      printf("\n-=-=-=-=-=-=-=-=-=-=-=-=-=-\n"); 
      printf("   アクセスを許可します。\n"); 
      printf("-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
   } else { 
      printf("\nアクセスを拒否しました。\n");
   }
}



さて、ここでパスワードとは全く異なる文字列"AAAAAAAAAAAAAAAAAAAAAAAAAAAAA"(A×29回)を入力したらどうなるでしょうか?
その結果は...
f:id:kasayanus:20180712170928p:plain


”アクセスを許可してしまいました!”


プログラムのソースコードにはもちろんこのような文字列での分岐は想定されていません。
ではなぜこの文字列でパスしてしまうのでしょうか。

その秘密はバッファーオーバーフロー攻撃という、有名な攻撃手法にあります。

このプログラムで起きたことを説明します。

このプログラムでは"password_buffer[16]"という配列にユーザーからの入力文字列を格納します。
しかし、ここに29文字のAを格納しようとすると、溢れてしまった13文字はpassword_bufferのすぐ隣のメモリ領域に"無理矢理"格納されてしまいます。
これがバッファーオーバーフローです。
その結果、運の悪いことに、その隣にあった変数"auth_flag"のメモリ領域が、"A"という文字(16進数で41)で上書きされてしまったというわけです。
c言語では0以外の数はTrueとみなされるので、その結果アクセスを許可してしまったというわけです。
41という文字がAを意味しています。


ここでは長くなるので触れませんが、実際にデバッグツールgdbを使うとpassword_bufferからバッファーオーバーフローが起きている様子を確認することができます。
下の写真では、auth_flagのアドレス”0x7fffffffdbec”を見事なまでに"A"が侵食していることがわかります。

f:id:kasayanus:20180712173158p:plain



いかがでしたでしょうか。

気づいた方もいるかもしれませんが、この攻撃はpassword_bufferのメモリアドレスの”後ろ”にauth_flagのメモリアドレスがあったからこそ成功していました。

では逆の位置関係の場合どうなるでしょうか。

ソースコードでこの2つの変数宣言の順番を変えれば、メモリアドレスの位置関係を逆にすることができます。

この場合同様の攻撃は通用しません。

しかし、攻撃の仕方を変えると、実は不正な文字列でパスすることが可能です!
この場合は少し話が複雑になります。
アセンブリやスタックセグメント、インストラクションポインタの仕組みを理解すると、攻撃可能になります。
具体的には、auth_flagを汚染するのではなく、スタックフレームの戻りアドレスを汚染することで可能となります。

また機会があれば書きたいと思います。