Lesson
5 minutos de lectura
Se nos proporciona un archivo binario llamado main
y su código fuente en C:
#include <stdio.h>
void under_construction(){
printf("This is under development\n");
}
void print_msg(char *user){
char formatter[0x20];
strncpy(formatter, user, 5);
for (size_t i = 0; i < 5; i++) formatter[i] = tolower(formatter[i]);
printf(strncmp(formatter, "admin", 5) == 0 ? "\nWelcome admin!\n\n" : "\nWelcome user!\n\n");
}
int main(int argc, char **argv){
char name[0x20] = {0};
unsigned long x, y;
printf("Enter your name: ");
scanf("%s", name);
print_msg(name);
return 0;
}
Se nos pide que respondamos algunas preguntas sobre explotación de binarios.
Pregunta 1
$ nc 94.237.63.93 58324
This is a quick lesson to get started with the basics.
◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉
◉ ◉
◉ HINT: Run 'file ./main' to get some information about the binary. ◉
◉ ◉
◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉
[*] Question number 0x1:
Is this a '32-bit' or '64-bit' ELF? (e.g. 1337-bit)
Debemos comprobar si el binario es de 32 bits o de 64 bits:
$ file main
main: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter ./glibc/ld-linux-x86-64.so.2, BuildID[sha1]=da663acb70f9fa157a543a6c4affd05e53fbcb07, for GNU/Linux 3.2.0, not stripped
>> 64-bit
♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠
♠ ♠
♠ Correct ♠
♠ ♠
♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠
Pregunta 2
◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉
◉ ◉
◉ HINT: Run 'gdb ./main' to open the binary in the debugger, then ◉
◉ run 'checksec' to see the protections. ◉
◉ ◉
◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉
[*] Question number 0x2:
Which of these 3 protections are enabled (Canary, NX, PIE)?
Se nos pide que veamos las medidas de seguridad habilitadas en el binario:
$ checksec main
[*] './main'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
RUNPATH: b'./glibc/'
>> NX
♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠
♠ ♠
♠ Correct ♠
♠ ♠
♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠
Pregunta 3
Debemos echar un vistazo al código y ver qué usuario necesitamos proporcionar para obtener un determinado mensaje:
◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉
◉ ◉
◉ HINT: Pay attention to the 'void print_msg(char *user)' ◉
◉ and the 'strncmp(arg1, arg2, n_bytes)'. ◉
◉ ◉
◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉
[*] Question number 0x3:
What do you need to enter so the message 'Welcome admin!' is printed?
>> admin
♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠
♠ ♠
♠ Correct ♠
♠ ♠
♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠
Pregunta 4
Esta pregunta por el tamaño reservado para el buffer name
:
◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉
◉ ◉
◉ HINT: This is the buffer --> char name[0x20] = {0}; ◉
◉ ◉
◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉
[*] Question number 0x4:
What is the size of the 'name' buffer (in hex or decimal)?
>> 0x20
♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠
♠ ♠
♠ Correct ♠
♠ ♠
♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠
Pregunta 5
Aquí, debemos proporcionar el nombre de la función que nunca se ejecuta en la rutina principal:
◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉
◉ ◉
◉ HINT: Only functions inside 'main()' are called. ◉
◉ Also, the functions these functions call. ◉
◉ ◉
◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉
[*] Question number 0x5:
Which custom function is never called? (e.g. vuln())
>> under_construction
♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠
♠ ♠
♠ Correct ♠
♠ ♠
♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠
Pregunta 6
Esta vez, debemos encontrar una función que se use de manera incorrecta y que pueda causar una vulnerabilidad de Buffer Overflow:
◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉
◉ ◉
◉ HINT: Which function reads the string from the stdin? ◉
◉ ◉
◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉
[*] Question number 0x6:
What is the name of the standard function that could trigger a Buffer Overflow? (e.g. fprintf())
Esta vulnerabilidad aparece en scanf("%s", name)
, porque la cadena de formato "%s"
admite cualquier longitud de cadena, pero name
tiene solamente 0x20
bytes reservados:
>> scanf
♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠
♠ ♠
♠ Correct ♠
♠ ♠
♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠
Pregunta 7
◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉
◉ ◉
◉ HINT: A Segmentation Fault occurs when the return ◉
◉ address is overwritten with an invalid address. ◉
◉ ◉
◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉
[*] Question number 0x7:
Insert 30, then 39, then 40 'A's in the program and see the output.
After how many bytes a Segmentation Fault occurs (in hex or decimal)?
Debemos probar algunos payloads para ver si ocurre un Segmentation Fault:
$ python3 -c 'print("A" * 30)'
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
$ ./main
Enter your name: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Welcome user!
$ python3 -c 'print("A" * 39)'
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
$ ./main
Enter your name: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Welcome user!
$ python3 -c 'print("A" * 40)'
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
$ ./main
Enter your name: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Welcome user!
zsh: segmentation fault (core dumped) ./main
So, we have the answer:
>> 40
♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠
♠ ♠
♠ Correct ♠
♠ ♠
♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠
Pregunta 8
◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉
◉ ◉
◉ HINT: Run 'gdb ./main' to open the binary in the debugger, then ◉
◉ run 'p <function_name>' to see the address of a function. ◉
◉ ◉
◉ e.g. pwndbg> p main ◉
◉ $2 = {<text variable, no debug info>} 0x401294 <main> ◉
◉ ◉
◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉
[*] Question number 0x8:
What is the address of 'under_construction()' in hex? (e.g. 0x401337)
Se nos pide que veamos la dirección de under_construction
:
$ objdump -M intel -d main | grep under_construction
00000000004011d6 <under_construction>:
Y esta es:
>> 0x4011d6
♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠
♠ ♠
♠ Correct ♠
♠ ♠
♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠
Flag
Esta es la flag:
Great job! It's high time you solved your first challenge! Here is the flag!
HTB{w4rm35t_w4rmup_3v3r}