mgchem's log
article thumbnail
Published 2023. 10. 7. 05:04
Lab2: Bomblab (bomb-quiet) Study/CS

Bomblab

 

시스템프로그래밍 Lab2 Bomblab이 나왔다.

나온지는 지난 9/26부터 시작하여 열흘도 넘었지만 ...

어셈블리어 해석과 gdb 사용이 처음인터라 익숙해지는데 오래도 걸렸다.

 

학생이 본인의 학번과 이메일 주소를 입력하여 bomb 파일을 요청하면 bomb1, bomb2, bomb3, ... 순으로 배정되는 방식이었다.

직전 과제였던 Lab1: Datalab 제출 마감된 날에 바로 열렸던 것으로 기억하는데, 나는 공지 올라오자마자 배정받았지만 도무지 진도가 나가질 않았다.

 

datalab에서 skeleton code에 내용을 채워넣던 것을 생각하던 내겐 굉장히 당황스러운 과제였다.

배정받은 binary 형식 bomb 파일은 phase_1 ~ phase_6 (+secret phase)로 구성되어 있다.

각 phase를 해결하기 위해서는 정해진 정답을 입력해야 하는데 총 몇자리인지, 정답을 구성하는 문자 종류는 무엇인지 공개하지 않아서 brute-force로 해결하기에는 무리가 있다.

폭탄 터질때마다 기록이 남아 횟수에 비례한 감점이 있기도 하고.

 

덩그러니 bomb 파일만 달랑 있어서 당황스럽지만, bomblab을 해결하는 정석적인 과정은 다음과 같다.

1. bomb 파일을 disassemble하고 잘 읽어보며 폭탄의 작동 원리와 정답의 위치를 파악한 다음,

2. gdb로 폭탄이 터지지 않도록 잘 breakpoint를 걸고 한 줄씩 실행시키며 register에 들어있는 값을 확인하고,

3. 최종적으로 각 phase마다 요구하는 정답을 알아내면 된다.

 

처음엔 뜬구름 잡는 소리로 들렸고 일주일 넘게 헤맸다. 사실 폭탄 터뜨릴까 겁나서 배정받은 bomb 파일로는 시작도 못하고 있었다.

감사하게도, gdb 사용이 익숙하지 않은 학생들을 위해 마음껏 터뜨려도 기록이 남지 않는 bomb-quiet를 제공해 주셨다.

 

bomb-quiet를 실행하면 환영 문구가 출력되고 뭔가 입력받는다.

 

시험삼아 hello를 입력했더니 폭탄이 터졌다. 폭탄 해체를 위해 bomb-quiet 파일을 disassemble하는데 사용할 수 있는 도구가 무엇이 있는지 살펴보자.

 


 

Disassemble

$ objdump -t bomb-quiet

bomb-quiet의 symbol table을 출력할 수 있다. bomb-quiet 내 모든 함수 이름이 포함되어있으며, 중요해 보이는 함수 이름을 확인하자.

$ objdump -d bomb-quiet

bomb-quiet 전체를 disassemble하여 terminal에 쭉 띄워준다. 전체 assembly code의 양이 꽤 많다. 나처럼 bomb-quiet의 전체 작동 원리를 파악하겠답시고 머리박고 한 줄 한 줄 읽어보고 있지는 말자 .. gdb를 사용하면 특정 함수만 disassemble할 수 있다.

$ strings bomb-quiet

bomb-quiet의 printable string 목록을 쭉 나열한다.

그리고 gdb를 사용하여도 된다. gdb 매뉴얼은 공식 홈페이지에도 있다.

gdbnotes-x86-64.pdf
0.00MB

위에 나열된 도구를 사용하여 bomb-quiet를 분석해도 되고, 혹은 bomb-quiet는 연습용이니까 편한 마음으로 야매로 정답을 알아낼수도 있다.

 


 

Defusing bomb-quiet

 

bomb-quiet를 disassemble하면 중간에 phase_1, explode_bomb 등 중요해 보이는 함수가 있다.

 

phase_1 함수의 assembly code를 보면 b65에서 strings_not_equal로 가는데, 그 전에 %rip + 0x51b를 %rsi에 copy한다. 두 string을 비교하러 가기 전에 %rsi에 저장하는 저 data는 무엇일까..?

 

위는 main 함수의 assembly code 중 일부이다. ctrl+f (찾기)로 phase_1을 call하는 부분을 찾았다. read_line에서는 우리가 입력한 string이 %rax에 저장된 채로 return될 것이고, 이 값을 %rdi에 copy한다. 그리고 phase_1으로 간다. 즉, phase_1에서는 %rdi에 저장된 우리의 입력값과 %rsi에 저장된 정답(혹은 정답이 저장된 memory의 address)을 비교하여 같다면 main으로 돌아가고(아마 해체 성공으로 이어질 것이다) 다르다면 b6c에서 b73으로 jump하여 이름부터 불길한 explode_bomb로 이동할 것이다.

 

gdb를 실행하고 breakpoint를 phase_1, explode_bomb에 각각 걸어준다.

 

bomb-quiet를 실행하고 임시로 hello를 입력한다. 우리가 설정한 breakpoint 중 phase_1에서 먼저 멈췄다.

 

정답을 %rsi에 저장하는 instruction인 b5e가 실행될 때까지 si를 입력하여 한 줄씩 실행시킨다.

 

해당 시점에서 x/s $rsi 를 입력하여 $rsi가 가리키는 memory의 data를 string으로 출력하면 정답으로 추정되는 시적인 문구가 등장한다. 쌍따옴표 제외하여 복사해두자. 우리는 이미 정답이 아닌 "hello"를 입력해버렸으니 이대로 쭉 실행하면 폭탄이 터진다. 따라서 quit를 입력하여 현재의 debugging session을 종료한 뒤 해당 문구가 정답이 맞는지 확인하기 위해 다시 gdb를 실행한다. 이 때 gdb를 껐다 다시 켜면 설정했던 breakpoint들이 날아간다. 혹시나 위의 문구가 정답이 아니라면 폭탄이 바로 터져버리므로 동일하게 breakpoint를 설정하고 실행시켜 답을 입력하면?

 

Phase 1 defused. 라고 출력되고 프로그램이 종료됨을 확인할 수 있다. bomb-quiet에 들어있는 phase는 하나이다. 이로써 bomb-quiet를 해결하였다.

'Study > CS' 카테고리의 다른 글

Lab2: Bomblab (phase 5)  (0) 2023.10.08
Lab2: Bomblab (phase 4)  (0) 2023.10.08
Lab2: Bomblab (phase 3)  (1) 2023.10.08
Lab2: Bomblab (phase 2)  (0) 2023.10.08
Lab2: Bomblab (phase 1)  (1) 2023.10.07
profile

mgchem's log

@mgchem

뱁새의 다리찣기