## Reverse Engineering/CSS Password (148 solves)  
Created by: `notnotpuns`  
> My web developer friend said JavaScript is insecure so he made a password
> vault with CSS. Can you find the password to open the vault? Wrap the flag
> in uoftctf{} Make sure to use a browser that supports the CSS :has selector,
> such as Firefox 121+ or Chrome 105+. The challenge is verified to work for
> Firefox 121.0.

Looking at the file were provided is ALOT of css, the page looks like this:

![CSS Password Page](https://seall.dev/images/ctfs/uoftctf2024/csspass-1.png)

It has a total of 19 bytes, each byte 8 bits, looking at the CSS comments we
see a format. Let's take this one for example.

`/* b3_8_l1_c6 */`  
\- b3 = Byte 3  
\- 8 = 8th Bit  
\- l1 = LED 1  
\- c6 = Check 6

Looking at LED2 it seems to take only the 1st bit, and we can see in the CSS
content the following for each LED.

```css  
.wrapper:has(.byte:nth-child(18) .latch:nth-child(1) .latch__reset:active)
.checker:nth-of-type(3) .checker__state:nth-child(18) {  
transform: translateX(-100%);  
transition: transform 0s;  
}

.wrapper:has(.byte:nth-child(18) .latch:nth-child(1) .latch__set:active)
.checker:nth-of-type(3) .checker__state:nth-child(18) {  
transform: translateX(0%);  
transition: transform 0s;  
}  
```

When the `latch` is set to reset (0) we get a translation. If we set all the
1st bits for each byte to a 0 we get a green LED! Alphabetical characters tend
to start with a 0 in binary so this makes alot of sense! (Thanks skat :3).

So, when the `translateX(-100%)` is set that is the correct option! I now make
a script with `css.js` to parse the CSS automatically:

```js  
var cssdata = "..."  
var cssjs = require("./css.js");  
var parser = new cssjs.cssjs();  
var parsed = parser.parseCSS(cssdata);  
data=Array(19*8)  
for (x in parsed) {  
selector=parsed[x].selector  
byte=selector.split('.wrapper:has(.byte:nth-child(')[1].split(').latch:')[0]  
bit=selector.split('.latch:nth-child(')[1].split(').latch__')[0]  
state=selector.split(').latch__')[1].split(':active)')[0] === "set" ? 1 : 0  
val=parsed[x].rules[0].value  
if (val === "translateX(-100%)") {  
data[((byte*8)-1)+bit]=state  
}  
}  
console.log(data.join(""))  
```

```  
$ node cssparse.js  
01000011011100110101001101011111011011000011000001100111001100010110001101011111011010010111001101011111011001100111010101101110010111110011001101101000  
```

The binary decodes to our flag content: `CsS_l0g1c_is_fun_3h`

There we go!

Flag: `uoftctf{CsS_l0g1c_is_fun_3h}`

**Files:** [css-password.html](https://files.seall.dev/ctfs/uoftctf2024/css-
password/css-password.html)

Original writeup (https://seall.dev/posts/uoftctf2024#reverse-engineeringcss-
password-148-solves).