Identify an ELF binary
Run the binary once, then inspect it without executing it:
file elf-basics readelf -h elf-basics readelf -S elf-basics
Answer in your report
- Is this an ELF32 or ELF64 binary?
- Which CPU architecture does the header report?
- What is the entry-point address?
- Which section contains executable program instructions?
Useful habit: file gives a quick summary; readelf shows the actual ELF metadata.
Follow function arguments
The program calls combine with seven numbers. Inspect the call site:
./arguments objdump -d -M intel arguments | less
Find main and the call instruction for combine.
Answer in your report
- Which registers carry arguments 1 through 6 on x86-64 Linux?
- Where does the seventh argument go?
- Which immediate values correspond to
10,20, and70before the call? - Does
combinereceive values or pointers in this example?
Hint: the standard calling convention here is the System V AMD64 ABI.
Read a conditional branch
Try two ordinary inputs, then inspect is_class_key:
./branches 1 ./branches 4919 objdump -d -M intel branches | less
Answer in your report
- Which instruction compares the argument with the class key?
- Which conditional jump selects the non-matching path?
- Is the comparison made in decimal or hexadecimal at machine-code level?
- How can you confirm your reading by running the program with a normal input?
This is a control-flow reading exercise, not a bypass exercise.
Inspect a stack frame with GDB
This program is safe: snprintf is given the size of greeting. Use GDB to observe its stack frame:
gdb ./stack-frame (gdb) break inspect_stack (gdb) run Alice (gdb) info registers (gdb) disassemble /m inspect_stack (gdb) print &greeting (gdb) info frame
Answer in your report
- Which register initially holds the
namepointer? - Where is
greetingstored whileinspect_stackruns? - What stack space does the compiler reserve? Read the instruction instead of guessing.
- Which source line copies text into
greeting, and what size limit does it use?
Quit GDB with quit. Do not modify registers or return addresses in this first lesson.
Review an input boundary
This is a code-review exercise. Run the program only with a short name:
./copy-review Alice objdump -d -M intel copy-review | less
Answer in your report
- How many bytes can
namehold? - Which function does not receive that destination size?
- Why is that a bug when the command-line input is longer than the buffer?
- Replace the copy with a bounded operation, compile your own fixed version, and test it with a short name.
Do not test oversized inputs in this exercise. The goal is to identify the boundary and implement a defensive fix.
Guided ret2shellcode
This course-owned local demonstration shows control flow reaching bytes placed in a stack buffer. The supplied shellcode starts /bin/sh with your own student-account permissions; it does not use the network or elevate privileges.
Inspect the binary
file ret2shellcode readelf -W -l ret2shellcode | grep GNU_STACK objdump -d -M intel ret2shellcode | less
- What permissions are shown for the
GNU_STACKprogram header, and why does this matter for this lab? - Why does compiling without PIE make code addresses more stable, while the printed buffer address still changes between runs?
- Which source line lets more bytes be read than
buffercan hold? - In the
vulnerableprologue, where isbufferrelative torbp? Use that to calculate the offset from the start ofbufferto the saved return address.
Use GDB to verify the frame
gdb ./ret2shellcode (gdb) break vulnerable (gdb) run (gdb) disassemble /m vulnerable (gdb) print &buffer (gdb) info frame
Do not change registers, memory, or return addresses in GDB. Use it only to read the frame layout for this guided exercise.
Read the shellcode
Open shellcode.py. It is x86 Linux shellcode that uses int 0x80 to call execve("/bin//sh", ["/bin//sh", NULL], NULL).
- Which register carries the syscall number?
- Which registers carry the filename, argument list, and environment pointers?
- Why is a NOP sled placed before the shellcode in the reference payload?
- Why does
solution.pyusestruct.pack("<I", address)?