'Study > 안드로이드' 카테고리의 다른 글
aarch64에서 LD_PRELOAD Injection을 통한 함수후킹(실패) (0) | 2017.04.10 |
---|---|
JDB이용하여 앱 동적 분석하기 (0) | 2017.02.13 |
안드로이드 재서명 하기 (2) | 2016.05.08 |
안드로이드 apk서명 (0) | 2016.05.02 |
안드로이드 apk꺼내기 (0) | 2016.05.02 |
aarch64에서 LD_PRELOAD Injection을 통한 함수후킹(실패) (0) | 2017.04.10 |
---|---|
JDB이용하여 앱 동적 분석하기 (0) | 2017.02.13 |
안드로이드 재서명 하기 (2) | 2016.05.08 |
안드로이드 apk서명 (0) | 2016.05.02 |
안드로이드 apk꺼내기 (0) | 2016.05.02 |
File Download 취약점
외부 입력 값에 대해 경로 조작에 사용될 수 있는 문자를 필터링 하지 않으면, 예상 밖의 접근 제한 영역에 대한 경로 문자열 구성이 가능해져 시스템 정보누출, 서비스 장애 등을 유발 시킬 수 있는 취약점
출처: http://skynarciss.tistory.com/37 [IT 보물창고]
1. 대상 확인
작성된 게시글의 첨부파일을 다운받는 페이지를 살펴봅시다.
업로드된 파일명을 클릭하면 다운로드를 받을 수 있습니다.
Burp Suite를 이용하여 파일 다운로드 요청이 어떻게 전송되는지 살펴보겠습니다.
파일 다운로드를 하기 위해 fileDown.jsp로 요청을 보내는데, 파일명을 GET방식으로 fileName이라는 파라미터에 값을 셋팅하여 전송하고있습니다.
GET방식이기 때문에, 같은 url을 입력하면 파일을 다운 받을 수 있습니다.
2. 로직
이 게시판에서 파일을 다운받게 해주는 로직을 추측해보고, 실제 소스코드를 봅시다.
1. GET 파라미터인 fileName에 파일명이 전달된다.
2. 파일 업로드 시 파일을 저장한 저장 디렉토리의 위치에 파일명을 덧붙혀 파일경로를 완성한다.
3. 해당 파일 경로에 있는 파일을 클라이언트로 전송한다.
실제 소스코드를 보면 위에서 추측한 로직과 동일한 것을 알 수 있습니다.
이 게시판은 C드라이브 아래에 있는 save_dir 디렉토리에 파일을 저장하고 있었네요.
3. 공격
File Download 취약점이 존재하는 지 알아 보기 위해 디렉터리 이동 명령어들이 실행 되는지를 아래와 같이 확인해 볼 수 있습니다.
파라미터는 test/../148609......jpg 의 형태로 입력이 되었습니다.
이 파일 명이 의미하는 바는 잘 아시다시피 현재 경로에서 test디렉터리 아래 -> 한 단계 상위 -> 에 있는 148609......jpg가 됩니다. test디렉터리 아래 -> 한 단계 상위는 서로 상쇄되어 결국 148609......jpg가 되는 것인데,
이 테스트의 의미는 디렉터리 이동 명령어들이 필터에 걸리지 않는 지, 혹은 다른 조치가 되어 있는 지를 확인하는데 의미가 있습니다.
위 테스트를 하였을 때 성공적으로 튤립 그림을 다운받을 수 있었으므로, File Download취약점이 있다고 보여집니다.
파일 이동 명령어가 실행이 되는 상태라면 자유자재로 서버의 파일들을 다운 받을 수 있습니다.(물론 원하는 파일의 위치를 알아야겠지만요)
이 게시물에서는 예시로 C:/Window/System32 경로에 test.txt파일을 만들어서 공격 예시를 들어보도록 하겠습니다.
구조는 어렵지 않고 다만 파라미터에 원하는 경로를 조립하여 넘겨주었습니다.
결과적으로 해당 경로에있는 test.txt파일을 다운 받을 수 있었습니다.
4. 조치 방법
각 개발 프레임 워크 별 설정방법이 있는 것 같습니다만, 우리 게시판 프로젝트는 순수 jsp로 짜여진 게시판이므로ㅠㅠ 간단한 필터링을 통해 조치를 해보도록 하겠습니다.
위의 소스코드와 같이 입력받은 파라미터를 곧바로 사용하지 않고 디렉터리 이동에 사용되는 문자("\.", "..", "/"들을 공백으로 치환해주었습니다.
그리고 파일이 존재 하지 않는 경우에는 (더 좋은 처리가 있겠지만..) 더미 파일을 전송하도록 하여 처리를 했습니다.
jspBoardProject#4(SQL Injection / Blind SQL Injection) (0) | 2017.02.07 |
---|---|
jspBoardProject#3(파라미터 변조) (0) | 2017.02.06 |
jspBoardProject#2(XSS) (0) | 2017.02.06 |
jspBoardProject#1 (0) | 2017.02.06 |
SQL
RDBMS(Relation DataBase Management System)의 데이터를 관리하기 위해 설계 된 특수 목적 프로그래밍 언어로써 쉽게 말해 데이터베이스를 핸들링 하기 위해 사용하는 언어입니다.
SQL Injection
응용 프로그램 보안 상의 허점을 의도적으로 이용해, 개발자가 생각지 못한 SQL문을 실행되게 함으로써 데이터베이스를 비정상적으로 조작하는 코드 인젝션 공격 방법입니다.
[출처] 위키백과(https://ko.wikipedia.org/wiki/SQL_%EC%82%BD%EC%9E%85)
Blind SQL Injection
SQL Injection의 결과를 이용하여 참, 거짓 값을 구별 할 수 있을 때 사용할 수 있는 방법으로 장님이 길을 지팡이로 짚으며 가는 듯한 과정이 있어 이를 Blind SQL Injection이라고 합니다.
1. 대상 확인
언제나 처럼 게시판을 이용하여 정리해보도록 하겠습니다.
먼저 게시판의 검색 부분을 살펴보겠습니다.
검색조건을 선택하고 검색 키워드를 입력한 후 검색 버튼을 누르면 해당하는 내용을 검색 할 수 있습니다.
검색 조건은 작성자 / 키워드 / 작성자 + 키워드이며 공란인 경우 아래와 같은 알럿메시지를 표출합니다.
검색에 이용되는 키워드는 쿼리 작성에 사용이 될텐데 검색 후 URL에 파라미터가 표시되지 않는 것으로 보아 POST방식으로 파라미터가 전달 되고 있는 것 같습니다.
검색 할 당시의 패킷을 Burp Suite로 확인 해보도록 하겠습니다.
위에서 추측한대로 검색에 관련된 파라미터들(검색 조건/검색 키워드)이 POST방식으로 전달되고 있는 것을 확인 할 수 있습니다. (searching_condition=title&searching_keyword=TE)
2. 우회 과정
이 키워드에 전달되는 파라미터에 쿼리를 인젝션하여 특정 게시물의 비밀번호를 알아내보겠습니다.
결론부터 이야기하자면 인젝션하여 서버에서 실행 될 쿼리의 예시는 아래와 같습니다.
SELECT letterNum, userID, letterTitle, secretYN
FROM board
WHERE userID LIKE '%USER%'AND ((ascii(substr((SELECT letterPW from board where letterNum = 6), 1, 1))) = 48)#%'
현재 서버에서 실행되고 있는 쿼리는
SELECT letterNum, userID, letterTitle, secretYN
FROM board
WHERE userID LIKE '%{INPUT}%'
의 형태이고, 이 INPUT안에 쿼리를 삽입하여 위처럼 공격 쿼리를 만들어 내야합니다.
(지금은 직접 개발한 게시판이기 때문에 DB정보와 쿼리문의 구조를 알고있지만,
실제로는 추측/유추 해야하는 과정이 필요합니다.)
따라서 INPUT에 삽입될 쿼리는 아래와 같습니다.
USER%'
AND ((ascii(substr((SELECT letterPW from board where letterNum = 6), 1, 1))) = 48)#%'
AND 뒷 부분이 핵심이므로 이 부분을 상세히 살펴보도록하겠습니다.
1) SELECT letterPW FROM board WHERE letterNum = 6
-> 이 예시에서는 게시글 번호 6번 글에 대한 패스워드를 유추하고 있습니다. 따라서 6번 게시물의 패스워드를 조회해 옵니다.
2) substr( 6번게시물 패스워드, 1, 1)
-> mysql에서 실행되는 함수로 문자열의 첫 번째 글자부터 한 글자를 조회해옵니다.
-> 결과적으로 6번 게시물 패스워드의 맨 첫 글자를 가져올 수 있습니다.
3) ascii(문자)
-> 해당 문자를 아스키 코드 값으로 변환해줍니다.
4) 결과
6번 게시물 패스워드의 첫 글자의 아스키코드가 아스키코드 값 48과 같은 지를 반환합니다.
위의 결과가 true인 경우, 원래의 쿼리와 결과가 종합되어 모든 게시물이 출력되고(true and true이므로),
false인 경우 게시물 조회 결과가 없음으로 표시됩니다.
패스워드를 한 글자씩 찾는 스크립트가 필요합니다.
스크립트 풀 소스는 첨부 하고, 주요 부분만 확인하도록 하겠습니다. : )
실습환경이기때문에, 비밀번호는 숫자와 영대소문자로만 이루어져있다는 가정을 하였습니다.
스크립트는 파이썬으로 작성하였으며 스크립트 실행 전 설치해야할 파이썬 라이브러리로는
http리퀘스트를 위한 requests와 결과를 파싱하기 위한 Beautifulsoup가 있습니다.
헤더 값은 Burp Suite에서 얻은 패킷의 값과 동일하게 맞추어주고, 파라미터를 변경합니다.
우리가 수정해서 삽입할 쿼리를 완성시킨 executeSql을 키워드 파리미터에 셋팅해줍니다.
requests를 이용하여 리퀘스트를 보내고 받은 결과를 BeautifulSoup를 사용하여 파싱합니다.
해당 게시판의 list.jsp 응답 내용 중 "총 게시물 : x개" 로 body에 응답이 오는데 이 부분을 파싱하여
0개인 경우에는 찾지 못한 것으로, 0개 이상인 경우에는 찾은 것으로 판별하였습니다.
아래는 파싱하여 게시물의 갯수를 int형으로 변환하여 리턴해주는 함수입니다.
첫 째줄에서는 공백을 제거하였고, ":"로 스플릿한 뒷부분을 공백제거하여 이 후
첫 글자를 int형으로 변환한 후 리턴해줍니다.
비교할 검사 문자는 0~9, a ~ z, A ~ Z 입니다. 각 문자들이 아스키 코드표 상 연속되어 존재하지 않기 때문에
구간 구간 점프를 뛰어야하는 부분을 if문으로 걸러주었으며, 찾는 문자 구간에 문자가 없으면 패스워드의 끝으로 인식하고 있습니다. ( elif int(asciiNum) > 122 부분)
문자를 찾은 경우에는 targetPW라는 필드에 찾은 문자를 덧 붙혀주고, 검사 문자 순서를 다음으로 넘긴 후
비교 문자를 0('48')로 초기화 시켜주고, 쿼리문을 갱신합니다.
위 과정을 모두 마친 후 추출해낸 패스워드를 확인합니다.
스크립트 실행 결과
3. 조치 방법
1. 에서 조치했던 것 처럼 입력 값에 필터링을 수행하여 검사할 수 있습니다.
2. JAVA/JSP에서는 쿼리 실행을 Statement클래스를 사용하지 않고 PreparedStatement를 사용하는 방법이 있습니다.
필터링에 관해서는 앞서 다뤄본 방식과 별반 다르지 않기 때문에, PreparedStatement를 사용하는 방법으로 조치해보도록 하겠습니다.
먼저, 문제가 되는 부분의 소스코드를 살펴보면,
아래와 같이 변수가 쿼리에 직접적으로 연결되는 구조로 Injection하기 너무나 편리하게 되어있는 것을 확인 할 수 있습니다.
이 부분을 PreparedStatement 인터페이스를 사용하여 다음과 같이 조치 할 수 있습니다.
바뀐 점은 일반 Statement인터페이스에서는 쿼리와 Input value가 직접적으로 연결되어 실행이 되지만,
PreparedStatement에서는 쿼리문에서는 ? 로 인자 표시를 하고 후에 setString과 같은 메서드를 사용하여
변수를 추가 해주고있습니다.
코드 수정 후 스크립트 결과를 보면 아래와 같이 조치가 된 것을 확인 해볼 수 있습니다.
여담.
order by 뒷 부분 역시 PreparedStatement방식으로 사용 해보려고했으나, setString(4, sorting_cond); 와 같은 방식으로 추가했을 때 sorting_cond가 상수 값으로 인식되어 정상적으로 정렬이 되지 않았습니다.
외부에서 직접적으로 입력을 받는 부분이 아니기때문에 문제가 없을 것으로 생각되어 기존처럼 쿼리에 연결을 하였습니다.
jspBoardProject#5(File Download) (0) | 2017.02.08 |
---|---|
jspBoardProject#3(파라미터 변조) (0) | 2017.02.06 |
jspBoardProject#2(XSS) (0) | 2017.02.06 |
jspBoardProject#1 (0) | 2017.02.06 |
파라미터 변조
- 클라이언트와 서버 사이에서 주고받는 파라미터 값을 조작
- 매개변수라고 하며 웹페이지상에서 request에 대한 값을 가지고 있는 변수
- 사용자 기밀정보, 허가, 상품의 개수, 가격 등을 조작
- 이러한 정보는 쿠키나 숨겨진 폼 필드, UR 쿼리 문자열 등에 저장
출처: http://elmosec.tistory.com/4 [보알못 엘모의 보안 겅부 필기 공책 :)]
게시판으로 예시를 들어보도록 하겠습니다.
게시판의 메인 페이지입니다. 여러 글들이 있고, 그 중 비밀글인 글들이 보입니다.
파라미터 변조를 통해 비밀글에 접근을 해보도록 하겠습니다.
1. 대상 확인
1.1) 비밀글을 열람하려고 글을 클릭하면 비밀번호를 묻는 페이지가 나오고, 비밀번호가 틀리면 비밀번호가 틀렸다는 얼럿이 나타납니다.
1.2) 서버에 날아가는 요청을 프록시 툴인 Burp Suite로 분석을 해보겠습니다.
우선, 요청 url은 openSecret_ok.jsp이며,
POST방식으로 입력한 패스워드가 평문으로 전송되고, 비밀 게시글의 번호가 idx라는 GET파라미터로 전송되고 있습니다.
이 페이지(openSecret_ok.jsp)에서 글의 인덱스와 비밀번호를 파라미터로 받아서 패스워드 검사를 하였는지, 비밀번호가 틀렸다는 알럿 메시지가 뜨는 자바스크립트를 응답으로 받았습니다.
2. 로직 분석
메인 아이디어는 아래와 같습니다. 이 게시판 서비스는 openSecret.jsp에서 비밀번호를 입력 받은 후 openSecret_ok.jsp에서 인증을 하여 인증에 성공한 경우 view.jsp에서 서비스가 실행 되는 구조로써 인증과 서비스 로직이 분리되어 있어 이 점을 이용하였습니다.
3. 우회 시나리오
1) openSecret_ok.jsp 에서 인증가능한 파라미터를 전달합니다.
- 하나의 새 글을 작성하여 패스워드를 알고있는 글을 만들었습니다.
2) openSecret_ok.jsp의 인증을 따낸 후 view에 글을 열람할 인덱스를 전달 할 것이므로, 이 인덱스를 우리가 원하는 비밀글의 인덱스로 변경하여 전달합니다.
사실 비밀글이 아닌 곳에서 view.jsp에 전달되는 get 파라미터만 변경하여도 비밀글에 접근이 가능했었습니다..ㅋㅋ
조치 방안에서는 이 두 가지 문제점 모두 수정하였습니다. :)
4. 우회 과정
4.1 시나리오에서 언급했던 것 처럼 새 글을 비밀번호 1234로 하여 작성하였습니다.
4.2 비밀번호 입력 후 패킷을 변조해봅시다.
패스워드를 1234로 변경하였고(입력할 때 부터 1234로 입력해도됩니다.), 인덱스가 원래 4였지만 18(우리가 게시한 글의 인덱스)로 수정하였습니다.
4.3 인증에 성공하자 예상한 대로 view.jsp에 GET방식으로 파라미터를 인덱스로 던지고 있습니다. 이 부분을 4(비밀게시글 인덱스)로 수정해보겠습니다.
4.4 우회 성공
5. 조치 과정
5.1 조치 전 소스 코드
openSecret_ok.jsp
view.jsp
위 로직의 가장 큰 문제점(본인이 짰지만..)이라고 생각한 건 위에서 말한 것 처럼 인증 로직과 서비스로직이 분리되어 있기 때문에 이 같은 취약점이 발생했다고 생각했습니다.
openSecret_ok.jsp에서는 인증만을 수행하고 view.jsp에서는 글을 보여주는 서비스 로직만 있으므로, 생각해낸 방법은 openSecret_ok페이지를 삭제하여 인증 과정을 view.jsp페이지에 넣는 방법을 사용해보기로 하였습니다.
5.1 조치 후 소스 코드
먼저, openSecret.jsp의 소스에서 입력 내용을 openSeceret_ok.jsp로 전송하던 부분을 view.jsp로 전송하도록 수정하였습니다.
이후 view.jsp에서는 pw를 추가로 파라미터로 수신하며, 비밀글 여부 체크 후 비밀번호 인증하는 로직을 추가하여 조치하였습니다.
jspBoardProject#5(File Download) (0) | 2017.02.08 |
---|---|
jspBoardProject#4(SQL Injection / Blind SQL Injection) (0) | 2017.02.07 |
jspBoardProject#2(XSS) (0) | 2017.02.06 |
jspBoardProject#1 (0) | 2017.02.06 |
XSS
XSS(Cross-site Scripting)는 웹 상에서 가장 기초적인 취약점 공격 방법의 일종으로, 악의적인 사용자가 공격하려는 사이트에 스크립트를 넣는 기법을 말합니다.
스크립트가 삽입 가능할 때 쿠키 탈취, 악성코드 유포, 특정 사이트로 납치 등 많은 공격이 가능 합니다.
게시판으로 예시를 보도록 하겠습니다.
게시판에 글을 작성 하며 글 내용에 알림창을 띄우는 간단한 자바스크립트를 삽입하였습니다.
해당 글을 열람하기위해 제목을 누르는 순간 삽입한 javascript 코드가 실행 되는 것을 확인 할 수 있습니다.
게시판의 글 작성 로직을 살펴보면
1. write.jsp에서 작성자 / 제목 / pw 등의 입력을 받는다.
2. write.jsp에서 입력 값의 유효성을 검사한다.
3. wirte_ok.jsp에서 게시글을 DB에 등록한다.
위 과정을 통하여 글이 작성되는 것을 살펴 볼수 있습니다.
아래의 자바스크립트 코드는 위 과정 중 2번에 해당하는 부분으로 클라이언트가 글을 작성 한 후 그 컨텐츠의 유효성을 체크하는 코드입니다.
보이는 것처럼 글을 작성할 당시 각 필드의 값이 빈 값인지 여부만을 확인 하고 있습니다.
이 코드만 보면.. 글 제목과 작성자 란에도 스크립트 삽입이 가능하며, 메인페이지만 열어도 스크립트가 실행되어 방문자 모두가 스크립트를 실행하게 될 수 도있 습니다.
이제 이 유효성 검사 부분을 수정하여 XSS를 방어하는 방법 중 입력 내용을 필터링 하도록 수정해보도록 하겠습니다.
각 필드의 공백 유효성 검사 한 후 공백이 아닌 경우 스크립트에 포함되는 문자열들을 빈문자열 혹은 다른 문자열로 대체하도록 필터링을 하는 코드를 추가하였습니다.
결과로 같은 스크립트를 삽입하였을 때 아래와 같이 게시글이 필터링되어 게시됩니다.
jspBoardProject#5(File Download) (0) | 2017.02.08 |
---|---|
jspBoardProject#4(SQL Injection / Blind SQL Injection) (0) | 2017.02.07 |
jspBoardProject#3(파라미터 변조) (0) | 2017.02.06 |
jspBoardProject#1 (0) | 2017.02.06 |
JSP를 사용하여 간단하게 게시판을 만들고 취약점을 찾아 진단, 조치까지 해보기로 하였습니다.
게시판을 만드는 과정은 소스코드를 첨부 : jspBoardProject.zip하는 것으로 생략하고
취약점을 진단하고 조치하는 과정에 초점을 맞추어 블로깅을 해보도록 하겠습니다.
급박하게 개발하느라 발로 짠부분도 있고, 후에 취약점 진단을 하기위해 일부러 취약하게 짠점도 있는데
양해부탁드립니다 ㅠㅠ
개발 환경은 아래와 같습니다.
개발환경
1. IDE : STS 3.8.3 / Dynamic Web Project
2. DB: mysql
간단하게 게시판의 형태를 살펴보도록 하겠습니다.
게시판의 메인화면입니다.
분석해볼 게시판의 기능은 크게
1. 일반/비밀 게시글 작성
2. 파일첨부 기능
3. 게시글 정렬 기능
4. 게시글 검색 기능
5. 게시글 삭제 기능
6. 게시글 수정 기능
일반적으로 게시판이 가지는 기능을 가지고 있습니다.
블로깅은 취약점 진단/해당 취약점 조치 식으로 진행 해보도록하겠습니다.
jspBoardProject#5(File Download) (0) | 2017.02.08 |
---|---|
jspBoardProject#4(SQL Injection / Blind SQL Injection) (0) | 2017.02.07 |
jspBoardProject#3(파라미터 변조) (0) | 2017.02.06 |
jspBoardProject#2(XSS) (0) | 2017.02.06 |
1. 서론
apk 파일은 Zip파일에서 확장된 형태로 Zip파일과 동일한 구조를 같습니다. apk의 구조를 알아보기 위해 Zip파일 구조를 알아보았습니다.
2. 본론
Zip 파일은 여러 개의 파일이 압축(혹은 압축되지 않은)되어 묶여 있는 파일이며 각 파일에 대한 내용이 담긴 헤더(Local file header)가 있고 이 헤더를 위한 각각의 헤더(Central Directory header)가 있으며 이 헤더들을 위한 끝판왕 헤더(End of Central Directory header)로 살펴볼 수 있습니다. 말로 풀어 이해가 잘 안되지만 그림으로 살펴보면 아래와 같습니다.
zip file 개요
2.1 ) End of Central Directory
End of Central Directory는 파일의 맨 마지막에 위치하고 있으며, 위에서 언급했 듯 Central Directory의 정보(시작 offset, 전체 Central Directory사이즈 등)를 가지고 있습니다. 즉, Zip파일 구조를 뜯어보려면 제일 먼저 End of Central Directory를 찾으면서 시작해야합니다. 하지만 End of Central Directory의 크기는 file comment때문에 가변적이고, 시작점을 단번에 찾기는 쉽지 않습니다.
file comment는 End of Central Directory의 맨 마지막에 위치하고, file comment를 제외한 상위 바이트들의 사이즈는 22바이트입니다. 따라서 file comment가 존재하지않는 경우 파일의 끝에서부터 22바이트 떨어진 지점 부터 End of Central Directory가 시작됩니다. End of Central Directory가 시작되는지 확인하기 위해서는 4바이트를 읽어 signature(0x06054B50)와 일치하는지 확인해여 확인 할수 있습니다.
종합해보면 End of Central Directory를 찾는 과정은 다음 처럼 생각해 볼 수 있습니다.
1) 파일 맨 끝에서부터 22바이트 떨어진 지점으로 파일포인터를 이동한다.
2) 해당 지점에서 4바이트를 읽는다.
3) signature와 일치하는지 확인한다.
4) 일치하지 않는 경우 파일의 상위로 파일포인터를 감아가면서 2) ~ 3)의 과정을 반복한다.
end of central dir signature 4 bytes (0x06054b50)
number of this disk 2 bytes
number of the disk with the
start of the central directory 2 bytes
total number of entries in the
central directory on this disk 2 bytes
total number of entries in
the central directory 2 bytes
size of the central directory 4 bytes
offset of start of central
directory with respect to
the starting disk number 4 bytes
.ZIP file comment length 2 bytes
.ZIP file comment (variable size)
End of Central Directory 구조
End of Central Directory의 시작점을 찾았다면 위에 서술된 구조를 참조하여, 차례대로 읽어드리면됩니다.
참고 : http://stackoverflow.com/questions/8593904/how-to-find-the-position-of-central-directory-in-a-zip-file
End of Central Directory에서 Central Directory들의 첫 시작 offset을 읽어 파일포인터를 이동시킴으로써 Central Directory를 읽을 수 있습니다.
2.2) Central Directory
Central Directory는 zip파일에 포함된 파일들의 정보를 가지고 있는 Local header의 정보(Local header의 offset, 파일명, 압축사이즈 등)를 가지고있습니다. End of Central Directory에서 얻은 offset을 통해 Central Directory들의 첫 시작 주소를 찾았다면, 이 또한 역시 4바이트를 읽어 signature(0x02014B50)와 비교하여 검증을 해볼 수 있습니다. 일치 하지 않는다면, 위에서 offset을 잘못찾은 것입니다.
Central Directory들은 연속되어 존재합니다.
ex) 첫 번째 파일의 Central Directory -> 두 번째 파일의 Central Directory -> ....... -> N 번째 파일의 Central Directory
Central Directory의 구조는 아래와 같습니다.
central file header signature 4 bytes (0x02014b50)
version made by 2 bytes
version needed to extract 2 bytes
general purpose bit flag 2 bytes
compression method 2 bytes
last mod file time 2 bytes
last mod file date 2 bytes
crc-32 4 bytes
compressed size 4 bytes
uncompressed size 4 bytes
file name length 2 bytes
extra field length 2 bytes
file comment length 2 bytes
disk number start 2 bytes
internal file attributes 2 bytes
external file attributes 4 bytes
relative offset of local header 4 bytes
file name (variable size)
extra field (variable size)
file comment (variable size)
Central Directory 구조
Central Directory역시 파일명, extra field, file comment등의 가변 크기의 변수를 갖지만 사이즈를 가지고 있으므로, 읽는데 어려움은 없습니다. file comment의 끝에 바로 다음 Central Directory가 시작 되기 때문에 다음 Central Directory의 offset이 따로 존재 하지 않는 것으로 추측됩니다.
Central Directory에서 local header offset을 얻었으면 비로소 실제 파일에 접근 할 수 있는 local header에 도달할 수 있습니다.
2.3) Local file header
Local file header는 파일의 0번부터 시작하며, 순차적으로 N번째 파일까지 이어집니다.
Local file header에는 Zip파일 내부에 존재하는 각 파일에 대한 정보들(파일 명, 압축 메서드 정보, crc-32 등)을 가지고 있습니다.
Local file header뒤에는 압축에 암호화가 되어있는 경우와 암호화가 되어있지 않은 경우로 뒤에 위치하는 데이터가 다릅니다.
암호화가 되어있는 경우에는 encryption header가 뒤에 온 후 file data(압축 되어있거나 압축되지 않은)
암호화가 되어 있지 않은 경우에는 바로 file data가 오게 됩니다.
local file header signature 4 bytes (0x04034b50)
version needed to extract 2 bytes
general purpose bit flag 2 bytes
compression method 2 bytes
last mod file time 2 bytes
last mod file date 2 bytes
crc-32 4 bytes
compressed size 4 bytes
uncompressed size 4 bytes
file name length 2 bytes
extra field length 2 bytes
file name (variable size)
extra field (variable size)
Local file header 구조
3. 결론
Zip파일 구조를 파악하기 위해 가장 중요한 세 가지 헤더를 알아보았는데, 아직 부족한 점이 많습니다.
encryption 여부를 파악하여 실제 file data를 찾아내는 방법, file data뒤에 이어지는 file description파트, zip64에 따른 내용 등
Zip파일 전체 구조를 확실히 파악하기 위해서는 조금 더 연구를 해보아야 할 것 같습니다.
개인적으로는 한글 자료가 상세하게 되어있는 것이 없어서 짦은 영어끈으로 머리 싸매가며 연구해본 첫 경험이라 매우 뜻깊었습니다.
참고
1) 위에 분석 방법을 C로 개발한 프로젝트를 git hub에 올려두었습니다.
링크 : https://github.com/uisooshin/ZipAnalyzer
2) 위 내용은 아래의 링크에 상세 내용이 있습니다.
링크 : https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT
2017년도 블로그 결산! (0) | 2018.01.09 |
---|---|
Google I/O 2016 Extended Seoul 정리 및 후기 (4) | 2016.06.19 |
Arpspoofing (0) | 2015.10.16 |
실전 악성코드와 멀웨어 분석 Lab03_03.exe (0) | 2014.09.01 |
실전 악성코드와 멀웨어 분석 Lab03-02.dll (0) | 2014.08.29 |
2016년 6월 19일 세종대학교 광개토관 컨벤션홀에서 열린 Google I/O 2016 Extended Seoul에 다녀온 후 개인적으로 정리 / 후기를 남겨봅니다!
이 행사는 13:00 ~ 18:00 동안 50분 컨퍼런스 10분 휴식방식으로 5번 3개의 트랙이 진행되었습니다. 저는 안드로이드에 타겟을 맞추어 세션을 왔다 갔다하며 참여하였습니다! 꼼꼼히 적는다고 적었으나, 아는만큼 보인다고.. 알아들은 것 위주로 개인적으로 중요하다 생각했던 것 위주로 적어서 두서없이 정리가 되었네요ㅠ 정리한 내용은 아래와 같습니다.
1. 안드로이드 N을 준비하는 개발자를 위한 안내서 - 이승찬 (Track A)
1-1) Android N 진행 현황
Android N은 6월 15일에 공개된 API 즉, API24가 최종으로 배포될 예정이고 큰 결함이 없는 이상 수정없이 배포될 예정이라고 합니다. 또한 이전 배포한 마쉬멜로 이하 버전들은 항상 버그가 발견되거나 수정사항이 생겨서 일정이 조금씩 밀려서 10월 정도에 릴리즈가 되곤했다고 하는데, 이번 N버전은 일정대로 순항 중이고 현재 큰 버그가 없다면 8월 중에는 N버전 사용가능 단말(Nexsus, xperia)에 한해 릴리즈 유저가 생길 전망이라고 합니다!
1-2) Android N for Developer
Android N에 대처하는 개발자들에게 3가지 정도를 이야기했습니다.
1-2-1) Supproting Multiple Screens
기존에 많이 알려져있듯이 Android N 버전에서의 가장 큰 변화는 Supproting Multiple Screens 입니다. 단말의 화면을 분할하여 2개의 앱을 실행하는 기능인데요, 나뉜 화면 간 Drag and Drop까지 가능하다고 합니다.
Multiple Screens는 기본적으로 한 화면에 두 개의 Activity가 실행되지만 기존의 Activity생명주기라던지, Orientation과 같은 View 메커니즘 상의 변화는 없다고 합니다. 다만 유의할 점이 몇 가지 생겼습니다.
유의점
- 앱에서 화면을 landscape 또는 portrait로 제한하고 있는 경우 멀티스크린에서 view가 제대로 동작하지 않을 수 있으니 유의해야합니다.
- Screen Zoom이라는 기능은 안드로이드 접근성을 고려해 생긴 기능으로 말그대로 화면을 Zoom을 할 수 있는 기능입니다. 기존에 High performance device를 타겟으로 한 앱이라면 320dp의 리소스가 누락되어있을 수 있는데, 이런 경우에는 resource not found exception -> app crash 가능성이 있습니다.
- Chrome Book은 아직 국내에서 많은 인기를 얻고 있지는 못하지만 미국에서 진행된 Google I/O 2016에서는 상당한 관심을 보였던 분야라고 합니다. Chrome Book에서도 Multiple Screens를 고려한 개발이 이루어져야 한다고 합니다.
제가 유의점을 들으면서 종합적으로 이해한 내용은 기존의 버전에서 앱의 화면은 비교적 정적으로 지정되어있었다면 N버전부터는 내 앱이 어떤 화면에서 어떤 해상도로 어떻게 실행 될지 알수 없는 상황이 되고 많은 UI의 가능성을 고려하지 않으면 안된다는 내용이라고 이해했습니다.
물론 멀티스크린을 무조건 지원해야하는 것은 아닙니다. 멀티스크린을 지원하지 않게 지정하려면 엑티비티 설정 중 resizeableActivity를 false 값으로 셋팅하여 지원하지 않도록 설정 할 수 있습니다. 다만 이 resizeableActivity의 default값은 true이고, Activity_task의 root에 설정된 값을 나머지 task들이 모두 같은 값을 갖게 됩니다.
구체적인 방법은 아래와 같습니다.
if I can't support Multi-Window
1. targetSdk < 24, screenOrientation = portrait | landscape
2. targetSdk = 24
a. resizeableActivity = false
launchMode = singleInstance | singleTask
b. resizeableActivity = fase
documentLaunchMode = always
1-2-2) Battery Optimization
더 나은 앱을 위해서 모든 개발자들이 고민하는 요소 중의 하나인 베터리 최적화에 대한 내용을 이야기했습니다.
구글이 생각하는 Battery Optimization을 위해 Background Activity 3가지 원칙이 있었는데요,
1. Reduce
- 하지말자
2. Defet
- 해야되면 충전 할 때 하자
3. Coalesce
- 여러가지 작업을 한번에 몰아서 하자
이런 원칙을 지키기 위해서 Marshmallow버전부터 있었던 Doze mode라는 것을 N에 더 강화시켰다고합니다. 안드로이드 개발을 하고있다고 하면서도 처음듣는 내용이라서 매우 부끄러웠습니당ㅠㅠ
Marshmallow에서 Doze mode는 간단히 말해서 단말이 일정시간동안 움직이지 않고 스크린이 비활성화 되어있다면 네트워크 작업, 알람 작업 등의 백그라운드 작업이 멈추게됩니다. 이 기능이 Android N에서는 한층 더 강화되어서 이동 중일때에도 스크린이 비활성화 된 경우 Doze mode가 활성화 된다고하네요.
이런 Doze mode에 대한 앱 테스트를 진행 할 수 있는 방법은 아래의 adb 커맨드로 환경을 설정해서 테스트를 진행 할 수 있습니다.
adb shell dumpsys deviceidle step (light)
또한 베터리 관련해서 Battery Historian이라는 것을 이용하면 app의 베터리 사용량을 자세히 모니터링 할 수 있다고 하니 참고하시기바랍니다.
1-2-3) Memory Optimization
4. Android Studio 2.2(Preview 3 기준) - 김태호 (Track A)
새롭게 나올 Android Studio 2.2에 대해서 현재까지 나온 Preview 3을 기준으로 잘 설명해주셨습니다. 개인적으로 이 세션을 듣고나서 Android Studio 2.2에 대한 기대감이 엄청나게 올라갔습니다!
4-1) Design
4-1-1) 기존에 있었던 Visual Editor가 더욱 심플하고 파워풀해졌습니다.
몇 가지 눈에 띄는 것을 꼽아보자면 레이아웃 리소스 외 menu와 Preferences를 지원하고 에디터 내에서 스크롤 뷰의 스크롤 지원하며 속성 탭 개편을 통해 주요 속성화면과 전체 속성 화면간 전환이 이루어져서 굉장히 편리하게 개선되었습니다!
4-1-2) Constraint Layout
새롭게 추가된 Constraint Layout은 Visual Editor와 맞물려서 앱의 Layout과 View를 굉장히 간편하게 만들수 있게 되었습니다. XCode와 견주어도 더 좋으면 좋았지 떨어질 것 같지 않은 성능인 것 같았습니다. 세션 진행자 분께서 시연영상을 보여 주셨는데 기존에는 거의 xml로 작업했다면 제 기준으로 1~2시간은 족히 했을 작업을 10분도 안되서 뚝딱 하는 걸 보고 굉장히 놀랐습니다. 거의 프리젠테이션에서 도형그리기 수준(?)으로 보였습니다. 또한 기존의 레이아웃은 Relative Layout안에 Linear Layout이 배치되고, 또 안에 Layout이 배치되거나 View가 배치되는 구조가 일반적이였는데 Constraint Layout은 이러한 계층 구조를 가지지 않고 Constraint Layout안에 한번에 다 배치가 되는 구조라 계층구조가 굉장히 단순해지고 쉬워졌습니다!
4-1-3) Layout inspector
현재 표시되고 있는 단말기 (혹은 에뮬레이터)의 뷰 구조를 확인할 때 사용하는 툴인데요, 기존에 DDMS 내에 포함되어 있던 기능과 거의 유사하며 뷰 디버깅에 용이하다고 합니다. Android Monitor Pane > Layout Inspector를 통해 사용할 수 있다고하는데, 사실 아직 개발하면서 UI 디버깅을 많이 해본 적이 없어서 그런지 Constraint Layout에 비해 크게 기대되는 기능은 아니였습니다. 역시 아는만큼 보이는 거겠지요.ㅠㅠ
4-2) Develop
코드 분석과 리소스 관리측면에 대해서 향상되었습니다.
4-2-1) Find & Remove Unused Resources기능은 앱내에서 참조하지 않고 있는 리소스를 찾아서 제거해주는 기능이라고 합니다. Android N에서 제공하는 멀티스크린에서는 리소스의 량이 크게 증가할 거라는 생각이 들었는데, 이것과 맞물려서 유용할 것 같습니다.
4-2-2) 또한 추가된 Annotations 22.2에서 Threading Annotations를 통해서 @UIThread, @MainThread, @WokerThread, @BinderThread 등으로 지정하고 구현을 해서 런타임 에러를 많이 줄일 수 있게 될거 같습니다.
또한 기존에 타겟 sdk를 지정하고 그와 맞지 않는 api를 사용하여 개발을 하면 노란 밑줄이 가면서 잠재적인 에러를 내포하는 코드가 되곤했는데 @RequiresApi를 통해서 호출하는 단말의 api레벨에 따라 알아서 판단해서 분기해서 호출하게 됩니다.
@Dimension, @Px 어노테이션은 px과 dp 값을 표시하게 되어 좀더 깔끔한 UI처리를 할 수 있게 도와줍니다.
@Keep은 난독화 관련 어노테이션은 Proguard 돌릴 때 난독화를 돌리지말아라 하는 어노테이션으로 알아두면 굉장히 유용할 것 같습니다. 단, Keep 어노테이션은 Gradle plugin 2.2+를 사용 해야합니다.
4-2-3) firebase plugin이 추가되었는데 GCM등의 서비스를 제공하기 편하도록 해주는 플러그인이라고 합니다.
4-2-4) 현재 개발 중 모르는 api는 f2키를 눌러 제공되는 document를 보고 확인 할 수 있습니다. 앞으로는 sample code 또한 document와 같이 제공되어 더욱 쉽게 이해 할 수 있게 도와준다고합니다.
2017년도 블로그 결산! (0) | 2018.01.09 |
---|---|
Zip file구조 (2) | 2016.10.27 |
Arpspoofing (0) | 2015.10.16 |
실전 악성코드와 멀웨어 분석 Lab03_03.exe (0) | 2014.09.01 |
실전 악성코드와 멀웨어 분석 Lab03-02.dll (0) | 2014.08.29 |
서론
탈옥된 단말에는 파일을 전송하고, 그 파일을 실행시킬 수 있다.
2장 iOS해킹 기초 에서는 간단하게 hello world를 출력하는 프로그램을 탈옥단말에서 실행시키는 것을 실습하게 되어있다. 책에 있는 방법을 따라가면서 실습을 진행하려고 하였으나, 책이 12년도에 출판된 책이라서 OS환경이 달라 똑같이 진행하는데는 무리가 있었고, 다른 방법을 찾아가면서 실습을 마칠 수 있었다.
본론
탈옥 단말에서 hellow world를 출력하는 프로그램을 실행하기 위한 순서는 아래와 같다.
1. hellow world를 출력하는 소스 코드 작성
2. 컴파일
3. 파일전송을 통해 탈옥단말로 파일 전송
4. 파일 실행
1. hellow world를 출력하는 .c 파일 작성
처음에 소스코드가 간단하기 때문에 vi로 작성하였다.
2. 컴파일
gcc로 컴파일 하여 실행파일을 만들어냈다.
3. sftp를 이용하여 파일전송
책에서는 scp를 이용한 방법으로 써져있었지만, FileZilla로 sftp를 이용하여 파일을 전송하였다.
4. 파일실행
파일을 실행했더니, 아래와 같은 에러 문구가 나오고 실행이 되지 않았다.
이유를 곰곰히 생각해보니, 파일이 arm cpu에서 실행될 수 없는 파일이라는 것을 깨닫게 되었고, 직접확인해본 결과
file의 타겟 cpu타입이 다르다는 것을 확인할 수 있었다.
file 명령어를 통해 확인해 본 결과로 컴파일된 test라는 프로그램은 Mach-O 64-bit바이너리이고, 타겟 cpu는 x86_64였다.
문제 해결을 위해 arm cpu를 타깃으로 컴파일할 수 있는 방법에 대해서 여러가지 찾아보았으나, 책에서 제시하고 있는 llvm-gcc는 OS버전이 올라가면서 경로에서 찾을 수 없었다. arm cpu를 타깃으로 컴파일할 수 있는 arm-eabi-gcc를 설치하고 컴파일 해보니 arm타깃으로 컴파일이 되기는 하나 ELF파일 형식을 가지고 있어서 실행이 될 것같지는 않았다.
한 가지 들었던 생각은 어찌됐건 XCode에서 앱을 만들면 ipa안에 실행 바이너리가 들어있으니까, llvm-gcc가 XCode안에 들어있지 않을까 하고 생각하기는 했지만 찾을 수는 없었고, 조언을 통해 XCode로 컴파일을 하는 방법을 시도해보았다.
iOS 앱 프로젝트를 하나 생성한 후 Supporting Files안에 있는 main.m을 위의 사진과 같이 만들어서 실행 바이너리를 얻을 수 있었다.
한 가지 유의할 점은 앱을 빌드할 때 타깃이 시뮬레이터인경우 생성되는 바이너리는 타깃 cpu가 x86_64로 생성된다. 생각해보면 시뮬레이터는 컴퓨터에서 돌아가는 환경이니 당연한 결과인 것 같고, 원하는 arm 타깃 바이너리를 만들기 위해서는 실 디바이스를 연결해서 빌드하는 과정이 필요했다.
이렇게 생성한 바이너리를 동일한 3, 4과정을 거쳐 실행을 한 결과 아주 잘 동작하는 것을 확인할 수 있었다!
결과
정리하고 나니 삽질의 흔적이 많이 보이지는 않지만 저 mach-o arm 실행 바이너리를 얻기위해 많은 것을 시도했다. 이 과정을 통해서 컴파일러들에 대해서 조금은 더 알게되었고 막연했던 무언가가 윤곽이 보이는 것 같은 느낌이든다.
지금은 간단하게 hellow world를 출력하는 코드를 삽입한 것일 뿐이지만, 특정 위치의 파일을 읽어 온다거나 어떤 메모리의 덤프를 뜬다거나 하는 코드 또한 동작시킬 수 있을 것 같고, 나중에 꼭 쓰게될 기술일거라고 생각한다.
다음 블로깅에는 삽입한 코드를 특정 이벤트 발생 시 실행 시킬수 있는 plist를 작성해서 실습을 진행해볼 예정이다.
iOS Hooking#2(Frida) (0) | 2017.04.19 |
---|---|
iOS Hooking#1(Logos) (1) | 2017.04.18 |
자주쓰는 데이터형 변환 (0) | 2016.06.01 |
[iOS/GCC] __attribute__((constructor)) / __attribute__((desstructor)) (0) | 2016.05.13 |
[iOS] MD5해시 생성 / SHA256해시 생성 (0) | 2016.05.09 |
서론
iOS에서 개발을 하다보면, C <-> Objective C 간 데이터 형변환을 하게되는 경우가 빈번한 것 같다. 예를 들어 C에서의 문자열은 Char * / Char[] 데이터형을 사용하지만, Objective C에서는 NSString객체를 사용한다. 또한 NSString 객체를 Char * / Char[]의 형태로 역변환해서 사용하는 경우도 빈번하기 때문에 경우의 수도 많고, 외워서 쓰기에는 불편함이 있어서 정리해서 모아보는 글을 작성해보기로 하였다.
본론
1 ) unsigned char * ( C ) 와 NSData (Objective C)
1-1) unsigned char * to NSData
1 2 3 | unsigned char * byteString = "byteString"; int byteStringLen = strlen(byteString); NSData * data = [NSData dataWithBytes:byteString length:byteStringLen]; |
byteString이 바이트 data라고 가정할 때, 위와 같이 변환 할 수 있다. 만약, 문자열을 바이트 데이터로 바꾸고 싶다면 base64디코딩 과정을 거쳐야 한다.
1-2) NSData to unsigned char *
1 2 | NSData * data; unsigned char* bytesForData = [data bytes]; |
예시에서는 값이 들어 있지 않지만, NSData형의 data라는 변수에 값이 있을 때 위와 같이 변환 할수 있다.
2 ) char * ( C ) 와 NSString (Objective C)
1-1) char * to NSString
1 2 | NSString * nsString = @"Hello Bach!"; char * cString = [nsString UTF8String]; |
NSString에서 제공하는 UTF8String 메서드는 NSString문자열을 char * 데이터형을 반환해준다.
1-2) NSString to char *
1 2 | char * cString = "Hello Bach!"; NSString *nsString = [NSString stringWithUTF8String:cString]; |
NSString 문자열 변수 또한 NSString에서 제공하는 stringWithUTF8String 메서드를 통해서 char * 데이터형으로 변환할 수 있다.
결론
개인적으로 Objective C에서 프로그래밍을 하면서 느낀점은 C와 같이 혼용해서 사용할 수 있기 때문에 편한 점도 있지만 불편한 점 또한 있고, 그 불편한 점 중에 한가지가 데이터형태가 일치하지 않기 때문에 변환 과정이 필요하다는 것이다. 간단하게 가장 많이 사용하는(본인이) 형변환 두 가지만을 다루었는데, 다른 데이터 형 변환 중 자주 쓰이는 변환이 생긴다면 더 추가할 생각이다.
iOS Hooking#2(Frida) (0) | 2017.04.19 |
---|---|
iOS Hooking#1(Logos) (1) | 2017.04.18 |
2장 iOS 해킹 기초 (1) (0) | 2016.06.18 |
[iOS/GCC] __attribute__((constructor)) / __attribute__((desstructor)) (0) | 2016.05.13 |
[iOS] MD5해시 생성 / SHA256해시 생성 (0) | 2016.05.09 |