소스코드를 보자
#!/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), 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()
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:
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>'
app.run(host='0.0.0.0', port=8000)
admin으로 로그인을 해야 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), 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()
저번 sql문제에서는 admin을 주석 처리했는데 이번에는 안통한다.. 레벨..레벨이다
분명 게스트랑 어드민 둘다 0레벨이다 어떻게 어드민 레벨로 로그인이 가능한건가?
지피티야 지피티야!
이 코드에는 SQL 인젝션(SQL Injection) 취약점이 있으며, 이를 통해 `admin` 계정의 정보를 조회하여 `FLAG` 값을 얻을 수 있습니다. 코드를 분석해보면, **SQL 인젝션을 통한 공격 가능성**이 다음과 같이 드러납니다.
### 취약점 분석
`/login` 라우트에서 사용자의 입력을 바탕으로 SQL 쿼리가 생성되며, 이 때 `userlevel` 값을 필터링하지 않고 바로 SQL 쿼리에 삽입하고 있습니다. 이로 인해 공격자가 임의의 SQL 코드를 주입할 수 있는 **SQL 인젝션** 취약점이 발생합니다.
코드 상의 쿼리 부분은 다음과 같습니다:
```python
res = query_db(f"select * from users where userlevel='{userlevel}'")
```
사용자가 `userlevel` 값에 SQL 구문을 주입하면, 쿼리 전체가 변경될 수 있습니다. 예를 들어, `userlevel`에 `0' OR '1'='1`을 입력하면 쿼리가 다음과 같이 변형됩니다:
```sql
select * from users where userlevel='0' OR '1'='1'
```
이 쿼리는 항상 참이 되므로 모든 `userlevel` 행이 반환됩니다. 그 중 첫 번째 결과가 `admin` 계정이라면, 플래그가 노출될 수 있습니다.
### 공격 방법
1. **SQL 인젝션 페이로드**: `userlevel`에 다음 값을 삽입합니다.
```
0' OR '1'='1
```
2. **실제 요청 예제**:
- `/login` 페이지에서 `POST` 요청으로 `userlevel`에 위의 페이로드를 입력합니다.
3. **요청 분석**:
이 페이로드를 통해 다음과 같은 쿼리가 실행됩니다:
```sql
select * from users where userlevel='0' OR '1'='1'
```
이 쿼리는 `userlevel` 값이 `0`이거나 `'1'='1'`인 행을 반환하므로, 모든 사용자를 가져오고, 그 중 첫 번째 사용자 (보통 `admin`)에 대한 정보가 반환될 가능성이 큽니다.
4. **결과 확인**:
- 요청이 성공하면 `admin`의 정보가 조회되어 `FLAG`가 출력됩니다:
```html
hello admin flag is [FLAG 값]
```
이 공격 방법을 통해 SQL 인젝션 취약점을 이용해 플래그를 획득할 수 있습니다.
헤에..아니야 아니야
왜 안될까 했는데
캬..위에서 아래로 읽기때문이다..
그래서 쓰는 거다 where!
sql에서는 where절이나 union select을 이용하면 된다..캬..
실질적으로 sql에서 쓰는 문은
select * from users where userlevel'0' AND userid='admin'
이거이며 우리는 여기서 '0' and userid = 'admin'을 입력하는거다.
캬~
'Dreamhack > Dreamhack Wargame (Challenge)' 카테고리의 다른 글
[54] IT 비전공자 [dreamhack]basic_exploitation_003문제 풀기 (0) | 2024.11.02 |
---|---|
[53] IT 비전공자 [dreamhack]out_of_bound문제 풀기 (5) | 2024.11.01 |
[51] IT 비전공자 [dreamhack]rev-basic-6문제 풀기 (2) | 2024.10.30 |
[50] IT 비전공자 [dreamhack]php-1문제 풀기 (5) | 2024.10.29 |
[49] IT 비전공자 [dreamhack]XSS Filtering Bypass문제 풀기 (7) | 2024.10.28 |