모의해킹 실무자가 알려주는, SQL Injection 공격 기법과 시큐어 코딩 : PART 1
강의주소 : https://www.inflearn.com/course/sql-injection-secure-coding-1/dashboard
원인
입력값 검증 없이 구문을 조합할 경우, 변조된 sql 질의가 발생할 수 있다
대응방안
1) Prepared Statement 사용
2) 사용자 입력 값 타입에 따른 입력 값 검증 로직 구현
3) 길이제한
WAF라는 인라인 방식의 보안 솔루션을 많이 사용.
하지만 보안 솔루션 외의 다른 부분이 취약한 경우가 많다
Prepared Statement
Prepared Statement
구분분석 및 정규화 -> 컴파일 -> 쿼리 최적화 -> 캐시 -> 실행
기존: conn.createStatement().executeQuery(query);
=> 변경: conn.prepareStatement(query).setString(n, value);
PlaceHolder
쿼리에서 물음표로 표시되며 런타임 시 사용자 입력값과 치환된다
PlaceHolder를 제외한 쿼리가 미리 컴파일 된다
사용자 입력 값은 순수 문자로 처리된다 (쿼리가 되지 않는다)
입력값 바인딩 : setString, setInt, setLong, setFloat 등...
Prepared Statement를 사용하더라도, 컴파일 전에 변수를 셋팅하면 취약하다
컴파일 이후( conn.prepareStatement )에 변수를 바인딩하여야 한다
iBatis, myBatis의 경우
기존 : ... LIKE '%${keyword}%'
변경(안전) : ... LIKE '%#{keyword}%'
Hibenate
기존 : LCASE('")).append(vl.getVlaueAsString("keyword")).append("')
변경(안전) : sql.append((new StringBuilder(" LCASE(keyword) = LCASE(:keyword)").toString()).append("\n");
사용 불가능한 경우
: 사용자 입력값을 통해 테이블이나 컬럼명을 입력받는 경우
사용자 입력 값 타입에 따른 검증 로직
1) 숫자
JAVA : Pattern.matche("^[0-9]*$", 입력값);
PHP : is_numeric(입력값)
=> 숫자만 입력받도록 정규식이나 함수를 활용
2) 문자
JAVA : (mssal, oracle) keyword.replace("'", "''");
(mysql) keyword.replace("\"", "'\"\"");
PHP : real_escape_string(입력값);
=> JAVA의 경우 싱글쿼터'를 싱글쿼터 2개로 바꾸고, 역슬래시더블쿼터\"를 \"\"로 변경한다. 메타문자로 인식하지 않기 위해서.
3) 테이블, 컬럼
JAVA : Pattern.matche("^[0-9a-zA-Z-]*$", 입력값);
PHP : preg_match("/^[0-9a-zA-Z-]*$/", 입력값)
4) 키워드
JAVA : 값.toLowerCase().equals("asc") 또는 "desc" 일 때 쿼리에 ASC나 DESC 추가
취약한 코드 $id = $_POST["id"];
$pw = md5($_POST["pw"]);
$query = "select * from member where id='{$id}' and pw='{$pw}'";
$tmp = $db_conn -> query($query);
|
변경된 코드 $id = $_POST["id"];
$id = str_replace("'", "\'", $id);
$pw = md5($_POST["pw"]);
$query = "select * from member where id='{$id}' and pw='{$pw}'";
|
그런데 이 코드 또한 부족하다
' or 1=1# 입력시
\' or 1=1# 입력시
맞는 치환
$id = $_POST["id"]; $id = str_replace("\\'", "\\\\", $id);
$id = str_replace("'", "\'", $id);
$pw = md5($_POST["pw"]);
|
이를 함수로 변경함
$id = $_POST["id"]; $id = $db_conn -> real_escape_string($id);
$pw = md5($_POST["pw"]);
|
수동으로 하게 되면 휴먼에러가 일어날 수 있으니 공식에서 지원해주는 함수를 사용하는 것을 권장한다.
MYSQL 시큐어코딩
사용자 입력값 구분
1) 목록 : index.php 검색어(문자형), 검색 종류(컬럼형), 정렬(컬럼형, 키워드)
2) 상세보기 : view.php 게시글 번호(숫자형), 패스워드(문자형)
3) 상세보기 수정 : modify.php 게시글 번호 (숫자형)
4) 액션(삭제, 수정, 작성) : action.php
목록
검색어
$keyword = $db_conn->real_escape_string($_POST["keyword"]);
검색 종류($search_type, $sort_column)
if((!preg_match("/^[0-9a-zA-Z-]*$/", $search_type) && !empty($search_type))
|| (!preg_match("/^[0-9a-zA-Z-]*$/", $sort_column) && !empty($sort_column))){
echo "<script>alert('정상적인 입력 값이 아닙니다.'); history.back(-1);</script>";
exit();
}
=> 정규식을 통해 허용된 값 이외에는 불가능. exit()로 구문종료해주는 것도 중요하다.
정렬
$sort = strtoupper($_GET["sort"]);
if(strpos($sort, "ASC")){
$sort = "ASC";
} else {
$sort = "DESC";
}
=> 서버사이드에서 하드코딩으로 정렬을 지정하여 인젝션 방지
키워드 인젝션 테스트. 싱글쿼터 ' 를 넣어도 에러 발생하지 않고 결과값도 나오지 않음.
keyword=te\'st 로 테스트해도 동일함.
keyword=te\'st+or+1=1%23
\'는 필터때문에 에러가 안날 수 있으니, 뒤에 공격구문을 덧붙여서 테스트까지 완료.
search_type=)
특수문자 등 입력시 응답 확인.
길이설정도 해주면 더 안전해진다. strlen함수 사용.
?sort_column=idx\n+and+1=1+title
?sort_column=idx&sort=\'
예외처리, 무반응 확인
인젝션이 되지 않더라도 에러 메시지는 그대로 노출하면 안된다.
$result = $db_conn->query($query);// or die($db_conn->error);
이런식으로 주석 등으로 die 부분 삭제.
상세보기
$password = $db_conn->real_escape_string($_POST["password"]);
if(!is_numeric($idx)){
echo "<script>alert('정상적인 입력 값이 아닙니다.'); history.back(-1);</script>";
exit();
}
=> 패스워드와 idx에 대해 검증
패스워드는 request method를 체인지하여 POST로 전송하여 확인한다.
수정페이지도 is_numeric을 이용해 idx 인젝션을 방지한다.
실습코드에는 common.php가 있어서 거기서 db관련 설정이($password 포함) 하드코딩되어 있다
이곳에 $salt = "hackTest"; 솔트값을 추가하고,
$password = md5($password.$salt); 이렇게 연결연산자 . 을 넣어서 합쳐서 사용하도록 한다.
쓰기, 수정, 삭제시 전부 md5로 변경시켜 사용해야 한다.
MSSQL
$keyword = str_replace("'", "''", $keyword);
키워드
sort_column, search_type, idx은 mysql과 동일한 적용
mssql은 die()함수가 없는데도 에러가 출력되므로, php.ini에서 별도 설정해주어야 한다
( display_errors = Off )
function sqli_secure($value){
return str_replace("'", "''", $value);
}
이런식으로 공통부분에 함수를 만들어서 사용해도 편함
ORACLE의 경우 MSSQL과 다른 부분이 없다.
SQL INJECTION 공격의 공통점
- SQL 문법이 들어가고, 공격 페이로드가 길다
- 특수문자가 반드시 들어간다
이를 시큐어 코딩에 적용하여야 한다
에필로그
취약점 분석 > dbms 파악 > 인증우회 / 시스템 명령어 실행 > 데이터 조회 공격
>> 웹페이지 출력시 Union-Based 공격
>>> 웹페이지 출력X dbms 에러 출력시 Error-Based 공격
>>> 웹페이지 출력X dbms 에러 출력X Blind-Based 공격
UNION-Based
1) Order by 구문 확인
2) UNION 구문 확인
3) 출력 포지션 파악 후 공격
ERROR-Based
- 공격 페이로드 검증 후 공격
BLIND-Based
- 기준문자를 통해 Content-Based, Response-Based, Time-Based 등 순차, 이진, 비트단위 탐색 후 공격
* 메타데이터 목록화는 손으로 쓸 수 있을 정도로 암기하여 숙지할것
자동화도구의 양면성
편리하지만, 반대로 진단자를 바보로 만들 수 있음
프로세스대로 수동으로 1-2가지 결과를 확인한 후 자동화 도구를 이용하는 것을 권장
취약점은 있는 것 같은데, 자동화 도구를 돌렸는데 데이터가 나오지 않을때 => 원인을 파악할 수 있어야 함
커스터마이징을 통해 자동화도구를 직접 만드는 것 추천
추가로 필요한 실습
1) CASE WHEN 데이터 조회 실습
2) 숫자형, 테이블, 컬럼 입력값에 데이터조회 공격 실습
3) 숫자형, 테이블, 컬럼 입력값에 싱글쿼터 필터링이 존재할 때
4) 한글 데이터 추출
'정보보안 > 모의해킹' 카테고리의 다른 글
모의해킹 강의(SQL Injection Part1) 9 UNION-BASED (0) | 2024.10.26 |
---|---|
모의해킹 강의(SQL Injection Part1) 8 ERROR-BASED (0) | 2024.10.24 |
모의해킹 강의(SQL Injection Part1) 7 - 메타데이터 (주기적으로 복습) (0) | 2024.10.22 |
모의해킹 강의(SQL Injection Part1) 6 (0) | 2024.10.21 |
모의해킹 강의(SQL Injection Part1) 5 (0) | 2024.10.18 |