Portswigger-Authentication bypass via encryption oracle

problem link

풀이

wiener:peter 계정을 이용해 로그인할 수 있다. encryption oracle이 있다. 이를 이용해 admin 판넬에 접근, Carlos를 삭제하라.

stay-logged-in 쿠키를 이용하면 세션이 달라도 로그인을 유지할 수 있다. 다른 세션 2개에서 이 쿠키를 이용해 로그인하면 한쪽에서 로그아웃을 해도 다른 한 쪽은 로그인이 유지된다. 로그아웃을 한다고 당장 파기되지는 않는듯 하다.

새로 로그인하여 새로운 stay-logged-in 쿠키를 발급받으면 그 값이 다르다. 하지만 그 내용은 모두 base64를 URL인코딩한 것으로 보인다. stay-logged-in 쿠키는 암호문이나 해시 등을 base64 인코딩하고, 이를 URL 인코딩한 것이라 추측할 수 있다.

stay-logged-in 쿠키의 값이 어떻게 생성되는지 알아낼 수 있다면 admin으로 로그인할 수 있다. admin 계정의 아이디는 administrator 인 것 같다.

포스트의 댓글을 쓰는 기능에서 stay-logged-in 쿠키와 유사한 형태의 암호문이 나타난다. 잘못된 형식의 데이터(Email에 Email 형식이 아닌 값을 넣어 보내거나, Website가 유효한 URL 형태가 아닌 경우)를 보내면 오류메시지를 보내는데, 이 로직이 독특하다.

Email을 유효하지 않은 형태로 입력해 보내면 위와 같은 반응이 온다. notification=%2bx%2fblbGjTetnvub8opXjgZF3pgW2ToiuxDDCM2N2P1Q%3d 와 같이 notification 쿠키가 stay-logged-in 쿠키와 유사한 형태를 보인다. 이 쿠키를 가지고 다시 포스트의 내용을 요청하는 GET을 보낸다. 그렇면 상단에 해당하는 오류 메시지가 뜬다.

이 오류메시지는 공격자가 이메일로 입력한 값을 보여준다. notification 쿠키가 오류문을 암호화한 것인지, 아니면 특정 오류 코드 등을 나타내는지 알아내야 한다. 이를 위해 여러 값을 입력해 테스트해본다.

이번에는 Email을 testtesttesttest 로 해보았다. notification 쿠키가 %2bx%2fblbGjTetnvub8opXjgfmMxJnV%2f4R4MOPnkSJm4E6AyikxcOoWLoI5929YdFlJ로, 앞부분 %2bx%2fblbGjTetnvub8opXjg까지는 동일하지만 뒷부분이 다르다. 오류메시지에 반사되는 앞부분은 동일하지만 뒷부분은 달라졌고, 또한 길이도 길어졌다. 이를 통해 notification이 코드이기보다는 암호문이라는 추측을 할 수 있다. 그렇다면 notification에 입력된 암호문을 복호화하여 보여주는 것이라 추측할 수 있다.

notification 쿠키에 stay-logged-in 쿠키 값을 넣어 보내보았다.

stay-logged-in 쿠키를 디코딩하여 wiener:1601929756637 라는 값이라는 것을 보여준다. stay-logged-in 쿠키는 다시 발급받을 때마다 변경되므로 아이디와 타임스탬프라는 것을 추측할 수 있다. administrator:타임스탬프 의 암호문을 만들어 stay-logged-in 쿠키로 지정하면 admin으로 로그인할 수 있다.

임의의 암호문을 만들어야 한다. 잘못된 Email을 입력했을 때 오류메시지에 사용자의 입력값이 반사된다는 점을 이용하면 administrator:타임스탬프 의 암호화 값을 얻을 수 있다. 오류 메시지의 앞부분이 동일하기에, 100%는 아니지만, 뒤의 암호가 앞의 암호에 영향을 받지 않을 가능성이 있다.

<<<여기부터 시간이 지나 문제가 초기화되었다. 암호화 키도 변경하는지 쿠키값이 변경되었지만 일관성은 여전하다.>>>

이메일로 administrator:1601929756637을 입력해 생성한 notification 쿠키의 뒷부분을 조금씩 떼어 복호화해본다. Repeter를 이용해 반복한다.

base64를 디코딩하여 암호문을 얻는다. 이를 ASCII hex로 변경한 뒤, 원하는만큼만 잘라서 다시 바이너리로 변환, base64 인코딩한다. 그리고 특수문자만 URL 인코딩하여 notification 쿠키에 넣어본다.

맨 뒤 16바이트만 넣어보니 37이라고 디코딩했다. 이는 입력한 administrator:1601929756637 의 맨 뒤 두 글자이다. 이렇게 앞 암호문이 뒤 암호문에 영향을 끼치지 않으며, 잘 떼어내면 임의의 문장에 대한 암호문을 만들 수 있다는 것을 확인했다.

암호문을 잘못된 길이로 자르면 위와같은 에러를 반환한다. 이를 통해 이 암호는 16바이트 단위의 블록 암호라는 것을 알 수 있다. 블록단위로 암호화를 한다면 암호화 하고자 하는 administrator:1601929756637와 앞의 Invalid email address: 문장을 분리해야 한다.

앞 문장과 administrator:1601929756637 문장이 서로 다른 블록에 속하도록 하기 위해 앞 블록을 채워준다. 앞 문장은 23글자로, 32-23인 9바이트를 쓰레기 값으로 더 채워준다.

뒤의 32바이트를 자르니 딱 맞았다. 이 암호문을 stay-logged-in 쿠키로 지정한다.

administrator로 로그인하여 Carlos를 삭제할 수 있다.

이 취약점은 사용자가 임의의 암호문을 복호화할 수 있어 발생했다. 또한 임의의 평문을 암호화할 수 있기에 발생했다. 그리고 notification이 조작될 가능성을 배제하고, 디코딩한 값이 유효한 에러메시지인지 체크하지 않았기에 발생했다.


tags: writeup, business-logic-vul, wstg-busl-02, wstg-cryp-04, web hacking