Related: Hosting these challenges
EZ pwn 1 (2022)
https://squarectf.com/2022/ezpwn1.html
Challenge Description:
Memory safety? Whats that? Required Reading:
Along with this challenge, we are given the following C program:
This helpful program starts by copying a command into memory, which will then be executed at runtime.
In ideal usage, we can netcat into this server, and it will helpfully print out the files:
Hmm, it looks like there’s a directory called the_flag_is_in_here
. It sure would be nice if we could do more than just ls
.
Let’s look at the core part of the program:
The read
function is trying to read 24 bytes of data into way_too_small_input_buf
, which is only 8 bytes in size. This means that if a user inputs more than 8 bytes, the excess data will overflow into the adjacent memory space, which in this case is occupied by the command
buffer.
In C, local variable order is implementation defined. That is, we can’t guarantee it’s going to be in a specific order. However, when C is compiled with gcc, variables are stored on the stack in the reverse order of their declaration. So, even though way_too_small_input_buf
is declared after command
, it is actually located at a lower memory address. When a buffer overflow occurs, it overflows upwards into higher memory addresses, affecting command
in this case.
Higher memory addresses
---------------------------
| command |
---------------------------
| way_too_small_input_buf |
---------------------------
Lower memory addresses
So, if a buffer overflow occurs in way_too_small_input_buf
, it will overflow into the memory space occupied by command
.
Using this information, we can try to overflow the buffer:
Higher memory addresses
------------
| pwd |
------------
| aaaaaaaa |
------------
Lower memory addresses
So we can enter:
Hi! would you like me to ls the current directory?
aaaaaaaapwd
Ok, here ya go!
/home/pwnable_user
That’s great! We just changed the command it’s executing. Let’s try using /bin/bash
to get an executable shell.
And, there we go!
Hi! would you like me to ls the current directory?
aaaaaaaa/bin/bash
Ok, here ya go!
pwd
/home/pwnable_user
ls
ez-pwn-1 the_flag_is_in_here
cd the_flag_is_in_here
ls
flag.txt
cat flag.txt
flag{congrats_youve_exploited_a_memory_corruption_vulnerability}
EZ pwn 2 (2022)
https://squarectf.com/2022/ezpwn2.html
Challenge Description:
Required reading:
Optional Reading:
And we are given the following C program:
Looking at the required reading, we see a reference to the x86-64 stack layout.
Eli Bendersky’s blog post has a great series of diagrams showing how data is pushed onto the stack.
When a buffer overflow occurs, you’re writing more data to a local variable than it can hold. This extra data can overwrite other local variables and even the return address. By carefully controlling the data that’s written, you can overwrite the return address with an address of your choosing.
Looking at the code:
Our goal here is to find the offset of the function this_function_literally_prints_the_flag
.
The gimme_pointer function has a buffer overflow vulnerability because it reads 64 bytes into a 17-byte buffer. This can overwrite the saved return address on the stack. If we can control this overwrite, we can make the function return to this_function_literally_prints_the_flag instead of where it was supposed to go.
Also, note that modern systems use Address Space Layout Randomization (ASLR) to randomize the location of functions in memory, so we’re going to have to do this calculation based on the printed hex value.
It’s also important to note how our input must be formed:
Hi! I am the Stack Oracle.
You are here: 0x7ffc771ffd60
Give me an address and I will grant you 8 leaked bytes:
deadbeef
Here are the contents of 0xefbeadde:
In little endian format, the least significant byte is stored first. So, for the hexadecimal number deadbeef, it would be stored and interpreted as efbeadde
.
This is why when we input deadbeef
, the program reads it as 0xefbeadde. If you want the program to interpret it as 0xdeadbeef
, you would need to input it in little endian format, which would be efbeadde
.
Hi! I am the Stack Oracle.
You are here: 0x7ffff5a86980
Give me an address and I will grant you 8 leaked bytes:
efbeadde
Here are the contents of 0xdeadbeef:
I’m gonna be real with you: i haven’t figured this out yet. If I find a solution, I’ll update you here. This is my best attempt so far, but I think I’m missing something.
Huge Primes (2021)
https://squarectf.com/2021/hugeprimes.html
Find the prime factors of
22952152323332505688670761214671498225451684330137990990356473040741684014997701799009910066964917896400501477
This challenge is designed to trick you.
Factoring this really large number is going to be incredibly difficult.
This is really a challenge about binary numbers in JavaScript.
We are provided with the file sourcecode.js
:
Here is the solution provided by the challenge author:
One solution is to find the actual prime factors of 22952152323332505688670761214671498225451684330137990990356473040741684014997701799009910066964917896400501477 by actually factorizing it. The solution is 618706242907094285939447607839 * 37097011039500744117766681095100420923783393727502071430377140015810453843499643 (I know because I generated these two primes and multipled them together :P) This is nontrivial however, and not even I know the prime factors :PHowever, all numbers in JavaScript are floats, and beyond 2^53 - 1, all numbers in js are floats. With a number as large as the one above, this means that the double precision representation of the number is:
1.0011100010111011111000001010110110101011111111100001 * 2^363
Which is equal to 22952152323332505416587153773067821404219604570062873267600242062142093944707836288883856033656043372550291456 (which is definitely NOT the same number!). In fact, with numbers that large, all numbers in js are actually just powers of 2 and thus, are even!
This leads to weird quirks, such as the fact that 22952152323332505416587153773067821404219604570062873267600242062142093944707836288883856033656043372550291456 == 22952152323332505688670761214671498225451684330137990990356473040741684014997701799009910066964917896400501477 returns true
We could thus bypass the check with something like this: 22952152323332505688670761214671498225451684330137990990356473040741684014997701799009910066964917896400501477 / 2 = 1.1476076161666253e+109
Note that this returns true: 1.1476076161666253e+109 * 2 == 22952152323332505688670761214671498225451684330137990990356473040741684014997701799009910066964917896400501477
(see https://www.exploringbinary.com/the-spacing-of-binary-float)
To solve this one, I recommend used WolframAlpha to handle the math for me, in scientific notation, with the query “number / 2 in scientific notation” (link)
Clicking ‘more digits’, and converting the result to Javascript yields us 1.1476076161666252e109
and 2
, which gives us the flag.
Developer’s Hubris (2022)
https://squarectf.com/2022/developershubris.html
You’re a new security engineer at the company, and you just found a fairly old, unfinished application running in a staging environment that is exposed to the internet. You bring this up to the developers, since it seems likely that hackers will look for ways to use this application as an entrypoint into the corporate environment. However, they tell you that it’s just a basic bug report submission portal, and any dangerous code has been removed or hidden, so it should be safe. See if they left any loose ends that could be used to compromise the entire application
Well, that’s a bit vague.
Let’s see what we’re working with:
Beautiful graphic design 🤩
What happens when we enter in some data?
And we get:
Sorry, a new folder couldn't be created for your reports
Hmm. Unfortunate.
Checking the source code (Ctrl+U) of the main page, we see:
Looks like someone commented out an iframe linking to the help menu!
What happens when we visit /help.html
?
If we use our browser’s developer tools to edit the page to replace
<!--<iframe src="/help.html" title="Help Menu"></iframe>-->
with
We can see the help page.
In the source code distributed with the challenge, we see the following file:
This is not finished either.
Korean Space Program (2021)
https://squarectf.com/2021/koreanspaceprogram.html
The Korean Space Program’s login portal is having trouble with unauthorized access to their systems. You can find their login page linked. Can you take a look at it and the included source file to figure out what is wrong?
This problem includes the following Express app:
Show full code
This looks pretty innocent to begin with. They’re even making sure that it’s secure against timing attacks. That’s great.
However, if you’re in Vim and you do :set list
, you’ll notice something off:
There are no spaces between the environment checks 🤔
Looking more closely, using a Unicode Character analyzer, we can see that the Korean developers must have errantly added some whitespace to this code:
This is a theme for all of the unary plus expressions. They are prefixed by the Unicode Character “ㅤ” (U+3164)
The Hangul Filler character is used to introduce eight-byte Hangul composition sequences and to stand in for an absent element (usually an empty final) in such a sequence.
There’s also a Hangul Filler character in the object destructuring:
meaning that three request parameters are destructured into local variables:
As such, we can control the value of the filler character via URL parameters.
If we throw this into https://astexplorer.net/, we can see that the left expression is properly interpreted as a UnaryExpression, which is what we wanted. It’s going to make any number positive.
However, the right hand side of +ENV_STAGE_WEST ==ㅤ+ENVIRONMENT
gets interpreted as a binary expression, concatenating the variable named \u3164
(whitespace) to ENVIRONMENT
.
Thus, if we can control the value of that variable, we can make the environment comparison evaluate to true
, and we can get access.
Looking at the values we’re comparing to, we’d need to produce one of 1, 2, 4, 8, 16, or 32.
In the final comparison, we can see that ENV_DEV_WEST
equals 32
, and we know that ENVIRONMENT
is set to 2
.
As such, if we set the Hangul whitespace to 3, we’ll make "32"
, which is equal to 32
when compared with ==
.
We can start with a request saying that \u3164
must equal 3
, such as:
In the provided code, the Hangul whitespace character ‘ㅤ’ is being used as a property name in req.query
. When you visit /login?%E3%85%A4=3
, the URL is decoded to /login?ㅤ=3
, and req.query.ㅤ
is set to '3'
.
It’s worth being aware of Non-space blank characters for situations like this.