1. SQL Injection 공격/ 대응 방안 문서화
SQL Injection 이란?
: 악의적으로 보안 상의 취약점을 이용해, 임의의 SQL 문을 주입하고 실행하게 해 데이터베이스가 비정상적인 동작을 하도록 조작하는 공격 기법이다.
SQL 연산자 | |
OR AND like |
|| && = |
SQL 문자열 | |
' ?변수=값 ; |
문자 데이터 구분기호 url 매개변수 쿼리 구분 기호 |
SQL 주석 | |
-- # /* */ |
뒤에 공백이 있어야 주석처리 가능 뒤에 공백 없어도 주석처리 가능 (url에서 쓸 땐 %23으로 사용) /*와*/사이 문자열 주석처리 가능 |
SQLi 공격 과정
1) 취약한 SQL 기반 웹 사이트을 식별하고 입력 데이터를 이용해 악의적인 SQL 쿼리를 주입한다.
2) 악의적인 SQL 쿼리는 검증되고 데이터 베이스에 의해 명령 실행된다.
3) 해커는 관리자 권한을 부여 받을 수 있게 된다.
SQL Injection 공격 기법
1. in-band SQLi 대역 내 SQLi
(1) Error based
: 쿼리에 고의적으로 오류를 발생시켜 시스템 권한 체크를 우회하는 공격 기법
: Error based 공격은 로그인 창에서 나타나기도 한다.
[ webhacking.kr old 39 문제 풀이 ]
먼저 ID에 admin 입력, PASSWD에 ‘or 1=1-- 입력해준다.
이때 --은 주석처리 이므로 user_id = ‘”&User ID&”’ and passwd=’”&passwd &”’ “ 여기서 ‘”이 주석처리 된다.
-- 주석 처리로 인해 뒤에 쿼리가 무시되어 1=1에 대한 OR 연산도 추가가 되어 존재하는 계정으로 로그인 됩니다.
(2) Union based
: Union 연산자를 이용해 원래의 요청에 추가 query를 삽입하는 공격 기법
+ union: 두 개의 쿼리를 보낼 수 있는 연산자
unionall:조회되는 데이터 중 중복행을 제거하지 않는다.
문제점 : 조회되는 컬럼 수가 동일해야만 한다.
- union based 공격 과정
1) 칼럼 수 찾기
order by n 이용하여 n번째 컬럼으로 오름차순 정렬 후 n번 째 컬럼이 없다면, 쿼리가 실행되지 않음(에러발생)
2) db+칼럼 이름 찾기
information_schema 이용하여 db의 메타 데이터*(테이블, 컬럼, 인덱스 등)를 담고 있는 데이터 사전
table_schema, table_name, column_name 칼럼 사용한다.
3) union 사용해서 정보 얻기
2단계에서 얻은 테이블의 칼럼 이름으로 정보를 얻을 수 있다.
2. blind SQLi ) 추론적 SQLi
(1) Boolean based
: 대입 값에 대한 참 또는 거짓의 결과를 서버의 응답 패턴을 통해 데이터를 유추
1. 비밀번호 직접 구하기
(1) ?pw=’ or length(pw)’l 을 통해 비밀번호의 길이(l)를 구할 수 있다.
(2)?pw=’ or substr(pw,p,1)=n%23 을 통해 각 자리(p) 해당하는 번호(n)을 구할 수 있다.
2. 코드 짜기
(2) Time based
: 대입 값에 대한 참 또는 거짓의 결과를 응답의 전송 시간을 이용하여 데이터를 유추한다.
timebased_sqli' or(length(database())=n and sleep(2);#--
- DB길이 알아내기
database()을 통해 db이름을 반환
length()을 통해 db길이를 반환
db 길이가 n이면 뒤의 sleep(2) 실행하여 참이면 지정된 시간만큼 지연
3. out of band SQLi ) 대역 외 SQLi
: query의 결과를 다른 외부 채널을 통해 전달하는 기법
query의 결과를 DNS 서버에 보내기도 한다. 여기서 DNS 서버란 IP주소를 사람이 이해하기 쉽게 도메인 네임으로 변환해주는 서버이다.
- 대응 방안
1) 입력값 검증
사용자의 입력이 DB Query 에 동적으로 영향을 주는 경우, 입력된 값이 개발자가 의도한 값(요효값) 인지 검증한다.
2) 저장 프로시저 사용
저장 프로시저는 사용하자고 하는 Query 에 미리 형식을 지정하는 것으로 지정된 형식의 데이터가 아니면 Query 가 실행되지 않기 때문에 보안성을 크게 높인다.
3) 서버 보안
(1) 최소 권한 유저로 DB 운영
(2) 사용하지 않는 저장 프로시저와 내장함수 제거 또는 권한 제어
(3) 목적에 따라 Query 권한 수정
(4) 공용 시스템 객체의 접근 제어
(5) 신뢰할 수 있는 네트워크, 서버에 대해서만 접근 허용
(6) 에러 메시지 노출 차단
2. dreamhack simple_sqli 풀이
simple_sqli 문제는 admin으로 로그인을 성공했을 경우, flag 값이 뜨는 문제로 error based 유형이다.
아래 주어진 파일을 열면 로그인 부분을 보게 되면 userid를 admin으로 바꿔서 query하면 flag를 얻을 수 있다.
위에 파일에서 select * from users where userid="{userid}" and userpassword="{userpassword}" 이 부분에서 "{userid}"를 "admin" 으로 수정하고 My SQL 서버의 주석인 --을 사용하여 password 부분을 주석처리하면 password 값을 알지 않아도 flag를 얻을 수 있다.
3. Lord of SQLi gremlin, cobolt, goblin, orc 풀이
(1) Lord of SQLi gremlin
gremlin 문제를 누르게 되면 아래와 같은 php 언어로 된 코드들이 나온다.
php 코드는 SQL 쿼리문을 이용해 id와 pw가 일치한지 확인하는 코드로 get 방식($_GET)을 이용하여 데이터 값을 받아 도메인의 뒤에 값을 주어 변수 값을 수정하면 된다.
주소창에 ?id=admin%27%23 을 적으면 문제가 해결된다. 이는 pw를 주석처리 하는 것으로 id=admin' 이고 pw는 주석처리 되어 무시가 되는 쿼리문이 된다. 여기서 SQL 주석에 따르면 %27은 ', %23은 #으로 #은 쿼리문을 주석처리 할 때 사용한다.
(2) Lord of SQLi cobolt
gremlin 문제와 동일하게 문제를 누르면 아래 php 코드가 나타난다. 아래 php 코드에서 id가 admin이 되게끔 하면 문제가 풀린다는 것을 알 수 있다. gremlin 문제와 유사하게 id를 admin으로 참이 되게 하고 pw를 주석처리를 하게 된다면 문제는 풀리게 된다.
if($result['id'] == 'admin') solve("cobolt");
(3) Lord of SQLi goblin
php 코드를 읽어봤을 때, id= admin 일때, goblin이 해결된다고 나와 있고, get 방식으로 no 값을 받을 수 있다.
먼저 no에 1을 넣었을 때 guest가 출력된 것을 보아 no=1이 guest 번호임을 알 수 있었다.
주소창에 no=0 or id='admin' 을 넣었지만 아래 화면이 출력되었다.
no=0 은 guest 조건에서 벗어나기 위함이고, id가 admin일 경우 문제가 해결되는 점에서 작성했지만 답안이 아니었다.
url 인코딩은 인터넷을 통해 전송 될 수 있는 포맷으로 문자를 변환하는 것으로 ASCII 문자 집합을 유효한 형식으로 변환하고, 보안 상 안전하게 변환하기 위해 16진수(hex값)으로 변환해야 한다.
id=admin인 문자열을 url 에 인코딩하려면 admin을 16진수로 변환하여 값을 인코딩해야 함을 알게 되었다.
admin의 핵사값은 61646d696e 로 16진수를 사용할 때는 앞에 0x를 붙여서 써야한다.
주소창에 no=0||id=0x61646d696e 넣은 결과 문제가 해결되었다.
(4) Lord of SQLi orc
boolean based 공격 기법이라는 것을 알 수 있는 부분이 if($result['id']) echo "<h2>Hello admin</h2>";
로 id 값이 admin일 경우 Hello admin을 출력하게 된다.
if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("orc");
문제를 해결하기 위한 조건으로 get 방식으로 pw를 입력해서 $result['pw'] 값을 직접 구해야 한다는 것을 알 수 있다.
두 가지 방법 중 비밀번호를 직접 구하는 방법으로 문제를 해결하고자 한다.
첫 번째로 비밀번호의 길이를 먼저 구해야 한다.
?pw=' or length(pw)='l
l이 pw의 길이로 숫자를 대입한 결과 8을 넣었을 때 hello admin 이 출력되는 것으로 보아 pw 는 8자리이다.
두 번째로 각 자리(p) 해당하는 번호(n)을 구하는 거로
?pw=' or substr(pw, p, 1)=n%23
여기서 1은 자르고자 하는 길이로 하나씩 pw 번호를 알게 된다.
p는 pw가 8자리이기 때문에 1~8이고, n은 해당하는 숫자를 대입하여 맞다면 hello admin 이 출력되는 것으로 8자리 pw를 알 수 있다.
대입한 결과 ?pw=095a9852 로 orc 문제가 해결된다.
'자기개발 > Web' 카테고리의 다른 글
[2022 리버싱: Day 18] 패킹과 언패킹 (0) | 2022.02.21 |
---|---|
[ 웹스터디 5주차 ] (0) | 2021.11.23 |
[ 웹 스터디 4주차 ] (0) | 2021.11.16 |
[ 웹 스터디 2주차 ] (0) | 2021.09.28 |
[ 웹 스터디 1주차 ] (0) | 2021.09.14 |