Description
Debugger0_c stores 0x2262c96b on the stack. Examine the bytes exactly as they appear in memory and wrap them (in order) inside picoCTF{...}.
Setup
Launch the binary under gdb and switch to layout asm to see where the MOV that stores 0x2262c96b executes.
Set a breakpoint right afterward (main+25) so the stack contents can be inspected before anything is overwritten.
wget https://artifacts.picoctf.net/c/531/debugger0_cchmod +x debugger0_cgdb --args ./debugger0_cSolution
Want to try it yourself first?
The guided walkthrough reveals hints one step at a time.
Step 1Break after the store
ObservationA MOV stores 0x2262c96b onto the stack. Halt right after it, while the bytes are in place and nothing has overwritten them.Place b *(main+25) so execution halts immediately after the constant is written to the stack. Run the program to hit that breakpoint.bashb *(main+25)bashrunWhat didn't work first
Tried: Breaking at main instead of main+25 to inspect the stack slot early.
At the top of main the frame is not set up and the store has not run, so that slot holds whatever was there before. Break after the store, and the four bytes are actually present when you look.
Tried: Using 'break main' and then stepping through with 'next' until reaching the store instruction.
Source-level stepping skips individual instructions, because GDB maps several of them to one source line. If the store sits inside a line that completes in a single step, you land past it and read a later value. An offset breakpoint stops at the exact instruction boundary.
Learn more
This challenge introduces memory inspection: reading raw bytes from a specific address rather than just reading a register value. After the MOV instruction writes
0x2262c96bto[rbp-0x4], the four bytes are stored in RAM at that stack address. Breaking immediately after the store lets you inspect those bytes before anything overwrites them.The key concept is that the CPU stores multi-byte integers in little-endian byte order on x86. Little-endian means the least significant byte is stored at the lowest memory address. So the 32-bit value
0x2262c96bis stored in memory as the byte sequence6b c9 62 22(lowest byte first). When the challenge asks you to report the bytes "in order," it means in the order they appear in memory - which is the reversed byte order compared to how you read the constant in the assembly listing.Understanding endianness is critical in networking (network byte order is big-endian), binary exploitation (shellcode must account for byte order when encoding addresses), and file format parsing (file formats vary by endianness - JPEG is big-endian, most x86 executables are little-endian). Getting endianness wrong is one of the most common sources of bugs in low-level code.
Step 2Dump four bytes from the stack
ObservationThe flag wants the bytes in the order they sit in memory, so read the stack slot one byte at a time. That shows the little-endian sequence rather than the constant as the assembly listing writes it.Use x/4xb $rbp-4 to view the byte order as stored in memory. The address $rbp-4 matches the [rbp-0x4] stack slot where the assembly stored the constant; the little-endian byte order means the bytes appear reversed compared to reading 0x2262c96b left-to-right. Concatenate those bytes, preserving order, to form the hexadecimal inside the flag.bashx/4xb $rbp-4Expected output
0x...: 0x6b 0xc9 0x62 0x22
What didn't work first
Tried: Reading the flag bytes directly from the constant 0x2262c96b as printed in the assembly listing, giving '2262c96b'.
The listing prints the value in logical order and x86 stores it little-endian, so memory holds it reversed. Concatenate what the byte-wise examine prints, not the immediate as written. Submitting the immediate is the most common wrong answer here.
Tried: Using x/1xw $rbp-4 to print the whole 32-bit word at once instead of examining individual bytes.
A word-sized examine prints the value as a 32-bit integer, converting back to host order, so you see the same number the assembly already showed you. That hides the reversal instead of revealing it. Examine four individual bytes.
Learn more
The GDB examine command (
x) reads memory at an arbitrary address and displays it in a chosen format. The syntaxx/4xb $rbp-4means: examine 4 units, formatted as hex, each unit being one byte, starting at the address$rbp - 4. GDB prints each byte individually, separated by spaces, which makes it easy to read the byte sequence in memory order.To build the flag, concatenate the four bytes exactly as GDB prints them. Because x86 is little-endian, the byte GDB prints first is the least-significant byte of the original 32-bit value - so the output will appear "reversed" compared to
0x2262c96b. The challenge is testing whether you understand this reversal and report the bytes in memory order rather than the logical order.The
xcommand is invaluable in real debugging and exploitation work. When inspecting a buffer overflow, you might usex/32xb $rspto view 32 bytes of stack data. When verifying a shellcode injection,x/10i $ripdisassembles ten instructions starting at the instruction pointer. Learning the format specifiers (x=hex, d=decimal, s=string, i=instruction, b=byte, h=halfword, w=word, g=giant/8-byte) is worth the small investment.
Interactive tools
- Cyclic Pattern GeneratorGenerate de Bruijn cyclic patterns and find buffer overflow offsets. The browser equivalent of pwntools cyclic and cyclic_find.
- pwntools Payload BuilderPack integers into little-endian bytes (p32 / p64), unpack bytes back to integers, and build flat ROP payloads with offset-based insertion.
- Hex ViewerView text or raw hex bytes as a xxd-style hex dump with byte offset, hex columns, and ASCII sidebar. Highlights printable characters and null bytes.
Flag
Reveal flag
picoCTF{0x6b......22}
For this binary the four bytes are always 6b c9 62 22; copy them exactly as x/4xb prints them, in memory order.