오늘은
제로보드의 SQL 취약점을 살펴볼 것이다.
그 중에서 PHP File Download 취약점을 살펴 볼 것이다.
지난 글에서 만들었던 게시판에서 글을 확인해 보면
다운로드 옆에 숫자가 보이는데
다운로드 횟수를 보여준다.
(다운로드 횟수)
바로 이 횟수가 DB에 저장된 값 중 하나인데
이 페이지의 소스코드를 분석해보자
다운로드를 클릭하면 download.php 파일로 이동하는 것을 확인 할 수 있다.
(download.php 파일 이동)
download.php?id=gogo_test&page=1&page_num=20&category=&sn=off&ss=off&sc=off&keyword
=&prev_no=&select_arrange=headnum&desc=asc&no=19&filenum=1
코드를 보면 download.php 파일로 GET방식으로 변수들의 값을 가져가고 있는 것을 확인 할 수 있다.
그렇다면 download.php 파일을 확인해보자.
(download.php 파일)
소스 코드를 보면 44번 행에
mysql_query를 볼 수 있다.
(SQL 구문)
mysql_query("update $t_board"."_$id set douwnload".$filenum."=download".$filenum."+1 where no='$no'");
이 구문인데 실행될 떄 어떤 SQL이 만들어져서 보내지는지 확인해 보겠다.
먼저 $t_board 변수인데
download.php 페이지에서는 이 변수를 정의하고 있지 않다.
대신
이 페이지의 위 쪽에 코드를 보면
require "lib.php"; 에서
즉 lib.php에서 이 변수를 정의하고 있는 것을 확인 할 수 있었다.
(lib.php 에서 정의)
확인한 결과
lib.php 39번라인에서 $t_board = "zetyx_board";로 정의 되어있었다.
또 나머지 변수는 GET 방식에서 넘어오는 변수들인 것을 확인 할 수 있다.
$id=gogo_test
$filenum=1
$no=19
즉, 이 값들을 토대로 해서
어떤 쿼리가 전송되는지 조합해보면
update zetyx_board_gogo_test set download1=download1+1 where no='19';
이러한 쿼리가 만들어져서 보내지는 것을 확인 할 수 있다.
실제로 이런 쿼리가 만들어지는지 확인해보자
먼저
SQL 로그를 기록되게 하기위해서 실행중인 SQL을 끄고 다시 실행하도록 하자.
(sql 종료)
종료 후 옵션을 걸어서 실행해 줄 것이다.
#> mysqld_safe --log=query.log &
로 실행하게 되면
로그가 기록되게 된다.
(로그 기록 실행)
기록되는 로그의 위치는
/var/lib/mysql 에 있는
query.log 파일이다.
(로그 파일 확인)
로그 파일을 열어둔채 다시 다운로드를 클릭하면
아래와 같이 로그가 기록되는 것을 확인 할 수 있다.
(로그 확인)
로그를 보면 우리가 예상했던 update 구문이 정확히 일치한다는 것을 볼 수 있다.
우리의 생각이 맞았던 것이다.
자 그렇게되면
우리가 조작할 수 있는 값은 3개
이 3개로 SQL구문을 Injection 할 수 있다는 것이다.
예를 들어 id변수를 hello로 바꿀 수 있다.
(SQL Injection)
(결과 화면)
그 결과 hello라는 게시판이 없어서 이런 페이지가 나왔고
아무 일이 이러나지 않았다.
두번 째로 no변수를 1로 바꾸어 보았다.
(no 변조)
no 1의 게시 다운로드1 의 횟수가 1 추가되었는지 확인해보자
mysql에 들어가서 아래와 같이 확인해본다.
(확인)
(1 추가)
확인해본 결과 1이 증가했다는 것을 볼 수 있다.
그렇다면 마지막으로 filenum?
$filenum=1=100
으로 하면 어떻게 될까?
그렇게 되면
update zetyx_board_gogo_test set download1=100=download1=100+1 where no='19';
이 되게 되고 문법에 맞지 않아 실행이 되지 않는다.
하지만 이러한 변조는 아마 눈치 챘을 거라 생각한다.
바로 다운로드 횟수 100으로 바꿀 수 있다는 가능성이 있다는 것이다.
(다운로드 회수 100 조작)
하지만 뒤에 문법이 맞지 않는다는 것이 문제다.
그렇다면 뒷 부분을 주석처리할 수 있다면?
주석 : --, /* */, #
예를 들어
update zetyx_board_gogo_test set download1=100#=download1=100#+1 where no='19';
이렇게 되게 하기 위하여
filenum에다가 1=100# 을 넣는다면
뒷부분은 주석처리 되고 다운로드1의 횟수가 100이 되는 SQL 명령이 된다.
(SQL Injection)
(실행 결과)
실행 결과 로그를 확인해보니 #이 빠져있다..!
바로 URL에서 입력할 때 특수 문자는 URL Encoding이 되기 때문이다.
* URL encoding
- URL에서 사용하는 특수문자
- 공백: +, %20 (아스키 코드)
- 문자에 해당하는 아스키코드 앞에 %를 붙여주면된다.
# -> %23
그렇기 때문에 주석 처리를 위한 # 대신에 %23을 사용한다면?
(%23 사용)
결과 다운로드 수가 100으로 적용된 것을 볼 수 있다.
(100 적용)
그리고 뒤에 where 조건이 없었으므로 아마 모든 글의
다운로드1 횟수가 100으로 됬을 것이다.
(100으로 적용됨)
이 때 사용된 쿼리문을 로그에서 확인해보면
(쿼리 확인)
#이 아까처럼 사라지지 않고
남아서 주석처리 역할을 한것을 볼 수 있다.
그렇다면~?
이러한 SQL Injection을 이용해 XSS공격을 할 수 있을까?
예를들어 update구문을 이용해 게시글에 스크립트를 추가하도록 하는 것이다.
그렇게 되면 스크립트 차단을 해놨어도 우회할 수 있는 길이 생기게 된다.
먼저 게시글이 DB의 어떤 컬럼에 저장되는지 확인한다.
(게시글 내용)
확인해본 결과 게시글은 memo라는 컬럼에 데이터가 저장되는 것을 확인 할 수 있다.
우리는 그냥 update를 사용하면 원래 글 내용이 사라지므로
원래 글 뒷부분에 스크립트를 추가해보겠다.
이를 위해 concat이라는 함수가 있다.
바로 문자열을 연결해주는 함수이다.
(concat)
위 처럼 문자열을 연결해주는 역할을 한다.
우리는 이것을 이용하여
concat(memo, '스크립트') 를 사용할 것이다.
그렇게 되면 아래와 같은 url이 나온다.
(공격에 사용된 url)
실제 적용해보면
예상되는 쿼리는
update zetyx_board_gogo_test set download1=100, memo=concat(memo, '<script>alert(\'attack!!\') </script>') #=download1=100#+1 where no='19';
이렇다.
게시글 뒷부분에 스크립트 코드가 추가되는 것이다.
(SQL Injection 실행)
실행 후 로그를 확인해보면
(로그 확인)
우리가 예상한 대로 SQL 명령이 전달 된 것을 확인 할 수 있다.
우리가 where 조건을 주지 않았기 때문에
모든 글에 스크립트가 들어가서
(XSS 공격)
XSS 공격 팝업 창이 뜰 것이다.
게시글의 코드를 확인해보면
(스크립트 코드 추가)
스크립트 코드가 추가된 것을 확인 할 수 있다.
간단하게 이러한 Injection을 막기 위해
magic_quotes_gpc 라는 설정을 켜둔다. GPC(Get, Post, Cookie)
하지만 5.4버전부터 이 설정이 사라져있다. (성능 때문에)
설정의 vi /etc/php.ini
파일에서 483번 라인을 On 해주면 된다.
(설정)
이렇게 되면 문자열 입력이 안된다.
한번 해보겠다.
단순히
download.php?id=gogo_test&page=1&page_num=20&category=&sn=off&ss=off&sc=off&keyword
=&prev_no=&select_arrange=headnum&desc=asc&no=19&filenum=1=100,%20me
mo=concat(memo,'injection test !')%20%23
이렇게 게시글에 injection test! 문자열을 추가해볼것이다.
(SQL Injection)
실행 후 SQL 로그를 확인해 보면
(로그 확인)
' 쿼터 앞에 \ (역슬래쉬)가 붙은 것을 볼 수 있다.
그래서 '가 문자열의 역할을 못하게 되어 SQL Injection이 되지 않았다.
=> 문자열 인젝션은 따옴표를 적어줘야하는데
여기서 magic_quotes_gpc 설정을 해주면 문자열 따옴표가 escape되서
문자열을 나타내지 못하게 된다.
그러므로 문자열 인젝션이 불가능하게 된다.
하지만 이걸 켜주게 되면
모든 입력에 대해 전부 체크하게 된다.
-> 쿼리문이 없더라도 입력값을 전부 체크하기 때문에 성능이 떨어지게 된다.
그렇기 때문에 사라진 것이다. 만들때 함수를 이용하여 체크할 수 있도록 해둔 것이다.
=> 설정에서 빠진 이유이다.
'Hacking > Web Hacking' 카테고리의 다른 글
WebHacking - Information_schema이용 SQL Injection (0) | 2017.02.27 |
---|---|
WebHacking - SQL Injection(우회), Blind SQL Injection (0) | 2017.02.24 |
WebHacking - 기초 SQL (0) | 2017.02.23 |
WebHacking - Include 취약점, SQL (0) | 2017.02.22 |
WebHacking - File Upload 취약점 (우회), Web SHell(웹 쉘) (0) | 2017.02.21 |