보안을 그리다, 훈이

[Web Hacking] SQL Injection 실습 본문

Security/Web Hacking

[Web Hacking] SQL Injection 실습

HooNeee 2021. 5. 12. 19:04

 

이전에 포스팅한 [Web Hacking] SQL Injection 취약점을 토대로 실습을 진행해보았다.

 

[SQL Injection 실습]

- Error based SQL Injection

 

논리적 에러를 이용한 SQL Injection 기법으로, 입력값에 대한 검증이 없을 시 참값과 주석을 활용하여 세션을 탈취할 수 있다.

//입력된 아이디가 DB에 존재하는지 검사
$query = "select * from member where id='$id'";
$result = $connect->query($query);

앞서 제작한 게시판 웹페이지 중 [login_action.php] 페이지의 일부 소스코드를 가져왔다.

 

사용자가 입력한 아이디가 DB의 id 컬럼에 존재하면 그 값에 대한 전체 속성값을 가져오는 쿼리문을 통해 id 존재 여부를 파악하게 되는데, 입력값에 대한 검증이 존재하지 않기 때문에 이 부분을 악용하여 모든 권한을 가진 관리자 세션을 탈취할 수 있다.

 

//아이디가 있다면 비밀번호 검사
if (mysqli_num_rows($result)) {     //($result) == 1 에서 수정!

    $row = mysqli_fetch_assoc($result);

    //비밀번호가 맞다면 세션 생성
    if ($row['password'] == $pw) {    //password 평문비교 취약!
        $_SESSION['userid'] = $row['id'];

필자가 구현한 소스코드는 위와 같이 id와 password 검증 과정이 따로 발생한다. 즉, 입력한 id 값이 속해있는 튜플의 password 속성값을 password 입력값과 비교하기 때문에, id 입력 폼을 통한 탈취만 시연하도록 하겠다.

 

$query = "select * from member where id='$id'";

다시 입력한 id 값과 일치하는 DB 내 튜플의 전체 속성값을 불러오는 쿼리문을 살펴보면 where 절을 참으로 만들면 취약점이 발생하게 된다는 것을 알 수 있다.

로그인 페이지의 id 입력 폼에 필자가 주입한 임의의 SQL 구문은 ' OR 1=1 -- 이다. 주석처리 이후엔 꼭 띄어쓰기를 해야된다. 안 했다간 저처럼 고생합니다ㅜㅜ

 

여튼 저 구문을 쿼리문에 주입해보면..

$query = "select * from member where id='' OR 1=1 -- '";

이렇게 된다. ' OR 1=1 -- 에서 첫 싱글쿼터(')는 앞에 생성된 싱글쿼터를 닫아주는 역할을 하고 OR 연산자로 두 개의 식 중 하나만 참이면 결과값은 참이 되도록 한다. 1=1은 역시 참이며 뒤의 주석처리( -- )는 뒤에 생성된 싱글쿼터를 주석처리하여 식에 오류가 생기지 않도록 한다. 따라서 where 절은 참이 되며 첫 번째로 생성된 관리자 계정 계정을 탈취할 수 있다.

게시판 등록 계정 조회

위와 같이, hooneee 계정의 permit = 1을 보면 모든 권한이 주어져있으며 관리자 계정인 것을 유추할 수 있다.

일반적으로 가장 먼저 생성된 계정은 많은 권한이 주어진 관리자 계정일 확률이 크기 때문에 SQL Injection에 대한 대응처리가 미비하다면 악의적인 사용자로 하여금 DB의 모든 자료에 접근, 생성 및 수정, 삭제까지도 할 수 있는 기회를 제공하는 것이다.

만약 그 정보가 고객들의 개인정보라면, 탈취한 개인정보를 유출한다면 더욱 심각한 상황에 직면할 수 있기에 개발 초기부터 경각심을 가지고 보안사항을 언제나 고려하고 관리해나가야 된다.

 

실제로 필자가 구현한 페이지에서 실습해보면,

게시판 로그인 페이지 SQL 구문 주입 과정
게시판 로그인 페이지 SQL 구문 주입 결과

 

id 값에 ' OR 1=1 -- 을 입력했음에도 불구하고, 왼쪽 상단을 보면 'hooneee님 반갑습니다.' 라며 환영인사를 해준다. 재미있다...

 

$query = "select * from member where id='$id' && pw='$pw'";

만약 쿼리문이 위와 같이 입력된 id 값과 pw 값이 && 연산자를 통해 한 쿼리문 내에서 조회된다면,

$query = "select * from member where id='' OR 1=1-- ' && pw='$pw'";

이처럼 ' OR 1=1 -- 의 주석처리를 사용하여 && 이후 구문인 pw 절까지 무효화시킬 수 있다. 또한 ' OR '1'='1' -- 도 참 값이므로 가능하며 다른 식을 사용해도 무방하다. pw 값을 입력 하지 않아도 관리자 계정으로 로그인됨을 확인할 수 있었다.

 

Comments