Description
The judge for these pictures is a real fan of antiques. Can you age this photo to the specifications? Set the timestamps on this picture to 1970:01:01 00:00:00.001+00:00 with as much precision as possible for each timestamp. In this example, +00:00 is a timezone adjustment. Any timezone is acceptable as long as the time is equivalent. As an example, this timestamp is acceptable as well: 1969:12:31 19:00:00.001-05:00. For timestamps without a timezone adjustment, put them in GMT time (+00:00). The checker program provides the timestamp needed for each.
Setup
Download original.jpg, rename it to original_modified.jpg, and keep a backup.
Install exiftool and a hex editor (Bless works well on Linux).
wget https://artifacts.picoctf.net/c_mimas/91/original.jpg -O original_modified.jpgSolution
Want to try it yourself first?
The guided walkthrough reveals hints one step at a time.
Step 1
Set EXIF sub-second fieldsObservationI noticed the checker required millisecond precision (the .001 component) in every timestamp, which suggested the standard -AllDates exiftool flag would be insufficient and that the SubSec* family of EXIF tags needed to be set explicitly.Use exiftool to set SubSecCreateDate, SubSecDateTimeOriginal, and SubSecModifyDate to 1970:01:01 00:00:00.001. The checker verifies each field independently.bashexiftool -SubSecCreateDate='1970:01:01 00:00:00.001' \ -SubSecDateTimeOriginal='1970:01:01 00:00:00.001' \ -SubSecModifyDate='1970:01:01 00:00:00.001' original_modified.jpgWhat didn't work first
Tried: Use exiftool -AllDates='1970:01:01 00:00:00.001' to set all timestamps in one flag.
-AllDates only writes to the three standard EXIF IFD fields (DateTimeOriginal, CreateDate, ModifyDate) and ignores the SubSec* sub-second tags entirely. The checker validates SubSecCreateDate, SubSecDateTimeOriginal, and SubSecModifyDate as separate fields, so they remain at their original values and the checker still fails on each one.
Tried: Set the timestamp without the millisecond component: exiftool -SubSecCreateDate='1970:01:01 00:00:00' .
The field stores sub-seconds as a fractional suffix on the time string. Omitting '.001' leaves the sub-second precision field blank or zero, and the checker explicitly requires 1 ms precision (the .001 part). The checker will report the SubSec fields as unset or mismatched even though the date portion is correct.
Learn more
EXIF (Exchangeable Image File Format) embeds metadata inside JPEG, TIFF, and other image formats. Every camera and smartphone writes dozens of fields (shutter speed, GPS, camera model, multiple timestamps) into the file before the pixel data.
Timestamps live in several fields:
DateTimeOriginal(when the shutter fired),CreateDate(file creation), andModifyDate(last edit). The-AllDatesflag covers these standard EXIF fields in one shot, but it skips Samsung-proprietary blocks likeImage_UTC_Data, which is why hex editing is needed in the next step.In digital forensics, timestamps are crucial evidence. Investigators compare EXIF timestamps against file-system timestamps (
mtime,atime,ctime) and network logs to build timelines. Knowing how to manipulate (and detect manipulation of) these fields is a core skill on both sides.Step 2
Patch Samsung:TimeStampObservationI noticed the checker was still reporting a failed timestamp even after all standard EXIF SubSec fields were set, which suggested a vendor-proprietary metadata block outside the EXIF IFD structure (Samsung's Image_UTC_Data) was holding a separate millisecond Unix timestamp that only a hex editor could reach.Open the JPEG in Bless. Search for the ASCII string Image_UTC_Data; the 13-digit number that follows it (e.g. 1700513181420) is the millisecond timestamp. Replace the digits with 0000000000001 (epoch + 1 ms), keeping the byte length identical.Learn more
Many Android manufacturers embed proprietary metadata blocks in JPEG files that sit outside the standard EXIF IFD structure. Samsung's
Image_UTC_Datablock stores a Unix timestamp in milliseconds as a plain decimal ASCII string embedded in the file's bytes.To find the field in a hex editor, search for the ASCII string
Image_UTC_Data. The 13-digit decimal number immediately after the label is the millisecond timestamp. Overwrite just those digits in place so the file size stays identical; otherwise the JPEG offsets shift and the structure breaks.The target value
0000000000001is 1 millisecond past Unix epoch (1970-01-01 00:00:00.001 UTC), matching the EXIF fields you set in the previous step. Tools likegrep -b(byte-offset grep) or Python'sbytes.find()can locate the pattern programmatically if you prefer scripting to a GUI hex editor.Step 3
Submit and verifyObservationI noticed the challenge provided two separate ports (an upload port and a checker port), which suggested that raw file bytes needed to be piped via netcat to the upload port first, then a second connection to the checker port would confirm all timestamps matched the target before revealing the flag.Pipe the modified file to the uploader port, then connect to the checker. Once every timestamp reads 1970:01:01 00:00:00.001, the checker prints the flag.bashnc -w 2 mimas.picoctf.net 57925 < original_modified.jpg \ && nc -d mimas.picoctf.net 50499Expected output
picoCTF{71m3_7r4v311ng_p1c7ur3_12e0...}What didn't work first
Tried: Upload the original.jpg file directly to the checker port instead of original_modified.jpg.
The checker reads all timestamp fields from whichever file you send. Sending the unmodified original leaves every timestamp at its camera-recorded value (the original shoot date), so the checker reports all fields wrong. The rename and edit steps must be applied to the file you pipe to netcat.
Tried: Connect to the upload port and the checker port simultaneously in one netcat command using a pipe.
The upload port (57925) expects raw file bytes sent over the socket, and the checker port (50499) is a separate service that reads back the result after upload. Chaining them with a Unix pipe passes the checker's response bytes back into the upload socket, corrupting the upload. Using two sequential netcat calls - one with stdin redirect for the upload, then a separate read-only connection to the checker - keeps the data flows independent.
Learn more
netcat (
nc) is the Swiss army knife of networking. The<redirection feeds the file's raw bytes directly into the TCP stream, which is how binary upload services typically work over a raw socket.-w 2sets a 2-second idle timeout so netcat doesn't hang after the server stops sending data.-don the checker connection disables stdin entirely from the outset, so netcat does not block waiting for terminal input that will never come.Using two separate netcat connections (one to upload, one to check) is a common CTF pattern where submission and verification run on different ports. The same raw socket pattern shows up in real assessments when probing custom protocols or pushing files to embedded devices.
Flag
Reveal flag
picoCTF{71m3_7r4v311ng_p1c7ur3_12e0...}
Once every timestamp reads 1970:01:01 00:00:00.001, the checker returns the flag above.