1. simple_sqli
거두절미하고 바로 문제 정보부터 보자
별거없다.... 소스코드를 살펴보자
#!/usr/bin/python3
from flask import Flask, request, render_template, g
import sqlite3
import os
import binascii
app = Flask( __name__ )
app .secret_key = os . urandom ( 32 )
try :
FLAG = open ( './flag.txt' , 'r' ). read ()
except :
FLAG = '[**FLAG**]'
DATABASE = "database.db"
if os . path . exists ( DATABASE ) == False :
db = sqlite3 . connect ( DATABASE )
db . execute ( 'create table users(userid char(100), userpassword char(100));' )
db . execute ( f 'insert into users(userid, userpassword) values ("guest", "guest"), ("admin", " { binascii . hexlify ( os . urandom ( 16 )). decode ( "utf8" ) } ");' )
db . commit ()
db . close ()
def get_db ():
db = getattr (g, '_database' , None )
if db is None :
db = g._database = sqlite3 . connect ( DATABASE )
db . row_factory = sqlite3 . Row
return db
def query_db ( query , one = True ):
cur = get_db (). execute ( query )
rv = cur . fetchall ()
cur . close ()
return ( rv [ 0 ] if rv else None ) if one else rv
@ app .teardown_appcontext
def close_connection ( exception ):
db = getattr (g, '_database' , None )
if db is not None :
db .close()
@ app .route ( '/' )
def index ():
return render_template( 'index.html' )
@ app .route ( '/login' , methods =[ 'GET' , 'POST' ])
def login ():
if request.method == 'GET' :
return render_template( 'login.html' )
else :
userid = request.form.get( 'userid' )
userpassword = request.form.get( 'userpassword' )
res = query_db ( f 'select * from users where userid=" { userid } " and userpassword=" { userpassword } "' )
if res :
userid = res [ 0 ]
if userid == 'admin' :
return f 'hello { userid } flag is { FLAG } '
return f '<script>alert("hello { userid } ");history.go(-1);</script>'
return '<script>alert("wrong");history.go(-1);</script>'
app .run( host = '0.0.0.0' , port = 8000 )
코드를 살펴보니 userid가 admin일때 FLAG가 출력되는 모습이다. 하지만 정상적인 방법으로는 admin 계정으로 로그인 할 수 없다.
id: admin, passwd: admin
문제를 풀기 위해서는 제목처럼 SQLi, 즉 SQL injection 이 필요하다. 그럼 SQL query 문을 살펴보자
select * from users where userid=" { userid } " and userpassword=" { userpassword }
우리가 userid 와 userpassword를 입력하면 저 쿼리문에 들어간다. 그럼 우리는 admin 계정의 password 를 알 수 없기 때문에 userid 부분에 SQL injection 구문을 집어넣어서 userpassword에 뭘 집어넣든 무조건 참이 되게 만들어야 한다.
이 구문을 끼워넣으면 userpassword가 주석처리 되어서 admin 계정으로 로그인 할 수 있다.
admin" --
생각보다 엄청 간단하다. 이 구문을 {userid} 부분에 넣으면
select * from users where userid="admin" -- " and userpassword=" { userpassword }
이런식으로 구문을 쓰면 userid 는 admin이 되고 그 뒤는 주석처리가 되어 admin 계정으로 쉽게 로그인 할 수 있다.
userid: admin" --, passwd: a;dflkjad;fs
성공적으로 로그인 된 모습이다!!!
2. simple_sqli_chatgpt
얘도 문제부터 보자
전 문제와 달리 userlevel 을 입력하는곳 하나만 있는 모습이다!!
어떻게 풀지 감이 잘 안잡힌다... 문제 소스코드를 봐보자.
#!/usr/bin/python3
from flask import Flask, request, render_template, g
import sqlite3
import os
import binascii
app = Flask( __name__ )
app .secret_key = os . urandom ( 32 )
try :
FLAG = open ( './flag.txt' , 'r' ). read ()
except :
FLAG = '[**FLAG**]'
DATABASE = "database.db"
if os . path . exists ( DATABASE ) == False :
db = sqlite3 . connect ( DATABASE )
db . execute ( 'create table users(userid char(100), userpassword char(100), userlevel integer);' )
db . execute ( f 'insert into users(userid, userpassword, userlevel) values ("guest", "guest", 0), ("admin", " { binascii . hexlify ( os . urandom ( 16 )). decode ( "utf8" ) } ", 0);' )
db . commit ()
db . close ()
def get_db ():
db = getattr (g, '_database' , None )
if db is None :
db = g._database = sqlite3 . connect ( DATABASE )
db . row_factory = sqlite3 . Row
return db
def query_db ( query , one = True ):
cur = get_db (). execute ( query )
rv = cur . fetchall ()
cur . close ()
return ( rv [ 0 ] if rv else None ) if one else rv
@ app .teardown_appcontext
def close_connection ( exception ):
db = getattr (g, '_database' , None )
if db is not None :
db .close()
@ app .route ( '/' )
def index ():
return render_template( 'index.html' )
@ app .route ( '/login' , methods =[ 'GET' , 'POST' ])
def login ():
if request.method == 'GET' :
return render_template( 'login.html' )
else :
userlevel = request.form.get( 'userlevel' )
res = query_db ( f "select * from users where userlevel=' { userlevel } '" )
if res :
userid = res [ 0 ]
userlevel = res [ 2 ]
print ( userid , userlevel )
if userid == 'admin' and userlevel == 0 :
return f 'hello { userid } flag is { FLAG } '
return f '<script>alert("hello { userid } ");history.go(-1);</script>'
return '<script>alert("wrong");history.go(-1);</script>'
app .run( host = '0.0.0.0' , port = 8000 )
FLAG 를 얻는 조건은 userlevel 이 0이고 userid가 admin 일때 FLAG를 얻을 수 있다.
그러나 문제에서는 userid 입력란이 없다...
그렇다면 AND 를 사용하여 둘을 동시에 입력할 수 있다.
예시 구문을 보자
이 구문을 입력하면 sql query 는 다음과 같이 바뀌게 된다.
select * from users where userlevel='0' AND userid='admin'
그럼 userlevel 은 0이고 userid 도 admin 이기에 FLAG가 출력된다!!
와우!!!!!!!!