4주차. 워게임 (웹 분야)

한샛코드·2025년 5월 17일
0

@Xpert

목록 보기
4/4

1. simple_sqli_chatgpt

🕰️ 풀이 시간 : 7분 (SQL 문법을 알고 있어서, 접근이 다소 쉬웠음)

분석하기

1. 데이터베이스 생성하기

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()
  1. 관계형 데이터베이스 구축을 위해 SQLite를 이용한다.
  2. 테이블 users는 길이가 char형 userid, userpassword 및 integer형의 userlevel을 열로 사용한다.
  3. 테이블을 생성하고 나서, userid, userpassword, userlevel이 각각 ("guest", "guest", 0)과 ("admin", (난수), 0)인 값을 각각의 행으로 삽입한다.

2. 실제 웹사이트 작동 부분

@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>'
  1. 로그인 페이지에 접속하면, userlevel을 입력할 수 있는 form이 있다.
  2. 현재 res는 데이터베이스를 명령어를 통해 직접적으로 접근하고 있다.
  3. 플래그를 얻으려면, userid"admin"이어야 하고, userlevel이 0이어야 한다.
  4. 하지만, 정상적인 접근 방법으로는 userlevel을 하나 밖에 입력하지 못한다.
  5. 여기서 우리는 명령어로 직접적으로 접근하는 취약점을 사용하는 SQL Injection 방법을 사용한다.

풀이하기

  1. form을 통해 string을 입력받고, userlevel이라는 변수에 저장됨을 알 수 있다.
  2. 테이블 접근을 SELECT * FROM users WHERE userlevel = '{userlevel}'로 하고,
    Python f-string 특성상 실제로 사용하는 부분은 쌍따옴표 안을 명령어로 그대로 사용한다.
  3. "그대로 사용한다"에 집중하며, form에 0' AND userid = 'admin을 채운다.
    즉, 명령어는 SELECT * FROM users WHERE userlevel = '0' AND userid = 'admin'이 된다.
    (간단히 해석하자면 "users 테이블에 있는 행들 중, userlevel의 값이 '0'이고, userid의 값이 'admin'인 값을 찾아(WHERE) 출력(SELECT)한다." 라는 의미이다)
  4. 채우고나서 로그인 버튼을 누르면 웹페이지에 정답이 출력된다.

2. simple_sqli

🕰️ 풀이 시간 : 3분 (1번 문제와 비슷한 문제였음)

분석하기

1. 데이터베이스 생성하기

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()
  1. 관계형 데이터베이스 구축을 위해 SQLite를 이용한다.
  2. 테이블 users는 길이가 char형 userid, userpassword을 열로 사용한다.
  3. 테이블을 생성하고 나서, userid, userpassword가 각각 ("guest", "guest")과 ("admin", (난수))인 값을 각각의 행으로 삽입한다.

2. 실제 웹사이트 작동 부분

@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>'
  1. 로그인 페이지에 접속하면, useriduserpassword를 입력할 수 있는 form이 있다.
  2. 현재 res는 데이터베이스를 명령어를 통해 직접적으로 접근하고 있다.
  3. 플래그를 얻으려면, userid"admin"이면 된다.
  4. 그러나, 우리는 admin 계정의 userpassword를 알지못한다.
  5. 여기서 우리는 명령어로 직접적으로 접근하는 취약점을 사용하는 SQL Injection 방법을 사용한다.

풀이하기

  1. 2개 각각의 form을 통해 string을 입력받고, userid, userpassword 라는 변수에 저장된다.
  2. 테이블 접근을 이전 문제와 같은 방법으로, Python f-string 따옴표 안을 명령어로 그대로 사용한다.
  3. "그대로 사용한다"에 집중하며, form에 admin" --을 채운다.
    즉, 명령어는 SELECT * FROM users WHERE userid = "admin"이 된다.
    (왜 뒤에 userpassword 부분은 생략되냐 생각할 수 있는데, SQL 문법에서 -- 표현은 주석을 뜻한다. 즉, 해당 표현 뒤에 있는 문장은 모두 무시된다.
    따라서, "users 테이블에 있는 행들 중, userid의 값이 'admin'인 값을 찾아(WHERE) 출력(SELECT)한다." 라는 의미이다)
  4. 채우고나서 로그인 버튼을 누르면 웹페이지에 정답이 출력된다.

3. XSS-1

아직 해결하지 못한 문제. (VM 코인 제한)

분석하기

풀이하기

4. XSS-2

아직 해결하지 못한 문제. (VM 코인 제한)

분석하기

풀이하기


회고

이번에는 기존에 배운 지식을 바탕으로 웹사이트의 취약점을 찾는 실습을 진행하였다. 사실 SQL injection 문제는 유튜브에서 개념을 한 번 본적이 있기도하고, 특히 SQL 문법을 알았던지라 풀기 쉬웠다. 풀면서 느낀점은 최근 채팅 보조 서비스(봇) 운영과 DB를 한 번에 관리한 것과 연관짓자면, form 하나로 모든 DB에 접근 가능하다는 것을 보고, '개발을 할 때에는 이런 취약점도 고려해야겠구나'하고 생각하기도 했다. 다행히도 봇을 서비스 하는 플랫폼에서는 이러한 SQL 인젝션 공격에 대비하기위해 셀렉트 메뉴를 선택한다는 점에서 참 다행이라고 생각된다. 하마타면 모든 DB가 공개될 뻔한 것이니까. 반면에, XSS 문제는 (아직 풀지는 못했지만) 뭔가 JavaScript를 사용하는 문제 같은데, 어떻게 접근해야할 지 감이 안온다. 문제 파일도 보면 cookie를 어떻게 하는 것 같아보인다. 이 문제에 대해서는 동아리 시간에 알아보거나, 따로 공부를 직접 해야할 듯 하다. 그래도, 취약점을 찾아서 정답(플래그)를 찾는 것도 수수께끼를 푸는 것 같아 재미있었다. 그리고, 허점(취약점)을 찾아 정답을 발견하면서 생각해본 점이라면 개발을 할 때에 보안에 대해 신경쓰게 되는 계기가 된 것 같아서 좋았다.

profile
개발도 하고 요리도 하는 노근본 개발자

0개의 댓글