BWAPP 3주차
SQL Injection – POST/search
MISSON. 버프스위트를 이용해 사용자들의 id와 password를 획득하자.
난이도 low
모든 공격은 버프스위트를 이용해주세요. 공격 과정은 GET방식과 유사합니다.
Quest. 데이터베이스 정보를 알아내세요.
Hint1. DB버전을 확인하는 쿼리를 찾아보세요.
Hint2. @@vesion, database()으로 버전과 이름을 알 수 있습니다.
Quest. 데이터베이스에 존재하는 모든 테이블 명을 출력하세요.
Hint1. GET방식과 쿼리는 같습니다.
Quest. 사용자 정보가 들어있는 칼럼을 출력하세요.
Hint1. 사용자 정보는 users테이블에 있습니다.
Quest. 사용자의 id, password, secret, login 정보를 출력해봅시다.
Quest. 사용자의 비밀번호는 해시 값으로 암호화되어 있습니다. 해시값을 크랙해 비밀번호를 알아봅시다. (툴을 설치할 필요 없이 웹사이트를 이용하셔도 됩니다.)
Hint1. https://crackstation.net/ 해시값을 크랙할 수 있는 사이트입니다.
Hint2. password값으로 나온 해시값을 크랙해서 나온 결과를 첨부하면 됩니다.
+) 버프 스위트를 켰을 때 지정한 사이트 이외에는 인터셉트가 안 되게 하는 방법
(위 방법을 참고하되, 타겟 사이트 url에는 크롬으로 켠 비박스 링크를 붙여넣으면 된다.
자신의 비박스 서버 아이피로 되어 있을 것이다.)
_ 난이도 low
우선 버프 스위트를 켜고, 비박스에 아무 값이나 입력한 뒤 인터셉트해보았다.
링크에 변수가 표시되지 않는 것을 보아 post 방식이 맞고, 입력한 값은 title이라는 변수를 통해 들어가고 있다.
위의 패킷 내용은 클라이언트가 서버로 보내는 것이다. forward를 한 번 누르면 위의 패킷에 서버가 응답하는 내용을 볼 수 있다. 사용자에게 응답 화면으로 보여줄 웹 페이지의 코드이다. 잘 뜯어보면 이런 내용이 있다.
우리가 입력한 부분, 그러니까 form에 /bWAPP/sqli_6.php라는 코드가 있다. action 부분에 걸린 코드이므로 아마 입력한 값은 저 코드를 거쳐 동작한다는 뜻일 것이다. 터미널에서 저 부분의 코드를 찾아가 보자. 경로는 다음과 같다.
/bin/www/bWAPP -> cat sqli_6.php
그리고 이 코드에서 title 변수가 쓰이는 부분은 위와 같다.
post 방식으로 전송된 title 변수는 위와 같은 식으로 sql문 쿼리에 포함되어 보내지고 있었다.
쿼리 전문을 적자면 이런 식일 것이다.
SELECT * FROM movies WHERE title LIKE '&.입력값.&'
해석하자면 우리가 입력한 값이 movies라는 테이블에 있는 title 필드의 어떤 값과 일치하면
아래 스크린샷 코드를 따라, 해당하는 row의 title, release_year, main_character, genre, imdb(링크) 필드를
결과 화면에 표 형식으로 내보낸다는 뜻이다.
작동 원리는 알았으니, 이제 이 쿼리문을 이용해 보자.
먼저 해볼 것은 일부러 오류를 띄우는 것이다.
입력값으로 따옴표 하나(')를 입력한다.
송신되는 패킷은 이런 모양새다. 타이틀 변수에 들어가는 값을 보면 한 번 인코딩을 거치는 것 같다.
한 번 더 forward를 눌러보면 이런 에러 화면이 온다. 쿼리에 구문 오류가 있다고 한다.
물어보지도 않았는데 자기 db가 MySQL이라는 것까지 친절하게 가르쳐 준다.
그럼 여기서 장난을 한 번 더 치자. '을 입력하되, 버프 스위트에서 패킷을 가로채면서 입력값을 약간 수정해 준다.
' or 1=1#
이렇게 입력해 주는 것이다.
그러니까 쿼리 전문은 이런 모양새가 된다.
SELECT * FROM movies WHERE title LIKE '&.' or 1=1#.&'
참고로 #을 붙이지 않고 입력해 보았을 땐 위와 같이 구문 오류가 난다.
아마 #이 뒷부분의 .&'와 같은 쓸모없는 값을 무력화시켜주는 효과가 있을 것이라고 예상한다.
앞에 '을 붙여야 하는 이유도 구문적인 이유일 것이다. 따옴표가 하나 있어야지만 앞에 있는 따옴표와 짝을 이루어 &을 감싸는 모양새가 될 테고, 그렇게 해야 구문 오류를 막을 수 있을 테니까 말이다. (구글링해 보아도 이 부분을 정확히 짚어주는 게시글이 나오지 않아 위와 같은 실험을 통해 예측해 보았다. 정확한 이유를 알 수 있으면 좋을 텐데)
어쨌든간에 이 쿼리로 노리고자 하는 결과가 무엇이냐 하면 이렇다.
이 쿼리를 통해 movies라는 테이블에 있는 모든 row를 출력하고 싶다.
하지만 틀이 되는 쿼리에는 WHERE로 시작하는 조건식이 걸려 있다.
때문에 or문을 사용해 이를 무력화해 주는 것이다. WHERE (조건식) or 1=1, 이런 식으로 말이다.
뒤에 1=1처럼 반드시 참인 조건이 or로 걸려 있다면 앞의 조건이 어떻게 되든 결과는 무조건 참이 된다.
그러면 앞에 있는 SELECT * FROM movies는 아무런 제약조건 없이,
title 필드에 값을 가지고 있는 행은 무조건 출력할 수 있을 것이다.
한번 해보자.
성공이다. movies 테이블에 들어 있는 모든 영화가 출력되었다.
그럼 여기서 한 단계 더 나아가서, movies 테이블과 관계없는 값도 출력하고 싶어진다.
이를테면 이 데이터베이스의 버전 같은 것 말이다.
Quest. 데이터베이스 정보를 알아내세요.
Hint1. DB버전을 확인하는 쿼리를 찾아보세요.
Hint2. @@version, database()으로 버전과 이름을 알 수 있습니다.
@@version은 db 버전을, database()는 db 이름을 알려주는 시스템 변수이다.
어쨌든 db에서는 모든 정보를 테이블로 보여주기 때문에
우리가 노리는 버전, db 이름 같은 정보들도 테이블 형식으로 출력될 것이다.
그리고 입력값이 들어가는 쿼리는 이미 특정 테이블을 보여주는 형식으로 적혀 있다.
그러면 생각해 볼 수 있는 방법은 무엇이냐,
기존 쿼리가 보여주고자 하는 테이블 밑에 우리가 얻고자 하는 정보가 끼워진 테이블을 출력하고
기존에 보여지던 테이블은 보이지 않게 하면 깔끔할 것이다.
이런 작업을 하기 위해서는 기존 테이블과 우리가 만들어내는 테이블을 합칠 필요가 있다.이것을 위해 테이블을 합치는 UNION 쿼리가 필요하다.UNION은 중복을 없애고 보여주고, UNION ALL은 중복값까지도 모두 보여주는데중복될 값이 없으므로 연산이 더 빠른 UNION ALL을 쓰는 것이 좋겠다.또한 우리가 원하는 표를 얻기 위해서는 SELECT 쿼리도 필요하므로> ' UNION ALL SELECT 칼럼1, 칼럼2, @@version, 칼럼3, database()... #이런 식으로 입력값을 짜는 것이 좋겠다.
그런데 유니언 쿼리에는 조건이 하나 더 붙는다.합쳐서 보여줄 표끼리 칼럼 수가 동일해야 한다는 것이다.얼핏 보기에 이것은 별 문제가 되지 않는 것처럼 보인다. 우리가 본 표에는 칼럼이 다섯 개 있었으니까.그러면 시험삼아 한번 해보자.
> ' UNION ALL SELECT 1, 2, 3, 4, 5#
에러가 뜬다. 칼럼 수가 다르다고 한다.
생각해 보면 위의 PHP 코드에서는 테이블의 특정 필드 5개를 뽑아 화면에 표시하고 있었을 뿐
그것이 테이블의 모든 칼럼이라는 말은 없었다.
이렇게 되면 우리가 칼럼 수를 직접 알아내야 한다. 적어도 5개보다는 많을 것이다. 하나씩 늘려가며 칼럼수를 찾아보자.
7개째에서 정상적인 결과가 떴다. 더불어 몇 번째 필드가 어디로 들어가는지도 알아냈다.
영화명은 2, 제작년도는 3, 등장인물은 5, 장르는 4번째다. 이를 참고해 쿼리문을 다시 짜면 될 것이다.
더불어 ' 앞에 의미 없는 값을 입력하면 해당 값과 제목이 일치하는 영화가 없으므로
movie 테이블의 내용은 출력되지 않고, 우리가 바라는 내용만 출력할 수 있을 것이다.
> 1' UNION ALL SELECT 1, @@version, 3, 4, database(), 6, 7#
성공이다. 다음 퀘스트로 넘어가자.
Quest. 데이터베이스에 존재하는 모든 테이블 명을 출력하세요.
Hint1. GET방식과 쿼리는 같습니다.
이 db에 존재하는 모든 테이블 명을 출력하는 것이 미션이다.
파일시스템도 그렇고 db도 그렇고, 이런 '시스템 자체에 대한 정보'를 보통 메타 데이터라고 한다.
메타 데이터는 시스템이 자체적으로 파일이나 디렉토리, 혹은 테이블을 만들어 관리한다.
db에 있어 모든 테이블의 정보는 information_schema라는 스키마의 tables라는 테이블이 갖고 있다. (참고)
테이블 명만 알아내면 되므로, 테이블의 아무 한 칸이나 잡아 table_names 변수를 넣어준다.
> 1' UNION ALL SELECT 1, table_name, 3, 4, 5, 6, 7 FROM information_schema.tables#
방대한 양의 테이블 이름들이 나온다. 그 중 예제와 일치하는 일부만 스크린샷으로 가져왔다.
공격 성공이다.
Quest. 사용자 정보가 들어있는 칼럼을 출력하세요.
Hint1. 사용자 정보는 users테이블에 있습니다.
위에서 했던 것과 같은 방식이다. 위 쿼리문과 같은 양식을 지키고 from을 사용하면 어떤 테이블에서든 데이터를 빼낼 수 있다. 먼저 users 테이블에 어떤 칼럼이 있는지 알아야 하므로 위의 인포메이션 스키마를 한 번 더 사용하겠다.
COLUMNS 테이블은 각 테이블마다 어떤 칼럼이 있는지를 알려주는 테이블이다. 테이블명을 키값으로 사용해 셀렉트하면 해당 테이블에 소속된 칼럼명을 알아낼 수 있다. 쿼리문으로 적어보자.
> 1' UNION SELECT ALL 1,column_name,3,4,5,6,7 FROM information_schema.columns where table_name='users'#
다양한 정보가 나온다. 공격 성공이다.
Quest. 사용자의 id, password, secret, login 정보를 출력해봅시다.
위의 양식을 다시 한 번 이용하자. 이번엔 users 테이블에서 위의 정보를 뽑아낼 것이다.
> 1' UNION SELECT ALL 1,id,password,login,secret,6,7 FROM users#
간단하게 뽑아졌다. 공격 성공이다.
왼쪽부터 차례대로 id, password, secret, login이다. 4번째와 5번째 필드는 순서가 뒤바뀜에 주의한다.
Quest. 사용자의 비밀번호는 해시 값으로 암호화되어 있습니다. 해시값을 크랙해 비밀번호를 알아봅시다.
(툴을 설치할 필요 없이 웹사이트를 이용하셔도 됩니다.)
Hint1. https://crackstation.net/ 해시값을 크랙할 수 있는 사이트입니다.
Hint2. password값으로 나온 해시값을 크랙해서 나온 결과를 첨부하면 됩니다.
해시값으로 나온 비밀번호는 다음과 같다. (위 스크린샷에 나온 두 해시값은 서로 동일하다.)
6885858486f31043e5839c735d99457f045affd0
이를 크랙 사이트에서 해독해 보면,
이런 결과가 뜬다. Type은 sha1, Result는 bug이다.
'WEB > 웹해킹' 카테고리의 다른 글
XSS Game 1, 2 (0) | 2022.08.12 |
---|---|
[bWAPP] XSS - Stored(Blog) ~ (Change Secret) (0) | 2022.08.07 |
[bWAPP] XSS - reflected (GET) (0) | 2022.07.31 |
[bWAPP] reflected (GET) ~ stored (Blog) (0) | 2022.07.14 |
[bWAPP] HTML 인젝션 (GET) 풀이 (0) | 2022.07.09 |