Description
A server log file has a flag fragmented across multiple lines. Find and reassemble the pieces.
Setup
Download the log file from the challenge page.
Solution
Want to try it yourself first?
The guided walkthrough reveals hints one step at a time.
Step 1
Search for flag fragmentsObservationI noticed the challenge description stated the flag was fragmented across multiple lines of a large log file, which suggested using grep to quickly filter the file down to only the lines containing the picoCTF label before attempting any reassembly.Use grep to find all lines containing picoCTF. Some lines may contain only partial fragments of the flag spread across multiple log entries.bashgrep -i 'picoCTF' server.logWhat didn't work first
Tried: Run grep without -i so the search is case-sensitive
If any log line uses lowercase 'picoctf' or uppercase 'PICOCTF' the match silently fails and those lines are excluded from the output. The -i flag collapses all case variants into one pass, which is the safe default when the log format is unknown.
Tried: Anchor the grep pattern on the full flag prefix: grep 'picoCTF{' server.log
Only the first fragment line contains the opening brace, so lines carrying the middle and closing fragments never match. The grep pattern must anchor on a label that is present on every fragment line, such as 'picoCTF' without the brace, or better yet the 'FLAGPART:' label used in step 2.
Learn more
grep scans a file line by line and prints every line that matches a pattern. The
-iflag makes the match case-insensitive, catching variations likePICOCTF,picoctf, or mixed case. In large log files with thousands of lines, grep reduces the search space from the full file to only the relevant matches in milliseconds.Log files are structured text files where each line typically represents one event: a timestamp, severity level, source, and message. CTF challenges use log files as a forensic artifact - the flag may appear as part of a simulated HTTP request, an error message, a database query result, or split across multiple events. Understanding the log format first helps determine how fragments are separated.
For more complex log analysis, tools like
awk,sed,jq(for JSON logs), or dedicated log analysis platforms (Splunk, Elasticsearch) provide richer filtering and transformation capabilities. In security operations, log analysis is the primary method for detecting intrusions and reconstructing attacker activity.Step 2
Extract and join all fragmentsObservationI noticed the grep output showed each relevant line contained a 'FLAGPART:' label followed by one piece of the flag, which suggested anchoring a regex on that stable label to capture every fragment in document order and then joining them into the complete flag.Use Python's re.findall to capture the value after each 'FLAGPART:' label. The fragments appear in order in the log, so joining them directly reassembles the complete flag.pythonpython3 -c " import re data = open('server.log').read() frags = re.findall(r'FLAGPART:\s*([^\n]+)', data) print(frags) print(''.join(f.strip() for f in frags)) "What didn't work first
Tried: Anchor the regex on the flag prefix instead: re.findall(r'picoCTF\{([^}]+)\}', data)
This pattern requires the opening brace, the full body, and the closing brace all on the same line. Because the flag is split across multiple lines, only the first fragment line matches and the rest are silently dropped, producing a truncated or empty result. Anchoring on the stable 'FLAGPART:' label instead captures every fragment regardless of its content.
Tried: Use grep output piped to cut or awk to extract the fragment value, skipping Python entirely
Tools like cut -d':' -f2 split on the first colon only, which breaks if any fragment value itself contains a colon (a common character in URLs logged in HTTP access logs). Python's regex with a non-greedy capture group handles arbitrary fragment content robustly and joins duplicates in one pass without a secondary deduplication step.
Learn more
Each relevant log line follows the format
[timestamp] INFO FLAGPART: <fragment>. Only the first fragment starts withpicoCTF{; the remaining fragments contain the rest of the flag body and closing brace. A pattern that anchors onpicoCTF{would therefore only capture the first piece and silently drop everything else.re.findall(pattern, string) returns a list of all non-overlapping matches in document order. The pattern
FLAGPART:\s*([^\n]+)matches the literal labelFLAGPART:, skips any whitespace with\s*, then captures everything up to the end of the line with([^\n]+). The parentheses form a capturing group, so findall returns the captured fragment values rather than the full matched strings.The
join()step concatenates the list of fragments into a single string. Because the log repeats each FLAGPART entry many times, you may see duplicates in the printed list - that is expected. The deduplication is not necessary if you only need the unique ordered sequence; reading unique fragments in document order (e.g. withdict.fromkeys(frags)) also works. Always verify the reassembled result starts withpicoCTF{and ends with}before submitting.
Flag
Reveal flag
picoCTF{us3_y0urlinux_sk1lls_...}
Fixed flag, confirmed consistent across multiple independent verified solutions.