프로그램을 실행하면 위처럼 1번 옵션인 add_note를 했을 때 index, number of note, content를 입력할 수 있다.
2번 옵션인 del note를 실행하면 index값을 입력해주고, 해당 index에 노트가 존재하면 지우고 없으면 없다고 출력해준다.
위 바이너리를 ida로 열어본다.
메인 소스코드이다. 각 옵션들에 따라 해당 함수를 실행시키는 것을 알 수 있다.
2번옵션인 delete_note 함수 소스이다.
get num으로 값을 받아서 해당 인덱스에 해당하는 부분을 free해주는것으로 보인다.
1번 옵션인 add_note 함수이다.
for문안을 보면 qword_2020e0[v2+i] 를 보면 note의 index로 입력해주는 v2 값을 배열의 인덱스로 사용한다.
qword_2020e0에 들어가면 bss영역임을 확인 할 수 있다. 해당 주소에서 조금더 올라가면
Got영역이 나온다. V2 입력값을 음수로 입력 및 조절해서 got영역으로 이동시킬 수 있고 content를 입력해주는 함수를 통해 got overwrite가 가능하다.
exploit을 하기 위해서
stlen 함수에 의해서 content의 길이가 3byte 보다 작아야하기 때문에 strlen got overwrite를 통해 strlen 길이 제한을 없애준다.
if문을 정상적으로 통과해야 got overwrite가 가능하기 때문에 3byte 크기로 overwrite해줘야 한다.
어떤식으로 overwrite를 해주냐면 strlen의 반환값인 eax를 0으로 고정시켜주는 asm을 짜야한다.
xor eax,eax
ret
을 기계어로 디스어셈블 해준다.
\x31\xc0\xc3 -> 3byte가 나온다.
위 기계어를 strlen함수의 got에 overwrite해주고
이후에 exploit을 계획하면된다.
content를 입력하는 부분을 보면 길이제한이 8바이트로 제한되어있다. 그렇기 때문에 바로 쉘코드를 삽입하지 못하고
system_exec를 디스어셈블해서 atoi 함수에 넣어준다.
atoi 함수는 note옵션을 입력할 떄 사용된다.
해당 코드는 system_exec함수를 호출하기 위한 코드이다. 64bit syscall에서는 인자순서에따라 들어가는 레지스터들이 정해져있다.
2번째, 3번째인자로 들어가는 esi 와 edx를 0으로 초기화해주고 system_exec에 해당하는 syscall number를 al에 넣고 syscall을 실행해준다.
위 코드를 통해 argv, envp를 0으로 초기화해줬다. 이후 atoi함수가 실행될때 filename을 /bin/sh로 입력해주면 실행이 될것이다.
위 코드는 \x31\xf6\x31\xd2\xb0\x3b\x0f\x05로 8byte이다.
atoi함수가 실행되는 옵션 번호를 받아오는 함수이다.
해당 입력값은 &nptr로 들어가는데 이값이 sys_execve가 되면 rdi값으로 들어가게 된다.
그렇기 때문에 overwrite이후 입력값이 rdi 즉 실행시키는 파일주소로 들어가 sys_call을 실행시킨다.
우리는 rdi -> &nptr에 /bin/sh을 넣어주면 될것이다.
========================흐름 정리=======================
1. qword_2020e0[v2+i] = strdup(&s)를 보면 content에 입력한 값이 bss영역을 참조하는 배열의 인덱스로 들어가는데, index값에 음수를 넣어 줌으로써 got영역에 접근이 가능하고 content_input 함수를 통해 그 주소에 입력이 가능하다. -> got overwrite가 가능하다.
그리고 qword 단위로 들어가기때문에 주소는 8byte단위로 잘라준다.
2. 위부분의 if문을 우회하기 위해 strlen 함수의 got를 overwrite 해야한다. strlen의 반환값은 eax에 저장되므로 우회하기 위해서 eax를 0으로 고정시켜주는 어셈블리어를 기계어로 변환하여 넣어준다. => \x31\xc0\xc3
ret은 프로그램을 계속 실행시켜주기위해 저장해둔 eip를 pop하는 것이다.
3.이후 쉘 코드를 넣어야 하지만 contant_input의 크기가 8byte로 되어있기 때문에 8byte에 맞춰서 exploit을 계획해야한다. 여기서 get_num함수에 있는 atoi함수를 이용한다. 이유는 atoi에 입력한 값이 & 즉 주소로 들어가기 때문이다. sys_execv의 함수의 첫번쨰 인자도 파일의 주소를 넣어줘야하기 때문에 atoi의 &인자가 들어가면 편하다.
4. atoi 함수를 got overwrite하기 위해 sys_execve을 함수 호출 규약에 맞게 어셈코드를 짜준다.
xor esi, esi
xor edx,edx
mov al,0x3b
syscall
위 코드를 기계어 코드로 변환하면 \x31\xf6\x31\xd2\xb0\x3b\x0f\x05 총 8바이트이다.
위 기계어로 got overwrite를 해주고 실행시키고 싶은 /bin/sh을 입력하면 쉘을 실행시킬 수 있다.
페이로드이다.
32-bit와 64-bit system 함수 호출 규약의 차이를 잘알아야한다.
기계어를 입력해주기 위해선 python프로그램을 통해 입력해줘야한다.
contant_input 은 변수명을 왜저렇게 설정했는지 모르겠다 bob중이라 뇌가 이상해졌었나보다