이문제는 한번쭉 문제풀 때 메뉴랑 기능이 여러개 있어서 풀기 귀찮아서 접어놨었는데 회사동기가 풀고있다해서 다시 풀어봤다.

 

여러가지 기능이 있는데 별다른 취약점이 안터진다. 업로드쪽에 php가 올라가긴하는데 경로를 알 수가 없다.

일단 문제에서 zip파일을 업로드해보라는 힌트를 주고있었기 때문에 업로드기능이 있는곳에 zip파일을 모두

올려봤다.  storage게시판에서 zip파일을 업로드하면 해당 zip파일과 zip파일을 압축해제 해 내부 파일이 같이 서버로 올라가는 걸 확인할 수 있었고 바로 그냥 심볼릭링크 걸어서 index.php 읽으면 되겠다고 생각했다.

먼저 현재 압축해제된 파일의 위치를 모르기 때문에 ../부터 ../../../../../../../../../../../../../../../../까지 하나씩 상위경로로 심볼릭링크를 걸어서 zip파일을 하나씩 올려봤다. 상위 5번 위치의 index.php에 심볼릭링크 걸어준 파일에서 index.php파일이 읽혔고 플래그가 있었다.

 

 

 

 

 

블로그 이미지

JeonYoungSin

메모 기록용 공간

,

들어가보면 검색기능만 떡하니 하나있다. 뻔한 sqli 느낌이었는데 검색할때 js단에서 base64로 파라미터값을 인코딩해서 날리기만 할뿐 실제로 뻔한 Sqli였다. union이 필터링당하고 있어서 blind를 해야했는데 코드짜기 귀찮아서 그냥 sqmap으로 돌렸다.

 

 

 

