김치콘 2019 후기 + M5Stack Challenge

언제나 그렇듯 김치콘에 가게되면 기술외적으로 다양한 경험을 하고 오는 것 같습니다.

다양한 사람들을 많나고 이야기는 나누는 것, 그리고 다양한 분야의 전문가들의 경험을 통한 간접적인 경험들… 이번에는 챌린지에 빠져서 keynote 이외에 발표는 집중해서 듣지 않았지만, 그럼에도 불구하고 귀에 꽂히는 여러 키워드들이 있었습니다. 특히 Exodus 근무하시는 안기찬님의 발표는 버그헌팅을 하고 있는 저에게는 꽤 신선하게 다가왔고, 앞으로의 방향을 정하는데 큰 도움이 될 것 같습니다. 0day를 주 목적으로 하는 회사의 근무 방식과 인력 채용 과정, 그리고 그러한 회사들에 스스로를 PR하기 위한 방법 등… 어떻게 보면 버그헌팅 보다 더 궁금했지만 기존에 어디에서도 들을 수 없었던 이야기인지라 저에게는 무척 신선하게 다가왔습니다. 생각해보니 keynote도 제가 최근에 들었던 것들 중에서 가장 편하고 또 재미있었습니다. “와이프를 설득하면 회사의 모든 상사를 설득할 수 있고, 자식을 설득할 수 있으면 모든 부하 직원들에게 동기를 부여할 수 있다”라는 이야기는 이번 김치콘에서 가장 insightful한 이야기가 아니었나 생각됩니다.

이석찬님의 키노트

