하루동안 날잡고 웹 파트랑 리버싱 점수 낮은것만 풀어보자하고 내내봤는데 유일하게 푼 웹 문제고 딱 하나밖에 풀지못해 자괴감이 들었지만 해당문제를 엄청 고생끝에 풀어서 기분이 좋았다.

   

해당 문제는 들어가보면 전체 소스코드를 제공해주고 있어 소스코드 오디팅 방식으로 취약점을 찾으면 된다.


일단 플래그를 얻으려면 아래와 같이 admin.php에 접근할때 세션 값 중 userid가 1이 세팅되어 있어야 한다.



그럼 이 값이 어떻게 세팅되는지를 알아야하는데 코드를 살펴보면 아래와 같은 형태로 진행이 된다. 

먼저 세션이 할당되어있을때와 되어있지 않을때 로직이 나뉘어져 있는데 세션이 할당되지 않은 상태에서는 로그인 계정정보를 가지고 authenticate 함수를 호출해서 userid 세션값을 세팅한다. 여기서 SQLI가 터지면 리턴값을 조작할 수 있겠다 했지만 역시나 SQLI는 터지지않았고 나머지 로직을 살펴보기로 했다.




다음으로 세션이 존재하지 않을때를 보면 쿠키 값중 user값을 decryptCookie 함수에 인자로 사용하여 리턴된 값을 통해 userid값이 세팅된다. 일단 decryptCookie  함수를 살펴보니 config.php 파일에서 아래와 같은 구조로 암복호화가 이루어지고 있었다.



암복호화 과정을 간단히 살펴보면 먼저 암호화 시에는 사용자 정보 배열(userid값,유저명,이메일)을 compress함수를 통해 직렬화된 형태의 문자열 데이터로 변환한 뒤 이 문자열 값을 crc32 처리해서 체크섬값을 세팅해 최종적으로  userid값,유저명,이메일,체크섬 형태의 배열을 만들고 이 배열을 다시 compress함수에 넣어 직렬화된 문자열 데이터 형태로 만들어 대칭키 암호화방식에 cbc 모드로 암호화를 진행한다. 그리고 이 때 암호화된 데이터의 길이를 암호화 값 마지막 6바이트영역에 추가해주게 된다.


다음으로 중요하게 봐야할 복호화 과정을 보면 위에서 만든 암호화 값을 받아와서 마지막 6바이트 영역의 길이부분을 떼어낸 뒤 복호화를 진행하고 복호화한 값을 6바이트 영역의 길이 값만큼 substring처리해서 직렬화된 형태의 문자열을 decompress 함수내에서 배열형태로 변환한다. 이 때 배열 내 저장되어있는 checksum값과 checksum 값을 제외한 나머지 값(userid값,유저명,이메일)로 다시 checksum값을 만들어 이 둘을 비교해 암호화된 데이터가 변조되어있는지 확인한다.


여기까지 분석하고 처음 든 생각은 Oracle Padding Attack으로 암호화된 값을 복호화한 뒤 userid값과 checksum값을 변조하면 되겠다고 생각이 들었다.


그래서 padbuster로 일단 암호화된 값을 복호화했더니 내가 옵션을 잘못준건지 잘못사용한건진 몰라도 복호화된 값이 아래와 같은 형태로 username 키 값과 그 전의 id값이 잘린채 깨져서 나왔다.


e¡youngsin÷email¡youngsin@naver.com÷checksum¡÷338124513 


한번정도 더 시도해봤는데 결과가 같았고 한번 복호화하는데 시간도 너무 오래걸려서 그사이 코드를 한번더 유심히 보다가 username,emali값을 통해 아래와 같은 식으로 id값을 덮을 수 있겠다 싶었고 이걸로 뭔가 익스가 가능할 것 같다는 느낌이 들어서 테스트를 시작해봤다.


내가 정상적으로 계정 생성 후 로그인을 할 경우 암호화되는 평문 값은 아래와 같은 형태일 것이다.

id¡1500÷username¡youngsin÷email¡youngsin@naver.com÷checksum¡÷338124513 


여기서 나는 가입할 계정 및 이메일을 입력할 때 별도의 필터링 구문이 없기 때문에 youngsin@naver.com÷id¡1 요런식으로 가입을 해주면 아래와 같은 형태로 암호화될 평문 값이 세팅될 것이다.


id¡1500÷username¡youngsin÷email¡youngsin@naver.com÷id¡1÷checksum¡÷338124513 


여기서 이 문자열 값은 decompress 함수내에서 배열로 변환되면서 아래의 코드에 의해 중복된 키 값이 가장 뒤에값으로 세팅되어 id값이 1이 되게된다.



 

이를 통해 id를 덮을 수 있다는걸 알았고 이제 문제는 checksum 값이었는데 checksum값 같은 경우 내가 입력한 값보다 뒤쪽에 존재해 값을 덮을 수가 없었다. 그러나 이 때 굳이 왜 암호화 길이를 세팅해서 추가해놨지 했던 부분이 떠올랐고 이걸 이용하면 뒤쪽에 적용되어있는 기존 checksum값을 잘라내고 내가 입력한 checksum값이 적용되게 할 수 있겠구나 생각이 들었다. 그래서 이 시나리오대로 아래와 같은 형태로 공격을 진행했다.


1. 회원가입 시 이메일 값을 다음과 같이 세팅

ssrjys1@naver.com÷id¡1÷checksum¡2486825947


2. 가입한 계정으로 로그인하여 암호화된 값 획득


3. 로그아웃 후 암호화된 값에서 길이 값을 줄여가며 decrypt 에러가 안뜨는 길이 값을 찾음.


4. 3번에서 찾은 값으로 index.php를 접근하면 세션 내 userid값이 1로 세팅되어서 플래그 출력


 

1) 이메일 값에 조작한 값을 삽입하여 가입 시도



2) 가입한 계정으로 로그인하여 조작한 평문이 담긴 암호화값 획득



3)암호화 값에서 길이영역을 조작하여 Decrypt 에러가 안터지는 길이 값 확인(원본 checksum값이 정확히 잘린 시점의 값)



4) 3번에서 구한 암호화 값으로 index.php 접근 시도(로그아웃 후 진행하여 세션 값내 userid값이 세팅되어 있지 않아야함)



5) 조작한 암호화 값이 Decrypt되면서 세션 내 userid 값이 1로 세팅되어 플래그 출력











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

InCTF 2018 The Most Secure File Uploader  (0) 2018.10.08
D-CTF Quals 2018 secops  (0) 2018.09.26
Codegate 2018 CTF RedVelvet  (0) 2018.09.18
BugsBunny CTF 2017 Rev150  (0) 2018.09.17
LAYER7 CTF 2018 Margaret  (0) 2018.09.17
블로그 이미지

JeonYoungSin

메모 기록용 공간

,