strings | grep -i flag
dd if=<input_file> of=<output_file> bs=<block_size> skip=<n_blocks> count=<n_blocks>
dd if=<input_file> of=<output_file> bs=<block_size> skip=<n_blocks> count=<n_blocks>
dd if=<input_file> of=<output_file> bs=<block_size> skip=<n_blocks> count=<n_blocks>
skip=4096 count=200
conv=notrunc
$ file mystery.img
mystery.img: DOS/MBR boot record $ strings mystery.img | grep -i "flag\|ctf\|pico"
(no output) $ xxd mystery.img | head -50
00000000: eb52 9045 5854 3220 2020 2000 0201 2000 .R.EXT2 .. .
00000010: 0000 0000 0000 29f8 b703 004e 4f20 4e41 ......)....NO NA
# I scrolled through this for 20+ minutes $ binwalk mystery.img DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
0 0x0 DOS/MBR boot record
1048576 0x100000 PNG image, 640 x 480, 8-bit/color RGB
1183744 0x121000 End of Zip archive # I stared at this output for five minutes not knowing what to do with it
$ file mystery.img
mystery.img: DOS/MBR boot record $ strings mystery.img | grep -i "flag\|ctf\|pico"
(no output) $ xxd mystery.img | head -50
00000000: eb52 9045 5854 3220 2020 2000 0201 2000 .R.EXT2 .. .
00000010: 0000 0000 0000 29f8 b703 004e 4f20 4e41 ......)....NO NA
# I scrolled through this for 20+ minutes $ binwalk mystery.img DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
0 0x0 DOS/MBR boot record
1048576 0x100000 PNG image, 640 x 480, 8-bit/color RGB
1183744 0x121000 End of Zip archive # I stared at this output for five minutes not knowing what to do with it
$ file mystery.img
mystery.img: DOS/MBR boot record $ strings mystery.img | grep -i "flag\|ctf\|pico"
(no output) $ xxd mystery.img | head -50
00000000: eb52 9045 5854 3220 2020 2000 0201 2000 .R.EXT2 .. .
00000010: 0000 0000 0000 29f8 b703 004e 4f20 4e41 ......)....NO NA
# I scrolled through this for 20+ minutes $ binwalk mystery.img DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
0 0x0 DOS/MBR boot record
1048576 0x100000 PNG image, 640 x 480, 8-bit/color RGB
1183744 0x121000 End of Zip archive # I stared at this output for five minutes not knowing what to do with it
$ binwalk mystery.img DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
0 0x0 DOS MBR boot record
1048576 0x100000 PNG image, 640 x 480, 8-bit/color RGB
1183744 0x121000 End of Zip archive # count = end_offset - start_offset = 1183744 - 1048576 = 135168
$ dd if=mystery.img of=extracted.png bs=1 skip=1048576 count=135168
135168+0 records in
135168+0 records out
135168 bytes (135 kB, 132 KiB) copied, 0.412 s, 328 kB/s $ file extracted.png
extracted.png: PNG image data, 640 x 480, 8-bit/color RGB, non-interlaced
$ binwalk mystery.img DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
0 0x0 DOS MBR boot record
1048576 0x100000 PNG image, 640 x 480, 8-bit/color RGB
1183744 0x121000 End of Zip archive # count = end_offset - start_offset = 1183744 - 1048576 = 135168
$ dd if=mystery.img of=extracted.png bs=1 skip=1048576 count=135168
135168+0 records in
135168+0 records out
135168 bytes (135 kB, 132 KiB) copied, 0.412 s, 328 kB/s $ file extracted.png
extracted.png: PNG image data, 640 x 480, 8-bit/color RGB, non-interlaced
$ binwalk mystery.img DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
0 0x0 DOS MBR boot record
1048576 0x100000 PNG image, 640 x 480, 8-bit/color RGB
1183744 0x121000 End of Zip archive # count = end_offset - start_offset = 1183744 - 1048576 = 135168
$ dd if=mystery.img of=extracted.png bs=1 skip=1048576 count=135168
135168+0 records in
135168+0 records out
135168 bytes (135 kB, 132 KiB) copied, 0.412 s, 328 kB/s $ file extracted.png
extracted.png: PNG image data, 640 x 480, 8-bit/color RGB, non-interlaced
00 00 00 00 4E 47 0D 0A
89 50 4E 47 0D 0A 1A 0A
# Create a file containing the correct PNG magic bytes
$ printf '\x89\x50\x4e\x47\x0d\x0a\x1a\x0a' > correct_header.bin # Patch the header — conv=notrunc is mandatory
$ dd if=correct_header.bin of=broken.png bs=1 count=8 conv=notrunc
8+0 records in
8+0 records out
8 bytes copied, 0.000074 s, 108 kB/s $ file broken.png
broken.png: PNG image data, 1920 x 1080, 8-bit/color RGBA, non-interlaced
# Create a file containing the correct PNG magic bytes
$ printf '\x89\x50\x4e\x47\x0d\x0a\x1a\x0a' > correct_header.bin # Patch the header — conv=notrunc is mandatory
$ dd if=correct_header.bin of=broken.png bs=1 count=8 conv=notrunc
8+0 records in
8+0 records out
8 bytes copied, 0.000074 s, 108 kB/s $ file broken.png
broken.png: PNG image data, 1920 x 1080, 8-bit/color RGBA, non-interlaced
# Create a file containing the correct PNG magic bytes
$ printf '\x89\x50\x4e\x47\x0d\x0a\x1a\x0a' > correct_header.bin # Patch the header — conv=notrunc is mandatory
$ dd if=correct_header.bin of=broken.png bs=1 count=8 conv=notrunc
8+0 records in
8+0 records out
8 bytes copied, 0.000074 s, 108 kB/s $ file broken.png
broken.png: PNG image data, 1920 x 1080, 8-bit/color RGBA, non-interlaced
conv=notrunc
# -b: print byte offset, -o: only matching text, -a: treat binary as text
$ grep -boa "END_HEADER" data.bin
204800:END_HEADER # Skip past the marker: offset 204800 + len("END_HEADER") = 204810
$ dd if=data.bin of=after_marker.bin bs=1 skip=204810 $ strings after_marker.bin | head -3
picoCTF{h1dd3n_4ft3r_th3_m4rk3r_ab12cd}
# -b: print byte offset, -o: only matching text, -a: treat binary as text
$ grep -boa "END_HEADER" data.bin
204800:END_HEADER # Skip past the marker: offset 204800 + len("END_HEADER") = 204810
$ dd if=data.bin of=after_marker.bin bs=1 skip=204810 $ strings after_marker.bin | head -3
picoCTF{h1dd3n_4ft3r_th3_m4rk3r_ab12cd}
# -b: print byte offset, -o: only matching text, -a: treat binary as text
$ grep -boa "END_HEADER" data.bin
204800:END_HEADER # Skip past the marker: offset 204800 + len("END_HEADER") = 204810
$ dd if=data.bin of=after_marker.bin bs=1 skip=204810 $ strings after_marker.bin | head -3
picoCTF{h1dd3n_4ft3r_th3_m4rk3r_ab12cd}
$ fdisk -l disk.img
Disk disk.img: 100 MiB, 104857600 bytes, 204800 sectors
Units: sectors of 1 * 512 = 512 bytes Device Boot Start End Sectors Size Type
disk.img1 2048 43007 40960 20M Linux filesystem
disk.img2 43008 204799 161792 79M Linux filesystem # Extract partition 2: skip and count are in sectors because bs=512
$ dd if=disk.img of=partition2.img bs=512 skip=43008 count=161792
161792+0 records in
161792+0 records out $ file partition2.img
partition2.img: Linux rev 1.0 ext2 filesystem data
$ fdisk -l disk.img
Disk disk.img: 100 MiB, 104857600 bytes, 204800 sectors
Units: sectors of 1 * 512 = 512 bytes Device Boot Start End Sectors Size Type
disk.img1 2048 43007 40960 20M Linux filesystem
disk.img2 43008 204799 161792 79M Linux filesystem # Extract partition 2: skip and count are in sectors because bs=512
$ dd if=disk.img of=partition2.img bs=512 skip=43008 count=161792
161792+0 records in
161792+0 records out $ file partition2.img
partition2.img: Linux rev 1.0 ext2 filesystem data
$ fdisk -l disk.img
Disk disk.img: 100 MiB, 104857600 bytes, 204800 sectors
Units: sectors of 1 * 512 = 512 bytes Device Boot Start End Sectors Size Type
disk.img1 2048 43007 40960 20M Linux filesystem
disk.img2 43008 204799 161792 79M Linux filesystem # Extract partition 2: skip and count are in sectors because bs=512
$ dd if=disk.img of=partition2.img bs=512 skip=43008 count=161792
161792+0 records in
161792+0 records out $ file partition2.img
partition2.img: Linux rev 1.0 ext2 filesystem data
$ binwalk multi.bin DECIMAL HEXADECIMAL DESCRIPTION
280 0x118 JPEG image data
4096 0x1000 Zip archive data
8192 0x2000 ELF 64-bit LSB executable $ dd if=multi.bin of=image.jpg bs=1 skip=280 count=3816
$ dd if=multi.bin of=archive.zip bs=1 skip=4096 count=4096
$ dd if=multi.bin of=binary.elf bs=1 skip=8192
$ binwalk multi.bin DECIMAL HEXADECIMAL DESCRIPTION
280 0x118 JPEG image data
4096 0x1000 Zip archive data
8192 0x2000 ELF 64-bit LSB executable $ dd if=multi.bin of=image.jpg bs=1 skip=280 count=3816
$ dd if=multi.bin of=archive.zip bs=1 skip=4096 count=4096
$ dd if=multi.bin of=binary.elf bs=1 skip=8192
$ binwalk multi.bin DECIMAL HEXADECIMAL DESCRIPTION
280 0x118 JPEG image data
4096 0x1000 Zip archive data
8192 0x2000 ELF 64-bit LSB executable $ dd if=multi.bin of=image.jpg bs=1 skip=280 count=3816
$ dd if=multi.bin of=archive.zip bs=1 skip=4096 count=4096
$ dd if=multi.bin of=binary.elf bs=1 skip=8192
# Step 1: What is this thing?
file target.img # Step 2: What's embedded inside it?
binwalk target.img # Step 3: If binwalk shows interesting offsets, act immediately
dd if=target.img of=extracted bs=1 skip=<offset> # Step 4: What did we get?
file extracted
strings extracted | head -20
exiftool extracted # if it looks like an image
# Step 1: What is this thing?
file target.img # Step 2: What's embedded inside it?
binwalk target.img # Step 3: If binwalk shows interesting offsets, act immediately
dd if=target.img of=extracted bs=1 skip=<offset> # Step 4: What did we get?
file extracted
strings extracted | head -20
exiftool extracted # if it looks like an image
# Step 1: What is this thing?
file target.img # Step 2: What's embedded inside it?
binwalk target.img # Step 3: If binwalk shows interesting offsets, act immediately
dd if=target.img of=extracted bs=1 skip=<offset> # Step 4: What did we get?
file extracted
strings extracted | head -20
exiftool extracted # if it looks like an image
dd if=mystery.img of=mystery.img ...
extracted.png - if= — your input (the disk image or binary you're carving from)
- of= — your output (always write to a new file — never overwrite the original)
- bs= — block size. Use bs=1 for byte-accurate extraction, bs=512 or bs=4096 for disk sector operations
- skip= — skip this many blocks from the start before reading
- count= — read this many blocks total