17 Jun 2021
b1c and Rogue Waves merged for a big 1st place (W over both redpwn teams!!) in bcaCTF 2021.
Though the pwn curve was pretty sad, I also solved a web challenge, Gerald Catalog.
Gerald Catalog
Least solved challenge in the whole CTF!
The website we are given lets us view and create “Geralds”. Gerald is just an image (of a stegosaurus). Each Gerald has a title and a caption. There is a Gerald with the flag, and only the admin can see it. Our goal is to get the contents of the flag Gerald.
We are also allowed to opt into push notifications. When a Gerald is viewed, we can opt into getting push notifications for view events. Viewing a corresponding Gerald will cause a push notification to be sent to one’s browser, and a popup will be shown.
23 Apr 2021
Even though I was going through some post-quarter-end burnout, I managed to join DiceGang for a bit during PlaidCTF 2021. We ended up getting 2nd, 1 place short of pre-qualifying for DEFCONCTF 2021 Finals :(
The Cobol Job
We are given a cobol program that lets us:
-----------------------
1 - Create file
2 - Open file
3 - Read file
4 - Write file
5 - Close file
6 - Copy file
7 - Exit
>
We can leak all the addresses including the base of libc by copying /proc/self/maps
to a file we create, and then reading it.
18 Apr 2021
Previously, I went over how to turn an out of bounds read and write into shellcode execution in picoCTF 2021’s Download Horsepower.
However, that vulnerability was fairly contrived; generally, no sane developer would make a function to unsafely set arbitrary lengths of arrays.
It turns out that a lot of v8 exploitation is about tricking the v8 Just-In-Time (JIT) compiler, TurboFan, to make dangerous compiler optimizations which can lead to type confusion.
TurboFlan
The provided patch removes the calls to DeoptimizeIfNot(DeoptimizeReason::kWrongMap, ...);
in EffectControlLinearizer::LowerCheckMaps()
.
v8 is known for its speed, and one way it achieves this is by optimizing hot functions, or functions that get called many times. If it gets called so many times, why not compile it and skip the interpretation each call?
However, such optimization presents the danger of confusing types in passed arguments. So, v8 also includes checks to verify the types of objects that are passed to a JITted function, among other checks too. If a check fails, the optimized code is considered unusable and is “deoptimized”, or thrown out.
The patch in TurboFlan basically removes the check that the maps are the same across function calls. If we get a function to be JITted that expects an argument of type a
, and then give it an argument of type b
, the function won’t be de-optimized and will treat the argument that is actually type b
as type a
.
14 Apr 2021
Even though I didn’t do the v8 pwns during the timeframe of the competition, I was interested in learning v8 exploitation and so I upsolved them.
This is the first time I’ve ever done any browser exploitation, and I hope that documenting my thought process will be a reference for future me. Perhaps one day I will look back at this writeup like I look at my writeup of my first heap challenge.
Download Horsepower
This was essentially the Four Function Heap
version of v8 exploitation to me. I learned so much about how v8 objects are represented in memory (and how to corrupt them, of course).
Reading the patch, it is clear that they give us essentially an unlimited Out-Of-Bounds read/write in an array:
...
+namespace array {
+
+transitioning javascript builtin
+ArraySetHorsepower(
+ js-implicit context: NativeContext, receiver: JSAny)(horsepower: JSAny): JSAny {
+ try {
+ const h: Smi = Cast<Smi>(horsepower) otherwise End;
+ const a: JSArray = Cast<JSArray>(receiver) otherwise End;
+ a.SetLength(h);
+ } label End {
+ Print("Improper attempt to set horsepower");
+ }
+ return receiver;
+}
+}
...
07 Apr 2021
This past weekend I had the privilege of helping organize ĂĄngstromCTF 2021!
These are the solutions to my challenges.
Sea of Quills
From the app.rb
, we can see that it filters our input in cols
, limit
, and offset
. Because cols
does not have a length check, we can simply bypass the blacklist.
We can find the name of the flag table by sending cols
as name from sqlite_master union select name
, flagtable
. Some further digging shows that there is a column named flag
.
Our final payload is:
cols: "flag FROM flagtable UNION SELECT name"
limit: "1"
offset: "0"
Flag: actf{and_i_was_doing_fine_but_as_you_came_in_i_watch_my_regex_rewrite_f53d98be5199ab7ff81668df}