Rating:

# Solution

We have to reconstruct the original code by generating each of the commits in the commit history. Each commit's sha must exactly match each sha in the history. The commit messages give hints about the specific code change that need to be made.

### Commit 1

```
commit 7cababac3f3499755d64cf216e237b6969dcedde
Author: CTF Organizer <[email protected]>
Date: Wed Nov 1 09:36:47 2023 -0700

Add hello example from https://go.dev/tour/welcome/1
```

- Create a new directory that will contain our git repo and run `git init`.
- The message says what code is needed for this commit. Go to the URL, copy the code, and notice the file name is `hello.go`. Add the code to a new file named `hello.go`, and then run `git add hello.go`.
- To regenerate a commit with the same sha as the original, we have to set the author, email, date, and message to be the same as the example. See how to set the author, email, and date using environment variables as described in [Git Internals - Environment Variables](https://git-scm.com/book/en/v2/Git-Internals-Environment-Variables).
- After adding `hello.go` and setting the environment variables appropriately, run `git commit -m "Add hello example from https://go.dev/tour/welcome/1"` to regenerate the commit with the same sha as the one in the history (`7201f4b76583397b0a363611da39dbf811ffe912`).

```go
package main

import "fmt"

func main() {
fmt.Println("Hello, 世界")
}
```

### Commit 2

```
commit 7f29b946f68f2cef5bbaab03cbe8049c64dbc29c
Author: CTF Organizer <[email protected]>
Date: Wed Nov 1 09:47:39 2023 -0700

I forgot how to run go code... go mod init ctf
```

- Run `go mod init ctf`. You might need to install go if it's not already installed.
- Set the environment variables appropriately and run `git commit` with the same message.
- In order to get the correct sha, go version `1.21.3` must be used inside `go.mod`. This is not explicitly stated so we have to guess for it. At the time of the commit, `1.21.3` was the latest version.

```go
module ctf

go 1.21.3
```

### Commit 3

```
commit 391229073873729b50318bf385494d0b195a9cb1
Author: CTF Organizer <[email protected]>
Date: Wed Nov 1 10:09:11 2023 -0700

Rename hello.go to main.go and update the prompt. Almost forgot about go fmt .
```

- `git mv hello.go main.go`
- Connect to the server and notice that the prompt is "Password: ".
- Also, be careful to notice there is no newline after the prompt, so we change `fmt.Println` to `fmt.Print`.
- The message also gives a hint that you should use `go fmt .` to format the code. *This should be used for all of the following challenges.*

```go
package main

import "fmt"

func main() {
fmt.Print("Password: ")
}
```

### Commit 4

```
commit 70d45a6d98f5642cdc5c79921815a760d290abe2
Author: CTF Organizer <[email protected]>
Date: Wed Nov 1 10:26:51 2023 -0700

So many ways to read from stdin in go... create a bufio scanner and just call scanner.Scan() I guess? Also, simplify the imports since there are 3 now.
```

- Add the code to read from stdin. The variable name is hinted at in the message.
- Simplify the imports by parenthesizing them.

```go
package main

import (
"bufio"
"fmt"
"os"
)

func main() {
fmt.Print("Password: ")

scanner := bufio.NewScanner(os.Stdin)
scanner.Scan()
}
```

### Commit 5

```
commit 27eeebb5355d8430b5c72757580c7875eba3a6b1
Author: CTF Organizer <[email protected]>
Date: Wed Nov 1 10:43:07 2023 -0700

Read the flag file and print it to stdout as a string. Who needs error handling, it's just a ctf!
```

- Add the `os.ReadFile` and `fmt.Println`.
- The file name and the fact that we ignore the error are hinted at in the message.

```go
package main

import (
"bufio"
"fmt"
"os"
)

func main() {
fmt.Print("Password: ")

scanner := bufio.NewScanner(os.Stdin)
scanner.Scan()

flag, _ := os.ReadFile("flag")
fmt.Println(string(flag))
}
```

### Commit 6

```
commit aa188dbd6fc8342a63c81f2625b7e35a8d605359
Author: CTF Organizer <[email protected]>
Date: Wed Nov 1 11:05:29 2023 -0700

Actually, only print the flag if the scanned bytes matches foo. Make sure to compare in constant time so we don't leak any info!
```

- Wrap the flag print block with an if statement.
- Use `subtle.ConstantTimeCompare` as hinted at in the message.

```go
package main

import (
"bufio"
"crypto/subtle"
"fmt"
"os"
)

func main() {
fmt.Print("Password: ")

scanner := bufio.NewScanner(os.Stdin)
scanner.Scan()

if subtle.ConstantTimeCompare(scanner.Bytes(), []byte("foo")) == 1 {
flag, _ := os.ReadFile("flag")
fmt.Println(string(flag))
}
}
```

### Commit 7

```
commit 152c3c6a671eebf80447224edb6ffce3459cb25f
Author: CTF Organizer <[email protected]>
Date: Wed Nov 1 11:33:56 2023 -0700

Add a sleep before the compare, this will be so hard to crack!
```

- Add `time.Sleep` statement
- The amount of time to sleep is not given and must be guessed from the binary running on the server.

```go
package main

import (
"bufio"
"crypto/subtle"
"fmt"
"os"
"time"
)

func main() {
fmt.Print("Password: ")

scanner := bufio.NewScanner(os.Stdin)
scanner.Scan()

time.Sleep(5 * time.Second)

if subtle.ConstantTimeCompare(scanner.Bytes(), []byte("foo")) == 1 {
flag, _ := os.ReadFile("flag")
fmt.Println(string(flag))
}
}
```

### Commit 8

```
commit 958290ed4c52c380e0ebd0797a298119bcb3ba5d
Author: CTF Organizer <[email protected]>
Date: Wed Nov 1 11:57:38 2023 -0700

Replace foo with an actual password. How about the git tree hash? That should be random enough.
```

Find the git tree hash by running

```
git cat-file commit HEAD | head -n1 | sed 's/tree \(.*\)/\1/'
```

Submit that to the server and get back the flag!

```go
package main

import (
"bufio"
"crypto/subtle"
"fmt"
"os"
"time"
)

func main() {
fmt.Print("Password: ")

scanner := bufio.NewScanner(os.Stdin)
scanner.Scan()

time.Sleep(5 * time.Second)

if subtle.ConstantTimeCompare(scanner.Bytes(), []byte("41156adeacb68c10705f9a6f50c8e9ef92de4e58")) == 1 {
flag, _ := os.ReadFile("flag")
fmt.Println(string(flag))
}
}
```