Database: spy_database
Table: users
[2 entries]
+----------+--------------------------------------+
| username | password                             |
+----------+--------------------------------------+
| admin    | pctf{L31's~@Ll_h4il-1h3-c4T_Qu33n.?} |
| test     | test                                 |
+----------+--------------------------------------+

 

 

블로그 이미지

JeonYoungSin

메모 기록용 공간

,

들어가보면 간단한 Email/Team name을 통한 로그인 기능이 나온다.

 

 

admin으로 로그인을 해야되는데 SQLI나 Oracle Padding attack , admin          1 요런식 등의 취약점이 따로 터지지는 않고 있었다.

 

첨에 소스제공해주는걸 못보고 삽질좀하다 문제에서 소스를 제공해주길래 열어봤다.

 

login.php

 

 

 

homepage.php

 

 

소스를 보면 team_name혹은 email과 비밀번호가 일치하면 true가 반환되면서 세션의 logged_in 값이 true로 세팅된다. 로그인 성공 시 리다이렉트되는 homepage.php에서 admin으로 인증되려면 다음과 같이 세션의 logged_in , id , type값이 정상적으로 세팅되야 하는데 admin의 임의의 패스워드로 인증을하면 id , type값은 정상적으로 세팅되지만 logged_in값이 false로 세팅된다.

 

그렇다면 일단 정상 사용자로 로그인을해서 logged_in값을 세팅해놓은다음 admin의 임의의 패스워드로 인증을 시도하면 패스워드 인증 전에 id , type값이 세팅되기 때문에 id를 admin값으로 만들고 logged_in 값은 그대로 true로 유지한채 세션을 만들 수 있었다.

 

다음과 같은 순서로 접근해주니 인증이 됬다.

 

 

 

 

 

 

 

 

블로그 이미지

JeonYoungSin

메모 기록용 공간

,

들어가보면 기사들을 볼 수 있는 사이트가 나오는데 각 기사를 클릭해보면 파라미터로 파일명을 던지고 있는것을 볼 수 있었다.

 

 

해당 파라미터에서 ...../// 이런식으로 필터링 우회해주면 경로이동이 가능한 취약점이 터졌는데 문제는 확장자로 무조건 .txt가 붙는다는 제약이 있었다. %00도 안먹히고 php 5.3에서 터지는 4096 byte 이슈도 안먹히는 것 같았다. 처음엔 include나 require일지도 모른다고 생각하고 RFI를 시도해봤는데 명령어실행이 안되고 단순히 파일내용 뿌려주는걸로보아 file_get_contents를 쓰고 있는것 같았다.

 

내가모르는 트릭이 있나하고 한참 고민하다가 일단 접어두고 다른 벡터를 찾아보기 시작했다.

 

그러다가 이미지를 가져올 때 id파라미터에서 파일다운로드가 가능한 취약점이 터지는걸 확인할 수 있었다. 파일명 뒤에 ico , png , php를 붙여보고 파일이 존재하면 다운받는 형식이었다.

 

바로 index.php를 다운로드해서 소스를 본 후 helpers.php를 확인했더니 flag관련 파일명이 있어서 뒤에 .txt붙여서 내용을 보니 플래그가 있었다.

 

 

 

 

 

 

 

 

블로그 이미지

JeonYoungSin

메모 기록용 공간

,

글쓴시점에 아직 대회가 진행중이라 대회가 끝나고나면 해당글은 공개로 돌리도록 하겠다.


문제에 들어가보면 간단한 게시판 기능이 있는 사이트다. 문제자체는 크게 어렵지 않았는데 SQLI가 두군데서 터지는데 실제 문제풀때 쓸 부분을 나중에 찾고 먼저 찾은 Insert based Sql injection에서 시간소모를 많이했다. 회원가입할때 사이트입력하는 필드에서 SQLI가 터진다. time based insert sql injection으로 데이터를 뽑아올 수 있는 상황이었는데 코드짜서 할려고 만들다가 귀찮아서 딴방법없나하며 뒤적거렸는데 유저정보 조회할 때 union sqli가 터져서 이쪽을 좀 더 파봤다.



냥쭉 디비털어서 플래그 가져오면 되겠다 했는데 information이 필터링당하고 유저도 root가 아니라 mysql.innodb_table_stats 등의 root일 때 테이블명 구할 수 있는 케이스도 적용이 안되는 상황이었다.


여기서 살짝 멘탈나갔었는데 이것저것 보다가 요걸 발견했다.


admin으로 가입할 때 사이트에 네이버주소를 적었었는데 해당 계정정보를 조회할때 302 응답값이 출력된게 보였다. 여기서 내가입력한 사이트로 뭔가 요청을 한다는걸 알 수 있었고 SSRF구나 하고 감이 왔다.


문제에서 index.php를 읽으래서 180%20union%20select%201,2,3,4,'file:///proc/self/cwd/index.php',6 요런식으로 읽으려고 했더니 php가 필터링당하고 있었다. 


요런식으로 간단히 우회해서 플래그를 구했다.





블로그 이미지

JeonYoungSin

메모 기록용 공간

,

글쓴시점에 아직 대회가 진행중이라 대회가 끝나고나면 해당글은 공개로 돌리도록 하겠다.


들어가보면 다음과 같은 소스를 볼 수 있다.



파라미터와 파라미터값을 통해 php함수를 실행시킬 수 있는 구조인데 flag파일을 읽기 위해 쓸수있는 대부분의 함수와 관련된 문자열이 필터링되고 있다.


잘보니까 include나 require 이 없길래 이놈들 활용해서 플래그출력하려했더니 서버에러가 자꾸 떴다. 필터링은 안당하는데 일단 사용은 못하는것 같아서 접어두고 다른함수를 좀 생각해보다 show_source로 읽어오면 되겠다 생각했는데 _가 필터링당하고 있었다.


전에 ctf write up들 보다가 php에 _관련된 트릭이 있었다고 본 기억이 나서 show$브루트포싱지점$source 요런식으로 _위치에다가 이것저것 값을 다 때려박고 브루트포싱했더니 _대신 공백이 들어가면 우회가 되는걸 볼 수 있었다. 어떤 이유로 우회가 되는지는 잘 모르고 일단 풀긴했는데 좀 제대로 알아봐야겠다는 생각이 들었다.


 

나중에 _트릭공부하면서 다시 시도하려다 알게됬는데 문제가 깨진것 같다. preg_match가 제대로 동작을 안해서 필터링함수가 모두 사용가능한 상황이었다..

블로그 이미지

JeonYoungSin

메모 기록용 공간

,

글쓴시점에 아직 대회가 진행중이라 대회가 끝나고나면 해당글은 공개로 돌리도록 하겠다.


들어가보면 다음과 같이 등록기능과 조회 기능 두가지가 존재한다.



archive.is가 뭐하는 건지 몰랐는데 찾아보니까 현재 존재하는 페이지에 대해서 스냅샷과 같은 개념으로 저장시켜놓고 나중에 이 페이지가 날라가도 저장된 페이지를 조회할 수 있다는 대충 뭐 그런 개념인 것 같았다.


그렇다면 위의 문서 저장 기능에서 내가원하는 url주소를 입력하면 해당 url 및 내용이 디비에 저장될 거라고 생각했다.


실제로 기능을 사용해 보니 내가 저장한 페이지를 검새기능을 통해 조회하면 실제 페이지 내용이 출력되는 것을 확인할 수 있었다.


여기까지 확인하고 그럼 저장할때 url대신 file://./index.php 요런식으로 입력해주면 서버 내 index.php파일의 내용을 읽어와 출력해줄거라고 생각하고 시도해봤는데 file을 필터링하고 있었다.


여기서 대충 SSRF겠다 생각이 들었고 일단은 필터링때문에 SSRF만 가지고 뭘 할 수 없을 것 같아 다른 취약점을 찾았는데 문서 저장할때 insert sql injection이 터지는걸 확인할 수 있었다.


끝났다 생각하고 123',0,1,20180303),(1,0x66696c653a2f2f2e2f696e6465782e706870,1,1,20180304)# 요런식으로 file://./index.php 삽입해서 접근해보면 되겠다 생각했는데 강제로 삽입한 file://./index.php 부분이 조회가 안되고 있었다.


뭐지 하고 생각하다가 업로드된 게시글에 914번이 비어있는걸 보니 업로드는 됬는데 리스트 페이지 접근시 안보이는거다 생각했고 리스트 페이지에는 데이터뽑아올 기준이 되는게 세션밖에 없었으므로 세션값이 문서저장시에 같이 박히고 있겠구나라고 추측할 수 있었다.


그렇다면 문서저장시 사용하는 쿼리구조에 대해 파악해서 세션관련 데이터뽑아주고 이 데이터도file://./index.php 넣을때 같이 넣어주면 되겠다고 생각했다.


우선 요런식으로 문서저장시 사용되는 쿼리에 대해 조회를 했다.



쿼리를 잘 보면 id부분에 세션관련된 값이 저장되고 있는걸 확인할 수 있었다. 근데 전체데이터가 안나오고 잘려 나오고 있어 substring으로 정확한 세션관련값을 가져왔다.



이제 구한 세션값을 토대로 file://./index.php를 읽어오는 쿼리를 삽입해줬다.


여기서 멘탈이 한번더 나갔는데 경로조작해가면서 index.php읽어볼려고 이것저것 넣어봤는데 죄다 실패했다. index.php가 존재하는 절대경로를 알아내야 했는데 딱히 방법이 떠오르지가 않았다. 그래서 경로관련해서 이것저것 찾아보다가 이런걸 발견했다.

/proc/self/cwd/란 놈인데 대충 현재 디렉토리와 같은 개념으로 사용할 수 있다고 한다. 

요걸 활용해서 file:///proc/self/cwd/index.php로 시도해봤더니 플래그가 나왔다.






블로그 이미지

JeonYoungSin

메모 기록용 공간

,

바이너리를 실행해보면 패스워드값 입력 후 정답여부를 출력한다.

 

디버깅 해보면 패스워드값은 I have a pen.으로 쉽게 구할 수 있는데 그 다음부터 쭉 안티디버깅 코드들이 나온다. 하나씩 우회해주면된다.

 

패스워드 값 확인.

 

 

 

 

IsDebuggerPresent 실행 후 리턴값 0으로 변경하여 우회.

 

 

 

 

 

CALL 00401120을 통해 리턴된 PEB.NtGlobalFlag값을 0으로 변경하여 우회.

 

 

 

 

CheckRemoteDebuggerPresent 실행 후 리턴값 0으로 변경하여 우회.

 

 

 

 

GetickCount를 두번호출해서 타이밍 체크를 하고 있어 구해진 시간차값을 3E8보다 작게만들어서 우회.

 

 

 

 

 

특정파일을 생성한 뒤 결과를 가지고 검증하는데 이부분은 내환경에서 안티디버깅에 안걸려서 그냥 진행.

 

 

 

 

각 프로그램들이 실행되어있는지 확인. 각 문자열들을 모두 NULL처리해서 우회.

 

 

 

 

 

VMware 실행여부 판단할때 호출하는 함수 내에서 예외가 발생하도록 되어있어서 디버기 프로세스한테 예외처리하도록 넘기고 진행.

 

 

 

 

 

0으로 나누기를해서 강제 예외 발생시키고 있길래 디버기 프로세스한테 예외처리 넘기고 진행.

 

 

 

 

 

디버그 탐지 후 종료하는 로직안타도록 Flag값 수정을 통해 점프문 조작.

 

 

 

 

문자열 디코딩 후 메시지박스 호출하는 로직으로 들어가도록 점프문 조작.

 

 

 

Flag = SECCON{check_Ascii85}

 

 

블로그 이미지

JeonYoungSin

메모 기록용 공간

,

Google CTF 2017 Food

CTF/Writeup 2018. 2. 13. 18:17

일단 다운로드받은 apk파일을 까서 jeb로 확인해보면 자바코드자체는 매우 단순하게 되어있다.

 

 

단순히 JNI로 cook.so파일을 로딩하여 쓰고있는걸 볼 수 있다.

 

ida로 cook.so를 까서 분석을 해봤다.

 

일단 java쪽에서 따로 호출하는 네이티브 메소드도 없었고 마침 JNI_OnLoad함수도 존재해서 여기부터 분석을 시작했다.

 

 

일단 함수 내부를 봤는데 생각보다 코드가 길었고 시작 부분의 코드부터일단 분석해보기로 했다. 코드를 보면 sub_680이라는 함수의 리턴값을 통해 filename, path 등 여러 변수가 세팅되는걸 볼 수 있다. 이를 통해 sub_680함수가 인자값을 토대로 어떠한 문자열을 리턴하는 함수라는걸 대강 유추할 수 있었고 좀더 상세히 분석하기 위해 해당 함수의 내부로 들어가봤다.

 

 

이부분은 분석좀 하다가 넘어갔는데 문제푸는데 큰 지장은 없어서 대충 인자로 들어온값들을 통해 특정문자열이 세팅된 주소를 리턴해 주는 기능을 한다는것만 알고일단 넘어갔다.

 

이후 JNI_OnLoad 코드를 좀더 보다보면 다음과 같이 어떤 파일명으로 파일을 생성한 다음 해당 파일에다가 dex\n035라는 값이 존재하는 주소부터 0x15a8만큼 더한 주소까지의 바이트값들을 쓰고있는 것을 확인 할 수 있었다. 

 

 

dex 포맷의 값을 특정 파일에다 쓰고있는 걸 보아 앱 실행 시 동적으로 임의의 dex파일을 만들고 있다는걸 알 수 있었다.

 

해당 파일의 내용으로 들어갈 byte 값들은 이미 알고있었기 때문에 이 영역의 값들을 긁어다가 dex파일을 임의로 만들어서 어떤 dex파일을 만들어내는지 확인해 보면 될 것 같았다.

 

먼저 1640~2BE7 까지의 값을 긁어서 새로운 dex파일을 만들었다.

 

 

 

해당 dex파일을 디컴파일해서 확인해봤더니 다음과 같은 코드가 나왔다.

 

 

떡하니 flag값이 있길래 이건줄 알았는데 바이트값들을 보니까 아스키로 변환이 안되는 값들이다. 근데 따로 이 값이 사용되거나 하는 곳도 없었다. 여기서 살짝 멘탈이 나갔는데 좀 자세히 보니까 cc라는 메소드가 정의는 되있는데 아무내용이 없는게 눈에들어왔다. 네이티브 메소드도 아닌데 뭐지 싶다가 내가 복구한 dex파일에서 cc메소드 부분이 디컴파일이 제대로 안이루어진 것 같다고 생각해 JNI_OnLoad함수를 다시 분석하기 시작했다.

 

쭉 보다보니 마지막부분쯤에 동적으로 생성한 dex파일을 삭제한다음 sub_710이란 함수가 호출되는 부분이 있었다.

 

 

sub_710함수 내부로 들어가서 뭐하는놈인지 분석을 시작해봤다.

 

 

 

쭉 보다보면 memcpy로 15A0부터 0x90만큼의 바이트들을 xor 0x5A로 돌려서 어떤메모리영역에 쓰고있는걸 볼 수 있었다. 이 영역이 cc함수와 연관되어 있을 거라고 생각했고 동적디버깅을 통해 해당 영역을 확인해보니 동적으로 생성한 dex파일의 0x720영역부터 0x90만큼인 것을 알 수 있었다.

이제 xor 5A한 값을 구하기 위해 일단 스크립트를 짠 뒤 dex파일을 새로만들고 디컴파일을 시도해봤다.  

 

 

 

cc메소드가 정상적으로 디컴파일되어 나온것을 확인할 수 있었다.

 

이제 flag값과 같이 인자로 들어가는 k변수값을 찾아야되는데 이 값은 내가 입력한 값과 특정 byte들을 연산해서 유니코드로 적힌 값과 일치하면 되기때문에 간단히 xor연산해서 값을 구했다.

 

 

이제 이 값을 가지고 플래그랑 같이 특문으로된 이상한 메소드를 실행하면 플래그가 나올 것이다.

자바로 소스를 긁어다가 실행시켜서 돌리면 플래그가 나온다.

 

 

flag = CTF{bacon_lettuce_tomato_lobster_soul}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

블로그 이미지

JeonYoungSin

메모 기록용 공간

,

다운받은 apk을 디컴파일해서 분석해보면 다음과 같은 핵심메소드를 쉽게 찾을 수 있다.

 

 

뒤부분이 살짝 잘리긴 했지만 isValidLicenceKey 메소드의 결과 값이 참이면 라이센스 등록이 성공하는 루틴이다. 이 때 isValidLicenceKey 메소드의 인자으로 내가입력한 값 , Key값 , IV값 이렇게 세가지 값이 들어간다.

 

일단 여기까지 분석하고 isValidLicenceKey 메소드를 분석해봤다.

 

 

메소드 자체는 간단하다. 입력받은 파라미터 값들을 차례대로 encrypt함수에 넣고 리턴된 암호화값이 29~와 같으면 된다.

 

그럼 이제 encrypt 함수를 분석하면 될 것 같다.

 

 

해당 함수는 AES/CBC 형태로 암호화되고 있는걸 확인할 수 있었다.

 

이제 문제는 입력값을 제외한 key값과 iv값을 알아내야 하는데 어디서 이 값이 세팅되는지 확인해봤다.

 

 

 

 

key값과 iv값이 세팅되는 메소드인데 보면 Sqlite Database 쿼리를 통해 값을 얻어오는 것을 확인할 수 있었다. database 파일은 /data/data/edu.sharif.ctf/databases/db.db 요 경로에 있었고 config 테이블에서 key와 iv를 뽑아오는걸 알 수 있었다.

이제 이 sqlite 데이터베이스 파일가져오기만 하면되는데 해당앱이 루팅탐지를 따로 하고있지 않아서 루팅폰에 앱을 설치한다음 해당 파일을 빼내올 수 있었다.

 

su -

cp /data/data/edu.sharif.ctf/databases/db.db /data/local/tmp/

chmod 777 /data/local/tmp/db.db

adb.exe pull /data/local/tmp/db.db

 

이제 가져온 db.db를 sqlite db browser로 열어서 key, iv값을 확인해봤다.

 

 

iv = a5efdbd57b84ca36

key = 37eaae0141f1a3adf8a1dee655853714

 

그럼 이제 복호화 할 때 필요한 재료가 모두 갖춰졌기 때문에 복호화 코드짜서 그대로 돌려주면 된다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

'CTF > Writeup' 카테고리의 다른 글

SECCON Online CTF 2016 Anti-Debugging  (0) 2018.02.26
Google CTF 2017 Food  (0) 2018.02.13
SECCON CTF 2015 reverse-engineering-android-apk-1  (0) 2018.02.12
nullcon CTF 2018 web2  (0) 2018.02.12
Easy CTF 2018 Nosource, Jr.  (0) 2018.02.11
블로그 이미지

JeonYoungSin

메모 기록용 공간

,