이제 챌리지에 대해서 이야기해보려고 합니다. 사실 작년 김치콘 챌린지는 기대가 커서 그랬는지 저에겐 조금 실망스러웠는데, 올해는 기대 이상으로 재미있게 참여했습니다. 옆에서 같이 삽질하는 친구(김동현, https://www.facebook.com/hackpupu)가 있어서 그랬을 수도 있을 것 같네요. 올해 챌린지는 M5Stack의 ESP32 SoC에 올라간 애플리케이션을 분석하고, 취약점을 공격해서 김치콘 이미지를 디스플레이에 출력하는 것이었습니다.

막상 하드웨어는 받았는데, 뭘해야 될지 몰라서 구글을 뒤지고, esptool(https://github.com/espressif/esptool) 프로젝트를 찾아서 flash 메모리도 덤프해보고, serial 포트에 출력되는 내용도 확인하고… 그리고 뭔지 모르겠지만 crash도 내보고, ida-xtensa(https://github.com/themadinventor/ida-xtensa) 프로젝트로 매트님이 올려주신 바이너리도 열어서 확인해보고, 이것저것 하면서 새로운 architecture에 대해서도 배우고, 뭔가 근본적인 것(architecture, assembly, etc…)들에 집중할 수 있었던 시간이었습니다. 물론, 김치콘 기간 중에는 이상한 함정에 빠져서 삽질만 하다 돌아왔지만… 그래도 다행히 오늘 오전에 모든 것들을 온전히 이해한 상태에서 챌린지 문제를 풀어낼 수 있었습니다.

아래는 제가 빠졌던 함정입니다. 아두이노 스튜디오로 시리얼 포트를 모니터링하는 상태에서 /setName 페이지의 name 파라미터에 110byte의 데이터를 입력하면 아래와 같이 crash가 발생합니다.

아래 로그는 curl http://192.168.4.1/setName -d ‘name=’python -c "print 'A' * 110" 명령어를 실행하면 serial 포트에 출력되는 crash 로그입니다.

15:40:08.410 -> Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled.
15:40:08.410 -> Core 1 register dump:
15:40:08.410 -> PC : 0x4014fa7b PS : 0x00060e30 A0 : 0x800d624f A1 : 0x3ffb1e10
15:40:08.410 -> A2 : 0x3ffc0df0 A3 : 0x3ffcae08 A4 : 0x00000054 A5 : 0x3ffc15d8
15:40:08.410 -> A6 : 0x00000091 A7 : 0xfffffffe A8 : 0x00414141 A9 : 0x3ffb1dd0
15:40:08.410 -> A10 : 0x3ffc0df0 A11 : 0x3ffb1e04 A12 : 0x3ffb1e04 A13 : 0x00000000
15:40:08.410 -> A14 : 0x00ff0000 A15 : 0xff000000 SAR : 0x00000010 EXCCAUSE: 0x0000001c
15:40:08.410 -> EXCVADDR: 0x00**41414d** LBEG : 0x400013f9 LEND : 0x4000140d LCOUNT : 0xffffffff
15:40:08.410 ->
15:40:08.410 -> Backtrace: 0x4014fa7b:0x3ffb1e10 0x400d624c:0x3ffb1e30 0x400d39b1:0x3ffb1e60 0x400d646f:0x3ffb1eb0 0x400d64e5:0x3ffb1ed0 0x400d652e:0x3ffb1f00 0x400d68e9:0x3ffb1f40 0x400d1e42:0x3ffb1f90 0x400df3a1:0x3ffb1fb0 0x40089225:0x3ffb1fd0

그림에 보이는 것처럼 EXCVADDR 값을 컨트롤할 수 있었고, 저희는 이 crash 로그를 단순 stackoverflow 일 것이라고 착하는 아주 큰 착각하는 실수를 저릴렀습니다. 당시 Xtensa LX6(ESP32 SoC의 processor) instruction에 익숙하지 않아서 코드도 대충 봤거든요… 그래서 분석을 좀 더 하기 보다는 어떻게 하면 저 EXCVADDR(EXCVADDR을 EXECADDR로 본건 안비밀…)을 우리가 원하는 값으로 컨트롤할 수 있을까에 대해 고민하며, 게싱하고, 브루트포싱 하는 것을 반복하다 보니… 어느새 김치콘 종료 시간이 되었습니다. 혹시라도 김치콘 이후에 챌린지에 도전하시는 분들은 저와 같은 함정에 빠지지 않으시길 바라며, 스펙 문서와 IDA로 코드를 좀 더 꼼꼼히 살펴보시기 바랍니다. 그리고 무엇보다 챌린지를 준비하는 과정에 매트님이 준비해두신 작은 배려(힌트?)들이 바이너리 사이사이에 잘 박혀있습니다. 바이너리를 조금 더 꼼꼼하게 봤다면… 시간 내에 문제를 풀 수 있었을 텐데 매우 아쉽습니다 ㅠㅜ

ps. 추후에 분석 과정에서 알게된 사실이지만 아래 crash는 메모리에 저장된 web server 관련 구조체를 건드려서 발생한 crash 였습니다.

EXVADDR에 대한 내용(https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/fatal-errors.html에서 발췌)

This CPU exception happens when application attempts to read from or write to an invalid memory location. The address which was written/read is found in EXCVADDR register in the register dump. If this address is zero, it usually means that application attempted to dereference a NULL pointer.

비록 시간 내에 문제를 해결하진 못했지만 이번 기회가 아니었다면 경험해보지 못했을 새로운 플랫폼에 대해서 스터디할 수 있었고, 결국엔 이렇게 문제를 해결하고 성취감까지 얻을 수 있으니 정말 유익한 시간이 아니었나 생각됩니다.

아래는 제가 참고한 자료들이니 챌린지에 도전하실 분들은 한번씩 둘러보시면 좋을 것 같습니다.

긴 글 읽어주셔서 감사합니다.

마지막으로 이렇게 좋은 컨텐츠 준비해주신 모든 김치콘 스탭분들에게 감사드립니다.

아! 그리고 제가 보드받을 때 노트북을 놔두고 가서 점수를 못보여드렸는데 … 늦었지만 지금이라도 점수 인증 합니다 !

혹시라도 기회가 된다면 김치콘 챌린지 라이트업으로 한번 더 찾아뵙겠습니다 !

Leave a Reply