카테고리 없음

PHDays Qual - stand back, we have PHDays!

진모씨 2014. 1. 28. 16:03

개인적으로 재미진 문제였고 이 문제덕분에 조금 감이 돌아온 것 같다.


이 문제는 index.php~라는 백업 파일을 갖고 있다. 솔직히 이 부분은 대회에서 가장 마음이 안 드는 부분이다.

누가 소스코드 백업을 저렇게 해놨을거라고 상상했겠나!


이 문제 설명은 없고, secure:LthGfhjkm 로 접속이 가능하다.

주어진 아이디와 비밀번호로 http://195.133.87.167/ 에 접속해본다.


소스를 보면 Home 링크 외에 아무 것도 제대로 링크되지 않았다.

#로 다 링크되어있고 자바스크립트도 원본과 대조해봤는데 똑같다.


근데 쿠키에 uid라는 쿠키가 있었다.

url-encode가 된 base64문자열이 있는데, 풀어보면 32글자의 이상한 암호화된 글자들이다.


대준이가 index.php~ 라는 소스 코드가 있다고 해서 봤다. 아래와 같다.


중간에 db관련 php코드가 있다. '가 안들어간 32개의 문자를 생성해서 아이디로 쓴다.

저 아이디를 암호화한 값을 쿠키에 저장한다.


쿠키에 아이디가 있으면 불러와서 조회한다. 없으면 Stand back, stranger! 을 출력하고, 있으면 Welcome, "아이디"!를 출력한다.


보자! aes-256-ofb를 이용해 암호화하는데, ofb모드에 대해 몰라서 찾아봤는데 엄청 쉬웠다.

ofb 모드는 아래와 같다.

1. IV값을 암호화한다.

2. IV를 암호화한 값(IV[1])이랑 평문이랑 xor한다. 이게 암호문이다.

3. 다음 블록의 IV는 IV[1]이며, 1, 2를 다음 블록에 대해 반복한다.

반복..


그렇다. 평문은 암호화 과정에도 들어가지 않는다.

특이한 점은 복호화 과정도 "완전히 똑같고" 평문과 암호문의 위치만 바뀐다.

게다가 "암호화"를 한다. IV에다 암호화를 하는 것이다. 복호화할때도.


이 점을 이용하면, 그냥 IV[1]의 값만 유추해도 32글자는 내가 맘대로 조작 가능하다.

게다가 그 다음 블록도 그렇게 가능하다.

어떻게 알아낼까 하면..


이러면 된다.

소스 코드를 잘 보면 에러가 났을 경우 에러가 났다는 사실을 알려주고 종료한다.


그렇다, 평문에 ' 가 들어가면 에러가 나는 사실을 이용하는 것이다.

오류가 안나는 암호문에서 하나씩 처음부터 값을 0~255씩 대입해서 에러가 나는 부분이 ', 즉 0x27 코드일 것이다.

그럼 그 에러가 나는 바이트들을 처음부터 모아서 마지막까지 대입한다.


근데 마지막에는 0x27이 아니라 0x5c도 에러가 날 것이다, 분명히.

왜냐하면 마지막이 \ 가 되버리면(0x5c면) 닫아주는 ' 표시가 \'가 되어서 그냥 문자로 인식될 것이다(sql 구문에서).

그래서 마지막에 아무 바이트나 추가해서 에러가 안나게 해주면 된다. 그러면 에러가 안 날 것이다.(근데 소스코드에서는 안썼다.. 귀찮았고 그냥 나중에 오류가 나길래 그 바이트만 고쳤다)


아래는 그 소스이다. 참 쉽다.


20스레드로 서버에게 무리를 주면서까지 대입한다. 근데 속도는 똑같..다.....

여기 나온 헥스 결과값을 0x27만큼 xor해주면 된다.

근데 32자로 인젝션하기는 부족했다. 약간 바꾸면 된다. 아까 ofb의 특성을 이용하면 그냥 똑같이 대입해주면 될것이다.

이건 무려 4번째 블록을 위한 것이다. 두번째는 96부분을 32로 바꿔주자.


(추후에 블록을 연달아 하는 코드로 수정해야겠다)

이 코드에서는 \x00을 나중에 붙이지 않고 \x02를 붙였는데, \x00으로 하니까 mysql 에러가 났기 때문이다.

그러니까 iv[1]에 00이 있다는 것이다. (두번째 블록에 그랬다)

이건 결과값에 0x27 xor 0x2 의 값을 xor해줘야 한다. \x02를 대입했기 때문이다.


그래서 iv값을 알아낸 후, 그냥 평문에다가 그 iv값을 xor한 값이 내가 원하는 평문의 암호문이 될 것이다.

그걸 base64해서 넣어준다.


아래의 쿼리를 실행했다.


' union select group_concat(table_name) from information_schema.tables where table_schema not in ('information_schema')

=> user테이블이 있다. db는 코드에 나와있다. phdiiii

' union select group_concat(column_name) from information_schema.columns where table_schema='phdiiii' and table_name='user'

=> id, user, password 라는 컬럼이 phdiiii.user에 있다. user은 아이디고 password는 패스워드다.

' union select password from user

=> 컬럼이 하나다. admin:키값 이다.


이렇게 해서 password를 얻으면 그게 키값이었다.

조금 수정해야겠다. 학원 갔다 와서 수정해야겠다..